Converts the particle accelerator over to ECS + misc (#17075)
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
||||
using Content.Server.Mind.Components;
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Utility;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems;
|
||||
|
||||
@@ -7,11 +13,361 @@ public sealed partial class ParticleAcceleratorSystem
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
private static void OnControlBoxPowerChange(EntityUid uid, ParticleAcceleratorControlBoxComponent component, ref PowerChangedEvent args)
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
component.OnPowerStateChanged(args);
|
||||
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, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
|
||||
DebugTools.Assert(comp.Assembled);
|
||||
|
||||
if (comp.Enabled || !comp.CanBeEnabled)
|
||||
return;
|
||||
|
||||
if (HasComp<MindComponent>(user?.AttachedEntity))
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{EntityManager.ToPrettyString((EntityUid) user!.AttachedEntity):player} has turned {EntityManager.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, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
if (!comp.Enabled)
|
||||
return;
|
||||
|
||||
if (HasComp<MindComponent>(user?.AttachedEntity))
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low, $"{EntityManager.ToPrettyString((EntityUid) user!.AttachedEntity):player} has turned {EntityManager.ToPrettyString(uid)} off");
|
||||
|
||||
comp.Enabled = false;
|
||||
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, IPlayerSession? 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 (HasComp<MindComponent>(user?.AttachedEntity))
|
||||
{
|
||||
var impact = strength switch
|
||||
{
|
||||
ParticleAcceleratorPowerState.Standby => LogImpact.Low,
|
||||
ParticleAcceleratorPowerState.Level0 => LogImpact.Medium,
|
||||
ParticleAcceleratorPowerState.Level1 => LogImpact.High,
|
||||
ParticleAcceleratorPowerState.Level2
|
||||
or ParticleAcceleratorPowerState.Level3
|
||||
or _ => LogImpact.Extreme,
|
||||
};
|
||||
|
||||
_adminLogger.Add(LogType.Action, impact, $"{EntityManager.ToPrettyString(user!.AttachedEntity!.Value):player} has set the strength of {EntityManager.ToPrettyString(uid)} to {strength}");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp = null)
|
||||
{
|
||||
if (!Resolve(uid, ref comp))
|
||||
return;
|
||||
if (!_uiSystem.TryGetUi(uid, ParticleAcceleratorControlBoxUiKey.Key, out var bui))
|
||||
return;
|
||||
|
||||
var draw = 0f;
|
||||
var receive = 0f;
|
||||
|
||||
if (TryComp<PowerConsumerComponent>(comp.PowerBox, out var powerConsumer))
|
||||
{
|
||||
draw = powerConsumer.DrawRate;
|
||||
receive = powerConsumer.ReceivedPower;
|
||||
}
|
||||
|
||||
_uiSystem.SetUiState(bui, 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.TryCloseAll(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, (IPlayerSession?) msg.Session, comp);
|
||||
}
|
||||
else
|
||||
SwitchOff(uid, (IPlayerSession?) msg.Session, 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, (IPlayerSession?) msg.Session, 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, (IPlayerSession?) msg.Session, comp);
|
||||
|
||||
UpdateUI(uid, comp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using Content.Server.Singularity.Components;
|
||||
using Content.Shared.Projectiles;
|
||||
using Content.Shared.Singularity.Components;
|
||||
using Robust.Shared.Physics.Components;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems;
|
||||
|
||||
public sealed partial class ParticleAcceleratorSystem
|
||||
{
|
||||
private void FireEmitter(EntityUid uid, ParticleAcceleratorPowerState strength, ParticleAcceleratorEmitterComponent? emitter = null)
|
||||
{
|
||||
if (!Resolve(uid, ref emitter))
|
||||
return;
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
if (!xformQuery.TryGetComponent(uid, out var xform))
|
||||
{
|
||||
Logger.Error("ParticleAccelerator attempted to emit a particle without (having) a transform from which to base its initial position and orientation.");
|
||||
return;
|
||||
}
|
||||
|
||||
var emitted = Spawn(emitter.EmittedPrototype, xform.Coordinates);
|
||||
|
||||
if (xformQuery.TryGetComponent(emitted, out var particleXform))
|
||||
_transformSystem.SetLocalRotation(emitted, xform.LocalRotation, particleXform);
|
||||
|
||||
if (TryComp<PhysicsComponent>(emitted, out var particlePhys))
|
||||
{
|
||||
var angle = _transformSystem.GetWorldRotation(uid, xformQuery);
|
||||
_physicsSystem.SetBodyStatus(particlePhys, BodyStatus.InAir);
|
||||
|
||||
var velocity = angle.ToWorldVec() * 20f;
|
||||
if (TryComp<PhysicsComponent>(uid, out var phys))
|
||||
velocity += phys.LinearVelocity; // Inherit velocity from parent so if the clown has strapped a dozen engines to departures we don't outpace the particles.
|
||||
|
||||
_physicsSystem.SetLinearVelocity(emitted, velocity, body: particlePhys);
|
||||
}
|
||||
|
||||
if (TryComp<ProjectileComponent>(emitted, out var proj))
|
||||
_projectileSystem.SetShooter(proj, uid);
|
||||
|
||||
if (TryComp<SinguloFoodComponent>(emitted, out var food))
|
||||
{
|
||||
// TODO: Unhardcode this.
|
||||
food.Energy = strength switch
|
||||
{
|
||||
ParticleAcceleratorPowerState.Standby => 0,
|
||||
ParticleAcceleratorPowerState.Level0 => 1,
|
||||
ParticleAcceleratorPowerState.Level1 => 3,
|
||||
ParticleAcceleratorPowerState.Level2 => 6,
|
||||
ParticleAcceleratorPowerState.Level3 => 10,
|
||||
_ => 0,
|
||||
} * 10;
|
||||
}
|
||||
|
||||
if (TryComp<ParticleProjectileComponent>(emitted, out var particle))
|
||||
particle.State = strength;
|
||||
|
||||
_appearanceSystem.SetData(emitted, ParticleAcceleratorVisuals.VisualState, strength);
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,162 @@
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Physics.Events;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ParticleAcceleratorSystem
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public sealed partial class ParticleAcceleratorSystem
|
||||
private void InitializePartSystem()
|
||||
{
|
||||
private void InitializePartSystem()
|
||||
SubscribeLocalEvent<ParticleAcceleratorPartComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
SubscribeLocalEvent<ParticleAcceleratorPartComponent, MoveEvent>(OnMoveEvent);
|
||||
SubscribeLocalEvent<ParticleAcceleratorPartComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
|
||||
}
|
||||
|
||||
public void RescanParts(EntityUid uid, IPlayerSession? user = null, ParticleAcceleratorControlBoxComponent? controller = null)
|
||||
{
|
||||
if (!Resolve(uid, ref controller))
|
||||
return;
|
||||
|
||||
SwitchOff(uid, user, controller);
|
||||
|
||||
var partQuery = GetEntityQuery<ParticleAcceleratorPartComponent>();
|
||||
foreach (var part in AllParts(uid, controller))
|
||||
{
|
||||
SubscribeLocalEvent<ParticleAcceleratorPartComponent, MoveEvent>(OnMoveEvent);
|
||||
SubscribeLocalEvent<ParticleAcceleratorPartComponent, PhysicsBodyTypeChangedEvent>(BodyTypeChanged);
|
||||
if (partQuery.TryGetComponent(part, out var partState))
|
||||
partState.Master = null;
|
||||
}
|
||||
|
||||
private static void BodyTypeChanged(
|
||||
EntityUid uid,
|
||||
ParticleAcceleratorPartComponent component,
|
||||
ref PhysicsBodyTypeChangedEvent args)
|
||||
controller.Assembled = false;
|
||||
controller.FuelChamber = null;
|
||||
controller.EndCap = null;
|
||||
controller.PowerBox = null;
|
||||
controller.PortEmitter = null;
|
||||
controller.ForeEmitter = null;
|
||||
controller.StarboardEmitter = null;
|
||||
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
if (!xformQuery.TryGetComponent(uid, out var xform) || !xform.Anchored)
|
||||
return;
|
||||
|
||||
var gridUid = xform.GridUid;
|
||||
if (gridUid == null || gridUid != xform.ParentUid || !_mapManager.TryGetGrid(gridUid, out var grid))
|
||||
return;
|
||||
|
||||
// Find fuel chamber first by scanning cardinals.
|
||||
var fuelQuery = GetEntityQuery<ParticleAcceleratorFuelChamberComponent>();
|
||||
foreach (var adjacent in grid.GetCardinalNeighborCells(xform.Coordinates))
|
||||
{
|
||||
component.OnAnchorChanged();
|
||||
if (fuelQuery.HasComponent(adjacent)
|
||||
&& partQuery.TryGetComponent(adjacent, out var partState)
|
||||
&& partState.Master == null)
|
||||
{
|
||||
controller.FuelChamber = adjacent;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private static void OnMoveEvent(EntityUid uid, ParticleAcceleratorPartComponent component, ref MoveEvent args)
|
||||
if (controller.FuelChamber == null)
|
||||
{
|
||||
component.Moved();
|
||||
UpdateUI(uid, controller);
|
||||
return;
|
||||
}
|
||||
|
||||
// Align ourselves to match fuel chamber orientation.
|
||||
// This means that if you mess up the orientation of the control box it's not a big deal,
|
||||
// because the sprite is far from obvious about the orientation.
|
||||
var fuelXform = xformQuery.GetComponent(controller.FuelChamber!.Value);
|
||||
var rotation = fuelXform.LocalRotation;
|
||||
_transformSystem.SetLocalRotation(uid, rotation, xform);
|
||||
|
||||
// Calculate offsets for each of the parts of the PA.
|
||||
// These are all done relative to the fuel chamber BC that is basically the center of the machine.
|
||||
var positionFuelChamber = grid.TileIndicesFor(fuelXform.Coordinates); // //
|
||||
var positionEndCap = positionFuelChamber + (Vector2i) rotation.RotateVec((0, 1)); // n // n: End Cap
|
||||
var positionPowerBox = positionFuelChamber + (Vector2i) rotation.RotateVec((0, -1)); // CF // C: Control Box, F: Fuel Chamber
|
||||
var positionPortEmitter = positionFuelChamber + (Vector2i) rotation.RotateVec((1, -2)); // P // P: Power Box
|
||||
var positionForeEmitter = positionFuelChamber + (Vector2i) rotation.RotateVec((0, -2)); // EEE // E: Emitter (Starboard, Fore, Port)
|
||||
var positionStarboardEmitter = positionFuelChamber + (Vector2i) rotation.RotateVec((-1, -2)); // //
|
||||
|
||||
ScanPart<ParticleAcceleratorEndCapComponent>(gridUid!.Value, positionEndCap, rotation, out controller.EndCap, out var _, grid);
|
||||
ScanPart<ParticleAcceleratorPowerBoxComponent>(gridUid!.Value, positionPowerBox, rotation, out controller.PowerBox, out var _, grid);
|
||||
|
||||
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionPortEmitter, rotation, out controller.PortEmitter, out var portEmitter, grid)
|
||||
|| portEmitter!.Type != ParticleAcceleratorEmitterType.Port)
|
||||
controller.PortEmitter = null;
|
||||
|
||||
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionForeEmitter, rotation, out controller.ForeEmitter, out var foreEmitter, grid)
|
||||
|| foreEmitter!.Type != ParticleAcceleratorEmitterType.Fore)
|
||||
controller.ForeEmitter = null;
|
||||
|
||||
if (!ScanPart<ParticleAcceleratorEmitterComponent>(gridUid!.Value, positionStarboardEmitter, rotation, out controller.StarboardEmitter, out var starboardEmitter, grid)
|
||||
|| starboardEmitter!.Type != ParticleAcceleratorEmitterType.Starboard)
|
||||
controller.StarboardEmitter = null;
|
||||
|
||||
controller.Assembled =
|
||||
controller.FuelChamber.HasValue
|
||||
&& controller.EndCap.HasValue
|
||||
&& controller.PowerBox.HasValue
|
||||
&& controller.PortEmitter.HasValue
|
||||
&& controller.ForeEmitter.HasValue
|
||||
&& controller.StarboardEmitter.HasValue;
|
||||
|
||||
foreach (var part in AllParts(uid, controller))
|
||||
{
|
||||
if (partQuery.TryGetComponent(part, out var partState))
|
||||
partState.Master = uid;
|
||||
}
|
||||
|
||||
UpdatePowerDraw(uid, controller);
|
||||
UpdateUI(uid, controller);
|
||||
}
|
||||
|
||||
private bool ScanPart<T>(EntityUid uid, Vector2i coordinates, Angle? rotation, [NotNullWhen(true)] out EntityUid? part, [NotNullWhen(true)] out T? comp, MapGridComponent? grid = null)
|
||||
where T : Component
|
||||
{
|
||||
if (!Resolve(uid, ref grid))
|
||||
{
|
||||
part = null;
|
||||
comp = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
var compQuery = GetEntityQuery<T>();
|
||||
foreach (var entity in grid.GetAnchoredEntities(coordinates))
|
||||
{
|
||||
if (compQuery.TryGetComponent(entity, out comp)
|
||||
&& TryComp<ParticleAcceleratorPartComponent>(entity, out var partState) && partState.Master == null
|
||||
&& (rotation == null || MathHelper.CloseTo(Transform(entity).LocalRotation.Theta, rotation!.Value.Theta)))
|
||||
{
|
||||
part = entity;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
part = null;
|
||||
comp = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(EntityUid uid, ParticleAcceleratorPartComponent comp, ComponentShutdown args)
|
||||
{
|
||||
if (EntityManager.EntityExists(comp.Master))
|
||||
RescanParts(comp.Master!.Value);
|
||||
}
|
||||
|
||||
private void BodyTypeChanged(EntityUid uid, ParticleAcceleratorPartComponent comp, ref PhysicsBodyTypeChangedEvent args)
|
||||
{
|
||||
if (EntityManager.EntityExists(comp.Master))
|
||||
RescanParts(comp.Master!.Value);
|
||||
}
|
||||
|
||||
private void OnMoveEvent(EntityUid uid, ParticleAcceleratorPartComponent comp, ref MoveEvent args)
|
||||
{
|
||||
if (EntityManager.EntityExists(comp.Master))
|
||||
RescanParts(comp.Master!.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,28 @@
|
||||
using Content.Server.ParticleAccelerator.Components;
|
||||
using Content.Server.Power.EntitySystems;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems
|
||||
{
|
||||
public sealed partial class ParticleAcceleratorSystem
|
||||
{
|
||||
private void InitializePowerBoxSystem()
|
||||
{
|
||||
SubscribeLocalEvent<ParticleAcceleratorPowerBoxComponent, PowerConsumerReceivedChanged>(PowerBoxReceivedChanged);
|
||||
}
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems;
|
||||
|
||||
private void PowerBoxReceivedChanged(
|
||||
EntityUid uid,
|
||||
ParticleAcceleratorPowerBoxComponent component,
|
||||
ref PowerConsumerReceivedChanged args)
|
||||
{
|
||||
if (TryComp(uid, out ParticleAcceleratorPartComponent? paPart))
|
||||
paPart.Master?.PowerBoxReceivedChanged(args);
|
||||
}
|
||||
public sealed partial class ParticleAcceleratorSystem
|
||||
{
|
||||
private void InitializePowerBoxSystem()
|
||||
{
|
||||
SubscribeLocalEvent<ParticleAcceleratorPowerBoxComponent, PowerConsumerReceivedChanged>(PowerBoxReceivedChanged);
|
||||
}
|
||||
|
||||
private void PowerBoxReceivedChanged(EntityUid uid, ParticleAcceleratorPowerBoxComponent component, ref PowerConsumerReceivedChanged args)
|
||||
{
|
||||
if (!TryComp<ParticleAcceleratorPartComponent>(uid, out var part))
|
||||
return;
|
||||
if (!TryComp<ParticleAcceleratorControlBoxComponent>(part.Master, out var controller))
|
||||
return;
|
||||
|
||||
var master = part.Master!.Value;
|
||||
if (controller.Enabled && args.ReceivedPower >= args.DrawRate * ParticleAcceleratorControlBoxComponent.RequiredPowerRatio)
|
||||
PowerOn(master, comp: controller);
|
||||
else
|
||||
PowerOff(master, comp: controller);
|
||||
|
||||
UpdateUI(master, controller);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,23 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Projectiles;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server.ParticleAccelerator.EntitySystems;
|
||||
|
||||
public sealed partial class ParticleAcceleratorSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly ProjectileSystem _projectileSystem = default!;
|
||||
[Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physicsSystem = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Reference in New Issue
Block a user