RottingSystem.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using Content.Server.Atmos.EntitySystems;
  2. using Content.Server.Body.Components;
  3. using Content.Server.Temperature.Components;
  4. using Content.Shared.Atmos;
  5. using Content.Shared.Atmos.Rotting;
  6. using Content.Shared.Damage;
  7. using Robust.Server.Containers;
  8. using Robust.Shared.Physics.Components;
  9. using Robust.Shared.Timing;
  10. namespace Content.Server.Atmos.Rotting;
  11. public sealed class RottingSystem : SharedRottingSystem
  12. {
  13. [Dependency] private readonly IGameTiming _timing = default!;
  14. [Dependency] private readonly AtmosphereSystem _atmosphere = default!;
  15. [Dependency] private readonly ContainerSystem _container = default!;
  16. [Dependency] private readonly DamageableSystem _damageable = default!;
  17. public override void Initialize()
  18. {
  19. base.Initialize();
  20. SubscribeLocalEvent<RottingComponent, BeingGibbedEvent>(OnGibbed);
  21. SubscribeLocalEvent<TemperatureComponent, IsRottingEvent>(OnTempIsRotting);
  22. }
  23. private void OnGibbed(EntityUid uid, RottingComponent component, BeingGibbedEvent args)
  24. {
  25. if (!TryComp<PhysicsComponent>(uid, out var physics))
  26. return;
  27. if (!TryComp<PerishableComponent>(uid, out var perishable))
  28. return;
  29. var molsToDump = perishable.MolsPerSecondPerUnitMass * physics.FixturesMass * (float)component.TotalRotTime.TotalSeconds;
  30. var tileMix = _atmosphere.GetTileMixture(uid, excite: true);
  31. tileMix?.AdjustMoles(Gas.Ammonia, molsToDump);
  32. }
  33. private void OnTempIsRotting(EntityUid uid, TemperatureComponent component, ref IsRottingEvent args)
  34. {
  35. if (args.Handled)
  36. return;
  37. args.Handled = component.CurrentTemperature < Atmospherics.T0C + 0.85f;
  38. }
  39. /// <summary>
  40. /// Is anything speeding up the decay?
  41. /// e.g. buried in a grave
  42. /// TODO: hot temperatures increase rot?
  43. /// </summary>
  44. /// <returns></returns>
  45. private float GetRotRate(EntityUid uid)
  46. {
  47. if (_container.TryGetContainingContainer((uid, null, null), out var container) &&
  48. TryComp<ProRottingContainerComponent>(container.Owner, out var rotContainer))
  49. {
  50. return rotContainer.DecayModifier;
  51. }
  52. return 1f;
  53. }
  54. public override void Update(float frameTime)
  55. {
  56. base.Update(frameTime);
  57. var perishQuery = EntityQueryEnumerator<PerishableComponent>();
  58. while (perishQuery.MoveNext(out var uid, out var perishable))
  59. {
  60. if (_timing.CurTime < perishable.RotNextUpdate)
  61. continue;
  62. perishable.RotNextUpdate += perishable.PerishUpdateRate;
  63. var stage = PerishStage((uid, perishable), MaxStages);
  64. if (stage != perishable.Stage)
  65. {
  66. perishable.Stage = stage;
  67. Dirty(uid, perishable);
  68. }
  69. if (IsRotten(uid) || !IsRotProgressing(uid, perishable))
  70. continue;
  71. perishable.RotAccumulator += perishable.PerishUpdateRate * GetRotRate(uid);
  72. if (perishable.RotAccumulator >= perishable.RotAfter)
  73. {
  74. var rot = AddComp<RottingComponent>(uid);
  75. rot.NextRotUpdate = _timing.CurTime + rot.RotUpdateRate;
  76. }
  77. }
  78. var rotQuery = EntityQueryEnumerator<RottingComponent, PerishableComponent, TransformComponent>();
  79. while (rotQuery.MoveNext(out var uid, out var rotting, out var perishable, out var xform))
  80. {
  81. if (_timing.CurTime < rotting.NextRotUpdate) // This is where it starts to get noticable on larger animals, no need to run every second
  82. continue;
  83. rotting.NextRotUpdate += rotting.RotUpdateRate;
  84. if (!IsRotProgressing(uid, perishable))
  85. continue;
  86. rotting.TotalRotTime += rotting.RotUpdateRate * GetRotRate(uid);
  87. if (rotting.DealDamage)
  88. {
  89. var damage = rotting.Damage * rotting.RotUpdateRate.TotalSeconds;
  90. _damageable.TryChangeDamage(uid, damage, true, false);
  91. }
  92. if (TryComp<RotIntoComponent>(uid, out var rotInto))
  93. {
  94. var stage = RotStage(uid, rotting, perishable);
  95. if (stage >= rotInto.Stage)
  96. {
  97. Spawn(rotInto.Entity, xform.Coordinates);
  98. QueueDel(uid);
  99. continue;
  100. }
  101. }
  102. if (!TryComp<PhysicsComponent>(uid, out var physics))
  103. continue;
  104. // We need a way to get the mass of the mob alone without armor etc in the future
  105. // or just remove the mass mechanics altogether because they aren't good.
  106. var molRate = perishable.MolsPerSecondPerUnitMass * (float)rotting.RotUpdateRate.TotalSeconds;
  107. var tileMix = _atmosphere.GetTileMixture(uid, excite: true);
  108. tileMix?.AdjustMoles(Gas.Ammonia, molRate * physics.FixturesMass);
  109. }
  110. }
  111. }