GunSystem.Cartridges.cs 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. using Content.Server.Weapons.Ranged.Components;
  2. using Content.Shared.Damage;
  3. using Content.Shared.Damage.Events;
  4. using Content.Shared.Examine;
  5. using Content.Shared.FixedPoint;
  6. using Content.Shared.Projectiles;
  7. using Content.Shared.Weapons.Ranged.Components;
  8. using Robust.Shared.GameObjects;
  9. using Robust.Shared.Prototypes;
  10. using Robust.Shared.Timing;
  11. namespace Content.Server.Weapons.Ranged.Systems;
  12. public sealed partial class GunSystem
  13. {
  14. [Dependency] private readonly ITimerManager _timerManager = default!;
  15. [Dependency] private readonly ILogManager _logManager = default!;
  16. private ISawmill _sawmill = default!;
  17. protected override void InitializeCartridge()
  18. {
  19. _sawmill = _logManager.GetSawmill("cartridge");
  20. base.InitializeCartridge();
  21. SubscribeLocalEvent<CartridgeAmmoComponent, ExaminedEvent>(OnCartridgeExamine);
  22. SubscribeLocalEvent<CartridgeAmmoComponent, DamageExamineEvent>(OnCartridgeDamageExamine);
  23. // Handle cartridges that are already spent when they are initialized
  24. SubscribeLocalEvent<CartridgeAmmoComponent, ComponentStartup>(OnCartridgeStartupForDeletionCheck);
  25. }
  26. private void OnCartridgeDamageExamine(EntityUid uid, CartridgeAmmoComponent component, ref DamageExamineEvent args)
  27. {
  28. var damageSpec = GetProjectileDamage(component.Prototype);
  29. if (damageSpec == null)
  30. return;
  31. _damageExamine.AddDamageExamine(args.Message, Damageable.ApplyUniversalAllModifiers(damageSpec), Loc.GetString("damage-projectile"));
  32. }
  33. private DamageSpecifier? GetProjectileDamage(string proto)
  34. {
  35. if (!ProtoManager.TryIndex<EntityPrototype>(proto, out var entityProto))
  36. return null;
  37. if (entityProto.Components
  38. .TryGetValue(_factory.GetComponentName(typeof(ProjectileComponent)), out var projectile))
  39. {
  40. var p = (ProjectileComponent)projectile.Component;
  41. if (!p.Damage.Empty)
  42. {
  43. return p.Damage * Damageable.UniversalProjectileDamageModifier;
  44. }
  45. }
  46. return null;
  47. }
  48. private void OnCartridgeExamine(EntityUid uid, CartridgeAmmoComponent component, ExaminedEvent args)
  49. {
  50. if (component.Spent)
  51. {
  52. args.PushMarkup(Loc.GetString("gun-cartridge-spent"));
  53. }
  54. else
  55. {
  56. args.PushMarkup(Loc.GetString("gun-cartridge-unspent"));
  57. }
  58. }
  59. protected override void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
  60. {
  61. base.SetCartridgeSpent(uid, cartridge, spent);
  62. // Now call the server-specific logic after the spent status is updated
  63. CheckAndScheduleSpentCartridgeDeletion(uid, cartridge);
  64. }
  65. private void OnCartridgeStartupForDeletionCheck(EntityUid uid, CartridgeAmmoComponent component, ComponentStartup args)
  66. {
  67. CheckAndScheduleSpentCartridgeDeletion(uid, component);
  68. }
  69. /// <summary>
  70. /// Checks if a cartridge is spent and, if so, schedules it for deletion after a delay.
  71. /// This function can be called when a cartridge's state might have changed to spent.
  72. /// </summary>
  73. public void CheckAndScheduleSpentCartridgeDeletion(EntityUid cartridgeUid, CartridgeAmmoComponent cartridge)
  74. {
  75. if (cartridge.Spent)
  76. {
  77. // If not already marked for deletion
  78. if (!EntityManager.HasComponent<DeletingSpentCartridgeComponent>(cartridgeUid))
  79. {
  80. EntityManager.AddComponent<DeletingSpentCartridgeComponent>(cartridgeUid);
  81. //_sawmill.Info($"Scheduling spent cartridge {ToPrettyString(cartridgeUid)} for deletion in 5 minutes.");
  82. _timerManager.AddTimer(new Timer((int)TimeSpan.FromMinutes(5).TotalMilliseconds, false, () =>
  83. {
  84. // Re-check conditions before deleting, as state might have changed or entity might be gone.
  85. if (EntityManager.Deleted(cartridgeUid))
  86. return;
  87. if (EntityManager.TryGetComponent<CartridgeAmmoComponent>(cartridgeUid, out var currentCartridge) && currentCartridge.Spent)
  88. {
  89. //_sawmill.Info($"Deleting spent cartridge {ToPrettyString(cartridgeUid)} after 5 minutes.");
  90. EntityManager.QueueDeleteEntity(cartridgeUid);
  91. }
  92. else
  93. {
  94. // Condition no longer met (e.g., no longer spent, or component removed), so just remove the marker.
  95. EntityManager.RemoveComponent<DeletingSpentCartridgeComponent>(cartridgeUid);
  96. }
  97. }));
  98. }
  99. }
  100. else if (EntityManager.HasComponent<DeletingSpentCartridgeComponent>(cartridgeUid))
  101. {
  102. // If it's not spent but was somehow marked, remove the marker.
  103. // Note: This doesn't cancel the timer here, but the timer's callback will handle it.
  104. EntityManager.RemoveComponent<DeletingSpentCartridgeComponent>(cartridgeUid);
  105. }
  106. }
  107. }