Machine-code cleanup (#28489)

This commit is contained in:
Nemanja 2024-06-05 22:23:23 +02:00 committed by null
parent e92d9031b3
commit e057218952
No known key found for this signature in database
GPG Key ID: 212F05528FD678BE
35 changed files with 438 additions and 982 deletions

View File

@ -75,8 +75,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
else if (_currentBoard != null)
{
Dictionary<string, int> cost;
if (_entityManager.TryGetComponent(_currentBoard, out machineBoardComp) &&
machineBoardComp.Prototype is not null)
if (_entityManager.TryGetComponent(_currentBoard, out machineBoardComp))
cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker), (_currentBoard.Value, machineBoardComp));
else
cost = _flatpack.GetFlatpackCreationCost((_owner, flatpacker));

View File

@ -2,6 +2,8 @@
using System.Linq;
using Content.Server.Construction.Components;
using Content.Shared.Construction.Components;
using Content.Shared.Prototypes;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests;
@ -49,12 +51,11 @@ public sealed class MachineBoardTest
Assert.Multiple(() =>
{
Assert.That(mId, Is.Not.Null, $"Machine board {p.ID} does not have a corresponding machine.");
Assert.That(protoMan.TryIndex<EntityPrototype>(mId, out var mProto),
$"Machine board {p.ID}'s corresponding machine has an invalid prototype.");
Assert.That(mProto.TryGetComponent<MachineComponent>(out var mComp),
$"Machine board {p.ID}'s corresponding machine {mId} does not have MachineComponent");
Assert.That(mComp.BoardPrototype, Is.EqualTo(p.ID),
Assert.That(mComp.Board, Is.EqualTo(p.ID),
$"Machine {mId}'s BoardPrototype is not equal to it's corresponding machine board, {p.ID}");
});
}
@ -101,4 +102,40 @@ public sealed class MachineBoardTest
await pair.CleanReturnAsync();
}
/// <summary>
/// Ensures that every single computer board's corresponding entity
/// is a computer that can be properly deconstructed to the correct board
/// </summary>
[Test]
public async Task TestValidateBoardComponentRequirements()
{
await using var pair = await PoolManager.GetServerClient();
var server = pair.Server;
var entMan = server.ResolveDependency<IEntityManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
await server.WaitAssertion(() =>
{
foreach (var p in protoMan.EnumeratePrototypes<EntityPrototype>()
.Where(p => !p.Abstract)
.Where(p => !pair.IsTestPrototype(p))
.Where(p => !_ignoredPrototypes.Contains(p.ID)))
{
if (!p.TryGetComponent<MachineBoardComponent>(out var board, entMan.ComponentFactory))
continue;
Assert.Multiple(() =>
{
foreach (var component in board.ComponentRequirements.Keys)
{
Assert.That(entMan.ComponentFactory.TryGetRegistration(component, out _), $"Invalid component requirement {component} specified on machine board entity {p}");
}
});
}
});
await pair.CleanReturnAsync();
}
}

View File

@ -60,7 +60,8 @@ public sealed class MaterialArbitrageTest
}
// Lets assume the possible lathe for resource multipliers:
var multiplier = MathF.Pow(LatheComponent.DefaultPartRatingMaterialUseMultiplier, MachinePartComponent.MaxRating - 1);
// TODO: each recipe can technically have its own cost multiplier associated with it, so this test needs redone to factor that in.
var multiplier = MathF.Pow(0.85f, 3);
// create construction dictionary
Dictionary<string, ConstructionComponent> constructionRecipes = new();

View File

@ -1,10 +0,0 @@
using Content.Shared.Construction.Components;
namespace Content.Server.Construction.Components
{
[RequiresExplicitImplementation]
public interface IRefreshParts
{
void RefreshParts(IEnumerable<MachinePartComponent> parts);
}
}

View File

@ -1,27 +1,17 @@
using Robust.Shared.Containers;
using Content.Shared.Construction.Components;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Construction.Components
namespace Content.Server.Construction.Components;
[RegisterComponent]
public sealed partial class MachineComponent : Component
{
[RegisterComponent, ComponentProtoName("Machine")]
public sealed partial class MachineComponent : Component
{
[DataField("board", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? BoardPrototype { get; private set; }
[DataField]
public EntProtoId<MachineBoardComponent>? Board { get; private set; }
[ViewVariables]
public Container BoardContainer = default!;
[ViewVariables]
public Container PartContainer = default!;
}
/// <summary>
/// The different types of scaling that are available for machine upgrades
/// </summary>
public enum MachineUpgradeScalingType : byte
{
Linear,
Exponential
}
[ViewVariables]
public Container BoardContainer = default!;
[ViewVariables]
public Container PartContainer = default!;
}

View File

@ -1,7 +1,8 @@
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Stacks;
using Content.Shared.Tag;
using Robust.Shared.Containers;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
using Robust.Shared.Prototypes;
namespace Content.Server.Construction.Components
{
@ -14,29 +15,23 @@ namespace Content.Server.Construction.Components
[ViewVariables]
public bool HasBoard => BoardContainer?.ContainedEntities.Count != 0;
[DataField("progress", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, MachinePartPrototype>))]
public Dictionary<string, int> Progress = new();
[ViewVariables]
public readonly Dictionary<string, int> MaterialProgress = new();
public readonly Dictionary<ProtoId<StackPrototype>, int> MaterialProgress = new();
[ViewVariables]
public readonly Dictionary<string, int> ComponentProgress = new();
[ViewVariables]
public readonly Dictionary<string, int> TagProgress = new();
[DataField("requirements", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, MachinePartPrototype>))]
public Dictionary<string, int> Requirements = new();
public readonly Dictionary<ProtoId<TagPrototype>, int> TagProgress = new();
[ViewVariables]
public Dictionary<string, int> MaterialRequirements = new();
public Dictionary<ProtoId<StackPrototype>, int> MaterialRequirements = new();
[ViewVariables]
public Dictionary<string, GenericPartInfo> ComponentRequirements = new();
[ViewVariables]
public Dictionary<string, GenericPartInfo> TagRequirements = new();
public Dictionary<ProtoId<TagPrototype>, GenericPartInfo> TagRequirements = new();
[ViewVariables]
public Container BoardContainer = default!;

View File

@ -1,29 +0,0 @@
using Robust.Shared.Audio;
namespace Content.Server.Construction.Components;
[RegisterComponent]
public sealed partial class PartExchangerComponent : Component
{
/// <summary>
/// How long it takes to exchange the parts
/// </summary>
[DataField("exchangeDuration")]
public float ExchangeDuration = 3;
/// <summary>
/// Whether or not the distance check is needed.
/// Good for BRPED.
/// </summary>
/// <remarks>
/// I fucking hate BRPED and if you ever add it
/// i will personally kill your dog.
/// </remarks>
[DataField("doDistanceCheck")]
public bool DoDistanceCheck = true;
[DataField("exchangeSound")]
public SoundSpecifier ExchangeSound = new SoundPathSpecifier("/Audio/Items/rped.ogg");
public EntityUid? AudioStream;
}

View File

@ -2,6 +2,7 @@ using Content.Server.Construction.Components;
using Content.Shared.Construction;
using Content.Shared.Examine;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Server.Construction.Conditions
@ -17,7 +18,7 @@ namespace Content.Server.Construction.Conditions
public SpriteSpecifier? GuideIconBoard { get; private set; }
[DataField("guideIconParts")]
public SpriteSpecifier? GuideIconPart { get; private set; }
public SpriteSpecifier? GuideIconParts { get; private set; }
public bool Condition(EntityUid uid, IEntityManager entityManager)
@ -33,6 +34,8 @@ namespace Content.Server.Construction.Conditions
var entity = args.Examined;
var entityManager = IoCManager.Resolve<IEntityManager>();
var protoManager = IoCManager.Resolve<IPrototypeManager>();
var constructionSys = entityManager.System<ConstructionSystem>();
if (!entityManager.TryGetComponent(entity, out MachineFrameComponent? machineFrame))
return false;
@ -47,17 +50,6 @@ namespace Content.Server.Construction.Conditions
return false;
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-requirement-label"));
foreach (var (part, required) in machineFrame.Requirements)
{
var amount = required - machineFrame.Progress[part];
if(amount == 0)
continue;
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
("amount", amount),
("elementName", Loc.GetString(part))));
}
foreach (var (material, required) in machineFrame.MaterialRequirements)
{
@ -65,10 +57,12 @@ namespace Content.Server.Construction.Conditions
if(amount == 0)
continue;
var stack = protoManager.Index(material);
var stackEnt = protoManager.Index(stack.Spawn);
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
("amount", amount),
("elementName", Loc.GetString(material))));
("elementName", stackEnt.Name)));
}
foreach (var (compName, info) in machineFrame.ComponentRequirements)
@ -78,9 +72,10 @@ namespace Content.Server.Construction.Conditions
if(amount == 0)
continue;
var examineName = constructionSys.GetExamineName(info);
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
("amount", info.Amount),
("elementName", Loc.GetString(info.ExamineName))));
("elementName", examineName)));
}
foreach (var (tagName, info) in machineFrame.TagRequirements)
@ -90,9 +85,10 @@ namespace Content.Server.Construction.Conditions
if(amount == 0)
continue;
var examineName = constructionSys.GetExamineName(info);
args.PushMarkup(Loc.GetString("construction-condition-machine-frame-required-element-entry",
("amount", info.Amount),
("elementName", Loc.GetString(info.ExamineName)))
("elementName", examineName))
+ "\n");
}
@ -111,7 +107,7 @@ namespace Content.Server.Construction.Conditions
yield return new ConstructionGuideEntry()
{
Localization = "construction-step-condition-machine-frame-parts",
Icon = GuideIconPart,
Icon = GuideIconParts,
EntryNumber = 0, // Set this to anything so the guide generation takes this as a numbered step.
};
}

View File

@ -50,7 +50,7 @@ namespace Content.Server.Construction
// If the set graph prototype does not exist, also return null. This could be due to admemes changing values
// in ViewVariables, so even though the construction state is invalid, just return null.
return _prototypeManager.TryIndex(construction.Graph, out ConstructionGraphPrototype? graph) ? graph : null;
return PrototypeManager.TryIndex(construction.Graph, out ConstructionGraphPrototype? graph) ? graph : null;
}
/// <summary>
@ -300,7 +300,7 @@ namespace Content.Server.Construction
}
// Exit if the new entity's prototype is the same as the original, or the prototype is invalid
if (newEntity == metaData.EntityPrototype?.ID || !_prototypeManager.HasIndex<EntityPrototype>(newEntity))
if (newEntity == metaData.EntityPrototype?.ID || !PrototypeManager.HasIndex<EntityPrototype>(newEntity))
return null;
// [Optional] Exit if the new entity's prototype is a parent of the original
@ -310,7 +310,7 @@ namespace Content.Server.Construction
if (GetCurrentNode(uid, construction)?.DoNotReplaceInheritingEntities == true &&
metaData.EntityPrototype?.ID != null)
{
var parents = _prototypeManager.EnumerateParents<EntityPrototype>(metaData.EntityPrototype.ID)?.ToList();
var parents = PrototypeManager.EnumerateParents<EntityPrototype>(metaData.EntityPrototype.ID)?.ToList();
if (parents != null && parents.Any(x => x.ID == newEntity))
return null;
@ -427,7 +427,7 @@ namespace Content.Server.Construction
if (!Resolve(uid, ref construction))
return false;
if (!_prototypeManager.TryIndex<ConstructionGraphPrototype>(graphId, out var graph))
if (!PrototypeManager.TryIndex<ConstructionGraphPrototype>(graphId, out var graph))
return false;
if(GetNodeFromGraph(graph, nodeId) is not {})

View File

@ -25,7 +25,7 @@ namespace Content.Server.Construction
private void OnGuideRequested(RequestConstructionGuide msg, EntitySessionEventArgs args)
{
if (!_prototypeManager.TryIndex(msg.ConstructionId, out ConstructionPrototype? prototype))
if (!PrototypeManager.TryIndex(msg.ConstructionId, out ConstructionPrototype? prototype))
return;
if(GetGuide(prototype) is {} guide)
@ -41,7 +41,7 @@ namespace Content.Server.Construction
component.Node == component.DeconstructionNode)
return;
if (!_prototypeManager.TryIndex(component.Graph, out ConstructionGraphPrototype? graph))
if (!PrototypeManager.TryIndex(component.Graph, out ConstructionGraphPrototype? graph))
return;
if (component.DeconstructionNode == null)
@ -145,7 +145,7 @@ namespace Content.Server.Construction
return guide;
// If the graph doesn't actually exist, do nothing.
if (!_prototypeManager.TryIndex(construction.Graph, out ConstructionGraphPrototype? graph))
if (!PrototypeManager.TryIndex(construction.Graph, out ConstructionGraphPrototype? graph))
return null;
// If either the start node or the target node are missing, do nothing.

View File

@ -325,13 +325,13 @@ namespace Content.Server.Construction
// LEGACY CODE. See warning at the top of the file!
public async Task<bool> TryStartItemConstruction(string prototype, EntityUid user)
{
if (!_prototypeManager.TryIndex(prototype, out ConstructionPrototype? constructionPrototype))
if (!PrototypeManager.TryIndex(prototype, out ConstructionPrototype? constructionPrototype))
{
Log.Error($"Tried to start construction of invalid recipe '{prototype}'!");
return false;
}
if (!_prototypeManager.TryIndex(constructionPrototype.Graph,
if (!PrototypeManager.TryIndex(constructionPrototype.Graph,
out ConstructionGraphPrototype? constructionGraph))
{
Log.Error(
@ -404,14 +404,14 @@ namespace Content.Server.Construction
// LEGACY CODE. See warning at the top of the file!
private async void HandleStartStructureConstruction(TryStartStructureConstructionMessage ev, EntitySessionEventArgs args)
{
if (!_prototypeManager.TryIndex(ev.PrototypeName, out ConstructionPrototype? constructionPrototype))
if (!PrototypeManager.TryIndex(ev.PrototypeName, out ConstructionPrototype? constructionPrototype))
{
Log.Error($"Tried to start construction of invalid recipe '{ev.PrototypeName}'!");
RaiseNetworkEvent(new AckStructureConstructionMessage(ev.Ack));
return;
}
if (!_prototypeManager.TryIndex(constructionPrototype.Graph, out ConstructionGraphPrototype? constructionGraph))
if (!PrototypeManager.TryIndex(constructionPrototype.Graph, out ConstructionGraphPrototype? constructionGraph))
{
Log.Error($"Invalid construction graph '{constructionPrototype.Graph}' in recipe '{ev.PrototypeName}'!");
RaiseNetworkEvent(new AckStructureConstructionMessage(ev.Ack));

View File

@ -1,23 +1,15 @@
using System.Linq;
using Content.Server.Construction.Components;
using Content.Server.Examine;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Verbs;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
namespace Content.Server.Construction;
public sealed partial class ConstructionSystem
{
[Dependency] private readonly ExamineSystem _examineSystem = default!;
private void InitializeMachines()
{
SubscribeLocalEvent<MachineComponent, ComponentInit>(OnMachineInit);
SubscribeLocalEvent<MachineComponent, MapInitEvent>(OnMachineMapInit);
SubscribeLocalEvent<MachineComponent, GetVerbsEvent<ExamineVerb>>(OnMachineExaminableVerb);
}
private void OnMachineInit(EntityUid uid, MachineComponent component, ComponentInit args)
@ -29,84 +21,6 @@ public sealed partial class ConstructionSystem
private void OnMachineMapInit(EntityUid uid, MachineComponent component, MapInitEvent args)
{
CreateBoardAndStockParts(uid, component);
RefreshParts(uid, component);
}
private void OnMachineExaminableVerb(EntityUid uid, MachineComponent component, GetVerbsEvent<ExamineVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
var markup = new FormattedMessage();
RaiseLocalEvent(uid, new UpgradeExamineEvent(ref markup));
if (markup.IsEmpty)
return; // Not upgradable.
markup = FormattedMessage.FromMarkup(markup.ToMarkup().TrimEnd('\n')); // Cursed workaround to https://github.com/space-wizards/RobustToolbox/issues/3371
var verb = new ExamineVerb()
{
Act = () =>
{
_examineSystem.SendExamineTooltip(args.User, uid, markup, getVerbs: false, centerAtCursor: false);
},
Text = Loc.GetString("machine-upgrade-examinable-verb-text"),
Message = Loc.GetString("machine-upgrade-examinable-verb-message"),
Category = VerbCategory.Examine,
Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/pickup.svg.192dpi.png"))
};
args.Verbs.Add(verb);
}
public List<MachinePartComponent> GetAllParts(EntityUid uid, MachineComponent? component = null)
{
if (!Resolve(uid, ref component))
return new List<MachinePartComponent>();
return GetAllParts(component);
}
public List<MachinePartComponent> GetAllParts(MachineComponent component)
{
var parts = new List<MachinePartComponent>();
foreach (var entity in component.PartContainer.ContainedEntities)
{
if (TryComp<MachinePartComponent>(entity, out var machinePart))
parts.Add(machinePart);
}
return parts;
}
public Dictionary<string, float> GetPartsRatings(List<MachinePartComponent> parts)
{
var output = new Dictionary<string, float>();
foreach (var type in _prototypeManager.EnumeratePrototypes<MachinePartPrototype>())
{
var amount = 0f;
var sumRating = 0f;
foreach (var part in parts.Where(part => part.PartType == type.ID))
{
amount++;
sumRating += part.Rating;
}
var rating = amount != 0 ? sumRating / amount : 0;
output.Add(type.ID, rating);
}
return output;
}
public void RefreshParts(EntityUid uid, MachineComponent component)
{
var parts = GetAllParts(component);
EntityManager.EventBus.RaiseLocalEvent(uid, new RefreshPartsEvent
{
Parts = parts,
PartRatings = GetPartsRatings(parts),
}, true);
}
private void CreateBoardAndStockParts(EntityUid uid, MachineComponent component)
@ -115,54 +29,37 @@ public sealed partial class ConstructionSystem
var boardContainer = _container.EnsureContainer<Container>(uid, MachineFrameComponent.BoardContainerName);
var partContainer = _container.EnsureContainer<Container>(uid, MachineFrameComponent.PartContainerName);
if (string.IsNullOrEmpty(component.BoardPrototype))
if (string.IsNullOrEmpty(component.Board))
return;
// We're done here, let's suppose all containers are correct just so we don't screw SaveLoadSave.
if (boardContainer.ContainedEntities.Count > 0)
return;
var board = EntityManager.SpawnEntity(component.BoardPrototype, Transform(uid).Coordinates);
if (!_container.Insert(board, component.BoardContainer))
var xform = Transform(uid);
if (!TrySpawnInContainer(component.Board, uid, MachineFrameComponent.BoardContainerName, out var board))
{
throw new Exception($"Couldn't insert board with prototype {component.BoardPrototype} to machine with prototype {MetaData(uid).EntityPrototype?.ID ?? "N/A"}!");
throw new Exception($"Couldn't insert board with prototype {component.Board} to machine with prototype {Prototype(uid)?.ID ?? "N/A"}!");
}
if (!TryComp<MachineBoardComponent>(board, out var machineBoard))
{
throw new Exception($"Entity with prototype {component.BoardPrototype} doesn't have a {nameof(MachineBoardComponent)}!");
throw new Exception($"Entity with prototype {component.Board} doesn't have a {nameof(MachineBoardComponent)}!");
}
var xform = Transform(uid);
foreach (var (part, amount) in machineBoard.Requirements)
foreach (var (stackType, amount) in machineBoard.StackRequirements)
{
var partProto = _prototypeManager.Index<MachinePartPrototype>(part);
for (var i = 0; i < amount; i++)
{
var p = EntityManager.SpawnEntity(partProto.StockPartPrototype, xform.Coordinates);
if (!_container.Insert(p, partContainer))
throw new Exception($"Couldn't insert machine part of type {part} to machine with prototype {partProto.StockPartPrototype}!");
}
}
foreach (var (stackType, amount) in machineBoard.MaterialRequirements)
{
var stack = _stackSystem.Spawn(amount, stackType, Transform(uid).Coordinates);
var stack = _stackSystem.Spawn(amount, stackType, xform.Coordinates);
if (!_container.Insert(stack, partContainer))
throw new Exception($"Couldn't insert machine material of type {stackType} to machine with prototype {MetaData(uid).EntityPrototype?.ID ?? "N/A"}");
throw new Exception($"Couldn't insert machine material of type {stackType} to machine with prototype {Prototype(uid)?.ID ?? "N/A"}");
}
foreach (var (compName, info) in machineBoard.ComponentRequirements)
{
for (var i = 0; i < info.Amount; i++)
{
var c = EntityManager.SpawnEntity(info.DefaultPrototype, Transform(uid).Coordinates);
if(!_container.Insert(c, partContainer))
throw new Exception($"Couldn't insert machine component part with default prototype '{compName}' to machine with prototype {MetaData(uid).EntityPrototype?.ID ?? "N/A"}");
if(!TrySpawnInContainer(info.DefaultPrototype, uid, MachineFrameComponent.PartContainerName, out _))
throw new Exception($"Couldn't insert machine component part with default prototype '{compName}' to machine with prototype {Prototype(uid)?.ID ?? "N/A"}");
}
}
@ -170,58 +67,9 @@ public sealed partial class ConstructionSystem
{
for (var i = 0; i < info.Amount; i++)
{
var c = EntityManager.SpawnEntity(info.DefaultPrototype, Transform(uid).Coordinates);
if(!_container.Insert(c, partContainer))
throw new Exception($"Couldn't insert machine component part with default prototype '{tagName}' to machine with prototype {MetaData(uid).EntityPrototype?.ID ?? "N/A"}");
if(!TrySpawnInContainer(info.DefaultPrototype, uid, MachineFrameComponent.PartContainerName, out _))
throw new Exception($"Couldn't insert machine component part with default prototype '{tagName}' to machine with prototype {Prototype(uid)?.ID ?? "N/A"}");
}
}
}
}
public sealed class RefreshPartsEvent : EntityEventArgs
{
public IReadOnlyList<MachinePartComponent> Parts = new List<MachinePartComponent>();
public Dictionary<string, float> PartRatings = new();
}
public sealed class UpgradeExamineEvent : EntityEventArgs
{
private FormattedMessage Message;
public UpgradeExamineEvent(ref FormattedMessage message)
{
Message = message;
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a percentage-based increase or decrease.
/// </summary>
public void AddPercentageUpgrade(string upgradedLocId, float multiplier)
{
var percent = Math.Round(100 * MathF.Abs(multiplier - 1), 2);
var locId = multiplier switch {
< 1 => "machine-upgrade-decreased-by-percentage",
1 or float.NaN => "machine-upgrade-not-upgraded",
> 1 => "machine-upgrade-increased-by-percentage",
};
var upgraded = Loc.GetString(upgradedLocId);
this.Message.AddMarkup(Loc.GetString(locId, ("upgraded", upgraded), ("percent", percent)) + '\n');
}
/// <summary>
/// Add a line to the upgrade examine tooltip with a numeric increase or decrease.
/// </summary>
public void AddNumberUpgrade(string upgradedLocId, int number)
{
var difference = Math.Abs(number);
var locId = number switch {
< 0 => "machine-upgrade-decreased-by-amount",
0 => "machine-upgrade-not-upgraded",
> 0 => "machine-upgrade-increased-by-amount",
};
var upgraded = Loc.GetString(upgradedLocId);
this.Message.AddMarkup(Loc.GetString(locId, ("upgraded", upgraded), ("difference", difference)) + '\n');
}
}

View File

@ -16,7 +16,6 @@ namespace Content.Server.Construction
[UsedImplicitly]
public sealed partial class ConstructionSystem : SharedConstructionSystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly ContainerSystem _container = default!;

View File

@ -7,7 +7,7 @@ using Content.Shared.Stacks;
using Content.Shared.Tag;
using Content.Shared.Popups;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
using Robust.Shared.Prototypes;
namespace Content.Server.Construction;
@ -62,24 +62,7 @@ public sealed class MachineFrameSystem : EntitySystem
// If this changes in the future, then RegenerateProgress() also needs to be updated.
// Note that one entity is ALLOWED to satisfy more than one kind of component or tag requirements. This is
// necessary in order to avoid weird entity-ordering shenanigans in RegenerateProgress().
var stack = CompOrNull<StackComponent>(args.Used);
var machinePart = CompOrNull<MachinePartComponent>(args.Used);
if (stack != null && machinePart != null)
{
if (TryInsertPartStack(uid, args.Used, component, machinePart, stack))
args.Handled = true;
return;
}
// Handle parts
if (machinePart != null)
{
if (TryInsertPart(uid, args.Used, component, machinePart))
args.Handled = true;
return;
}
if (stack != null)
if (TryComp<StackComponent>(args.Used, out var stack))
{
if (TryInsertStack(uid, args.Used, component, stack))
args.Handled = true;
@ -172,67 +155,6 @@ public sealed class MachineFrameSystem : EntitySystem
return true;
}
/// <returns>Whether or not the function had any effect. Does not indicate success.</returns>
private bool TryInsertPart(EntityUid uid, EntityUid used, MachineFrameComponent component, MachinePartComponent machinePart)
{
DebugTools.Assert(!HasComp<StackComponent>(uid));
if (!component.Requirements.ContainsKey(machinePart.PartType))
return false;
if (component.Progress[machinePart.PartType] >= component.Requirements[machinePart.PartType])
return false;
if (!_container.TryRemoveFromContainer(used))
return false;
if (!_container.Insert(used, component.PartContainer))
return true;
component.Progress[machinePart.PartType]++;
if (IsComplete(component))
_popupSystem.PopupEntity(Loc.GetString("machine-frame-component-on-complete"), uid);
return true;
}
/// <returns>Whether or not the function had any effect. Does not indicate success.</returns>
private bool TryInsertPartStack(EntityUid uid, EntityUid used, MachineFrameComponent component, MachinePartComponent machinePart, StackComponent stack)
{
if (!component.Requirements.ContainsKey(machinePart.PartType))
return false;
var progress = component.Progress[machinePart.PartType];
var requirement = component.Requirements[machinePart.PartType];
var needed = requirement - progress;
if (needed <= 0)
return false;
var count = stack.Count;
if (count < needed)
{
if (!_container.Insert(used, component.PartContainer))
return true;
component.Progress[machinePart.PartType] += count;
return true;
}
var splitStack = _stack.Split(used, needed, Transform(uid).Coordinates, stack);
if (splitStack == null)
return false;
if (!_container.Insert(splitStack.Value, component.PartContainer))
return true;
component.Progress[machinePart.PartType] += needed;
if (IsComplete(component))
_popupSystem.PopupEntity(Loc.GetString("machine-frame-component-on-complete"), uid);
return true;
}
/// <returns>Whether or not the function had any effect. Does not indicate success.</returns>
private bool TryInsertStack(EntityUid uid, EntityUid used, MachineFrameComponent component, StackComponent stack)
{
@ -281,12 +203,6 @@ public sealed class MachineFrameSystem : EntitySystem
if (!component.HasBoard)
return false;
foreach (var (part, amount) in component.Requirements)
{
if (component.Progress[part] < amount)
return false;
}
foreach (var (type, amount) in component.MaterialRequirements)
{
if (component.MaterialProgress[type] < amount)
@ -310,21 +226,14 @@ public sealed class MachineFrameSystem : EntitySystem
public void ResetProgressAndRequirements(MachineFrameComponent component, MachineBoardComponent machineBoard)
{
component.Requirements = new Dictionary<string, int>(machineBoard.Requirements);
component.MaterialRequirements = new Dictionary<string, int>(machineBoard.MaterialIdRequirements);
component.MaterialRequirements = new Dictionary<ProtoId<StackPrototype>, int>(machineBoard.StackRequirements);
component.ComponentRequirements = new Dictionary<string, GenericPartInfo>(machineBoard.ComponentRequirements);
component.TagRequirements = new Dictionary<string, GenericPartInfo>(machineBoard.TagRequirements);
component.TagRequirements = new Dictionary<ProtoId<TagPrototype>, GenericPartInfo>(machineBoard.TagRequirements);
component.Progress.Clear();
component.MaterialProgress.Clear();
component.ComponentProgress.Clear();
component.TagProgress.Clear();
foreach (var (machinePart, _) in component.Requirements)
{
component.Progress[machinePart] = 0;
}
foreach (var (stackType, _) in component.MaterialRequirements)
{
component.MaterialProgress[stackType] = 0;
@ -349,7 +258,6 @@ public sealed class MachineFrameSystem : EntitySystem
component.MaterialRequirements.Clear();
component.ComponentRequirements.Clear();
component.TagRequirements.Clear();
component.Progress.Clear();
component.MaterialProgress.Clear();
component.ComponentProgress.Clear();
component.TagProgress.Clear();
@ -368,19 +276,6 @@ public sealed class MachineFrameSystem : EntitySystem
foreach (var part in component.PartContainer.ContainedEntities)
{
if (TryComp<MachinePartComponent>(part, out var machinePart))
{
// Check this is part of the requirements...
if (!component.Requirements.ContainsKey(machinePart.PartType))
continue;
if (!component.Progress.ContainsKey(machinePart.PartType))
component.Progress[machinePart.PartType] = 1;
else
component.Progress[machinePart.PartType]++;
continue;
}
if (TryComp<StackComponent>(part, out var stack))
{
var type = stack.StackTypeId;
@ -404,9 +299,7 @@ public sealed class MachineFrameSystem : EntitySystem
if (!HasComp(part, registration.Type))
continue;
if (!component.ComponentProgress.ContainsKey(compName))
component.ComponentProgress[compName] = 1;
else
if (!component.ComponentProgress.TryAdd(compName, 1))
component.ComponentProgress[compName]++;
}
@ -419,18 +312,17 @@ public sealed class MachineFrameSystem : EntitySystem
if (!_tag.HasTag(tagComp, tagName))
continue;
if (!component.TagProgress.ContainsKey(tagName))
component.TagProgress[tagName] = 1;
else
if (!component.TagProgress.TryAdd(tagName, 1))
component.TagProgress[tagName]++;
}
}
}
private void OnMachineFrameExamined(EntityUid uid, MachineFrameComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange)
if (!args.IsInDetailsRange || !component.HasBoard)
return;
if (component.HasBoard)
args.PushMarkup(Loc.GetString("machine-frame-component-on-examine-label", ("board", EntityManager.GetComponent<MetaDataComponent>(component.BoardContainer.ContainedEntities[0]).EntityName)));
var board = component.BoardContainer.ContainedEntities[0];
args.PushMarkup(Loc.GetString("machine-frame-component-on-examine-label", ("board", Name(board))));
}
}

View File

@ -1,180 +0,0 @@
using System.Linq;
using Content.Server.Construction.Components;
using Content.Server.Storage.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.Construction.Components;
using Content.Shared.Exchanger;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Robust.Shared.Containers;
using Robust.Shared.Utility;
using Content.Shared.Wires;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
namespace Content.Server.Construction;
public sealed class PartExchangerSystem : EntitySystem
{
[Dependency] private readonly ConstructionSystem _construction = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StorageSystem _storage = default!;
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PartExchangerComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<PartExchangerComponent, ExchangerDoAfterEvent>(OnDoAfter);
}
private void OnDoAfter(EntityUid uid, PartExchangerComponent component, DoAfterEvent args)
{
if (args.Cancelled)
{
component.AudioStream = _audio.Stop(component.AudioStream);
return;
}
if (args.Handled || args.Args.Target == null)
return;
if (!TryComp<StorageComponent>(uid, out var storage))
return; //the parts are stored in here
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var machineParts = new List<(EntityUid, MachinePartComponent)>();
foreach (var item in storage.Container.ContainedEntities) //get parts in RPED
{
if (machinePartQuery.TryGetComponent(item, out var part))
machineParts.Add((item, part));
}
TryExchangeMachineParts(args.Args.Target.Value, uid, machineParts);
TryConstructMachineParts(args.Args.Target.Value, uid, machineParts);
args.Handled = true;
}
private void TryExchangeMachineParts(EntityUid uid, EntityUid storageUid, List<(EntityUid part, MachinePartComponent partComp)> machineParts)
{
if (!TryComp<MachineComponent>(uid, out var machine))
return;
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var board = machine.BoardContainer.ContainedEntities.FirstOrNull();
if (board == null || !TryComp<MachineBoardComponent>(board, out var macBoardComp))
return;
foreach (var item in new ValueList<EntityUid>(machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
{
if (machinePartQuery.TryGetComponent(item, out var part))
{
machineParts.Add((item, part));
_container.RemoveEntity(uid, item);
}
}
machineParts.Sort((x, y) => y.partComp.Rating.CompareTo(x.partComp.Rating));
var updatedParts = new List<(EntityUid part, MachinePartComponent partComp)>();
foreach (var (type, amount) in macBoardComp.Requirements)
{
var target = machineParts.Where(p => p.partComp.PartType == type).Take(amount);
updatedParts.AddRange(target);
}
foreach (var part in updatedParts)
{
_container.Insert(part.part, machine.PartContainer);
machineParts.Remove(part);
}
//put the unused parts back into rped. (this also does the "swapping")
foreach (var (unused, _) in machineParts)
{
_storage.Insert(storageUid, unused, out _, playSound: false);
}
_construction.RefreshParts(uid, machine);
}
private void TryConstructMachineParts(EntityUid uid, EntityUid storageEnt, List<(EntityUid part, MachinePartComponent partComp)> machineParts)
{
if (!TryComp<MachineFrameComponent>(uid, out var machine))
return;
var machinePartQuery = GetEntityQuery<MachinePartComponent>();
var board = machine.BoardContainer.ContainedEntities.FirstOrNull();
if (!machine.HasBoard || !TryComp<MachineBoardComponent>(board, out var macBoardComp))
return;
foreach (var item in new ValueList<EntityUid>(machine.PartContainer.ContainedEntities)) //clone so don't modify during enumeration
{
if (machinePartQuery.TryGetComponent(item, out var part))
{
machineParts.Add((item, part));
_container.RemoveEntity(uid, item);
machine.Progress[part.PartType]--;
}
}
machineParts.Sort((x, y) => y.partComp.Rating.CompareTo(x.partComp.Rating));
var updatedParts = new List<(EntityUid part, MachinePartComponent partComp)>();
foreach (var (type, amount) in macBoardComp.Requirements)
{
var target = machineParts.Where(p => p.partComp.PartType == type).Take(amount);
updatedParts.AddRange(target);
}
foreach (var pair in updatedParts)
{
var part = pair.partComp;
var partEnt = pair.part;
if (!machine.Requirements.ContainsKey(part.PartType))
continue;
_container.Insert(partEnt, machine.PartContainer);
machine.Progress[part.PartType]++;
machineParts.Remove(pair);
}
//put the unused parts back into rped. (this also does the "swapping")
foreach (var (unused, _) in machineParts)
{
_storage.Insert(storageEnt, unused, out _, playSound: false);
}
}
private void OnAfterInteract(EntityUid uid, PartExchangerComponent component, AfterInteractEvent args)
{
if (component.DoDistanceCheck && !args.CanReach)
return;
if (args.Target == null)
return;
if (!HasComp<MachineComponent>(args.Target) && !HasComp<MachineFrameComponent>(args.Target))
return;
if (TryComp<WiresPanelComponent>(args.Target, out var panel) && !panel.Open)
{
_popup.PopupEntity(Loc.GetString("construction-step-condition-wire-panel-open"),
args.Target.Value);
return;
}
component.AudioStream = _audio.PlayPvs(component.ExchangeSound, uid).Value.Entity;
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.ExchangeDuration, new ExchangerDoAfterEvent(), uid, target: args.Target, used: uid)
{
BreakOnDamage = true,
BreakOnMove = true
});
}
}

View File

@ -71,6 +71,15 @@ namespace Content.Server.Stack
return entity;
}
/// <summary>
/// Spawns a stack of a certain stack type. See <see cref="StackPrototype"/>.
/// </summary>
public EntityUid Spawn(int amount, ProtoId<StackPrototype> id, EntityCoordinates spawnPosition)
{
var proto = _prototypeManager.Index(id);
return Spawn(amount, proto, spawnPosition);
}
/// <summary>
/// Spawns a stack of a certain stack type. See <see cref="StackPrototype"/>.
/// </summary>

View File

@ -1,54 +1,47 @@
using Content.Shared.Construction.Prototypes;
using Content.Shared.Stacks;
using Content.Shared.Tag;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary;
namespace Content.Shared.Construction.Components
namespace Content.Shared.Construction.Components;
[RegisterComponent, NetworkedComponent]
public sealed partial class MachineBoardComponent : Component
{
[RegisterComponent, NetworkedComponent]
public sealed partial class MachineBoardComponent : Component
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
/// <summary>
/// The stacks needed to construct this machine
/// </summary>
[DataField]
public Dictionary<ProtoId<StackPrototype>, int> StackRequirements = new();
[DataField("requirements", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, MachinePartPrototype>))]
public Dictionary<string, int> Requirements = new();
/// <summary>
/// Entities needed to construct this machine, discriminated by tag.
/// </summary>
[DataField]
public Dictionary<ProtoId<TagPrototype>, GenericPartInfo> TagRequirements = new();
[DataField("materialRequirements")]
public Dictionary<string, int> MaterialIdRequirements = new();
/// <summary>
/// Entities needed to construct this machine, discriminated by component.
/// </summary>
[DataField]
public Dictionary<string, GenericPartInfo> ComponentRequirements = new();
[DataField("tagRequirements")]
public Dictionary<string, GenericPartInfo> TagRequirements = new();
[DataField("componentRequirements")]
public Dictionary<string, GenericPartInfo> ComponentRequirements = new();
[ViewVariables(VVAccess.ReadWrite)]
[DataField("prototype")]
public string? Prototype { get; private set; }
public IEnumerable<KeyValuePair<StackPrototype, int>> MaterialRequirements
{
get
{
foreach (var (materialId, amount) in MaterialIdRequirements)
{
var material = _prototypeManager.Index<StackPrototype>(materialId);
yield return new KeyValuePair<StackPrototype, int>(material, amount);
}
}
}
}
[Serializable]
[DataDefinition]
public partial struct GenericPartInfo
{
[DataField("Amount")]
public int Amount;
[DataField("ExamineName")]
public string ExamineName;
[DataField("DefaultPrototype")]
public string DefaultPrototype;
}
/// <summary>
/// The machine that's constructed when this machine board is completed.
/// </summary>
[DataField(required: true)]
public EntProtoId Prototype;
}
[DataDefinition, Serializable]
public partial struct GenericPartInfo
{
[DataField(required: true)]
public int Amount;
[DataField(required: true)]
public EntProtoId DefaultPrototype;
[DataField]
public LocId? ExamineName;
}

View File

@ -1,24 +0,0 @@
using Content.Shared.Construction.Prototypes;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Construction.Components
{
[RegisterComponent, NetworkedComponent]
public sealed partial class MachinePartComponent : Component
{
[DataField("part", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MachinePartPrototype>))]
public string PartType { get; private set; } = default!;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("rating")]
public int Rating { get; private set; } = 1;
/// <summary>
/// This number is used in tests to ensure that you can't use high quality machines for arbitrage. In
/// principle there is nothing wrong with using higher quality parts, but you have to be careful to not
/// allow them to be put into a lathe or something like that.
/// </summary>
public const int MaxRating = 4;
}
}

View File

@ -1,10 +1,8 @@
using System.Linq;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Examine;
using Content.Shared.Lathe;
using Content.Shared.Materials;
using Content.Shared.Stacks;
using Robust.Shared.Prototypes;
namespace Content.Shared.Construction
@ -16,6 +14,7 @@ namespace Content.Shared.Construction
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedLatheSystem _lathe = default!;
[Dependency] private readonly SharedConstructionSystem _construction = default!;
public override void Initialize()
{
@ -31,32 +30,30 @@ namespace Content.Shared.Construction
using (args.PushGroup(nameof(MachineBoardComponent)))
{
args.PushMarkup(Loc.GetString("machine-board-component-on-examine-label"));
foreach (var (part, amount) in component.Requirements)
foreach (var (material, amount) in component.StackRequirements)
{
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
("amount", amount),
("requiredElement", Loc.GetString(_prototype.Index<MachinePartPrototype>(part).Name))));
}
var stack = _prototype.Index(material);
var name = _prototype.Index(stack.Spawn).Name;
foreach (var (material, amount) in component.MaterialRequirements)
{
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
("amount", amount),
("requiredElement", Loc.GetString(material.Name))));
("requiredElement", Loc.GetString(name))));
}
foreach (var (_, info) in component.ComponentRequirements)
{
var examineName = _construction.GetExamineName(info);
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
("amount", info.Amount),
("requiredElement", Loc.GetString(info.ExamineName))));
("requiredElement", examineName)));
}
foreach (var (_, info) in component.TagRequirements)
{
var examineName = _construction.GetExamineName(info);
args.PushMarkup(Loc.GetString("machine-board-component-required-element-entry-text",
("amount", info.Amount),
("requiredElement", Loc.GetString(info.ExamineName))));
("requiredElement", examineName)));
}
}
}
@ -66,30 +63,13 @@ namespace Content.Shared.Construction
var (_, comp) = entity;
var materials = new Dictionary<string, int>();
foreach (var (partId, amount) in comp.Requirements)
foreach (var (stackId, amount) in comp.StackRequirements)
{
var partProto = _prototype.Index<MachinePartPrototype>(partId);
if (!_lathe.TryGetRecipesFromEntity(partProto.StockPartPrototype, out var recipes))
continue;
var partRecipe = recipes[0];
if (recipes.Count > 1)
partRecipe = recipes.MinBy(p => p.RequiredMaterials.Values.Sum());
foreach (var (mat, matAmount) in partRecipe!.RequiredMaterials)
{
materials.TryAdd(mat, 0);
materials[mat] += matAmount * amount * coefficient;
}
}
foreach (var (stackId, amount) in comp.MaterialIdRequirements)
{
var stackProto = _prototype.Index<StackPrototype>(stackId);
var stackProto = _prototype.Index(stackId);
var defaultProto = _prototype.Index(stackProto.Spawn);
if (defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
if (defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp, EntityManager.ComponentFactory))
{
foreach (var (mat, matAmount) in physComp.MaterialComposition)
{
@ -130,7 +110,7 @@ namespace Content.Shared.Construction
}
}
else if (_prototype.TryIndex(defaultProtoId, out var defaultProto) &&
defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp))
defaultProto.TryGetComponent<PhysicalCompositionComponent>(out var physComp, EntityManager.ComponentFactory))
{
foreach (var (mat, matAmount) in physComp.MaterialComposition)
{

View File

@ -1,28 +0,0 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Shared.Construction.Prototypes;
/// <summary>
/// This is a prototype for categorizing
/// different types of machine parts.
/// </summary>
[Prototype("machinePart")]
public sealed partial class MachinePartPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; private set; } = default!;
/// <summary>
/// A human-readable name for the machine part type.
/// </summary>
[DataField("name")]
public string Name = string.Empty;
/// <summary>
/// A stock part entity based on the machine part.
/// </summary>
[DataField("stockPartPrototype", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>), required: true)]
public string StockPartPrototype = string.Empty;
}

View File

@ -1,5 +1,7 @@
using System.Linq;
using Content.Shared.Construction.Components;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using static Content.Shared.Interaction.SharedInteractionSystem;
namespace Content.Shared.Construction
@ -7,6 +9,7 @@ namespace Content.Shared.Construction
public abstract class SharedConstructionSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
/// <summary>
/// Get predicate for construction obstruction checks.
@ -22,5 +25,13 @@ namespace Content.Shared.Construction
var ignored = grid.GetAnchoredEntities(coords).ToHashSet();
return e => ignored.Contains(e);
}
public string GetExamineName(GenericPartInfo info)
{
if (info.ExamineName is not null)
return Loc.GetString(info.ExamineName.Value);
return PrototypeManager.Index(info.DefaultPrototype).Name;
}
}
}

View File

@ -1,4 +1,3 @@
using System.Numerics;
using Content.Shared.Construction.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
@ -9,7 +8,6 @@ using Content.Shared.Popups;
using Content.Shared.Tools.Systems;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
@ -88,7 +86,8 @@ public abstract class SharedFlatpackSystem : EntitySystem
if (_net.IsServer)
{
var spawn = Spawn(comp.Entity, _map.GridTileToLocal(grid, gridComp, buildPos));
_adminLogger.Add(LogType.Construction, LogImpact.Low,
_adminLogger.Add(LogType.Construction,
LogImpact.Low,
$"{ToPrettyString(args.User):player} unpacked {ToPrettyString(spawn):entity} at {xform.Coordinates} from {ToPrettyString(uid):entity}");
QueueDel(uid);
}
@ -115,9 +114,7 @@ public abstract class SharedFlatpackSystem : EntitySystem
return;
var machinePrototypeId = new EntProtoId();
if (TryComp<MachineBoardComponent>(board, out var machineBoard) && machineBoard.Prototype is not null)
machinePrototypeId = machineBoard.Prototype;
else if (TryComp<ComputerBoardComponent>(board, out var computerBoard) && computerBoard.Prototype is not null)
if (TryComp<ComputerBoardComponent>(board, out var computerBoard) && computerBoard.Prototype is not null)
machinePrototypeId = computerBoard.Prototype;
var comp = ent.Comp!;

View File

@ -59,8 +59,6 @@ namespace Content.Shared.Lathe
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float MaterialUseMultiplier = 1;
public const float DefaultPartRatingMaterialUseMultiplier = 0.85f;
#endregion
}

View File

@ -1,2 +1,10 @@
# Shown when examining an in-construction object
construction-insert-arbitrary-entity = Next, insert {$stepName}.
construction-insert-arbitrary-entity = Next, insert {$stepName}.
construction-insert-info-examine-name-instrument-brass = brass instrument
construction-insert-info-examine-name-instrument-keyed = keyed instrument
construction-insert-info-examine-name-instrument-percussion = percussion instrument
construction-insert-info-examine-name-instrument-string = string intrument
construction-insert-info-examine-name-instrument-woodwind = woodwind instrument
construction-insert-info-examine-name-knife = knife
construction-insert-info-examine-name-utensil = utensil

View File

@ -18,7 +18,6 @@ loadout-group-botanist-neck = Botanist Neck
loadout-group-mime-neck = Mime neck
loadout-group-musician-jumpsuit = Musician jumpsuit
loadout-group-musician-neck = Musician neck
loadout-group-serviceworker-head = Service Worker head

View File

@ -0,0 +1,89 @@
# Pending merge of 7309704ace2017e701e1b566359d012067c4107a, use this instead as its the latest
## Most of these have DO NOT MAP, since stations are completely unequipped to deal with ship combat + these are basically placeholder.
#
#- type: entity
# id: ShuttleGunSvalinnMachineGunCircuitboard
# parent: BaseMachineCircuitboard
# name: LSE-400c "Svalinn machine gun" machine board
# description: A machine printed circuit board for an LSE-400c "Svalinn machine gun"
# suffix: DO NOT MAP, Machine Board
# components:
# - type: Sprite
# state: security
# - type: MachineBoard
# prototype: ShuttleGunSvalinnMachineGun
# stackRequirements:
# MatterBin: 2
# Manipulator: 4
# Steel: 5
# CableHV: 5
#
#- type: entity
# id: ShuttleGunPerforatorCircuitboard
# parent: BaseMachineCircuitboard
# name: LSE-1200c "Perforator" machine board
# description: A machine printed circuit board for an LSE-1200c "Perforator"
# suffix: DO NOT MAP, Machine Board
# components:
# - type: Sprite
# state: security
# - type: MachineBoard
# prototype: ShuttleGunPerforator
# stackRequirements:
# MatterBin: 4
# Manipulator: 6
# Steel: 10
# CableHV: 5
#
#- type: entity
# id: ShuttleGunFriendshipCircuitboard
# parent: BaseMachineCircuitboard
# name: EXP-320g "Friendship" machine board
# description: A machine printed circuit board for an EXP-320g "Friendship"
# suffix: DO NOT MAP, Machine Board
# components:
# - type: Sprite
# state: security
# - type: MachineBoard
# prototype: ShuttleGunFriendship
# stackRequirements:
# MatterBin: 3
# Manipulator: 2
# Steel: 7
# CableHV: 5
#
#- type: entity
# id: ShuttleGunDusterCircuitboard
# parent: BaseMachineCircuitboard
# name: EXP-2100g "Duster" machine board
# description: A machine printed circuit board for an EXP-2100g "Duster"
# suffix: DO NOT MAP, Machine Board
# components:
# - type: Sprite
# state: security
# - type: MachineBoard
# prototype: ShuttleGunDuster
# stackRequirements:
# MatterBin: 6
# Manipulator: 4
# Steel: 10
# CableHV: 5
# Uranium: 2
#
#- type: entity
# id: ShuttleGunKineticCircuitboard
# parent: BaseMachineCircuitboard
# name: PTK-800 "Matter Dematerializer" machine board
# description: A machine printed circuit board for an PTK-800 "Matter Dematerializer"
# suffix: DO NOT MAP, Machine Board
# components:
# - type: Sprite
# state: security
# - type: MachineBoard
# prototype: ShuttleGunKinetic
# stackRequirements:
# MatterBin: 2
# Manipulator: 3
# Steel: 5
# CableHV: 2

View File

@ -8,7 +8,7 @@
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEndCapUnfinished
materialRequirements:
stackRequirements:
Glass: 15
Steel: 15
@ -24,10 +24,9 @@
prototype: ParticleAcceleratorFuelChamberUnfinished
componentRequirements:
AmeFuelContainer:
Amount: 1
DefaultPrototype: AmeJar
ExamineName: AME Fuel Jar
materialRequirements:
amount: 1
defaultPrototype: AmeJar
stackRequirements:
Glass: 10
Steel: 10
@ -41,7 +40,7 @@
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorPowerBoxUnfinished
materialRequirements:
stackRequirements:
Glass: 5
Steel: 5
@ -57,7 +56,7 @@
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterStarboardUnfinished
materialRequirements:
stackRequirements:
Glass: 5
Steel: 5
@ -71,7 +70,7 @@
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterForeUnfinished
materialRequirements:
stackRequirements:
Glass: 5
Steel: 5
@ -85,6 +84,6 @@
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterPortUnfinished
materialRequirements:
stackRequirements:
Glass: 5
Steel: 5

View File

@ -6,10 +6,9 @@
components:
- type: MachineBoard
prototype: Autolathe
requirements:
stackRequirements:
MatterBin: 3
Manipulator: 1
materialRequirements:
Glass: 1
- type: entity
@ -20,15 +19,13 @@
components:
- type: MachineBoard
prototype: AutolatheHyperConvection
requirements:
stackRequirements:
MatterBin: 3
materialRequirements:
Glass: 1
tagRequirements:
Igniter:
Amount: 1
DefaultPrototype: Igniter
ExamineName: Igniter
amount: 1
defaultPrototype: Igniter
- type: ReverseEngineering # delta
difficulty: 2
recipes:
@ -42,14 +39,13 @@
components:
- type: MachineBoard
prototype: Protolathe
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: entity
parent: BaseMachineCircuitboard
@ -59,17 +55,15 @@
components:
- type: MachineBoard
prototype: ProtolatheHyperConvection
requirements:
stackRequirements:
MatterBin: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
Igniter:
Amount: 1
DefaultPrototype: Igniter
ExamineName: Igniter
amount: 1
defaultPrototype: Igniter
- type: ReverseEngineering # delta
difficulty: 2
recipes:
@ -83,9 +77,8 @@
components:
- type: MachineBoard
prototype: Biofabricator
requirements:
stackRequirements:
MatterBin: 4
materialRequirements:
Glass: 1
- type: ReverseEngineering # delta
difficulty: 2
@ -102,14 +95,13 @@
state: security
- type: MachineBoard
prototype: SecurityTechFab
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: entity
id: AmmoTechFabCircuitboard
@ -121,7 +113,7 @@
state: security
- type: MachineBoard
prototype: AmmoTechFab
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 1
@ -135,14 +127,13 @@
state: medical
- type: MachineBoard
prototype: MedicalTechFab
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: StealTarget
stealGroup: MedicalTechFabCircuitboard
@ -155,14 +146,13 @@
state: science
- type: MachineBoard
prototype: CircuitImprinter
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 1
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: entity
parent: BaseMachineCircuitboard
@ -174,17 +164,15 @@
state: science
- type: MachineBoard
prototype: CircuitImprinterHyperConvection
requirements:
stackRequirements:
MatterBin: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
Igniter:
Amount: 1
DefaultPrototype: Igniter
ExamineName: Igniter
amount: 1
defaultPrototype: Igniter
- type: entity
id: ExosuitFabricatorMachineCircuitboard
@ -195,10 +183,9 @@
state: science
- type: MachineBoard
prototype: ExosuitFabricator
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 3
materialRequirements:
Glass: 5
- type: ReverseEngineering # Nyano
difficulty: 2
@ -219,7 +206,7 @@
state: science
- type: MachineBoard
prototype: ResearchAndDevelopmentServer
materialRequirements:
stackRequirements:
Plasma: 5
- type: entity
@ -229,7 +216,7 @@
components:
- type: MachineBoard
prototype: UniformPrinter
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 2
@ -242,16 +229,14 @@
state: medical
- type: MachineBoard
prototype: Vaccinator
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 1
materialRequirements:
Cable: 5
tagRequirements:
GlassBeaker:
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 1
defaultPrototype: Beaker
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
@ -266,22 +251,20 @@
state: medical
- type: MachineBoard
prototype: DiseaseDiagnoser
materialRequirements:
stackRequirements:
Cable: 5
tagRequirements:
GlassBeaker:
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 1
defaultPrototype: Beaker
componentRequirements:
DiseaseSwab:
Amount: 1
DefaultPrototype: DiseaseSwab
ExamineName: Swab
BotanySwab:
amount: 1
defaultPrototype: DiseaseSwab
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
- DiagnoserMachineCircuitboard
- DiagnoserMachineCircuitboard
- type: entity
id: ArtifactAnalyzerMachineCircuitboard
@ -293,10 +276,9 @@
state: science
- type: MachineBoard
prototype: MachineArtifactAnalyzer
requirements:
stackRequirements:
Manipulator: 3
Capacitor: 1
materialRequirements:
Glass: 5
- type: ReverseEngineering # Nyano
difficulty: 2
@ -313,9 +295,8 @@
state: science
- type: MachineBoard
prototype: MachineArtifactCrusher
requirements:
stackRequirements:
Manipulator: 2
materialRequirements:
Glass: 1
Steel: 5
- type: ReverseEngineering # delta
@ -333,9 +314,8 @@
state: science
- type: MachineBoard
prototype: MachineAnomalyVessel
requirements:
stackRequirements:
Capacitor: 3
materialRequirements:
Cable: 1
PlasmaGlass: 10
- type: ReverseEngineering # Nyano
@ -353,9 +333,8 @@
state: science
- type: MachineBoard
prototype: MachineAnomalyVesselExperimental
requirements:
stackRequirements:
Capacitor: 3
materialRequirements:
Cable: 5
PlasmaGlass: 15
MetalRod: 4
@ -374,10 +353,9 @@
state: science
- type: MachineBoard
prototype: MachineAnomalySynchronizer
requirements:
stackRequirements:
Manipulator: 2
Capacitor: 5
materialRequirements:
PlasmaGlass: 5
Cable: 5
- type: ReverseEngineering # delta
@ -395,9 +373,8 @@
state: science
- type: MachineBoard
prototype: MachineAPE
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Cable: 1
Glass: 1
- type: ReverseEngineering # Nyano
@ -415,10 +392,9 @@
state: engineering
- type: MachineBoard
prototype: GasThermoMachineFreezer
requirements:
stackRequirements:
MatterBin: 2
Capacitor: 2
materialRequirements:
Cable: 5
- type: Construction
deconstructionTarget: null
@ -439,10 +415,9 @@
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHeater
requirements:
stackRequirements:
MatterBin: 2
Capacitor: 2
materialRequirements:
Cable: 5
- type: Construction
graph: ThermomachineBoard
@ -459,10 +434,9 @@
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHellfireFreezer
requirements:
stackRequirements:
MatterBin: 2
Capacitor: 2
materialRequirements:
Plasma: 1
- type: Construction
deconstructionTarget: null
@ -483,10 +457,9 @@
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHellfireHeater
requirements:
stackRequirements:
MatterBin: 2
Capacitor: 2
materialRequirements:
Plasma: 1
- type: Construction
graph: ThermomachineBoard
@ -503,9 +476,8 @@
state: engineering
- type: MachineBoard
prototype: BaseGasCondenser
requirements:
stackRequirements:
MatterBin: 1
materialRequirements:
Glass: 1
- type: entity
@ -518,10 +490,9 @@
state: engineering
- type: MachineBoard
prototype: PortableScrubber
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 2
materialRequirements:
Cable: 5
Glass: 2
- type: ReverseEngineering # Nayno
@ -539,10 +510,9 @@
state: engineering
- type: MachineBoard
prototype: SpaceHeater
requirements:
stackRequirements:
MatterBin: 1
Capacitor: 2
materialRequirements:
Cable: 5
- type: entity
@ -555,10 +525,9 @@
state: medical
- type: MachineBoard
prototype: CloningPod
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 2
materialRequirements:
Glass: 1
Cable: 1
- type: ReverseEngineering # Nyano
@ -576,9 +545,8 @@
state: medical
- type: MachineBoard
prototype: MedicalScanner
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
Glass: 5
Cable: 1
- type: ReverseEngineering # Nyano
@ -594,7 +562,7 @@
components:
- type: MachineBoard
prototype: CrewMonitoringServer
materialRequirements:
stackRequirements:
Steel: 1
Cable: 2
@ -608,7 +576,7 @@
state: medical
- type: MachineBoard
prototype: CryoPod
materialRequirements:
stackRequirements:
Glass: 5
Cable: 1
- type: ReverseEngineering # Nyano
@ -626,16 +594,14 @@
state: medical
- type: MachineBoard
prototype: ChemMaster
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
Glass: 1
Cable: 1
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: entity
id: ChemDispenserMachineCircuitboard
@ -647,16 +613,14 @@
state: medical
- type: MachineBoard
prototype: ChemDispenserEmpty
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
Glass: 1
Steel: 3
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: entity
id: BiomassReclaimerMachineCircuitboard
@ -666,20 +630,19 @@
components:
- type: MachineBoard
prototype: BiomassReclaimer
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 1
Steel: 5
tagRequirements:
Knife:
Amount: 2
DefaultPrototype: KitchenKnife
ExamineName: Knife
materialRequirements:
Steel: 5
amount: 2
defaultPrototype: KitchenKnife
examineName: construction-insert-info-examine-name-knife
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
- BiomassReclaimerMachineCircuitboard
- BiomassReclaimerMachineCircuitboard
- type: entity
id: HydroponicsTrayMachineCircuitboard
@ -691,15 +654,14 @@
state: service
- type: MachineBoard
prototype: HydroponicsTrayEmpty
materialRequirements:
stackRequirements:
# replacing the console screen
Glass: 5
Cable: 2
tagRequirements:
GlassBeaker:
Amount: 2
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 2
defaultPrototype: Beaker
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
@ -715,10 +677,9 @@
state: service
- type: MachineBoard
prototype: SeedExtractor
requirements:
stackRequirements:
Manipulator: 2
Capacitor: 1
materialRequirements:
# replacing the console screen
Glass: 1
Cable: 2
@ -738,11 +699,13 @@
state: power_mod
- type: MachineBoard
prototype: SMESBasicEmpty
requirements:
stackRequirements:
Capacitor: 1
PowerCell: 4
materialRequirements:
CableHV: 10
componentRequirements:
PowerCell:
amount: 4
defaultPrototype: PowerCellSmall
- type: entity
id: CellRechargerCircuitboard
@ -755,9 +718,8 @@
state: charger_APC
- type: MachineBoard
prototype: PowerCellRecharger
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Cable: 5
- type: PhysicalComposition
materialComposition:
@ -777,9 +739,8 @@
state: charger_APC
- type: MachineBoard
prototype: PowerCageRecharger
requirements:
stackRequirements:
Capacitor: 4
materialRequirements:
Steel: 5
Cable: 10
- type: PhysicalComposition
@ -804,9 +765,8 @@
state: charger_APC
- type: MachineBoard
prototype: BorgCharger
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Cable: 5
- type: PhysicalComposition
materialComposition:
@ -826,9 +786,8 @@
state: charger_APC
- type: MachineBoard
prototype: WeaponCapacitorRecharger
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
CableMV: 5
- type: PhysicalComposition
materialComposition:
@ -848,9 +807,8 @@
state: charger_APC
- type: MachineBoard
prototype: TurboItemRecharger
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
CableMV: 5
- type: PhysicalComposition
materialComposition:
@ -869,12 +827,14 @@
components:
- type: MachineBoard
prototype: SubstationBasicEmpty
requirements:
stackRequirements:
Capacitor: 1
PowerCell: 1
materialRequirements:
CableMV: 5
CableHV: 5
componentRequirements:
PowerCell:
amount: 1
defaultPrototype: PowerCellSmall
- type: PhysicalComposition
materialComposition:
Glass: 200
@ -890,35 +850,35 @@
components:
- type: MachineBoard
prototype: DawInstrument
materialRequirements:
stackRequirements:
Glass: 1
Cable: 1
tagRequirements:
# One instrument to bring them all and in the darkness bind them...
KeyedInstrument:
Amount: 1
DefaultPrototype: SynthesizerInstrument
ExamineName: Keyed Instrument
amount: 1
defaultPrototype: SynthesizerInstrument
examineName: construction-insert-info-examine-name-instrument-keyed
StringInstrument:
Amount: 1
DefaultPrototype: AcousticGuitarInstrument
ExamineName: String Instrument
amount: 1
defaultPrototype: AcousticGuitarInstrument
examineName: construction-insert-info-examine-name-instrument-string
PercussionInstrument:
Amount: 1
DefaultPrototype: GlockenspielInstrument
ExamineName: Percussion Instrument
amount: 1
defaultPrototype: GlockenspielInstrument
examineName: construction-insert-info-examine-name-instrument-percussion
BrassInstrument:
Amount: 1
DefaultPrototype: TrumpetInstrument
ExamineName: Brass Instrument
amount: 1
defaultPrototype: TrumpetInstrument
examineName: construction-insert-info-examine-name-instrument-brass
WoodwindInstrument:
Amount: 1
DefaultPrototype: SaxophoneInstrument
ExamineName: Woodwind Instrument
amount: 1
defaultPrototype: SaxophoneInstrument
examineName: construction-insert-info-examine-name-instrument-woodwind
- type: ReverseEngineering # Nyano
difficulty: 2
recipes:
- DawInstrumentMachineCircuitboard
- DawInstrumentMachineCircuitboard
- type: entity
id: PortableGeneratorPacmanMachineCircuitboard
@ -929,9 +889,8 @@
state: engineering
- type: MachineBoard
prototype: PortableGeneratorPacman
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
CableHV: 5
- type: ReverseEngineering # Nyano
difficulty: 2
@ -952,9 +911,8 @@
components:
- type: MachineBoard
prototype: Thruster
requirements:
stackRequirements:
Capacitor: 4
materialRequirements:
Steel: 5
- type: ReverseEngineering # delta
difficulty: 3
@ -968,10 +926,9 @@
components:
- type: MachineBoard
prototype: Gyroscope
requirements:
stackRequirements:
Manipulator: 2
Capacitor: 1
materialRequirements:
Glass: 2
- type: ReverseEngineering # delta
difficulty: 3
@ -987,9 +944,8 @@
state: engineering
- type: MachineBoard
prototype: PortableGeneratorSuperPacman
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
CableHV: 10
- type: PhysicalComposition
materialComposition:
@ -1012,9 +968,8 @@
state: engineering
- type: MachineBoard
prototype: PortableGeneratorJrPacman
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
Cable: 10
- type: PhysicalComposition
materialComposition:
@ -1036,14 +991,13 @@
components:
- type: MachineBoard
prototype: KitchenReagentGrinder
requirements:
stackRequirements:
MatterBin: 2
Manipulator: 2
tagRequirements:
GlassBeaker:
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 1
defaultPrototype: Beaker
- type: entity
id: HotplateMachineCircuitboard
@ -1053,9 +1007,8 @@
components:
- type: MachineBoard
prototype: ChemistryHotplate
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Glass: 1
- type: entity
@ -1066,9 +1019,8 @@
components:
- type: MachineBoard
prototype: KitchenElectricGrill
requirements:
stackRequirements:
Capacitor: 4
materialRequirements:
Glass: 2
Cable: 5
@ -1081,10 +1033,9 @@
state: medical
- type: MachineBoard
prototype: StasisBed
requirements:
stackRequirements:
Capacitor: 1
Manipulator: 1
materialRequirements:
Cable: 3
Steel: 2
- type: ReverseEngineering # Nyano
@ -1102,9 +1053,8 @@
state: medical
- type: MachineBoard
prototype: MachineElectrolysisUnit
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Cable: 1
- type: entity
@ -1117,9 +1067,8 @@
state: medical
- type: MachineBoard
prototype: MachineCentrifuge
requirements:
stackRequirements:
Manipulator: 1
materialRequirements:
Steel: 1
- type: entity
@ -1131,9 +1080,8 @@
state: supply
- type: MachineBoard
prototype: MaterialReclaimer
requirements:
stackRequirements:
Manipulator: 2
materialRequirements:
Steel: 5
Plastic: 5
@ -1146,10 +1094,9 @@
state: supply
- type: MachineBoard
prototype: OreProcessor
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 3
materialRequirements:
Glass: 1
- type: entity
@ -1161,10 +1108,9 @@
state: supply
- type: MachineBoard
prototype: OreProcessorIndustrial
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 3
materialRequirements:
Glass: 1
- type: ReverseEngineering # delta
difficulty: 2
@ -1178,7 +1124,7 @@
components:
- type: MachineBoard
prototype: Sheetifier
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 1
- type: ReverseEngineering # delta
@ -1195,9 +1141,8 @@
state: service
- type: MachineBoard
prototype: KitchenMicrowave
requirements:
stackRequirements:
Capacitor: 1
materialRequirements:
Glass: 2
Cable: 2
- type: Tag
@ -1227,17 +1172,17 @@
state: service
- type: MachineBoard
prototype: FatExtractor
requirements:
stackRequirements:
Manipulator: 1
componentRequirements:
Utensil:
Amount: 1
DefaultPrototype: ForkPlastic
ExamineName: Utensil
amount: 1
defaultPrototype: ForkPlastic
examineName: construction-insert-info-examine-name-utensil
- type: ReverseEngineering # delta
difficulty: 2
recipes:
- FatExtractorMachineCircuitboard
- FatExtractorMachineCircuitboard
- type: entity
parent: BaseMachineCircuitboard
@ -1246,10 +1191,9 @@
components:
- type: MachineBoard
prototype: MachineFlatpacker
requirements:
stackRequirements:
Manipulator: 2
MatterBin: 1
materialRequirements:
Steel: 1
- type: ReverseEngineering # delta
difficulty: 2
@ -1265,9 +1209,8 @@
state: engineering
- type: MachineBoard
prototype: Emitter
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
CableHV: 5
Glass: 2
@ -1279,7 +1222,7 @@
components:
- type: MachineBoard
prototype: SurveillanceCameraRouterConstructed
materialRequirements:
stackRequirements:
Cable: 1
- type: ReverseEngineering # Nyano
difficulty: 2
@ -1294,7 +1237,7 @@
components:
- type: MachineBoard
prototype: SurveillanceCameraWirelessRouterConstructed
materialRequirements:
stackRequirements:
Cable: 2
Glass: 1
- type: ReverseEngineering # Nyano
@ -1310,7 +1253,7 @@
components:
- type: MachineBoard
prototype: SurveillanceWirelessCameraMovableConstructed
materialRequirements:
stackRequirements:
Glass: 2
Cable: 2
- type: ReverseEngineering # Nyano
@ -1326,7 +1269,7 @@
components:
- type: MachineBoard
prototype: SurveillanceWirelessCameraAnchoredConstructed
materialRequirements:
stackRequirements:
Cable: 2
Glass: 1
- type: ReverseEngineering # Nyano
@ -1342,10 +1285,9 @@
components:
- type: MachineBoard
prototype: GasRecycler
requirements:
stackRequirements:
Capacitor: 1
Manipulator: 1
materialRequirements:
Steel: 10
Plasma: 5
- type: ReverseEngineering # Nyano
@ -1363,13 +1305,12 @@
state: service
- type: MachineBoard
prototype: BoozeDispenserEmpty
materialRequirements:
stackRequirements:
Steel: 5
tagRequirements:
GlassBeaker:
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 1
defaultPrototype: Beaker
- type: entity
id: CargoTelepadMachineCircuitboard
@ -1381,9 +1322,8 @@
state: supply
- type: MachineBoard
prototype: CargoTelepad
requirements:
stackRequirements:
Capacitor: 2
materialRequirements:
Steel: 5
Bluespace: 2 #DeltaV Bluespace Exists
- type: ReverseEngineering # delta
@ -1401,13 +1341,12 @@
state: service
- type: MachineBoard
prototype: SodaDispenserEmpty
materialRequirements:
stackRequirements:
Steel: 5
tagRequirements:
GlassBeaker:
Amount: 1
DefaultPrototype: Beaker
ExamineName: Glass Beaker
amount: 1
defaultPrototype: Beaker
- type: entity
id: TelecomServerCircuitboard
@ -1417,7 +1356,7 @@
components:
- type: MachineBoard
prototype: TelecomServer
materialRequirements:
stackRequirements:
Steel: 1
Cable: 2
- type: ReverseEngineering # Nyano
@ -1432,9 +1371,8 @@
components:
- type: MachineBoard
prototype: SalvageMagnet
requirements:
stackRequirements:
Capacitor: 4
materialRequirements:
Steel: 5
CableHV: 5
Cable: 2
@ -1450,10 +1388,9 @@
components:
- type: MachineBoard
prototype: GravityGeneratorMini
requirements:
stackRequirements:
Capacitor: 4
MatterBin: 3
materialRequirements:
Steel: 5
CableHV: 5
Uranium: 2
@ -1575,10 +1512,9 @@
components:
- type: MachineBoard
prototype: ReagentGrinderIndustrial
requirements:
stackRequirements:
MatterBin: 1
Manipulator: 3
materialRequirements:
Glass: 1
- type: ReverseEngineering # delta
difficulty: 2
@ -1593,7 +1529,7 @@
components:
- type: MachineBoard
prototype: Jukebox
materialRequirements:
stackRequirements:
WoodPlank: 5
Steel: 2
Glass: 5

View File

@ -21,9 +21,6 @@
components:
- type: Sprite
state: capacitor
- type: MachinePart
part: Capacitor
rating: 1
- type: Tag
tags:
- CapacitorStockPart
@ -39,11 +36,8 @@
components:
- type: Sprite
state: micro_mani
- type: MachinePart
part: Manipulator
rating: 1
- type: Stack
stackType: MicroManipulator
stackType: Manipulator
- type: entity
id: MatterBinStockPart
@ -54,8 +48,5 @@
components:
- type: Sprite
state: matter_bin
- type: MachinePart
part: MatterBin
rating: 1
- type: Stack
stackType: MatterBin

View File

@ -73,9 +73,6 @@
- type: Battery
maxCharge: 360
startingCharge: 360
- type: MachinePart
part: PowerCell
rating: 1
- type: Tag
tags:
- PowerCellSmall
@ -114,9 +111,6 @@
- type: Battery
maxCharge: 720
startingCharge: 720
- type: MachinePart
part: PowerCell
rating: 2
- type: entity
id: PowerCellMediumPrinted
@ -152,9 +146,6 @@
- type: Battery
maxCharge: 1080
startingCharge: 1080
- type: MachinePart
part: PowerCell
rating: 3
- type: entity
id: PowerCellHighPrinted
@ -190,9 +181,6 @@
- type: Battery
maxCharge: 1800
startingCharge: 1800
- type: MachinePart
part: PowerCell
rating: 4
- type: entity
id: PowerCellHyperPrinted

View File

@ -36,7 +36,7 @@
- BaseStation
- BaseStationAlertLevels
- BaseStationNanotrasen
- BaseRandomStation
# - BaseRandomStation
noSpawn: true
components:
- type: Transform

View File

@ -574,13 +574,6 @@
- ScarfPurple
- ScarfZebra
- type: loadoutGroup # DeltaV
id: MusicianJumpsuit
name: loadout-group-musician-jumpsuit
loadouts:
- MusicianJumpsuit
- MusicianJumpskirt
- type: loadoutGroup
id: MusicianBackpack
name: loadout-group-musician-backpack

View File

@ -1,20 +0,0 @@
- type: machinePart
id: Capacitor
name: machine-part-name-capacitor
stockPartPrototype: CapacitorStockPart
- type: machinePart
id: Manipulator
name: machine-part-name-manipulator
stockPartPrototype: MicroManipulatorStockPart
- type: machinePart
id: MatterBin
name: machine-part-name-matter-bin
stockPartPrototype: MatterBinStockPart
- type: machinePart
id: PowerCell
name: machine-part-name-power-cell
stockPartPrototype: PowerCellSmall

View File

@ -40,7 +40,6 @@
force: !type:Bool
true
useSound: /Audio/Items/jaws_pry.ogg
- type: ToolForcePowered
- type: Clothing
sprite: Nyanotrasen/Objects/Weapons/Melee/breaching_hammer.rsi
quickEquip: false

View File

@ -11,7 +11,7 @@
maxCount: 10
- type: stack
id: MicroManipulator
id: Manipulator
name: micro manipulator
spawn: MicroManipulatorStockPart
maxCount: 10