Merge remote-tracking branch 'space-wizards/master'
# Conflicts: # Resources/Locale/en-US/_strings/materials/silo.ftl # Resources/Textures/Clothing/Neck/mantles/cemantle.rsi/equipped-NECK.png # Resources/Textures/Clothing/Neck/mantles/cemantle.rsi/icon.png # Resources/Textures/Clothing/Neck/mantles/cemantle.rsi/meta.json
|
|
@ -127,12 +127,17 @@
|
|||
HorizontalExpand="True"
|
||||
Orientation="Vertical">
|
||||
<Label Text="{Loc 'lathe-menu-materials-title'}" Margin="5 5 5 5" HorizontalAlignment="Center"/>
|
||||
<BoxContainer
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True">
|
||||
<ui:MaterialStorageControl Name="MaterialsList" SizeFlagsStretchRatio="8"/>
|
||||
</BoxContainer>
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True">
|
||||
<ui:MaterialStorageControl Name="MaterialsList" SizeFlagsStretchRatio="8"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
|
|
|
|||
6
Content.Client/Materials/OreSiloSystem.cs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
using Content.Shared.Materials.OreSilo;
|
||||
|
||||
namespace Content.Client.Materials;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class OreSiloSystem : SharedOreSiloSystem;
|
||||
|
|
@ -2,7 +2,10 @@
|
|||
SizeFlagsStretchRatio="8"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<BoxContainer Name="MaterialList" Orientation="Vertical">
|
||||
<Label Name="NoMatsLabel" Text="{Loc 'lathe-menu-no-materials-message'}" Align="Center"/>
|
||||
<BoxContainer Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Name="MaterialList" Orientation="Vertical" VerticalExpand="True">
|
||||
<Label Name="NoMatsLabel" Text="{Loc 'lathe-menu-no-materials-message'}" HorizontalAlignment="Center" VerticalAlignment="Center" VerticalExpand="True"/>
|
||||
</BoxContainer>
|
||||
<Label Name="SiloLinkedLabel" Text="{Loc 'lathe-menu-silo-linked-message'}" StyleClasses="LabelSubText" Visible="False" HorizontalAlignment="Center"/>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Linq;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Materials.OreSilo;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
|
@ -15,6 +16,7 @@ namespace Content.Client.Materials.UI;
|
|||
public sealed partial class MaterialStorageControl : ScrollContainer
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||
private readonly MaterialStorageSystem _materialStorage;
|
||||
|
||||
private EntityUid? _owner;
|
||||
|
||||
|
|
@ -24,6 +26,8 @@ public sealed partial class MaterialStorageControl : ScrollContainer
|
|||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_materialStorage = _entityManager.System<MaterialStorageSystem>();
|
||||
}
|
||||
|
||||
public void SetOwner(EntityUid owner)
|
||||
|
|
@ -45,7 +49,8 @@ public sealed partial class MaterialStorageControl : ScrollContainer
|
|||
}
|
||||
|
||||
var canEject = materialStorage.CanEjectStoredMaterials;
|
||||
var mats = materialStorage.Storage;
|
||||
var mats = _materialStorage.GetStoredMaterials((_owner.Value, materialStorage));
|
||||
|
||||
if (_currentMaterials.Equals(mats))
|
||||
return;
|
||||
|
||||
|
|
@ -89,5 +94,6 @@ public sealed partial class MaterialStorageControl : ScrollContainer
|
|||
|
||||
_currentMaterials = mats;
|
||||
NoMatsLabel.Visible = MaterialList.ChildCount == 1;
|
||||
SiloLinkedLabel.Visible = _entityManager.TryGetComponent<OreSiloClientComponent>(_owner.Value, out var client) && client.Silo != null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
34
Content.Client/Materials/UI/OreSiloBoundUserInterface.cs
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
using Content.Shared.Materials.OreSilo;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.Materials.UI;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class OreSiloBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey)
|
||||
{
|
||||
[ViewVariables]
|
||||
private OreSiloMenu? _menu;
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<OreSiloMenu>();
|
||||
_menu.SetEntity(Owner);
|
||||
|
||||
_menu.OnClientEntryPressed += netEnt =>
|
||||
{
|
||||
SendPredictedMessage(new ToggleOreSiloClientMessage(netEnt));
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
if (state is not OreSiloBuiState msg)
|
||||
return;
|
||||
_menu?.Update(msg);
|
||||
}
|
||||
}
|
||||
42
Content.Client/Materials/UI/OreSiloMenu.xaml
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<controls:FancyWindow xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:ui="clr-namespace:Content.Client.Materials.UI"
|
||||
Title="{Loc 'ore-silo-ui-title'}"
|
||||
MinSize="400 260"
|
||||
SetSize="400 460">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
Margin="10 10 10 10">
|
||||
<BoxContainer VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Orientation="Vertical"
|
||||
SizeFlagsStretchRatio="3">
|
||||
<Label Text="{Loc 'ore-silo-ui-label-clients'}" Margin="5 5 5 5" HorizontalAlignment="Center" StyleClasses="LabelKeyText"/>
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#1B1B1E" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<ItemList Name="ClientList" SelectMode="Button" VerticalExpand="True"/>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
<BoxContainer VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Orientation="Vertical"
|
||||
SizeFlagsStretchRatio="2">
|
||||
<Label Text="{Loc 'ore-silo-ui-label-mats'}" Margin="5 5 5 5" HorizontalAlignment="Center" StyleClasses="LabelKeyText"/>
|
||||
<PanelContainer VerticalExpand="True">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#1B1B1E" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer
|
||||
Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True">
|
||||
<ui:MaterialStorageControl Name="Materials"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</controls:FancyWindow>
|
||||
64
Content.Client/Materials/UI/OreSiloMenu.xaml.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
using System.Linq;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Materials.OreSilo;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client.Materials.UI;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class OreSiloMenu : FancyWindow
|
||||
{
|
||||
public event Action<NetEntity>? OnClientEntryPressed;
|
||||
|
||||
public OreSiloMenu()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
ClientList.OnItemSelected += args =>
|
||||
{
|
||||
var item = ClientList[args.ItemIndex];
|
||||
// a little bit of null suppression makes me feel great! :-)
|
||||
OnClientEntryPressed?.Invoke((NetEntity) item.Metadata!);
|
||||
};
|
||||
}
|
||||
|
||||
public void SetEntity(EntityUid uid)
|
||||
{
|
||||
Materials.SetOwner(uid);
|
||||
}
|
||||
|
||||
public void Update(OreSiloBuiState state)
|
||||
{
|
||||
var items = new List<ItemList.Item>();
|
||||
var orderedClients = state.Clients.OrderBy(t => t.Item3).ThenBy(t => t.Item1.Id);
|
||||
foreach (var (ent, _, _) in orderedClients)
|
||||
{
|
||||
items.Add(new ItemList.Item(ClientList)
|
||||
{
|
||||
Metadata = ent
|
||||
});
|
||||
}
|
||||
|
||||
ClientList.SetItems(items,
|
||||
(item1, item2) =>
|
||||
{
|
||||
var ent1 = (NetEntity) item1.Metadata!;
|
||||
var ent2 = (NetEntity) item2.Metadata!;
|
||||
return ent1.CompareTo(ent2);
|
||||
});
|
||||
|
||||
var entTextDict = state.Clients.Select(t => (t.Item1, t.Item2)).ToDictionary();
|
||||
using var enumerator = ClientList.GetEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
if (enumerator.Current.Metadata is not NetEntity ent)
|
||||
continue;
|
||||
|
||||
if (entTextDict.TryGetValue(ent, out var text))
|
||||
enumerator.Current.Text = text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,14 +61,14 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
var oldProgress = component.Progress.ShallowClone();
|
||||
component.Progress.Clear();
|
||||
|
||||
var water = solution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
|
||||
if (water > FixedPoint2.Zero)
|
||||
var mopReagent = solution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(solution));
|
||||
if (mopReagent > FixedPoint2.Zero)
|
||||
{
|
||||
component.Progress[solution.GetColorWithOnly(_prototype, PuddleSystem.EvaporationReagents)] = water.Float();
|
||||
component.Progress[solution.GetColorWithOnly(_prototype, _puddleSystem.GetAbsorbentReagents(solution))] = mopReagent.Float();
|
||||
}
|
||||
|
||||
var otherColor = solution.GetColorWithout(_prototype, PuddleSystem.EvaporationReagents);
|
||||
var other = (solution.Volume - water).Float();
|
||||
var otherColor = solution.GetColorWithout(_prototype, _puddleSystem.GetAbsorbentReagents(solution));
|
||||
var other = (solution.Volume - mopReagent).Float();
|
||||
|
||||
if (other > 0f)
|
||||
{
|
||||
|
|
@ -189,7 +189,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
}
|
||||
|
||||
// Prioritize transferring non-evaporatives if absorbent has any
|
||||
var contaminants = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, transferAmount, PuddleSystem.EvaporationReagents);
|
||||
var contaminants = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, transferAmount, _puddleSystem.GetAbsorbentReagents(absorbentSoln.Comp.Solution));
|
||||
if (contaminants.Volume > 0)
|
||||
{
|
||||
_solutionContainerSystem.TryAddSolution(refillableSoln, contaminants);
|
||||
|
|
@ -214,7 +214,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
Entity<SolutionComponent> absorbentSoln,
|
||||
Entity<SolutionComponent> refillableSoln)
|
||||
{
|
||||
var contaminantsFromAbsorbent = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, component.PickupAmount, PuddleSystem.EvaporationReagents);
|
||||
var contaminantsFromAbsorbent = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, component.PickupAmount, _puddleSystem.GetAbsorbentReagents(absorbentSoln.Comp.Solution));
|
||||
|
||||
var absorbentSolution = absorbentSoln.Comp.Solution;
|
||||
if (contaminantsFromAbsorbent.Volume == FixedPoint2.Zero && absorbentSolution.AvailableVolume == FixedPoint2.Zero)
|
||||
|
|
@ -231,7 +231,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
absorbentSolution.AvailableVolume;
|
||||
|
||||
var refillableSolution = refillableSoln.Comp.Solution;
|
||||
var waterFromRefillable = refillableSolution.SplitSolutionWithOnly(waterPulled, PuddleSystem.EvaporationReagents);
|
||||
var waterFromRefillable = refillableSolution.SplitSolutionWithOnly(waterPulled, _puddleSystem.GetAbsorbentReagents(refillableSoln.Comp.Solution));
|
||||
_solutionContainerSystem.UpdateChemicals(refillableSoln);
|
||||
|
||||
if (waterFromRefillable.Volume == FixedPoint2.Zero && contaminantsFromAbsorbent.Volume == FixedPoint2.Zero)
|
||||
|
|
@ -293,7 +293,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
|
||||
// Check if we have any evaporative reagents on our absorber to transfer
|
||||
var absorberSolution = absorberSoln.Comp.Solution;
|
||||
var available = absorberSolution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
|
||||
var available = absorberSolution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// No material
|
||||
if (available == FixedPoint2.Zero)
|
||||
|
|
@ -305,8 +305,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||
var transferMax = absorber.PickupAmount;
|
||||
var transferAmount = available > transferMax ? transferMax : available;
|
||||
|
||||
var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
|
||||
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
|
||||
var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, _puddleSystem.GetAbsorbentReagents(puddleSolution));
|
||||
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, _puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// Do tile reactions first
|
||||
var transform = Transform(target);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Fluids.Components;
|
||||
|
||||
|
|
@ -20,7 +21,7 @@ public sealed partial class PuddleSystem
|
|||
return;
|
||||
}
|
||||
|
||||
if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
||||
if (solution.GetTotalPrototypeQuantity(GetEvaporatingReagents(solution)) > FixedPoint2.Zero)
|
||||
{
|
||||
var evaporation = AddComp<EvaporationComponent>(uid);
|
||||
evaporation.NextTick = _timing.CurTime + EvaporationCooldown;
|
||||
|
|
@ -45,8 +46,11 @@ public sealed partial class PuddleSystem
|
|||
if (!_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution, out var puddleSolution))
|
||||
continue;
|
||||
|
||||
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
|
||||
puddleSolution.SplitSolutionWithOnly(reagentTick, EvaporationReagents);
|
||||
foreach ((string evaporatingReagent, FixedPoint2 evaporatingSpeed) in GetEvaporationSpeeds(puddleSolution))
|
||||
{
|
||||
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds * evaporatingSpeed;
|
||||
puddleSolution.SplitSolutionWithOnly(reagentTick, evaporatingReagent);
|
||||
}
|
||||
|
||||
// Despawn if we're done
|
||||
if (puddleSolution.Volume == FixedPoint2.Zero)
|
||||
|
|
|
|||
|
|
@ -102,14 +102,18 @@ public sealed class MaterialStorageSystem : SharedMaterialStorageSystem
|
|||
if (!base.TryInsertMaterialEntity(user, toInsert, receiver, storage, material, composition))
|
||||
return false;
|
||||
_audio.PlayPvs(storage.InsertingSound, receiver);
|
||||
_popup.PopupEntity(Loc.GetString("machine-insert-item", ("user", user), ("machine", receiver),
|
||||
("item", toInsert)), receiver);
|
||||
_popup.PopupEntity(Loc.GetString("machine-insert-item",
|
||||
("user", user),
|
||||
("machine", receiver),
|
||||
("item", toInsert)),
|
||||
receiver);
|
||||
QueueDel(toInsert);
|
||||
|
||||
// Logging
|
||||
TryComp<StackComponent>(toInsert, out var stack);
|
||||
var count = stack?.Count ?? 1;
|
||||
_adminLogger.Add(LogType.Action, LogImpact.Low,
|
||||
_adminLogger.Add(LogType.Action,
|
||||
LogImpact.Low,
|
||||
$"{ToPrettyString(user):player} inserted {count} {ToPrettyString(toInsert):inserted} into {ToPrettyString(receiver):receiver}");
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
119
Content.Server/Materials/OreSiloSystem.cs
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
using Content.Server.Pinpointer;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Materials.OreSilo;
|
||||
using Robust.Server.GameStates;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server.Materials;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public sealed class OreSiloSystem : SharedOreSiloSystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _entityLookup = default!;
|
||||
[Dependency] private readonly NavMapSystem _navMap = default!;
|
||||
[Dependency] private readonly PvsOverrideSystem _pvsOverride = default!;
|
||||
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
|
||||
|
||||
private const float OreSiloPreloadRangeSquared = 225f; // ~1 screen
|
||||
|
||||
private readonly HashSet<Entity<OreSiloClientComponent>> _clientLookup = new();
|
||||
private readonly HashSet<(NetEntity, string, string)> _clientInformation = new();
|
||||
private readonly HashSet<EntityUid> _silosToAdd = new();
|
||||
private readonly HashSet<EntityUid> _silosToRemove = new();
|
||||
|
||||
protected override void UpdateOreSiloUi(Entity<OreSiloComponent> ent)
|
||||
{
|
||||
if (!_userInterface.IsUiOpen(ent.Owner, OreSiloUiKey.Key))
|
||||
return;
|
||||
_clientLookup.Clear();
|
||||
_clientInformation.Clear();
|
||||
|
||||
var xform = Transform(ent);
|
||||
|
||||
// Sneakily uses override with TComponent parameter
|
||||
_entityLookup.GetEntitiesInRange(xform.Coordinates, ent.Comp.Range, _clientLookup);
|
||||
|
||||
foreach (var client in _clientLookup)
|
||||
{
|
||||
// don't show already-linked clients.
|
||||
if (client.Comp.Silo is not null)
|
||||
continue;
|
||||
|
||||
var netEnt = GetNetEntity(client);
|
||||
var name = Identity.Name(client, EntityManager);
|
||||
var beacon = _navMap.GetNearestBeaconString(client.Owner, onlyName: true);
|
||||
|
||||
var txt = Loc.GetString("ore-silo-ui-itemlist-entry",
|
||||
("name", name),
|
||||
("beacon", beacon),
|
||||
("linked", ent.Comp.Clients.Contains(client)),
|
||||
("inRange", true));
|
||||
|
||||
_clientInformation.Add((netEnt, txt, beacon));
|
||||
}
|
||||
|
||||
// Get all clients of this silo, including those out of range.
|
||||
foreach (var client in ent.Comp.Clients)
|
||||
{
|
||||
var netEnt = GetNetEntity(client);
|
||||
var name = Identity.Name(client, EntityManager);
|
||||
var beacon = _navMap.GetNearestBeaconString(client, onlyName: true);
|
||||
var inRange = CanTransmitMaterials((ent, ent), client);
|
||||
|
||||
var txt = Loc.GetString("ore-silo-ui-itemlist-entry",
|
||||
("name", name),
|
||||
("beacon", beacon),
|
||||
("linked", ent.Comp.Clients.Contains(client)),
|
||||
("inRange", inRange));
|
||||
|
||||
_clientInformation.Add((netEnt, txt, beacon));
|
||||
}
|
||||
|
||||
_userInterface.SetUiState(ent.Owner, OreSiloUiKey.Key, new OreSiloBuiState(_clientInformation));
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
// Solving an annoying problem: we need to send the silo to people who are near the silo so that
|
||||
// Things don't start wildly mispredicting. We do this as cheaply as possible via grid-based local-pos checks.
|
||||
// Sloth okay-ed this in the interim until a better solution comes around.
|
||||
|
||||
var actorQuery = EntityQueryEnumerator<ActorComponent, TransformComponent>();
|
||||
while (actorQuery.MoveNext(out _, out var actorComp, out var actorXform))
|
||||
{
|
||||
_silosToAdd.Clear();
|
||||
_silosToRemove.Clear();
|
||||
|
||||
var clientQuery = EntityQueryEnumerator<OreSiloClientComponent, TransformComponent>();
|
||||
while (clientQuery.MoveNext(out _, out var clientComp, out var clientXform))
|
||||
{
|
||||
if (clientComp.Silo == null)
|
||||
continue;
|
||||
|
||||
// We limit it to same-grid checks only for peak perf
|
||||
if (actorXform.GridUid != clientXform.GridUid)
|
||||
continue;
|
||||
|
||||
if ((actorXform.LocalPosition - clientXform.LocalPosition).LengthSquared() <= OreSiloPreloadRangeSquared)
|
||||
{
|
||||
_silosToAdd.Add(clientComp.Silo.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_silosToRemove.Add(clientComp.Silo.Value);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var toRemove in _silosToRemove)
|
||||
{
|
||||
_pvsOverride.RemoveSessionOverride(toRemove, actorComp.PlayerSession);
|
||||
}
|
||||
foreach (var toAdd in _silosToAdd)
|
||||
{
|
||||
_pvsOverride.AddSessionOverride(toAdd, actorComp.PlayerSession);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -436,12 +436,12 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||
/// to the position of <paramref name="ent"/> from the nearest beacon.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public string GetNearestBeaconString(Entity<TransformComponent?> ent)
|
||||
public string GetNearestBeaconString(Entity<TransformComponent?> ent, bool onlyName = false)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return Loc.GetString("nav-beacon-pos-no-beacons");
|
||||
|
||||
return GetNearestBeaconString(_transformSystem.GetMapCoordinates(ent, ent.Comp));
|
||||
return GetNearestBeaconString(_transformSystem.GetMapCoordinates(ent, ent.Comp), onlyName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -449,11 +449,14 @@ public sealed partial class NavMapSystem : SharedNavMapSystem
|
|||
/// to <paramref name="coordinates"/> from the nearest beacon.
|
||||
/// </summary>
|
||||
|
||||
public string GetNearestBeaconString(MapCoordinates coordinates)
|
||||
public string GetNearestBeaconString(MapCoordinates coordinates, bool onlyName = false)
|
||||
{
|
||||
if (!TryGetNearestBeacon(coordinates, out var beacon, out var pos))
|
||||
return Loc.GetString("nav-beacon-pos-no-beacons");
|
||||
|
||||
if (onlyName)
|
||||
return beacon.Value.Comp.Text!;
|
||||
|
||||
var gridOffset = Angle.Zero;
|
||||
if (_mapManager.TryFindGridAt(pos.Value, out var grid, out _))
|
||||
gridOffset = Transform(grid).LocalRotation;
|
||||
|
|
|
|||
|
|
@ -243,7 +243,7 @@ public sealed partial class ShuttleSystem
|
|||
}
|
||||
}
|
||||
|
||||
if (HasComp<PreventPilotComponent>(shuttleUid))
|
||||
if (HasComp<PreventPilotComponent>(shuttleUid) || HasComp<PreventFTLComponent>(shuttleUid))
|
||||
{
|
||||
reason = Loc.GetString("shuttle-console-prevent");
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ public sealed class MobsterAccentSystem : EntitySystem
|
|||
private static readonly Regex RegexUpperAr = new(@"(?<=\w)A[Rr](?=\w)");
|
||||
private static readonly Regex RegexFirstWord = new(@"^(\S+)");
|
||||
private static readonly Regex RegexLastWord = new(@"(\S+)$");
|
||||
|
||||
private static readonly Regex RegexLastPunctuation = new(@"([.!?]+$)(?!.*[.!?])|(?<![.!?])$");
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly ReplacementAccentSystem _replacement = default!;
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ public sealed class MobsterAccentSystem : EntitySystem
|
|||
}
|
||||
if (lastWordAllCaps)
|
||||
suffix = suffix.ToUpper();
|
||||
msg += suffix;
|
||||
msg = RegexLastPunctuation.Replace(msg, suffix);
|
||||
}
|
||||
|
||||
return msg;
|
||||
|
|
|
|||
|
|
@ -199,6 +199,13 @@ namespace Content.Server.Zombies
|
|||
private void OnPendingMapInit(EntityUid uid, IncurableZombieComponent component, MapInitEvent args)
|
||||
{
|
||||
_actions.AddAction(uid, ref component.Action, component.ZombifySelfActionPrototype);
|
||||
|
||||
if (HasComp<ZombieComponent>(uid) || HasComp<ZombieImmuneComponent>(uid))
|
||||
return;
|
||||
|
||||
EnsureComp<PendingZombieComponent>(uid, out PendingZombieComponent pendingComp);
|
||||
|
||||
pendingComp.GracePeriod = _random.Next(pendingComp.MinInitialInfectedGrace, pendingComp.MaxInitialInfectedGrace);
|
||||
}
|
||||
|
||||
private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, MapInitEvent args)
|
||||
|
|
@ -210,7 +217,6 @@ namespace Content.Server.Zombies
|
|||
}
|
||||
|
||||
component.NextTick = _timing.CurTime + TimeSpan.FromSeconds(1f);
|
||||
component.GracePeriod = _random.Next(component.MinInitialInfectedGrace, component.MaxInitialInfectedGrace);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System.Collections.Frozen;
|
||||
using System.Linq;
|
||||
using Content.Shared.FixedPoint;
|
||||
using System.Text.Json.Serialization;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Body.Prototypes;
|
||||
|
|
@ -7,14 +8,12 @@ using Content.Shared.Chemistry.Components;
|
|||
using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.EntityEffects;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Nutrition;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Serialization;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
|
|
@ -105,6 +104,18 @@ namespace Content.Shared.Chemistry.Reagent
|
|||
[DataField]
|
||||
public bool Slippery;
|
||||
|
||||
/// <summary>
|
||||
/// The speed at which the reagent evaporates over time.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public FixedPoint2 EvaporationSpeed = FixedPoint2.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// If this reagent can be used to mop up other reagents.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Absorbent = false;
|
||||
|
||||
/// <summary>
|
||||
/// How easily this reagent becomes fizzy when aggitated.
|
||||
/// 0 - completely flat, 1 - fizzes up when nudged.
|
||||
|
|
@ -206,7 +217,7 @@ namespace Content.Shared.Chemistry.Reagent
|
|||
.ToDictionary(x => x.Key, x => x.Item2);
|
||||
if (proto.PlantMetabolisms.Count > 0)
|
||||
{
|
||||
PlantMetabolisms = new List<string> (proto.PlantMetabolisms
|
||||
PlantMetabolisms = new List<string>(proto.PlantMetabolisms
|
||||
.Select(x => x.GuidebookEffectDescription(prototype, entSys))
|
||||
.Where(x => x is not null)
|
||||
.Select(x => x!)
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ public sealed partial class EvaporationComponent : Component
|
|||
public TimeSpan NextTick = TimeSpan.Zero;
|
||||
|
||||
/// <summary>
|
||||
/// How much evaporation per second.
|
||||
/// Evaporation factor. Multiplied by the evaporating speed of the reagent.
|
||||
/// </summary>
|
||||
[DataField("evaporationAmount")]
|
||||
public FixedPoint2 EvaporationAmount = FixedPoint2.New(0.3);
|
||||
public FixedPoint2 EvaporationAmount = FixedPoint2.New(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,52 @@
|
|||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared.Fluids;
|
||||
|
||||
public abstract partial class SharedPuddleSystem
|
||||
{
|
||||
[ValidatePrototypeId<ReagentPrototype>]
|
||||
private const string Water = "Water";
|
||||
public string[] GetEvaporatingReagents(Solution solution)
|
||||
{
|
||||
var evaporatingReagents = new List<string>();
|
||||
foreach (ReagentPrototype solProto in solution.GetReagentPrototypes(_prototypeManager).Keys)
|
||||
{
|
||||
if (solProto.EvaporationSpeed > FixedPoint2.Zero)
|
||||
evaporatingReagents.Add(solProto.ID);
|
||||
}
|
||||
return evaporatingReagents.ToArray();
|
||||
}
|
||||
|
||||
public static readonly string[] EvaporationReagents = [Water];
|
||||
public string[] GetAbsorbentReagents(Solution solution)
|
||||
{
|
||||
var absorbentReagents = new List<string>();
|
||||
foreach (ReagentPrototype solProto in solution.GetReagentPrototypes(_prototypeManager).Keys)
|
||||
{
|
||||
if (solProto.Absorbent)
|
||||
absorbentReagents.Add(solProto.ID);
|
||||
}
|
||||
return absorbentReagents.ToArray();
|
||||
}
|
||||
|
||||
public bool CanFullyEvaporate(Solution solution)
|
||||
{
|
||||
return solution.GetTotalPrototypeQuantity(EvaporationReagents) == solution.Volume;
|
||||
return solution.GetTotalPrototypeQuantity(GetEvaporatingReagents(solution)) == solution.Volume;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the evaporating speed of the reagents within a solution.
|
||||
/// The speed at which a solution evaporates is the sum of the speed of all evaporating reagents in it.
|
||||
/// </summary>
|
||||
public Dictionary<string, FixedPoint2> GetEvaporationSpeeds(Solution solution)
|
||||
{
|
||||
var evaporatingSpeeds = new Dictionary<string, FixedPoint2>();
|
||||
foreach (ReagentPrototype solProto in solution.GetReagentPrototypes(_prototypeManager).Keys)
|
||||
{
|
||||
if (solProto.EvaporationSpeed > FixedPoint2.Zero)
|
||||
{
|
||||
evaporatingSpeeds.Add(solProto.ID, solProto.EvaporationSpeed);
|
||||
}
|
||||
}
|
||||
return evaporatingSpeeds;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ public abstract partial class SharedPuddleSystem : EntitySystem
|
|||
{
|
||||
if (CanFullyEvaporate(solution))
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
||||
else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
||||
else if (solution.GetTotalPrototypeQuantity(GetEvaporatingReagents(solution)) > FixedPoint2.Zero)
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
||||
else
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||
|
|
|
|||
|
|
@ -75,6 +75,24 @@ public enum MaterialStorageVisuals : byte
|
|||
Inserting
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Collects all the materials stored on a <see cref="MaterialStorageComponent"/>
|
||||
/// </summary>
|
||||
/// <param name="Entity">The entity holding all these materials</param>
|
||||
/// <param name="Materials">A dictionary of all materials held</param>
|
||||
/// <param name="LocalOnly">An optional specifier. Non-local sources (silo, etc.) should not add materials when this is false.</param>
|
||||
[ByRefEvent]
|
||||
public readonly record struct GetStoredMaterialsEvent(Entity<MaterialStorageComponent> Entity, Dictionary<ProtoId<MaterialPrototype>, int> Materials, bool LocalOnly);
|
||||
|
||||
/// <summary>
|
||||
/// After using materials, removes them from storage.
|
||||
/// </summary>
|
||||
/// <param name="Entity">The entity that held the materials and is being used up</param>
|
||||
/// <param name="Materials">A dictionary of the difference of materials left.</param>
|
||||
/// <param name="LocalOnly">An optional specifier. Non-local sources (silo, etc.) should not consume materials when this is false.</param>
|
||||
[ByRefEvent]
|
||||
public readonly record struct ConsumeStoredMaterialsEvent(Entity<MaterialStorageComponent> Entity, Dictionary<ProtoId<MaterialPrototype>, int> Materials, bool LocalOnly);
|
||||
|
||||
/// <summary>
|
||||
/// event raised on the materialStorage when a material entity is inserted into it.
|
||||
/// </summary>
|
||||
|
|
|
|||
18
Content.Shared/Materials/OreSilo/OreSiloClientComponent.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
/// <summary>
|
||||
/// An entity with <see cref="MaterialStorageComponent"/> that interfaces with an <see cref="OreSiloComponent"/>.
|
||||
/// Used for tracking the connected silo.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(SharedOreSiloSystem))]
|
||||
public sealed partial class OreSiloClientComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The silo that this client pulls materials from.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public EntityUid? Silo;
|
||||
}
|
||||
55
Content.Shared/Materials/OreSilo/OreSiloComponent.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
/// <summary>
|
||||
/// Provides additional materials to linked clients across long distances.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(SharedOreSiloSystem))]
|
||||
public sealed partial class OreSiloComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="OreSiloClientComponent"/> that are connected to this silo.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<EntityUid> Clients = new();
|
||||
|
||||
/// <summary>
|
||||
/// The maximum distance you can be to the silo and still receive transmission.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Default value should be big enough to span a single large department.
|
||||
/// </remarks>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float Range = 20f;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class OreSiloBuiState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly HashSet<(NetEntity, string, string)> Clients;
|
||||
|
||||
public OreSiloBuiState(HashSet<(NetEntity, string, string)> clients)
|
||||
{
|
||||
Clients = clients;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class ToggleOreSiloClientMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly NetEntity Client;
|
||||
|
||||
public ToggleOreSiloClientMessage(NetEntity client)
|
||||
{
|
||||
Client = client;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum OreSiloUiKey : byte
|
||||
{
|
||||
Key
|
||||
}
|
||||
168
Content.Shared/Materials/OreSilo/SharedOreSiloSystem.cs
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
using Content.Shared.Power.EntitySystems;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared.Materials.OreSilo;
|
||||
|
||||
public abstract class SharedOreSiloSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMaterialStorageSystem _materialStorage = default!;
|
||||
[Dependency] private readonly SharedPowerReceiverSystem _powerReceiver = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
|
||||
private EntityQuery<OreSiloClientComponent> _clientQuery;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<OreSiloComponent, ToggleOreSiloClientMessage>(OnToggleOreSiloClient);
|
||||
SubscribeLocalEvent<OreSiloComponent, ComponentShutdown>(OnSiloShutdown);
|
||||
Subs.BuiEvents<OreSiloComponent>(OreSiloUiKey.Key,
|
||||
subs =>
|
||||
{
|
||||
subs.Event<BoundUIOpenedEvent>(OnBoundUIOpened);
|
||||
});
|
||||
|
||||
|
||||
SubscribeLocalEvent<OreSiloClientComponent, GetStoredMaterialsEvent>(OnGetStoredMaterials);
|
||||
SubscribeLocalEvent<OreSiloClientComponent, ConsumeStoredMaterialsEvent>(OnConsumeStoredMaterials);
|
||||
SubscribeLocalEvent<OreSiloClientComponent, ComponentShutdown>(OnClientShutdown);
|
||||
|
||||
_clientQuery = GetEntityQuery<OreSiloClientComponent>();
|
||||
}
|
||||
|
||||
private void OnToggleOreSiloClient(Entity<OreSiloComponent> ent, ref ToggleOreSiloClientMessage args)
|
||||
{
|
||||
var client = GetEntity(args.Client);
|
||||
|
||||
if (!_clientQuery.TryComp(client, out var clientComp))
|
||||
return;
|
||||
|
||||
if (ent.Comp.Clients.Contains(client)) // remove client
|
||||
{
|
||||
clientComp.Silo = null;
|
||||
Dirty(client, clientComp);
|
||||
ent.Comp.Clients.Remove(client);
|
||||
Dirty(ent);
|
||||
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
else // add client
|
||||
{
|
||||
if (!CanTransmitMaterials((ent, ent), client))
|
||||
return;
|
||||
|
||||
var clientMats = _materialStorage.GetStoredMaterials(client, true);
|
||||
var inverseMats = new Dictionary<string, int>();
|
||||
foreach (var (mat, amount) in clientMats)
|
||||
{
|
||||
inverseMats.Add(mat, -amount);
|
||||
}
|
||||
_materialStorage.TryChangeMaterialAmount(client, inverseMats, localOnly: true);
|
||||
_materialStorage.TryChangeMaterialAmount(ent.Owner, clientMats);
|
||||
|
||||
ent.Comp.Clients.Add(client);
|
||||
Dirty(ent);
|
||||
clientComp.Silo = ent;
|
||||
Dirty(client, clientComp);
|
||||
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnBoundUIOpened(Entity<OreSiloComponent> ent, ref BoundUIOpenedEvent args)
|
||||
{
|
||||
UpdateOreSiloUi(ent);
|
||||
}
|
||||
|
||||
private void OnSiloShutdown(Entity<OreSiloComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
foreach (var client in ent.Comp.Clients)
|
||||
{
|
||||
if (!_clientQuery.TryComp(client, out var comp))
|
||||
continue;
|
||||
|
||||
comp.Silo = null;
|
||||
Dirty(client, comp);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void UpdateOreSiloUi(Entity<OreSiloComponent> ent)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private void OnGetStoredMaterials(Entity<OreSiloClientComponent> ent, ref GetStoredMaterialsEvent args)
|
||||
{
|
||||
if (args.LocalOnly)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Silo is not { } silo)
|
||||
return;
|
||||
|
||||
if (!CanTransmitMaterials(silo, ent))
|
||||
return;
|
||||
|
||||
var materials = _materialStorage.GetStoredMaterials(silo);
|
||||
|
||||
foreach (var (mat, amount) in materials)
|
||||
{
|
||||
// Don't supply materials that they don't usually have access to.
|
||||
if (!_materialStorage.IsMaterialWhitelisted((args.Entity, args.Entity), mat))
|
||||
continue;
|
||||
|
||||
var existing = args.Materials.GetOrNew(mat);
|
||||
args.Materials[mat] = existing + amount;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnConsumeStoredMaterials(Entity<OreSiloClientComponent> ent, ref ConsumeStoredMaterialsEvent args)
|
||||
{
|
||||
if (args.LocalOnly)
|
||||
return;
|
||||
|
||||
if (ent.Comp.Silo is not { } silo || !TryComp<MaterialStorageComponent>(silo, out var materialStorage))
|
||||
return;
|
||||
|
||||
if (!CanTransmitMaterials(silo, ent))
|
||||
return;
|
||||
|
||||
foreach (var (mat, amount) in args.Materials)
|
||||
{
|
||||
if (!_materialStorage.TryChangeMaterialAmount(silo, mat, amount, materialStorage))
|
||||
continue;
|
||||
args.Materials[mat] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnClientShutdown(Entity<OreSiloClientComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (!TryComp<OreSiloComponent>(ent.Comp.Silo, out var silo))
|
||||
return;
|
||||
|
||||
silo.Clients.Remove(ent);
|
||||
Dirty(ent.Comp.Silo.Value, silo);
|
||||
UpdateOreSiloUi((ent.Comp.Silo.Value, silo));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a given client fulfills the criteria to link/receive materials from an ore silo.
|
||||
/// </summary>
|
||||
[PublicAPI]
|
||||
public bool CanTransmitMaterials(Entity<OreSiloComponent?> silo, EntityUid client)
|
||||
{
|
||||
if (!Resolve(silo, ref silo.Comp))
|
||||
return false;
|
||||
|
||||
if (!_powerReceiver.IsPowered(silo.Owner))
|
||||
return false;
|
||||
|
||||
if (_transform.GetGrid(client) != _transform.GetGrid(silo.Owner))
|
||||
return false;
|
||||
|
||||
if (!_transform.InRange(silo.Owner, client, silo.Comp.Range))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
using System.Linq;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.Whitelist;
|
||||
using JetBrains.Annotations;
|
||||
|
|
@ -58,16 +57,22 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume of a specified material contained in this storage.
|
||||
/// Gets all the materials stored on this entity
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
[PublicAPI]
|
||||
public int GetMaterialAmount(EntityUid uid, MaterialPrototype material, MaterialStorageComponent? component = null)
|
||||
/// <param name="ent"></param>
|
||||
/// <param name="localOnly">Include only materials held "locally", as determined by event subscribers</param>
|
||||
/// <returns></returns>
|
||||
public Dictionary<ProtoId<MaterialPrototype>, int> GetStoredMaterials(Entity<MaterialStorageComponent?> ent, bool localOnly = false)
|
||||
{
|
||||
return GetMaterialAmount(uid, material.ID, component);
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return new();
|
||||
|
||||
// clone so we don't modify by accident.
|
||||
var mats = new Dictionary<ProtoId<MaterialPrototype>, int>(ent.Comp.Storage);
|
||||
var ev = new GetStoredMaterialsEvent((ent, ent.Comp), mats, localOnly);
|
||||
RaiseLocalEvent(ent, ref ev, true);
|
||||
|
||||
return ev.Materials;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -76,12 +81,27 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
public int GetMaterialAmount(EntityUid uid, string material, MaterialStorageComponent? component = null)
|
||||
[PublicAPI]
|
||||
public int GetMaterialAmount(EntityUid uid, MaterialPrototype material, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
return GetMaterialAmount(uid, material.ID, component, localOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the volume of a specified material contained in this storage.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="material"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of the material</returns>
|
||||
public int GetMaterialAmount(EntityUid uid, string material, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0; //you have nothing
|
||||
return component.Storage.GetValueOrDefault(material, 0);
|
||||
return GetStoredMaterials((uid, component), localOnly).GetValueOrDefault(material, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -89,26 +109,43 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>The volume of all materials in the storage</returns>
|
||||
public int GetTotalMaterialAmount(EntityUid uid, MaterialStorageComponent? component = null)
|
||||
public int GetTotalMaterialAmount(EntityUid uid, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return 0;
|
||||
return component.Storage.Values.Sum();
|
||||
return GetStoredMaterials((uid, component), localOnly).Values.Sum();
|
||||
}
|
||||
|
||||
// TODO: Revisit this if we ever decide to do things with storage limits. As it stands, the feature is unused.
|
||||
/// <summary>
|
||||
/// Tests if a specific amount of volume will fit in the storage.
|
||||
/// </summary>
|
||||
/// <param name="uid"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If the specified volume will fit</returns>
|
||||
public bool CanTakeVolume(EntityUid uid, int volume, MaterialStorageComponent? component = null)
|
||||
public bool CanTakeVolume(EntityUid uid, int volume, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
return component.StorageLimit == null || GetTotalMaterialAmount(uid, component) + volume <= component.StorageLimit;
|
||||
return component.StorageLimit == null || GetTotalMaterialAmount(uid, component, true) + volume <= component.StorageLimit;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a certain material prototype is supported by this entity.
|
||||
/// </summary>
|
||||
public bool IsMaterialWhitelisted(Entity<MaterialStorageComponent?> ent, ProtoId<MaterialPrototype> material)
|
||||
{
|
||||
if (!Resolve(ent, ref ent.Comp))
|
||||
return false;
|
||||
|
||||
if (ent.Comp.MaterialWhiteList == null)
|
||||
return true;
|
||||
|
||||
return ent.Comp.MaterialWhiteList.Contains(material);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -118,8 +155,9 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// <param name="materialId"></param>
|
||||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool CanChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null)
|
||||
public bool CanChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
|
@ -127,10 +165,10 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
if (!CanTakeVolume(uid, volume, component))
|
||||
return false;
|
||||
|
||||
if (component.MaterialWhiteList == null ? false : !component.MaterialWhiteList.Contains(materialId))
|
||||
if (!IsMaterialWhitelisted((uid, component), materialId))
|
||||
return false;
|
||||
|
||||
var amount = component.Storage.GetValueOrDefault(materialId);
|
||||
var amount = GetMaterialAmount(uid, materialId, component, localOnly);
|
||||
return amount + volume >= 0;
|
||||
}
|
||||
|
||||
|
|
@ -140,14 +178,24 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// <param name="entity"></param>
|
||||
/// <param name="materials"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool CanChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
|
||||
/// <param name="localOnly"></param>
|
||||
public bool CanChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return false;
|
||||
|
||||
var inVolume = materials.Values.Sum();
|
||||
var stored = GetStoredMaterials((entity, entity.Comp), localOnly);
|
||||
|
||||
if (!CanTakeVolume(entity, inVolume, entity.Comp))
|
||||
return false;
|
||||
|
||||
foreach (var (material, amount) in materials)
|
||||
{
|
||||
if (!CanChangeMaterialAmount(entity, material, amount, entity.Comp))
|
||||
if (!IsMaterialWhitelisted(entity, material))
|
||||
return false;
|
||||
|
||||
if (stored.GetValueOrDefault(material) + amount < 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -163,16 +211,27 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// <param name="volume"></param>
|
||||
/// <param name="component"></param>
|
||||
/// <param name="dirty"></param>
|
||||
/// <param name="localOnly"></param>
|
||||
/// <returns>If it was successful</returns>
|
||||
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool dirty = true)
|
||||
public bool TryChangeMaterialAmount(EntityUid uid, string materialId, int volume, MaterialStorageComponent? component = null, bool dirty = true, bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
if (!CanChangeMaterialAmount(uid, materialId, volume, component))
|
||||
|
||||
if (!CanChangeMaterialAmount(uid, materialId, volume, component, localOnly))
|
||||
return false;
|
||||
|
||||
var changeEv = new ConsumeStoredMaterialsEvent((uid, component), new() {{materialId, volume}}, localOnly);
|
||||
RaiseLocalEvent(uid, ref changeEv);
|
||||
var remaining = changeEv.Materials.Values.First();
|
||||
|
||||
var existing = component.Storage.GetOrNew(materialId);
|
||||
existing += volume;
|
||||
|
||||
var localUpperLimit = component.StorageLimit == null ? int.MaxValue : component.StorageLimit.Value - existing;
|
||||
var localLowerLimit = -existing;
|
||||
var localChange = Math.Clamp(remaining, localLowerLimit, localUpperLimit);
|
||||
|
||||
existing += localChange;
|
||||
|
||||
if (existing == 0)
|
||||
component.Storage.Remove(materialId);
|
||||
|
|
@ -191,23 +250,54 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// Changes the amount of a specific material in the storage.
|
||||
/// Still respects the filters in place.
|
||||
/// </summary>
|
||||
/// <param name="entity"></param>
|
||||
/// <param name="materials"></param>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool TryChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string,int> materials)
|
||||
public bool TryChangeMaterialAmount(Entity<MaterialStorageComponent?> entity, Dictionary<string, int> materials, bool localOnly = false)
|
||||
{
|
||||
return TryChangeMaterialAmount(entity, materials.Select(p => (new ProtoId<MaterialPrototype>(p.Key), p.Value)).ToDictionary(), localOnly);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the amount of a specific material in the storage.
|
||||
/// Still respects the filters in place.
|
||||
/// </summary>
|
||||
/// <returns>If the amount can be changed</returns>
|
||||
public bool TryChangeMaterialAmount(
|
||||
Entity<MaterialStorageComponent?> entity,
|
||||
Dictionary<ProtoId<MaterialPrototype>, int> materials,
|
||||
bool localOnly = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return false;
|
||||
|
||||
if (!CanChangeMaterialAmount(entity, materials))
|
||||
return false;
|
||||
|
||||
foreach (var (material, amount) in materials)
|
||||
{
|
||||
if (!TryChangeMaterialAmount(entity, material, amount, entity.Comp, false))
|
||||
if (!CanChangeMaterialAmount(entity, material, amount, entity))
|
||||
return false;
|
||||
}
|
||||
|
||||
var changeEv = new ConsumeStoredMaterialsEvent((entity, entity.Comp), materials, localOnly);
|
||||
RaiseLocalEvent(entity, ref changeEv);
|
||||
|
||||
foreach (var (material, remaining) in changeEv.Materials)
|
||||
{
|
||||
var existing = entity.Comp.Storage.GetOrNew(material);
|
||||
|
||||
var localUpperLimit = entity.Comp.StorageLimit == null ? int.MaxValue : entity.Comp.StorageLimit.Value - existing;
|
||||
var localLowerLimit = -existing;
|
||||
var localChange = Math.Clamp(remaining, localLowerLimit, localUpperLimit);
|
||||
|
||||
existing += localChange;
|
||||
|
||||
if (existing == 0)
|
||||
entity.Comp.Storage.Remove(material);
|
||||
else
|
||||
entity.Comp.Storage[material] = existing;
|
||||
|
||||
}
|
||||
|
||||
var ev = new MaterialAmountChangedEvent();
|
||||
RaiseLocalEvent(entity, ref ev);
|
||||
|
||||
Dirty(entity, entity.Comp);
|
||||
return true;
|
||||
}
|
||||
|
|
@ -221,6 +311,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
/// <param name="volume">The stored material volume to set the storage to.</param>
|
||||
/// <param name="component">The storage component on <paramref name="uid"/>. Resolved automatically if not given.</param>
|
||||
/// <returns>True if it was successful (enough space etc).</returns>
|
||||
[PublicAPI]
|
||||
public bool TrySetMaterialAmount(
|
||||
EntityUid uid,
|
||||
string materialId,
|
||||
|
|
@ -268,7 +359,7 @@ public abstract class SharedMaterialStorageSystem : EntitySystem
|
|||
totalVolume += vol * multiplier;
|
||||
}
|
||||
|
||||
if (!CanTakeVolume(receiver, totalVolume, storage))
|
||||
if (!CanTakeVolume(receiver, totalVolume, storage, localOnly: true))
|
||||
return false;
|
||||
|
||||
foreach (var (mat, vol) in composition.MaterialComposition)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Shuttles.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Add to grids that you do not want to FTL, but still might want to pilot.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class PreventFTLComponent : Component;
|
||||
|
|
@ -17,7 +17,7 @@ public sealed partial class PendingZombieComponent : Component
|
|||
{
|
||||
DamageDict = new ()
|
||||
{
|
||||
{ "Poison", 0.2 },
|
||||
{ "Poison", 0.4 },
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,57 +1,4 @@
|
|||
Entries:
|
||||
- author: Beck Thompson
|
||||
changes:
|
||||
- message: Defibrillator cooldowns are now clearly visible.
|
||||
type: Tweak
|
||||
id: 7740
|
||||
time: '2024-12-20T21:26:56.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/31251
|
||||
- author: J C Denton
|
||||
changes:
|
||||
- message: Syndicate and NanoTrasen NPCs and turrets are now hostile to Dragons
|
||||
and Carps
|
||||
type: Tweak
|
||||
id: 7741
|
||||
time: '2024-12-20T21:38:27.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32515
|
||||
- author: lzk228
|
||||
changes:
|
||||
- message: Item's tool function now shows on examine.
|
||||
type: Add
|
||||
id: 7742
|
||||
time: '2024-12-20T22:15:40.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32436
|
||||
- author: Pinkbat5
|
||||
changes:
|
||||
- message: Diona can now chirp.
|
||||
type: Add
|
||||
- message: Nymphs can scream and laugh like adult diona.
|
||||
type: Add
|
||||
id: 7743
|
||||
time: '2024-12-20T22:34:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32511
|
||||
- author: ScarKy0
|
||||
changes:
|
||||
- message: Syndicate uplinks now have 6 discounts instead of 3.
|
||||
type: Tweak
|
||||
id: 7744
|
||||
time: '2024-12-21T02:14:08.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33950
|
||||
- author: JustinWinningham
|
||||
changes:
|
||||
- message: Wood walls no longer require girders and are built from barricades instead.
|
||||
type: Tweak
|
||||
id: 7745
|
||||
time: '2024-12-21T03:28:46.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33902
|
||||
- author: ElectroJr
|
||||
changes:
|
||||
- message: Toolshed console commands have been reworked. Some old commands may no
|
||||
longer work.
|
||||
type: Tweak
|
||||
id: 7746
|
||||
time: '2024-12-21T06:45:48.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33598
|
||||
- author: muburu
|
||||
changes:
|
||||
- message: Space Ninjas now have silent footsteps.
|
||||
|
|
@ -3912,3 +3859,56 @@
|
|||
id: 8240
|
||||
time: '2025-04-18T23:26:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/32396
|
||||
- author: ScarKy0
|
||||
changes:
|
||||
- message: Changed the air vent and scrubber sprites.
|
||||
type: Tweak
|
||||
id: 8241
|
||||
time: '2025-04-18T23:34:59.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/34223
|
||||
- author: EmoGarbage404
|
||||
changes:
|
||||
- message: Added the material silo. This machine allows nearby machines to share
|
||||
a pool of resources, cutting down on micromanagement.
|
||||
type: Add
|
||||
id: 8242
|
||||
time: '2025-04-18T23:43:17.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36492
|
||||
- author: Onezero0
|
||||
changes:
|
||||
- message: Modular Grenades can now fit inside Security belts and carriers.
|
||||
type: Tweak
|
||||
id: 8243
|
||||
time: '2025-04-19T00:04:44.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/34169
|
||||
- author: Alpaccalypse
|
||||
changes:
|
||||
- message: The cocktail "Irish slammer" has been renamed to "Grenade Penguin".
|
||||
type: Tweak
|
||||
id: 8244
|
||||
time: '2025-04-19T00:24:26.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/34181
|
||||
- author: ScarKy0
|
||||
changes:
|
||||
- message: Added a couple more tools to the artifact borg module.
|
||||
type: Tweak
|
||||
id: 8245
|
||||
time: '2025-04-19T00:25:29.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/33338
|
||||
- author: august-sun
|
||||
changes:
|
||||
- message: Resprited the Chief Engineer's mantle.
|
||||
type: Tweak
|
||||
id: 8246
|
||||
time: '2025-04-19T00:26:24.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/36697
|
||||
- author: IProduceWidgets
|
||||
changes:
|
||||
- message: Vox are no longer immune to the zombie virus under certain circumstances
|
||||
type: Fix
|
||||
- message: The zombie virus no longer provides non-Initial Infected an undue grace
|
||||
period before poisoning them.
|
||||
type: Fix
|
||||
id: 8247
|
||||
time: '2025-04-19T00:38:33.0000000+00:00'
|
||||
url: https://github.com/space-wizards/space-station-14/pull/34472
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ lathe-menu-material-amount-missing = { $amount ->
|
|||
*[other] {NATURALFIXED($amount, 2)} {MAKEPLURAL($unit)} of {$material} ([color=red]{NATURALFIXED($missingAmount, 2)} {MAKEPLURAL($unit)} missing[/color])
|
||||
}
|
||||
lathe-menu-no-materials-message = No materials loaded.
|
||||
lathe-menu-silo-linked-message = Silo Linked
|
||||
lathe-menu-fabricating-message = Fabricating...
|
||||
lathe-menu-materials-title = Materials
|
||||
lathe-menu-queue-title = Build Queue
|
||||
|
|
|
|||
10
Resources/Locale/en-US/_strings/materials/silo.ftl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
ore-silo-ui-title = Material Silo
|
||||
ore-silo-ui-label-clients = Machines
|
||||
ore-silo-ui-label-mats = Materials
|
||||
ore-silo-ui-itemlist-entry = {$linked ->
|
||||
[true] {"[Linked] "}
|
||||
*[False] {""}
|
||||
} {$name} ({$beacon}) {$inRange ->
|
||||
[true] {""}
|
||||
*[false] (Out of Range)
|
||||
}
|
||||
|
|
@ -157,8 +157,8 @@ reagent-desc-hooch = Either someone's failure at cocktail making or attempt in a
|
|||
reagent-name-iced-beer = iced beer
|
||||
reagent-desc-iced-beer = A beer which is so cold the air around it freezes.
|
||||
|
||||
reagent-name-irish-slammer = Irish slammer
|
||||
reagent-desc-irish-slammer = An unconventional mixture of irish cream and stout.
|
||||
reagent-name-irish-slammer = Grenade Penguin
|
||||
reagent-desc-irish-slammer = What's black and white and red all over?
|
||||
|
||||
reagent-name-irish-cream = Irish cream
|
||||
reagent-desc-irish-cream = Whiskey-imbued cream. What else could you expect from the Irish.
|
||||
|
|
|
|||
|
|
@ -98,6 +98,16 @@
|
|||
category: cargoproduct-category-name-materials
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: MaterialSilo
|
||||
icon:
|
||||
sprite: Structures/Machines/silo.rsi
|
||||
state: silo
|
||||
product: CrateMaterialSilo
|
||||
cost: 5000
|
||||
category: cargoproduct-category-name-materials
|
||||
group: market
|
||||
|
||||
- type: cargoProduct
|
||||
id: MaterialFuelTank
|
||||
icon:
|
||||
|
|
|
|||
|
|
@ -153,6 +153,22 @@
|
|||
# for some reason, the selector here adds 1 to whatever value it generates,
|
||||
# so this is actually 2-4
|
||||
|
||||
- type: entity
|
||||
id: CrateMaterialSilo
|
||||
parent: CrateGenericSteel
|
||||
name: material silo crate
|
||||
description: A package including all the materials to create a material silo.
|
||||
components:
|
||||
- type: StorageFill
|
||||
contents:
|
||||
- id: MaterialSiloMachineCircuitboard
|
||||
- id: SheetSteel1
|
||||
amount: 5
|
||||
- id: MatterBinStockPart
|
||||
amount: 4
|
||||
- id: CableApcStack1
|
||||
amount: 2
|
||||
|
||||
- type: entity
|
||||
id: CrateMaterialBasicResource
|
||||
parent: CrateGenericSteel
|
||||
|
|
|
|||
|
|
@ -513,6 +513,7 @@
|
|||
- MagazineMagnum
|
||||
- CombatKnife
|
||||
- Truncheon
|
||||
- HandGrenade
|
||||
components:
|
||||
- Stunbaton
|
||||
- FlashOnTrigger
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@
|
|||
- type: entity
|
||||
parent: [ClothingNeckBase, BaseCommandContraband]
|
||||
id: ClothingNeckMantleCE
|
||||
name: chief engineer's mantle
|
||||
description: High visibility, check. RIG system, check. High capacity cell, check. Everything a chief engineer could need in a stylish mantle.
|
||||
name: chief engineer's manica
|
||||
description: A segmented arm covering for the experienced Chief Engineer, to signify the hazards of the job and the dangers faced to earn it.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Clothing/Neck/mantles/cemantle.rsi
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
damage:
|
||||
types:
|
||||
Heat: -0.07
|
||||
Poison: -0.2
|
||||
Poison: -0.2 # needs to be less than the PendingZombieComponent does or they never become zombies by the disease.
|
||||
groups:
|
||||
Brute: -0.07
|
||||
- type: DamageVisuals
|
||||
|
|
|
|||
|
|
@ -1124,7 +1124,7 @@
|
|||
- type: entity
|
||||
parent: DrinkGlass
|
||||
id: DrinkIrishSlammer
|
||||
suffix: irish slammer
|
||||
suffix: grenade penguin
|
||||
components:
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
|
|
|
|||
|
|
@ -1005,6 +1005,19 @@
|
|||
Manipulator: 1
|
||||
Steel: 1
|
||||
|
||||
- type: entity
|
||||
id: MaterialSiloMachineCircuitboard
|
||||
parent: BaseMachineCircuitboard
|
||||
name: material silo machine board
|
||||
components:
|
||||
- type: Sprite
|
||||
state: supply
|
||||
- type: MachineBoard
|
||||
prototype: MachineMaterialSilo
|
||||
stackRequirements:
|
||||
MatterBin: 4
|
||||
Cable: 1
|
||||
|
||||
- type: entity
|
||||
id: OreProcessorMachineCircuitboard
|
||||
parent: BaseMachineCircuitboard
|
||||
|
|
|
|||
|
|
@ -601,6 +601,11 @@
|
|||
- type: ItemBorgModule
|
||||
items:
|
||||
- NodeScanner
|
||||
- Multitool
|
||||
- Wrench
|
||||
- SprayBottle
|
||||
- Beaker
|
||||
- Syringe
|
||||
- type: BorgModuleIcon
|
||||
icon: { sprite: Interface/Actions/actions_borg.rsi, state: node-scanner-module }
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@
|
|||
enum.ConstructionVisuals.Layer:
|
||||
Primed: { state: primed }
|
||||
Unprimed: { state: icon }
|
||||
- type: Tag
|
||||
tags:
|
||||
- HandGrenade
|
||||
|
||||
- type: entity
|
||||
name: explosive grenade
|
||||
|
|
@ -85,6 +88,7 @@
|
|||
- Antagonists
|
||||
- type: Tag
|
||||
tags:
|
||||
- HandGrenade
|
||||
- GrenadeFlashBang
|
||||
|
||||
- type: entity
|
||||
|
|
@ -314,6 +318,9 @@
|
|||
map: [ "enum.ConstructionVisuals.Layer" ]
|
||||
- type: Item
|
||||
size: Small
|
||||
- type: Tag
|
||||
tags:
|
||||
- HandGrenade
|
||||
- type: PayloadCase
|
||||
- type: Construction
|
||||
graph: ModularGrenadeGraph
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@
|
|||
enum.ConstructionVisuals.Layer:
|
||||
Primed: { state: primed }
|
||||
Unprimed: { state: icon }
|
||||
- type: Tag
|
||||
tags:
|
||||
- HandGrenade
|
||||
|
||||
- type: entity
|
||||
parent: [ProjectileGrenadeBase, BaseSecurityContraband]
|
||||
|
|
|
|||
|
|
@ -18,6 +18,9 @@
|
|||
behaviors:
|
||||
- !type:TriggerBehavior
|
||||
- type: ScatteringGrenade
|
||||
- type: Tag
|
||||
tags:
|
||||
- HandGrenade
|
||||
|
||||
- type: entity
|
||||
parent: [ScatteringGrenadeBase, BaseSecurityContraband]
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@
|
|||
- Sheet
|
||||
materialWhiteList:
|
||||
- Plasma
|
||||
- type: OreSiloClient
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: AmbientSound
|
||||
enabled: false
|
||||
volume: 5
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: Lathe
|
||||
idleState: icon
|
||||
runningState: building
|
||||
|
|
@ -185,6 +186,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: Lathe
|
||||
idleState: icon
|
||||
runningState: building
|
||||
|
|
@ -283,6 +285,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: RequireProjectileTarget
|
||||
|
||||
- type: entity
|
||||
|
|
@ -333,6 +336,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: GuideHelp
|
||||
guides:
|
||||
- Robotics
|
||||
|
|
@ -422,6 +426,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
- type: LatheAnnouncing
|
||||
channels: [Security]
|
||||
|
||||
|
|
@ -457,6 +462,7 @@
|
|||
- Sheet
|
||||
- RawMaterial
|
||||
- Ingot
|
||||
- type: OreSiloClient
|
||||
|
||||
- type: entity
|
||||
id: MedicalTechFab
|
||||
|
|
@ -497,6 +503,7 @@
|
|||
board: MedicalTechFabCircuitboard
|
||||
- type: StealTarget
|
||||
stealGroup: MedicalTechFabCircuitboard
|
||||
- type: OreSiloClient
|
||||
- type: LatheAnnouncing
|
||||
channels: [Medical]
|
||||
|
||||
|
|
|
|||
61
Resources/Prototypes/Entities/Structures/Machines/silo.yml
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
- type: entity
|
||||
id: MachineMaterialSilo
|
||||
parent: [ BaseMachinePowered, ConstructibleMachine ]
|
||||
name: material silo
|
||||
description: An advanced machine, capable of using bluespace technology to transmit materials to nearby machines.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: Structures/Machines/silo.rsi
|
||||
layers:
|
||||
- state: silo
|
||||
map: [ "base" ]
|
||||
- type: Appearance
|
||||
- type: GenericVisualizer
|
||||
visuals:
|
||||
enum.PowerDeviceVisuals.Powered:
|
||||
base:
|
||||
True: { state: silo_active }
|
||||
False: { state: silo }
|
||||
- type: OreSilo
|
||||
- type: MaterialStorage
|
||||
whitelist:
|
||||
tags:
|
||||
- Sheet
|
||||
- Ingot
|
||||
- type: ActivatableUI
|
||||
key: enum.OreSiloUiKey.Key
|
||||
- type: ActivatableUIRequiresPower
|
||||
- type: UserInterface
|
||||
interfaces:
|
||||
enum.OreSiloUiKey.Key:
|
||||
type: OreSiloBoundUserInterface
|
||||
- type: Machine
|
||||
board: MaterialSiloMachineCircuitboard
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.4,-0.4,0.4,0.4"
|
||||
density: 190
|
||||
mask:
|
||||
- MachineMask
|
||||
layer:
|
||||
- MachineLayer
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 300
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: MetalBreak
|
||||
- !type:ChangeConstructionNodeBehavior
|
||||
node: machineFrame
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- type: WiresVisuals
|
||||
- type: WiresPanel
|
||||
- type: StaticPrice
|
||||
price: 1500
|
||||
|
|
@ -500,6 +500,8 @@
|
|||
parent: BaseDrink
|
||||
desc: reagent-desc-water
|
||||
slippery: true
|
||||
evaporationSpeed: 0.3
|
||||
absorbent: true
|
||||
physicalDesc: reagent-physical-desc-translucent
|
||||
flavor: water
|
||||
color: "#75b1f0"
|
||||
|
|
|
|||
|
|
@ -573,6 +573,8 @@
|
|||
amount: 1
|
||||
products:
|
||||
IrishSlammer: 2
|
||||
sound:
|
||||
path: /Audio/Animals/penguin_squawk.ogg # Cocktail is called grenade penguin in localisation
|
||||
|
||||
- type: reaction
|
||||
id: IrishCoffee
|
||||
|
|
|
|||
|
|
@ -641,6 +641,9 @@
|
|||
- type: Tag
|
||||
id: Handcuffs
|
||||
|
||||
- type: Tag
|
||||
id: HandGrenade
|
||||
|
||||
- type: Tag
|
||||
id: HappyHonk
|
||||
|
||||
|
|
|
|||
40
Resources/Textures/Structures/Machines/silo.rsi/meta.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"version": 1,
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/d74b67828394a9842578279a6b8ab2955bb08216. Created by MrDoomBringer (github)",
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"states": [
|
||||
{
|
||||
"name": "silo"
|
||||
},
|
||||
{
|
||||
"name": "silo_active",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "overlay_active",
|
||||
"delays": [
|
||||
[
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1,
|
||||
0.1
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
After Width: | Height: | Size: 336 B |
BIN
Resources/Textures/Structures/Machines/silo.rsi/silo.png
Normal file
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Resources/Textures/Structures/Machines/silo.rsi/silo_active.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
|
|
@ -1,34 +1,133 @@
|
|||
{
|
||||
"version":1,
|
||||
"size":{
|
||||
"x":32,
|
||||
"y":32
|
||||
},
|
||||
"license":"CC-BY-SA-3.0",
|
||||
"copyright":"Taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da",
|
||||
"states":[
|
||||
{
|
||||
"name":"scrub_off",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name":"scrub_welded",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name":"scrub_on",
|
||||
"directions": 4,
|
||||
"delays": [[0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08], [0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08, 0.08]]
|
||||
},
|
||||
{
|
||||
"name": "scrub_purge",
|
||||
"directions": 4,
|
||||
"delays": [[0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]]
|
||||
},
|
||||
{
|
||||
"name": "scrub_wide",
|
||||
"directions": 4,
|
||||
"delays": [[0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04], [0.2, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04]]
|
||||
}
|
||||
]
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/32742/commits/44820f5b6e2c864a35bfad448e0a9437f01ad2e2",
|
||||
"states": [
|
||||
{
|
||||
"name": "scrub_off",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "scrub_welded",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "scrub_on",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "scrub_purge",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06
|
||||
],
|
||||
[
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06
|
||||
],
|
||||
[
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06
|
||||
],
|
||||
[
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06,
|
||||
0.06
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "scrub_wide",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
],
|
||||
[
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10,
|
||||
0.10
|
||||
]
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1,002 B After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 6.5 KiB |
|
|
@ -1,37 +1,103 @@
|
|||
{
|
||||
"version":1,
|
||||
"size":{
|
||||
"x":32,
|
||||
"y":32
|
||||
},
|
||||
"license":"CC-BY-SA-3.0",
|
||||
"copyright":"Taken from https://github.com/BeeStation/BeeStation-Hornet at commit 4ccd79de285e79e504308bcd6fa5908d6b7685f7",
|
||||
"states":[
|
||||
{
|
||||
"name":"vent_passive",
|
||||
"directions" : 4
|
||||
},
|
||||
{
|
||||
"name":"vent_off",
|
||||
"directions" : 4
|
||||
},
|
||||
{
|
||||
"name":"vent_welded",
|
||||
"directions" : 4
|
||||
},
|
||||
{
|
||||
"name":"vent_out",
|
||||
"directions" : 4,
|
||||
"delays":[ [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ] ]
|
||||
},
|
||||
{
|
||||
"name":"vent_in",
|
||||
"directions" : 4,
|
||||
"delays":[ [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ], [ 0.08, 0.08, 0.08, 0.08 ] ]
|
||||
},
|
||||
{
|
||||
"name":"vent_lockout",
|
||||
"directions" : 4
|
||||
}
|
||||
]
|
||||
"version": 1,
|
||||
"size": {
|
||||
"x": 32,
|
||||
"y": 32
|
||||
},
|
||||
"license": "CC-BY-SA-3.0",
|
||||
"copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/32742/commits/44820f5b6e2c864a35bfad448e0a9437f01ad2e2",
|
||||
"states": [
|
||||
{
|
||||
"name": "vent_passive",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "vent_off",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "vent_welded",
|
||||
"directions": 4
|
||||
},
|
||||
{
|
||||
"name": "vent_out",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "vent_in",
|
||||
"directions": 4,
|
||||
"delays": [
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
],
|
||||
[
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05,
|
||||
0.05
|
||||
]
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "vent_lockout",
|
||||
"directions": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 4.1 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 853 B |
|
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 1.8 KiB |