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));
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;
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}");
});
}
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();
+ }
}
}
// 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();
+++ /dev/null
-using Content.Shared.Construction.Components;
-
-namespace Content.Server.Construction.Components
-{
- [RequiresExplicitImplementation]
- public interface IRefreshParts
- {
- void RefreshParts(IEnumerable<MachinePartComponent> parts);
- }
-}
-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
-{
- [RegisterComponent, ComponentProtoName("Machine")]
- public sealed partial class MachineComponent : Component
- {
- [DataField("board", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
- public string? BoardPrototype { get; private set; }
+namespace Content.Server.Construction.Components;
- [ViewVariables]
- public Container BoardContainer = default!;
- [ViewVariables]
- public Container PartContainer = default!;
- }
+[RegisterComponent]
+public sealed partial class MachineComponent : Component
+{
+ [DataField]
+ public EntProtoId<MachineBoardComponent>? Board { get; private set; }
- /// <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!;
}
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
{
[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!;
+++ /dev/null
-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;
-}
using Content.Shared.Construction;
using Content.Shared.Examine;
using JetBrains.Annotations;
+using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
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)
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;
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)
{
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)
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)
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");
}
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.
};
}
// 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>
}
// 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
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;
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 {})
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)
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)
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.
// 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(
// 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));
-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)
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)
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)}!");
- }
-
- var xform = Transform(uid);
- foreach (var (part, amount) in machineBoard.Requirements)
- {
- 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}!");
- }
+ throw new Exception($"Entity with prototype {component.Board} doesn't have a {nameof(MachineBoardComponent)}!");
}
- foreach (var (stackType, amount) in machineBoard.MaterialRequirements)
+ foreach (var (stackType, amount) in machineBoard.StackRequirements)
{
- 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"}");
}
}
{
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');
- }
-}
[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!;
using Content.Shared.Tag;
using Content.Shared.Popups;
using Robust.Shared.Containers;
-using Robust.Shared.Utility;
+using Robust.Shared.Prototypes;
namespace Content.Server.Construction;
// 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;
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)
{
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)
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;
component.MaterialRequirements.Clear();
component.ComponentRequirements.Clear();
component.TagRequirements.Clear();
- component.Progress.Clear();
component.MaterialProgress.Clear();
component.ComponentProgress.Clear();
component.TagProgress.Clear();
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;
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]++;
}
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))));
}
}
+++ /dev/null
-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
- });
- }
-}
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>
-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
+{
+ /// <summary>
+ /// The stacks needed to construct this machine
+ /// </summary>
+ [DataField]
+ public Dictionary<ProtoId<StackPrototype>, int> StackRequirements = new();
+
+ /// <summary>
+ /// Entities needed to construct this machine, discriminated by tag.
+ /// </summary>
+ [DataField]
+ public Dictionary<ProtoId<TagPrototype>, GenericPartInfo> TagRequirements = new();
+
+ /// <summary>
+ /// Entities needed to construct this machine, discriminated by component.
+ /// </summary>
+ [DataField]
+ public Dictionary<string, GenericPartInfo> ComponentRequirements = new();
+
+ /// <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
{
- [RegisterComponent, NetworkedComponent]
- public sealed partial class MachineBoardComponent : Component
- {
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
-
- [DataField("requirements", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, MachinePartPrototype>))]
- public Dictionary<string, int> Requirements = new();
-
- [DataField("materialRequirements")]
- public Dictionary<string, int> MaterialIdRequirements = 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;
- }
+ [DataField(required: true)]
+ public int Amount;
+
+ [DataField(required: true)]
+ public EntProtoId DefaultPrototype;
+
+ [DataField]
+ public LocId? ExamineName;
}
+++ /dev/null
-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;
- }
-}
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
{
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedLatheSystem _lathe = default!;
+ [Dependency] private readonly SharedConstructionSystem _construction = default!;
public override void Initialize()
{
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)));
}
}
}
var (_, comp) = entity;
var materials = new Dictionary<string, int>();
- foreach (var (partId, amount) in comp.Requirements)
- {
- 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)
+ foreach (var (stackId, amount) in comp.StackRequirements)
{
- 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)
{
}
}
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)
{
+++ /dev/null
-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;
-}
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
public abstract class SharedConstructionSystem : EntitySystem
{
[Dependency] private readonly IMapManager _mapManager = default!;
+ [Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
/// <summary>
/// Get predicate for construction obstruction checks.
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;
+ }
}
}
-using System.Numerics;
using Content.Shared.Construction.Components;
using Content.Shared.Administration.Logs;
using Content.Shared.Database;
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;
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);
}
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!;
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
public float MaterialUseMultiplier = 1;
-
- public const float DefaultPartRatingMaterialUseMultiplier = 0.85f;
#endregion
}
# Shown when examining an in-construction object
-construction-insert-arbitrary-entity = Next, insert {$stepName}.
\ No newline at end of file
+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
state: security
- type: MachineBoard
prototype: ShuttleGunSvalinnMachineGun
- requirements:
+ stackRequirements:
MatterBin: 2
Manipulator: 4
- materialRequirements:
Steel: 5
CableHV: 5
state: security
- type: MachineBoard
prototype: ShuttleGunPerforator
- requirements:
+ stackRequirements:
MatterBin: 4
Manipulator: 6
- materialRequirements:
Steel: 10
CableHV: 5
state: security
- type: MachineBoard
prototype: ShuttleGunFriendship
- requirements:
+ stackRequirements:
MatterBin: 3
Manipulator: 2
- materialRequirements:
Steel: 7
CableHV: 5
state: security
- type: MachineBoard
prototype: ShuttleGunDuster
- requirements:
+ stackRequirements:
MatterBin: 6
Manipulator: 4
- materialRequirements:
Steel: 10
CableHV: 5
Uranium: 2
state: security
- type: MachineBoard
prototype: ShuttleGunKinetic
- requirements:
+ stackRequirements:
MatterBin: 2
Manipulator: 3
- materialRequirements:
Steel: 5
- CableHV: 2
\ No newline at end of file
+ CableHV: 2
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEndCapUnfinished
- materialRequirements:
+ stackRequirements:
Glass: 15
Steel: 15
prototype: ParticleAcceleratorFuelChamberUnfinished
componentRequirements:
AmeFuelContainer:
- Amount: 1
- DefaultPrototype: AmeJar
- ExamineName: AME Fuel Jar
- materialRequirements:
+ amount: 1
+ defaultPrototype: AmeJar
+ stackRequirements:
Glass: 10
Steel: 10
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorPowerBoxUnfinished
- materialRequirements:
+ stackRequirements:
Glass: 5
Steel: 5
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterStarboardUnfinished
- materialRequirements:
+ stackRequirements:
Glass: 5
Steel: 5
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterForeUnfinished
- materialRequirements:
+ stackRequirements:
Glass: 5
Steel: 5
state: engineering
- type: MachineBoard
prototype: ParticleAcceleratorEmitterPortUnfinished
- materialRequirements:
+ stackRequirements:
Glass: 5
Steel: 5
components:
- type: MachineBoard
prototype: Autolathe
- requirements:
+ stackRequirements:
MatterBin: 3
Manipulator: 1
- materialRequirements:
Glass: 1
- type: entity
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: entity
id: ProtolatheMachineCircuitboard
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
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: entity
id: BiofabricatorMachineCircuitboard
components:
- type: MachineBoard
prototype: Biofabricator
- requirements:
+ stackRequirements:
MatterBin: 4
- materialRequirements:
Glass: 1
- type: entity
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
state: security
- type: MachineBoard
prototype: AmmoTechFab
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 1
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
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
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
state: science
- type: MachineBoard
prototype: ExosuitFabricator
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 3
- materialRequirements:
Glass: 5
- type: GuideHelp
guides:
state: science
- type: MachineBoard
prototype: ResearchAndDevelopmentServer
- materialRequirements:
+ stackRequirements:
Plasma: 5
- type: entity
components:
- type: MachineBoard
prototype: UniformPrinter
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 2
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: entity
id: DiagnoserMachineCircuitboard
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: entity
id: ArtifactAnalyzerMachineCircuitboard
state: science
- type: MachineBoard
prototype: MachineArtifactAnalyzer
- requirements:
+ stackRequirements:
Manipulator: 3
Capacitor: 1
- materialRequirements:
Glass: 5
- type: entity
state: science
- type: MachineBoard
prototype: MachineArtifactCrusher
- requirements:
+ stackRequirements:
Manipulator: 2
- materialRequirements:
Glass: 1
Steel: 5
state: science
- type: MachineBoard
prototype: MachineAnomalyVessel
- requirements:
+ stackRequirements:
Capacitor: 3
- materialRequirements:
Cable: 1
PlasmaGlass: 10
state: science
- type: MachineBoard
prototype: MachineAnomalyVesselExperimental
- requirements:
+ stackRequirements:
Capacitor: 3
- materialRequirements:
Cable: 5
PlasmaGlass: 15
MetalRod: 4
state: science
- type: MachineBoard
prototype: MachineAnomalySynchronizer
- requirements:
+ stackRequirements:
Manipulator: 2
Capacitor: 5
- materialRequirements:
PlasmaGlass: 5
Cable: 5
state: science
- type: MachineBoard
prototype: MachineAPE
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Cable: 1
Glass: 1
state: engineering
- type: MachineBoard
prototype: GasThermoMachineFreezer
- requirements:
+ stackRequirements:
MatterBin: 2
Capacitor: 2
- materialRequirements:
Cable: 5
- type: Construction
deconstructionTarget: null
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHeater
- requirements:
+ stackRequirements:
MatterBin: 2
Capacitor: 2
- materialRequirements:
Cable: 5
- type: Construction
graph: ThermomachineBoard
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHellfireFreezer
- requirements:
+ stackRequirements:
MatterBin: 2
Capacitor: 2
- materialRequirements:
Plasma: 1
- type: Construction
deconstructionTarget: null
state: engineering
- type: MachineBoard
prototype: GasThermoMachineHellfireHeater
- requirements:
+ stackRequirements:
MatterBin: 2
Capacitor: 2
- materialRequirements:
Plasma: 1
- type: Construction
graph: ThermomachineBoard
state: engineering
- type: MachineBoard
prototype: BaseGasCondenser
- requirements:
+ stackRequirements:
MatterBin: 1
- materialRequirements:
Glass: 1
- type: entity
state: engineering
- type: MachineBoard
prototype: PortableScrubber
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 2
- materialRequirements:
Cable: 5
Glass: 2
state: engineering
- type: MachineBoard
prototype: SpaceHeater
- requirements:
+ stackRequirements:
MatterBin: 1
Capacitor: 2
- materialRequirements:
Cable: 5
- type: entity
state: medical
- type: MachineBoard
prototype: CloningPod
- requirements:
+ stackRequirements:
MatterBin: 2
Manipulator: 2
- materialRequirements:
Glass: 1
Cable: 1
state: medical
- type: MachineBoard
prototype: MedicalScanner
- requirements:
+ stackRequirements:
Capacitor: 1
- materialRequirements:
Glass: 5
Cable: 1
components:
- type: MachineBoard
prototype: CrewMonitoringServer
- materialRequirements:
+ stackRequirements:
Steel: 1
Cable: 2
state: medical
- type: MachineBoard
prototype: CryoPod
- materialRequirements:
+ stackRequirements:
Glass: 5
Cable: 1
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
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
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: entity
id: HydroponicsTrayMachineCircuitboard
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: entity
id: SeedExtractorMachineCircuitboard
state: service
- type: MachineBoard
prototype: SeedExtractor
- requirements:
+ stackRequirements:
Manipulator: 2
Capacitor: 1
- materialRequirements:
# replacing the console screen
Glass: 1
Cable: 2
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
state: charger_APC
- type: MachineBoard
prototype: PowerCellRecharger
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Cable: 5
- type: PhysicalComposition
materialComposition:
state: charger_APC
- type: MachineBoard
prototype: PowerCageRecharger
- requirements:
+ stackRequirements:
Capacitor: 4
- materialRequirements:
Steel: 5
Cable: 10
- type: PhysicalComposition
state: charger_APC
- type: MachineBoard
prototype: BorgCharger
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Cable: 5
- type: PhysicalComposition
materialComposition:
state: charger_APC
- type: MachineBoard
prototype: WeaponCapacitorRecharger
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
CableMV: 5
- type: PhysicalComposition
materialComposition:
state: charger_APC
- type: MachineBoard
prototype: TurboItemRecharger
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
CableMV: 5
- type: PhysicalComposition
materialComposition:
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
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: entity
id: PortableGeneratorPacmanMachineCircuitboard
state: engineering
- type: MachineBoard
prototype: PortableGeneratorPacman
- requirements:
+ stackRequirements:
Capacitor: 1
- materialRequirements:
CableHV: 5
- type: PhysicalComposition
materialComposition:
components:
- type: MachineBoard
prototype: Thruster
- requirements:
+ stackRequirements:
Capacitor: 4
- materialRequirements:
Steel: 5
- type: entity
components:
- type: MachineBoard
prototype: Gyroscope
- requirements:
+ stackRequirements:
Manipulator: 2
Capacitor: 1
- materialRequirements:
Glass: 2
- type: entity
state: engineering
- type: MachineBoard
prototype: PortableGeneratorSuperPacman
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
CableHV: 10
- type: PhysicalComposition
materialComposition:
state: engineering
- type: MachineBoard
prototype: PortableGeneratorJrPacman
- requirements:
+ stackRequirements:
Capacitor: 1
- materialRequirements:
Cable: 10
- type: PhysicalComposition
materialComposition:
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
components:
- type: MachineBoard
prototype: ChemistryHotplate
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Glass: 1
- type: entity
components:
- type: MachineBoard
prototype: KitchenElectricGrill
- requirements:
+ stackRequirements:
Capacitor: 4
- materialRequirements:
Glass: 2
Cable: 5
state: medical
- type: MachineBoard
prototype: StasisBed
- requirements:
+ stackRequirements:
Capacitor: 1
Manipulator: 1
- materialRequirements:
Cable: 3
Steel: 2
state: medical
- type: MachineBoard
prototype: MachineElectrolysisUnit
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Cable: 1
- type: entity
state: medical
- type: MachineBoard
prototype: MachineCentrifuge
- requirements:
+ stackRequirements:
Manipulator: 1
- materialRequirements:
Steel: 1
- type: entity
state: supply
- type: MachineBoard
prototype: MaterialReclaimer
- requirements:
+ stackRequirements:
Manipulator: 2
- materialRequirements:
Steel: 5
Plastic: 5
state: supply
- type: MachineBoard
prototype: OreProcessor
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 3
- materialRequirements:
Glass: 1
- type: entity
state: supply
- type: MachineBoard
prototype: OreProcessorIndustrial
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 3
- materialRequirements:
Glass: 1
- type: entity
components:
- type: MachineBoard
prototype: Sheetifier
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 1
state: service
- type: MachineBoard
prototype: KitchenMicrowave
- requirements:
+ stackRequirements:
Capacitor: 1
- materialRequirements:
Glass: 2
Cable: 2
- type: Tag
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: entity
parent: BaseMachineCircuitboard
components:
- type: MachineBoard
prototype: MachineFlatpacker
- requirements:
+ stackRequirements:
Manipulator: 2
MatterBin: 1
- materialRequirements:
Steel: 1
- type: entity
state: engineering
- type: MachineBoard
prototype: Emitter
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
CableHV: 5
Glass: 2
components:
- type: MachineBoard
prototype: SurveillanceCameraRouterConstructed
- materialRequirements:
+ stackRequirements:
Cable: 1
- type: entity
components:
- type: MachineBoard
prototype: SurveillanceCameraWirelessRouterConstructed
- materialRequirements:
+ stackRequirements:
Cable: 2
Glass: 1
components:
- type: MachineBoard
prototype: SurveillanceWirelessCameraMovableConstructed
- materialRequirements:
+ stackRequirements:
Glass: 2
Cable: 2
components:
- type: MachineBoard
prototype: SurveillanceWirelessCameraAnchoredConstructed
- materialRequirements:
+ stackRequirements:
Cable: 2
Glass: 1
components:
- type: MachineBoard
prototype: GasRecycler
- requirements:
+ stackRequirements:
Capacitor: 1
Manipulator: 1
- materialRequirements:
Steel: 10
Plasma: 5
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
state: supply
- type: MachineBoard
prototype: CargoTelepad
- requirements:
+ stackRequirements:
Capacitor: 2
- materialRequirements:
Steel: 5
- type: entity
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
components:
- type: MachineBoard
prototype: TelecomServer
- materialRequirements:
+ stackRequirements:
Steel: 1
Cable: 2
components:
- type: MachineBoard
prototype: SalvageMagnet
- requirements:
+ stackRequirements:
Capacitor: 4
- materialRequirements:
Steel: 5
CableHV: 5
Cable: 2
components:
- type: MachineBoard
prototype: GravityGeneratorMini
- requirements:
+ stackRequirements:
Capacitor: 4
MatterBin: 3
- materialRequirements:
Steel: 5
CableHV: 5
Uranium: 2
components:
- type: MachineBoard
prototype: ReagentGrinderIndustrial
- requirements:
+ stackRequirements:
MatterBin: 1
Manipulator: 3
- materialRequirements:
Glass: 1
- type: entity
components:
- type: MachineBoard
prototype: Jukebox
- materialRequirements:
+ stackRequirements:
WoodPlank: 5
Steel: 2
Glass: 5
components:
- type: Sprite
state: capacitor
- - type: MachinePart
- part: Capacitor
- rating: 1
- type: Tag
tags:
- CapacitorStockPart
components:
- type: Sprite
state: micro_mani
- - type: MachinePart
- part: Manipulator
- rating: 1
- type: Stack
- stackType: MicroManipulator
+ stackType: Manipulator
- type: entity
id: MatterBinStockPart
components:
- type: Sprite
state: matter_bin
- - type: MachinePart
- part: MatterBin
- rating: 1
- type: Stack
stackType: MatterBin
- type: Battery
maxCharge: 360
startingCharge: 360
- - type: MachinePart
- part: PowerCell
- rating: 1
- type: Tag
tags:
- PowerCellSmall
- type: Battery
maxCharge: 720
startingCharge: 720
- - type: MachinePart
- part: PowerCell
- rating: 2
- type: entity
id: PowerCellMediumPrinted
- type: Battery
maxCharge: 1080
startingCharge: 1080
- - type: MachinePart
- part: PowerCell
- rating: 3
- type: entity
id: PowerCellHighPrinted
- type: Battery
maxCharge: 1800
startingCharge: 1800
- - type: MachinePart
- part: PowerCell
- rating: 4
- type: entity
id: PowerCellHyperPrinted
+++ /dev/null
-- 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
-
maxCount: 10
- type: stack
- id: MicroManipulator
+ id: Manipulator
name: micro manipulator
spawn: MicroManipulatorStockPart
maxCount: 10