forked from Goob-Station/Goob-Station
-
Notifications
You must be signed in to change notification settings - Fork 19
Розумний Револьвер #290
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
JustDecor
wants to merge
3
commits into
SpaceStationUA:master
Choose a base branch
from
JustDecor:Revolver
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Розумний Револьвер #290
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
97 changes: 97 additions & 0 deletions
97
Content.Pirate.Client/_JustDecor/Weapons/SmartRevolver/SmartRevolverOverlay.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| using System.Numerics; | ||
| using Content.Pirate.Shared._JustDecor.Weapons.SmartRevolver; | ||
| using Content.Shared.Hands.Components; | ||
| using Content.Shared.Hands.EntitySystems; | ||
| using Robust.Client.GameObjects; | ||
| using Robust.Client.Graphics; | ||
| using Robust.Client.Player; | ||
| using Robust.Client.UserInterface; | ||
| using Robust.Shared.Enums; | ||
| using Robust.Shared.Maths; | ||
|
|
||
| namespace Content.Pirate.Client._JustDecor.Weapons.SmartRevolver; | ||
|
|
||
| /// <summary> | ||
| /// Overlay that shows a target indicator around the selected entity for the smart revolver. | ||
| /// </summary> | ||
| public sealed class SmartRevolverOverlay : Overlay | ||
| { | ||
| private readonly IEntityManager _entityManager; | ||
| private readonly IPlayerManager _playerManager; | ||
| private readonly IEyeManager _eyeManager; | ||
| private readonly SharedHandsSystem _hands; | ||
|
|
||
| public override OverlaySpace Space => OverlaySpace.ScreenSpace; | ||
|
|
||
| public SmartRevolverOverlay(IEntityManager entityManager, IPlayerManager playerManager, IEyeManager eyeManager) | ||
| { | ||
| _entityManager = entityManager; | ||
| _playerManager = playerManager; | ||
| _eyeManager = eyeManager; | ||
| _hands = _entityManager.System<SharedHandsSystem>(); | ||
| } | ||
|
|
||
| protected override void Draw(in OverlayDrawArgs args) | ||
| { | ||
| var player = _playerManager.LocalSession?.AttachedEntity; | ||
| if (player == null) | ||
| return; | ||
|
|
||
| if (!_hands.TryGetActiveItem(player.Value, out var activeHandEntity)) | ||
| return; | ||
|
|
||
| if (!_entityManager.TryGetComponent<SmartRevolverComponent>(activeHandEntity, out var comp)) | ||
| return; | ||
|
|
||
| if (comp.SelectedTarget == null || !_entityManager.EntityExists(comp.SelectedTarget.Value)) | ||
| return; | ||
|
|
||
| if (!_entityManager.TryGetComponent<TransformComponent>(comp.SelectedTarget.Value, out var targetXform)) | ||
| return; | ||
|
|
||
| if (targetXform.MapID != args.MapId) | ||
| return; | ||
|
|
||
| var screenPos = _eyeManager.CoordinatesToScreen(targetXform.Coordinates); | ||
| var handle = args.ScreenHandle; | ||
| var uiScale = (args.ViewportControl as Control)?.UIScale ?? 1f; | ||
|
|
||
| // Прицільний індикатор | ||
| var color = Color.Gold; | ||
| var boxSize = new Vector2(60f, 60f) * uiScale; | ||
| var halfSize = boxSize / 2; | ||
| var topLeft = screenPos.Position - halfSize; | ||
| var borderThickness = 2.5f * uiScale; | ||
|
|
||
| // Зовнішня рамка | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft, new Vector2(boxSize.X, borderThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(0, boxSize.Y - borderThickness), new Vector2(boxSize.X, borderThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft, new Vector2(borderThickness, boxSize.Y)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(boxSize.X - borderThickness, 0), new Vector2(borderThickness, boxSize.Y)), color); | ||
|
|
||
| // Кути для "lock-on" ефекту | ||
| var cornerLength = 12f * uiScale; | ||
| var cornerThickness = 3f * uiScale; | ||
| var cornerOffset = 5f * uiScale; | ||
|
|
||
| // Верхній лівий кут | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft - new Vector2(cornerOffset, cornerOffset), new Vector2(cornerLength, cornerThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft - new Vector2(cornerOffset, cornerOffset), new Vector2(cornerThickness, cornerLength)), color); | ||
|
|
||
| // Верхній правий кут | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(boxSize.X - cornerLength + cornerOffset, -cornerOffset), new Vector2(cornerLength, cornerThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(boxSize.X - cornerThickness + cornerOffset, -cornerOffset), new Vector2(cornerThickness, cornerLength)), color); | ||
|
|
||
| // Нижній лівий кут | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(-cornerOffset, boxSize.Y - cornerThickness + cornerOffset), new Vector2(cornerLength, cornerThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(-cornerOffset, boxSize.Y - cornerLength + cornerOffset), new Vector2(cornerThickness, cornerLength)), color); | ||
|
|
||
| // Нижній правий кут | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(boxSize.X - cornerLength + cornerOffset, boxSize.Y - cornerThickness + cornerOffset), new Vector2(cornerLength, cornerThickness)), color); | ||
| handle.DrawRect(UIBox2.FromDimensions(topLeft + new Vector2(boxSize.X - cornerThickness + cornerOffset, boxSize.Y - cornerLength + cornerOffset), new Vector2(cornerThickness, cornerLength)), color); | ||
|
|
||
| // Центральна частинка | ||
| var diamondSize = 5f * uiScale; | ||
| handle.DrawRect(UIBox2.FromDimensions(screenPos.Position - new Vector2(diamondSize / 2, diamondSize / 2), new Vector2(diamondSize, diamondSize)), color); | ||
| } | ||
| } |
113 changes: 113 additions & 0 deletions
113
Content.Pirate.Client/_JustDecor/Weapons/SmartRevolver/SmartRevolverSystem.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| using Robust.Client.Graphics; | ||
| using Robust.Client.Player; | ||
| using Robust.Client.Input; | ||
| using Robust.Shared.Input; | ||
| using Robust.Shared.Input.Binding; | ||
| using Content.Shared.CombatMode; | ||
| using Robust.Shared.Network; | ||
| using Robust.Shared.GameObjects; | ||
| using Robust.Shared.Map; | ||
| using Robust.Shared.IoC; | ||
| using Content.Pirate.Shared._JustDecor.Weapons.SmartRevolver; | ||
| using Content.Shared.Mobs.Components; | ||
| using Content.Shared.Damage; | ||
| using Robust.Shared.Player; | ||
| using Content.Shared.Hands.EntitySystems; | ||
| using Content.Client.ContextMenu.UI; | ||
| using Content.Client.UserInterface.Systems.Actions; | ||
| using Content.Client.UserInterface.Systems.Hands; | ||
| using Content.Client.UserInterface.Systems.Inventory; | ||
| using Content.Client.UserInterface.Systems.Storage; | ||
|
|
||
| namespace Content.Pirate.Client._JustDecor.Weapons.SmartRevolver; | ||
|
|
||
| public sealed class SmartRevolverSystem : EntitySystem | ||
| { | ||
| [Dependency] private readonly SharedCombatModeSystem _combat = default!; | ||
| [Dependency] private readonly IOverlayManager _overlay = default!; | ||
| [Dependency] private readonly IPlayerManager _player = default!; | ||
| [Dependency] private readonly IEyeManager _eye = default!; | ||
| [Dependency] private readonly IEntityManager _entity = default!; | ||
| [Dependency] private readonly SharedHandsSystem _hands = default!; | ||
| [Dependency] private readonly SharedTransformSystem _transform = default!; | ||
|
|
||
| private SmartRevolverOverlay _overlayInst = default!; | ||
|
|
||
| public override void Initialize() | ||
| { | ||
| base.Initialize(); | ||
|
|
||
| _overlayInst = new SmartRevolverOverlay(_entity, _player, _eye); | ||
| _overlay.AddOverlay(_overlayInst); | ||
| CommandBinds.Builder | ||
| .BindAfter(EngineKeyFunctions.UseSecondary, new PointerInputCmdHandler(OnRightClick), | ||
| typeof(EntityMenuUIController), | ||
| typeof(HandsUIController), | ||
| typeof(InventoryUIController), | ||
| typeof(StorageUIController), | ||
| typeof(ActionUIController)) | ||
| .Register<SmartRevolverSystem>(); | ||
| } | ||
|
|
||
| private bool OnRightClick(ICommonSession? session, EntityCoordinates coords, EntityUid uid) | ||
| { | ||
| return TryHandleInstantTargeting(session, coords, uid); | ||
| } | ||
|
|
||
| private bool TryHandleInstantTargeting(ICommonSession? session, EntityCoordinates coords, EntityUid uid) | ||
| { | ||
| if (session == null) | ||
| return false; | ||
|
|
||
| var player = session?.AttachedEntity; | ||
| if (player == null) | ||
| return false; | ||
|
|
||
| // Instant targeting only in combat mode | ||
| if (!_combat.IsInCombatMode(player.Value)) | ||
| return false; | ||
|
|
||
| // Must be holding Smart Revolver | ||
| if (!_hands.TryGetActiveItem(player.Value, out var activeItem)) | ||
| return false; | ||
|
|
||
| if (!TryComp(activeItem.Value, out SmartRevolverComponent? revolver)) | ||
| return false; | ||
|
|
||
| EntityUid target = uid; | ||
|
|
||
| if (!target.IsValid() || target == player || target == activeItem.Value) | ||
| { | ||
| RaiseNetworkEvent(new SmartRevolverSetTargetMessage(NetEntity.Invalid)); | ||
| return true; | ||
| } | ||
|
|
||
| var playerPos = _transform.GetMapCoordinates(player.Value).Position; | ||
| var targetPos = target.IsValid() | ||
| ? _transform.GetMapCoordinates(target).Position | ||
| : _transform.ToMapCoordinates(coords).Position; | ||
|
|
||
| if ((targetPos - playerPos).Length() > revolver.MaxTargetDistance) | ||
| { | ||
| RaiseNetworkEvent(new SmartRevolverSetTargetMessage(NetEntity.Invalid)); | ||
| return true; | ||
| } | ||
|
|
||
| if (HasComp<MobStateComponent>(target) || HasComp<DamageableComponent>(target)) | ||
| { | ||
| RaiseNetworkEvent(new SmartRevolverSetTargetMessage(GetNetEntity(target))); | ||
| return true; | ||
| } | ||
|
|
||
| // Клік в пусте місце -> очищення цілі | ||
| RaiseNetworkEvent(new SmartRevolverSetTargetMessage(NetEntity.Invalid)); | ||
| return true; | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
Comment on lines
+57
to
+105
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧹 Nitpick | 🔵 Trivial Зайвий оператор
♻️ Запропоноване спрощення- var player = session?.AttachedEntity;
+ var player = session.AttachedEntity;- var targetPos = target.IsValid()
- ? _transform.GetMapCoordinates(target).Position
- : _transform.ToMapCoordinates(coords).Position;
+ var targetPos = _transform.GetMapCoordinates(target).Position;🤖 Prompt for AI Agents |
||
|
|
||
| public override void Shutdown() | ||
| { | ||
| base.Shutdown(); | ||
| _overlay.RemoveOverlay(_overlayInst); | ||
| CommandBinds.Unregister<SmartRevolverSystem>(); | ||
| } | ||
| } | ||
91 changes: 91 additions & 0 deletions
91
Content.Pirate.Shared/_JustDecor/Weapons/Ranged/RicochetProjectileComponent.cs
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,91 @@ | ||
| using System.Numerics; | ||
| using Robust.Shared.GameStates; | ||
|
|
||
| namespace Content.Pirate.Shared._JustDecor.Weapons.Ranged; | ||
|
|
||
| /// <summary> | ||
| /// Component for projectiles that can ricochet off walls to hit a target. | ||
| /// </summary> | ||
| [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] | ||
| public sealed partial class RicochetProjectileComponent : Component | ||
| { | ||
| /// <summary> | ||
| /// The target entity that the projectile should try to hit via ricochets. | ||
| /// </summary> | ||
| [DataField, AutoNetworkedField] | ||
| public EntityUid? Target; | ||
|
|
||
| /// <summary> | ||
| /// Maximum number of bounces allowed before the projectile stops ricocheting. | ||
| /// </summary> | ||
| [DataField, AutoNetworkedField] | ||
| public int MaxBounces = 4; | ||
|
|
||
| /// <summary> | ||
| /// Current number of bounces that have occurred. | ||
| /// </summary> | ||
| [DataField, AutoNetworkedField] | ||
| public int CurrentBounces = 0; | ||
|
|
||
| /// <summary> | ||
| /// Planned waypoints for the ricochet path (wall hit positions). | ||
| /// </summary> | ||
| [DataField] | ||
| public List<Vector2> PlannedPath = new(); | ||
coderabbitai[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| /// <summary> | ||
| /// Whether the projectile should follow the planned path. | ||
| /// If false, the projectile will calculate ricochets dynamically on each bounce. | ||
| /// </summary> | ||
| [DataField, AutoNetworkedField] | ||
| public bool FollowPlannedPath = true; | ||
|
|
||
| /// <summary> | ||
| /// Minimum speed required for ricochet to occur. Below this speed, projectile will stop. | ||
| /// </summary> | ||
| [DataField] | ||
| public float MinimumRicochetSpeed = 5f; | ||
|
|
||
| /// <summary> | ||
| /// Speed multiplier applied after each bounce (energy loss). | ||
| /// </summary> | ||
| [DataField] | ||
| public float SpeedRetentionOnBounce = 0.95f; | ||
|
|
||
| /// <summary> | ||
| /// How strongly the projectile steers towards its target every frame. | ||
| /// 0.0 means no steering, 1.0 means instant snap. | ||
| /// </summary> | ||
| [DataField] | ||
| public float SteeringStrength = 1.0f; // High default for 100% hits | ||
|
|
||
| /// <summary> | ||
| /// Delay before homing starts (seconds). | ||
| /// </summary> | ||
| [DataField] | ||
| public float HomingDelay = 0.2f; | ||
|
|
||
| /// <summary> | ||
| /// Current accumulator for homing delay. | ||
| /// </summary> | ||
| [ViewVariables] | ||
| public float HomingAccumulator = 0f; | ||
|
|
||
| /// <summary> | ||
| /// How much speed to add per bounce. | ||
| /// </summary> | ||
| [DataField] | ||
| public float SpeedBonusPerBounce = 5f; | ||
|
|
||
| /// <summary> | ||
| /// Lifetime bonus applied after each bounce. | ||
| /// </summary> | ||
| [DataField] | ||
| public float BounceLifetimeBonus = 3f; | ||
|
|
||
| /// <summary> | ||
| /// Target number of bounces before hitting the final target. | ||
| /// </summary> | ||
| [DataField] | ||
| public int TargetBounces = 0; | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.