Files
tbd-station-14/Content.Server/NPC/Systems/NPCRetaliationSystem.cs
Hannah Giovanna Dawson cdbe92d37d Update DamageableSystem to modern standards (#39417)
* Update DamageableSystem to modern standards

* DamageContainerId -> DamageContainerID with lint flag

* Replace strings with protoids

* Make CVar subscription declarations all consistently whitespaced

* ChangeDamage -> TryChangeDamage, cope with C# jank

* Revert event signature changes

* Restore a comment

* Re-add two queries

* Init the queries

* Use appearanceQuery in DamageChanged

* Use damageableQuery in TryChangeDamage

* Use damageableQuery in SetDamageModifierSetId

* Final cleanup, fix sandboxing

* Rectify ExplosionSystem:::ProcessEntity's call to TryChangeDamage

* Re-organize DamageableSystem

* first big fuck you breaking change.

* THATS A LOT OF DAMAGE!!!

* Fix test fails

* test fixes 2

* push it

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
2025-10-27 19:53:04 +00:00

80 lines
2.7 KiB
C#

using Content.Server.NPC.Components;
using Content.Shared.CombatMode;
using Content.Shared.Damage;
using Content.Shared.Damage.Systems;
using Content.Shared.Mobs.Components;
using Content.Shared.NPC.Components;
using Content.Shared.NPC.Systems;
using Robust.Shared.Collections;
using Robust.Shared.Timing;
namespace Content.Server.NPC.Systems;
/// <summary>
/// Handles NPC which become aggressive after being attacked.
/// </summary>
public sealed class NPCRetaliationSystem : EntitySystem
{
[Dependency] private readonly NpcFactionSystem _npcFaction = default!;
[Dependency] private readonly IGameTiming _timing = default!;
/// <inheritdoc />
public override void Initialize()
{
SubscribeLocalEvent<NPCRetaliationComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<NPCRetaliationComponent, DisarmedEvent>(OnDisarmed);
}
private void OnDamageChanged(Entity<NPCRetaliationComponent> ent, ref DamageChangedEvent args)
{
if (!args.DamageIncreased)
return;
if (args.Origin is not {} origin)
return;
TryRetaliate(ent, origin);
}
private void OnDisarmed(Entity<NPCRetaliationComponent> ent, ref DisarmedEvent args)
{
TryRetaliate(ent, args.Source);
}
public bool TryRetaliate(Entity<NPCRetaliationComponent> ent, EntityUid target)
{
// don't retaliate against inanimate objects.
if (!HasComp<MobStateComponent>(target))
return false;
// don't retaliate against the same faction
if (_npcFaction.IsEntityFriendly(ent.Owner, target))
return false;
_npcFaction.AggroEntity(ent.Owner, target);
if (ent.Comp.AttackMemoryLength is {} memoryLength)
ent.Comp.AttackMemories[target] = _timing.CurTime + memoryLength;
return true;
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<NPCRetaliationComponent, FactionExceptionComponent>();
while (query.MoveNext(out var uid, out var retaliationComponent, out var factionException))
{
// TODO: can probably reuse this allocation and clear it
foreach (var entity in new ValueList<EntityUid>(retaliationComponent.AttackMemories.Keys))
{
if (!TerminatingOrDeleted(entity) && _timing.CurTime < retaliationComponent.AttackMemories[entity])
continue;
_npcFaction.DeAggroEntity((uid, factionException), entity);
// TODO: should probably remove the AttackMemory, thats the whole point of the ValueList right??
}
}
}
}