From 4454e1feba006513294fe95bef99bbb37627591b Mon Sep 17 00:00:00 2001 From: Rain Caldwell <67359748+Just-a-Unity-Dev@users.noreply.github.com> Date: Wed, 10 Jul 2024 18:38:37 +0800 Subject: [PATCH] Advanced targeting --- .../Components/NPCRangedCombatComponent.cs | 6 +++ .../Operators/Combat/Ranged/GunOperator.cs | 1 + Content.Server/NPC/NPCBlackboard.cs | 1 + .../NPC/Systems/NPCCombatSystem.Ranged.cs | 45 ++++++++++++------- .../Weapons/Ranged/Systems/GunSystem.cs | 2 - .../Weapons/Guns/Naval/Ballistic/20mm.yml | 22 +++++++++ 6 files changed, 60 insertions(+), 17 deletions(-) diff --git a/Content.Server/NPC/Components/NPCRangedCombatComponent.cs b/Content.Server/NPC/Components/NPCRangedCombatComponent.cs index 2e4fcf5298..7ae9b47dae 100644 --- a/Content.Server/NPC/Components/NPCRangedCombatComponent.cs +++ b/Content.Server/NPC/Components/NPCRangedCombatComponent.cs @@ -34,6 +34,12 @@ public sealed partial class NPCRangedCombatComponent : Component [ViewVariables(VVAccess.ReadWrite)] public float LOSAccumulator = 0f; + /// + /// Does this predict where the target is moving towards, and then fires there? + /// + [ViewVariables(VVAccess.ReadWrite)] + public bool Advanced = false; + /// /// Is the target still considered in LOS since the last check. /// diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Ranged/GunOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Ranged/GunOperator.cs index 53c5ed1952..177152d85a 100644 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Ranged/GunOperator.cs +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/Ranged/GunOperator.cs @@ -58,6 +58,7 @@ public override void Startup(NPCBlackboard blackboard) base.Startup(blackboard); var ranged = _entManager.EnsureComponent(blackboard.GetValue(NPCBlackboard.Owner)); ranged.Target = blackboard.GetValue(TargetKey); + ranged.Advanced = blackboard.GetValueOrDefault("AdvancedTargeting", _entManager); if (blackboard.TryGetValue(NPCBlackboard.RotateSpeed, out var rotSpeed, _entManager)) { diff --git a/Content.Server/NPC/NPCBlackboard.cs b/Content.Server/NPC/NPCBlackboard.cs index 322ff0f85b..9919f2eb6a 100644 --- a/Content.Server/NPC/NPCBlackboard.cs +++ b/Content.Server/NPC/NPCBlackboard.cs @@ -32,6 +32,7 @@ public sealed partial class NPCBlackboard : IEnumerable _physicsQuery; private EntityQuery _xformQuery; - // TODO: Don't predict for hitscan - private const float ShootSpeed = 20f; - /// /// Cooldown on raycasting to check LOS. /// @@ -121,20 +119,42 @@ private void UpdateRanged(float frameTime) comp.LOSAccumulator -= frameTime; - var worldPos = _transform.GetWorldPosition(xform); - var targetPos = _transform.GetWorldPosition(targetXform); + var (x, worldRot) = _transform.GetWorldPositionRotation(xform); + var v = gun.ProjectileSpeed; // bullet velocity + var (xt, targetRot) = _transform.GetWorldPositionRotation(targetXform); + var vt = targetBody.LinearVelocity; // target velocity - // We'll work out the projected spot of the target and shoot there instead of where they are. - var distance = (targetPos - worldPos).Length(); - var oldInLos = comp.TargetInLOS; + Vector2 targetSpot; + Angle goalRotation; + var dx = xt - x; // target displacement from gun + var distance = dx.Length(); // distance to target + + if (comp.Advanced) + { + var phi = (-dx).ToWorldAngle() - vt.ToWorldAngle(); + var theta = Math.Asin(vt.Length() / v * Math.Sin(phi.Theta)); + goalRotation = dx.ToWorldAngle() + theta; + var psi = Math.PI - phi - theta; + var intercept_dist = (float)(distance * Math.Sin(theta)/Math.Sin(psi)); + targetSpot = xt + vt.Normalized() * intercept_dist; + } + else + { + // We'll work out the projected spot of the target and shoot there instead of where they are. + targetSpot = xt + vt * distance / v; + goalRotation = (targetSpot - x).ToWorldAngle(); + } // TODO: Should be doing these raycasts in parallel // Ideally we'd have 2 steps, 1. to go over the normal details for shooting and then 2. to handle beep / rotate / shoot + var oldInLos = comp.TargetInLOS; + if (comp.LOSAccumulator < 0f) { comp.LOSAccumulator += UnoccludedCooldown; // For consistency with NPC steering. - comp.TargetInLOS = _interaction.InRangeUnobstructed(uid, Transform(comp.Target).Coordinates, distance + 0.1f); + comp.TargetInLOS = _interaction.InRangeUnobstructed(comp.Owner, comp.Target, distance + 0.1f) && + (!comp.Advanced | _interaction.InRangeUnobstructed(comp.Owner, new MapCoordinates(targetSpot, xform.MapID), distance + 0.1f)); } if (!comp.TargetInLOS) @@ -162,11 +182,6 @@ private void UpdateRanged(float frameTime) continue; } - var mapVelocity = targetBody.LinearVelocity; - var targetSpot = targetPos + mapVelocity * distance / ShootSpeed; - - // If we have a max rotation speed then do that. - var goalRotation = (targetSpot - worldPos).ToWorldAngle(); var rotationSpeed = comp.RotationSpeed; if (!_rotate.TryRotateTo(uid, goalRotation, frameTime, comp.AccuracyThreshold, rotationSpeed?.Theta ?? double.MaxValue, xform)) @@ -187,7 +202,7 @@ private void UpdateRanged(float frameTime) EntityCoordinates targetCordinates; - if (_mapManager.TryFindGridAt(xform.MapID, targetPos, out var gridUid, out var mapGrid)) + if (_mapManager.TryFindGridAt(xform.MapID, xt, out var gridUid, out var mapGrid)) { targetCordinates = new EntityCoordinates(gridUid, mapGrid.WorldToLocal(targetSpot)); } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index 7f7c7ba855..df4c83f8c9 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -304,8 +304,6 @@ private void ShootOrThrow(EntityUid uid, Vector2 mapDirection, Vector2 gunVeloci if (!HasComp(uid)) { RemoveShootable(uid); - // TODO: Someone can probably yeet this a billion miles so need to pre-validate input somewhere up the call stack. - ThrowingSystem.TryThrow(uid, mapDirection, gun.ProjectileSpeedModified, user); return; } diff --git a/Resources/Prototypes/_FTL/Entities/Objects/Weapons/Guns/Naval/Ballistic/20mm.yml b/Resources/Prototypes/_FTL/Entities/Objects/Weapons/Guns/Naval/Ballistic/20mm.yml index a40545f847..9cf81cf129 100644 --- a/Resources/Prototypes/_FTL/Entities/Objects/Weapons/Guns/Naval/Ballistic/20mm.yml +++ b/Resources/Prototypes/_FTL/Entities/Objects/Weapons/Guns/Naval/Ballistic/20mm.yml @@ -30,3 +30,25 @@ - type: NpcFactionMember factions: - PointDefenseGun + - type: BallisticAmmoProvider + proto: Cartridge20mm + capacity: 1500 + - type: Gun + fireRate: 20 + selectedMode: FullAuto + availableModes: + - FullAuto + - type: HTN + rootTask: + task: TurretCompound + blackboard: + RotateSpeed: !type:Single + 15.705 # 3.141 * 5 + SoundTargetInLOS: !type:SoundPathSpecifier + path: /Audio/Effects/double_beep.ogg + AdvancedTargeting: !type:Bool + true + RangedRange: !type:Single + 60.0 + VisionRadius: !type:Single + 100.0