From a35100995664f4fa32593a3af5010f8aa85edf93 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Thu, 17 Sep 2026 14:00:59 +0200 Subject: [PATCH] Gate weapon fire on the shooter's own stance, shared by player and AI Weapon.StanceAllowsFire is the one shared gate: true with no target, else the shooter's own Entity.IsHostileTo(Target) -- not the target's stance toward the shooter. It lives on the Weapon base class so every weapon subtype and every caller (player input, TurretController, AI) goes through the same rule. Wired at the two places weapons actually start dealing damage: - InstantWeapon.Trigger (the base for InstantWeapon, AutoWeapon, ChargedWeapon and LockWeapon/Launcher, all of which route real firing through Trigger). - ConstantWeapon.Execute's continuous-beam loop, which stops firing (and raises OnStopFiring) the moment the shooter's stance disallows it. Also fixes LockWeapon's lock-building condition, which read the wrong direction (target.IsHostileTo(shooter) instead of shooter.IsHostileTo(target)) -- the same backwards check as the HUD lock indicator, fixed alongside this in ActionGameManager. Co-Authored-By: Claude Opus 5 --- Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs | 7 +++++++ Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs | 3 +++ Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs | 2 +- Assets/Scripts/ServerShared/Behaviors/Weapon.cs | 7 ++++++- 4 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs index 7e4eaf1d5..26027ca4b 100644 --- a/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/ConstantWeapon.cs @@ -75,6 +75,13 @@ public class ConstantWeapon : Weapon, IProgressBehavior, IEventBehavior public override bool Execute(float dt) { base.Execute(dt); + if (_firing && !StanceAllowsFire) + { + // Safed: shooter has a target and hasn't declared hostility toward it. + _firing = false; + OnStopFiring?.Invoke(); + return false; + } if (_firing) { if (!Entity.TryConsumeEnergy(Evaluate(_data.Energy) * dt)) diff --git a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs index cf50f7494..b5f5d2dec 100644 --- a/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/InstantWeapon.cs @@ -90,6 +90,9 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior protected void Trigger() { + // Safed: shooter has a target and hasn't declared hostility toward it. + if (!StanceAllowsFire) return; + // If 1 ammo is consumed per burst, perform ammo and energy consumption here // UseAmmo returns false when triggering reload; cancel firing if that is the case if(_data.SingleAmmoBurst && (!Entity.TryConsumeEnergy(Energy) || !UseAmmo())) return; diff --git a/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs b/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs index c27e51af7..665471184 100644 --- a/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/LockWeapon.cs @@ -77,7 +77,7 @@ public class LockWeapon : InstantWeapon _target = Entity.Target.Value; } - if (Entity.Target.Value != null && Entity.Target.Value.IsHostileTo(Entity)) + if (Entity.Target.Value != null && Entity.IsHostileTo(Entity.Target.Value)) { LockSpeed = Evaluate(_data.LockSpeed); SensorImpact = Evaluate(_data.SensorImpact); diff --git a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs index 417751b4c..5e5636f00 100644 --- a/Assets/Scripts/ServerShared/Behaviors/Weapon.cs +++ b/Assets/Scripts/ServerShared/Behaviors/Weapon.cs @@ -94,7 +94,12 @@ public abstract class Weapon : Behavior, IActivatedBehavior { get => _firing; } - + + // Single shared fire gate for player and AI shooters alike: weapons are safed by the + // shooter's OWN declared stance toward its target, not the target's stance toward the shooter. + // With no target set, behaviour is unchanged (nothing to be safe about). + public bool StanceAllowsFire => Entity.Target.Value == null || Entity.IsHostileTo(Entity.Target.Value); + public Weapon(WeaponData data, EquippedItem item) : base(data, item) { _data = data;