using Content.Server.Body.Systems; using Content.Server.Popups; using Content.Shared.Body.Components; using Content.Shared.Examine; using Content.Shared.Popups; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Events; using Robust.Shared.Physics.Systems; using Robust.Shared.Random; namespace Content.Server.ImmovableRod; public sealed class ImmovableRodSystem : EntitySystem { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly BodySystem _bodySystem = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly SharedAudioSystem _audio = default!; public override void Update(float frameTime) { base.Update(frameTime); // we are deliberately including paused entities. rod hungers for all foreach (var (rod, trans) in EntityManager.EntityQuery(true)) { if (!rod.DestroyTiles) continue; if (!TryComp(trans.GridUid, out var grid)) continue; grid.SetTile(trans.Coordinates, Tile.Empty); } } public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnCollide); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnExamined); } private void OnMapInit(EntityUid uid, ImmovableRodComponent component, MapInitEvent args) { if (EntityManager.TryGetComponent(uid, out PhysicsComponent? phys)) { _physics.SetLinearDamping(phys, 0f); _physics.SetFriction(phys, 0f); _physics.SetBodyStatus(phys, BodyStatus.InAir); if (!component.RandomizeVelocity) return; var xform = Transform(uid); var vel = component.DirectionOverride.Degrees switch { 0f => _random.NextVector2(component.MinSpeed, component.MaxSpeed), _ => xform.WorldRotation.RotateVec(component.DirectionOverride.ToVec()) * _random.NextFloat(component.MinSpeed, component.MaxSpeed) }; _physics.ApplyLinearImpulse(uid, vel, body: phys); xform.LocalRotation = (vel - xform.WorldPosition).ToWorldAngle() + MathHelper.PiOver2; } } private void OnCollide(EntityUid uid, ImmovableRodComponent component, ref StartCollideEvent args) { var ent = args.OtherEntity; if (_random.Prob(component.HitSoundProbability)) { _audio.PlayPvs(component.Sound, uid); } if (HasComp(ent)) { // oh god. var coords = Transform(uid).Coordinates; _popup.PopupCoordinates(Loc.GetString("immovable-rod-collided-rod-not-good"), coords, PopupType.LargeCaution); Del(uid); Del(ent); Spawn("Singularity", coords); return; } // gib em if (TryComp(ent, out var body)) { component.MobCount++; _popup.PopupEntity(Loc.GetString("immovable-rod-penetrated-mob", ("rod", uid), ("mob", ent)), uid, PopupType.LargeCaution); _bodySystem.GibBody(ent, body: body); return; } QueueDel(ent); } private void OnExamined(EntityUid uid, ImmovableRodComponent component, ExaminedEvent args) { if (component.MobCount == 0) { args.PushText(Loc.GetString("immovable-rod-consumed-none", ("rod", uid))); } else { args.PushText(Loc.GetString("immovable-rod-consumed-souls", ("rod", uid), ("amount", component.MobCount))); } } }