1
0

NPCRetaliationSystem.cs 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using Content.Server.NPC.Components;
  2. using Content.Shared.CombatMode;
  3. using Content.Shared.Damage;
  4. using Content.Shared.Mobs.Components;
  5. using Content.Shared.NPC.Components;
  6. using Content.Shared.NPC.Systems;
  7. using Robust.Shared.Collections;
  8. using Robust.Shared.Timing;
  9. namespace Content.Server.NPC.Systems;
  10. /// <summary>
  11. /// Handles NPC which become aggressive after being attacked.
  12. /// </summary>
  13. public sealed class NPCRetaliationSystem : EntitySystem
  14. {
  15. [Dependency] private readonly NpcFactionSystem _npcFaction = default!;
  16. [Dependency] private readonly IGameTiming _timing = default!;
  17. /// <inheritdoc />
  18. public override void Initialize()
  19. {
  20. SubscribeLocalEvent<NPCRetaliationComponent, DamageChangedEvent>(OnDamageChanged);
  21. SubscribeLocalEvent<NPCRetaliationComponent, DisarmedEvent>(OnDisarmed);
  22. }
  23. private void OnDamageChanged(Entity<NPCRetaliationComponent> ent, ref DamageChangedEvent args)
  24. {
  25. if (!args.DamageIncreased)
  26. return;
  27. if (args.Origin is not {} origin)
  28. return;
  29. TryRetaliate(ent, origin);
  30. }
  31. private void OnDisarmed(Entity<NPCRetaliationComponent> ent, ref DisarmedEvent args)
  32. {
  33. TryRetaliate(ent, args.Source);
  34. }
  35. public bool TryRetaliate(Entity<NPCRetaliationComponent> ent, EntityUid target)
  36. {
  37. // don't retaliate against inanimate objects.
  38. if (!HasComp<MobStateComponent>(target))
  39. return false;
  40. // don't retaliate against the same faction
  41. if (_npcFaction.IsEntityFriendly(ent.Owner, target))
  42. return false;
  43. _npcFaction.AggroEntity(ent.Owner, target);
  44. if (ent.Comp.AttackMemoryLength is {} memoryLength)
  45. ent.Comp.AttackMemories[target] = _timing.CurTime + memoryLength;
  46. return true;
  47. }
  48. public override void Update(float frameTime)
  49. {
  50. base.Update(frameTime);
  51. var query = EntityQueryEnumerator<NPCRetaliationComponent, FactionExceptionComponent>();
  52. while (query.MoveNext(out var uid, out var retaliationComponent, out var factionException))
  53. {
  54. // TODO: can probably reuse this allocation and clear it
  55. foreach (var entity in new ValueList<EntityUid>(retaliationComponent.AttackMemories.Keys))
  56. {
  57. if (!TerminatingOrDeleted(entity) && _timing.CurTime < retaliationComponent.AttackMemories[entity])
  58. continue;
  59. _npcFaction.DeAggroEntity((uid, factionException), entity);
  60. // TODO: should probably remove the AttackMemory, thats the whole point of the ValueList right??
  61. }
  62. }
  63. }
  64. }