CatStation/Content.Server/Spreader/KudzuSystem.cs
Eveloop 22a547c7c8
Use dependency injection for EntityQuery<T>s in Content.Server (#43566)
* Replace usages of EntityQuery with dependency injected ones in Content.Server

* Remove unused EntityQuery dependencies

* Restore CheckPressureAndFire override method

* Revert EntityQuery refactor changes to DisposalTubeSystem.cs & DisposableSystem.cs

* Infer Transform/Metadata directly instead of passing (#43479)

* Resolve RA0049, RA0051 errors (#43479)

* Resolve RA0049, RA0051 errors (#43479)

* Apply suggestions from code review

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>

---------

Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
2026-05-17 15:59:37 +00:00

155 lines
5.5 KiB
C#

using Content.Shared.Damage.Components;
using Content.Shared.Damage.Systems;
using Content.Shared.Spreader;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Spreader;
public sealed partial class KudzuSystem : EntitySystem
{
[Dependency] private IGameTiming _timing = default!;
[Dependency] private IRobustRandom _robustRandom = default!;
[Dependency] private SharedMapSystem _map = default!;
[Dependency] private SharedAppearanceSystem _appearance = default!;
[Dependency] private DamageableSystem _damageable = default!;
[Dependency] private EntityQuery<AppearanceComponent> _appearanceQuery = default!;
[Dependency] private EntityQuery<KudzuComponent> _kudzuQuery = default!;
[Dependency] private EntityQuery<DamageableComponent> _damageableQuery = default!;
private static readonly ProtoId<EdgeSpreaderPrototype> KudzuGroup = "Kudzu";
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<KudzuComponent, ComponentStartup>(SetupKudzu);
SubscribeLocalEvent<KudzuComponent, SpreadNeighborsEvent>(OnKudzuSpread);
SubscribeLocalEvent<KudzuComponent, DamageChangedEvent>(OnDamageChanged);
}
private void OnDamageChanged(EntityUid uid, KudzuComponent component, DamageChangedEvent args)
{
// Every time we take any damage, we reduce growth depending on all damage over the growth impact
// So the kudzu gets slower growing the more it is hurt.
var growthDamage = (int) (_damageable.GetTotalDamage((uid, args.Damageable)) / component.GrowthHealth);
if (growthDamage > 0)
{
if (!EnsureComp<GrowingKudzuComponent>(uid, out _))
component.GrowthLevel = 3;
component.GrowthLevel = Math.Max(1, component.GrowthLevel - growthDamage);
if (TryComp<AppearanceComponent>(uid, out var appearance))
{
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, component.GrowthLevel, appearance);
}
}
}
private void OnKudzuSpread(EntityUid uid, KudzuComponent component, ref SpreadNeighborsEvent args)
{
if (component.GrowthLevel < 3)
return;
if (args.NeighborFreeTiles.Count == 0)
{
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
if (!_robustRandom.Prob(component.SpreadChance))
return;
var prototype = MetaData(uid).EntityPrototype?.ID;
if (prototype == null)
{
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
foreach (var neighbor in args.NeighborFreeTiles)
{
var neighborUid = Spawn(prototype, _map.GridTileToLocal(neighbor.Tile.GridUid, neighbor.Grid, neighbor.Tile.GridIndices));
DebugTools.Assert(HasComp<EdgeSpreaderComponent>(neighborUid));
DebugTools.Assert(HasComp<ActiveEdgeSpreaderComponent>(neighborUid));
DebugTools.Assert(Comp<EdgeSpreaderComponent>(neighborUid).Id == KudzuGroup);
args.Updates--;
if (args.Updates <= 0)
return;
}
}
private void SetupKudzu(EntityUid uid, KudzuComponent component, ComponentStartup args)
{
if (!TryComp<AppearanceComponent>(uid, out var appearance))
{
return;
}
_appearance.SetData(uid, KudzuVisuals.Variant, _robustRandom.Next(1, component.SpriteVariants), appearance);
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, 1, appearance);
}
/// <inheritdoc/>
public override void Update(float frameTime)
{
var kudzuEnumerator = EntityQueryEnumerator<GrowingKudzuComponent>();
var curTime = _timing.CurTime;
while (kudzuEnumerator.MoveNext(out var uid, out var grow))
{
if (grow.NextTick > curTime)
continue;
grow.NextTick = curTime + TimeSpan.FromSeconds(0.5);
if (!_kudzuQuery.TryGetComponent(uid, out var kudzu))
{
RemCompDeferred(uid, grow);
continue;
}
if (!_robustRandom.Prob(kudzu.GrowthTickChance))
{
continue;
}
if (_damageableQuery.TryGetComponent(uid, out var damage))
{
var totalDamage = _damageable.GetTotalDamage((uid, damage));
if (totalDamage > 1.0)
{
if (kudzu.DamageRecovery != null)
{
// This kudzu features healing, so Gradually heal
_damageable.TryChangeDamage(uid, kudzu.DamageRecovery, true);
}
if (totalDamage >= kudzu.GrowthBlock)
{
// Don't grow when quite damaged
if (_robustRandom.Prob(0.95f))
{
continue;
}
}
}
}
kudzu.GrowthLevel += 1;
if (kudzu.GrowthLevel >= 3)
{
// why cache when you can simply cease to be? Also saves a bit of memory/time.
RemCompDeferred(uid, grow);
}
if (_appearanceQuery.TryGetComponent(uid, out var appearance))
{
_appearance.SetData(uid, KudzuVisuals.GrowthLevel, kudzu.GrowthLevel, appearance);
}
}
}
}