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)); } } } }