Re-organize all projects (#4166)
This commit is contained in:
182
Content.Server/AME/AMENodeGroup.cs
Normal file
182
Content.Server/AME/AMENodeGroup.cs
Normal file
@@ -0,0 +1,182 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Server.AME.Components;
|
||||
using Content.Server.Explosion;
|
||||
using Content.Server.NodeContainer.NodeGroups;
|
||||
using Content.Server.NodeContainer.Nodes;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.AME
|
||||
{
|
||||
/// <summary>
|
||||
/// Node group class for handling the Antimatter Engine's console and parts.
|
||||
/// </summary>
|
||||
[NodeGroup(NodeGroupID.AMEngine)]
|
||||
public class AMENodeGroup : BaseNodeGroup
|
||||
{
|
||||
/// <summary>
|
||||
/// The AME controller which is currently in control of this node group.
|
||||
/// This could be tracked a few different ways, but this is most convenient,
|
||||
/// since any part connected to the node group can easily find the master.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
private AMEControllerComponent? _masterController;
|
||||
|
||||
[Dependency]
|
||||
private readonly IRobustRandom _random = default!;
|
||||
|
||||
public AMEControllerComponent? MasterController => _masterController;
|
||||
|
||||
private readonly List<AMEShieldComponent> _cores = new();
|
||||
|
||||
public int CoreCount => _cores.Count;
|
||||
|
||||
protected override void OnAddNode(Node node)
|
||||
{
|
||||
base.OnAddNode(node);
|
||||
if (_masterController == null)
|
||||
{
|
||||
node.Owner.TryGetComponent<AMEControllerComponent>(out var controller);
|
||||
_masterController = controller;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRemoveNode(Node node)
|
||||
{
|
||||
base.OnRemoveNode(node);
|
||||
RefreshAMENodes(_masterController);
|
||||
if (_masterController != null && _masterController?.Owner == node.Owner) { _masterController = null; }
|
||||
}
|
||||
|
||||
public void RefreshAMENodes(AMEControllerComponent? controller)
|
||||
{
|
||||
if(_masterController == null && controller != null)
|
||||
{
|
||||
_masterController = controller;
|
||||
}
|
||||
|
||||
foreach (AMEShieldComponent core in _cores)
|
||||
{
|
||||
core.UnsetCore();
|
||||
}
|
||||
_cores.Clear();
|
||||
|
||||
//Check each shield node to see if it meets core criteria
|
||||
foreach (Node node in Nodes)
|
||||
{
|
||||
var nodeOwner = node.Owner;
|
||||
if (!nodeOwner.TryGetComponent<AMEShieldComponent>(out var shield)) { continue; }
|
||||
|
||||
var grid = IoCManager.Resolve<IMapManager>().GetGrid(nodeOwner.Transform.GridID);
|
||||
var nodeNeighbors = grid.GetCellsInSquareArea(nodeOwner.Transform.Coordinates, 1)
|
||||
.Select(sgc => nodeOwner.EntityManager.GetEntity(sgc))
|
||||
.Where(entity => entity != nodeOwner)
|
||||
.Select(entity => entity.TryGetComponent<AMEShieldComponent>(out var adjshield) ? adjshield : null)
|
||||
.Where(adjshield => adjshield != null);
|
||||
|
||||
if (nodeNeighbors.Count() >= 8)
|
||||
{
|
||||
_cores.Add(shield);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (AMEShieldComponent core in _cores)
|
||||
{
|
||||
core.SetCore();
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateCoreVisuals(int injectionAmount, bool injecting)
|
||||
{
|
||||
|
||||
var injectionStrength = CoreCount > 0 ? injectionAmount / CoreCount : 0;
|
||||
|
||||
foreach (AMEShieldComponent core in _cores)
|
||||
{
|
||||
core.UpdateCoreVisuals(injectionStrength, injecting);
|
||||
}
|
||||
}
|
||||
|
||||
public int InjectFuel(int fuel, out bool overloading)
|
||||
{
|
||||
overloading = false;
|
||||
if(fuel > 0 && CoreCount > 0)
|
||||
{
|
||||
var safeFuelLimit = CoreCount * 2;
|
||||
if (fuel > safeFuelLimit)
|
||||
{
|
||||
// The AME is being overloaded.
|
||||
// Note about these maths: I would assume the general idea here is to make larger engines less safe to overload.
|
||||
// In other words, yes, those are supposed to be CoreCount, not safeFuelLimit.
|
||||
var instability = 0;
|
||||
var overloadVsSizeResult = fuel - CoreCount;
|
||||
|
||||
// fuel > safeFuelLimit: Slow damage. Can safely run at this level for burst periods if the engine is small and someone is keeping an eye on it.
|
||||
if (_random.Prob(0.5f))
|
||||
instability = 1;
|
||||
// overloadVsSizeResult > 5:
|
||||
if (overloadVsSizeResult > 5)
|
||||
instability = 5;
|
||||
// overloadVsSizeResult > 10: This will explode in at most 5 injections.
|
||||
if (overloadVsSizeResult > 10)
|
||||
instability = 20;
|
||||
|
||||
// Apply calculated instability
|
||||
if (instability != 0)
|
||||
{
|
||||
overloading = true;
|
||||
foreach(AMEShieldComponent core in _cores)
|
||||
{
|
||||
core.CoreIntegrity -= instability;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note the float conversions. The maths will completely fail if not done using floats.
|
||||
return (int) ((((float) fuel) / CoreCount) * fuel * 20000);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int GetTotalStability()
|
||||
{
|
||||
if(CoreCount < 1) { return 100; }
|
||||
var stability = 0;
|
||||
|
||||
foreach(AMEShieldComponent core in _cores)
|
||||
{
|
||||
stability += core.CoreIntegrity;
|
||||
}
|
||||
|
||||
stability = stability / CoreCount;
|
||||
|
||||
return stability;
|
||||
}
|
||||
|
||||
public void ExplodeCores()
|
||||
{
|
||||
if(_cores.Count < 1 || MasterController == null) { return; }
|
||||
|
||||
var intensity = 0;
|
||||
|
||||
/*
|
||||
* todo: add an exact to the shielding and make this find the core closest to the controller
|
||||
* so they chain explode, after helpers have been added to make it not cancer
|
||||
*/
|
||||
var epicenter = _cores.First();
|
||||
|
||||
foreach (AMEShieldComponent core in _cores)
|
||||
{
|
||||
intensity += MasterController.InjectionAmount;
|
||||
}
|
||||
|
||||
intensity = Math.Min(intensity, 8);
|
||||
|
||||
epicenter.Owner.SpawnExplosion(intensity / 2, intensity, intensity * 2, intensity * 3);
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Content.Server/AME/AntimatterEngineSystem.cs
Normal file
27
Content.Server/AME/AntimatterEngineSystem.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Content.Server.AME.Components;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.AME
|
||||
{
|
||||
[UsedImplicitly]
|
||||
public class AntimatterEngineSystem : EntitySystem
|
||||
{
|
||||
private float _accumulatedFrameTime;
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
_accumulatedFrameTime += frameTime;
|
||||
if (_accumulatedFrameTime >= 10)
|
||||
{
|
||||
foreach (var comp in ComponentManager.EntityQuery<AMEControllerComponent>(true))
|
||||
{
|
||||
comp.OnUpdate(frameTime);
|
||||
}
|
||||
_accumulatedFrameTime -= 10;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
366
Content.Server/AME/Components/AMEControllerComponent.cs
Normal file
366
Content.Server/AME/Components/AMEControllerComponent.cs
Normal file
@@ -0,0 +1,366 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Items;
|
||||
using Content.Server.NodeContainer;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.AME;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.AME.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
[ComponentReference(typeof(IInteractUsing))]
|
||||
public class AMEControllerComponent : SharedAMEControllerComponent, IActivate, IInteractUsing
|
||||
{
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(AMEControllerUiKey.Key);
|
||||
[ViewVariables] private bool _injecting;
|
||||
[ViewVariables] public int InjectionAmount;
|
||||
|
||||
private AppearanceComponent? _appearance;
|
||||
private PowerSupplierComponent? _powerSupplier;
|
||||
|
||||
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
private int _stability = 100;
|
||||
|
||||
private ContainerSlot _jarSlot = default!;
|
||||
[ViewVariables] private bool HasJar => _jarSlot.ContainedEntity != null;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
if (UserInterface != null)
|
||||
{
|
||||
UserInterface.OnReceiveMessage += OnUiReceiveMessage;
|
||||
}
|
||||
|
||||
Owner.TryGetComponent(out _appearance);
|
||||
|
||||
Owner.TryGetComponent(out _powerSupplier);
|
||||
|
||||
_injecting = false;
|
||||
InjectionAmount = 2;
|
||||
_jarSlot = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-fuelJarContainer");
|
||||
}
|
||||
|
||||
public override void HandleMessage(ComponentMessage message, IComponent? component)
|
||||
{
|
||||
base.HandleMessage(message, component);
|
||||
switch (message)
|
||||
{
|
||||
case PowerChangedMessage powerChanged:
|
||||
OnPowerChanged(powerChanged);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void OnUpdate(float frameTime)
|
||||
{
|
||||
if(!_injecting)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var group = GetAMENodeGroup();
|
||||
|
||||
if (group == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var jar = _jarSlot.ContainedEntity;
|
||||
if(jar is null)
|
||||
return;
|
||||
|
||||
jar.TryGetComponent<AMEFuelContainerComponent>(out var fuelJar);
|
||||
if(fuelJar != null && _powerSupplier != null)
|
||||
{
|
||||
var availableInject = fuelJar.FuelAmount >= InjectionAmount ? InjectionAmount : fuelJar.FuelAmount;
|
||||
_powerSupplier.SupplyRate = group.InjectFuel(availableInject, out var overloading);
|
||||
fuelJar.FuelAmount -= availableInject;
|
||||
InjectSound(overloading);
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
_stability = group.GetTotalStability();
|
||||
|
||||
UpdateDisplay(_stability);
|
||||
|
||||
if(_stability <= 0) { group.ExplodeCores(); }
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when you click the owner entity with an empty hand. Opens the UI client-side if possible.
|
||||
/// </summary>
|
||||
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
|
||||
void IActivate.Activate(ActivateEventArgs args)
|
||||
{
|
||||
if (!args.User.TryGetComponent(out ActorComponent? actor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.User.TryGetComponent(out IHandsComponent? hands))
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You have no hands."));
|
||||
return;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHand?.Owner;
|
||||
if (activeHandEntity == null)
|
||||
{
|
||||
UserInterface?.Open(actor.PlayerSession);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPowerChanged(PowerChangedMessage e)
|
||||
{
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
private AMEControllerBoundUserInterfaceState GetUserInterfaceState()
|
||||
{
|
||||
var jar = _jarSlot.ContainedEntity;
|
||||
if (jar == null)
|
||||
{
|
||||
return new AMEControllerBoundUserInterfaceState(Powered, IsMasterController(), false, HasJar, 0, InjectionAmount, GetCoreCount());
|
||||
}
|
||||
|
||||
var jarcomponent = jar.GetComponent<AMEFuelContainerComponent>();
|
||||
return new AMEControllerBoundUserInterfaceState(Powered, IsMasterController(), _injecting, HasJar, jarcomponent.FuelAmount, InjectionAmount, GetCoreCount());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether the player entity is able to use the controller.
|
||||
/// </summary>
|
||||
/// <param name="playerEntity">The player entity.</param>
|
||||
/// <returns>Returns true if the entity can use the controller, and false if it cannot.</returns>
|
||||
private bool PlayerCanUseController(IEntity playerEntity, bool needsPower = true)
|
||||
{
|
||||
//Need player entity to check if they are still able to use the dispenser
|
||||
if (playerEntity == null)
|
||||
return false;
|
||||
//Check if player can interact in their current state
|
||||
if (!ActionBlockerSystem.CanInteract(playerEntity) || !ActionBlockerSystem.CanUse(playerEntity))
|
||||
return false;
|
||||
//Check if device is powered
|
||||
if (needsPower && !Powered)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateUserInterface()
|
||||
{
|
||||
var state = GetUserInterfaceState();
|
||||
UserInterface?.SetState(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Handles ui messages from the client. For things such as button presses
|
||||
/// which interact with the world and require server action.
|
||||
/// </summary>
|
||||
/// <param name="obj">A user interface message from the client.</param>
|
||||
private void OnUiReceiveMessage(ServerBoundUserInterfaceMessage obj)
|
||||
{
|
||||
if (obj.Session.AttachedEntity == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var msg = (UiButtonPressedMessage) obj.Message;
|
||||
var needsPower = msg.Button switch
|
||||
{
|
||||
UiButton.Eject => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if (!PlayerCanUseController(obj.Session.AttachedEntity, needsPower))
|
||||
return;
|
||||
|
||||
switch (msg.Button)
|
||||
{
|
||||
case UiButton.Eject:
|
||||
TryEject(obj.Session.AttachedEntity);
|
||||
break;
|
||||
case UiButton.ToggleInjection:
|
||||
ToggleInjection();
|
||||
break;
|
||||
case UiButton.IncreaseFuel:
|
||||
InjectionAmount += 2;
|
||||
break;
|
||||
case UiButton.DecreaseFuel:
|
||||
InjectionAmount = InjectionAmount > 0 ? InjectionAmount -= 2 : 0;
|
||||
break;
|
||||
case UiButton.RefreshParts:
|
||||
RefreshParts();
|
||||
break;
|
||||
}
|
||||
|
||||
GetAMENodeGroup()?.UpdateCoreVisuals(InjectionAmount, _injecting);
|
||||
|
||||
UpdateUserInterface();
|
||||
ClickSound();
|
||||
}
|
||||
|
||||
private void TryEject(IEntity user)
|
||||
{
|
||||
if (!HasJar || _injecting)
|
||||
return;
|
||||
|
||||
var jar = _jarSlot.ContainedEntity;
|
||||
if(jar is null)
|
||||
return;
|
||||
|
||||
_jarSlot.Remove(jar);
|
||||
UpdateUserInterface();
|
||||
|
||||
if (!user.TryGetComponent<HandsComponent>(out var hands) || !jar.TryGetComponent<ItemComponent>(out var item))
|
||||
return;
|
||||
if (hands.CanPutInHand(item))
|
||||
hands.PutInHand(item);
|
||||
}
|
||||
|
||||
private void ToggleInjection()
|
||||
{
|
||||
if (!_injecting)
|
||||
{
|
||||
_appearance?.SetData(AMEControllerVisuals.DisplayState, "on");
|
||||
}
|
||||
else
|
||||
{
|
||||
_appearance?.SetData(AMEControllerVisuals.DisplayState, "off");
|
||||
if (_powerSupplier != null)
|
||||
{
|
||||
_powerSupplier.SupplyRate = 0;
|
||||
}
|
||||
}
|
||||
_injecting = !_injecting;
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
|
||||
private void UpdateDisplay(int stability)
|
||||
{
|
||||
if(_appearance == null) { return; }
|
||||
|
||||
_appearance.TryGetData<string>(AMEControllerVisuals.DisplayState, out var state);
|
||||
|
||||
var newState = "on";
|
||||
if (stability < 50) { newState = "critical"; }
|
||||
if (stability < 10) { newState = "fuck"; }
|
||||
|
||||
if (state != newState)
|
||||
{
|
||||
_appearance?.SetData(AMEControllerVisuals.DisplayState, newState);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void RefreshParts()
|
||||
{
|
||||
GetAMENodeGroup()?.RefreshAMENodes(this);
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
private AMENodeGroup? GetAMENodeGroup()
|
||||
{
|
||||
Owner.TryGetComponent(out NodeContainerComponent? nodeContainer);
|
||||
|
||||
var engineNodeGroup = nodeContainer?.Nodes.Values
|
||||
.Select(node => node.NodeGroup)
|
||||
.OfType<AMENodeGroup>()
|
||||
.FirstOrDefault();
|
||||
|
||||
return engineNodeGroup;
|
||||
}
|
||||
|
||||
private bool IsMasterController()
|
||||
{
|
||||
if(GetAMENodeGroup()?.MasterController == this)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private int GetCoreCount()
|
||||
{
|
||||
var coreCount = 0;
|
||||
var group = GetAMENodeGroup();
|
||||
|
||||
if (group != null)
|
||||
{
|
||||
coreCount = group.CoreCount;
|
||||
}
|
||||
|
||||
return coreCount;
|
||||
}
|
||||
|
||||
|
||||
private void ClickSound()
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f));
|
||||
}
|
||||
|
||||
private void InjectSound(bool overloading)
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(Owner), "/Audio/Effects/bang.ogg", Owner, AudioParams.Default.WithVolume(overloading ? 10f : 0f));
|
||||
}
|
||||
|
||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
|
||||
{
|
||||
if (!args.User.TryGetComponent(out IHandsComponent? hands))
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You have no hands."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hands.GetActiveHand == null)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You have nothing on your hand."));
|
||||
return false;
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHand.Owner;
|
||||
if (activeHandEntity.TryGetComponent<AMEFuelContainerComponent>(out var fuelContainer))
|
||||
{
|
||||
if (HasJar)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("The controller already has a jar loaded."));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
_jarSlot.Insert(activeHandEntity);
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You insert the jar into the fuel slot."));
|
||||
UpdateUserInterface();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You can't put that in the controller..."));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
43
Content.Server/AME/Components/AMEFuelContainerComponent.cs
Normal file
43
Content.Server/AME/Components/AMEFuelContainerComponent.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
#nullable enable
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.AME.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class AMEFuelContainerComponent : Component
|
||||
{
|
||||
public override string Name => "AMEFuelContainer";
|
||||
|
||||
private int _fuelAmount;
|
||||
private int _maxFuelAmount;
|
||||
|
||||
/// <summary>
|
||||
/// The amount of fuel in the jar.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int FuelAmount
|
||||
{
|
||||
get => _fuelAmount;
|
||||
set => _fuelAmount = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The maximum fuel capacity of the jar.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public int MaxFuelAmount
|
||||
{
|
||||
get => _maxFuelAmount;
|
||||
set => _maxFuelAmount = value;
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
_maxFuelAmount = 1000;
|
||||
_fuelAmount = 1000;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
60
Content.Server/AME/Components/AMEPartComponent.cs
Normal file
60
Content.Server/AME/Components/AMEPartComponent.cs
Normal file
@@ -0,0 +1,60 @@
|
||||
#nullable enable
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Hands.Components;
|
||||
using Content.Server.Tools.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification;
|
||||
using Content.Shared.Tool;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.AME.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IInteractUsing))]
|
||||
public class AMEPartComponent : Component, IInteractUsing
|
||||
{
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly IServerEntityManager _serverEntityManager = default!;
|
||||
|
||||
public override string Name => "AMEPart";
|
||||
private string _unwrap = "/Audio/Effects/unwrap.ogg";
|
||||
|
||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs args)
|
||||
{
|
||||
if (!args.User.TryGetComponent<IHandsComponent>(out var hands))
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("You have no hands."));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!args.Using.TryGetComponent<ToolComponent>(out var multitool) || multitool.Qualities != ToolQuality.Multitool)
|
||||
return true;
|
||||
|
||||
if (!_mapManager.TryGetGrid(args.ClickLocation.GetGridId(_serverEntityManager), out var mapGrid))
|
||||
return false; // No AME in space.
|
||||
|
||||
var snapPos = mapGrid.TileIndicesFor(args.ClickLocation);
|
||||
if (mapGrid.GetAnchoredEntities(snapPos).Any(sc => _serverEntityManager.ComponentManager.HasComponent<AMEShieldComponent>(sc)))
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("Shielding is already there!"));
|
||||
return true;
|
||||
}
|
||||
|
||||
var ent = _serverEntityManager.SpawnEntity("AMEShielding", mapGrid.GridTileToLocal(snapPos));
|
||||
ent.Transform.LocalRotation = Owner.Transform.LocalRotation;
|
||||
|
||||
SoundSystem.Play(Filter.Pvs(Owner), _unwrap, Owner);
|
||||
|
||||
Owner.Delete();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Content.Server/AME/Components/AMEShieldComponent.cs
Normal file
66
Content.Server/AME/Components/AMEShieldComponent.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using Content.Shared.AME;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
namespace Content.Server.AME.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class AMEShieldComponent : SharedAMEShieldComponent
|
||||
{
|
||||
|
||||
private bool _isCore = false;
|
||||
|
||||
[ViewVariables]
|
||||
public int CoreIntegrity = 100;
|
||||
|
||||
private AppearanceComponent? _appearance;
|
||||
private PointLightComponent? _pointLight;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
Owner.TryGetComponent(out _appearance);
|
||||
Owner.TryGetComponent(out _pointLight);
|
||||
}
|
||||
|
||||
public void SetCore()
|
||||
{
|
||||
if(_isCore) { return; }
|
||||
_isCore = true;
|
||||
_appearance?.SetData(AMEShieldVisuals.Core, "isCore");
|
||||
}
|
||||
|
||||
public void UnsetCore()
|
||||
{
|
||||
_isCore = false;
|
||||
_appearance?.SetData(AMEShieldVisuals.Core, "isNotCore");
|
||||
}
|
||||
|
||||
public void UpdateCoreVisuals(int injectionStrength, bool injecting)
|
||||
{
|
||||
if (!injecting)
|
||||
{
|
||||
_appearance?.SetData(AMEShieldVisuals.CoreState, "off");
|
||||
if (_pointLight != null) { _pointLight.Enabled = false; }
|
||||
return;
|
||||
}
|
||||
|
||||
if (_pointLight != null)
|
||||
{
|
||||
_pointLight.Radius = Math.Clamp(injectionStrength, 1, 12);
|
||||
_pointLight.Enabled = true;
|
||||
}
|
||||
|
||||
if (injectionStrength > 2)
|
||||
{
|
||||
_appearance?.SetData(AMEShieldVisuals.CoreState, "strong");
|
||||
return;
|
||||
}
|
||||
|
||||
_appearance?.SetData(AMEShieldVisuals.CoreState, "weak");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user