| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416 |
- using Content.Server.ParticleAccelerator.Components;
- using Content.Server.Power.Components;
- using Content.Shared.Database;
- using Content.Shared.Singularity.Components;
- using Robust.Shared.Utility;
- using System.Diagnostics;
- using Content.Server.Administration.Managers;
- using Content.Shared.CCVar;
- using Content.Shared.Power;
- using Robust.Shared.Audio;
- using Robust.Shared.Audio.Systems;
- using Robust.Shared.Player;
- namespace Content.Server.ParticleAccelerator.EntitySystems;
- public sealed partial class ParticleAcceleratorSystem
- {
- [Dependency] private readonly IAdminManager _adminManager = default!;
- [Dependency] private readonly SharedAudioSystem _audio = default!;
- private void InitializeControlBoxSystem()
- {
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, ComponentStartup>(OnComponentStartup);
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, ComponentShutdown>(OnComponentShutdown);
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, PowerChangedEvent>(OnControlBoxPowerChange);
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, ParticleAcceleratorSetEnableMessage>(OnUISetEnableMessage);
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, ParticleAcceleratorSetPowerStateMessage>(OnUISetPowerMessage);
- SubscribeLocalEvent<ParticleAcceleratorControlBoxComponent, ParticleAcceleratorRescanPartsMessage>(OnUIRescanMessage);
- }
- public override void Update(float frameTime)
- {
- var curTime = _gameTiming.CurTime;
- var query = EntityQueryEnumerator<ParticleAcceleratorControlBoxComponent>();
- while (query.MoveNext(out var uid, out var controller))
- {
- if (controller.Firing && curTime >= controller.NextFire)
- Fire(uid, curTime, controller);
- }
- }
- [Conditional("DEBUG")]
- private void EverythingIsWellToFire(ParticleAcceleratorControlBoxComponent controller)
- {
- DebugTools.Assert(controller.Powered);
- DebugTools.Assert(controller.SelectedStrength != ParticleAcceleratorPowerState.Standby);
- DebugTools.Assert(controller.Assembled);
- DebugTools.Assert(EntityManager.EntityExists(controller.PortEmitter));
- DebugTools.Assert(EntityManager.EntityExists(controller.ForeEmitter));
- DebugTools.Assert(EntityManager.EntityExists(controller.StarboardEmitter));
- }
- public void Fire(EntityUid uid, TimeSpan curTime, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- comp.LastFire = curTime;
- comp.NextFire = curTime + comp.ChargeTime;
- EverythingIsWellToFire(comp);
- var strength = comp.SelectedStrength;
- FireEmitter(comp.PortEmitter!.Value, strength);
- FireEmitter(comp.ForeEmitter!.Value, strength);
- FireEmitter(comp.StarboardEmitter!.Value, strength);
- }
- public void SwitchOn(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- DebugTools.Assert(comp.Assembled);
- if (comp.Enabled || !comp.CanBeEnabled)
- return;
- if (user is { } player)
- _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} has turned {ToPrettyString(uid)} on");
- comp.Enabled = true;
- UpdatePowerDraw(uid, comp);
- if (!TryComp<PowerConsumerComponent>(comp.PowerBox, out var powerConsumer)
- || powerConsumer.ReceivedPower >= powerConsumer.DrawRate * ParticleAcceleratorControlBoxComponent.RequiredPowerRatio)
- PowerOn(uid, comp);
- UpdateUI(uid, comp);
- }
- public void SwitchOff(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (!comp.Enabled)
- return;
- if (user is { } player)
- _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} has turned {ToPrettyString(uid)} off");
- comp.Enabled = false;
- SetStrength(uid, ParticleAcceleratorPowerState.Standby, user, comp);
- UpdatePowerDraw(uid, comp);
- PowerOff(uid, comp);
- UpdateUI(uid, comp);
- }
- public void PowerOn(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- DebugTools.Assert(comp.Enabled);
- DebugTools.Assert(comp.Assembled);
- if (comp.Powered)
- return;
- comp.Powered = true;
- UpdatePowerDraw(uid, comp);
- UpdateFiring(uid, comp);
- UpdatePartVisualStates(uid, comp);
- UpdateUI(uid, comp);
- }
- public void PowerOff(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (!comp.Powered)
- return;
- comp.Powered = false;
- UpdatePowerDraw(uid, comp);
- UpdateFiring(uid, comp);
- UpdatePartVisualStates(uid, comp);
- UpdateUI(uid, comp);
- }
- public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (comp.StrengthLocked)
- return;
- strength = (ParticleAcceleratorPowerState) MathHelper.Clamp(
- (int) strength,
- (int) ParticleAcceleratorPowerState.Standby,
- (int) comp.MaxStrength
- );
- if (strength == comp.SelectedStrength)
- return;
- if (user is { } player)
- {
- var impact = strength switch
- {
- ParticleAcceleratorPowerState.Standby => LogImpact.Low,
- ParticleAcceleratorPowerState.Level0
- or ParticleAcceleratorPowerState.Level1
- or ParticleAcceleratorPowerState.Level2 => LogImpact.Medium,
- ParticleAcceleratorPowerState.Level3 => LogImpact.Extreme,
- _ => throw new IndexOutOfRangeException(nameof(strength)),
- };
- _adminLogger.Add(LogType.Action, impact, $"{ToPrettyString(player):player} has set the strength of {ToPrettyString(uid)} to {strength}");
- var alertMinPowerState = (ParticleAcceleratorPowerState)_cfg.GetCVar(CCVars.AdminAlertParticleAcceleratorMinPowerState);
- if (strength >= alertMinPowerState)
- {
- var pos = Transform(uid);
- if (_gameTiming.CurTime > comp.EffectCooldown)
- {
- _chat.SendAdminAlert(player,
- Loc.GetString("particle-accelerator-admin-power-strength-warning",
- ("machine", ToPrettyString(uid)),
- ("powerState", GetPANumericalLevel(strength)),
- ("coordinates", pos.Coordinates)));
- _audio.PlayGlobal("/Audio/Misc/adminlarm.ogg",
- Filter.Empty().AddPlayers(_adminManager.ActiveAdmins),
- false,
- AudioParams.Default.WithVolume(-8f));
- comp.EffectCooldown = _gameTiming.CurTime + comp.CooldownDuration;
- }
- }
- }
- comp.SelectedStrength = strength;
- UpdateAppearance(uid, comp);
- UpdatePartVisualStates(uid, comp);
- if (comp.Enabled)
- {
- UpdatePowerDraw(uid, comp);
- UpdateFiring(uid, comp);
- }
- }
- private void UpdateFiring(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (!comp.Powered || comp.SelectedStrength < ParticleAcceleratorPowerState.Level0)
- {
- comp.Firing = false;
- return;
- }
- EverythingIsWellToFire(comp);
- var curTime = _gameTiming.CurTime;
- comp.LastFire = curTime;
- comp.NextFire = curTime + comp.ChargeTime;
- comp.Firing = true;
- }
- private void UpdatePowerDraw(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (!TryComp<PowerConsumerComponent>(comp.PowerBox, out var powerConsumer))
- return;
- var powerDraw = comp.BasePowerDraw;
- if (comp.Enabled)
- powerDraw += comp.LevelPowerDraw * (int) comp.SelectedStrength;
- powerConsumer.DrawRate = powerDraw;
- }
- public void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- if (!_uiSystem.HasUi(uid, ParticleAcceleratorControlBoxUiKey.Key))
- return;
- var draw = 0f;
- var receive = 0f;
- if (TryComp<PowerConsumerComponent>(comp.PowerBox, out var powerConsumer))
- {
- draw = powerConsumer.DrawRate;
- receive = powerConsumer.ReceivedPower;
- }
- _uiSystem.SetUiState(uid,
- ParticleAcceleratorControlBoxUiKey.Key,
- new ParticleAcceleratorUIState(
- comp.Assembled,
- comp.Enabled,
- comp.SelectedStrength,
- (int) draw,
- (int) receive,
- comp.StarboardEmitter != null,
- comp.ForeEmitter != null,
- comp.PortEmitter != null,
- comp.PowerBox != null,
- comp.FuelChamber != null,
- comp.EndCap != null,
- comp.InterfaceDisabled,
- comp.MaxStrength,
- comp.StrengthLocked
- ));
- }
- private void UpdateAppearance(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null, AppearanceComponent? appearance = null)
- {
- if (!Resolve(uid, ref comp))
- return;
- _appearanceSystem.SetData(
- uid,
- ParticleAcceleratorVisuals.VisualState,
- TryComp<ApcPowerReceiverComponent>(uid, out var apcPower) && !apcPower.Powered
- ? ParticleAcceleratorVisualState.Unpowered
- : (ParticleAcceleratorVisualState) comp.SelectedStrength,
- appearance
- );
- }
- private void UpdatePartVisualStates(EntityUid uid, ParticleAcceleratorControlBoxComponent? controller = null)
- {
- if (!Resolve(uid, ref controller))
- return;
- var state = controller.Powered ? (ParticleAcceleratorVisualState) controller.SelectedStrength : ParticleAcceleratorVisualState.Unpowered;
- // UpdatePartVisualState(ControlBox); (We are the control box)
- if (controller.FuelChamber.HasValue)
- _appearanceSystem.SetData(controller.FuelChamber!.Value, ParticleAcceleratorVisuals.VisualState, state);
- if (controller.PowerBox.HasValue)
- _appearanceSystem.SetData(controller.PowerBox!.Value, ParticleAcceleratorVisuals.VisualState, state);
- if (controller.PortEmitter.HasValue)
- _appearanceSystem.SetData(controller.PortEmitter!.Value, ParticleAcceleratorVisuals.VisualState, state);
- if (controller.ForeEmitter.HasValue)
- _appearanceSystem.SetData(controller.ForeEmitter!.Value, ParticleAcceleratorVisuals.VisualState, state);
- if (controller.StarboardEmitter.HasValue)
- _appearanceSystem.SetData(controller.StarboardEmitter!.Value, ParticleAcceleratorVisuals.VisualState, state);
- //no endcap because it has no powerlevel-sprites
- }
- private IEnumerable<EntityUid> AllParts(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
- {
- if (Resolve(uid, ref comp))
- {
- if (comp.FuelChamber.HasValue)
- yield return comp.FuelChamber.Value;
- if (comp.EndCap.HasValue)
- yield return comp.EndCap.Value;
- if (comp.PowerBox.HasValue)
- yield return comp.PowerBox.Value;
- if (comp.PortEmitter.HasValue)
- yield return comp.PortEmitter.Value;
- if (comp.ForeEmitter.HasValue)
- yield return comp.ForeEmitter.Value;
- if (comp.StarboardEmitter.HasValue)
- yield return comp.StarboardEmitter.Value;
- }
- }
- private void OnComponentStartup(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ComponentStartup args)
- {
- if (TryComp<ParticleAcceleratorPartComponent>(uid, out var part))
- part.Master = uid;
- }
- private void OnComponentShutdown(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ComponentShutdown args)
- {
- if (TryComp<ParticleAcceleratorPartComponent>(uid, out var partStatus))
- partStatus.Master = null;
- var partQuery = GetEntityQuery<ParticleAcceleratorPartComponent>();
- foreach (var part in AllParts(uid, comp))
- {
- if (partQuery.TryGetComponent(part, out var partData))
- partData.Master = null;
- }
- }
- // This is the power state for the PA control box itself.
- // Keep in mind that the PA itself can keep firing as long as the HV cable under the power box has... power.
- private void OnControlBoxPowerChange(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ref PowerChangedEvent args)
- {
- UpdateAppearance(uid, comp);
- if (!args.Powered)
- _uiSystem.CloseUi(uid, ParticleAcceleratorControlBoxUiKey.Key);
- }
- private void OnUISetEnableMessage(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ParticleAcceleratorSetEnableMessage msg)
- {
- if (!ParticleAcceleratorControlBoxUiKey.Key.Equals(msg.UiKey))
- return;
- if (comp.InterfaceDisabled)
- return;
- if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower) && !apcPower.Powered)
- return;
- if (msg.Enabled)
- {
- if (comp.Assembled)
- SwitchOn(uid, msg.Actor, comp);
- }
- else
- SwitchOff(uid, msg.Actor, comp);
- UpdateUI(uid, comp);
- }
- private void OnUISetPowerMessage(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ParticleAcceleratorSetPowerStateMessage msg)
- {
- if (!ParticleAcceleratorControlBoxUiKey.Key.Equals(msg.UiKey))
- return;
- if (comp.InterfaceDisabled)
- return;
- if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower) && !apcPower.Powered)
- return;
- SetStrength(uid, msg.State, msg.Actor, comp);
- UpdateUI(uid, comp);
- }
- private void OnUIRescanMessage(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ParticleAcceleratorRescanPartsMessage msg)
- {
- if (!ParticleAcceleratorControlBoxUiKey.Key.Equals(msg.UiKey))
- return;
- if (comp.InterfaceDisabled)
- return;
- if (TryComp<ApcPowerReceiverComponent>(uid, out var apcPower) && !apcPower.Powered)
- return;
- RescanParts(uid, msg.Actor, comp);
- UpdateUI(uid, comp);
- }
- public static int GetPANumericalLevel(ParticleAcceleratorPowerState state)
- {
- return state switch
- {
- ParticleAcceleratorPowerState.Level0 => 1,
- ParticleAcceleratorPowerState.Level1 => 2,
- ParticleAcceleratorPowerState.Level2 => 3,
- ParticleAcceleratorPowerState.Level3 => 4,
- _ => 0
- };
- }
- }
|