Borg type switching. (#32586)

* Borg type switching.

This allows borgs (new spawn or constructed) to select their chassis type on creation, like in SS13. This removes the need for the many different chassis types, and means round-start borgs can actually play the game immediately instead of waiting for science to unlock everything.

New borgs have an additional action that allows them to select their type. This opens a nice window with basic information about the borgs and a select button. Once a type has been selected it is permanent for that borg chassis.

These borg types also immediately start the borg with specific modules, so they do not need to be printed. Additional modules can still be inserted for upgrades, though this is now less critical. The built-in modules cannot be removed, but are shown in the UI.

The modules that each borg type starts with:

* Generic: tools
* Engineering: advanced tools, construction, RCD, cable
* Salvage: Grappling gun, appraisal, mining
* Janitor: cleaning, light replacer
* Medical: treatment
* Service: music, service, clowning

Specialized borgs have 3 additional module slots available on top of the ones listed above, generic borgs have 5.

Borg types are specified in a new BorgTypePrototype. These prototypes specify all information about the borg type. It is assigned to the borg entity through a mix of client side, server, and shared code. Some of the involved components were made networked, others are just ensured they're set on both sides of the wire.

The most gnarly change is the inventory template prototype, which needs to change purely to modify the borg hat offset. I managed to bodge this in with an API that *probably* won't explode for specifically for this use case, but it's still not the most clean of API designs.

Parts for specific borg chassis have been removed (so much deleted YAML) and specialized borg modules that are in the base set of a type have been removed from the exosuit fab as there's no point to printing those.

The ability to "downgrade" a borg so it can select a new chassis, like in SS13, is something that would be nice, but was not high enough priority for me to block the feature on. I did keep it in mind with some of the code, so it may be possible in the future.

There is no fancy animation when selecting borg types like in SS13, because I didn't think it was high priority, and it would add a lot of complex code.

* Fix sandbox failure due to collection expression.

* Module tweak

Fix salvage borg modules still having research/lathe recipes

Engie borg has regular tool module, not advanced.

* Fix inventory system breakage

* Fix migrations

Some things were missing

* Guidebook rewordings & review

* MinWidth on confirm selection button

(cherry picked from commit 1bebb3390ccedfdae173f0f681be6578146057ca)

(cherry picked from commit 44ca0d5228e4b3faf507a5915007f956c8475541)
This commit is contained in:
Pieter-Jan Briers
2024-11-14 20:08:35 +03:00
committed by Spatison
parent 99288cadfd
commit e1e9a79b82
46 changed files with 1591 additions and 1826 deletions

View File

@@ -64,6 +64,7 @@ public sealed class ClientClothingSystem : ClothingSystem
base.Initialize();
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
@@ -76,11 +77,7 @@ public sealed class ClientClothingSystem : ClothingSystem
if (args.Sprite == null)
return;
var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, component);
}
UpdateAllSlots(uid, component);
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
if (args.Sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer))
@@ -90,6 +87,23 @@ public sealed class ClientClothingSystem : ClothingSystem
}
}
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
{
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
}
private void UpdateAllSlots(
EntityUid uid,
InventoryComponent? inventoryComponent = null,
ClothingComponent? clothing = null)
{
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
}
}
private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args)
{
if (!TryComp(args.Equipee, out InventoryComponent? inventory))
@@ -299,23 +313,6 @@ public sealed class ClientClothingSystem : ClothingSystem
return;
}
if (TryComp<HideLayerClothingComponent>(equipment, out var hideLayer) &&
hideLayer.ClothingSlots != null)
{
foreach (var clothingSlot in hideLayer.ClothingSlots)
{
if (!inventorySlots.VisualLayerKeys.TryGetValue(clothingSlot, out var revealedLayersToHide))
continue;
foreach (var layerToHide in revealedLayersToHide)
sprite.LayerSetVisible(layerToHide, false);
}
inventorySlots.HiddenSlots.UnionWith(hideLayer.ClothingSlots);
}
if (clothingComponent.RenderLayer != null)
slot = clothingComponent.RenderLayer;
// temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a
// bookmark to determine where in the list of layers we should insert the clothing layers.
bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index);
@@ -383,6 +380,8 @@ public sealed class ClientClothingSystem : ClothingSystem
if (layerData.Color != null)
sprite.LayerSetColor(key, layerData.Color.Value);
if (layerData.Scale != null)
sprite.LayerSetScale(key, layerData.Scale.Value);
}
else
index = sprite.LayerMapReserveBlank(key);

View File

@@ -235,6 +235,20 @@ namespace Content.Client.Inventory
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
}
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
base.UpdateInventoryTemplate(ent);
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
{
foreach (var slot in ent.Comp.Slots)
{
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
slotData.SlotDef = slot;
}
}
}
public sealed class SlotData
{
[ViewVariables] // Shitmed Change - Mostly for debugging.

View File

@@ -14,6 +14,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
{
[Dependency] private readonly IPlayerManager _player = default!;
[ViewVariables]
protected bool IsActive;
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;

View File

@@ -21,9 +21,16 @@ public sealed class ShowHealthBarsSystem : EquipmentHudSystem<ShowHealthBarsComp
{
base.Initialize();
SubscribeLocalEvent<ShowHealthBarsComponent, AfterAutoHandleStateEvent>(OnHandleState);
_overlay = new(EntityManager, _prototype);
}
private void OnHandleState(Entity<ShowHealthBarsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthBarsComponent> component)
{
base.UpdateInternal(component);

View File

@@ -17,6 +17,7 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
{
[Dependency] private readonly IPrototypeManager _prototypeMan = default!;
[ViewVariables]
public HashSet<string> DamageContainers = new();
public override void Initialize()
@@ -24,6 +25,7 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
base.Initialize();
SubscribeLocalEvent<DamageableComponent, GetStatusIconsEvent>(OnGetStatusIconsEvent);
SubscribeLocalEvent<ShowHealthIconsComponent, AfterAutoHandleStateEvent>(OnHandleState);
}
protected override void UpdateInternal(RefreshEquipmentHudEvent<ShowHealthIconsComponent> component)
@@ -43,6 +45,11 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem<ShowHealthIconsCo
DamageContainers.Clear();
}
private void OnHandleState(Entity<ShowHealthIconsComponent> ent, ref AfterAutoHandleStateEvent args)
{
RefreshOverlay(ent);
}
private void OnGetStatusIconsEvent(Entity<DamageableComponent> entity, ref GetStatusIconsEvent args)
{
if (!IsActive)

View File

@@ -131,7 +131,8 @@ public sealed partial class BorgMenu : FancyWindow
_modules.Clear();
foreach (var module in chassis.ModuleContainer.ContainedEntities)
{
var control = new BorgModuleControl(module, _entity);
var moduleComponent = _entity.GetComponent<BorgModuleComponent>(module);
var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule);
control.RemoveButtonPressed += () =>
{
RemoveModuleButtonPressed?.Invoke(module);

View File

@@ -9,7 +9,7 @@ public sealed partial class BorgModuleControl : PanelContainer
{
public Action? RemoveButtonPressed;
public BorgModuleControl(EntityUid entity, IEntityManager entityManager)
public BorgModuleControl(EntityUid entity, IEntityManager entityManager, bool canRemove)
{
RobustXamlLoader.Load(this);
@@ -20,6 +20,7 @@ public sealed partial class BorgModuleControl : PanelContainer
{
RemoveButtonPressed?.Invoke();
};
RemoveButton.Visible = canRemove;
}
}

View File

@@ -0,0 +1,43 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
Title="{Loc 'borg-select-type-menu-title'}"
SetSize="550 300">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal" VerticalExpand="True">
<!-- Left pane: selection of borg type -->
<BoxContainer Orientation="Vertical" MinWidth="200" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-available'}" StyleClasses="LabelHeading" />
<ScrollContainer HScrollEnabled="False" VerticalExpand="True">
<BoxContainer Name="SelectionsContainer" Orientation="Vertical" />
</ScrollContainer>
</BoxContainer>
<customControls:VSeparator />
<!-- Right pane: information about selected borg module, confirm button. -->
<BoxContainer Orientation="Vertical" HorizontalExpand="True" Margin="2 0">
<Label Text="{Loc 'borg-select-type-menu-information'}" StyleClasses="LabelHeading" />
<Control VerticalExpand="True">
<controls:Placeholder Name="InfoPlaceholder" PlaceholderText="{Loc 'borg-select-type-menu-select-type'}" />
<BoxContainer Name="InfoContents" Orientation="Vertical" Visible="False">
<BoxContainer Orientation="Horizontal" Margin="0 0 0 4">
<EntityPrototypeView Name="ChassisView" Scale="2,2" />
<Label Name="NameLabel" HorizontalExpand="True" />
</BoxContainer>
<RichTextLabel Name="DescriptionLabel" VerticalExpand="True" VerticalAlignment="Top" />
</BoxContainer>
</Control>
<controls:ConfirmButton Name="ConfirmTypeButton" Text="{Loc 'borg-select-type-menu-confirm'}"
Disabled="True" HorizontalAlignment="Right"
MinWidth="200" />
</BoxContainer>
</BoxContainer>
<controls:StripeBack Margin="0 0 0 4">
<Label Text="{Loc 'borg-select-type-menu-bottom-text'}" HorizontalAlignment="Center" StyleClasses="LabelSubText" Margin="4 4 0 4"/>
</controls:StripeBack>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,81 @@
using System.Linq;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Systems.Guidebook;
using Content.Shared.Guidebook;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Menu used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeUserInterface"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
[GenerateTypedNameReferences]
public sealed partial class BorgSelectTypeMenu : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private BorgTypePrototype? _selectedBorgType;
public event Action<ProtoId<BorgTypePrototype>>? ConfirmedBorgType;
[ValidatePrototypeId<GuideEntryPrototype>]
private static readonly List<ProtoId<GuideEntryPrototype>> GuidebookEntries = new() { "Cyborgs", "Robotics" };
public BorgSelectTypeMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var group = new ButtonGroup();
foreach (var borgType in _prototypeManager.EnumeratePrototypes<BorgTypePrototype>().OrderBy(PrototypeName))
{
var button = new Button
{
Text = PrototypeName(borgType),
Group = group,
};
button.OnPressed += _ =>
{
_selectedBorgType = borgType;
UpdateInformation(borgType);
};
SelectionsContainer.AddChild(button);
}
ConfirmTypeButton.OnPressed += ConfirmButtonPressed;
HelpGuidebookIds = GuidebookEntries;
}
private void UpdateInformation(BorgTypePrototype prototype)
{
_selectedBorgType = prototype;
InfoContents.Visible = true;
InfoPlaceholder.Visible = false;
ConfirmTypeButton.Disabled = false;
NameLabel.Text = PrototypeName(prototype);
DescriptionLabel.Text = Loc.GetString($"borg-type-{prototype.ID}-desc");
ChassisView.SetPrototype(prototype.DummyPrototype);
}
private void ConfirmButtonPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedBorgType == null)
return;
ConfirmedBorgType?.Invoke(_selectedBorgType);
}
private static string PrototypeName(BorgTypePrototype prototype)
{
return Loc.GetString($"borg-type-{prototype.ID}-name");
}
}

View File

@@ -0,0 +1,30 @@
using Content.Shared.Silicons.Borgs.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// User interface used by borgs to select their type.
/// </summary>
/// <seealso cref="BorgSelectTypeMenu"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
/// <seealso cref="BorgSwitchableTypeUiKey"/>
[UsedImplicitly]
public sealed class BorgSelectTypeUserInterface : BoundUserInterface
{
[ViewVariables]
private BorgSelectTypeMenu? _menu;
public BorgSelectTypeUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = this.CreateWindow<BorgSelectTypeMenu>();
_menu.ConfirmedBorgType += prototype => SendMessage(new BorgSelectTypeMessage(prototype));
}
}

View File

@@ -0,0 +1,81 @@
using Content.Shared.Movement.Components;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Client.GameObjects;
namespace Content.Client.Silicons.Borgs;
/// <summary>
/// Client side logic for borg type switching. Sets up primarily client-side visual information.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
/// <seealso cref="BorgSwitchableTypeComponent"/>
public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
{
[Dependency] private readonly BorgSystem _borgSystem = default!;
[Dependency] private readonly AppearanceSystem _appearance = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BorgSwitchableTypeComponent, AfterAutoHandleStateEvent>(AfterStateHandler);
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentStartup>(OnComponentStartup);
}
private void OnComponentStartup(Entity<BorgSwitchableTypeComponent> ent, ref ComponentStartup args)
{
UpdateEntityAppearance(ent);
}
private void AfterStateHandler(Entity<BorgSwitchableTypeComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateEntityAppearance(ent);
}
protected override void UpdateEntityAppearance(
Entity<BorgSwitchableTypeComponent> entity,
BorgTypePrototype prototype)
{
if (TryComp(entity, out SpriteComponent? sprite))
{
sprite.LayerSetState(BorgVisualLayers.Body, prototype.SpriteBodyState);
sprite.LayerSetState(BorgVisualLayers.LightStatus, prototype.SpriteToggleLightState);
}
if (TryComp(entity, out BorgChassisComponent? chassis))
{
_borgSystem.SetMindStates(
(entity.Owner, chassis),
prototype.SpriteHasMindState,
prototype.SpriteNoMindState);
if (TryComp(entity, out AppearanceComponent? appearance))
{
// Queue update so state changes apply.
_appearance.QueueUpdate(entity, appearance);
}
}
if (prototype.SpriteBodyMovementState is { } movementState)
{
var spriteMovement = EnsureComp<SpriteMovementComponent>(entity);
spriteMovement.NoMovementLayers.Clear();
spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData
{
State = prototype.SpriteBodyState,
};
spriteMovement.MovementLayers.Clear();
spriteMovement.MovementLayers["movement"] = new PrototypeLayerData
{
State = movementState,
};
}
else
{
RemComp<SpriteMovementComponent>(entity);
}
base.UpdateEntityAppearance(entity, prototype);
}
}

View File

@@ -92,4 +92,18 @@ public sealed class BorgSystem : SharedBorgSystem
sprite.LayerSetState(MMIVisualLayers.Base, state);
}
}
/// <summary>
/// Sets the sprite states used for the borg "is there a mind or not" indication.
/// </summary>
/// <param name="borg">The entity and component to modify.</param>
/// <param name="hasMindState">The state to use if the borg has a mind.</param>
/// <param name="noMindState">The state to use if the borg has no mind.</param>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
public void SetMindStates(Entity<BorgChassisComponent> borg, string hasMindState, string noMindState)
{
borg.Comp.HasMindState = hasMindState;
borg.Comp.NoMindState = noMindState;
}
}

View File

@@ -134,4 +134,26 @@ public sealed class InteractionPopupSystem : EntitySystem
component.LastInteractTime = curTime;
}
/// <summary>
/// Sets <see cref="InteractionPopupComponent.InteractSuccessString"/>.
/// </summary>
/// <para>
/// This field is not networked automatically, so this method must be called on both sides of the network.
/// </para>
public void SetInteractSuccessString(Entity<InteractionPopupComponent> ent, string str)
{
ent.Comp.InteractSuccessString = str;
}
/// <summary>
/// Sets <see cref="InteractionPopupComponent.InteractFailureString"/>.
/// </summary>
/// <para>
/// This field is not networked automatically, so this method must be called on both sides of the network.
/// </para>
public void SetInteractFailureString(Entity<InteractionPopupComponent> ent, string str)
{
ent.Comp.InteractFailureString = str;
}
}

View File

@@ -0,0 +1,82 @@
using Content.Server.Inventory;
using Content.Server.Radio.Components;
using Content.Shared.Inventory;
using Content.Shared.Silicons.Borgs;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Server.Silicons.Borgs;
/// <summary>
/// Server-side logic for borg type switching. Handles more heavyweight and server-specific switching logic.
/// </summary>
public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem
{
[Dependency] private readonly BorgSystem _borgSystem = default!;
[Dependency] private readonly ServerInventorySystem _inventorySystem = default!;
protected override void SelectBorgModule(Entity<BorgSwitchableTypeComponent> ent, ProtoId<BorgTypePrototype> borgType)
{
var prototype = Prototypes.Index(borgType);
// Assign radio channels
string[] radioChannels = [.. ent.Comp.InherentRadioChannels, .. prototype.RadioChannels];
if (TryComp(ent, out IntrinsicRadioTransmitterComponent? transmitter))
transmitter.Channels = [.. radioChannels];
if (TryComp(ent, out ActiveRadioComponent? activeRadio))
activeRadio.Channels = [.. radioChannels];
// Borg transponder for the robotics console
if (TryComp(ent, out BorgTransponderComponent? transponder))
{
_borgSystem.SetTransponderSprite(
(ent.Owner, transponder),
new SpriteSpecifier.Rsi(new ResPath("Mobs/Silicon/chassis.rsi"), prototype.SpriteBodyState));
_borgSystem.SetTransponderName(
(ent.Owner, transponder),
Loc.GetString($"borg-type-{borgType}-transponder"));
}
// Configure modules
if (TryComp(ent, out BorgChassisComponent? chassis))
{
var chassisEnt = (ent.Owner, chassis);
_borgSystem.SetMaxModules(
chassisEnt,
prototype.ExtraModuleCount + prototype.DefaultModules.Length);
_borgSystem.SetModuleWhitelist(chassisEnt, prototype.ModuleWhitelist);
foreach (var module in prototype.DefaultModules)
{
var moduleEntity = Spawn(module);
var borgModule = Comp<BorgModuleComponent>(moduleEntity);
_borgSystem.SetBorgModuleDefault((moduleEntity, borgModule), true);
_borgSystem.InsertModule(chassisEnt, moduleEntity);
}
}
// Configure special components
if (Prototypes.TryIndex(ent.Comp.SelectedBorgType, out var previousPrototype))
{
if (previousPrototype.AddComponents is { } removeComponents)
EntityManager.RemoveComponents(ent, removeComponents);
}
if (prototype.AddComponents is { } addComponents)
{
EntityManager.AddComponents(ent, addComponents);
}
// Configure inventory template (used for hat spacing)
if (TryComp(ent, out InventoryComponent? inventory))
{
_inventorySystem.SetTemplateId((ent.Owner, inventory), prototype.InventoryTemplateId);
}
base.SelectBorgModule(ent, borgType);
}
}

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction.Components;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Whitelist;
using Content.Server.Silicons.Borgs.Components;
using Robust.Shared.Containers;
@@ -61,6 +62,10 @@ public sealed partial class BorgSystem
if (_actions.AddAction(chassis, ref component.ModuleSwapActionEntity, out var action, component.ModuleSwapActionId, uid))
{
if(TryComp<BorgModuleIconComponent>(uid, out var moduleIconComp))
{
action.Icon = moduleIconComp.Icon;
};
action.EntityIcon = uid;
Dirty(component.ModuleSwapActionEntity.Value, action);
}
@@ -281,6 +286,41 @@ public sealed partial class BorgSystem
return false;
}
if (TryComp<ItemBorgModuleComponent>(module, out var itemModuleComp))
{
foreach (var containedModuleUid in component.ModuleContainer.ContainedEntities)
{
if (!TryComp<ItemBorgModuleComponent>(containedModuleUid, out var containedItemModuleComp))
continue;
if (containedItemModuleComp.Items.Count == itemModuleComp.Items.Count &&
containedItemModuleComp.Items.All(itemModuleComp.Items.Contains))
{
if (user != null)
Popup.PopupEntity(Loc.GetString("borg-module-duplicate"), uid, user.Value);
return false;
}
}
}
return true;
}
/// <summary>
/// Check if a module can be removed from a borg.
/// </summary>
/// <param name="borg">The borg that the module is being removed from.</param>
/// <param name="module">The module to remove from the borg.</param>
/// <param name="user">The user attempting to remove the module.</param>
/// <returns>True if the module can be removed.</returns>
public bool CanRemoveModule(
Entity<BorgChassisComponent> borg,
Entity<BorgModuleComponent> module,
EntityUid? user = null)
{
if (module.Comp.DefaultModule)
return false;
return true;
}
@@ -353,4 +393,24 @@ public sealed partial class BorgSystem
var ev = new BorgModuleUninstalledEvent(uid);
RaiseLocalEvent(module, ref ev);
}
/// <summary>
/// Sets <see cref="BorgChassisComponent.MaxModules"/>.
/// </summary>
/// <param name="ent">The borg to modify.</param>
/// <param name="maxModules">The new max module count.</param>
public void SetMaxModules(Entity<BorgChassisComponent> ent, int maxModules)
{
ent.Comp.MaxModules = maxModules;
}
/// <summary>
/// Sets <see cref="BorgChassisComponent.ModuleWhitelist"/>.
/// </summary>
/// <param name="ent">The borg to modify.</param>
/// <param name="whitelist">The new module whitelist.</param>
public void SetModuleWhitelist(Entity<BorgChassisComponent> ent, EntityWhitelist? whitelist)
{
ent.Comp.ModuleWhitelist = whitelist;
}
}

View File

@@ -8,6 +8,7 @@ using Content.Server.DeviceNetwork;
using Content.Server.DeviceNetwork.Components;
using Content.Server.DeviceNetwork.Systems;
using Content.Server.Explosion.Components;
using Robust.Shared.Utility;
using Content.Server._Imp.Drone; //Goobstation drone
using Robust.Shared.Player; //Goobstation drone
namespace Content.Server.Silicons.Borgs;
@@ -161,4 +162,20 @@ public sealed partial class BorgSystem
return false;
}
/// <summary>
/// Sets <see cref="BorgTransponderComponent.Sprite"/>.
/// </summary>
public void SetTransponderSprite(Entity<BorgTransponderComponent> ent, SpriteSpecifier sprite)
{
ent.Comp.Sprite = sprite;
}
/// <summary>
/// Sets <see cref="BorgTransponderComponent.Name"/>.
/// </summary>
public void SetTransponderName(Entity<BorgTransponderComponent> ent, string name)
{
ent.Comp.Name = name;
}
}

View File

@@ -82,6 +82,9 @@ public sealed partial class BorgSystem
if (!component.ModuleContainer.Contains(module))
return;
if (!CanRemoveModule((uid, component), (module, Comp<BorgModuleComponent>(module)), args.Actor))
return;
_adminLog.Add(LogType.Action, LogImpact.Medium,
$"{ToPrettyString(args.Actor):player} removed module {ToPrettyString(module)} from borg {ToPrettyString(uid)}");
_container.Remove(module, component.ModuleContainer);

View File

@@ -130,7 +130,7 @@ public sealed partial class BorgSystem : SharedBorgSystem
if (module != null && CanInsertModule(uid, used, component, module, args.User))
{
_container.Insert(used, component.ModuleContainer);
InsertModule((uid, component), used);
_adminLog.Add(LogType.Action, LogImpact.Low,
$"{ToPrettyString(args.User):player} installed module {ToPrettyString(used)} into borg {ToPrettyString(uid)}");
args.Handled = true;
@@ -138,6 +138,19 @@ public sealed partial class BorgSystem : SharedBorgSystem
}
}
/// <summary>
/// Inserts a new module into a borg, the same as if a player inserted it manually.
/// </summary>
/// <para>
/// This does not run checks to see if the borg is actually allowed to be inserted, such as whitelists.
/// </para>
/// <param name="ent">The borg to insert into.</param>
/// <param name="module">The module to insert.</param>
public void InsertModule(Entity<BorgChassisComponent> ent, EntityUid module)
{
_container.Insert(module, ent.Comp.ModuleContainer);
}
// todo: consider transferring over the ghost role? managing that might suck.
protected override void OnInserted(EntityUid uid, BorgChassisComponent component, EntInsertedIntoContainerMessage args)
{

View File

@@ -7,10 +7,12 @@ namespace Content.Shared.Inventory;
[RegisterComponent, NetworkedComponent]
[Access(typeof(InventorySystem))]
[AutoGenerateComponentState(true)]
public sealed partial class InventoryComponent : Component
{
[DataField("templateId", customTypeSerializer: typeof(PrototypeIdSerializer<InventoryTemplatePrototype>))]
public string TemplateId { get; private set; } = "human";
[AutoNetworkedField]
public string TemplateId { get; set; } = "human";
[DataField("speciesId")] public string? SpeciesId { get; set; }
@@ -33,3 +35,9 @@ public sealed partial class InventoryComponent : Component
[DataField]
public Dictionary<string, DisplacementData> MaleDisplacements = new();
}
/// <summary>
/// Raised if the <see cref="InventoryComponent.TemplateId"/> of an inventory changed.
/// </summary>
[ByRefEvent]
public struct InventoryTemplateUpdated;

View File

@@ -24,6 +24,8 @@ public partial class InventorySystem : EntitySystem
_vvm.GetTypeHandler<InventoryComponent>()
.AddHandler(HandleViewVariablesSlots, ListViewVariablesSlots);
SubscribeLocalEvent<InventoryComponent, AfterAutoHandleStateEvent>(AfterAutoState);
}
private void ShutdownSlots()
@@ -73,6 +75,27 @@ public partial class InventorySystem : EntitySystem
}
}
private void AfterAutoState(Entity<InventoryComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateInventoryTemplate(ent);
}
protected virtual void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
if (ent.Comp.LifeStage < ComponentLifeStage.Initialized)
return;
if (!_prototypeManager.TryIndex(ent.Comp.TemplateId, out InventoryTemplatePrototype? invTemplate))
return;
DebugTools.Assert(ent.Comp.Slots.Length == invTemplate.Slots.Length);
ent.Comp.Slots = invTemplate.Slots;
var ev = new InventoryTemplateUpdated();
RaiseLocalEvent(ent, ref ev);
}
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { Valid: true } uid)
@@ -176,6 +199,31 @@ public partial class InventorySystem : EntitySystem
}
/// <summary>
/// Change the inventory template ID an entity is using. The new template must be compatible.
/// </summary>
/// <remarks>
/// <para>
/// For an inventory template to be compatible with another, it must have exactly the same slot names.
/// All other changes are rejected.
/// </para>
/// </remarks>
/// <param name="ent">The entity to update.</param>
/// <param name="newTemplate">The ID of the new inventory template prototype.</param>
/// <exception cref="ArgumentException">
/// Thrown if the new template is not compatible with the existing one.
/// </exception>
public void SetTemplateId(Entity<InventoryComponent> ent, ProtoId<InventoryTemplatePrototype> newTemplate)
{
var newPrototype = _prototypeManager.Index(newTemplate);
if (!newPrototype.Slots.Select(x => x.Name).SequenceEqual(ent.Comp.Slots.Select(x => x.Name)))
throw new ArgumentException("Incompatible inventory template!");
ent.Comp.TemplateId = newTemplate;
Dirty(ent);
}
/// <summary>
/// Enumerator for iterating over an inventory's slot containers. Also has methods that skip empty containers.
/// It should be safe to add or remove items while enumerating.

View File

@@ -0,0 +1,155 @@
using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.Radio;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Borgs;
/// <summary>
/// Information for a borg type that can be selected by <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
[Prototype]
public sealed partial class BorgTypePrototype : IPrototype
{
[ValidatePrototypeId<SoundCollectionPrototype>]
private static readonly ProtoId<SoundCollectionPrototype> DefaultFootsteps = new("FootstepBorg");
[IdDataField]
public required string ID { get; init; }
//
// Description info (name/desc) is configured via localization strings directly.
//
/// <summary>
/// The prototype displayed in the selection menu for this type.
/// </summary>
[DataField]
public required EntProtoId DummyPrototype { get; init; }
//
// Functional information
//
/// <summary>
/// The amount of free module slots this borg type has.
/// </summary>
/// <remarks>
/// This count is on top of the modules specified in <see cref="DefaultModules"/>.
/// </remarks>
/// <seealso cref="BorgChassisComponent.ModuleCount"/>
[DataField]
public int ExtraModuleCount { get; set; } = 0;
/// <summary>
/// The whitelist for borg modules that can be inserted into this borg type.
/// </summary>
/// <seealso cref="BorgChassisComponent.ModuleWhitelist"/>
[DataField]
public EntityWhitelist? ModuleWhitelist { get; set; }
/// <summary>
/// Inventory template used by this borg.
/// </summary>
/// <remarks>
/// This template must be compatible with the normal borg templates,
/// so in practice it can only be used to differentiate the visual position of the slots on the character sprites.
/// </remarks>
/// <seealso cref="InventorySystem.SetTemplateId"/>
[DataField]
public ProtoId<InventoryTemplatePrototype> InventoryTemplateId { get; set; } = "borgShort";
/// <summary>
/// Radio channels that this borg will gain access to from this module.
/// </summary>
/// <remarks>
/// These channels are provided on top of the ones specified in
/// <see cref="BorgSwitchableTypeComponent.InherentRadioChannels"/>.
/// </remarks>
[DataField]
public ProtoId<RadioChannelPrototype>[] RadioChannels = [];
/// <summary>
/// Borg module types that are always available to borgs of this type.
/// </summary>
/// <remarks>
/// These modules still work like modules, although they cannot be removed from the borg.
/// </remarks>
/// <seealso cref="BorgModuleComponent.DefaultModule"/>
[DataField]
public EntProtoId[] DefaultModules = [];
/// <summary>
/// Additional components to add to the borg entity when this type is selected.
/// </summary>
[DataField]
public ComponentRegistry? AddComponents { get; set; }
//
// Visual information
//
/// <summary>
/// The sprite state for the main borg body.
/// </summary>
[DataField]
public string SpriteBodyState { get; set; } = "robot";
/// <summary>
/// An optional movement sprite state for the main borg body.
/// </summary>
[DataField]
public string? SpriteBodyMovementState { get; set; }
/// <summary>
/// Sprite state used to indicate that the borg has a mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
[DataField]
public string SpriteHasMindState { get; set; } = "robot_e";
/// <summary>
/// Sprite state used to indicate that the borg has no mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
[DataField]
public string SpriteNoMindState { get; set; } = "robot_e_r";
/// <summary>
/// Sprite state used when the borg's flashlight is on.
/// </summary>
[DataField]
public string SpriteToggleLightState { get; set; } = "robot_l";
//
// Minor information
//
/// <summary>
/// String to use on petting success.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetSuccessString { get; set; } = "petting-success-generic-cyborg";
/// <summary>
/// String to use on petting failure.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetFailureString { get; set; } = "petting-failure-generic-cyborg";
//
// Sounds
//
/// <summary>
/// Sound specifier for footstep sounds created by this borg.
/// </summary>
[DataField]
public SoundSpecifier FootstepCollection { get; set; } = new SoundCollectionSpecifier(DefaultFootsteps);
}

View File

@@ -89,5 +89,18 @@ public enum BorgVisuals : byte
[Serializable, NetSerializable]
public enum BorgVisualLayers : byte
{
Light
/// <summary>
/// Main borg body layer.
/// </summary>
Body,
/// <summary>
/// Layer for the borg's mind state.
/// </summary>
Light,
/// <summary>
/// Layer for the borg flashlight status.
/// </summary>
LightStatus,
}

View File

@@ -7,6 +7,7 @@ namespace Content.Shared.Silicons.Borgs.Components;
/// to give them unique abilities and attributes.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))]
[AutoGenerateComponentState]
public sealed partial class BorgModuleComponent : Component
{
/// <summary>
@@ -16,6 +17,13 @@ public sealed partial class BorgModuleComponent : Component
public EntityUid? InstalledEntity;
public bool Installed => InstalledEntity != null;
/// <summary>
/// If true, this is a "default" module that cannot be removed from a borg.
/// </summary>
[DataField]
[AutoNetworkedField]
public bool DefaultModule;
}
/// <summary>

View File

@@ -0,0 +1,72 @@
using Content.Shared.Actions;
using Content.Shared.Radio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Silicons.Borgs.Components;
/// <summary>
/// Component for borgs that can switch their "type" after being created.
/// </summary>
/// <remarks>
/// <para>
/// This is used by all NT borgs, on construction and round-start spawn.
/// Borgs are effectively useless until they have made their choice of type.
/// Borg type selections are currently irreversible.
/// </para>
/// <para>
/// Available types are specified in <see cref="BorgTypePrototype"/>s.
/// </para>
/// </remarks>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(raiseAfterAutoHandleState: true)]
[Access(typeof(SharedBorgSwitchableTypeSystem))]
public sealed partial class BorgSwitchableTypeComponent : Component
{
/// <summary>
/// Action entity used by players to select their type.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? SelectTypeAction;
/// <summary>
/// The currently selected borg type, if any.
/// </summary>
/// <remarks>
/// This can be set in a prototype to immediately apply a borg type, and not have switching support.
/// </remarks>
[DataField, AutoNetworkedField]
public ProtoId<BorgTypePrototype>? SelectedBorgType;
/// <summary>
/// Radio channels that the borg will always have. These are added on top of the selected type's radio channels.
/// </summary>
[DataField]
public ProtoId<RadioChannelPrototype>[] InherentRadioChannels = [];
}
/// <summary>
/// Action event used to open the selection menu of a <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
public sealed partial class BorgToggleSelectTypeEvent : InstantActionEvent;
/// <summary>
/// UI message used by a borg to select their type with <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
/// <param name="prototype">The borg type prototype that the user selected.</param>
[Serializable, NetSerializable]
public sealed class BorgSelectTypeMessage(ProtoId<BorgTypePrototype> prototype) : BoundUserInterfaceMessage
{
public ProtoId<BorgTypePrototype> Prototype = prototype;
}
/// <summary>
/// UI key used by the selection menu for <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
[NetSerializable, Serializable]
public enum BorgSwitchableTypeUiKey : byte
{
SelectBorgType,
}

View File

@@ -0,0 +1,125 @@
using Content.Shared.Actions;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Borgs;
/// <summary>
/// Implements borg type switching.
/// </summary>
/// <seealso cref="BorgSwitchableTypeComponent"/>
public abstract class SharedBorgSwitchableTypeSystem : EntitySystem
{
// TODO: Allow borgs to be reset to default configuration.
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
[Dependency] protected readonly IPrototypeManager Prototypes = default!;
[Dependency] private readonly InteractionPopupSystem _interactionPopup = default!;
[ValidatePrototypeId<EntityPrototype>]
public const string ActionId = "ActionSelectBorgType";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BorgSwitchableTypeComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<BorgSwitchableTypeComponent, BorgToggleSelectTypeEvent>(OnSelectBorgTypeAction);
Subs.BuiEvents<BorgSwitchableTypeComponent>(BorgSwitchableTypeUiKey.SelectBorgType,
sub =>
{
sub.Event<BorgSelectTypeMessage>(SelectTypeMessageHandler);
});
}
//
// UI-adjacent code
//
private void OnMapInit(Entity<BorgSwitchableTypeComponent> ent, ref MapInitEvent args)
{
_actionsSystem.AddAction(ent, ref ent.Comp.SelectTypeAction, ActionId);
Dirty(ent);
if (ent.Comp.SelectedBorgType != null)
{
SelectBorgModule(ent, ent.Comp.SelectedBorgType.Value);
}
}
private void OnShutdown(Entity<BorgSwitchableTypeComponent> ent, ref ComponentShutdown args)
{
_actionsSystem.RemoveAction(ent, ent.Comp.SelectTypeAction);
}
private void OnSelectBorgTypeAction(Entity<BorgSwitchableTypeComponent> ent, ref BorgToggleSelectTypeEvent args)
{
if (args.Handled || !TryComp<ActorComponent>(ent, out var actor))
return;
args.Handled = true;
_userInterface.TryToggleUi((ent.Owner, null), BorgSwitchableTypeUiKey.SelectBorgType, actor.PlayerSession);
}
private void SelectTypeMessageHandler(Entity<BorgSwitchableTypeComponent> ent, ref BorgSelectTypeMessage args)
{
if (ent.Comp.SelectedBorgType != null)
return;
if (!Prototypes.HasIndex(args.Prototype))
return;
SelectBorgModule(ent, args.Prototype);
}
//
// Implementation
//
protected virtual void SelectBorgModule(
Entity<BorgSwitchableTypeComponent> ent,
ProtoId<BorgTypePrototype> borgType)
{
ent.Comp.SelectedBorgType = borgType;
_actionsSystem.RemoveAction(ent, ent.Comp.SelectTypeAction);
ent.Comp.SelectTypeAction = null;
Dirty(ent);
_userInterface.CloseUi((ent.Owner, null), BorgSwitchableTypeUiKey.SelectBorgType);
UpdateEntityAppearance(ent);
}
protected void UpdateEntityAppearance(Entity<BorgSwitchableTypeComponent> entity)
{
if (!Prototypes.TryIndex(entity.Comp.SelectedBorgType, out var proto))
return;
UpdateEntityAppearance(entity, proto);
}
protected virtual void UpdateEntityAppearance(
Entity<BorgSwitchableTypeComponent> entity,
BorgTypePrototype prototype)
{
if (TryComp(entity, out InteractionPopupComponent? popup))
{
_interactionPopup.SetInteractSuccessString((entity.Owner, popup), prototype.PetSuccessString);
_interactionPopup.SetInteractFailureString((entity.Owner, popup), prototype.PetFailureString);
}
if (TryComp(entity, out FootstepModifierComponent? footstepModifier))
{
footstepModifier.FootstepSoundCollection = prototype.FootstepCollection;
}
}
}

View File

@@ -124,4 +124,13 @@ public abstract partial class SharedBorgSystem : EntitySystem
var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed;
args.ModifySpeed(1f, sprintDif);
}
/// <summary>
/// Sets <see cref="BorgModuleComponent.DefaultModule"/>.
/// </summary>
public void SetBorgModuleDefault(Entity<BorgModuleComponent> ent, bool newDefault)
{
ent.Comp.DefaultModule = newDefault;
Dirty(ent);
}
}

View File

@@ -24,3 +24,40 @@ borg-transponder-disabling-popup = Your transponder begins to lock you out of th
borg-transponder-destroying-popup = The self destruct of {$name} starts beeping!
borg-transponder-emagged-disabled-popup = Your transponder's lights go out!
borg-transponder-emagged-destroyed-popup = Your transponder's fuse blows!
## Borg type selection UI.
borg-select-type-menu-title = Select Chassis Type
borg-select-type-menu-bottom-text = Chassis selection is irreversible
borg-select-type-menu-available = Available types
borg-select-type-menu-information = Information
borg-select-type-menu-select-type = Select type to view information
borg-select-type-menu-confirm = Confirm selection
borg-select-type-menu-guidebook = Guidebook
## Borg type information
borg-type-generic-name = Generic
borg-type-generic-desc = Jack of all trades, master of none. Do various random station tasks, or maybe help out the science department that built you.
borg-type-generic-transponder = generic cyborg
borg-type-engineering-name = Engineering
borg-type-engineering-desc = Assist the engineering team in station construction, repairing damage, or fixing electrical and atmospheric issues.
borg-type-engineering-transponder = engineering cyborg
borg-type-mining-name = Salvage
borg-type-mining-desc = Join salvage and help them mine for materials, scavenge wrecks, and fight off hostile wildlife.
borg-type-mining-transponder = salvage cyborg
borg-type-janitor-name = Janitor
borg-type-janitor-desc = Keep the station nice and tidy, clean up spills, collect and properly dispose of trash left around by lazy crewmembers.
borg-type-janitor-transponder = janitor cyborg
borg-type-medical-name = Medical
borg-type-medical-desc = Provide medical attention to crew who need it, either in medbay or in hazardous areas conventional paramedics cannot reach.
borg-type-medical-transponder = medical cyborg
borg-type-service-name = Service
borg-type-service-desc = Help out with a wide range of crew services, ranging from serving snacks and drinks to botany to entertainment.
borg-type-service-transponder = service cyborg

View File

@@ -305,6 +305,41 @@ FoodMeatHawaiianKebab: FoodKebabSkewer
FoodMeatKebab: FoodKebabSkewer
FoodMeatFiestaKebab: FoodKebabSkewer
# 2024-10-09
# Removal of separate borg chassis parts, replace them with generic borg parts.
LeftArmBorgEngineer: LeftArmBorg
RightArmBorgEngineer: RightArmBorg
LeftLegBorgEngineer: LeftLegBorg
RightLegBorgEngineer: RightLegBorg
HeadBorgEngineer: LightHeadBorg
TorsoBorgEngineer: TorsoBorg
LeftArmBorgMedical: LeftArmBorg
RightArmBorgMedical: RightArmBorg
LeftLegBorgMedical: LeftLegBorg
RightLegBorgMedical: RightLegBorg
HeadBorgMedical: LightHeadBorg
TorsoBorgMedical: TorsoBorg
LeftArmBorgMining: LeftArmBorg
RightArmBorgMining: RightArmBorg
LeftLegBorgMining: LeftLegBorg
RightLegBorgMining: RightLegBorg
HeadBorgMining: LightHeadBorg
TorsoBorgMining: TorsoBorg
LeftArmBorgService: LeftArmBorg
RightArmBorgService: RightArmBorg
LeftLegBorgService: LeftLegBorg
RightLegBorgService: RightLegBorg
HeadBorgService: LightHeadBorg
TorsoBorgService: TorsoBorg
LeftLegBorgJanitor: LeftLegBorg
RightLegBorgJanitor: RightLegBorg
HeadBorgJanitor: LightHeadBorg
TorsoBorgJanitor: TorsoBorg
# 2024-03-11
ImprovisedExplosive: FireBomb
ImprovisedExplosiveEmpty: FireBombEmpty

View File

@@ -11,3 +11,15 @@
state: state-laws
event: !type:ToggleLawsScreenEvent
useDelay: 0.5
- type: entity
id: ActionSelectBorgType
name: Select Cyborg Type
components:
- type: InstantAction
itemIconStyle: NoItem
icon:
sprite: Interface/Actions/actions_borg.rsi
state: select-type
event: !type:BorgToggleSelectTypeEvent
useDelay: 0.5

View File

@@ -35,14 +35,17 @@
# Shitmed Change End
- type: entity
id: BaseBorgArmLeft
id: LeftArmBorg
parent: PartSilicon
name: left cyborg arm
abstract: true
name: cyborg left arm
components:
- type: BodyPart
partType: Arm # Shitmed Change
symmetry: Left
- type: Sprite
state: borg_l_arm
- type: Icon
state: borg_l_arm
toolName: "a left arm" # Shitmed Change
children: # Shitmed Change
left hand:
@@ -52,16 +55,20 @@
tags:
- Trash
- BorgArm
- BorgLArm
- type: entity
id: BaseBorgArmRight
id: RightArmBorg
parent: PartSilicon
name: right cyborg arm
abstract: true
name: cyborg right arm
components:
- type: BodyPart
partType: Arm # Shitmed Change
symmetry: Right
- type: Sprite
state: borg_r_arm
- type: Icon
state: borg_r_arm
toolName: "a right arm" # Shitmed Change
children: # Shitmed Change
right hand:
@@ -71,16 +78,20 @@
tags:
- Trash
- BorgArm
- BorgRArm
- type: entity
id: BaseBorgLegLeft
id: LeftLegBorg
parent: PartSilicon
name: left cyborg leg
abstract: true
name: cyborg left leg
components:
- type: BodyPart
partType: Leg
symmetry: Left
- type: Sprite
state: borg_l_leg
- type: Icon
state: borg_l_leg
toolName: "a left leg" # Shitmed Change
children: # Shitmed Change
left foot:
@@ -90,17 +101,21 @@
tags:
- Trash
- BorgLeg
- BorgLLeg
- type: MovementBodyPart
- type: entity
id: BaseBorgLegRight
id: RightLegBorg
parent: PartSilicon
name: right cyborg leg
abstract: true
name: cyborg right leg
components:
- type: BodyPart
partType: Leg
symmetry: Right
- type: Sprite
state: borg_r_leg
- type: Icon
state: borg_r_leg
toolName: "a right leg" # Shitmed Change
children: # Shitmed Change
right foot:
@@ -110,16 +125,20 @@
tags:
- Trash
- BorgLeg
- BorgRLeg
- type: MovementBodyPart
- type: entity
id: BaseBorgHead
id: LightHeadBorg
parent: PartSilicon
name: cyborg head
abstract: true
components:
- type: BodyPart
partType: Head
- type: Sprite
state: borg_head
- type: Icon
state: borg_head
toolName: "a head" # Shitmed Change
- type: Tag
tags:
@@ -127,14 +146,18 @@
- BorgHead
- type: entity
id: BaseBorgTorso
id: TorsoBorg
parent: PartSilicon
name: cyborg torso
abstract: true
components:
- type: BodyPart
partType: Torso
- type: Sprite
state: borg_chest
- type: Icon
state: borg_chest
toolName: "a torso" # Shitmed Change
- type: Tag
tags:
- Trash
- BorgTorso

View File

@@ -1,5 +1,5 @@
- type: entity
parent: BaseMob
parent: [BaseMob, StripableInventoryBase]
id: BaseBorgChassis
name: cyborg
description: A man-machine hybrid that assists in station activity. They love being asked to state their laws over and over.
@@ -69,6 +69,9 @@
type: BorgBoundUserInterface
enum.StrippingUiKey.Key:
type: StrippableBoundUserInterface
# Only used for NT borgs that can switch type, defined here to avoid copy-pasting the rest of this component.
enum.BorgSwitchableTypeUiKey.SelectBorgType:
type: BorgSelectTypeUserInterface
- type: ActivatableUI
key: enum.BorgUiKey.Key
- type: SiliconLawBound
@@ -80,14 +83,12 @@
- type: SiliconLawProvider
laws: Asimov
- type: IonStormTarget
- type: Strippable
- type: StationAiVision
- type: InventorySlots
- type: Inventory
templateId: borg
- type: Hands
showInHands: false
disableExplosionRecursion: true
canBeStripped: false
- type: ComplexInteraction
- type: IntrinsicRadioReceiver
- type: IntrinsicRadioTransmitter
@@ -105,6 +106,11 @@
doAfterDelay: 10
allowSelfRepair: false
- type: BorgChassis
- type: LockingWhitelist
blacklist:
components:
- BorgChassis
- RoboticsConsole
- type: WiresPanel
- type: ActivatableUIRequiresPanel
- type: NameIdentifier
@@ -119,7 +125,10 @@
cellSlotId: cell_slot
fitsInCharger: true
- type: ItemToggle
onActivate: false # You should not be able to turn off a borg temporarily.
activated: false # gets activated when a mind is added
onUse: false # no item-borg toggling sorry
- type: ItemTogglePointLight
- type: AccessToggle
# TODO: refactor movement to just be based on toggle like speedboots but for the boots themselves
# TODO: or just have sentient speedboots be fast idk
@@ -137,6 +146,7 @@
- Stun
- KnockedDown
- SlowedDown
- Flashed
- type: TypingIndicator
proto: robot
- type: Speech
@@ -151,14 +161,16 @@
collection: FootstepBorg
- type: Construction
graph: Cyborg
node: cyborg
containers:
- part-container
- cell_slot
- type: Lock
locked: true
breakOnEmag: false
unlockOnClick: false
- type: ActivatableUIRequiresLock
- type: LockedWiresPanel
- type: Flashable
- type: Damageable
damageContainer: Silicon
- type: Destructible
@@ -294,6 +306,9 @@
access: [["Command"], ["Research"]]
- type: ShowJobIcons
- type: ShowMindShieldIcons
- type: InteractionPopup
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: entity
id: BaseBorgChassisSyndicate
@@ -327,3 +342,5 @@
- type: Vocal
sounds:
Unsexed: UnisexSiliconSyndicate
- type: PointLight
color: "#dd200b"

View File

@@ -1,23 +1,22 @@
- type: entity
id: BorgChassisGeneric
id: BorgChassisSelectable
parent: BaseBorgChassisNT
components:
- type: Sprite
layers:
- state: robot
map: ["enum.BorgVisualLayers.Body", "movement"]
- state: robot_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: robot_l
shader: unshaded
map: ["light"]
map: ["light","enum.BorgVisualLayers.LightStatus"]
visible: false
- type: BorgChassis
maxModules: 6
moduleWhitelist:
tags:
- BorgModuleGeneric
# Default borg can take no modules until selected type.
maxModules: 0
hasMindState: robot_e
noMindState: robot_e_r
- type: BorgTransponder
@@ -25,295 +24,62 @@
sprite: Mobs/Silicon/chassis.rsi
state: robot
name: cyborg
- type: Construction
node: cyborg
- type: Speech
speechVerb: Robotic
- type: InteractionPopup
interactSuccessString: petting-success-generic-cyborg
interactFailureString: petting-failure-generic-cyborg
- type: BorgSwitchableType
inherentRadioChannels:
- Common
- Binary
- type: entity
id: BorgChassisGeneric
parent: BorgChassisSelectable
name: generic cyborg
suffix: type picked
components:
- type: BorgSwitchableType
selectedBorgType: generic
- type: entity
id: BorgChassisMining
parent: BaseBorgChassisNT
parent: BorgChassisSelectable
name: salvage cyborg
components:
- type: Sprite
layers:
- state: miner
map: ["movement"]
- state: miner_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: miner_l
shader: unshaded
map: ["light"]
visible: false
- type: SpriteMovement
movementLayers:
movement:
state: miner_moving
noMovementLayers:
movement:
state: miner
- type: BorgChassis
maxModules: 4
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleCargo
hasMindState: miner_e
noMindState: miner_e_r
- type: BorgTransponder
sprite:
sprite: Mobs/Silicon/chassis.rsi
state: miner
name: salvage cyborg
- type: Construction
node: mining
- type: IntrinsicRadioTransmitter
channels:
- Supply
- Binary
- Common
- Science
- type: ActiveRadio
channels:
- Supply
- Binary
- Common
- Science
- type: AccessReader
access: [["Cargo"], ["Salvage"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgTall
- type: BorgSwitchableType
selectedBorgType: mining
- type: entity
id: BorgChassisEngineer
parent: BaseBorgChassisNT
parent: BorgChassisSelectable
name: engineer cyborg
components:
- type: Sprite
layers:
- state: engineer
- state: engineer_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: engineer_l
shader: unshaded
map: ["light"]
visible: false
- type: BorgChassis
maxModules: 4
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleEngineering
hasMindState: engineer_e
noMindState: engineer_e_r
- type: BorgTransponder
sprite:
sprite: Mobs/Silicon/chassis.rsi
state: engineer
name: engineer cyborg
- type: Construction
node: engineer
- type: IntrinsicRadioTransmitter
channels:
- Engineering
- Binary
- Common
- Science
- type: ActiveRadio
channels:
- Engineering
- Binary
- Common
- Science
- type: AccessReader
access: [["Engineering"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgShort
- type: SiliconLawProvider # Delta-V - Adds custom lawset for Engineering Cyborg
laws: Engineer
- type: BorgSwitchableType
selectedBorgType: engineering
- type: entity
id: BorgChassisJanitor
parent: BaseBorgChassisNT
parent: BorgChassisSelectable
name: janitor cyborg
components:
- type: Sprite
layers:
- state: janitor
map: ["movement"]
- state: janitor_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: janitor_l
shader: unshaded
map: ["light"]
visible: false
- type: SpriteMovement
movementLayers:
movement:
state: janitor_moving
noMovementLayers:
movement:
state: janitor
- type: BorgChassis
maxModules: 4
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleJanitor
hasMindState: janitor_e
noMindState: janitor_e_r
- type: BorgTransponder
sprite:
sprite: Mobs/Silicon/chassis.rsi
state: janitor
name: janitor cyborg
- type: Construction
node: janitor
- type: IntrinsicRadioTransmitter
channels:
- Service
- Binary
- Common
- Science
- type: ActiveRadio
channels:
- Service
- Binary
- Common
- Science
- type: AccessReader
access: [["Service"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgShort
- type: SiliconLawProvider # Delta-V Adds custom lawset for Janitor Cyborg
laws: Janitor
- type: BorgSwitchableType
selectedBorgType: janitor
- type: entity
id: BorgChassisMedical
parent: BaseBorgChassisNT
parent: BorgChassisSelectable
name: medical cyborg
components:
- type: Sprite
layers:
- state: medical
map: ["movement"]
- state: medical_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: medical_l
shader: unshaded
map: ["light"]
visible: false
- type: SpriteMovement
movementLayers:
movement:
state: medical_moving
noMovementLayers:
movement:
state: medical
- type: BorgChassis
maxModules: 4
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleMedical
hasMindState: medical_e
noMindState: medical_e_r
- type: BorgTransponder
sprite:
sprite: Mobs/Silicon/chassis.rsi
state: medical
name: medical cyborg
- type: Construction
node: medical
- type: IntrinsicRadioTransmitter
channels:
- Medical
- Binary
- Common
- Science
- type: ActiveRadio
channels:
- Medical
- Binary
- Common
- Science
- type: AccessReader
access: [["Medical"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgDutch
- type: FootstepModifier
footstepSoundCollection:
collection: FootstepHoverBorg
- type: FabricateActions
actions:
- ActionFabricateLollipop
- ActionFabricateGumball
- type: SiliconLawProvider
laws: Medical
- type: SurgeryTarget # Shitmed
- type: Sanitized # Shitmed
- type: SolutionScanner
- type: InteractionPopup
interactSuccessString: petting-success-medical-cyborg
interactFailureString: petting-failure-medical-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: BorgSwitchableType
selectedBorgType: medical
- type: entity
id: BorgChassisService
parent: BaseBorgChassisNT
parent: BorgChassisSelectable
name: service cyborg
components:
- type: Sprite
layers:
- state: service
- state: service_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: service_l
shader: unshaded
map: ["light"]
visible: false
- type: BorgChassis
maxModules: 4
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleService
hasMindState: service_e
noMindState: service_e_r
- type: BorgTransponder
sprite:
sprite: Mobs/Silicon/chassis.rsi
state: service
name: service cyborg
- type: Construction
node: service
- type: IntrinsicRadioTransmitter
channels:
- Service
- Binary
- Common
- Science
- type: ActiveRadio
channels:
- Service
- Binary
- Common
- Science
- type: AccessReader
access: [["Service"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgTall
- type: BorgSwitchableType
selectedBorgType: service
- type: entity
id: BorgChassisSyndicateAssault
@@ -332,8 +98,6 @@
shader: unshaded
map: ["light"]
visible: false
- type: PointLight
color: "#dd200b"
- type: BorgChassis
maxModules: 3
moduleWhitelist:
@@ -343,8 +107,11 @@
- BorgModuleSyndicateAssault
hasMindState: synd_sec_e
noMindState: synd_sec
- type: Construction
node: syndicateassault
- type: InteractionPopup
interactSuccessString: petting-success-syndicate-cyborg
interactFailureString: petting-failure-syndicate-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: entity
id: BorgChassisSyndicateMedical
@@ -372,8 +139,18 @@
- BorgModuleSyndicate
hasMindState: synd_medical_e
noMindState: synd_medical
- type: Construction
node: syndicatemedical
- type: ShowHealthBars
- type: InteractionPopup
interactSuccessString: petting-success-syndicate-cyborg
interactFailureString: petting-failure-syndicate-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: SolutionScanner
- type: FootstepModifier
footstepSoundCollection:
collection: FootstepHoverBorg
params:
volume: -6
- type: entity
id: BorgChassisSyndicateSaboteur
@@ -401,5 +178,12 @@
- BorgModuleSyndicate
hasMindState: synd_engi_e
noMindState: synd_engi
- type: Construction
node: syndicatesaboteur
- type: ShowHealthBars
damageContainers:
- Inorganic
- Silicon
- type: InteractionPopup
interactSuccessString: petting-success-syndicate-cyborg
interactFailureString: petting-failure-syndicate-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg

View File

@@ -733,44 +733,21 @@
range: 20
# Borgs
- type: entity
id: PlayerBorgGeneric
parent: BorgChassisGeneric
suffix: Battery, Tools
components:
- type: StationAiVision
- type: ContainerFill
containers:
borg_brain:
- PositronicBrain
borg_module:
- BorgModuleTool
- type: ItemSlots
slots:
cell_slot:
name: power-cell-slot-component-slot-name-default
startingItem: PowerCellMedium
- type: RandomMetadata
nameSegments: [names_borg]
- type: entity
id: PlayerBorgBattery
parent: BorgChassisGeneric
parent: BorgChassisSelectable
suffix: Battery
components:
- type: StationAiVision
- type: ContainerFill
containers:
borg_brain:
- MMIFilled
- PositronicBrain
- type: ItemSlots
slots:
cell_slot:
name: power-cell-slot-component-slot-name-default
startingItem: PowerCellMedium
- type: StartingMindRole
mindRole: "MindRoleSiliconBrain"
silent: true
- type: entity
id: PlayerBorgSyndicateAssaultBattery

View File

@@ -1,503 +0,0 @@
# generic parts
- type: entity
id: LeftArmBorg
parent: BaseBorgArmLeft
components:
- type: Sprite
state: borg_l_arm
- type: Icon
state: borg_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgGenericLArm
- type: entity
id: RightArmBorg
parent: BaseBorgArmRight
components:
- type: Sprite
state: borg_r_arm
- type: Icon
state: borg_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgGenericRArm
- type: entity
id: LeftLegBorg
parent: BaseBorgLegLeft
components:
- type: Sprite
state: borg_l_leg
- type: Icon
state: borg_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgGenericLLeg
- type: entity
id: RightLegBorg
parent: BaseBorgLegRight
components:
- type: Sprite
state: borg_r_leg
- type: Icon
state: borg_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgGenericRLeg
- type: entity
id: LightHeadBorg
parent: BaseBorgHead
components:
- type: Sprite
state: borg_head
- type: Icon
state: borg_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgGenericHead
- type: entity
id: TorsoBorg
parent: BaseBorgTorso
components:
- type: Sprite
state: borg_chest
- type: Icon
state: borg_chest
- type: Tag
tags:
- Trash
- BorgGenericTorso
# engineer parts
- type: entity
id: LeftArmBorgEngineer
parent: BaseBorgArmLeft
name: engineer cyborg left arm
components:
- type: Sprite
state: engineer_l_arm
- type: Icon
state: engineer_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgEngineerLArm
- type: entity
id: RightArmBorgEngineer
parent: BaseBorgArmRight
name: engineer cyborg right arm
components:
- type: Sprite
state: engineer_r_arm
- type: Icon
state: engineer_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgEngineerRArm
- type: entity
id: LeftLegBorgEngineer
parent: BaseBorgLegLeft
name: engineer cyborg left leg
components:
- type: Sprite
state: engineer_l_leg
- type: Icon
state: engineer_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgEngineerLLeg
- type: entity
id: RightLegBorgEngineer
parent: BaseBorgLegRight
name: engineer cyborg right leg
components:
- type: Sprite
state: engineer_r_leg
- type: Icon
state: engineer_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgEngineerRLeg
- type: entity
id: HeadBorgEngineer
parent: BaseBorgHead
name: engineer cyborg head
components:
- type: Sprite
state: engineer_head
- type: Icon
state: engineer_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgEngineerHead
- type: entity
id: TorsoBorgEngineer
parent: BaseBorgTorso
name: engineer cyborg torso
components:
- type: Sprite
state: engineer_chest
- type: Icon
state: engineer_chest
- type: Tag
tags:
- Trash
- BorgEngineerTorso
# janitor parts
- type: entity
id: LeftLegBorgJanitor
parent: BaseBorgLegLeft
name: janitor cyborg left leg
components:
- type: Sprite
state: janitor_l_leg
- type: Icon
state: janitor_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgJanitorLLeg
- type: entity
id: RightLegBorgJanitor
parent: BaseBorgLegRight
name: janitor cyborg right leg
components:
- type: Sprite
state: janitor_r_leg
- type: Icon
state: janitor_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgJanitorRLeg
- type: entity
id: HeadBorgJanitor
parent: BaseBorgHead
name: janitor cyborg head
components:
- type: Sprite
state: janitor_head
- type: Icon
state: janitor_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgJanitorHead
- type: entity
id: TorsoBorgJanitor
parent: BaseBorgTorso
name: janitor cyborg torso
components:
- type: Sprite
state: janitor_chest
- type: Icon
state: janitor_chest
- type: Tag
tags:
- Trash
- BorgJanitorTorso
# medical parts
- type: entity
id: LeftArmBorgMedical
parent: BaseBorgArmLeft
name: medical cyborg left arm
components:
- type: Sprite
state: medical_l_arm
- type: Icon
state: medical_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgMedicalLArm
- type: entity
id: RightArmBorgMedical
parent: BaseBorgArmRight
name: medical cyborg right arm
components:
- type: Sprite
state: medical_r_arm
- type: Icon
state: medical_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgMedicalRArm
- type: entity
id: LeftLegBorgMedical
parent: BaseBorgLegLeft
name: medical cyborg left leg
components:
- type: Sprite
state: medical_l_leg
- type: Icon
state: medical_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgMedicalLLeg
- type: entity
id: RightLegBorgMedical
parent: BaseBorgLegRight
name: medical cyborg right leg
components:
- type: Sprite
state: medical_r_leg
- type: Icon
state: medical_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgMedicalRLeg
- type: entity
id: HeadBorgMedical
parent: BaseBorgHead
name: medical cyborg head
components:
- type: Sprite
state: medical_head
- type: Icon
state: medical_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgMedicalHead
- type: entity
id: TorsoBorgMedical
parent: BaseBorgTorso
name: medical cyborg torso
components:
- type: Sprite
state: medical_chest
- type: Icon
state: medical_chest
- type: Tag
tags:
- Trash
- BorgMedicalTorso
# mining parts
- type: entity
id: LeftArmBorgMining
parent: BaseBorgArmLeft
name: mining cyborg left arm
components:
- type: Sprite
state: mining_l_arm
- type: Icon
state: mining_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgMiningLArm
- type: entity
id: RightArmBorgMining
parent: BaseBorgArmRight
name: mining cyborg right arm
components:
- type: Sprite
state: mining_r_arm
- type: Icon
state: mining_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgMiningRArm
- type: entity
id: LeftLegBorgMining
parent: BaseBorgLegLeft
name: mining cyborg left leg
components:
- type: Sprite
state: mining_l_leg
- type: Icon
state: mining_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgMiningLLeg
- type: entity
id: RightLegBorgMining
parent: BaseBorgLegRight
name: mining cyborg right leg
components:
- type: Sprite
state: mining_r_leg
- type: Icon
state: mining_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgMiningRLeg
- type: entity
id: HeadBorgMining
parent: BaseBorgHead
name: mining cyborg head
components:
- type: Sprite
state: mining_head
- type: Icon
state: mining_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgMiningHead
- type: entity
id: TorsoBorgMining
parent: BaseBorgTorso
name: mining cyborg torso
components:
- type: Sprite
state: mining_chest
- type: Icon
state: mining_chest
- type: Tag
tags:
- Trash
- BorgMiningTorso
# service parts
- type: entity
id: LeftArmBorgService
parent: BaseBorgArmLeft
name: service cyborg left arm
components:
- type: Sprite
state: service_l_arm
- type: Icon
state: service_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgServiceLArm
- type: entity
id: RightArmBorgService
parent: BaseBorgArmRight
name: service cyborg right arm
components:
- type: Sprite
state: service_r_arm
- type: Icon
state: service_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgServiceRArm
- type: entity
id: LeftLegBorgService
parent: BaseBorgLegLeft
name: service cyborg left leg
components:
- type: Sprite
state: service_l_leg
- type: Icon
state: service_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgServiceLLeg
- type: entity
id: RightLegBorgService
parent: BaseBorgLegRight
name: service cyborg right leg
components:
- type: Sprite
state: service_r_leg
- type: Icon
state: service_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgServiceRLeg
- type: entity
id: HeadBorgService
parent: BaseBorgHead
name: service cyborg head
components:
- type: Sprite
state: service_head
- type: Icon
state: service_head
- type: Tag
tags:
- Trash
- BorgHead
- BorgServiceHead
- type: entity
id: TorsoBorgService
parent: BaseBorgTorso
name: service cyborg torso
components:
- type: Sprite
state: service_chest
- type: Icon
state: service_chest
- type: Tag
tags:
- Trash
- BorgServiceTorso

View File

@@ -33,139 +33,27 @@
borg_l_arm+o:
whitelist:
tags:
- BorgGenericLArm
- BorgLArm
borg_r_arm+o:
whitelist:
tags:
- BorgGenericRArm
- BorgRArm
borg_l_leg+o:
whitelist:
tags:
- BorgGenericLLeg
- BorgLLeg
borg_r_leg+o:
whitelist:
tags:
- BorgGenericRLeg
- BorgRLeg
borg_head+o:
whitelist:
tags:
- BorgGenericHead
- BorgHead
borg_chest+o:
whitelist:
tags:
- BorgGenericTorso
service_l_arm+o:
whitelist:
tags:
- BorgServiceLArm
service_r_arm+o:
whitelist:
tags:
- BorgServiceRArm
service_l_leg+o:
whitelist:
tags:
- BorgServiceLLeg
service_r_leg+o:
whitelist:
tags:
- BorgServiceRLeg
service_head+o:
whitelist:
tags:
- BorgServiceHead
service_chest+o:
whitelist:
tags:
- BorgServiceTorso
engineer_l_arm+o:
whitelist:
tags:
- BorgEngineerLArm
engineer_r_arm+o:
whitelist:
tags:
- BorgEngineerRArm
engineer_l_leg+o:
whitelist:
tags:
- BorgEngineerLLeg
engineer_r_leg+o:
whitelist:
tags:
- BorgEngineerRLeg
engineer_head+o:
whitelist:
tags:
- BorgEngineerHead
engineer_chest+o:
whitelist:
tags:
- BorgEngineerTorso
mining_l_arm+o:
whitelist:
tags:
- BorgMiningLArm
mining_r_arm+o:
whitelist:
tags:
- BorgMiningRArm
mining_l_leg+o:
whitelist:
tags:
- BorgMiningLLeg
mining_r_leg+o:
whitelist:
tags:
- BorgMiningRLeg
mining_head+o:
whitelist:
tags:
- BorgMiningHead
mining_chest+o:
whitelist:
tags:
- BorgMiningTorso
medical_l_arm+o:
whitelist:
tags:
- BorgMedicalLArm
medical_r_arm+o:
whitelist:
tags:
- BorgMedicalRArm
medical_l_leg+o:
whitelist:
tags:
- BorgMedicalLLeg
medical_r_leg+o:
whitelist:
tags:
- BorgMedicalRLeg
medical_head+o:
whitelist:
tags:
- BorgMedicalHead
medical_chest+o:
whitelist:
tags:
- BorgMedicalTorso
janitor_l_leg+o:
whitelist:
tags:
- BorgJanitorLLeg
janitor_r_leg+o:
whitelist:
tags:
- BorgJanitorRLeg
janitor_head+o:
whitelist:
tags:
- BorgJanitorHead
janitor_chest+o:
whitelist:
tags:
- BorgJanitorTorso
- BorgTorso
- type: ContainerContainer
containers:
part-container: !type:Container
@@ -173,45 +61,12 @@
- type: PartAssembly
parts:
generic:
- BorgGenericLArm
- BorgGenericRArm
- BorgGenericLLeg
- BorgGenericRLeg
- BorgGenericHead
- BorgGenericTorso
service:
- BorgServiceLArm
- BorgServiceRArm
- BorgServiceLLeg
- BorgServiceRLeg
- BorgServiceHead
- BorgServiceTorso
engineer:
- BorgEngineerLArm
- BorgEngineerRArm
- BorgEngineerLLeg
- BorgEngineerRLeg
- BorgEngineerHead
- BorgEngineerTorso
medical:
- BorgMedicalLArm
- BorgMedicalRArm
- BorgMedicalLLeg
- BorgMedicalRLeg
- BorgMedicalHead
- BorgMedicalTorso
janitor:
- BorgJanitorLLeg
- BorgJanitorRLeg
- BorgJanitorHead
- BorgJanitorTorso
mining:
- BorgMiningLArm
- BorgMiningRArm
- BorgMiningLLeg
- BorgMiningRLeg
- BorgMiningHead
- BorgMiningTorso
- BorgLArm
- BorgRArm
- BorgLLeg
- BorgRLeg
- BorgHead
- BorgTorso
- type: Construction
graph: Cyborg
node: start

View File

@@ -673,12 +673,6 @@
- BorgModuleFireExtinguisher
- BorgModuleRadiationDetection
- BorgModuleTool
- BorgModuleAppraisal
- BorgModuleConstruction
- BorgModuleService
- BorgModuleTreatment
- BorgModuleSurgery
- BorgModuleCleaning
- CyborgEndoskeleton
- LeftArmBorg
- RightArmBorg
@@ -686,60 +680,21 @@
- RightLegBorg
- LightHeadBorg
- TorsoBorg
- LeftArmBorgEngineer
- RightArmBorgEngineer
- LeftLegBorgEngineer
- RightLegBorgEngineer
- HeadBorgEngineer
- TorsoBorgEngineer
- LeftLegBorgJanitor
- RightLegBorgJanitor
- HeadBorgJanitor
- TorsoBorgJanitor
- LeftArmBorgMedical
- RightArmBorgMedical
- LeftLegBorgMedical
- RightLegBorgMedical
- HeadBorgMedical
- TorsoBorgMedical
- LeftArmBorgMining
- RightArmBorgMining
- LeftLegBorgMining
- RightLegBorgMining
- HeadBorgMining
- TorsoBorgMining
- LeftArmBorgService
- RightArmBorgService
- LeftLegBorgService
- RightLegBorgService
- HeadBorgService
- TorsoBorgService
- MechAirTank # Goobstation
- MechThruster # Goobstation
- PowerCageMedium # Goobstation - Powercell to exosuit fab
- PowerCageSmall # Goobstation - Powercell to exosuit fab
dynamicRecipes:
- ProximitySensor
- BorgModuleLightReplacer
- BorgModuleAdvancedCleaning
- BorgModuleMining
- BorgModuleGrapplingGun
- BorgModuleAdvancedTool
- BorgModuleGPS
- BorgModuleRCD
- BorgModuleRPD
- BorgModuleJetpack
- BorgModulePka
- BorgModuleArtifact
- BorgModuleAnomaly
- BorgModuleGardening
- BorgModuleHarvesting
- BorgModuleMusique
- BorgModuleClowning
- BorgModuleDiagnosis
- BorgModuleDefibrillator
- BorgModuleAdvancedTreatment
- BorgModuleAdvancedSurgery
- JawsOfLifeLeftArm
- JawsOfLifeRightArm
- SpeedLeftLeg
@@ -839,16 +794,20 @@
layers:
- state: icon
map: ["enum.LatheVisualLayers.IsRunning"]
color: "#ffaa99"
- state: unlit
shader: unshaded
map: ["enum.PowerDeviceVisualLayers.Powered"]
color: "#ffaaaa"
- state: inserting
map: ["enum.MaterialStorageVisualLayers.Inserting"]
color: "#ffaaaa"
- state: panel
map: ["enum.WiresVisualLayers.MaintenancePanel"]
- type: Machine
board: BiofabricatorMachineCircuitboard
- type: MaterialStorage
ignoreColor: true
whitelist:
tags:
- Sheet

View File

@@ -26,8 +26,7 @@
- name: head
slotTexture: head
slotFlags: HEAD
slotGroup: MainHotbar
uiWindowPos: 0,0
uiWindowPos: 1,0
strippingWindowPos: 0,0
displayName: Head

View File

@@ -5,18 +5,6 @@
- node: start
entity: CyborgEndoskeleton
edges:
# empty the parts via prying
- to: start
conditions:
- !type:ContainerNotEmpty
container: part-container
steps:
- tool: Prying
doAfter: 0.5
completed:
- !type:EmptyAllContainers
- to: cyborg
steps:
- assemblyId: generic
@@ -43,165 +31,6 @@
- tool: Screwing
doAfter: 0.5
- to: engineer
steps:
- assemblyId: engineer
guideString: borg-construction-guide-string
- material: Cable
amount: 1
doAfter: 1
store: part-container
- component: Flash
name: flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- component: Flash
name: second flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- tool: Screwing
doAfter: 0.5
- to: janitor
steps:
- assemblyId: janitor
guideString: borg-construction-guide-string
- material: Cable
amount: 1
doAfter: 1
store: part-container
- component: Flash
name: flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- component: Flash
name: second flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- tool: Screwing
doAfter: 0.5
- to: medical
steps:
- assemblyId: medical
guideString: borg-construction-guide-string
- material: Cable
amount: 1
doAfter: 1
store: part-container
- component: Flash
name: flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- component: Flash
name: second flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- tool: Screwing
doAfter: 0.5
- to: mining
steps:
- assemblyId: mining
guideString: borg-construction-guide-string
- material: Cable
amount: 1
doAfter: 1
store: part-container
- component: Flash
name: flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- component: Flash
name: second flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- tool: Screwing
doAfter: 0.5
- to: service
steps:
- assemblyId: service
guideString: borg-construction-guide-string
- material: Cable
amount: 1
doAfter: 1
store: part-container
- component: Flash
name: flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- component: Flash
name: second flash
store: part-container
icon:
sprite: Objects/Weapons/Melee/flash.rsi
state: flash
- tool: Screwing
doAfter: 0.5
- node: cyborg
entity: BorgChassisGeneric
- node: engineer
entity: BorgChassisEngineer
- node: janitor
entity: BorgChassisJanitor
- node: mining
entity: BorgChassisMining
- node: medical
entity: BorgChassisMedical
- node: service
entity: BorgChassisService
- node: syndicateassault
entity: BorgChassisSyndicateAssault
- node: syndicatemedical
entity: BorgChassisSyndicateMedical
- node: syndicatesaboteur
entity: BorgChassisSyndicateSaboteur
entity: BorgChassisSelectable

View File

@@ -1,340 +1,104 @@
# Base prototypes
- type: latheRecipe
id: ProximitySensor
result: ProximitySensor
abstract: true
id: BaseRoboticsRecipe
category: Robotics
completetime: 2
- type: latheRecipe
abstract: true
parent: BaseRoboticsRecipe
id: BaseBorgLimbRecipe
materials:
Steel: 250
Glass: 100
- type: latheRecipe
abstract: true
parent: BaseRoboticsRecipe
id: BaseBorgModuleRecipe
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
abstract: true
parent: BaseBorgModuleRecipe
id: BaseGoldBorgModuleRecipe
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
# Recipes
- type: latheRecipe
parent: BaseRoboticsRecipe
id: ProximitySensor
result: ProximitySensor
materials:
Steel: 200
Glass: 300
- type: latheRecipe
parent: BaseRoboticsRecipe
id: SciFlash
result: SciFlash
category: Robotics
completetime: 2
materials:
Glass: 100
Plastic: 200
Steel: 100
- type: latheRecipe
parent: BaseRoboticsRecipe
id: CyborgEndoskeleton
result: CyborgEndoskeleton
category: Robotics
completetime: 3
materials:
Steel: 1500
# Generic
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorg
result: LeftArmBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightArmBorg
result: RightArmBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorg
result: LeftLegBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorg
result: RightLegBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LightHeadBorg
result: LightHeadBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorg
result: TorsoBorg
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftArmBorgEngineer
result: LeftArmBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightArmBorgEngineer
result: RightArmBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftLegBorgEngineer
result: LeftLegBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightLegBorgEngineer
result: RightLegBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: HeadBorgEngineer
result: HeadBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: TorsoBorgEngineer
result: TorsoBorgEngineer
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftArmBorgMedical
result: LeftArmBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightArmBorgMedical
result: RightArmBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftLegBorgMedical
result: LeftLegBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightLegBorgMedical
result: RightLegBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: HeadBorgMedical
result: HeadBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: TorsoBorgMedical
result: TorsoBorgMedical
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftArmBorgMining
result: LeftArmBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightArmBorgMining
result: RightArmBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftLegBorgMining
result: LeftLegBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightLegBorgMining
result: RightLegBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: HeadBorgMining
result: HeadBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: TorsoBorgMining
result: TorsoBorgMining
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftArmBorgService
result: LeftArmBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightArmBorgService
result: RightArmBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftLegBorgService
result: LeftLegBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightLegBorgService
result: RightLegBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: HeadBorgService
result: HeadBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: TorsoBorgService
result: TorsoBorgService
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: LeftLegBorgJanitor
result: LeftLegBorgJanitor
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: RightLegBorgJanitor
result: RightLegBorgJanitor
category: Robotics
completetime: 2
materials:
Steel: 250
Glass: 100
- type: latheRecipe
id: HeadBorgJanitor
result: HeadBorgJanitor
category: Robotics
completetime: 4
materials:
Steel: 500
Glass: 200
- type: latheRecipe
id: TorsoBorgJanitor
result: TorsoBorgJanitor
category: Robotics
completetime: 4
materials:
Steel: 500
Glass: 200
# Parts
- type: latheRecipe
parent: BaseRoboticsRecipe
id: MMI
result: MMI
category: Robotics
completetime: 3
icon:
sprite: Objects/Specific/Robotics/mmi.rsi
@@ -346,9 +110,9 @@
Gold: 200
- type: latheRecipe
parent: BaseRoboticsRecipe
id: PositronicBrain
result: PositronicBrain
category: Robotics
completetime: 3
materials:
Steel: 500
@@ -357,262 +121,82 @@
Silver: 100
Plasma: 1000
# Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleCable
result: BorgModuleCable
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleFireExtinguisher
result: BorgModuleFireExtinguisher
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleGPS
result: BorgModuleGPS
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleRadiationDetection
result: BorgModuleRadiationDetection
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleTool
result: BorgModuleTool
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleAppraisal
result: BorgModuleAppraisal
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleMining
result: BorgModuleMining
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleGrapplingGun
result: BorgModuleGrapplingGun
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
# Engineering Modules
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleAdvancedTool
result: BorgModuleAdvancedTool
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
- type: latheRecipe
id: BorgModuleConstruction
result: BorgModuleConstruction
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
- type: latheRecipe
id: BorgModuleRCD
result: BorgModuleRCD
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
- type: latheRecipe
id: BorgModuleRPD
result: BorgModuleRPD
category: Robotics
completetime: 3
materials:
Steel: 550
Glass: 550
Plastic: 300
Gold: 50
- type: latheRecipe
id: BorgModuleLightReplacer
result: BorgModuleLightReplacer
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleCleaning
result: BorgModuleCleaning
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
# Janitor Modules
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleAdvancedCleaning
result: BorgModuleAdvancedCleaning
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
Gold: 50
- type: latheRecipe
id: BorgModuleDiagnosis
result: BorgModuleDiagnosis
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleTreatment
result: BorgModuleTreatment
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
# Medical Modules
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleAdvancedTreatment
result: BorgModuleAdvancedTreatment
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleDefibrillator
result: BorgModuleDefibrillator
category: Robotics
completetime: 3
materials:
Steel: 500
Glass: 500
Plastic: 250
Gold: 50
# Science Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleArtifact
result: BorgModuleArtifact
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleAnomaly
result: BorgModuleAnomaly
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleService
result: BorgModuleService
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleMusique
result: BorgModuleMusique
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
# Service Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleGardening
result: BorgModuleGardening
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleHarvesting
result: BorgModuleHarvesting
category: Robotics
completetime: 3
materials:
Steel: 250
Glass: 250
Plastic: 250
- type: latheRecipe
id: BorgModuleClowning

View File

@@ -17,7 +17,20 @@
- MechEquipmentDrill # Goobstation
- OreProcessorIndustrialMachineCircuitboard
- ClothingMaskWeldingGas
- SalvageExpeditionsComputerCircuitboard
- type: technology
id: SpaceScanning
name: research-technology-space-scanning
icon:
sprite: Objects/Tools/handheld_mass_scanner.rsi
state: icon
discipline: Industrial
tier: 1
cost: 5000
recipeUnlocks:
- RadarConsoleCircuitboard
- HandHeldMassScanner
- BorgModuleGPS
- type: technology
id: AdvancedPowercells

View File

@@ -20,4 +20,4 @@
canBeAntag: false
icon: JobIconBorg
supervisors: job-supervisors-rd
jobEntity: PlayerBorgGeneric
jobEntity: PlayerBorgBattery

View File

@@ -0,0 +1,218 @@
# Generic borg
- type: borgType
id: generic
# Description
dummyPrototype: BorgChassisGeneric
# Functional
extraModuleCount: 5
moduleWhitelist:
tags:
- BorgModuleGeneric
defaultModules:
- BorgModuleTool
radioChannels:
- Science
# Visual
inventoryTemplateId: borgShort
spriteBodyState: robot
spriteHasMindState: robot_e
spriteNoMindState: robot_e_r
spriteToggleLightState: robot_l
# Pet
petSuccessString: petting-success-generic-cyborg
petFailureString: petting-failure-generic-cyborg
# Engineering borg
- type: borgType
id: engineering
# Description
dummyPrototype: BorgChassisEngineer
# Functional
extraModuleCount: 3
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleEngineering
defaultModules:
- BorgModuleTool
- BorgModuleConstruction
- BorgModuleRCD
- BorgModuleCable
radioChannels:
- Engineering
- Science
# Visual
inventoryTemplateId: borgShort
spriteBodyState: engineer
spriteHasMindState: engineer_e
spriteNoMindState: engineer_e_r
spriteToggleLightState: engineer_l
# Pet
petSuccessString: petting-success-engineer-cyborg
petFailureString: petting-failure-engineer-cyborg
# Salvage borg
- type: borgType
id: mining
# Description
dummyPrototype: BorgChassisMining
# Functional
extraModuleCount: 3
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleCargo
defaultModules:
- BorgModuleGrapplingGun
- BorgModuleMining
- BorgModuleAppraisal
radioChannels:
- Supply
- Science
# Visual
inventoryTemplateId: borgTall
spriteBodyState: miner
spriteBodyMovementState: miner_moving
spriteHasMindState: miner_e
spriteNoMindState: miner_e_r
spriteToggleLightState: miner_l
# Pet
petSuccessString: petting-success-salvage-cyborg
petFailureString: petting-failure-salvage-cyborg
# Janitor borg
- type: borgType
id: janitor
# Description
dummyPrototype: BorgChassisJanitor
# Functional
extraModuleCount: 3
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleJanitor
defaultModules:
- BorgModuleLightReplacer
- BorgModuleCleaning
radioChannels:
- Science
- Service
# Visual
inventoryTemplateId: borgShort
spriteBodyState: janitor
spriteBodyMovementState: janitor_moving
spriteHasMindState: janitor_e
spriteNoMindState: janitor_e_r
spriteToggleLightState: janitor_l
# Pet
petSuccessString: petting-success-janitor-cyborg
petFailureString: petting-failure-janitor-cyborg
# Medical borg
- type: borgType
id: medical
# Description
dummyPrototype: BorgChassisMedical
# Functional
extraModuleCount: 3
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleMedical
defaultModules:
- BorgModuleTreatment
radioChannels:
- Science
- Medical
addComponents:
- type: SolutionScanner
- type: ShowHealthBars
damageContainers:
- Biological
- type: ShowHealthIcons
damageContainers:
- Biological
# Visual
inventoryTemplateId: borgDutch
spriteBodyState: medical
spriteBodyMovementState: medical_moving
spriteHasMindState: medical_e
spriteNoMindState: medical_e_r
spriteToggleLightState: medical_l
# Pet
petSuccessString: petting-success-medical-cyborg
petFailureString: petting-failure-medical-cyborg
# Sounds
footstepCollection:
collection: FootstepHoverBorg
# Service borg
- type: borgType
id: service
# Description
dummyPrototype: BorgChassisService
# Functional
extraModuleCount: 3
moduleWhitelist:
tags:
- BorgModuleGeneric
- BorgModuleService
defaultModules:
- BorgModuleMusique
- BorgModuleService
- BorgModuleClowning
radioChannels:
- Science
- Service
# Visual
inventoryTemplateId: borgTall
spriteBodyState: service
spriteHasMindState: service_e
spriteNoMindState: service_e_r
spriteToggleLightState: service_l
# Pet
petSuccessString: petting-success-service-cyborg
petFailureString: petting-failure-service-cyborg

View File

@@ -73,96 +73,27 @@
- type: Tag
id: BorgArm
- type: Tag
id: BorgEngineerHead
- type: Tag
id: BorgEngineerLArm
- type: Tag
id: BorgEngineerLLeg
- type: Tag
id: BorgEngineerRArm
- type: Tag
id: BorgEngineerRLeg
- type: Tag
id: BorgEngineerTorso
- type: Tag
id: BorgGenericHead
- type: Tag
id: BorgGenericLArm
- type: Tag
id: BorgGenericLLeg
- type: Tag
id: BorgGenericRArm
- type: Tag
id: BorgGenericRLeg
- type: Tag
id: BorgGenericTorso
- type: Tag
id: BorgHead
- type: Tag
id: BorgJanitorHead
id: BorgLArm
- type: Tag
id: BorgJanitorLLeg
id: BorgLLeg
- type: Tag
id: BorgJanitorRLeg
id: BorgRArm
- type: Tag
id: BorgJanitorTorso
id: BorgRLeg
- type: Tag
id: BorgTorso
- type: Tag
id: BorgLeg
- type: Tag
id: BorgMedicalHead
- type: Tag
id: BorgMedicalLArm
- type: Tag
id: BorgMedicalLLeg
- type: Tag
id: BorgMedicalRArm
- type: Tag
id: BorgMedicalRLeg
- type: Tag
id: BorgMedicalTorso
- type: Tag
id: BorgMiningHead
- type: Tag
id: BorgMiningLArm
- type: Tag
id: BorgMiningLLeg
- type: Tag
id: BorgMiningRArm
- type: Tag
id: BorgMiningRLeg
- type: Tag
id: BorgMiningTorso
- type: Tag
id: BorgModuleCargo
@@ -188,22 +119,7 @@
id: BorgModuleSyndicateAssault
- type: Tag
id: BorgServiceHead
- type: Tag
id: BorgServiceLArm
- type: Tag
id: BorgServiceLLeg
- type: Tag
id: BorgServiceRArm
- type: Tag
id: BorgServiceRLeg
- type: Tag
id: BorgServiceTorso
id: Bot
- type: Tag
id: BotanyHatchet

View File

@@ -18,28 +18,28 @@
</Box>
Both brains can be fabricated without requiring any additional research.
## Chassis
While all cyborgs share the same endoskeleton, not all share the same chassis. The chassis determines what modules the cyborg can have, along with the [color=#a4885c]departmental radio channel[/color] they correspond to. By default, they will always have access to [color=#D381C9]Science[/color] and [color=green]station-wide[/color] frequencies, along with having [color=#a4885c]all-access[/color].
## Cyborg types
Once created, a cyborg needs to specialize its chassis to a duty on the station. This determines what modules it starts with, which additional modules can be installed, and what [color=#a4885c]departmental radio channel[/color] it has access to. All cyborgs have access to the [color=#D381C9]Science[/color] and [color=green]station-wide[/color] radio channels. All cyborg types have [color=#a4885c]all-access[/color].
<Box>
<GuideEntityEmbed Entity="BorgChassisGeneric" Caption="Generic"/>
<GuideEntityEmbed Entity="BorgChassisEngineer" Caption="Engineering"/>
<GuideEntityEmbed Entity="BorgChassisMining" Caption="Mining"/>
<GuideEntityEmbed Entity="BorgChassisMining" Caption="Salvage"/>
<GuideEntityEmbed Entity="BorgChassisJanitor" Caption="Janitor"/>
<GuideEntityEmbed Entity="BorgChassisService" Caption="Service"/>
<GuideEntityEmbed Entity="BorgChassisMedical" Caption="Medical"/>
</Box>
<Box>
[italic]Examples of various cyborg chassis[/italic]
[italic]Examples of various cyborg types[/italic]
</Box>
If you wish to change the chassis of an already existing cyborg, you have to construct a whole new one, limbs and frame included. The brain, power cell and modules [italic](if it can fit in the new chassis,)[/italic] can be carried over from the old chassis, if desired.
Once a cyborg chassis has been specialized, it cannot be changed. To change types, a new chassis must be constructed. The brain, power cell, and any modules [italic](if they are compatible with the new chassis)[/italic] can be carried over from the old chassis if desired.
## Modules
<Box>
<GuideEntityEmbed Entity="BorgModuleTool" Caption="Tool Cyborg Module"/>
</Box>
A cyborg isn't able to do much without [color=#a4885c]modules[/color]. These printed circuit boards are specific to cyborgs and grant additional functionality to them. They are printed at the [color=#a4885c]Exosuit Fabricator[/color].
Cyborgs do not have hands, and therefore cannot pick things up like most other players. Instead, their equipment is provided by various [color=#a4885c]modules[/color]. Every cyborg type starts with its own specific set of modules, but additional modules can be inserted as upgrades. These additional modules can be printed at the [color=#a4885c]Exosuit Fabricator[/color].
[color=#a4885c]Generic[/color] modules add versatility. They can be fitted into any chassis, granting useful tools such as crowbars, GPS, and the ability to interact with cables. [bold]The generic borg chassis can fit up to 6 modules in total.[/bold]
[color=#a4885c]Generic[/color] modules add versatility. They can be fitted into any chassis, granting useful tools such as crowbars, GPS, and the ability to interact with cables. [bold]The generic cyborg chassis can fit up to five additional modules.[/bold]
<Box>
<GuideEntityEmbed Entity="BorgModuleCable" Caption="Cable"/>
<GuideEntityEmbed Entity="BorgModuleGPS" Caption="GPS"/>
@@ -49,7 +49,7 @@
[italic]Examples of generic modules[/italic]
</Box>
For more specific needs, [color=#a4885c]specialized[/color] modules are available, granting capabilities like scanning anomalies, constructing walls, reviving crew mates, or cleaning a space lube spill. These modules are typically colored with the same palette as the department [italic](or occupation)[/italic] they relate to. These modules [italic](with exception to [color=#D381C9]science[/color] modules, which can fit any chassis,)[/italic] can only be fitted in their associated borg chassis. [bold]The specialized borg chassis, being the engineering, janitorial, service, medical, and mining chassis, can fit up to 4 modules.[/bold]
For more specific needs, [color=#a4885c]specialized[/color] modules are available, granting capabilities like scanning anomalies, constructing walls, reviving crew mates, or cleaning a space lube spill. These modules are typically colored with the same palette as the department [italic](or occupation)[/italic] they relate to. These modules [italic](with exception to [color=#D381C9]science[/color] modules, which can fit any chassis,)[/italic] can only be fitted in their associated borg chassis. [bold]The specialized borg chassis, being the engineering, janitorial, service, medical, and mining chassis, can fit up to three additional modules.[/bold]
<Box>
<GuideEntityEmbed Entity="BorgModuleAnomaly" Caption="Anomaly"/>
<GuideEntityEmbed Entity="BorgModuleRCD" Caption="RCD"/>

View File

@@ -9,6 +9,102 @@
"states": [
{
"name": "state-laws"
},
{
"name": "no-action"
},
{
"name":"tool-module"
},
{
"name":"wire-module"
},
{
"name":"gps-module"
},
{
"name":"extinguisher-module"
},
{
"name":"geiger-module"
},
{
"name":"rcd-module"
},
{
"name":"adv-tools-module"
},
{
"name":"construction-module"
},
{
"name":"appraisal-module"
},
{
"name":"grappling-module"
},
{
"name":"mining-module"
},
{
"name":"light-replacer-module"
},
{
"name":"cleaning-module"
},
{
"name":"adv-cleaning-module"
},
{
"name":"diagnosis-module"
},
{
"name":"treatment-module"
},
{
"name":"adv-diagnosis-module"
},
{
"name":"defib-module"
},
{
"name":"node-scanner-module"
},
{
"name":"anomaly-module"
},
{
"name":"service-module"
},
{
"name":"musical-module"
},
{
"name":"gardening-module"
},
{
"name":"harvesting-module"
},
{
"name":"clowning-module"
},
{
"name":"syndicate-weapon-module"
},
{
"name":"syndicate-operative-module"
},
{
"name":"syndicate-esword-module"
},
{
"name":"syndicate-l6c-module"
},
{
"name":"syndicate-martyr-module"
},
{
"name": "select-type"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B