1
0

NPCCombatSystem.Melee.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. using System.Numerics;
  2. using Content.Server.NPC.Components;
  3. using Content.Shared.CombatMode;
  4. using Content.Shared.NPC;
  5. using Robust.Shared.Map;
  6. using Robust.Shared.Physics.Components;
  7. using Robust.Shared.Random;
  8. namespace Content.Server.NPC.Systems;
  9. public sealed partial class NPCCombatSystem
  10. {
  11. private const float TargetMeleeLostRange = 14f;
  12. private void InitializeMelee()
  13. {
  14. SubscribeLocalEvent<NPCMeleeCombatComponent, ComponentStartup>(OnMeleeStartup);
  15. SubscribeLocalEvent<NPCMeleeCombatComponent, ComponentShutdown>(OnMeleeShutdown);
  16. }
  17. private void OnMeleeShutdown(EntityUid uid, NPCMeleeCombatComponent component, ComponentShutdown args)
  18. {
  19. if (TryComp<CombatModeComponent>(uid, out var combatMode))
  20. {
  21. _combat.SetInCombatMode(uid, false, combatMode);
  22. }
  23. _steering.Unregister(uid);
  24. }
  25. private void OnMeleeStartup(EntityUid uid, NPCMeleeCombatComponent component, ComponentStartup args)
  26. {
  27. if (TryComp<CombatModeComponent>(uid, out var combatMode))
  28. {
  29. _combat.SetInCombatMode(uid, true, combatMode);
  30. }
  31. }
  32. private void UpdateMelee(float frameTime)
  33. {
  34. var combatQuery = GetEntityQuery<CombatModeComponent>();
  35. var xformQuery = GetEntityQuery<TransformComponent>();
  36. var physicsQuery = GetEntityQuery<PhysicsComponent>();
  37. var curTime = _timing.CurTime;
  38. var query = EntityQueryEnumerator<NPCMeleeCombatComponent, ActiveNPCComponent>();
  39. while (query.MoveNext(out var uid, out var comp, out _))
  40. {
  41. if (!combatQuery.TryGetComponent(uid, out var combat) || !combat.IsInCombatMode)
  42. {
  43. RemComp<NPCMeleeCombatComponent>(uid);
  44. continue;
  45. }
  46. Attack(uid, comp, curTime, physicsQuery, xformQuery);
  47. }
  48. }
  49. private void Attack(EntityUid uid, NPCMeleeCombatComponent component, TimeSpan curTime, EntityQuery<PhysicsComponent> physicsQuery, EntityQuery<TransformComponent> xformQuery)
  50. {
  51. component.Status = CombatStatus.Normal;
  52. if (!_melee.TryGetWeapon(uid, out var weaponUid, out var weapon))
  53. {
  54. component.Status = CombatStatus.NoWeapon;
  55. return;
  56. }
  57. if (!xformQuery.TryGetComponent(uid, out var xform) ||
  58. !xformQuery.TryGetComponent(component.Target, out var targetXform))
  59. {
  60. component.Status = CombatStatus.TargetUnreachable;
  61. return;
  62. }
  63. if (!xform.Coordinates.TryDistance(EntityManager, targetXform.Coordinates, out var distance))
  64. {
  65. component.Status = CombatStatus.TargetUnreachable;
  66. return;
  67. }
  68. if (distance > TargetMeleeLostRange)
  69. {
  70. component.Status = CombatStatus.TargetUnreachable;
  71. return;
  72. }
  73. if (TryComp<NPCSteeringComponent>(uid, out var steering) &&
  74. steering.Status == SteeringStatus.NoPath)
  75. {
  76. component.Status = CombatStatus.TargetUnreachable;
  77. return;
  78. }
  79. // TODO: When I get parallel operators move this as NPC combat shouldn't be handling this.
  80. _steering.Register(uid, new EntityCoordinates(component.Target, Vector2.Zero), steering);
  81. if (distance > weapon.Range)
  82. {
  83. component.Status = CombatStatus.TargetOutOfRange;
  84. return;
  85. }
  86. if (weapon.NextAttack > curTime || !Enabled)
  87. return;
  88. if (_random.Prob(component.MissChance) &&
  89. physicsQuery.TryGetComponent(component.Target, out var targetPhysics) &&
  90. targetPhysics.LinearVelocity.LengthSquared() != 0f)
  91. {
  92. _melee.AttemptLightAttackMiss(uid, weaponUid, weapon, targetXform.Coordinates.Offset(_random.NextVector2(0.5f)));
  93. }
  94. else
  95. {
  96. _melee.AttemptLightAttack(uid, weaponUid, weapon, component.Target);
  97. }
  98. }
  99. }