using Content.Server.Body.Systems;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Stack;
using Content.Server.Storage.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts;
using Content.Shared.Body.Components;
using Content.Shared.Damage;
using Content.Shared.Power;
using Content.Shared.Verbs;
using Content.Shared.Whitelist;
using Content.Shared.Xenoarchaeology.Equipment;
using Robust.Shared.Collections;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
///
public sealed class ArtifactCrusherSystem : SharedArtifactCrusherSystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ArtifactSystem _artifact = default!;
[Dependency] private readonly BodySystem _body = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly StackSystem _stack = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
///
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent>(OnGetVerbs);
SubscribeLocalEvent(OnPowerChanged);
}
private void OnGetVerbs(Entity ent, ref GetVerbsEvent args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands == null || ent.Comp.Crushing)
return;
if (!TryComp(ent, out var entityStorageComp) ||
entityStorageComp.Contents.ContainedEntities.Count == 0)
return;
if (!this.IsPowered(ent, EntityManager))
return;
var verb = new AlternativeVerb
{
Text = Loc.GetString("artifact-crusher-verb-start-crushing"),
Priority = 2,
Act = () => StartCrushing((ent, ent.Comp, entityStorageComp))
};
args.Verbs.Add(verb);
}
private void OnPowerChanged(Entity ent, ref PowerChangedEvent args)
{
if (!args.Powered)
StopCrushing(ent);
}
public void StartCrushing(Entity ent)
{
var (uid, crusher, _) = ent;
if (crusher.Crushing)
return;
if (crusher.AutoLock)
_popup.PopupEntity(Loc.GetString("artifact-crusher-autolocks-enable"), uid);
crusher.Crushing = true;
crusher.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
crusher.CrushEndTime = _timing.CurTime + crusher.CrushDuration;
crusher.CrushingSoundEntity = AudioSystem.PlayPvs(crusher.CrushingSound, ent);
Appearance.SetData(ent, ArtifactCrusherVisuals.Crushing, true);
Dirty(ent, ent.Comp1);
}
public void FinishCrushing(Entity ent)
{
var (_, crusher, storage) = ent;
StopCrushing((ent, ent.Comp1), false);
AudioSystem.PlayPvs(crusher.CrushingCompleteSound, ent);
crusher.CrushingSoundEntity = null;
Dirty(ent, ent.Comp1);
var contents = new ValueList(storage.Contents.ContainedEntities);
var coords = Transform(ent).Coordinates;
foreach (var contained in contents)
{
if (_whitelistSystem.IsWhitelistPass(crusher.CrushingWhitelist, contained))
{
var amount = _random.Next(crusher.MinFragments, crusher.MaxFragments);
var stacks = _stack.SpawnMultiple(crusher.FragmentStackProtoId, amount, coords);
foreach (var stack in stacks)
{
ContainerSystem.Insert((stack, null, null, null), crusher.OutputContainer);
}
_artifact.ForceActivateArtifact(contained);
}
if (!TryComp(contained, out var body))
Del(contained);
var gibs = _body.GibBody(contained, body: body, gibOrgans: true);
foreach (var gib in gibs)
{
ContainerSystem.Insert((gib, null, null, null), crusher.OutputContainer);
}
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator();
while (query.MoveNext(out var uid, out var crusher, out var storage))
{
if (!crusher.Crushing)
continue;
if (crusher.NextSecond < _timing.CurTime)
{
var contents = new ValueList(storage.Contents.ContainedEntities);
foreach (var contained in contents)
{
_damageable.TryChangeDamage(contained, crusher.CrushingDamage);
}
crusher.NextSecond += TimeSpan.FromSeconds(1);
Dirty(uid, crusher);
}
if (crusher.CrushEndTime < _timing.CurTime)
{
FinishCrushing((uid, crusher, storage));
}
}
}
}