* 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>
80 lines
2.7 KiB
C#
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??
|
|
}
|
|
}
|
|
}
|
|
}
|