diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index f3b9d3b674..f2adf9203c 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -64,6 +64,7 @@ public sealed class ClientClothingSystem : ClothingSystem base.Initialize(); SubscribeLocalEvent(OnGetVisuals); + SubscribeLocalEvent(OnInventoryTemplateUpdated); SubscribeLocalEvent(OnVisualsChanged); SubscribeLocalEvent(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 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(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); diff --git a/Content.Client/Inventory/ClientInventorySystem.cs b/Content.Client/Inventory/ClientInventorySystem.cs index 248597e0ba..40e15c5c89 100644 --- a/Content.Client/Inventory/ClientInventorySystem.cs +++ b/Content.Client/Inventory/ClientInventorySystem.cs @@ -235,6 +235,20 @@ namespace Content.Client.Inventory EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true)); } + protected override void UpdateInventoryTemplate(Entity 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. diff --git a/Content.Client/Overlays/EquipmentHudSystem.cs b/Content.Client/Overlays/EquipmentHudSystem.cs index 1e36f0a4d6..6ad7be12fc 100644 --- a/Content.Client/Overlays/EquipmentHudSystem.cs +++ b/Content.Client/Overlays/EquipmentHudSystem.cs @@ -14,6 +14,7 @@ public abstract class EquipmentHudSystem : EntitySystem where T : IComponent { [Dependency] private readonly IPlayerManager _player = default!; + [ViewVariables] protected bool IsActive; protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET; diff --git a/Content.Client/Overlays/ShowHealthBarsSystem.cs b/Content.Client/Overlays/ShowHealthBarsSystem.cs index 1eb712a898..b23209ff20 100644 --- a/Content.Client/Overlays/ShowHealthBarsSystem.cs +++ b/Content.Client/Overlays/ShowHealthBarsSystem.cs @@ -21,9 +21,16 @@ public sealed class ShowHealthBarsSystem : EquipmentHudSystem(OnHandleState); + _overlay = new(EntityManager, _prototype); } + private void OnHandleState(Entity ent, ref AfterAutoHandleStateEvent args) + { + RefreshOverlay(ent); + } + protected override void UpdateInternal(RefreshEquipmentHudEvent component) { base.UpdateInternal(component); diff --git a/Content.Client/Overlays/ShowHealthIconsSystem.cs b/Content.Client/Overlays/ShowHealthIconsSystem.cs index 8c22c78f17..b4d845e421 100644 --- a/Content.Client/Overlays/ShowHealthIconsSystem.cs +++ b/Content.Client/Overlays/ShowHealthIconsSystem.cs @@ -17,6 +17,7 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem DamageContainers = new(); public override void Initialize() @@ -24,6 +25,7 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem(OnGetStatusIconsEvent); + SubscribeLocalEvent(OnHandleState); } protected override void UpdateInternal(RefreshEquipmentHudEvent component) @@ -43,6 +45,11 @@ public sealed class ShowHealthIconsSystem : EquipmentHudSystem ent, ref AfterAutoHandleStateEvent args) + { + RefreshOverlay(ent); + } + private void OnGetStatusIconsEvent(Entity entity, ref GetStatusIconsEvent args) { if (!IsActive) diff --git a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs index 08f15d9de2..57a9b50ba3 100644 --- a/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgMenu.xaml.cs @@ -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(module); + var control = new BorgModuleControl(module, _entity, !moduleComponent.DefaultModule); control.RemoveButtonPressed += () => { RemoveModuleButtonPressed?.Invoke(module); diff --git a/Content.Client/Silicons/Borgs/BorgModuleControl.xaml.cs b/Content.Client/Silicons/Borgs/BorgModuleControl.xaml.cs index d5cf05ba63..245425524c 100644 --- a/Content.Client/Silicons/Borgs/BorgModuleControl.xaml.cs +++ b/Content.Client/Silicons/Borgs/BorgModuleControl.xaml.cs @@ -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; } } diff --git a/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml new file mode 100644 index 0000000000..f51c2f53fd --- /dev/null +++ b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs new file mode 100644 index 0000000000..e1fbd376b5 --- /dev/null +++ b/Content.Client/Silicons/Borgs/BorgSelectTypeMenu.xaml.cs @@ -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; + +/// +/// Menu used by borgs to select their type. +/// +/// +/// +[GenerateTypedNameReferences] +public sealed partial class BorgSelectTypeMenu : FancyWindow +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + private BorgTypePrototype? _selectedBorgType; + + public event Action>? ConfirmedBorgType; + + [ValidatePrototypeId] + private static readonly List> GuidebookEntries = new() { "Cyborgs", "Robotics" }; + + public BorgSelectTypeMenu() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + + var group = new ButtonGroup(); + foreach (var borgType in _prototypeManager.EnumeratePrototypes().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"); + } +} diff --git a/Content.Client/Silicons/Borgs/BorgSelectTypeUserInterface.cs b/Content.Client/Silicons/Borgs/BorgSelectTypeUserInterface.cs new file mode 100644 index 0000000000..8c76fade8c --- /dev/null +++ b/Content.Client/Silicons/Borgs/BorgSelectTypeUserInterface.cs @@ -0,0 +1,30 @@ +using Content.Shared.Silicons.Borgs.Components; +using JetBrains.Annotations; +using Robust.Client.UserInterface; + +namespace Content.Client.Silicons.Borgs; + +/// +/// User interface used by borgs to select their type. +/// +/// +/// +/// +[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(); + _menu.ConfirmedBorgType += prototype => SendMessage(new BorgSelectTypeMessage(prototype)); + } +} diff --git a/Content.Client/Silicons/Borgs/BorgSwitchableTypeSystem.cs b/Content.Client/Silicons/Borgs/BorgSwitchableTypeSystem.cs new file mode 100644 index 0000000000..346dc5c276 --- /dev/null +++ b/Content.Client/Silicons/Borgs/BorgSwitchableTypeSystem.cs @@ -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; + +/// +/// Client side logic for borg type switching. Sets up primarily client-side visual information. +/// +/// +/// +public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem +{ + [Dependency] private readonly BorgSystem _borgSystem = default!; + [Dependency] private readonly AppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(AfterStateHandler); + SubscribeLocalEvent(OnComponentStartup); + } + + private void OnComponentStartup(Entity ent, ref ComponentStartup args) + { + UpdateEntityAppearance(ent); + } + + private void AfterStateHandler(Entity ent, ref AfterAutoHandleStateEvent args) + { + UpdateEntityAppearance(ent); + } + + protected override void UpdateEntityAppearance( + Entity 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(entity); + spriteMovement.NoMovementLayers.Clear(); + spriteMovement.NoMovementLayers["movement"] = new PrototypeLayerData + { + State = prototype.SpriteBodyState, + }; + spriteMovement.MovementLayers.Clear(); + spriteMovement.MovementLayers["movement"] = new PrototypeLayerData + { + State = movementState, + }; + } + else + { + RemComp(entity); + } + + base.UpdateEntityAppearance(entity, prototype); + } +} diff --git a/Content.Client/Silicons/Borgs/BorgSystem.cs b/Content.Client/Silicons/Borgs/BorgSystem.cs index e92ce5cc77..387a56384e 100644 --- a/Content.Client/Silicons/Borgs/BorgSystem.cs +++ b/Content.Client/Silicons/Borgs/BorgSystem.cs @@ -92,4 +92,18 @@ public sealed class BorgSystem : SharedBorgSystem sprite.LayerSetState(MMIVisualLayers.Base, state); } } + + /// + /// Sets the sprite states used for the borg "is there a mind or not" indication. + /// + /// The entity and component to modify. + /// The state to use if the borg has a mind. + /// The state to use if the borg has no mind. + /// + /// + public void SetMindStates(Entity borg, string hasMindState, string noMindState) + { + borg.Comp.HasMindState = hasMindState; + borg.Comp.NoMindState = noMindState; + } } diff --git a/Content.Server/Interaction/InteractionPopupSystem.cs b/Content.Server/Interaction/InteractionPopupSystem.cs index c31f7d341f..5e6f466bdf 100644 --- a/Content.Server/Interaction/InteractionPopupSystem.cs +++ b/Content.Server/Interaction/InteractionPopupSystem.cs @@ -134,4 +134,26 @@ public sealed class InteractionPopupSystem : EntitySystem component.LastInteractTime = curTime; } + + /// + /// Sets . + /// + /// + /// This field is not networked automatically, so this method must be called on both sides of the network. + /// + public void SetInteractSuccessString(Entity ent, string str) + { + ent.Comp.InteractSuccessString = str; + } + + /// + /// Sets . + /// + /// + /// This field is not networked automatically, so this method must be called on both sides of the network. + /// + public void SetInteractFailureString(Entity ent, string str) + { + ent.Comp.InteractFailureString = str; + } } diff --git a/Content.Server/Silicons/Borgs/BorgSwitchableTypeSystem.cs b/Content.Server/Silicons/Borgs/BorgSwitchableTypeSystem.cs new file mode 100644 index 0000000000..d1a32a6a5b --- /dev/null +++ b/Content.Server/Silicons/Borgs/BorgSwitchableTypeSystem.cs @@ -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; + +/// +/// Server-side logic for borg type switching. Handles more heavyweight and server-specific switching logic. +/// +public sealed class BorgSwitchableTypeSystem : SharedBorgSwitchableTypeSystem +{ + [Dependency] private readonly BorgSystem _borgSystem = default!; + [Dependency] private readonly ServerInventorySystem _inventorySystem = default!; + + protected override void SelectBorgModule(Entity ent, ProtoId 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(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); + } +} diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs index 0feecad4d0..4e4396bed4 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Modules.cs @@ -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(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(module, out var itemModuleComp)) + { + foreach (var containedModuleUid in component.ModuleContainer.ContainedEntities) + { + if (!TryComp(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; + } + + /// + /// Check if a module can be removed from a borg. + /// + /// The borg that the module is being removed from. + /// The module to remove from the borg. + /// The user attempting to remove the module. + /// True if the module can be removed. + public bool CanRemoveModule( + Entity borg, + Entity 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); } + + /// + /// Sets . + /// + /// The borg to modify. + /// The new max module count. + public void SetMaxModules(Entity ent, int maxModules) + { + ent.Comp.MaxModules = maxModules; + } + + /// + /// Sets . + /// + /// The borg to modify. + /// The new module whitelist. + public void SetModuleWhitelist(Entity ent, EntityWhitelist? whitelist) + { + ent.Comp.ModuleWhitelist = whitelist; + } } diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs index e449d97c66..f737c0d6b5 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -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; } + + /// + /// Sets . + /// + public void SetTransponderSprite(Entity ent, SpriteSpecifier sprite) + { + ent.Comp.Sprite = sprite; + } + + /// + /// Sets . + /// + public void SetTransponderName(Entity ent, string name) + { + ent.Comp.Name = name; + } } diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs index d0e9f80e36..40c2c3bf33 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs @@ -82,6 +82,9 @@ public sealed partial class BorgSystem if (!component.ModuleContainer.Contains(module)) return; + if (!CanRemoveModule((uid, component), (module, Comp(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); diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 4eddb29a96..32c9df21df 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -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 } } + /// + /// Inserts a new module into a borg, the same as if a player inserted it manually. + /// + /// + /// This does not run checks to see if the borg is actually allowed to be inserted, such as whitelists. + /// + /// The borg to insert into. + /// The module to insert. + public void InsertModule(Entity 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) { diff --git a/Content.Shared/Inventory/InventoryComponent.cs b/Content.Shared/Inventory/InventoryComponent.cs index db761ad693..6150bbaece 100644 --- a/Content.Shared/Inventory/InventoryComponent.cs +++ b/Content.Shared/Inventory/InventoryComponent.cs @@ -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))] - 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 MaleDisplacements = new(); } + +/// +/// Raised if the of an inventory changed. +/// +[ByRefEvent] +public struct InventoryTemplateUpdated; diff --git a/Content.Shared/Inventory/InventorySystem.Slots.cs b/Content.Shared/Inventory/InventorySystem.Slots.cs index b0aa12677d..f68148d20f 100644 --- a/Content.Shared/Inventory/InventorySystem.Slots.cs +++ b/Content.Shared/Inventory/InventorySystem.Slots.cs @@ -24,6 +24,8 @@ public partial class InventorySystem : EntitySystem _vvm.GetTypeHandler() .AddHandler(HandleViewVariablesSlots, ListViewVariablesSlots); + + SubscribeLocalEvent(AfterAutoState); } private void ShutdownSlots() @@ -73,6 +75,27 @@ public partial class InventorySystem : EntitySystem } } + private void AfterAutoState(Entity ent, ref AfterAutoHandleStateEvent args) + { + UpdateInventoryTemplate(ent); + } + + protected virtual void UpdateInventoryTemplate(Entity 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 } + /// + /// Change the inventory template ID an entity is using. The new template must be compatible. + /// + /// + /// + /// For an inventory template to be compatible with another, it must have exactly the same slot names. + /// All other changes are rejected. + /// + /// + /// The entity to update. + /// The ID of the new inventory template prototype. + /// + /// Thrown if the new template is not compatible with the existing one. + /// + public void SetTemplateId(Entity ent, ProtoId 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); + } + /// /// 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. diff --git a/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs b/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs new file mode 100644 index 0000000000..6154c12757 --- /dev/null +++ b/Content.Shared/Silicons/Borgs/BorgTypePrototype.cs @@ -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; + +/// +/// Information for a borg type that can be selected by . +/// +/// +[Prototype] +public sealed partial class BorgTypePrototype : IPrototype +{ + [ValidatePrototypeId] + private static readonly ProtoId DefaultFootsteps = new("FootstepBorg"); + + [IdDataField] + public required string ID { get; init; } + + // + // Description info (name/desc) is configured via localization strings directly. + // + + /// + /// The prototype displayed in the selection menu for this type. + /// + [DataField] + public required EntProtoId DummyPrototype { get; init; } + + // + // Functional information + // + + /// + /// The amount of free module slots this borg type has. + /// + /// + /// This count is on top of the modules specified in . + /// + /// + [DataField] + public int ExtraModuleCount { get; set; } = 0; + + /// + /// The whitelist for borg modules that can be inserted into this borg type. + /// + /// + [DataField] + public EntityWhitelist? ModuleWhitelist { get; set; } + + /// + /// Inventory template used by this borg. + /// + /// + /// 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. + /// + /// + [DataField] + public ProtoId InventoryTemplateId { get; set; } = "borgShort"; + + /// + /// Radio channels that this borg will gain access to from this module. + /// + /// + /// These channels are provided on top of the ones specified in + /// . + /// + [DataField] + public ProtoId[] RadioChannels = []; + + /// + /// Borg module types that are always available to borgs of this type. + /// + /// + /// These modules still work like modules, although they cannot be removed from the borg. + /// + /// + [DataField] + public EntProtoId[] DefaultModules = []; + + /// + /// Additional components to add to the borg entity when this type is selected. + /// + [DataField] + public ComponentRegistry? AddComponents { get; set; } + + // + // Visual information + // + + /// + /// The sprite state for the main borg body. + /// + [DataField] + public string SpriteBodyState { get; set; } = "robot"; + + /// + /// An optional movement sprite state for the main borg body. + /// + [DataField] + public string? SpriteBodyMovementState { get; set; } + + /// + /// Sprite state used to indicate that the borg has a mind in it. + /// + /// + [DataField] + public string SpriteHasMindState { get; set; } = "robot_e"; + + /// + /// Sprite state used to indicate that the borg has no mind in it. + /// + /// + [DataField] + public string SpriteNoMindState { get; set; } = "robot_e_r"; + + /// + /// Sprite state used when the borg's flashlight is on. + /// + [DataField] + public string SpriteToggleLightState { get; set; } = "robot_l"; + + // + // Minor information + // + + /// + /// String to use on petting success. + /// + /// + [DataField] + public string PetSuccessString { get; set; } = "petting-success-generic-cyborg"; + + /// + /// String to use on petting failure. + /// + /// + [DataField] + public string PetFailureString { get; set; } = "petting-failure-generic-cyborg"; + + // + // Sounds + // + + /// + /// Sound specifier for footstep sounds created by this borg. + /// + [DataField] + public SoundSpecifier FootstepCollection { get; set; } = new SoundCollectionSpecifier(DefaultFootsteps); +} diff --git a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs index de0fe0bce3..c2bf2b2801 100644 --- a/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/BorgChassisComponent.cs @@ -89,5 +89,18 @@ public enum BorgVisuals : byte [Serializable, NetSerializable] public enum BorgVisualLayers : byte { - Light + /// + /// Main borg body layer. + /// + Body, + + /// + /// Layer for the borg's mind state. + /// + Light, + + /// + /// Layer for the borg flashlight status. + /// + LightStatus, } diff --git a/Content.Shared/Silicons/Borgs/Components/BorgModuleComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgModuleComponent.cs index a7523c1ce7..e542a1e3e3 100644 --- a/Content.Shared/Silicons/Borgs/Components/BorgModuleComponent.cs +++ b/Content.Shared/Silicons/Borgs/Components/BorgModuleComponent.cs @@ -7,6 +7,7 @@ namespace Content.Shared.Silicons.Borgs.Components; /// to give them unique abilities and attributes. /// [RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))] +[AutoGenerateComponentState] public sealed partial class BorgModuleComponent : Component { /// @@ -16,6 +17,13 @@ public sealed partial class BorgModuleComponent : Component public EntityUid? InstalledEntity; public bool Installed => InstalledEntity != null; + + /// + /// If true, this is a "default" module that cannot be removed from a borg. + /// + [DataField] + [AutoNetworkedField] + public bool DefaultModule; } /// diff --git a/Content.Shared/Silicons/Borgs/Components/BorgSwitchableTypeComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgSwitchableTypeComponent.cs new file mode 100644 index 0000000000..9a783d19aa --- /dev/null +++ b/Content.Shared/Silicons/Borgs/Components/BorgSwitchableTypeComponent.cs @@ -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; + +/// +/// Component for borgs that can switch their "type" after being created. +/// +/// +/// +/// 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. +/// +/// +/// Available types are specified in s. +/// +/// +/// +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState(raiseAfterAutoHandleState: true)] +[Access(typeof(SharedBorgSwitchableTypeSystem))] +public sealed partial class BorgSwitchableTypeComponent : Component +{ + /// + /// Action entity used by players to select their type. + /// + [DataField, AutoNetworkedField] + public EntityUid? SelectTypeAction; + + /// + /// The currently selected borg type, if any. + /// + /// + /// This can be set in a prototype to immediately apply a borg type, and not have switching support. + /// + [DataField, AutoNetworkedField] + public ProtoId? SelectedBorgType; + + /// + /// Radio channels that the borg will always have. These are added on top of the selected type's radio channels. + /// + [DataField] + public ProtoId[] InherentRadioChannels = []; +} + +/// +/// Action event used to open the selection menu of a . +/// +public sealed partial class BorgToggleSelectTypeEvent : InstantActionEvent; + +/// +/// UI message used by a borg to select their type with . +/// +/// The borg type prototype that the user selected. +[Serializable, NetSerializable] +public sealed class BorgSelectTypeMessage(ProtoId prototype) : BoundUserInterfaceMessage +{ + public ProtoId Prototype = prototype; +} + +/// +/// UI key used by the selection menu for . +/// +[NetSerializable, Serializable] +public enum BorgSwitchableTypeUiKey : byte +{ + SelectBorgType, +} diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs new file mode 100644 index 0000000000..d9abeb2d32 --- /dev/null +++ b/Content.Shared/Silicons/Borgs/SharedBorgSwitchableTypeSystem.cs @@ -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; + +/// +/// Implements borg type switching. +/// +/// +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] + public const string ActionId = "ActionSelectBorgType"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnSelectBorgTypeAction); + + Subs.BuiEvents(BorgSwitchableTypeUiKey.SelectBorgType, + sub => + { + sub.Event(SelectTypeMessageHandler); + }); + } + + // + // UI-adjacent code + // + + private void OnMapInit(Entity 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 ent, ref ComponentShutdown args) + { + _actionsSystem.RemoveAction(ent, ent.Comp.SelectTypeAction); + } + + private void OnSelectBorgTypeAction(Entity ent, ref BorgToggleSelectTypeEvent args) + { + if (args.Handled || !TryComp(ent, out var actor)) + return; + + args.Handled = true; + + _userInterface.TryToggleUi((ent.Owner, null), BorgSwitchableTypeUiKey.SelectBorgType, actor.PlayerSession); + } + + private void SelectTypeMessageHandler(Entity 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 ent, + ProtoId 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 entity) + { + if (!Prototypes.TryIndex(entity.Comp.SelectedBorgType, out var proto)) + return; + + UpdateEntityAppearance(entity, proto); + } + + protected virtual void UpdateEntityAppearance( + Entity 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; + } + } +} diff --git a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs index c62e63481d..827bb351b0 100644 --- a/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs +++ b/Content.Shared/Silicons/Borgs/SharedBorgSystem.cs @@ -124,4 +124,13 @@ public abstract partial class SharedBorgSystem : EntitySystem var sprintDif = movement.BaseWalkSpeed / movement.BaseSprintSpeed; args.ModifySpeed(1f, sprintDif); } + + /// + /// Sets . + /// + public void SetBorgModuleDefault(Entity ent, bool newDefault) + { + ent.Comp.DefaultModule = newDefault; + Dirty(ent); + } } diff --git a/Resources/Locale/en-US/borg/borg.ftl b/Resources/Locale/en-US/borg/borg.ftl index 6f31ca781f..229b4a1977 100644 --- a/Resources/Locale/en-US/borg/borg.ftl +++ b/Resources/Locale/en-US/borg/borg.ftl @@ -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 + + diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index afca8b42fc..098218c967 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -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 diff --git a/Resources/Prototypes/Actions/borgs.yml b/Resources/Prototypes/Actions/borgs.yml index 950a7c8152..6439a43770 100644 --- a/Resources/Prototypes/Actions/borgs.yml +++ b/Resources/Prototypes/Actions/borgs.yml @@ -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 diff --git a/Resources/Prototypes/Body/Parts/silicon.yml b/Resources/Prototypes/Body/Parts/silicon.yml index 2c0624aa3f..48fa652d8c 100644 --- a/Resources/Prototypes/Body/Parts/silicon.yml +++ b/Resources/Prototypes/Body/Parts/silicon.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 4d84022c1b..b50959e3e2 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -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" diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index acb2c8d106..9f560468bf 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 5e7e1a92bd..11bae6b1d4 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_parts.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_parts.yml deleted file mode 100644 index 6df0488e28..0000000000 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_parts.yml +++ /dev/null @@ -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 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml index e1a2ff1847..dd7e6f19c5 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/endoskeleton.yml @@ -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 diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index bd552355a2..584da80dbd 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -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 diff --git a/Resources/Prototypes/InventoryTemplates/borg.yml b/Resources/Prototypes/InventoryTemplates/borg.yml index a03be16708..8e17a7985c 100644 --- a/Resources/Prototypes/InventoryTemplates/borg.yml +++ b/Resources/Prototypes/InventoryTemplates/borg.yml @@ -26,8 +26,7 @@ - name: head slotTexture: head slotFlags: HEAD - slotGroup: MainHotbar - uiWindowPos: 0,0 + uiWindowPos: 1,0 strippingWindowPos: 0,0 displayName: Head diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/machines/cyborg.yml b/Resources/Prototypes/Recipes/Construction/Graphs/machines/cyborg.yml index 0f012cefc9..4ebc43667c 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/machines/cyborg.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/machines/cyborg.yml @@ -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 diff --git a/Resources/Prototypes/Recipes/Lathes/robotics.yml b/Resources/Prototypes/Recipes/Lathes/robotics.yml index 9d6eb45aa2..d1194da559 100644 --- a/Resources/Prototypes/Recipes/Lathes/robotics.yml +++ b/Resources/Prototypes/Recipes/Lathes/robotics.yml @@ -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 diff --git a/Resources/Prototypes/Research/industrial.yml b/Resources/Prototypes/Research/industrial.yml index 4261cd924e..ac84b3dcfe 100644 --- a/Resources/Prototypes/Research/industrial.yml +++ b/Resources/Prototypes/Research/industrial.yml @@ -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 diff --git a/Resources/Prototypes/Roles/Jobs/Science/borg.yml b/Resources/Prototypes/Roles/Jobs/Science/borg.yml index 1d9e007eac..bffdade9b8 100644 --- a/Resources/Prototypes/Roles/Jobs/Science/borg.yml +++ b/Resources/Prototypes/Roles/Jobs/Science/borg.yml @@ -20,4 +20,4 @@ canBeAntag: false icon: JobIconBorg supervisors: job-supervisors-rd - jobEntity: PlayerBorgGeneric + jobEntity: PlayerBorgBattery diff --git a/Resources/Prototypes/borg_types.yml b/Resources/Prototypes/borg_types.yml new file mode 100644 index 0000000000..f6294be68e --- /dev/null +++ b/Resources/Prototypes/borg_types.yml @@ -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 diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 9feb93f56b..eba7f704d8 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -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 diff --git a/Resources/ServerInfo/Guidebook/Science/Cyborgs.xml b/Resources/ServerInfo/Guidebook/Science/Cyborgs.xml index 2b8defb070..c1507ca539 100644 --- a/Resources/ServerInfo/Guidebook/Science/Cyborgs.xml +++ b/Resources/ServerInfo/Guidebook/Science/Cyborgs.xml @@ -18,28 +18,28 @@ 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]. - + - [italic]Examples of various cyborg chassis[/italic] + [italic]Examples of various cyborg types[/italic] - 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 - 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] @@ -49,7 +49,7 @@ [italic]Examples of generic modules[/italic] - 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] diff --git a/Resources/Textures/Interface/Actions/actions_borg.rsi/meta.json b/Resources/Textures/Interface/Actions/actions_borg.rsi/meta.json index f63bacd07a..2ebb6eddcf 100644 --- a/Resources/Textures/Interface/Actions/actions_borg.rsi/meta.json +++ b/Resources/Textures/Interface/Actions/actions_borg.rsi/meta.json @@ -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" } ] } diff --git a/Resources/Textures/Interface/Actions/actions_borg.rsi/select-type.png b/Resources/Textures/Interface/Actions/actions_borg.rsi/select-type.png new file mode 100644 index 0000000000..766fd71abd Binary files /dev/null and b/Resources/Textures/Interface/Actions/actions_borg.rsi/select-type.png differ