KudzuSystem.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using Content.Shared.Damage;
  2. using Content.Shared.Spreader;
  3. using Robust.Shared.Random;
  4. using Robust.Shared.Timing;
  5. using Robust.Shared.Utility;
  6. namespace Content.Server.Spreader;
  7. public sealed class KudzuSystem : EntitySystem
  8. {
  9. [Dependency] private readonly IGameTiming _timing = default!;
  10. [Dependency] private readonly IRobustRandom _robustRandom = default!;
  11. [Dependency] private readonly SharedMapSystem _map = default!;
  12. [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
  13. [Dependency] private readonly DamageableSystem _damageable = default!;
  14. [ValidatePrototypeId<EdgeSpreaderPrototype>]
  15. private const string KudzuGroup = "Kudzu";
  16. /// <inheritdoc/>
  17. public override void Initialize()
  18. {
  19. SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
  20. SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
  21. SubscribeLocalEvent<KudzuComponent, DamageChangedEvent>(OnDamageChanged);
  22. }
  23. private void OnDamageChanged(EntityUid uid, KudzuComponent component, DamageChangedEvent args)
  24. {
  25. // Every time we take any damage, we reduce growth depending on all damage over the growth impact
  26. // So the kudzu gets slower growing the more it is hurt.
  27. var growthDamage = (int) (args.Damageable.TotalDamage / component.GrowthHealth);
  28. if (growthDamage > 0)
  29. {
  30. if (!EnsureComp<GrowingKudzuComponent>(uid, out _))
  31. component.GrowthLevel = 3;
  32. component.GrowthLevel = Math.Max(1, component.GrowthLevel - growthDamage);
  33. if (EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
  34. {
  35. _appearance.SetData(uid, KudzuVisuals.GrowthLevel, component.GrowthLevel, appearance);
  36. }
  37. }
  38. }
  39. private void OnKudzuSpread(EntityUid uid, KudzuComponent component, ref SpreadNeighborsEvent args)
  40. {
  41. if (component.GrowthLevel < 3)
  42. return;
  43. if (args.NeighborFreeTiles.Count == 0)
  44. {
  45. RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
  46. return;
  47. }
  48. if (!_robustRandom.Prob(component.SpreadChance))
  49. return;
  50. var prototype = MetaData(uid).EntityPrototype?.ID;
  51. if (prototype == null)
  52. {
  53. RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
  54. return;
  55. }
  56. foreach (var neighbor in args.NeighborFreeTiles)
  57. {
  58. var neighborUid = Spawn(prototype, _map.GridTileToLocal(neighbor.Tile.GridUid, neighbor.Grid, neighbor.Tile.GridIndices));
  59. DebugTools.Assert(HasComp<EdgeSpreaderComponent>(neighborUid));
  60. DebugTools.Assert(HasComp<ActiveEdgeSpreaderComponent>(neighborUid));
  61. DebugTools.Assert(Comp<EdgeSpreaderComponent>(neighborUid).Id == KudzuGroup);
  62. args.Updates--;
  63. if (args.Updates <= 0)
  64. return;
  65. }
  66. }
  67. private void SetupKudzu(EntityUid uid, KudzuComponent component, ComponentStartup args)
  68. {
  69. if (!EntityManager.TryGetComponent<AppearanceComponent>(uid, out var appearance))
  70. {
  71. return;
  72. }
  73. _appearance.SetData(uid, KudzuVisuals.Variant, _robustRandom.Next(1, component.SpriteVariants), appearance);
  74. _appearance.SetData(uid, KudzuVisuals.GrowthLevel, 1, appearance);
  75. }
  76. /// <inheritdoc/>
  77. public override void Update(float frameTime)
  78. {
  79. var appearanceQuery = GetEntityQuery<AppearanceComponent>();
  80. var query = EntityQueryEnumerator<GrowingKudzuComponent>();
  81. var kudzuQuery = GetEntityQuery<KudzuComponent>();
  82. var damageableQuery = GetEntityQuery<DamageableComponent>();
  83. var curTime = _timing.CurTime;
  84. while (query.MoveNext(out var uid, out var grow))
  85. {
  86. if (grow.NextTick > curTime)
  87. continue;
  88. grow.NextTick = curTime + TimeSpan.FromSeconds(0.5);
  89. if (!kudzuQuery.TryGetComponent(uid, out var kudzu))
  90. {
  91. RemCompDeferred(uid, grow);
  92. continue;
  93. }
  94. if (!_robustRandom.Prob(kudzu.GrowthTickChance))
  95. {
  96. continue;
  97. }
  98. if (damageableQuery.TryGetComponent(uid, out var damage))
  99. {
  100. if (damage.TotalDamage > 1.0)
  101. {
  102. if (kudzu.DamageRecovery != null)
  103. {
  104. // This kudzu features healing, so Gradually heal
  105. _damageable.TryChangeDamage(uid, kudzu.DamageRecovery, true);
  106. }
  107. if (damage.TotalDamage >= kudzu.GrowthBlock)
  108. {
  109. // Don't grow when quite damaged
  110. if (_robustRandom.Prob(0.95f))
  111. {
  112. continue;
  113. }
  114. }
  115. }
  116. }
  117. kudzu.GrowthLevel += 1;
  118. if (kudzu.GrowthLevel >= 3)
  119. {
  120. // why cache when you can simply cease to be? Also saves a bit of memory/time.
  121. RemCompDeferred(uid, grow);
  122. }
  123. if (appearanceQuery.TryGetComponent(uid, out var appearance))
  124. {
  125. _appearance.SetData(uid, KudzuVisuals.GrowthLevel, kudzu.GrowthLevel, appearance);
  126. }
  127. }
  128. }
  129. }