Merge branch 'space-wizards:master' into ion-storm-refactor

This commit is contained in:
ScarKy0
2024-11-16 00:50:48 +01:00
committed by GitHub
109 changed files with 10915 additions and 4591 deletions

2
.github/labeler.yml vendored
View File

@@ -16,7 +16,7 @@
- changed-files:
- any-glob-to-any-file: '**/*.swsl'
"No C#":
"Changes: No C#":
- changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
- all-globs-to-all-files: "!**/*.cs"

View File

@@ -16,6 +16,6 @@ jobs:
- name: Check for Merge Conflicts
uses: eps1lon/actions-label-merge-conflict@v3.0.0
with:
dirtyLabel: "Merge Conflict"
dirtyLabel: "S: Merge Conflict"
repoToken: "${{ secrets.GITHUB_TOKEN }}"
commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."

View File

@@ -10,7 +10,7 @@ jobs:
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Status: Needs Review"
labels: "S: Needs Review"
- uses: actions-ecosystem/action-remove-labels@v1
with:
labels: "Status: Awaiting Changes"
labels: "S: Awaiting Changes"

20
.github/workflows/labeler-size.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: "Labels: Size"
on: pull_request_target
jobs:
size-label:
runs-on: ubuntu-latest
steps:
- name: size-label
uses: "pascalgn/size-label-action@v0.5.5"
env:
GITHUB_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
with:
# Custom size configuration
sizes: >
{
"0": "XS",
"10": "S",
"30": "M",
"100": "L",
"1000": "XL"
}

View File

@@ -13,4 +13,4 @@ jobs:
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: stable"
labels: "Branch: Stable"

View File

@@ -13,4 +13,4 @@ jobs:
steps:
- uses: actions-ecosystem/action-add-labels@v1
with:
labels: "Branch: staging"
labels: "Branch: Staging"

View File

@@ -3,6 +3,8 @@
on:
issues:
types: [opened]
pull_request_target:
types: [opened]
jobs:
add_label:
@@ -11,4 +13,4 @@ jobs:
- uses: actions-ecosystem/action-add-labels@v1
if: join(github.event.issue.labels) == ''
with:
labels: "Status: Untriaged"
labels: "S: Untriaged"

View File

@@ -8,6 +8,7 @@
<Label Name="ExpiryLabel" Text="{Loc admin-note-editor-expiry-label}" Visible="False" />
<HistoryLineEdit Name="ExpiryLineEdit" PlaceHolder="{Loc admin-note-editor-expiry-placeholder}"
Visible="False" HorizontalExpand="True" />
<OptionButton Name="ExpiryLengthDropdown" Visible="False" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<OptionButton Name="TypeOption" HorizontalAlignment="Center" />

View File

@@ -17,6 +17,17 @@ public sealed partial class NoteEdit : FancyWindow
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientConsoleHost _console = default!;
private enum Multipliers
{
Minutes,
Hours,
Days,
Weeks,
Months,
Years,
Centuries
}
public event Action<int, NoteType, string, NoteSeverity?, bool, DateTime?>? SubmitPressed;
public NoteEdit(SharedAdminNote? note, string playerName, bool canCreate, bool canEdit)
@@ -31,6 +42,20 @@ public sealed partial class NoteEdit : FancyWindow
ResetSubmitButton();
// It's weird to use minutes as the IDs, but it works and makes sense kind of :)
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-minutes"), (int) Multipliers.Minutes);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-hours"), (int) Multipliers.Hours);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-days"), (int) Multipliers.Days);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-weeks"), (int) Multipliers.Weeks);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-months"), (int) Multipliers.Months);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-years"), (int) Multipliers.Years);
ExpiryLengthDropdown.AddItem(Loc.GetString("admin-note-button-centuries"), (int) Multipliers.Centuries);
ExpiryLengthDropdown.OnItemSelected += OnLengthChanged;
ExpiryLengthDropdown.SelectId((int) Multipliers.Weeks);
ExpiryLineEdit.OnTextChanged += OnTextChanged;
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-note"), (int) NoteType.Note);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-message"), (int) NoteType.Message);
TypeOption.AddItem(Loc.GetString("admin-note-editor-type-watchlist"), (int) NoteType.Watchlist);
@@ -172,8 +197,9 @@ public sealed partial class NoteEdit : FancyWindow
{
ExpiryLabel.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Visible = !PermanentCheckBox.Pressed;
ExpiryLengthDropdown.Visible = !PermanentCheckBox.Pressed;
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") : string.Empty;
ExpiryLineEdit.Text = !PermanentCheckBox.Pressed ? 1.ToString() : string.Empty;
}
private void OnSecretPressed(BaseButton.ButtonEventArgs _)
@@ -187,6 +213,16 @@ public sealed partial class NoteEdit : FancyWindow
SeverityOption.SelectId(args.Id);
}
private void OnLengthChanged(OptionButton.ItemSelectedEventArgs args)
{
ExpiryLengthDropdown.SelectId(args.Id);
}
private void OnTextChanged(HistoryLineEdit.LineEditEventArgs args)
{
ParseExpiryTime();
}
private void OnSubmitButtonPressed(BaseButton.ButtonEventArgs args)
{
if (!ParseExpiryTime())
@@ -263,13 +299,24 @@ public sealed partial class NoteEdit : FancyWindow
return true;
}
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !DateTime.TryParse(ExpiryLineEdit.Text, out var result) || DateTime.UtcNow > result)
if (string.IsNullOrWhiteSpace(ExpiryLineEdit.Text) || !uint.TryParse(ExpiryLineEdit.Text, out var inputInt))
{
ExpiryLineEdit.ModulateSelfOverride = Color.Red;
return false;
}
ExpiryTime = result.ToUniversalTime();
var mult = ExpiryLengthDropdown.SelectedId switch
{
(int) Multipliers.Minutes => TimeSpan.FromMinutes(1).TotalMinutes,
(int) Multipliers.Hours => TimeSpan.FromHours(1).TotalMinutes,
(int) Multipliers.Days => TimeSpan.FromDays(1).TotalMinutes,
(int) Multipliers.Weeks => TimeSpan.FromDays(7).TotalMinutes,
(int) Multipliers.Months => TimeSpan.FromDays(30).TotalMinutes,
(int) Multipliers.Years => TimeSpan.FromDays(365).TotalMinutes,
(int) Multipliers.Centuries => TimeSpan.FromDays(36525).TotalMinutes,
_ => throw new ArgumentOutOfRangeException(nameof(ExpiryLengthDropdown.SelectedId), "Multiplier out of range :(")
};
ExpiryTime = DateTime.UtcNow.AddMinutes(inputInt * mult);
ExpiryLineEdit.ModulateSelfOverride = null;
return true;
}

View File

@@ -58,6 +58,7 @@ public sealed class ClientClothingSystem : ClothingSystem
base.Initialize();
SubscribeLocalEvent<ClothingComponent, GetEquipmentVisualsEvent>(OnGetVisuals);
SubscribeLocalEvent<ClothingComponent, InventoryTemplateUpdated>(OnInventoryTemplateUpdated);
SubscribeLocalEvent<InventoryComponent, VisualsChangedEvent>(OnVisualsChanged);
SubscribeLocalEvent<SpriteComponent, DidUnequipEvent>(OnDidUnequip);
@@ -70,11 +71,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))
@@ -84,6 +81,23 @@ public sealed class ClientClothingSystem : ClothingSystem
}
}
private void OnInventoryTemplateUpdated(Entity<ClothingComponent> ent, ref InventoryTemplateUpdated args)
{
UpdateAllSlots(ent.Owner, clothing: ent.Comp);
}
private void UpdateAllSlots(
EntityUid uid,
InventoryComponent? inventoryComponent = null,
ClothingComponent? clothing = null)
{
var enumerator = _inventorySystem.GetSlotEnumerator((uid, inventoryComponent));
while (enumerator.NextItem(out var item, out var slot))
{
RenderEquipment(uid, item, slot.Name, inventoryComponent, clothingComponent: clothing);
}
}
private void OnGetVisuals(EntityUid uid, ClothingComponent item, GetEquipmentVisualsEvent args)
{
if (!TryComp(args.Equipee, out InventoryComponent? inventory))

View File

@@ -235,9 +235,23 @@ namespace Content.Client.Inventory
EntityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(GetNetEntity(item.Value), altInteract: true));
}
protected override void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
base.UpdateInventoryTemplate(ent);
if (TryComp(ent, out InventorySlotsComponent? inventorySlots))
{
foreach (var slot in ent.Comp.Slots)
{
if (inventorySlots.SlotData.TryGetValue(slot.Name, out var slotData))
slotData.SlotDef = slot;
}
}
}
public sealed class SlotData
{
public readonly SlotDefinition SlotDef;
public SlotDefinition SlotDef;
public EntityUid? HeldEntity => Container?.ContainedEntity;
public bool Blocked;
public bool Highlighted;

View File

@@ -14,6 +14,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
{
[Dependency] private readonly IPlayerManager _player = default!;
[ViewVariables]
protected bool IsActive;
protected virtual SlotFlags TargetSlots => ~SlotFlags.POCKET;
@@ -102,7 +103,7 @@ public abstract class EquipmentHudSystem<T> : EntitySystem where T : IComponent
args.Components.Add(component);
}
private void RefreshOverlay(EntityUid uid)
protected void RefreshOverlay(EntityUid uid)
{
if (uid != _player.LocalSession?.AttachedEntity)
return;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -146,8 +146,8 @@ namespace Content.Server.Abilities.Mime
mimePowers.ReadyToRepent = false;
mimePowers.VowBroken = false;
AddComp<MutedComponent>(uid);
_alertsSystem.ClearAlert(uid, mimePowers.VowAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowBrokenAlert);
_alertsSystem.ClearAlert(uid, mimePowers.VowBrokenAlert);
_alertsSystem.ShowAlert(uid, mimePowers.VowAlert);
_actionsSystem.AddAction(uid, ref mimePowers.InvisibleWallActionEntity, mimePowers.InvisibleWallAction, uid);
}
}

View File

@@ -22,6 +22,7 @@ using Content.Shared.Administration;
using Content.Shared.Administration.Components;
using Content.Shared.Body.Components;
using Content.Shared.Body.Part;
using Content.Shared.Clumsy;
using Content.Shared.Clothing.Components;
using Content.Shared.Cluwne;
using Content.Shared.Damage;

View File

@@ -1,27 +1,27 @@
using Content.Server.Administration.Components;
using Content.Shared.Climbing.Components;
using Content.Shared.Climbing.Events;
using Content.Shared.Climbing.Systems;
using Content.Shared.Interaction.Components;
using Content.Shared.Clumsy;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Robust.Shared.Audio.Systems;
namespace Content.Server.Administration.Systems;
public sealed class SuperBonkSystem: EntitySystem
public sealed class SuperBonkSystem : EntitySystem
{
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly BonkSystem _bonkSystem = default!;
[Dependency] private readonly ClumsySystem _clumsySystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
SubscribeLocalEvent<SuperBonkComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<SuperBonkComponent, ComponentShutdown>(OnBonkShutdown);
}
public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false )
public void StartSuperBonk(EntityUid target, float delay = 0.1f, bool stopWhenDead = false)
{
//The other check in the code to stop when the target dies does not work if the target is already dead.
@@ -31,7 +31,6 @@ public sealed class SuperBonkSystem: EntitySystem
return;
}
var hadClumsy = EnsureComp<ClumsyComponent>(target, out _);
var tables = EntityQueryEnumerator<BonkableComponent>();
@@ -79,16 +78,17 @@ public sealed class SuperBonkSystem: EntitySystem
private void Bonk(SuperBonkComponent comp)
{
var uid = comp.Tables.Current.Key;
var bonkComp = comp.Tables.Current.Value;
// It would be very weird for something without a transform component to have a bonk component
// but just in case because I don't want to crash the server.
if (!HasComp<TransformComponent>(uid))
if (!HasComp<TransformComponent>(uid) || !TryComp<ClumsyComponent>(comp.Target, out var clumsyComp))
return;
_transformSystem.SetCoordinates(comp.Target, Transform(uid).Coordinates);
_bonkSystem.TryBonk(comp.Target, uid, bonkComp);
_clumsySystem.HitHeadClumsy((comp.Target, clumsyComp), uid);
_audioSystem.PlayPvs(clumsyComp.TableBonkSound, comp.Target);
}
private void OnMobStateChanged(EntityUid uid, SuperBonkComponent comp, MobStateChangedEvent args)

View File

@@ -1,6 +1,7 @@
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.Hypospray.Events;
using Content.Shared.Chemistry;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
@@ -85,14 +86,44 @@ public sealed class HypospraySystem : SharedHypospraySystem
string? msgFormat = null;
if (target == user)
msgFormat = "hypospray-component-inject-self-message";
else if (EligibleEntity(user, EntityManager, component) && _interaction.TryRollClumsy(user, component.ClumsyFailChance))
// Self event
var selfEvent = new SelfBeforeHyposprayInjectsEvent(user, entity.Owner, target);
RaiseLocalEvent(user, selfEvent);
if (selfEvent.Cancelled)
{
msgFormat = "hypospray-component-inject-self-clumsy-message";
target = user;
_popup.PopupEntity(Loc.GetString(selfEvent.InjectMessageOverride ?? "hypospray-cant-inject", ("owner", Identity.Entity(target, EntityManager))), target, user);
return false;
}
target = selfEvent.TargetGettingInjected;
if (!EligibleEntity(target, EntityManager, component))
return false;
// Target event
var targetEvent = new TargetBeforeHyposprayInjectsEvent(user, entity.Owner, target);
RaiseLocalEvent(target, targetEvent);
if (targetEvent.Cancelled)
{
_popup.PopupEntity(Loc.GetString(targetEvent.InjectMessageOverride ?? "hypospray-cant-inject", ("owner", Identity.Entity(target, EntityManager))), target, user);
return false;
}
target = targetEvent.TargetGettingInjected;
if (!EligibleEntity(target, EntityManager, component))
return false;
// The target event gets priority for the overriden message.
if (targetEvent.InjectMessageOverride != null)
msgFormat = targetEvent.InjectMessageOverride;
else if (selfEvent.InjectMessageOverride != null)
msgFormat = selfEvent.InjectMessageOverride;
else if (target == user)
msgFormat = "hypospray-component-inject-self-message";
if (!_solutionContainers.TryGetSolution(uid, component.SolutionName, out var hypoSpraySoln, out var hypoSpraySolution) || hypoSpraySolution.Volume == 0)
{
_popup.PopupEntity(Loc.GetString("hypospray-component-empty-message"), target, user);

View File

@@ -16,6 +16,7 @@ using Content.Shared.Cluwne;
using Content.Shared.Interaction.Components;
using Robust.Shared.Audio.Systems;
using Content.Shared.NameModifier.EntitySystems;
using Content.Shared.Clumsy;
namespace Content.Server.Cluwne;

View File

@@ -77,7 +77,20 @@ public sealed class DefibrillatorSystem : EntitySystem
Zap(uid, target, args.User, component);
}
public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, DefibrillatorComponent? component = null)
/// <summary>
/// Checks if you can actually defib a target.
/// </summary>
/// <param name="uid">Uid of the defib</param>
/// <param name="target">Uid of the target getting defibbed</param>
/// <param name="user">Uid of the entity using the defibrillator</param>
/// <param name="component">Defib component</param>
/// <param name="targetCanBeAlive">
/// If true, the target can be alive. If false, the function will check if the target is alive and will return false if they are.
/// </param>
/// <returns>
/// Returns true if the target is valid to be defibed, false otherwise.
/// </returns>
public bool CanZap(EntityUid uid, EntityUid target, EntityUid? user = null, DefibrillatorComponent? component = null, bool targetCanBeAlive = false)
{
if (!Resolve(uid, ref component))
return false;
@@ -98,15 +111,25 @@ public sealed class DefibrillatorSystem : EntitySystem
if (!_powerCell.HasActivatableCharge(uid, user: user))
return false;
if (_mobState.IsAlive(target, mobState))
if (!targetCanBeAlive && _mobState.IsAlive(target, mobState))
return false;
if (!component.CanDefibCrit && _mobState.IsCritical(target, mobState))
if (!targetCanBeAlive && !component.CanDefibCrit && _mobState.IsCritical(target, mobState))
return false;
return true;
}
/// <summary>
/// Tries to start defibrillating the target. If the target is valid, will start the defib do-after.
/// </summary>
/// <param name="uid">Uid of the defib</param>
/// <param name="target">Uid of the target getting defibbed</param>
/// <param name="user">Uid of the entity using the defibrillator</param>
/// <param name="component">Defib component</param>
/// <returns>
/// Returns true if the defibrillation do-after started, otherwise false.
/// </returns>
public bool TryStartZap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null)
{
if (!Resolve(uid, ref component))
@@ -118,27 +141,44 @@ public sealed class DefibrillatorSystem : EntitySystem
_audio.PlayPvs(component.ChargeSound, uid);
return _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.DoAfterDuration, new DefibrillatorZapDoAfterEvent(),
uid, target, uid)
{
NeedHand = true,
BreakOnMove = !component.AllowDoAfterMovement
});
{
NeedHand = true,
BreakOnMove = !component.AllowDoAfterMovement
});
}
public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null, MobStateComponent? mob = null, MobThresholdsComponent? thresholds = null)
/// <summary>
/// Tries to defibrillate the target with the given defibrillator.
/// </summary>
public void Zap(EntityUid uid, EntityUid target, EntityUid user, DefibrillatorComponent? component = null)
{
if (!Resolve(uid, ref component) || !Resolve(target, ref mob, ref thresholds, false))
if (!Resolve(uid, ref component))
return;
// clowns zap themselves
if (HasComp<ClumsyComponent>(user) && user != target)
{
Zap(uid, user, user, component);
return;
}
if (!_powerCell.TryUseActivatableCharge(uid, user: user))
return;
var selfEvent = new SelfBeforeDefibrillatorZapsEvent(user, uid, target);
RaiseLocalEvent(user, selfEvent);
target = selfEvent.DefibTarget;
// Ensure thet new target is still valid.
if (selfEvent.Cancelled || !CanZap(uid, target, user, component, true))
return;
var targetEvent = new TargetBeforeDefibrillatorZapsEvent(user, uid, target);
RaiseLocalEvent(target, targetEvent);
target = targetEvent.DefibTarget;
if (targetEvent.Cancelled || !CanZap(uid, target, user, component, true))
return;
if (!TryComp<MobStateComponent>(target, out var mob) ||
!TryComp<MobThresholdsComponent>(target, out var thresholds))
return;
_audio.PlayPvs(component.ZapSound, uid);
_electrocution.TryDoElectrocution(target, null, component.ZapDamage, component.WritheDuration, true, ignoreInsulation: true);
component.NextZapTime = _timing.CurTime + component.ZapDelay;

View File

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

View File

@@ -2,6 +2,7 @@ using System.Linq;
using Content.Shared.Hands.Components;
using Content.Shared.Interaction.Components;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
namespace Content.Server.Silicons.Borgs;
@@ -300,6 +301,24 @@ public sealed partial class BorgSystem
return true;
}
/// <summary>
/// Check if a module can be removed from a borg.
/// </summary>
/// <param name="borg">The borg that the module is being removed from.</param>
/// <param name="module">The module to remove from the borg.</param>
/// <param name="user">The user attempting to remove the module.</param>
/// <returns>True if the module can be removed.</returns>
public bool CanRemoveModule(
Entity<BorgChassisComponent> borg,
Entity<BorgModuleComponent> module,
EntityUid? user = null)
{
if (module.Comp.DefaultModule)
return false;
return true;
}
/// <summary>
/// Installs and activates all modules currently inside the borg's module container
/// </summary>
@@ -369,4 +388,24 @@ public sealed partial class BorgSystem
var ev = new BorgModuleUninstalledEvent(uid);
RaiseLocalEvent(module, ref ev);
}
/// <summary>
/// Sets <see cref="BorgChassisComponent.MaxModules"/>.
/// </summary>
/// <param name="ent">The borg to modify.</param>
/// <param name="maxModules">The new max module count.</param>
public void SetMaxModules(Entity<BorgChassisComponent> ent, int maxModules)
{
ent.Comp.MaxModules = maxModules;
}
/// <summary>
/// Sets <see cref="BorgChassisComponent.ModuleWhitelist"/>.
/// </summary>
/// <param name="ent">The borg to modify.</param>
/// <param name="whitelist">The new module whitelist.</param>
public void SetModuleWhitelist(Entity<BorgChassisComponent> ent, EntityWhitelist? whitelist)
{
ent.Comp.ModuleWhitelist = whitelist;
}
}

View File

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

View File

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

View File

@@ -129,7 +129,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;
@@ -137,6 +137,19 @@ public sealed partial class BorgSystem : SharedBorgSystem
}
}
/// <summary>
/// Inserts a new module into a borg, the same as if a player inserted it manually.
/// </summary>
/// <para>
/// This does not run checks to see if the borg is actually allowed to be inserted, such as whitelists.
/// </para>
/// <param name="ent">The borg to insert into.</param>
/// <param name="module">The module to insert.</param>
public void InsertModule(Entity<BorgChassisComponent> ent, EntityUid module)
{
_container.Insert(module, ent.Comp.ModuleContainer);
}
// todo: consider transferring over the ghost role? managing that might suck.
protected override void OnInserted(EntityUid uid, BorgChassisComponent component, EntInsertedIntoContainerMessage args)
{

View File

@@ -1,15 +1,12 @@
using System.Linq;
using System.Numerics;
using Content.Server.Cargo.Systems;
using Content.Server.Interaction;
using Content.Server.Power.EntitySystems;
using Content.Server.Stunnable;
using Content.Server.Weapons.Ranged.Components;
using Content.Shared.Damage;
using Content.Shared.Damage.Systems;
using Content.Shared.Database;
using Content.Shared.Effects;
using Content.Shared.Interaction.Components;
using Content.Shared.Projectiles;
using Content.Shared.Weapons.Melee;
using Content.Shared.Weapons.Ranged;
@@ -33,16 +30,13 @@ public sealed partial class GunSystem : SharedGunSystem
[Dependency] private readonly IComponentFactory _factory = default!;
[Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly DamageExamineSystem _damageExamine = default!;
[Dependency] private readonly InteractionSystem _interaction = default!;
[Dependency] private readonly PricingSystem _pricing = default!;
[Dependency] private readonly SharedColorFlashEffectSystem _color = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly StaminaSystem _stamina = default!;
[Dependency] private readonly StunSystem _stun = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
private const float DamagePitchVariation = 0.05f;
public const float GunClumsyChance = 0.5f;
public override void Initialize()
{
@@ -71,26 +65,14 @@ public sealed partial class GunSystem : SharedGunSystem
{
userImpulse = true;
// Try a clumsy roll
// TODO: Who put this here
if (TryComp<ClumsyComponent>(user, out var clumsy) && gun.ClumsyProof == false)
if (user != null)
{
for (var i = 0; i < ammo.Count; i++)
var selfEvent = new SelfBeforeGunShotEvent(user.Value, (gunUid, gun), ammo);
RaiseLocalEvent(user.Value, selfEvent);
if (selfEvent.Cancelled)
{
if (_interaction.TryRollClumsy(user.Value, GunClumsyChance, clumsy))
{
// Wound them
Damageable.TryChangeDamage(user, clumsy.ClumsyDamage, origin: user);
_stun.TryParalyze(user.Value, TimeSpan.FromSeconds(3f), true);
// Apply salt to the wound ("Honk!")
Audio.PlayPvs(new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg"), gunUid);
Audio.PlayPvs(clumsy.ClumsySound, gunUid);
PopupSystem.PopupEntity(Loc.GetString("gun-clumsy"), user.Value);
userImpulse = false;
return;
}
userImpulse = false;
return;
}
}

View File

@@ -11,11 +11,6 @@ public sealed partial class HyposprayComponent : Component
[DataField]
public string SolutionName = "hypospray";
// TODO: This should be on clumsycomponent.
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float ClumsyFailChance = 0.5f;
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 TransferAmount = FixedPoint2.New(5);

View File

@@ -0,0 +1,38 @@
using Content.Shared.Inventory;
namespace Content.Shared.Chemistry.Hypospray.Events;
public abstract partial class BeforeHyposprayInjectsTargetEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public EntityUid EntityUsingHypospray;
public readonly EntityUid Hypospray;
public EntityUid TargetGettingInjected;
public string? InjectMessageOverride;
public BeforeHyposprayInjectsTargetEvent(EntityUid user, EntityUid hypospray, EntityUid target)
{
EntityUsingHypospray = user;
Hypospray = hypospray;
TargetGettingInjected = target;
InjectMessageOverride = null;
}
}
/// <summary>
/// This event is raised on the user using the hypospray before the hypospray is injected.
/// The event is triggered on the user and all their clothing.
/// </summary>
public sealed class SelfBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
{
public SelfBeforeHyposprayInjectsEvent(EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
}
/// <summary>
/// This event is raised on the target before the hypospray is injected.
/// The event is triggered on the target itself and all its clothing.
/// </summary>
public sealed class TargetBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
{
public TargetBeforeHyposprayInjectsEvent (EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
}

View File

@@ -1,5 +1,4 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Climbing.Components;
@@ -8,39 +7,18 @@ namespace Content.Shared.Climbing.Components;
/// Makes entity do damage and stun entities with ClumsyComponent
/// upon DragDrop or Climb interactions.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(Systems.BonkSystem))]
[RegisterComponent, NetworkedComponent]
public sealed partial class BonkableComponent : Component
{
/// <summary>
/// Chance of bonk triggering if the user is clumsy.
/// How long to stun players on bonk, in seconds.
/// </summary>
[DataField("bonkClumsyChance")]
public float BonkClumsyChance = 0.5f;
[DataField]
public TimeSpan BonkTime = TimeSpan.FromSeconds(2);
/// <summary>
/// Sound to play when bonking.
/// How much damage to apply on bonk.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkSound")]
public SoundSpecifier? BonkSound;
/// <summary>
/// How long to stun players on bonk, in seconds.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkTime")]
public float BonkTime = 2;
/// <summary>
/// How much damage to apply on bonk.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkDamage")]
[DataField]
public DamageSpecifier? BonkDamage;
/// <summary>
/// How long it takes to bonk.
/// </summary>
[DataField("bonkDelay")]
public float BonkDelay = 1.5f;
}

View File

@@ -0,0 +1,36 @@
using Content.Shared.Inventory;
using Content.Shared.Climbing.Components;
namespace Content.Shared.Climbing.Events;
public abstract partial class BeforeClimbEvent : CancellableEntityEventArgs
{
public readonly EntityUid GettingPutOnTable;
public readonly EntityUid PuttingOnTable;
public readonly Entity<ClimbableComponent> BeingClimbedOn;
public BeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn)
{
GettingPutOnTable = gettingPutOntable;
PuttingOnTable = puttingOnTable;
BeingClimbedOn = beingClimbedOn;
}
}
/// <summary>
/// This event is raised on the the person either getting put on or going on the table.
/// The event is also called on their clothing as well.
/// </summary>
public sealed class SelfBeforeClimbEvent : BeforeClimbEvent, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public SelfBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
}
/// <summary>
/// This event is raised on the thing being climbed on.
/// </summary>
public sealed class TargetBeforeClimbEvent : BeforeClimbEvent
{
public TargetBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
}

View File

@@ -1,130 +0,0 @@
using Content.Shared.CCVar;
using Content.Shared.Climbing.Components;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.DragDrop;
using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Serialization;
namespace Content.Shared.Climbing.Systems;
public sealed partial class BonkSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BonkableComponent, BonkDoAfterEvent>(OnBonkDoAfter);
SubscribeLocalEvent<BonkableComponent, AttemptClimbEvent>(OnAttemptClimb);
}
private void OnBonkDoAfter(EntityUid uid, BonkableComponent component, BonkDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Used == null)
return;
TryBonk(args.Args.Used.Value, uid, component, source: args.Args.User);
args.Handled = true;
}
public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bonkableComponent = null, EntityUid? source = null)
{
if (!Resolve(bonkableUid, ref bonkableComponent, false))
return false;
// BONK!
var userName = Identity.Entity(user, EntityManager);
var bonkableName = Identity.Entity(bonkableUid, EntityManager);
if (user == source)
{
// Non-local, non-bonking players
var othersMessage = Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName));
// Local, bonking player
var selfMessage = Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName));
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
}
else if (source != null)
{
// Local, non-bonking player (dragger)
_popupSystem.PopupClient(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, source.Value);
// Non-local, non-bonking players
_popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, Filter.Pvs(user).RemoveWhereAttachedEntity(e => e == user || e == source.Value), true);
// Non-local, bonking player
_popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName)), user, user);
}
if (source != null)
_audioSystem.PlayPredicted(bonkableComponent.BonkSound, bonkableUid, source);
else
_audioSystem.PlayPvs(bonkableComponent.BonkSound, bonkableUid);
_stunSystem.TryParalyze(user, TimeSpan.FromSeconds(bonkableComponent.BonkTime), true);
if (bonkableComponent.BonkDamage is { } bonkDmg)
_damageableSystem.TryChangeDamage(user, bonkDmg, true, origin: user);
return true;
}
private bool TryStartBonk(EntityUid uid, EntityUid user, EntityUid climber, BonkableComponent? bonkableComponent = null)
{
if (!Resolve(uid, ref bonkableComponent, false))
return false;
if (!HasComp<ClumsyComponent>(climber) || !HasComp<HandsComponent>(user))
return false;
if (!_cfg.GetCVar(CCVars.GameTableBonk))
{
// Not set to always bonk, try clumsy roll.
if (!_interactionSystem.TryRollClumsy(climber, bonkableComponent.BonkClumsyChance))
return false;
}
var doAfterArgs = new DoAfterArgs(EntityManager, user, bonkableComponent.BonkDelay, new BonkDoAfterEvent(), uid, target: uid, used: climber)
{
BreakOnMove = true,
BreakOnDamage = true,
DuplicateCondition = DuplicateConditions.SameTool | DuplicateConditions.SameTarget
};
return _doAfter.TryStartDoAfter(doAfterArgs);
}
private void OnAttemptClimb(EntityUid uid, BonkableComponent component, ref AttemptClimbEvent args)
{
if (args.Cancelled)
return;
if (TryStartBonk(uid, args.User, args.Climber, component))
args.Cancelled = true;
}
[Serializable, NetSerializable]
private sealed partial class BonkDoAfterEvent : SimpleDoAfterEvent
{
}
}

View File

@@ -251,6 +251,18 @@ public sealed partial class ClimbSystem : VirtualController
if (!Resolve(climbable, ref comp, false))
return;
var selfEvent = new SelfBeforeClimbEvent(uid, user, (climbable, comp));
RaiseLocalEvent(uid, selfEvent);
if (selfEvent.Cancelled)
return;
var targetEvent = new TargetBeforeClimbEvent(uid, user, (climbable, comp));
RaiseLocalEvent(climbable, targetEvent);
if (targetEvent.Cancelled)
return;
if (!ReplaceFixtures(uid, climbing, fixtures))
return;

View File

@@ -0,0 +1,61 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Clumsy;
/// <summary>
/// A simple clumsy tag-component.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ClumsyComponent : Component
{
// Standard options. Try to fit these in if you can!
/// <summary>
/// Sound to play when clumsy interactions fail.
/// </summary>
[DataField]
public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
/// <summary>
/// Default chance to fail a clumsy interaction.
/// If a system needs to use something else, add a new variable in the component, do not modify this percentage.
/// </summary>
[DataField, AutoNetworkedField]
public float ClumsyDefaultCheck = 0.5f;
/// <summary>
/// Default stun time.
/// If a system needs to use something else, add a new variable in the component, do not modify this number.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan ClumsyDefaultStunTime = TimeSpan.FromSeconds(2.5);
// Specific options
/// <summary>
/// Sound to play after hitting your head on a table. Ouch!
/// </summary>
[DataField]
public SoundCollectionSpecifier TableBonkSound = new SoundCollectionSpecifier("TrayHit");
/// <summary>
/// Stun time after failing to shoot a gun.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan GunShootFailStunTime = TimeSpan.FromSeconds(3);
/// <summary>
/// Stun time after failing to shoot a gun.
/// </summary>
[DataField, AutoNetworkedField]
public DamageSpecifier? GunShootFailDamage;
/// <summary>
/// Noise to play after failing to shoot a gun. Boom!
/// </summary>
[DataField]
public SoundSpecifier GunShootFailSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg");
}

View File

@@ -0,0 +1,146 @@
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Hypospray.Events;
using Content.Shared.Climbing.Components;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.IdentityManagement;
using Content.Shared.Medical;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared.Clumsy;
public sealed class ClumsySystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize()
{
SubscribeLocalEvent<ClumsyComponent, SelfBeforeHyposprayInjectsEvent>(BeforeHyposprayEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeDefibrillatorZapsEvent>(BeforeDefibrillatorZapsEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeGunShotEvent>(BeforeGunShotEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeClimbEvent>(OnBeforeClimbEvent);
}
// If you add more clumsy interactions add them in this section!
#region Clumsy interaction events
private void BeforeHyposprayEvent(Entity<ClumsyComponent> ent, ref SelfBeforeHyposprayInjectsEvent args)
{
// Clumsy people sometimes inject themselves! Apparently syringes are clumsy proof...
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
args.TargetGettingInjected = args.EntityUsingHypospray;
args.InjectMessageOverride = "hypospray-component-inject-self-clumsy-message";
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
}
private void BeforeDefibrillatorZapsEvent(Entity<ClumsyComponent> ent, ref SelfBeforeDefibrillatorZapsEvent args)
{
// Clumsy people sometimes defib themselves!
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
args.DefibTarget = args.EntityUsingDefib;
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
}
private void BeforeGunShotEvent(Entity<ClumsyComponent> ent, ref SelfBeforeGunShotEvent args)
{
// Clumsy people sometimes can't shoot :(
if (args.Gun.Comp.ClumsyProof)
return;
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
if (ent.Comp.GunShootFailDamage != null)
_damageable.TryChangeDamage(ent, ent.Comp.GunShootFailDamage, origin: ent);
_stun.TryParalyze(ent, ent.Comp.GunShootFailStunTime, true);
// Apply salt to the wound ("Honk!") (No idea what this comment means)
_audio.PlayPvs(ent.Comp.GunShootFailSound, ent);
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
_popup.PopupEntity(Loc.GetString("gun-clumsy"), ent, ent);
args.Cancel();
}
private void OnBeforeClimbEvent(Entity<ClumsyComponent> ent, ref SelfBeforeClimbEvent args)
{
// This event is called in shared, thats why it has all the extra prediction stuff.
var rand = new System.Random((int)_timing.CurTick.Value);
// If someone is putting you on the table, always get past the guard.
if (!_cfg.GetCVar(CCVars.GameTableBonk) && args.PuttingOnTable == ent.Owner && !rand.Prob(ent.Comp.ClumsyDefaultCheck))
return;
HitHeadClumsy(ent, args.BeingClimbedOn);
_audio.PlayPredicted(ent.Comp.ClumsySound, ent, ent);
_audio.PlayPredicted(ent.Comp.TableBonkSound, ent, ent);
var gettingPutOnTableName = Identity.Entity(args.GettingPutOnTable, EntityManager);
var puttingOnTableName = Identity.Entity(args.PuttingOnTable, EntityManager);
if (args.PuttingOnTable == ent.Owner)
{
// You are slamming yourself onto the table.
_popup.PopupPredicted(
Loc.GetString("bonkable-success-message-user", ("bonkable", args.BeingClimbedOn)),
Loc.GetString("bonkable-success-message-others", ("victim", gettingPutOnTableName), ("bonkable", args.BeingClimbedOn)),
ent,
ent);
}
else
{
// Someone else slamed you onto the table.
// This is only run in server so you need to use popup entity.
_popup.PopupPredicted(
Loc.GetString("forced-bonkable-success-message",
("bonker", puttingOnTableName),
("victim", gettingPutOnTableName),
("bonkable", args.BeingClimbedOn)),
ent,
null);
}
args.Cancel();
}
#endregion
#region Helper functions
/// <summary>
/// "Hits" an entites head against the given table.
/// </summary>
// Oh this fucntion is public le- NO!! This is only public for the one admin command if you use this anywhere else I will cry.
public void HitHeadClumsy(Entity<ClumsyComponent> target, EntityUid table)
{
var stunTime = target.Comp.ClumsyDefaultStunTime;
if (TryComp<BonkableComponent>(table, out var bonkComp))
{
stunTime = bonkComp.BonkTime;
if (bonkComp.BonkDamage != null)
_damageable.TryChangeDamage(target, bonkComp.BonkDamage, true);
}
_stun.TryParalyze(target, stunTime, true);
}
#endregion
}

View File

@@ -1,24 +0,0 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Interaction.Components;
/// <summary>
/// A simple clumsy tag-component.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ClumsyComponent : Component
{
/// <summary>
/// Damage dealt to a clumsy character when they try to fire a gun.
/// </summary>
[DataField(required: true), AutoNetworkedField]
public DamageSpecifier ClumsyDamage = default!;
/// <summary>
/// Sound to play when clumsy interactions fail.
/// </summary>
[DataField]
public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
}

View File

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

View File

@@ -1,26 +0,0 @@
using Content.Shared.Interaction.Components;
using Robust.Shared.Random;
namespace Content.Shared.Interaction
{
public partial class SharedInteractionSystem
{
public bool RollClumsy(ClumsyComponent component, float chance)
{
return component.Running && _random.Prob(chance);
}
/// <summary>
/// Rolls a probability chance for a "bad action" if the target entity is clumsy.
/// </summary>
/// <param name="entity">The entity that the clumsy check is happening for.</param>
/// <param name="chance">
/// The chance that a "bad action" happens if the user is clumsy, between 0 and 1 inclusive.
/// </param>
/// <returns>True if a "bad action" happened, false if the normal action should happen.</returns>
public bool TryRollClumsy(EntityUid entity, float chance, ClumsyComponent? component = null)
{
return Resolve(entity, ref component, false) && RollClumsy(component, chance);
}
}
}

View File

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

View File

@@ -1,4 +1,7 @@
using Content.Shared.Chat;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Hypospray.Events;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.Electrocution;
using Content.Shared.Explosion;
@@ -15,7 +18,7 @@ using Content.Shared.Slippery;
using Content.Shared.Strip.Components;
using Content.Shared.Temperature;
using Content.Shared.Verbs;
using Content.Shared.Chat;
using Content.Shared.Weapons.Ranged.Events;
namespace Content.Shared.Inventory;
@@ -33,6 +36,10 @@ public partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TargetBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
// by-ref events
SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);

View File

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

View File

@@ -0,0 +1,39 @@
using Content.Shared.Inventory;
namespace Content.Shared.Medical;
[ByRefEvent]
public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);
public abstract class BeforeDefibrillatorZapsEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public EntityUid EntityUsingDefib;
public readonly EntityUid Defib;
public EntityUid DefibTarget;
public BeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibTarget)
{
EntityUsingDefib = entityUsingDefib;
Defib = defib;
DefibTarget = defibTarget;
}
}
/// <summary>
/// This event is raised on the user using the defibrillator before is actually zaps someone.
/// The event is triggered on the user and all their clothing.
/// </summary>
public sealed class SelfBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
{
public SelfBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
}
/// <summary>
/// This event is raised on the target before it gets zapped with the defibrillator.
/// The event is triggered on the target itself and all its clothing.
/// </summary>
public sealed class TargetBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
{
public TargetBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
}

View File

@@ -1,4 +0,0 @@
namespace Content.Shared.Medical;
[ByRefEvent]
public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);

View File

@@ -9,12 +9,14 @@ namespace Content.Shared.Overlays;
/// This component allows you to see health bars above damageable mobs.
/// </summary>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(true)]
public sealed partial class ShowHealthBarsComponent : Component
{
/// <summary>
/// Displays health bars of the damage containers.
/// </summary>
[DataField]
[AutoNetworkedField]
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
{
"Biological"

View File

@@ -8,12 +8,14 @@ namespace Content.Shared.Overlays;
/// This component allows you to see health status icons above damageable mobs.
/// </summary>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(true)]
public sealed partial class ShowHealthIconsComponent : Component
{
/// <summary>
/// Displays health status icons of the damage containers.
/// </summary>
[DataField]
[AutoNetworkedField]
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
{
"Biological"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,20 @@
using Content.Shared.Inventory;
using Content.Shared.Weapons.Ranged.Components;
namespace Content.Shared.Weapons.Ranged.Events;
/// <summary>
/// This event is triggered on an entity right before they shoot a gun.
/// </summary>
public sealed partial class SelfBeforeGunShotEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public readonly EntityUid Shooter;
public readonly Entity<GunComponent> Gun;
public readonly List<(EntityUid? Entity, IShootable Shootable)> Ammo;
public SelfBeforeGunShotEvent(EntityUid shooter, Entity<GunComponent> gun, List<(EntityUid? Entity, IShootable Shootable)> ammo)
{
Shooter = shooter;
Gun = gun;
Ammo = ammo;
}
}

View File

@@ -605,5 +605,12 @@ Entries:
id: 75
time: '2024-11-13T23:27:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31751
- author: Beck Thompson
changes:
- message: Notes now use duration instead of timestamps for note expiry times.
type: Tweak
id: 76
time: '2024-11-15T03:24:27.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33262
Name: Admin
Order: 1

View File

@@ -1,56 +1,4 @@
Entries:
- author: Blackern5000
changes:
- message: Combat medical kits now contain saline syringes.
type: Add
id: 7108
time: '2024-08-14T06:25:54.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29954
- author: TheShuEd
changes:
- message: added morbilliard variants of procedural tacos and kebabs
type: Add
- message: removed all microwave taco and kebabs recipes (except for the taco shell
itself)
type: Remove
- message: you can fight with a skewer (even if it has food on it)
type: Tweak
- message: now you can't put more than 10 layers on a burger. (20 before)
type: Tweak
id: 7109
time: '2024-08-14T13:04:00.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30905
- author: themias
changes:
- message: Fixed lizards being unable to eat custom burgers
type: Fix
id: 7110
time: '2024-08-14T19:47:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31005
- author: Erisfiregamer1
changes:
- message: New chemical, Sedin. It restores seeds on plants 20% of the time with
other adverse effects included.
type: Add
id: 7111
time: '2024-08-15T00:38:24.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27110
- author: PoorMansDreams
changes:
- message: Added Star sticker in loadouts for Secoffs
type: Add
id: 7112
time: '2024-08-15T01:50:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29767
- author: FATFSAAM2
changes:
- message: added 7 new figurine voice lines.
type: Add
- message: changed a hos figurine voice line to not include a typo.
type: Fix
id: 7113
time: '2024-08-15T12:34:41.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30865
- author: to4no_fix
changes:
- message: Added a new electropack that shocks when a trigger is triggered
@@ -3941,3 +3889,57 @@
id: 7607
time: '2024-11-13T23:36:37.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33201
- author: CheddaCheez
changes:
- message: Fixed mimes being unable to break their vow more than once. Despicable!
type: Fix
id: 7608
time: '2024-11-14T16:56:22.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33303
- author: PJB3005
changes:
- message: Borgs can now select their chassis type upon creation (construction or
job spawn), immediately giving borgs access to all chassis types.
type: Add
- message: Borg chassis types now come with built-in modules depending on the type,
so you can immediately do your job without help from science. Some upgrade modules
must still be installed later however.
type: Add
- message: Specialized chassis types have been removed from construction, as they
are no longer necessary.
type: Remove
- message: Borg unlock access is no longer determined by their chassis, it's always
science or command. This means the janitor can't unlock jani borgs anymore.
type: Remove
id: 7609
time: '2024-11-14T17:08:35.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32586
- author: thetolbean
changes:
- message: The Quartermaster's requisition digi-board can no longer be recycled.
type: Fix
id: 7610
time: '2024-11-15T06:54:53.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33315
- author: RedBookcase
changes:
- message: Mixing up a Snow White no longer creates extra liquid out of thin air.
type: Fix
id: 7611
time: '2024-11-15T20:52:19.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33331
- author: lzk228
changes:
- message: Added 10 seconds delay to Succumb action
type: Add
id: 7612
time: '2024-11-15T21:21:08.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32985
- author: Beck Thompson
changes:
- message: Minor tweaks to clumsiness. Some of the timings and or noises have been
changed slightly!
type: Tweak
id: 7613
time: '2024-11-15T23:46:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31147

View File

@@ -57,13 +57,23 @@ admin-note-editor-severity-medium = Medium
admin-note-editor-severity-high = High
admin-note-editor-expiry-checkbox = Permanent?
admin-note-editor-expiry-checkbox-tooltip = Check this to make it expire
admin-note-editor-expiry-label = Expires on:
admin-note-editor-expiry-label = Expires in:
admin-note-editor-expiry-label-params = Expires on: {$date} (in {$expiresIn})
admin-note-editor-expiry-label-expired = Expired
admin-note-editor-expiry-placeholder = Enter expiration date (yyyy-MM-dd HH:mm:ss)
admin-note-editor-expiry-placeholder = Enter expiration time (integer).
admin-note-editor-submit = Submit
admin-note-editor-submit-confirm = Are you sure?
# Time
admin-note-button-minutes = Minutes
admin-note-button-hours = Hours
admin-note-button-days = Days
admin-note-button-weeks = Weeks
admin-note-button-months = Months
admin-note-button-years = Years
admin-note-button-centuries = Centuries
# Verb
admin-notes-verb-text = Open Admin Notes

View File

@@ -1,2 +1,4 @@
bonkable-success-message-others = { CAPITALIZE(THE($user)) } bonks { POSS-ADJ($user) } head against { THE($bonkable) }
bonkable-success-message-user = You bonk your head against { THE($bonkable) }
forced-bonkable-success-message = { CAPITALIZE($bonker) } bonks {$victim}s head against { THE($bonkable) }!
bonkable-success-message-user = You bonk your head against { THE($bonkable) }!
bonkable-success-message-others = {$victim} bonks their head against { THE($bonkable) }!

View File

@@ -25,3 +25,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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -586,7 +586,6 @@ entities:
2445: -41,19
2646: -33,-12
2665: -28,-14
2666: -23,-15
2667: -19,-23
2740: -20,-5
2794: 18,16
@@ -608,6 +607,7 @@ entities:
2979: -3,-48
3010: 12,14
3015: 2,-51
3114: -21,-15
- node:
angle: 1.5707963267948966 rad
color: '#FFFFFFFF'
@@ -1039,11 +1039,11 @@ entities:
color: '#52B4E996'
id: BrickTileWhiteCornerNw
decals:
2536: -23,-15
2544: -15,-15
2602: -19,-19
2630: -31,-16
2673: -16,-9
3119: -23,-15
- node:
color: '#DE3A3A96'
id: BrickTileWhiteCornerNw
@@ -1068,8 +1068,8 @@ entities:
color: '#FFFFFFFF'
id: BrickTileWhiteCornerNw
decals:
2533: -23,-15
2573: -19,-19
3118: -23,-15
- node:
color: '#52B4E996'
id: BrickTileWhiteCornerSe
@@ -4510,9 +4510,9 @@ entities:
color: '#52B4E996'
id: WarnLineGreyscaleN
decals:
2537: -22,-15
2605: -14,-19
2608: -14,-15
3115: -22,-15
- node:
color: '#D381C996'
id: WarnLineGreyscaleN
@@ -7544,6 +7544,16 @@ entities:
parent: 30
- proto: AirAlarm
entities:
- uid: 3167
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -23.5,-15.5
parent: 30
- type: DeviceList
devices:
- 9046
- 9049
- uid: 6224
components:
- type: Transform
@@ -7765,6 +7775,27 @@ entities:
- 18435
- 18436
- 18437
- uid: 18082
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -38.5,8.5
parent: 30
- type: DeviceList
devices:
- 3077
- 3076
- uid: 19145
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -35.5,-18.5
parent: 30
- type: DeviceList
devices:
- 6935
- 6920
- 22554
- uid: 19570
components:
- type: Transform
@@ -8808,6 +8839,26 @@ entities:
- 22084
- 3484
- 3481
- uid: 22553
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -23.5,-23.5
parent: 30
- type: DeviceList
devices:
- 6834
- 9713
- uid: 22555
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -31.5,-22.5
parent: 30
- type: DeviceList
devices:
- 7115
- 7119
- proto: AirAlarmElectronics
entities:
- uid: 15214
@@ -11906,6 +11957,14 @@ entities:
- type: Transform
pos: -2.5,8.5
parent: 30
- uid: 22554
components:
- type: Transform
pos: -34.5,-23.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 19145
- proto: AltarConvertRed
entities:
- uid: 17468
@@ -54920,11 +54979,11 @@ entities:
parent: 30
- proto: DefibrillatorCabinetFilled
entities:
- uid: 3167
- uid: 6956
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -23.5,-15.5
pos: -23.5,-14.5
parent: 30
- uid: 6970
components:
@@ -55583,6 +55642,12 @@ entities:
- type: Transform
pos: -19.5,-5.5
parent: 30
- uid: 6953
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -21.5,-14.5
parent: 30
- uid: 7412
components:
- type: Transform
@@ -55677,12 +55742,6 @@ entities:
rot: 1.5707963267948966 rad
pos: -19.5,-9.5
parent: 30
- uid: 7354
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -21.5,-14.5
parent: 30
- uid: 12233
components:
- type: Transform
@@ -59804,12 +59863,6 @@ entities:
rot: 3.141592653589793 rad
pos: -18.5,-22.5
parent: 30
- uid: 6956
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -22.5,-14.5
parent: 30
- uid: 6962
components:
- type: Transform
@@ -59821,6 +59874,12 @@ entities:
- type: Transform
pos: -19.5,-4.5
parent: 30
- uid: 7354
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -20.5,-14.5
parent: 30
- uid: 9753
components:
- type: Transform
@@ -60216,11 +60275,6 @@ entities:
- type: Transform
pos: -19.5,-4.5
parent: 30
- uid: 6953
components:
- type: Transform
pos: -22.5,-14.5
parent: 30
- uid: 6954
components:
- type: Transform
@@ -60296,6 +60350,11 @@ entities:
- type: Transform
pos: 14.5,-17.5
parent: 30
- uid: 19150
components:
- type: Transform
pos: -20.5,-14.5
parent: 30
- uid: 19407
components:
- type: Transform
@@ -86755,6 +86814,9 @@ entities:
- type: Transform
pos: -40.5,10.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 18082
- type: AtmosPipeColor
color: '#0000FFFF'
- uid: 3099
@@ -87044,6 +87106,9 @@ entities:
rot: 3.141592653589793 rad
pos: -25.5,-22.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 22553
- type: AtmosPipeColor
color: '#0000FFFF'
- uid: 6900
@@ -87060,6 +87125,9 @@ entities:
rot: 1.5707963267948966 rad
pos: -33.5,-16.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 19145
- type: AtmosPipeColor
color: '#0000FFFF'
- uid: 6939
@@ -87086,6 +87154,9 @@ entities:
- type: Transform
pos: -28.5,-20.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 22555
- type: AtmosPipeColor
color: '#0000FFFF'
- uid: 7136
@@ -87232,6 +87303,9 @@ entities:
- type: Transform
pos: -25.5,-15.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 3167
- type: AtmosPipeColor
color: '#0000FFFF'
- uid: 9686
@@ -88266,6 +88340,9 @@ entities:
rot: 1.5707963267948966 rad
pos: -39.5,10.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 18082
- type: AtmosPipeColor
color: '#FF0000FF'
- uid: 3100
@@ -88548,6 +88625,9 @@ entities:
rot: 1.5707963267948966 rad
pos: -33.5,-18.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 19145
- type: AtmosPipeColor
color: '#FF0000FF'
- uid: 7098
@@ -88577,6 +88657,9 @@ entities:
rot: 3.141592653589793 rad
pos: -28.5,-18.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 22555
- type: AtmosPipeColor
color: '#FF0000FF'
- uid: 7130
@@ -88714,6 +88797,9 @@ entities:
- type: Transform
pos: -25.5,-16.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 3167
- type: AtmosPipeColor
color: '#FF0000FF'
- uid: 9713
@@ -88722,6 +88808,9 @@ entities:
rot: 3.141592653589793 rad
pos: -25.5,-23.5
parent: 30
- type: DeviceNetwork
deviceLists:
- 22553
- type: AtmosPipeColor
color: '#FF0000FF'
- uid: 9793

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -12,6 +12,8 @@
sprite: Mobs/Ghosts/ghost_human.rsi
state: icon
event: !type:CritSuccumbEvent
startDelay: true
useDelay: 10
- type: entity
id: ActionCritFakeDeath
@@ -41,3 +43,5 @@
sprite: Interface/Actions/actions_crit.rsi
state: lastwords
event: !type:CritLastWordsEvent
startDelay: true
useDelay: 10

View File

@@ -28,82 +28,105 @@
- Robotics
- type: entity
id: BaseBorgArmLeft
id: LeftArmBorg
parent: PartSilicon
name: cyborg left arm
abstract: true
components:
- type: BodyPart
partType: Hand
symmetry: Left
- type: Sprite
state: borg_l_arm
- type: Icon
state: borg_l_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgLArm
- type: entity
id: BaseBorgArmRight
id: RightArmBorg
parent: PartSilicon
name: cyborg right arm
abstract: true
components:
- type: BodyPart
partType: Hand
symmetry: Right
- type: Sprite
state: borg_r_arm
- type: Icon
state: borg_r_arm
- type: Tag
tags:
- Trash
- BorgArm
- BorgRArm
- type: entity
id: BaseBorgLegLeft
id: LeftLegBorg
parent: PartSilicon
name: cyborg left leg
abstract: true
components:
- type: BodyPart
partType: Leg
symmetry: Left
- type: Sprite
state: borg_l_leg
- type: Icon
state: borg_l_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgLLeg
- type: entity
id: BaseBorgLegRight
id: RightLegBorg
parent: PartSilicon
name: cyborg right leg
abstract: true
components:
- type: BodyPart
partType: Leg
symmetry: Right
- type: Sprite
state: borg_r_leg
- type: Icon
state: borg_r_leg
- type: Tag
tags:
- Trash
- BorgLeg
- BorgRLeg
- 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
- type: Tag
tags:
- Trash
- 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
- type: Tag
tags:
- Trash
- BorgTorso

View File

@@ -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
@@ -157,6 +160,7 @@
collection: FootstepBorg
- type: Construction
graph: Cyborg
node: cyborg
containers:
- part-container
- cell_slot
@@ -285,6 +289,9 @@
- type: AccessReader
access: [["Command"], ["Research"]]
- type: ShowJobIcons
- type: InteractionPopup
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: entity
id: BaseBorgChassisSyndicate

View File

@@ -1,23 +1,22 @@
- type: entity
id: BorgChassisGeneric
id: BorgChassisSelectable
parent: BaseBorgChassisNT
components:
- type: Sprite
layers:
- state: robot
map: ["enum.BorgVisualLayers.Body", "movement"]
- state: robot_e_r
map: ["enum.BorgVisualLayers.Light"]
shader: unshaded
visible: false
- state: robot_l
shader: unshaded
map: ["light"]
map: ["light","enum.BorgVisualLayers.LightStatus"]
visible: false
- type: BorgChassis
maxModules: 6
moduleWhitelist:
tags:
- BorgModuleGeneric
# Default borg can take no modules until selected type.
maxModules: 0
hasMindState: robot_e
noMindState: robot_e_r
- type: BorgTransponder
@@ -25,308 +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
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- 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: InteractionPopup
interactSuccessString: petting-success-salvage-cyborg
interactFailureString: petting-failure-salvage-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- 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: InteractionPopup
interactSuccessString: petting-success-engineer-cyborg
interactFailureString: petting-failure-engineer-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- 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: InteractionPopup
interactSuccessString: petting-success-janitor-cyborg
interactFailureString: petting-failure-janitor-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: BorgSwitchableType
selectedBorgType: janitor
- type: entity
id: BorgChassisMedical
parent: [BaseBorgChassisNT, ShowMedicalIcons]
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: 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: InteractionPopup
interactSuccessString: petting-success-service-cyborg
interactFailureString: petting-failure-service-cyborg
interactSuccessSound:
path: /Audio/Ambience/Objects/periodic_beep.ogg
- type: BorgSwitchableType
selectedBorgType: service
- type: entity
id: BorgChassisSyndicateAssault
@@ -354,8 +107,6 @@
- BorgModuleSyndicateAssault
hasMindState: synd_sec_e
noMindState: synd_sec
- type: Construction
node: syndicateassault
- type: InteractionPopup
interactSuccessString: petting-success-syndicate-cyborg
interactFailureString: petting-failure-syndicate-cyborg
@@ -388,8 +139,6 @@
- BorgModuleSyndicate
hasMindState: synd_medical_e
noMindState: synd_medical
- type: Construction
node: syndicatemedical
- type: ShowHealthBars
- type: InteractionPopup
interactSuccessString: petting-success-syndicate-cyborg
@@ -429,8 +178,6 @@
- BorgModuleSyndicate
hasMindState: synd_engi_e
noMindState: synd_engi
- type: Construction
node: syndicatesaboteur
- type: ShowHealthBars
damageContainers:
- Inorganic

View File

@@ -1360,7 +1360,7 @@
rules: ghost-role-information-nonantagonist-rules
- type: GhostTakeoverAvailable
- type: Clumsy
clumsyDamage:
gunShootFailDamage:
types:
Blunt: 5
Piercing: 4
@@ -1536,7 +1536,7 @@
description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death.
components:
- type: Clumsy
clumsyDamage:
gunShootFailDamage:
types:
Blunt: 2
Piercing: 7

View File

@@ -231,7 +231,7 @@
- type: Hands
- type: ComplexInteraction
- type: Clumsy
clumsyDamage:
gunShootFailDamage:
types:
Blunt: 5
Piercing: 4

View File

@@ -429,28 +429,9 @@
map: ["base"]
# Borgs
- type: entity
id: PlayerBorgGeneric
parent: BorgChassisGeneric
suffix: Battery, Tools
components:
- 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: ContainerFill

View File

@@ -597,6 +597,10 @@
damage:
types:
Blunt: 10
- type: Tag
tags:
- Folder
- HighRiskItem
- type: StealTarget
stealGroup: BoxFolderQmClipboard

View File

@@ -126,6 +126,9 @@
state: icon
- type: Item
size: Large
storedSprite:
state: storage
sprite: Objects/Weapons/Melee/gorilla.rsi
- type: MeleeWeapon
attackRate: 0.5
angle: 0
@@ -134,6 +137,8 @@
damage:
types:
Blunt: 20
soundHit:
path: "/Audio/Weapons/Guns/Gunshots/kinetic_accel.ogg"
- type: CorePoweredThrower
- type: MeleeThrowOnHit
unanchorOnHit: true

View File

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

View File

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

View File

@@ -60,6 +60,7 @@
maxCount: 2
stationGrid: false
paths:
- /Maps/Ruins/abandoned_outpost.yml
- /Maps/Ruins/chunked_tcomms.yml
- /Maps/Ruins/biodome_satellite.yml
- /Maps/Ruins/derelict.yml

View File

@@ -104,6 +104,28 @@
- type: Wires
layoutId: AirlockEngineering
- type: entity
parent: AirlockExternal
id: AirlockExternalCommandLocked
suffix: External, Command, Locked
components:
- type: ContainerFill
containers:
board: [ DoorElectronicsCommand ]
- type: Wires
layoutId: AirlockCommand
- type: entity
parent: AirlockExternalGlass
id: AirlockExternalGlassCommandLocked
suffix: External, Glass, Command, Locked
components:
- type: ContainerFill
containers:
board: [ DoorElectronicsCommand ]
- type: Wires
layoutId: AirlockCommand
- type: entity
parent: AirlockExternal
id: AirlockExternalAtmosphericsLocked

View File

@@ -32,8 +32,6 @@
bonkDamage:
types:
Blunt: 4
bonkSound: !type:SoundCollectionSpecifier
collection: TrayHit
- type: Clickable
- type: FootstepModifier
footstepSoundCollection:

View File

@@ -572,11 +572,6 @@
- BorgModuleFireExtinguisher
- BorgModuleRadiationDetection
- BorgModuleTool
- BorgModuleAppraisal
- BorgModuleConstruction
- BorgModuleService
- BorgModuleTreatment
- BorgModuleCleaning
- CyborgEndoskeleton
- LeftArmBorg
- RightArmBorg
@@ -584,50 +579,15 @@
- 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
dynamicRecipes:
- ProximitySensor
- BorgModuleLightReplacer
- BorgModuleAdvancedCleaning
- BorgModuleMining
- BorgModuleGrapplingGun
- BorgModuleAdvancedTool
- BorgModuleGPS
- BorgModuleRCD
- BorgModuleArtifact
- BorgModuleAnomaly
- BorgModuleGardening
- BorgModuleHarvesting
- BorgModuleMusique
- BorgModuleClowning
- BorgModuleDiagnosis
- BorgModuleDefibrillator
- BorgModuleAdvancedTreatment
- RipleyHarness

View File

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

View File

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

View File

@@ -61,8 +61,6 @@
materials:
Steel: 1500
# Generic
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorg
@@ -93,162 +91,6 @@
id: TorsoBorg
result: TorsoBorg
# Engineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorgEngineer
result: LeftArmBorgEngineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightArmBorgEngineer
result: RightArmBorgEngineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorgEngineer
result: LeftLegBorgEngineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorgEngineer
result: RightLegBorgEngineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: HeadBorgEngineer
result: HeadBorgEngineer
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorgEngineer
result: TorsoBorgEngineer
# Medical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorgMedical
result: LeftArmBorgMedical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightArmBorgMedical
result: RightArmBorgMedical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorgMedical
result: LeftLegBorgMedical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorgMedical
result: RightLegBorgMedical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: HeadBorgMedical
result: HeadBorgMedical
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorgMedical
result: TorsoBorgMedical
# Mining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorgMining
result: LeftArmBorgMining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightArmBorgMining
result: RightArmBorgMining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorgMining
result: LeftLegBorgMining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorgMining
result: RightLegBorgMining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: HeadBorgMining
result: HeadBorgMining
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorgMining
result: TorsoBorgMining
# Service
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftArmBorgService
result: LeftArmBorgService
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightArmBorgService
result: RightArmBorgService
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorgService
result: LeftLegBorgService
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorgService
result: RightLegBorgService
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: HeadBorgService
result: HeadBorgService
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorgService
result: TorsoBorgService
# Janitor
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: LeftLegBorgJanitor
result: LeftLegBorgJanitor
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: RightLegBorgJanitor
result: RightLegBorgJanitor
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: HeadBorgJanitor
result: HeadBorgJanitor
materials:
Steel: 500
Glass: 200
- type: latheRecipe
parent: BaseBorgLimbRecipe
id: TorsoBorgJanitor
result: TorsoBorgJanitor
materials:
Steel: 500
Glass: 200
# Parts
- type: latheRecipe
@@ -304,23 +146,6 @@
id: BorgModuleTool
result: BorgModuleTool
# Mining Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleAppraisal
result: BorgModuleAppraisal
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleMining
result: BorgModuleMining
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleGrapplingGun
result: BorgModuleGrapplingGun
# Engineering Modules
- type: latheRecipe
@@ -328,28 +153,8 @@
id: BorgModuleAdvancedTool
result: BorgModuleAdvancedTool
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleConstruction
result: BorgModuleConstruction
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleRCD
result: BorgModuleRCD
# Janitor Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleLightReplacer
result: BorgModuleLightReplacer
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleCleaning
result: BorgModuleCleaning
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleAdvancedCleaning
@@ -357,16 +162,6 @@
# Medical Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleDiagnosis
result: BorgModuleDiagnosis
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleTreatment
result: BorgModuleTreatment
- type: latheRecipe
parent: BaseGoldBorgModuleRecipe
id: BorgModuleAdvancedTreatment
@@ -391,16 +186,6 @@
# Service Modules
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleService
result: BorgModuleService
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleMusique
result: BorgModuleMusique
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleGardening
@@ -410,8 +195,3 @@
parent: BaseBorgModuleRecipe
id: BorgModuleHarvesting
result: BorgModuleHarvesting
- type: latheRecipe
parent: BaseBorgModuleRecipe
id: BorgModuleClowning
result: BorgModuleClowning

View File

@@ -953,7 +953,7 @@
LemonLime:
amount: 1
products:
SnowWhite: 3
SnowWhite: 2
- type: reaction
id: SodaWater

View File

@@ -66,8 +66,6 @@
recipeUnlocks:
- ComputerTelevisionCircuitboard
- SynthesizerInstrument
- BorgModuleMusique
- BorgModuleClowning
- DawInstrumentMachineCircuitboard
- MassMediaCircuitboard
- JukeboxCircuitBoard
@@ -82,7 +80,6 @@
tier: 1
cost: 5000
recipeUnlocks:
- BorgModuleLightReplacer
- BorgModuleAdvancedCleaning
- type: technology

View File

@@ -12,8 +12,6 @@
recipeUnlocks:
- MiningDrill
- MineralScannerEmpty
- BorgModuleMining
- BorgModuleGrapplingGun
- OreProcessorIndustrialMachineCircuitboard
- ClothingMaskWeldingGas
@@ -168,7 +166,6 @@
- PowerDrill
- JawsOfLife
- BorgModuleAdvancedTool
- BorgModuleRCD
- type: technology
id: MassExcavation

View File

@@ -18,7 +18,6 @@
weight: 10
startingGear: QuartermasterGear
icon: "JobIconQuarterMaster"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -13,7 +13,7 @@
- !type:AddComponentSpecial
components:
- type: Clumsy
clumsyDamage:
gunShootFailDamage:
types: #literally just picked semi random valus. i tested this once and tweaked it.
Blunt: 5
Piercing: 4

View File

@@ -19,7 +19,6 @@
weight: 20
startingGear: CaptainGear
icon: "JobIconCaptain"
requireAdminNotify: true
joinNotifyCrew: true
supervisors: job-supervisors-centcom
canBeAntag: false

View File

@@ -19,7 +19,6 @@
weight: 20
startingGear: HoPGear
icon: "JobIconHeadOfPersonnel"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -18,7 +18,6 @@
weight: 10
startingGear: ChiefEngineerGear
icon: "JobIconChiefEngineer"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -20,7 +20,6 @@
weight: 10
startingGear: CMOGear
icon: "JobIconChiefMedicalOfficer"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -25,5 +25,5 @@
canBeAntag: false
icon: JobIconBorg
supervisors: job-supervisors-rd
jobEntity: PlayerBorgGeneric
jobEntity: PlayerBorgBattery
applyTraits: false

View File

@@ -12,7 +12,6 @@
weight: 10
startingGear: ResearchDirectorGear
icon: "JobIconResearchDirector"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -18,7 +18,6 @@
weight: 10
startingGear: HoSGear
icon: "JobIconHeadOfSecurity"
requireAdminNotify: true
supervisors: job-supervisors-captain
canBeAntag: false
access:

View File

@@ -9,7 +9,6 @@
time: 36000 #10 hrs
startingGear: WardenGear
icon: "JobIconWarden"
requireAdminNotify: true
supervisors: job-supervisors-hos
canBeAntag: false
access:

View File

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

Some files were not shown because too many files have changed in this diff Show More