Merge remote-tracking branch 'refs/remotes/upstream/master' into upstream-sync

# Conflicts:
#	Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml
#	Resources/Prototypes/StatusEffects/health.yml
#	Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png
#	Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/equipped-INNERCLOTHING.png
#	Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/icon.png
#	Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_officer.rsi/meta.json
This commit is contained in:
Morb0 2024-05-11 01:41:28 +03:00
commit d6403daf00
209 changed files with 36931 additions and 22164 deletions

View file

@ -0,0 +1,119 @@
using System;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.Chemistry.UI;
/// <summary>
/// Creates a grid of buttons given a comma-seperated list of Text
/// </summary>
public sealed class ButtonGrid : GridContainer
{
private string _buttonList = "";
/// <summary>
/// A comma-seperated list of text to use for each button. These will be inserted sequentially.
/// </summary>
public string ButtonList
{
get => _buttonList;
set
{
_buttonList = value;
Update();
}
}
public bool RadioGroup { get; set; } = false;
private string? _selected;
/// <summary>
/// Which button is currently selected. Only matters when <see cref="RadioGroup"/> is true.
/// </summary>
public string? Selected
{
get => _selected;
set
{
_selected = value;
Update();
}
}
public Action<string>? OnButtonPressed;
/// <summary>
/// <see cref="GridContainer.Columns"/>
/// </summary>
public new int Columns
{
get => base.Columns;
set
{
base.Columns = value;
Update();
}
}
/// <summary>
/// <see cref="GridContainer.Rows"/>
/// </summary>
public new int Rows
{
get => base.Rows;
set
{
base.Rows = value;
Update();
}
}
private void Update()
{
if (ButtonList == "")
return;
this.Children.Clear();
var i = 0;
var list = ButtonList.Split(",");
var group = new ButtonGroup();
foreach (var button in list)
{
var btn = new Button();
btn.Text = button;
btn.OnPressed += _ =>
{
if (RadioGroup)
btn.Pressed = true;
Selected = button;
OnButtonPressed?.Invoke(button);
};
if (button == Selected)
btn.Pressed = true;
var sep = HSeparationOverride ?? 0;
// ReSharper disable once PossibleLossOfFraction
// btn.SetWidth = (this.PixelWidth - sep * (Columns - 1)) / 3;
btn.Group = group;
var row = i / Columns;
var col = i % Columns;
var last = i == list.Length - 1;
var lastCol = i == Columns - 1;
var lastRow = row == list.Length / Columns - 1;
if (row == 0 && (lastCol || last))
btn.AddStyleClass("OpenLeft");
else if (col == 0 && lastRow)
btn.AddStyleClass("OpenRight");
else
btn.AddStyleClass("OpenBoth");
this.Children.Add(btn);
i++;
}
}
}

View file

@ -0,0 +1,37 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Name="MainContainer"
Orientation="Horizontal"
SetWidth="160">
<PanelContainer Name="ColorPanel"
VerticalExpand="True"
SetWidth="7"
Margin="0 1 0 0" />
<Button Name="MainButton"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="ButtonSquare"
Margin="-1 0 0 0">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Margin="-5 0 0 0">
<Label Name="ReagentNameLabel"
StyleClasses="LabelSubText" />
<Label Name="FillLabel"
StyleClasses="LabelSubText"
Margin="0 -5 0 0" />
</BoxContainer>
</BoxContainer>
</Button>
<Button Name="EjectButton"
StyleClasses="OpenLeft"
VerticalExpand="True"
SetWidth="20">
<Label Name="EjectButtonIcon"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Margin="-7 -4 0 0" />
</Button>
</BoxContainer>
</Control>

View file

@ -0,0 +1,30 @@
using Content.Shared.Chemistry;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Chemistry.UI;
[GenerateTypedNameReferences]
public sealed partial class ReagentCardControl : Control
{
public string StorageSlotId { get; }
public Action<string>? OnPressed;
public Action<string>? OnEjectButtonPressed;
public ReagentCardControl(ReagentInventoryItem item)
{
RobustXamlLoader.Load(this);
StorageSlotId = item.StorageSlotId;
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
ReagentNameLabel.Text = item.ReagentLabel;
ReagentNameLabel.FontColorOverride = Color.White;
FillLabel.Text = item.StoredAmount;
EjectButtonIcon.Text = Loc.GetString("reagent-dispenser-window-eject-container-button");
MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId);
EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId);
}
}

View file

@ -42,38 +42,11 @@ namespace Content.Client.Chemistry.UI
// Setup static button actions.
_window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName));
_window.ClearButton.OnPressed += _ => SendMessage(new ReagentDispenserClearContainerSolutionMessage());
_window.DispenseButton1.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U1));
_window.DispenseButton5.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U5));
_window.DispenseButton10.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U10));
_window.DispenseButton15.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U15));
_window.DispenseButton20.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U20));
_window.DispenseButton25.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U25));
_window.DispenseButton30.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U30));
_window.DispenseButton50.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U50));
_window.DispenseButton100.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U100));
// Setup reagent button actions.
_window.OnDispenseReagentButtonPressed += (args, button) => SendMessage(new ReagentDispenserDispenseReagentMessage(button.ReagentId));
_window.OnDispenseReagentButtonMouseEntered += (args, button) =>
{
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState);
};
_window.OnDispenseReagentButtonMouseExited += (args, button) =>
{
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState);
};
_window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s));
_window.OnEjectJugButtonPressed += (args, button) => SendMessage(new ItemSlotButtonPressedEvent(button.ReagentId));
_window.OnEjectJugButtonMouseEntered += (args, button) => {
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState);
};
_window.OnEjectJugButtonMouseExited += (args, button) => {
if (_lastState is not null)
_window.UpdateContainerInfo(_lastState);
};
_window.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id));
_window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id));
}
/// <summary>

View file

@ -1,53 +1,77 @@
<DefaultWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
MinSize="680 450">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}"/>
<Control MinSize="20 0"></Control>
<Button Name="DispenseButton1" Access="Public" Text="1" StyleClasses="OpenRight"/>
<Button Name="DispenseButton5" Access="Public" Text="5" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton10" Access="Public" Text="10" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton15" Access="Public" Text="15" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton20" Access="Public" Text="20" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton25" Access="Public" Text="25" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton30" Access="Public" Text="30" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton50" Access="Public" Text="50" StyleClasses="OpenBoth"/>
<Button Name="DispenseButton100" Access="Public" Text="100" StyleClasses="OpenLeft"/>
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
xmlns:ui="clr-namespace:Content.Client.Chemistry.UI"
Title="{Loc 'reagent-dispenser-bound-user-interface-title'}"
MinSize="680 460">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" MinWidth="170">
<Label Text="{Loc 'reagent-dispenser-window-amount-to-dispense-label'}" HorizontalAlignment="Center" />
<ui:ButtonGrid
Name="AmountGrid"
Access="Public"
Columns="3"
HorizontalAlignment="Center"
Margin="5"
ButtonList="1,5,10,15,20,25,30,50,100"
RadioGroup="True">
</ui:ButtonGrid>
<Control VerticalExpand="True" />
<Label Name="ContainerInfoName"
Access="Public"
Text=""
HorizontalAlignment="Center" />
<Label Name="ContainerInfoFill"
Access="Public"
Text=""
HorizontalAlignment="Center"
StyleClasses="LabelSubText" />
<SpriteView Name="View"
Scale="4 4"
HorizontalAlignment="Center" />
<BoxContainer Orientation="Horizontal" HorizontalAlignment="Center">
<Button Name="ClearButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-clear-button'}"
StyleClasses="OpenRight" />
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-eject-button'}"
StyleClasses="OpenLeft" />
</BoxContainer>
</BoxContainer>
<Control MinSize="0 10"/>
<GridContainer Name="ChemicalList" HorizontalExpand="True" VerticalExpand="True" Access="Public" Columns="6">
</GridContainer>
<Control MinSize="0 10"/>
<BoxContainer Orientation="Horizontal">
<Label Text="{Loc 'reagent-dispenser-window-container-label'}"/>
<Button Name="ClearButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-clear-button'}"
StyleClasses="OpenRight"/>
<Button Name="EjectButton"
Access="Public"
Text="{Loc 'reagent-dispenser-window-eject-button'}"
StyleClasses="OpenLeft"/>
</BoxContainer>
<Control MinSize="0 10"/>
<BoxContainer Orientation="Horizontal">
<SpriteView Name="View" Scale="4 4" MinSize="150 150"/>
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True" MinSize="0 160">
<PanelContainer VerticalExpand="True"
SizeFlagsStretchRatio="6"
MinSize="0 150">
<SplitContainer Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True">
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True"
MinHeight="50"
SizeFlagsStretchRatio="2.5">
<GridContainer Name="ReagentList"
HorizontalExpand="True"
VerticalExpand="True"
Access="Public"
Columns="3" />
</ScrollContainer>
<ScrollContainer HScrollEnabled="False"
HorizontalExpand="True"
VerticalExpand="True"
MinHeight="50">
<PanelContainer VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1b1b1e" />
</PanelContainer.PanelOverride>
<BoxContainer Name="ContainerInfo"
Orientation="Vertical"
HorizontalExpand="True">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}"/>
Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True"
Margin="5">
<Label Text="{Loc 'reagent-dispenser-window-no-container-loaded-text'}" />
</BoxContainer>
</PanelContainer>
</ScrollContainer>
</BoxContainer>
</SplitContainer>
</BoxContainer>
</DefaultWindow>
</controls:FancyWindow>

View file

@ -1,10 +1,9 @@
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BoxContainer;
@ -15,17 +14,12 @@ namespace Content.Client.Chemistry.UI
/// Client-side UI used to control a <see cref="ReagentDispenserComponent"/>.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class ReagentDispenserWindow : DefaultWindow
public sealed partial class ReagentDispenserWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public event Action<BaseButton.ButtonEventArgs, DispenseReagentButton>? OnDispenseReagentButtonPressed;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseEntered;
public event Action<GUIMouseHoverEventArgs, DispenseReagentButton>? OnDispenseReagentButtonMouseExited;
public event Action<BaseButton.ButtonEventArgs, EjectJugButton>? OnEjectJugButtonPressed;
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseEntered;
public event Action<GUIMouseHoverEventArgs, EjectJugButton>? OnEjectJugButtonMouseExited;
public event Action<string>? OnDispenseReagentButtonPressed;
public event Action<string>? OnEjectJugButtonPressed;
/// <summary>
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
@ -35,44 +29,27 @@ namespace Content.Client.Chemistry.UI
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var dispenseAmountGroup = new ButtonGroup();
DispenseButton1.Group = dispenseAmountGroup;
DispenseButton5.Group = dispenseAmountGroup;
DispenseButton10.Group = dispenseAmountGroup;
DispenseButton15.Group = dispenseAmountGroup;
DispenseButton20.Group = dispenseAmountGroup;
DispenseButton25.Group = dispenseAmountGroup;
DispenseButton30.Group = dispenseAmountGroup;
DispenseButton50.Group = dispenseAmountGroup;
DispenseButton100.Group = dispenseAmountGroup;
}
/// <summary>
/// Update the button grid of reagents which can be dispensed.
/// </summary>
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
public void UpdateReagentsList(List<KeyValuePair<string, KeyValuePair<string, string>>> inventory)
public void UpdateReagentsList(List<ReagentInventoryItem> inventory)
{
if (ChemicalList == null)
if (ReagentList == null)
return;
ChemicalList.Children.Clear();
ReagentList.Children.Clear();
//Sort inventory by reagentLabel
inventory.Sort((x, y) => x.Value.Key.CompareTo(y.Value.Key));
inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel));
foreach (KeyValuePair<string, KeyValuePair<string, string>> entry in inventory)
foreach (var item in inventory)
{
var button = new DispenseReagentButton(entry.Key, entry.Value.Key, entry.Value.Value);
button.OnPressed += args => OnDispenseReagentButtonPressed?.Invoke(args, button);
button.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button);
button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button);
ChemicalList.AddChild(button);
var ejectButton = new EjectJugButton(entry.Key);
ejectButton.OnPressed += args => OnEjectJugButtonPressed?.Invoke(args, ejectButton);
ejectButton.OnMouseEntered += args => OnEjectJugButtonMouseEntered?.Invoke(args, ejectButton);
ejectButton.OnMouseExited += args => OnEjectJugButtonMouseExited?.Invoke(args, ejectButton);
ChemicalList.AddChild(ejectButton);
var card = new ReagentCardControl(item);
card.OnPressed += OnDispenseReagentButtonPressed;
card.OnEjectButtonPressed += OnEjectJugButtonPressed;
ReagentList.Children.Add(card);
}
}
@ -93,36 +70,7 @@ namespace Content.Client.Chemistry.UI
ClearButton.Disabled = castState.OutputContainer is null;
EjectButton.Disabled = castState.OutputContainer is null;
switch (castState.SelectedDispenseAmount)
{
case ReagentDispenserDispenseAmount.U1:
DispenseButton1.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U5:
DispenseButton5.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U10:
DispenseButton10.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U15:
DispenseButton15.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U20:
DispenseButton20.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U25:
DispenseButton25.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U30:
DispenseButton30.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U50:
DispenseButton50.Pressed = true;
break;
case ReagentDispenserDispenseAmount.U100:
DispenseButton100.Pressed = true;
break;
}
AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString();
}
/// <summary>
@ -137,23 +85,15 @@ namespace Content.Client.Chemistry.UI
if (state.OutputContainer is null)
{
ContainerInfoName.Text = "";
ContainerInfoFill.Text = "";
ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
return;
}
ContainerInfo.Children.Add(new BoxContainer // Name of the container and its fill status (Ex: 44/100u)
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
new Label {Text = $"{state.OutputContainer.DisplayName}: "},
new Label
{
Text = $"{state.OutputContainer.CurrentVolume}/{state.OutputContainer.MaxVolume}",
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
}
}
});
// Set Name of the container and its fill status (Ex: 44/100u)
ContainerInfoName.Text = state.OutputContainer.DisplayName;
ContainerInfoFill.Text = state.OutputContainer.CurrentVolume + "/" + state.OutputContainer.MaxVolume;
foreach (var (reagent, quantity) in state.OutputContainer.Reagents!)
{

View file

@ -22,6 +22,7 @@ public static partial class PoolManager
(CVars.ThreadParallelCount.Name, "1"),
(CCVars.GameRoleTimers.Name, "false"),
(CCVars.GridFill.Name, "false"),
(CCVars.PreloadGrids.Name, "false"),
(CCVars.ArrivalsShuttles.Name, "false"),
(CCVars.EmergencyShuttleEnabled.Name, "false"),
(CCVars.ProcgenPreload.Name, "false"),

View file

@ -1,22 +1,23 @@
using System.Collections.Generic;
using Content.Server.Cargo.Systems;
using Content.Server.Construction.Completions;
using Content.Server.Construction.Components;
using Content.Server.Destructible;
using Content.Server.Destructible.Thresholds.Behaviors;
using Content.Server.Stack;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Construction.Components;
using Content.Shared.Construction.Prototypes;
using Content.Shared.Construction.Steps;
using Content.Shared.FixedPoint;
using Content.Shared.Lathe;
using Content.Shared.Materials;
using Content.Shared.Research.Prototypes;
using Content.Shared.Stacks;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using System.Collections.Generic;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Construction.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Materials;
using Robust.Shared.Utility;
namespace Content.IntegrationTests.Tests;
@ -52,10 +53,10 @@ public sealed class MaterialArbitrageTest
var destructibleName = compFact.GetComponentName(typeof(DestructibleComponent));
// construct inverted lathe recipe dictionary
Dictionary<string, LatheRecipePrototype> latheRecipes = new();
Dictionary<string, List<LatheRecipePrototype>> latheRecipes = new();
foreach (var proto in protoManager.EnumeratePrototypes<LatheRecipePrototype>())
{
latheRecipes.Add(proto.Result, proto);
latheRecipes.GetOrNew(proto.Result).Add(proto);
}
// Lets assume the possible lathe for resource multipliers:
@ -186,13 +187,16 @@ public sealed class MaterialArbitrageTest
Assert.That(spawnedPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after being destroyed\nEntities spawned on destruction: {string.Join(',', spawnedEnts)}");
// Check lathe production
if (latheRecipes.TryGetValue(id, out var recipe))
if (latheRecipes.TryGetValue(id, out var recipes))
{
foreach (var (matId, amount) in recipe.RequiredMaterials)
foreach (var recipe in recipes)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (spawnedMats.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"destroying a {id} spawns more {matId} than required to produce via an (upgraded) lathe.");
foreach (var (matId, amount) in recipe.RequiredMaterials)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (spawnedMats.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"destroying a {id} spawns more {matId} than required to produce via an (upgraded) lathe.");
}
}
}
@ -263,13 +267,16 @@ public sealed class MaterialArbitrageTest
Assert.That(deconstructedPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after being deconstructed");
// Check lathe production
if (latheRecipes.TryGetValue(id, out var recipe))
if (latheRecipes.TryGetValue(id, out var recipes))
{
foreach (var (matId, amount) in recipe.RequiredMaterials)
foreach (var recipe in recipes)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (deconstructedMats.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"deconstructing {id} spawns more {matId} than required to produce via an (upgraded) lathe.");
foreach (var (matId, amount) in recipe.RequiredMaterials)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (deconstructedMats.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"deconstructing {id} spawns more {matId} than required to produce via an (upgraded) lathe.");
}
}
}
@ -315,13 +322,16 @@ public sealed class MaterialArbitrageTest
Assert.That(sumPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after decomposed into raw materials");
// Check lathe production
if (latheRecipes.TryGetValue(id, out var recipe))
if (latheRecipes.TryGetValue(id, out var recipes))
{
foreach (var (matId, amount) in recipe.RequiredMaterials)
foreach (var recipe in recipes)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"The physical composition of {id} has more {matId} than required to produce via an (upgraded) lathe.");
foreach (var (matId, amount) in recipe.RequiredMaterials)
{
var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier);
if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned))
Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"The physical composition of {id} has more {matId} than required to produce via an (upgraded) lathe.");
}
}
}

View file

@ -1,8 +0,0 @@
using Content.Server.Access.Systems;
namespace Content.Server.Access.Components;
[RegisterComponent, Access(typeof(IdExaminableSystem))]
public sealed partial class IdExaminableComponent : Component
{
}

View file

@ -3,7 +3,6 @@ using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.ReactionEffects;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Forensics;
using Content.Server.HealthExaminable;
using Content.Server.Popups;
using Content.Shared.Alert;
using Content.Shared.Chemistry.Components;
@ -13,6 +12,7 @@ using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Drunk;
using Content.Shared.FixedPoint;
using Content.Shared.HealthExaminable;
using Content.Shared.Mobs.Systems;
using Content.Shared.Popups;
using Content.Shared.Rejuvenate;

View file

@ -81,9 +81,9 @@ namespace Content.Server.Chemistry.EntitySystems
return null;
}
private List<KeyValuePair<string, KeyValuePair<string, string>>> GetInventory(Entity<ReagentDispenserComponent> reagentDispenser)
private List<ReagentInventoryItem> GetInventory(Entity<ReagentDispenserComponent> reagentDispenser)
{
var inventory = new List<KeyValuePair<string, KeyValuePair<string, string>>>();
var inventory = new List<ReagentInventoryItem>();
for (var i = 0; i < reagentDispenser.Comp.NumSlots; i++)
{
@ -99,15 +99,17 @@ namespace Content.Server.Chemistry.EntitySystems
else
continue;
// Add volume remaining label
// Get volume remaining and color of solution
FixedPoint2 quantity = 0f;
var reagentColor = Color.White;
if (storedContainer != null && _solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out _, out var sol))
{
quantity = sol.Volume;
reagentColor = sol.GetColor(_prototypeManager);
}
var storedAmount = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity));
inventory.Add(new KeyValuePair<string, KeyValuePair<string, string>>(storageSlotId, new KeyValuePair<string, string>(reagentLabel, storedAmount)));
inventory.Add(new ReagentInventoryItem(storageSlotId, reagentLabel, storedAmount, reagentColor));
}
return inventory;

View file

@ -4,14 +4,12 @@ using Content.Server.Discord;
using Content.Server.GameTicking.Events;
using Content.Server.Ghost;
using Content.Server.Maps;
using Content.Server.Voting.Managers;
using Content.Shared.CCVar;
using Content.Shared.Database;
using Content.Shared.GameTicking;
using Content.Shared.Mind;
using Content.Shared.Players;
using Content.Shared.Preferences;
using Content.Shared.Voting;
using JetBrains.Annotations;
using Prometheus;
using Robust.Server.Maps;
@ -29,7 +27,6 @@ namespace Content.Server.GameTicking
{
[Dependency] private readonly DiscordWebhook _discord = default!;
[Dependency] private readonly ITaskManager _taskManager = default!;
[Dependency] private readonly IVoteManager _voteManager = default!;
private static readonly Counter RoundNumberMetric = Metrics.CreateCounter(
"ss14_round_number",
@ -513,11 +510,6 @@ namespace Content.Server.GameTicking
SendStatusToAll();
UpdateInfoText();
if (_configurationManager.GetCVar(CCVars.GameAutoMapVote))
{
_voteManager.CreateStandardVote(null, StandardVoteType.Map);
}
ReqWindowAttentionAll();
}
}

View file

@ -1,4 +1,6 @@
using Content.Server.Maps;
using Content.Shared.GridPreloader.Prototypes;
using Content.Shared.Storage;
using Content.Shared.Whitelist;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
@ -16,11 +18,14 @@ public sealed partial class LoadMapRuleComponent : Component
public MapId? Map;
[DataField]
public ProtoId<GameMapPrototype>? GameMap ;
public ProtoId<GameMapPrototype>? GameMap;
[DataField]
public ResPath? MapPath;
[DataField]
public ProtoId<PreloadedGridPrototype>? PreloadedGrid;
[DataField]
public List<EntityUid> MapGrids = new();

View file

@ -31,6 +31,9 @@ public sealed partial class TraitorRuleComponent : Component
[DataField]
public ProtoId<DatasetPrototype> CodewordVerbs = "verbs";
[DataField]
public ProtoId<DatasetPrototype> ObjectiveIssuers = "TraitorCorporations";
public int TotalTraitors => TraitorMinds.Count;
public string[] Codewords = new string[3];

View file

@ -1,9 +1,11 @@
using Content.Server.Antag;
using Content.Server.GameTicking.Components;
using Content.Server.GameTicking.Rules.Components;
using Content.Server.GridPreloader;
using Content.Server.Spawners.Components;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Server.GameTicking.Rules;
@ -11,9 +13,12 @@ namespace Content.Server.GameTicking.Rules;
public sealed class LoadMapRuleSystem : GameRuleSystem<LoadMapRuleComponent>
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly GridPreloaderSystem _gridPreloader = default!;
public override void Initialize()
{
@ -41,7 +46,9 @@ public sealed class LoadMapRuleSystem : GameRuleSystem<LoadMapRuleComponent>
if (comp.Map != null)
return;
_map.CreateMap(out var mapId);
// grid preloading needs map to init after moving it
var mapUid = comp.PreloadedGrid != null ? _map.CreateMap(out var mapId, false) : _map.CreateMap(out mapId);
_metaData.SetEntityName(mapUid, $"LoadMapRule destination for rule {ToPrettyString(uid)}");
comp.Map = mapId;
if (comp.GameMap != null)
@ -51,8 +58,29 @@ public sealed class LoadMapRuleSystem : GameRuleSystem<LoadMapRuleComponent>
}
else if (comp.MapPath != null)
{
if (_mapLoader.TryLoad(comp.Map.Value, comp.MapPath.Value.ToString(), out var roots, new MapLoadOptions { LoadMap = true }))
comp.MapGrids.AddRange(roots);
if (!_mapLoader.TryLoad(comp.Map.Value,
comp.MapPath.Value.ToString(),
out var roots,
new MapLoadOptions { LoadMap = true }))
{
_mapManager.DeleteMap(mapId);
return;
}
comp.MapGrids.AddRange(roots);
}
else if (comp.PreloadedGrid != null)
{
// TODO: If there are no preloaded grids left, any rule announcements will still go off!
if (!_gridPreloader.TryGetPreloadedGrid(comp.PreloadedGrid.Value, out var loadedShuttle))
{
_mapManager.DeleteMap(mapId);
return;
}
_transform.SetParent(loadedShuttle.Value, mapUid);
comp.MapGrids.Add(loadedShuttle.Value);
_map.InitializeMap(mapId);
}
else
{

View file

@ -74,6 +74,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
return false;
var briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", component.Codewords)));
var issuer = _random.Pick(_prototypeManager.Index(component.ObjectiveIssuers).Values);
Note[]? code = null;
if (giveUplink)
@ -97,7 +98,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("-", code).Replace("sharp", "#"))));
}
_antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code), null, component.GreetSoundNotification);
_antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code, issuer), null, component.GreetSoundNotification);
component.TraitorMinds.Add(mindId);
@ -142,10 +143,10 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
}
private string GenerateBriefing(string[] codewords, Note[]? uplinkCode)
private string GenerateBriefing(string[] codewords, Note[]? uplinkCode, string? objectiveIssuer = null)
{
var sb = new StringBuilder();
sb.AppendLine(Loc.GetString("traitor-role-greeting"));
sb.AppendLine(Loc.GetString("traitor-role-greeting", ("corporation", objectiveIssuer ?? Loc.GetString("objective-issuer-unknown"))));
sb.AppendLine(Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", codewords))));
if (uplinkCode != null)
sb.AppendLine(Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("-", uplinkCode).Replace("sharp", "#"))));

View file

@ -35,7 +35,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
{
base.Initialize();
SubscribeLocalEvent<PendingZombieComponent, ZombifySelfActionEvent>(OnZombifySelf);
SubscribeLocalEvent<IncurableZombieComponent, ZombifySelfActionEvent>(OnZombifySelf);
}
protected override void AppendRoundEndText(EntityUid uid, ZombieRuleComponent component, GameRuleComponent gameRule,
@ -128,7 +128,7 @@ public sealed class ZombieRuleSystem : GameRuleSystem<ZombieRuleComponent>
component.NextRoundEndCheck = _timing.CurTime + component.EndCheckDelay;
}
private void OnZombifySelf(EntityUid uid, PendingZombieComponent component, ZombifySelfActionEvent args)
private void OnZombifySelf(EntityUid uid, IncurableZombieComponent component, ZombifySelfActionEvent args)
{
_zombie.ZombifyEntity(uid);
if (component.Action != null)

View file

@ -0,0 +1,16 @@
using Content.Shared.GridPreloader.Prototypes;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Server.GridPreloader;
/// <summary>
/// Component storing data about preloaded grids and their location
/// Goes on the map entity
/// </summary>
[RegisterComponent, Access(typeof(GridPreloaderSystem))]
public sealed partial class GridPreloaderComponent : Component
{
[DataField]
public Dictionary<ProtoId<PreloadedGridPrototype>, List<EntityUid>> PreloadedGrids = new();
}

View file

@ -0,0 +1,147 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.CCVar;
using Content.Shared.GridPreloader.Prototypes;
using Content.Shared.GridPreloader.Systems;
using Robust.Server.GameObjects;
using Robust.Server.Maps;
using Robust.Shared.Configuration;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using System.Numerics;
using Content.Server.GameTicking;
using Content.Shared.GameTicking;
using JetBrains.Annotations;
namespace Content.Server.GridPreloader;
public sealed class GridPreloaderSystem : SharedGridPreloaderSystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly MapSystem _map = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundRestart);
SubscribeLocalEvent<PostGameMapLoad>(OnPostGameMapLoad);
}
private void OnRoundRestart(RoundRestartCleanupEvent ev)
{
var ent = GetPreloaderEntity();
if (ent == null)
return;
Del(ent.Value.Owner);
}
private void OnPostGameMapLoad(PostGameMapLoad ev)
{
EnsurePreloadedGridMap();
}
private void EnsurePreloadedGridMap()
{
// Already have a preloader?
if (GetPreloaderEntity() != null)
return;
if (!_cfg.GetCVar(CCVars.PreloadGrids))
return;
var mapUid = _map.CreateMap(out var mapId, false);
var preloader = EnsureComp<GridPreloaderComponent>(mapUid);
_meta.SetEntityName(mapUid, "GridPreloader Map");
_map.SetPaused(mapId, true);
var globalXOffset = 0f;
foreach (var proto in _prototype.EnumeratePrototypes<PreloadedGridPrototype>())
{
for (var i = 0; i < proto.Copies; i++)
{
var options = new MapLoadOptions
{
LoadMap = false,
};
if (!_mapLoader.TryLoad(mapId, proto.Path.ToString(), out var roots, options))
continue;
// only supports loading maps with one grid.
if (roots.Count != 1)
continue;
var gridUid = roots[0];
// gets grid + also confirms that the root we loaded is actually a grid
if (!TryComp<MapGridComponent>(gridUid, out var mapGrid))
continue;
if (!TryComp<PhysicsComponent>(gridUid, out var physics))
continue;
// Position Calculating
globalXOffset += mapGrid.LocalAABB.Width / 2;
var coords = new Vector2(-physics.LocalCenter.X + globalXOffset, -physics.LocalCenter.Y);
_transform.SetCoordinates(gridUid, new EntityCoordinates(mapUid, coords));
globalXOffset += (mapGrid.LocalAABB.Width / 2) + 1;
// Add to list
if (!preloader.PreloadedGrids.ContainsKey(proto.ID))
preloader.PreloadedGrids[proto.ID] = new();
preloader.PreloadedGrids[proto.ID].Add(gridUid);
}
}
}
/// <summary>
/// Should be a singleton no matter station count, so we can assume 1
/// (better support for singleton component in engine at some point i guess)
/// </summary>
/// <returns></returns>
public Entity<GridPreloaderComponent>? GetPreloaderEntity()
{
var query = AllEntityQuery<GridPreloaderComponent>();
while (query.MoveNext(out var uid, out var comp))
{
return (uid, comp);
}
return null;
}
/// <summary>
/// An attempt to get a certain preloaded shuttle. If there are no more such shuttles left, returns null
/// </summary>
[PublicAPI]
public bool TryGetPreloadedGrid(ProtoId<PreloadedGridPrototype> proto, [NotNullWhen(true)] out EntityUid? preloadedGrid, GridPreloaderComponent? preloader = null)
{
preloadedGrid = null;
if (preloader == null)
{
preloader = GetPreloaderEntity();
if (preloader == null)
return false;
}
if (!preloader.PreloadedGrids.TryGetValue(proto, out var list) || list.Count <= 0)
return false;
preloadedGrid = list[0];
list.RemoveAt(0);
if (list.Count == 0)
preloader.PreloadedGrids.Remove(proto);
return true;
}
}

View file

@ -55,7 +55,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
SubscribeLocalEvent<SiliconLawProviderComponent, GotEmaggedEvent>(OnEmagLawsAdded);
SubscribeLocalEvent<EmagSiliconLawComponent, MindAddedMessage>(OnEmagMindAdded);
SubscribeLocalEvent<EmagSiliconLawComponent, MindRemovedMessage>(OnEmagMindRemoved);
SubscribeLocalEvent<EmagSiliconLawComponent, ExaminedEvent>(OnExamined);
}
private void OnComponentShutdown(EntityUid uid, SiliconLawBoundComponent component, ComponentShutdown args)
@ -155,17 +154,6 @@ public sealed class SiliconLawSystem : SharedSiliconLawSystem
});
}
private void OnExamined(EntityUid uid, EmagSiliconLawComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange || !HasComp<EmaggedComponent>(uid))
return;
if (component.RequireOpenPanel && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)
return;
args.PushMarkup(Loc.GetString("laws-compromised-examine"));
}
protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args)
{
if (component.RequireOpenPanel && TryComp<WiresPanelComponent>(uid, out var panel) && !panel.Open)

View file

@ -89,8 +89,8 @@ namespace Content.Server.Speech.EntitySystems
// In-place replace the match with the transformed capitalization replacement
message = message.Remove(match.Index, match.Length).Insert(match.Index, replacement);
string mask = new string('_', match.Length);
maskMessage = message.Remove(match.Index, match.Length).Insert(match.Index, mask);
var mask = new string('_', replacement.Length);
maskMessage = maskMessage.Remove(match.Index, match.Length).Insert(match.Index, mask);
}
}

View file

@ -200,27 +200,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
loadout.SetDefault(_prototypeManager);
}
// Order loadout selections by the order they appear on the prototype.
foreach (var group in loadout.SelectedLoadouts.OrderBy(x => roleProto.Groups.FindIndex(e => e == x.Key)))
{
foreach (var items in group.Value)
{
if (!_prototypeManager.TryIndex(items.Prototype, out var loadoutProto))
{
Log.Error($"Unable to find loadout prototype for {items.Prototype}");
continue;
}
if (!_prototypeManager.TryIndex(loadoutProto.Equipment, out var startingGear))
{
Log.Error($"Unable to find starting gear {loadoutProto.Equipment} for loadout {loadoutProto}");
continue;
}
// Handle any extra data here.
EquipStartingGear(entity.Value, startingGear, raiseEvent: false);
}
}
EquipRoleLoadout(entity.Value, loadout, roleProto);
}
var gearEquippedEv = new StartingGearEquippedEvent(entity.Value);

View file

@ -1,4 +1,4 @@
using Robust.Shared.Audio;
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.StationEvents.Components;
@ -15,49 +15,49 @@ public sealed partial class StationEventComponent : Component
public const float WeightHigh = 15.0f;
public const float WeightVeryHigh = 20.0f;
[DataField("weight")]
[DataField]
public float Weight = WeightNormal;
[DataField("startAnnouncement")]
[DataField]
public string? StartAnnouncement;
[DataField("endAnnouncement")]
[DataField]
public string? EndAnnouncement;
[DataField("startAudio")]
[DataField]
public SoundSpecifier? StartAudio;
[DataField("endAudio")]
[DataField]
public SoundSpecifier? EndAudio;
/// <summary>
/// In minutes, when is the first round time this event can start
/// </summary>
[DataField("earliestStart")]
[DataField]
public int EarliestStart = 5;
/// <summary>
/// In minutes, the amount of time before the same event can occur again
/// </summary>
[DataField("reoccurrenceDelay")]
[DataField]
public int ReoccurrenceDelay = 30;
/// <summary>
/// How long after being added does the event start
/// </summary>
[DataField("startDelay")]
[DataField]
public TimeSpan StartDelay = TimeSpan.Zero;
/// <summary>
/// How long the event lasts.
/// </summary>
[DataField("duration")]
[DataField]
public TimeSpan? Duration = TimeSpan.FromSeconds(1);
/// <summary>
/// The max amount of time the event lasts.
/// </summary>
[DataField("maxDuration")]
[DataField]
public TimeSpan? MaxDuration;
/// <summary>
@ -66,13 +66,13 @@ public sealed partial class StationEventComponent : Component
/// <remarks>
/// To avoid running deadly events with low-pop
/// </remarks>
[DataField("minimumPlayers")]
[DataField]
public int MinimumPlayers;
/// <summary>
/// How many times this even can occur in a single round
/// </summary>
[DataField("maxOccurrences")]
[DataField]
public int? MaxOccurrences;
/// <summary>

View file

@ -1,3 +1,4 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Chat.Systems;
using Content.Server.GameTicking.Components;
@ -42,6 +43,7 @@ public abstract class StationEventSystem<T> : GameRuleSystem<T> where T : ICompo
if (!TryComp<StationEventComponent>(uid, out var stationEvent))
return;
AdminLogManager.Add(LogType.EventAnnounced, $"Event added / announced: {ToPrettyString(uid)}");
if (stationEvent.StartAnnouncement != null)

View file

@ -1,10 +1,16 @@
namespace Content.Server.Zombies;
using Robust.Shared.Prototypes;
namespace Content.Server.Zombies;
/// <summary>
/// This is used for a zombie that cannot be cured by any methods.
/// This is used for a zombie that cannot be cured by any methods. Gives a succumb to zombie infection action.
/// </summary>
[RegisterComponent]
public sealed partial class IncurableZombieComponent : Component
{
[DataField]
public EntProtoId ZombifySelfActionPrototype = "ActionTurnUndead";
[DataField]
public EntityUid? Action;
}

View file

@ -1,5 +1,4 @@
using Content.Shared.Damage;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Zombies;
@ -48,9 +47,6 @@ public sealed partial class PendingZombieComponent : Component
[DataField]
public TimeSpan MaxInitialInfectedGrace = TimeSpan.FromMinutes(15f);
[DataField]
public EntProtoId ZombifySelfActionPrototype = "ActionTurnUndead";
/// <summary>
/// The chance each second that a warning will be shown.
/// </summary>
@ -66,6 +62,4 @@ public sealed partial class PendingZombieComponent : Component
"zombie-infection-warning",
"zombie-infection-underway"
};
[DataField] public EntityUid? Action;
}

View file

@ -64,9 +64,16 @@ namespace Content.Server.Zombies
SubscribeLocalEvent<PendingZombieComponent, MapInitEvent>(OnPendingMapInit);
SubscribeLocalEvent<IncurableZombieComponent, MapInitEvent>(OnPendingMapInit);
SubscribeLocalEvent<ZombifyOnDeathComponent, MobStateChangedEvent>(OnDamageChanged);
}
private void OnPendingMapInit(EntityUid uid, IncurableZombieComponent component, MapInitEvent args)
{
_actions.AddAction(uid, ref component.Action, component.ZombifySelfActionPrototype);
}
private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, MapInitEvent args)
{
if (_mobState.IsDead(uid))
@ -77,7 +84,6 @@ namespace Content.Server.Zombies
component.NextTick = _timing.CurTime + TimeSpan.FromSeconds(1f);
component.GracePeriod = _random.Next(component.MinInitialInfectedGrace, component.MaxInitialInfectedGrace);
_actions.AddAction(uid, ref component.Action, component.ZombifySelfActionPrototype);
}
public override void Update(float frameTime)

View file

@ -40,4 +40,10 @@ public sealed partial class IdCardComponent : Component
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public bool BypassLogging;
[DataField]
public LocId NameLocId = "access-id-card-component-owner-name-job-title-text";
[DataField]
public LocId FullNameLocId = "access-id-card-component-owner-full-name-job-title-text";
}

View file

@ -0,0 +1,6 @@
using Content.Shared.Access.Systems;
namespace Content.Shared.Access.Components;
[RegisterComponent, Access(typeof(IdExaminableSystem))]
public sealed partial class IdExaminableComponent : Component;

View file

@ -1,4 +1,3 @@
using Content.Server.Access.Components;
using Content.Shared.Access.Components;
using Content.Shared.Examine;
using Content.Shared.Inventory;
@ -6,7 +5,7 @@ using Content.Shared.PDA;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
namespace Content.Server.Access.Systems;
namespace Content.Shared.Access.Systems;
public sealed class IdExaminableSystem : EntitySystem
{
@ -22,7 +21,7 @@ public sealed class IdExaminableSystem : EntitySystem
private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, GetVerbsEvent<ExamineVerb> args)
{
var detailsRange = _examineSystem.IsInDetailsRange(args.User, uid);
var info = GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id");
var info = GetMessage(uid);
var verb = new ExamineVerb()
{
@ -41,7 +40,12 @@ public sealed class IdExaminableSystem : EntitySystem
args.Verbs.Add(verb);
}
private string? GetInfo(EntityUid uid)
public string GetMessage(EntityUid uid)
{
return GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id");
}
public string? GetInfo(EntityUid uid)
{
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
{
@ -65,9 +69,9 @@ public sealed class IdExaminableSystem : EntitySystem
var jobSuffix = string.IsNullOrWhiteSpace(id.JobTitle) ? string.Empty : $" ({id.JobTitle})";
var val = string.IsNullOrWhiteSpace(id.FullName)
? Loc.GetString("access-id-card-component-owner-name-job-title-text",
? Loc.GetString(id.NameLocId,
("jobSuffix", jobSuffix))
: Loc.GetString("access-id-card-component-owner-full-name-job-title-text",
: Loc.GetString(id.FullNameLocId,
("fullName", id.FullName),
("jobSuffix", jobSuffix));

View file

@ -207,9 +207,9 @@ public abstract class SharedIdCardSystem : EntitySystem
var jobSuffix = string.IsNullOrWhiteSpace(id.JobTitle) ? string.Empty : $" ({id.JobTitle})";
var val = string.IsNullOrWhiteSpace(id.FullName)
? Loc.GetString("access-id-card-component-owner-name-job-title-text",
? Loc.GetString(id.NameLocId,
("jobSuffix", jobSuffix))
: Loc.GetString("access-id-card-component-owner-full-name-job-title-text",
: Loc.GetString(id.FullNameLocId,
("fullName", id.FullName),
("jobSuffix", jobSuffix));
_metaSystem.SetEntityName(uid, val);

View file

@ -0,0 +1,10 @@
namespace Content.Shared.Armor;
/// <summary>
/// Used on outerclothing to allow use of suit storage
/// </summary>
[RegisterComponent]
public sealed partial class AllowSuitStorageComponent : Component
{
}

View file

@ -330,12 +330,6 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> DebugCoordinatesAdminOnly =
CVarDef.Create("game.debug_coordinates_admin_only", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Controls if lobby has an automatic map vote.
/// </summary>
public static readonly CVarDef<bool>
GameAutoMapVote = CVarDef.Create("game.lobby_auto_map_vote", true, CVar.ARCHIVE | CVar.SERVERONLY);
#if EXCEPTION_TOLERANCE
/// <summary>
/// Amount of times round start must fail before the server is shut down.
@ -1381,6 +1375,12 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> GridFill =
CVarDef.Create("shuttle.grid_fill", true, CVar.SERVERONLY);
/// <summary>
/// Whether to automatically preloading grids by GridPreloaderSystem
/// </summary>
public static readonly CVarDef<bool> PreloadGrids =
CVarDef.Create("shuttle.preload_grids", true, CVar.SERVERONLY);
/*
* Emergency
*/

View file

@ -20,6 +20,46 @@ namespace Content.Shared.Chemistry
{
ReagentDispenserDispenseAmount = amount;
}
/// <summary>
/// Create a new instance from interpreting a String as an integer,
/// throwing an exception if it is unable to parse.
/// </summary>
public ReagentDispenserSetDispenseAmountMessage(String s)
{
switch (s)
{
case "1":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U1;
break;
case "5":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U5;
break;
case "10":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U10;
break;
case "15":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U15;
break;
case "20":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U20;
break;
case "25":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U25;
break;
case "30":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U30;
break;
case "50":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U50;
break;
case "100":
ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U100;
break;
default:
throw new Exception($"Cannot convert the string `{s}` into a valid ReagentDispenser DispenseAmount");
}
}
}
[Serializable, NetSerializable]
@ -52,20 +92,30 @@ namespace Content.Shared.Chemistry
U100 = 100,
}
[Serializable, NetSerializable]
public sealed class ReagentInventoryItem(string storageSlotId, string reagentLabel, string storedAmount, Color reagentColor)
{
public string StorageSlotId = storageSlotId;
public string ReagentLabel = reagentLabel;
public string StoredAmount = storedAmount;
public Color ReagentColor = reagentColor;
}
[Serializable, NetSerializable]
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly ContainerInfo? OutputContainer;
public readonly NetEntity? OutputContainerEntity;
/// <summary>
/// A list of the reagents which this dispenser can dispense.
/// </summary>
public readonly List<KeyValuePair<string, KeyValuePair<string, string>>> Inventory;
public readonly List<ReagentInventoryItem> Inventory;
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List<KeyValuePair<string, KeyValuePair<string, string>>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List<ReagentInventoryItem> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
{
OutputContainer = outputContainer;
OutputContainerEntity = outputContainerEntity;

View file

@ -1,6 +1,7 @@
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
using Robust.Shared.Prototypes;
namespace Content.Shared.Clothing.Components;
@ -10,7 +11,20 @@ public sealed partial class LoadoutComponent : Component
/// <summary>
/// A list of starting gears, of which one will be given.
/// All elements are weighted the same in the list.
///
/// If not specified, <see cref="RoleLoadout"/> will be used instead.
/// </summary>
[DataField("prototypes", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer<StartingGearPrototype>)), AutoNetworkedField]
public List<string>? Prototypes;
[DataField("prototypes")]
[AutoNetworkedField]
public List<ProtoId<StartingGearPrototype>>? StartingGear;
/// <summary>
/// A list of role loadouts, of which one will be given.
/// All elements are weighted the same in the list.
///
/// If not specified, <see cref="StartingGear"/> will be used instead.
/// </summary>
[DataField]
[AutoNetworkedField]
public List<ProtoId<RoleLoadoutPrototype>>? RoleLoadout;
}

View file

@ -9,7 +9,7 @@ using Robust.Shared.Random;
namespace Content.Shared.Clothing;
/// <summary>
/// Assigns a loadout to an entity based on the startingGear prototype
/// Assigns a loadout to an entity based on the RoleLoadout prototype
/// </summary>
public sealed class LoadoutSystem : EntitySystem
{
@ -110,10 +110,22 @@ public sealed class LoadoutSystem : EntitySystem
private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent args)
{
if (component.Prototypes == null)
// Use starting gear if specified
if (component.StartingGear != null)
{
var gear = _protoMan.Index(_random.Pick(component.StartingGear));
_station.EquipStartingGear(uid, gear);
return;
}
if (component.RoleLoadout == null)
return;
var proto = _protoMan.Index<StartingGearPrototype>(_random.Pick(component.Prototypes));
_station.EquipStartingGear(uid, proto);
// ...otherwise equip from role loadout
var id = _random.Pick(component.RoleLoadout);
var proto = _protoMan.Index(id);
var loadout = new RoleLoadout(id);
loadout.SetDefault(_protoMan, true);
_station.EquipRoleLoadout(uid, loadout, proto);
}
}

View file

@ -24,8 +24,12 @@ public sealed partial class BlindableComponent : Component
[ViewVariables(VVAccess.ReadWrite), DataField("EyeDamage"), AutoNetworkedField]
public int EyeDamage = 0;
[ViewVariables(VVAccess.ReadOnly), DataField]
public const int MaxDamage = 9;
[ViewVariables(VVAccess.ReadOnly), DataField]
public int MinDamage = 0;
/// <description>
/// Used to ensure that this doesn't break with sandbox or admin tools.
/// This is not "enabled/disabled".

View file

@ -62,13 +62,31 @@ public sealed class BlindableSystem : EntitySystem
return;
blindable.Comp.EyeDamage += amount;
blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, 0, BlindableComponent.MaxDamage);
Dirty(blindable);
UpdateIsBlind(blindable);
UpdateEyeDamage(blindable, true);
}
private void UpdateEyeDamage(Entity<BlindableComponent?> blindable, bool isDamageChanged)
{
if (!Resolve(blindable, ref blindable.Comp, false))
return;
var previousDamage = blindable.Comp.EyeDamage;
blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, blindable.Comp.MinDamage, BlindableComponent.MaxDamage);
Dirty(blindable);
if (!isDamageChanged && previousDamage == blindable.Comp.EyeDamage)
return;
UpdateIsBlind(blindable);
var ev = new EyeDamageChangedEvent(blindable.Comp.EyeDamage);
RaiseLocalEvent(blindable.Owner, ref ev);
}
public void SetMinDamage(Entity<BlindableComponent?> blindable, int amount)
{
if (!Resolve(blindable, ref blindable.Comp, false))
return;
blindable.Comp.MinDamage = amount;
UpdateEyeDamage(blindable, false);
}
}
/// <summary>

View file

@ -0,0 +1,21 @@
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Shared.GridPreloader.Prototypes;
/// <summary>
/// Creating this prototype will automatically load the grid at the specified path at the beginning of the round,
/// and allow the GridPreloader system to load them in the middle of the round. This is needed for optimization,
/// because loading grids in the middle of a round causes the server to lag.
/// </summary>
[Prototype("preloadedGrid")]
public sealed partial class PreloadedGridPrototype : IPrototype
{
[IdDataField] public string ID { get; } = string.Empty;
[DataField(required: true)]
public ResPath Path;
[DataField]
public int Copies = 1;
}

View file

@ -0,0 +1,4 @@
namespace Content.Shared.GridPreloader.Systems;
public abstract class SharedGridPreloaderSystem : EntitySystem
{
}

View file

@ -1,8 +1,8 @@
using Content.Shared.Damage.Prototypes;
using Content.Shared.FixedPoint;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Robust.Shared.Prototypes;
namespace Content.Server.HealthExaminable;
namespace Content.Shared.HealthExaminable;
[RegisterComponent, Access(typeof(HealthExaminableSystem))]
public sealed partial class HealthExaminableComponent : Component
@ -10,14 +10,14 @@ public sealed partial class HealthExaminableComponent : Component
public List<FixedPoint2> Thresholds = new()
{ FixedPoint2.New(10), FixedPoint2.New(25), FixedPoint2.New(50), FixedPoint2.New(75) };
[DataField("examinableTypes", required: true, customTypeSerializer:typeof(PrototypeIdHashSetSerializer<DamageTypePrototype>))]
public HashSet<string> ExaminableTypes = default!;
[DataField(required: true)]
public HashSet<ProtoId<DamageTypePrototype>> ExaminableTypes = default!;
/// <summary>
/// Health examine text is automatically generated through creating loc string IDs, in the form:
/// `health-examine-[prefix]-[type]-[threshold]`
/// This part determines the prefix.
/// </summary>
[DataField("locPrefix")]
[DataField]
public string LocPrefix = "carbon";
}

View file

@ -5,7 +5,7 @@ using Content.Shared.IdentityManagement;
using Content.Shared.Verbs;
using Robust.Shared.Utility;
namespace Content.Server.HealthExaminable;
namespace Content.Shared.HealthExaminable;
public sealed class HealthExaminableSystem : EntitySystem
{
@ -42,7 +42,7 @@ public sealed class HealthExaminableSystem : EntitySystem
args.Verbs.Add(verb);
}
private FormattedMessage CreateMarkup(EntityUid uid, HealthExaminableComponent component, DamageableComponent damage)
public FormattedMessage CreateMarkup(EntityUid uid, HealthExaminableComponent component, DamageableComponent damage)
{
var msg = new FormattedMessage();

View file

@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Armor;
using Content.Shared.Clothing.Components;
using Content.Shared.DoAfter;
using Content.Shared.Hands;
@ -114,7 +115,7 @@ public abstract partial class InventorySystem
if (!_handsSystem.CanDropHeld(actor, hands.ActiveHand!, checkActionBlocker: false))
return;
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor), false);
RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor));
TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter:true);
}
@ -243,8 +244,16 @@ public abstract partial class InventorySystem
return false;
DebugTools.Assert(slotDefinition.Name == slot);
if (slotDefinition.DependsOn != null && !TryGetSlotEntity(target, slotDefinition.DependsOn, out _, inventory))
return false;
if (slotDefinition.DependsOn != null)
{
if (!TryGetSlotEntity(target, slotDefinition.DependsOn, out EntityUid? slotEntity, inventory))
return false;
if (slotDefinition.DependsOnComponents is { } componentRegistry)
foreach (var (_, entry) in componentRegistry)
if (!HasComp(slotEntity, entry.Component.GetType()))
return false;
}
var fittingInPocket = slotDefinition.SlotFlags.HasFlag(SlotFlags.POCKET) &&
item != null &&
@ -301,7 +310,6 @@ public abstract partial class InventorySystem
reason = itemAttemptEvent.Reason ?? reason;
return false;
}
return true;
}

View file

@ -34,6 +34,8 @@ public sealed partial class SlotDefinition
[DataField("dependsOn")] public string? DependsOn { get; private set; }
[DataField("dependsOnComponents")] public ComponentRegistry? DependsOnComponents { get; private set; }
[DataField("displayName", required: true)]
public string DisplayName { get; private set; } = string.Empty;

View file

@ -1,6 +1,8 @@
using System.Linq;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Inventory;
using Content.Shared.Preferences.Loadouts;
using Content.Shared.Roles;
using Content.Shared.Storage;
using Content.Shared.Storage.EntitySystems;
@ -31,6 +33,34 @@ public abstract class SharedStationSpawningSystem : EntitySystem
_xformQuery = GetEntityQuery<TransformComponent>();
}
/// <summary>
/// Equips the given starting gears from a `RoleLoadout` onto an entity.
/// </summary>
public void EquipRoleLoadout(EntityUid entity, RoleLoadout loadout, RoleLoadoutPrototype roleProto)
{
// Order loadout selections by the order they appear on the prototype.
foreach (var group in loadout.SelectedLoadouts.OrderBy(x => roleProto.Groups.FindIndex(e => e == x.Key)))
{
foreach (var items in group.Value)
{
if (!PrototypeManager.TryIndex(items.Prototype, out var loadoutProto))
{
Log.Error($"Unable to find loadout prototype for {items.Prototype}");
continue;
}
if (!PrototypeManager.TryIndex(loadoutProto.Equipment, out var startingGear))
{
Log.Error($"Unable to find starting gear {loadoutProto.Equipment} for loadout {loadoutProto}");
continue;
}
// Handle any extra data here.
EquipStartingGear(entity, startingGear, raiseEvent: false);
}
}
}
/// <summary>
/// <see cref="EquipStartingGear(Robust.Shared.GameObjects.EntityUid,System.Nullable{Robust.Shared.Prototypes.ProtoId{Content.Shared.Roles.StartingGearPrototype}},bool)"/>
/// </summary>

View file

@ -8,5 +8,7 @@ namespace Content.Shared.Traits.Assorted;
[RegisterComponent, NetworkedComponent]
public sealed partial class PermanentBlindnessComponent : Component
{
[ViewVariables(VVAccess.ReadWrite), DataField]
public int Blindness = 0; // How damaged should their eyes be. Set 0 for maximum damage.
}

View file

@ -18,15 +18,14 @@ public sealed class PermanentBlindnessSystem : EntitySystem
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<PermanentBlindnessComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<PermanentBlindnessComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<PermanentBlindnessComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<PermanentBlindnessComponent, EyeDamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<PermanentBlindnessComponent, ExaminedEvent>(OnExamined);
}
private void OnExamined(Entity<PermanentBlindnessComponent> blindness, ref ExaminedEvent args)
{
if (args.IsInDetailsRange && !_net.IsClient)
if (args.IsInDetailsRange && !_net.IsClient && blindness.Comp.Blindness == 0)
{
args.PushMarkup(Loc.GetString("permanent-blindness-trait-examined", ("target", Identity.Entity(blindness, EntityManager))));
}
@ -37,28 +36,17 @@ public sealed class PermanentBlindnessSystem : EntitySystem
_blinding.UpdateIsBlind(blindness.Owner);
}
private void OnStartup(Entity<PermanentBlindnessComponent> blindness, ref ComponentStartup args)
private void OnMapInit(Entity<PermanentBlindnessComponent> blindness, ref MapInitEvent args)
{
if (!_entityManager.TryGetComponent<BlindableComponent>(blindness, out var blindable))
return;
var damageToDeal = (int) BlurryVisionComponent.MaxMagnitude - blindable.EyeDamage;
if (damageToDeal <= 0)
return;
_blinding.AdjustEyeDamage(blindness.Owner, damageToDeal);
}
private void OnDamageChanged(Entity<PermanentBlindnessComponent> blindness, ref EyeDamageChangedEvent args)
{
if (args.Damage >= BlurryVisionComponent.MaxMagnitude)
return;
if (!_entityManager.TryGetComponent<BlindableComponent>(blindness, out var blindable))
return;
var damageRestoration = (int) BlurryVisionComponent.MaxMagnitude - args.Damage;
_blinding.AdjustEyeDamage(blindness.Owner, damageRestoration);
if (blindness.Comp.Blindness != 0)
_blinding.SetMinDamage(new Entity<BlindableComponent?>(blindness.Owner, blindable), blindness.Comp.Blindness);
else
{
var maxMagnitudeInt = (int) BlurryVisionComponent.MaxMagnitude;
_blinding.SetMinDamage(new Entity<BlindableComponent?>(blindness.Owner, blindable), maxMagnitudeInt);
}
}
}

View file

@ -33,4 +33,7 @@ public sealed partial class GunWieldBonusComponent : Component
/// </summary>
[DataField, AutoNetworkedField]
public Angle AngleIncrease = Angle.FromDegrees(0);
[DataField]
public LocId? WieldBonusExamineMessage = "gunwieldbonus-component-examine";
}

View file

@ -1,3 +1,4 @@
using Content.Shared.Examine;
using Content.Shared.Hands;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
@ -45,6 +46,7 @@ public sealed class WieldableSystem : EntitySystem
SubscribeLocalEvent<GunWieldBonusComponent, ItemWieldedEvent>(OnGunWielded);
SubscribeLocalEvent<GunWieldBonusComponent, ItemUnwieldedEvent>(OnGunUnwielded);
SubscribeLocalEvent<GunWieldBonusComponent, GunRefreshModifiersEvent>(OnGunRefreshModifiers);
SubscribeLocalEvent<GunWieldBonusComponent, ExaminedEvent>(OnExamine);
SubscribeLocalEvent<IncreaseDamageOnWieldComponent, GetMeleeDamageEvent>(OnGetMeleeDamage);
}
@ -95,6 +97,12 @@ public sealed class WieldableSystem : EntitySystem
}
}
private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args)
{
if (component.WieldBonusExamineMessage != null)
args.PushText(Loc.GetString(component.WieldBonusExamineMessage));
}
private void AddToggleWieldVerb(EntityUid uid, WieldableComponent component, GetVerbsEvent<InteractionVerb> args)
{
if (args.Hands == null || !args.CanAccess || !args.CanInteract)

View file

@ -1,106 +1,4 @@
Entries:
- author: MACMAN2003
changes:
- message: There are now more ways to craft reinforced plasma/uranium glass.
type: Tweak
id: 6066
time: '2024-02-29T22:57:18.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/22804
- author: deltanedas
changes:
- message: Acidifiers and microbombs now require confirmation before gibbing you.
type: Tweak
id: 6067
time: '2024-03-01T02:48:43.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/24609
- author: exincore
changes:
- message: Chameleon gear now only reveals its menu button to its wearer.
type: Tweak
id: 6068
time: '2024-03-01T12:49:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25746
- author: Nairodian
changes:
- message: Fixed all command and security roles not having cryogenics access.
type: Fix
id: 6069
time: '2024-03-01T21:21:37.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25752
- author: IlyaElDunaev
changes:
- message: Added detective's rubber stamp.
type: Add
id: 6070
time: '2024-03-01T22:50:17.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25676
- author: rosieposieeee
changes:
- message: Added additional signage to help the crew navigate.
type: Add
id: 6071
time: '2024-03-02T06:42:06.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25766
- author: EmoGarbage404
changes:
- message: Space heaters machine boards are now printable round start and can additionally
be ordered by cargo.
type: Tweak
id: 6072
time: '2024-03-02T06:43:29.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25735
- author: Krunk
changes:
- message: Picking up and dumping trash is less arduous for tiny, plentiful items,
such as bullets.
type: Tweak
id: 6073
time: '2024-03-02T13:57:44.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/24899
- author: Errant
changes:
- message: Breathing tritium or plasma now displays a HUD alert.
type: Add
id: 6074
time: '2024-03-02T14:07:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/24484
- author: waylon531
changes:
- message: Nutribrick and MRE wrappers can now be put in trash bags
type: Tweak
id: 6075
time: '2024-03-02T14:23:00.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25760
- author: Fildrance
changes:
- message: fixed lobby music restarting after volume change in options. Lobby music
is also not being looped by default - all lobby songs will play in shuffle mode.
type: Fix
id: 6076
time: '2024-03-02T20:40:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25530
- author: exincore
changes:
- message: Inventories now show a secondary smart-equip star.
type: Add
id: 6077
time: '2024-03-02T23:57:42.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25696
- author: Emisse
changes:
- message: Rev's reenabled
type: Tweak
id: 6078
time: '2024-03-03T00:30:22.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25704
- author: EmoGarbage404
changes:
- message: Fixed issues where using the Quantum Spin Inverted would bug out the
character's physics.
type: Fix
id: 6079
time: '2024-03-03T06:45:26.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25700
- author: deltanedas
changes:
- message: No more raiding the jani vend for galoshes, which are back to normal
@ -3855,3 +3753,111 @@
id: 6565
time: '2024-05-09T07:12:48.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27161
- author: Dutch-VanDerLinde
changes:
- message: Fixed non-inital infected getting the succumb to zombie action.
type: Fix
id: 6566
time: '2024-05-09T21:45:23.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27820
- author: Hanzdegloker
changes:
- message: Added CMO turtleneck jumpsuit/jumpskirt.
type: Add
- message: Added a head mirror which may spawn in medical doctor's lockers
type: Add
id: 6567
time: '2024-05-09T21:53:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26153
- author: PrPleGoo
changes:
- message: The crafted medsec hud now displays health icons too.
type: Tweak
- message: The health status icon now goes on the left for all types of med HUD.
type: Tweak
id: 6568
time: '2024-05-10T01:35:29.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27483
- author: Moomoobeef
changes:
- message: CentCom has now started hiring crew who are short-sighted.
type: Add
id: 6569
time: '2024-05-10T01:40:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26037
- author: whateverusername0
changes:
- message: Traitors now know their employers.
type: Tweak
id: 6570
time: '2024-05-10T02:01:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27855
- author: Boaz1111
changes:
- message: Loneops now has a functioning ghost role raffle.
type: Fix
id: 6571
time: '2024-05-10T02:01:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27841
- author: Boaz1111
changes:
- message: You can now actually spawn as a reporter on Oasis
type: Fix
- message: Oasis now has roundstart sec radios instead of handheld radios mapped
in sec, det now has a criminal records computer on box
type: Tweak
id: 6572
time: '2024-05-10T02:15:34.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27564
- author: notquitehadouken
changes:
- message: You can now only use suit storage with hardsuits, softsuits, and armor
instead of all outer clothing
type: Tweak
id: 6573
time: '2024-05-10T02:19:08.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27546
- author: aspiringLich
changes:
- message: The Chemical, Booze, and Soda Dispensers now have updated UIs.
type: Add
id: 6574
time: '2024-05-10T02:37:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27831
- author: Jajsha
changes:
- message: Emagged cyborgs no longer reveal that they have been emagged by simply
examining their internals.
type: Tweak
id: 6575
time: '2024-05-10T02:57:34.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27816
- author: RiceMar
changes:
- message: Larger guns are now wieldable and suffer an inaccuracy when not wielded.
type: Add
id: 6576
time: '2024-05-10T02:58:15.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26970
- author: Doctor-Cpu
changes:
- message: Atlas has been reworked.
type: Tweak
id: 6577
time: '2024-05-10T08:12:14.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27702
- author: TheShuEd
changes:
- message: 'New events added to the game: Random ships with new ghost roles can
now come to the station.'
type: Add
id: 6578
time: '2024-05-10T11:35:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/24490
- author: MisterMecky
changes:
- message: Fland kitchen freezer now starts off cold
type: Fix
id: 6579
time: '2024-05-10T15:57:21.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27532

View file

@ -23,6 +23,7 @@ grid_fill = false
auto_call_time = 0
emergency = false
arrivals = false
preload_grids = false
[admin]
see_own_notes = true

View file

@ -4,7 +4,6 @@
[game]
desc = "Official English Space Station 14 servers. Vanilla, low roleplay."
lobbyenabled = true
lobby_auto_map_vote = false
soft_max_players = 80
panic_bunker.enabled = true
panic_bunker.disable_with_admins = true

View file

@ -10,9 +10,9 @@ reagent-dispenser-bound-user-interface-title = Reagent dispenser
## UI
reagent-dispenser-window-amount-to-dispense-label = Amount
reagent-dispenser-window-container-label = Container:
reagent-dispenser-window-clear-button = Clear
reagent-dispenser-window-eject-button = Eject
reagent-dispenser-window-eject-container-button = ⏏
reagent-dispenser-window-no-container-loaded-text = No container loaded.
reagent-dispenser-window-reagent-name-not-found-text = Reagent name not found
reagent-dispenser-window-unknown-reagent-text = Unknown reagent

View file

@ -4,6 +4,7 @@ traitor-round-end-codewords = The codewords were: [color=White]{$codewords}[/col
traitor-round-end-agent-name = traitor
objective-issuer-syndicate = [color=crimson]The Syndicate[/color]
objective-issuer-unknown = Unknown
# Shown at the end of a round of Traitor
@ -23,7 +24,7 @@ traitor-death-match-end-round-description-entry = {$originalName}'s PDA, with {$
# TraitorRole
traitor-role-greeting =
You are a syndicate agent.
You are an agent sent by {$corporation} on behalf of The Syndicate.
Your objectives and codewords are listed in the character menu.
Use the uplink loaded into your PDA to buy the tools you'll need for this mission.
Death to Nanotrasen!

View file

@ -224,6 +224,26 @@ ghost-role-information-syndicate-monkey-reinforcement-name = Syndicate Monkey Ag
ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them.
ghost-role-information-syndicate-monkey-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them.
ghost-role-information-lost-cargo-technical-name = Lost Cargo Technician
ghost-role-information-lost-cargo-technical-description = Something went wrong and your cargo shuttle with the goods was beamed into the sector to another station.
ghost-role-information-lost-cargo-technical-rules = You're a regular cargo technician from another station. Do what regular cargo do.
ghost-role-information-clown-troupe-name = Space Clown
ghost-role-information-clown-troupe-description = You and your troupe have come to cheer up this station with your best jokes. Honk!
ghost-role-information-clown-troupe-rules = Normal station crew rules apply.
ghost-role-information-traveling-chef-name = Traveling Chef
ghost-role-information-traveling-chef-description = You are a chef on a traveling shuttle of exotic cuisine. Delight the station with delicious food!
ghost-role-information-traveling-chef-rules = Normal station crew rules apply.
ghost-role-information-disaster-victim-name = Disaster Victim
ghost-role-information-disaster-victim-description = You were rescued in an escape pod from another station that suffered a terrible fate. Perhaps you will be found and rescued.
ghost-role-information-disaster-victim-rules = Normal station crew rules apply.
ghost-role-information-syndie-disaster-victim-name = Syndie Disaster Victim
ghost-role-information-syndie-disaster-victim-description = You're a regular passenger from a syndicate station. Unfortunately, an evacuation pod has thrown you into an enemy sector.....
ghost-role-information-syndie-disaster-victim-rules = Normal station crew rules apply. You are NOT an antagonist!
ghost-role-information-syndicate-kobold-reinforcement-name = Syndicate Kobold Agent
ghost-role-information-syndicate-kobold-reinforcement-description = Someone needs reinforcements. You, a trained kobold, will help them.
ghost-role-information-syndicate-kobold-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them.

View file

@ -0,0 +1 @@
station-event-unknown-shuttle-incoming = Attention! An unidentified space shuttle has been spotted approaching your sector.

View file

@ -42,5 +42,3 @@ laws-ui-state-law = State law:
laws-notify = You are bound to silicon laws, which you can view via the sidebar action. You are required to always follow your laws.
laws-update-notify = Your laws have been updated. You can view the changes via the sidebar action.
laws-compromised-examine = The [color=red]law-governing[/color] internals seem damaged...

View file

@ -1,6 +1,9 @@
trait-blindness-name = Blindness
trait-blindness-desc = You are legally blind, and can't see clearly past a few meters in front of you.
trait-poor-vision-name = Short-sighted
trait-poor-vision-desc = Your eyes are not what they once were, you have difficulty seeing things far away without corrective glasses.
trait-narcolepsy-name = Narcolepsy
trait-narcolepsy-desc = You fall asleep randomly

View file

@ -1,4 +1,4 @@
### Locale for wielding items; i.e. two-handing them
### Locale for wielding items; i.e. two-handing them
wieldable-verb-text-wield = Wield
wieldable-verb-text-unwield = Unwield
@ -17,3 +17,4 @@ wieldable-component-not-in-hands = { CAPITALIZE(THE($item)) } isn't in your hand
wieldable-component-requires = { CAPITALIZE(THE($item))} must be wielded!
gunwieldbonus-component-examine = This weapon has improved accuracy when wielded.

View file

@ -0,0 +1,350 @@
meta:
format: 6
postmapinit: false
tilemap:
0: Space
82: FloorShuttleOrange
85: FloorShuttleWhite
120: Lattice
121: Plating
entities:
- proto: ""
entities:
- uid: 1
components:
- type: MetaData
name: Evacuation pod
- type: Transform
parent: invalid
- type: MapGrid
chunks:
0,0:
ind: 0,0
tiles: eQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
version: 6
-1,0:
ind: -1,0
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
version: 6
0,-1:
ind: 0,-1
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
version: 6
-1,-1:
ind: -1,-1
tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAA
version: 6
- type: Broadphase
- type: Physics
bodyStatus: InAir
angularDamping: 0.05
linearDamping: 0.05
fixedRotation: False
bodyType: Dynamic
- type: Fixtures
fixtures: {}
- type: OccluderTree
- type: SpreaderGrid
- type: Shuttle
- type: GridPathfinding
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DecalGrid
chunkCollection:
version: 2
nodes: []
- type: GridAtmosphere
version: 2
data:
tiles:
0,-1:
0: 4368
1: 32
0,0:
1: 2
-1,0:
1: 8
-1,-1:
1: 128
uniqueMixes:
- volume: 2500
temperature: 293.15
moles:
- 21.824879
- 82.10312
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- volume: 2500
immutable: True
moles:
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
chunkSize: 4
- type: GasTileOverlay
- type: RadiationGridResistance
- type: NavMap
- proto: AirlockShuttle
entities:
- uid: 2
components:
- type: Transform
pos: 0.5,-2.5
parent: 1
- proto: APCBasic
entities:
- uid: 3
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 1.5,-0.5
parent: 1
- proto: AtmosDeviceFanTiny
entities:
- uid: 4
components:
- type: Transform
pos: 0.5,-2.5
parent: 1
- proto: BoxMRE
entities:
- uid: 6
components:
- type: Transform
parent: 5
- type: Physics
canCollide: False
- type: InsideEntityStorage
- proto: CableApcExtension
entities:
- uid: 10
components:
- type: Transform
pos: 1.5,-0.5
parent: 1
- uid: 11
components:
- type: Transform
pos: 0.5,-0.5
parent: 1
- uid: 12
components:
- type: Transform
pos: 0.5,-1.5
parent: 1
- proto: CableHV
entities:
- uid: 13
components:
- type: Transform
pos: -0.5,-1.5
parent: 1
- uid: 14
components:
- type: Transform
pos: -0.5,-0.5
parent: 1
- proto: CableMV
entities:
- uid: 15
components:
- type: Transform
pos: -0.5,-0.5
parent: 1
- uid: 16
components:
- type: Transform
pos: 0.5,-0.5
parent: 1
- uid: 17
components:
- type: Transform
pos: 1.5,-0.5
parent: 1
- proto: ChairPilotSeat
entities:
- uid: 18
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 0.5,-1.5
parent: 1
- proto: ClosetWallMaintenanceFilledRandom
entities:
- uid: 5
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 1.5,-1.5
parent: 1
- type: EntityStorage
air:
volume: 200
immutable: False
temperature: 293.14673
moles:
- 1.7459903
- 6.568249
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- 0
- type: ContainerContainer
containers:
entity_storage: !type:Container
showEnts: False
occludes: True
ents:
- 8
- 9
- 6
- 7
- proto: ClothingOuterSuitEmergency
entities:
- uid: 7
components:
- type: Transform
parent: 5
- type: Physics
canCollide: False
- type: InsideEntityStorage
- proto: ComputerShuttle
entities:
- uid: 19
components:
- type: Transform
pos: 0.5,-0.5
parent: 1
- proto: DisasterVictimSpawner
entities:
- uid: 20
components:
- type: Transform
pos: 0.5,-1.5
parent: 1
- proto: GeneratorWallmountAPU
entities:
- uid: 21
components:
- type: Transform
pos: -0.5,-1.5
parent: 1
- proto: Gyroscope
entities:
- uid: 32
components:
- type: Transform
pos: -0.5,-2.5
parent: 1
- proto: HandheldGPSBasic
entities:
- uid: 8
components:
- type: Transform
parent: 5
- type: Physics
canCollide: False
- type: InsideEntityStorage
- proto: Poweredlight
entities:
- uid: 22
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 0.5,-1.5
parent: 1
- proto: ShuttleWindow
entities:
- uid: 23
components:
- type: Transform
pos: 0.5,0.5
parent: 1
- proto: SubstationWallBasic
entities:
- uid: 24
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: -0.5,-0.5
parent: 1
- proto: Thruster
entities:
- uid: 25
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 1.5,-2.5
parent: 1
- proto: WallShuttle
entities:
- uid: 26
components:
- type: Transform
pos: -0.5,-0.5
parent: 1
- uid: 27
components:
- type: Transform
rot: 3.141592653589793 rad
pos: -0.5,-1.5
parent: 1
- uid: 28
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 1.5,-0.5
parent: 1
- uid: 29
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 1.5,-1.5
parent: 1
- proto: WallShuttleDiagonal
entities:
- uid: 30
components:
- type: Transform
pos: -0.5,0.5
parent: 1
- uid: 31
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 1.5,0.5
parent: 1
- proto: WeaponLaserSvalinn
entities:
- uid: 9
components:
- type: Transform
parent: 5
- type: Physics
canCollide: False
- type: InsideEntityStorage
...

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -61,6 +61,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -60,6 +60,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -67,6 +67,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -66,6 +66,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -68,6 +68,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -51,6 +51,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -70,6 +70,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -66,6 +66,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

View file

@ -62,6 +62,10 @@ entities:
- type: Gravity
gravityShakeSound: !type:SoundPathSpecifier
path: /Audio/Effects/alert.ogg
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
- type: DecalGrid
chunkCollection:
version: 2

File diff suppressed because it is too large Load diff

View file

@ -55,12 +55,13 @@ entities:
- type: MetaData
- type: Transform
- type: Map
mapPaused: True
- type: PhysicsMap
- type: GridTree
- type: MovedGrids
- type: Broadphase
- type: OccluderTree
- type: LoadedMap
- type: GridTree
- type: MovedGrids
- uid: 5691
components:
- type: MetaData
@ -11540,7 +11541,7 @@ entities:
pos: 24.5,16.5
parent: 8364
- type: Door
secondsUntilStateChange: -295.63562
secondsUntilStateChange: -354.4333
state: Opening
- type: DeviceLinkSource
lastSignals:
@ -69689,6 +69690,12 @@ entities:
rot: -1.5707963267948966 rad
pos: 12.5,33.5
parent: 8364
- uid: 9627
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -3.5,13.5
parent: 8364
- uid: 14307
components:
- type: Transform
@ -69936,12 +69943,6 @@ entities:
rot: -1.5707963267948966 rad
pos: -9.5,-26.5
parent: 8364
- uid: 9627
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -3.5,13.5
parent: 8364
- uid: 19297
components:
- type: Transform

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -27814,6 +27814,13 @@ entities:
- type: Transform
pos: -4.5,-19.5
parent: 31
- proto: ComputerRoboticsControl
entities:
- uid: 11453
components:
- type: Transform
pos: -0.5,-28.5
parent: 31
- proto: ComputerSalvageExpedition
entities:
- uid: 33

View file

@ -39,7 +39,10 @@
- id: ClothingNeckMantleCMO
- id: ClothingCloakCmo
- id: ClothingOuterCoatLabCmo
- id: ClothingUniformJumpsuitCMOTurtle
- id: ClothingUniformJumpskirtCMOTurtle
- id: ClothingHeadHatBeretCmo
- id: ClothingHeadMirror
- id: ClothingEyesGlasses
- id: ClothingOuterWinterCMO

View file

@ -45,6 +45,8 @@
contents:
- id: HandheldHealthAnalyzer
prob: 0.6
- id: ClothingHeadMirror
prob: 0.1
- id: ClothingHandsGlovesLatex
- id: ClothingHeadsetMedical
- id: ClothingEyesHudMedical

View file

@ -0,0 +1,12 @@
- type: dataset
id: TraitorCorporations
values:
- "CyberSun Industries"
- "Gorlex Marauders"
- "MI13"
- "Tiger Cooperative"
- "S.E.L.F."
- "Animal Rights Consortium"
- "Donk Corporation"
- "Waffle Corporation"
- "Interdyne Pharmaceutics"

View file

@ -162,6 +162,9 @@
- type: ShowHealthBars
damageContainers:
- Biological
- type: ShowHealthIcons
damageContainers:
- Biological
- type: entity
parent: [ClothingEyesBase, ShowSecurityIcons]

View file

@ -86,6 +86,17 @@
- type: Clothing
sprite: Clothing/Head/Misc/pwig.rsi
- type: entity
parent: ClothingHeadBase
id: ClothingHeadMirror
name: head mirror
description: I doubt even the CMO knows how to use this thing.
components:
- type: Sprite
sprite: Clothing/Head/Misc/head_mirror.rsi
- type: Clothing
sprite: Clothing/Head/Misc/head_mirror.rsi
- type: entity
parent: ClothingHeadBase
id: ClothingHeadHatRichard

View file

@ -21,6 +21,7 @@
Heat: 0.80
- type: ExplosionResistance
damageCoefficient: 0.90
- type: AllowSuitStorage
#Alternate / slim basic armor vest
- type: entity
@ -211,6 +212,7 @@
- type: ExplosionResistance
damageCoefficient: 0.65
- type: GroupExamine
- type: AllowSuitStorage
- type: entity
parent: ClothingOuterBaseLarge

View file

@ -138,6 +138,7 @@
- WhitelistChameleon
- type: ClothingRequiredStepTriggerImmune
slots: WITHOUT_POCKET
- type: AllowSuitStorage
- type: entity
abstract: true
@ -158,6 +159,7 @@
size: Huge
- type: ClothingRequiredStepTriggerImmune
slots: WITHOUT_POCKET
- type: AllowSuitStorage
- type: entity
parent: ClothingOuterBase

View file

@ -119,6 +119,17 @@
- type: Clothing
sprite: Clothing/Uniforms/Jumpskirt/cmo.rsi
- type: entity
parent: ClothingUniformSkirtBase
id: ClothingUniformJumpskirtCMOTurtle
name: chief medical officer's turtleneck jumpskirt
description: It's a turtleneck worn by those with the experience to be Chief Medical Officer. It provides minor biological protection.
components:
- type: Sprite
sprite: Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi
- type: Clothing
sprite: Clothing/Uniforms/Jumpskirt/cmo_turtle.rsi
- type: entity
parent: ClothingUniformSkirtBase
id: ClothingUniformJumpskirtDetective

View file

@ -264,6 +264,17 @@
- type: Clothing
sprite: Clothing/Uniforms/Jumpsuit/cmo.rsi
- type: entity
parent: ClothingUniformBase
id: ClothingUniformJumpsuitCMOTurtle
name: chief medical officer's turtleneck jumpsuit
description: It's a turtleneck worn by those with the experience to be Chief Medical Officer. It provides minor biological protection.
components:
- type: Sprite
sprite: Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi
- type: Clothing
sprite: Clothing/Uniforms/Jumpsuit/cmo_turtle.rsi
- type: entity
parent: ClothingUniformBase
id: ClothingUniformJumpsuitDetective

View file

@ -92,6 +92,8 @@
name: ghost-role-information-loneop-name
description: ghost-role-information-loneop-description
rules: ghost-role-information-loneop-rules
raffle:
settings: default
- type: GhostRoleAntagSpawner
- type: Sprite
sprite: Markers/jobs.rsi

View file

@ -838,3 +838,17 @@
- type: ConditionalSpawner
prototypes:
- MobLuminousEntity
- type: entity
name: clown spider spawner
id: SpawnClownSpider
parent: MarkerBase
components:
- type: Sprite
layers:
- state: green
- state: clown
sprite: Mobs/Animals/clownspider.rsi
- type: ConditionalSpawner
prototypes:
- MobClownSpider

View file

@ -248,8 +248,6 @@
- type: FootstepModifier
footstepSoundCollection:
collection: FootstepHoverBorg
params:
volume: -6
- type: TTS # Corvax-TTS
voice: TrainingRobot

View file

@ -595,3 +595,307 @@
settings: default
- type: GhostTakeoverAvailable
- type: Cluwne
## Lost Cargo technician
- type: entity
name: lost cargo technician spawner
id: LostCargoTechnicianSpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Objects/Tools/appraisal-tool.rsi
state: icon
- type: RandomSpawner
prototypes:
- RandomHumanoidLostCargoTechnician
chance: 1
- type: entity
id: RandomHumanoidLostCargoTechnician
name: lost cargo technician ghost role
components:
- type: Sprite
sprite: Objects/Tools/appraisal-tool.rsi
state: icon
- type: RandomHumanoidSpawner
settings: LostCargoTechnician
- type: randomHumanoidSettings
id: LostCargoTechnician
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-lost-cargo-technical-name
description: ghost-role-information-lost-cargo-technical-description
rules: ghost-role-information-lost-cargo-technical-rules
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobCargoTechnician ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last
# Clown troupe
- type: entity
name: clown troupe spawner
id: ClownTroupeSpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Objects/Fun/bikehorn.rsi
state: icon
- type: RandomSpawner
prototypes:
- RandomHumanoidClownTroupe
rarePrototypes:
- RandomHumanoidClownTroupeBanana
rareChance: 0.3
- type: entity
id: RandomHumanoidClownTroupe
name: clown troupe ghost role
components:
- type: Sprite
sprite: Objects/Tools/appraisal-tool.rsi
state: icon
- type: RandomHumanoidSpawner
settings: ClownTroupe
- type: entity
id: RandomHumanoidClownTroupeBanana
name: banana clown troupe
parent: RandomHumanoidClownTroupe
components:
- type: RandomHumanoidSpawner
settings: ClownTroupeBanana
- type: randomHumanoidSettings
id: ClownTroupe
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-clown-troupe-name
description: ghost-role-information-clown-troupe-description
rules: ghost-role-information-clown-troupe-rules
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobClown ]
- type: RandomMetadata
nameSegments:
- names_clown
- type: randomHumanoidSettings
id: ClownTroupeBanana
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-clown-troupe-name
description: ghost-role-information-clown-troupe-description
rules: ghost-role-information-clown-troupe-rules
- type: GhostTakeoverAvailable
- type: Loadout
prototypes: [ BananaClown ]
- type: RandomMetadata
nameSegments:
- names_clown
# Traveling exotic chef
- type: entity
name: traveling chef spawner
id: TravelingChefSpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Objects/Weapons/Melee/kitchen_knife.rsi
state: icon
- type: RandomSpawner
prototypes:
- RandomHumanoidTravelingChef
- type: entity
id: RandomHumanoidTravelingChef
name: traveling chef ghost role
components:
- type: Sprite
sprite: Objects/Tools/appraisal-tool.rsi
state: icon
- type: RandomHumanoidSpawner
settings: TravelingChef
- type: randomHumanoidSettings
id: TravelingChef
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-traveling-chef-name
description: ghost-role-information-traveling-chef-description
rules: ghost-role-information-traveling-chef-rules
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobChef ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last
# Disaster victim
- type: entity
name: disaster victim spawner
id: DisasterVictimSpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Clothing/OuterClothing/Hardsuits/basic.rsi
state: icon
- type: RandomSpawner
prototypes:
- RandomHumanoidDisasterVictimRD
- RandomHumanoidDisasterVictimCMO
- RandomHumanoidDisasterVictimCaptain
- MobSkeletonCloset
- type: entity
id: RandomHumanoidDisasterVictimRD
name: disaster victim RD ghost role
components:
- type: Sprite
sprite: Clothing/OuterClothing/Hardsuits/basic.rsi
state: icon
- type: RandomHumanoidSpawner
settings: DisasterVictimResearchDirector
- type: entity
id: RandomHumanoidDisasterVictimCMO
parent: RandomHumanoidDisasterVictimRD
name: disaster victim CMO ghost role
components:
- type: RandomHumanoidSpawner
settings: DisasterVictimCMO
- type: entity
id: RandomHumanoidDisasterVictimCaptain
parent: RandomHumanoidDisasterVictimRD
name: disaster victim Captain ghost role
components:
- type: RandomHumanoidSpawner
settings: DisasterVictimCaptain
- type: randomHumanoidSettings
id: DisasterVictimResearchDirector
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-disaster-victim-name
description: ghost-role-information-disaster-victim-description
rules: ghost-role-information-disaster-victim-rules
raffle:
settings: default
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobResearchDirector ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last
- type: randomHumanoidSettings
id: DisasterVictimCMO
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-disaster-victim-name
description: ghost-role-information-disaster-victim-description
rules: ghost-role-information-disaster-victim-rules
raffle:
settings: default
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobChiefMedicalOfficer ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last
- type: randomHumanoidSettings
id: DisasterVictimCaptain
randomizeName: false
components:
- type: GhostRole
name: ghost-role-information-disaster-victim-name
description: ghost-role-information-disaster-victim-description
rules: ghost-role-information-disaster-victim-rules
raffle:
settings: default
- type: GhostTakeoverAvailable
- type: Loadout
roleLoadout: [ JobCaptain ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last
# Syndie Disaster Victim
- type: entity
name: syndie disaster victim spawner
id: SyndieDisasterVictimSpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Decoration/banner.rsi
state: banner_syndicate
- type: RandomSpawner
prototypes:
- RandomHumanoidSyndieDisasterVictim
- type: entity
id: RandomHumanoidSyndieDisasterVictim
name: syndie disaster victim ghost role
components:
- type: Sprite
sprite: Structures/Decoration/banner.rsi
state: banner_syndicate
- type: RandomHumanoidSpawner
settings: SyndieDisasterVictim
- type: randomHumanoidSettings
id: SyndieDisasterVictim
randomizeName: false
components:
- type: NpcFactionMember
factions:
- Syndicate
- type: GhostRole
name: ghost-role-information-syndie-disaster-victim-name
description: ghost-role-information-syndie-disaster-victim-description
rules: ghost-role-information-syndie-disaster-victim-rules
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: Loadout
prototypes: [ SyndicateOperativeGearCivilian ]
- type: RandomMetadata
nameSegments:
- names_first
- names_last

View file

@ -0,0 +1,12 @@
# A basic inheritable template for a gun that is wieldable and has the standard inaccuracy.
- type: entity
id: BaseGunWieldable
abstract: true
components:
- type: Wieldable
- type: GunWieldBonus
minAngle: -20
maxAngle: -30
- type: Gun
minAngle: 21
maxAngle: 32

View file

@ -200,7 +200,7 @@
- type: entity
name: laser rifle
parent: BaseWeaponBattery
parent: [BaseWeaponBattery, BaseGunWieldable]
id: WeaponLaserCarbine
description: Favoured by Nanotrasen Security for being cheap and easy to use.
components:
@ -267,7 +267,7 @@
- type: entity
name: pulse carbine
parent: BaseWeaponBattery
parent: [BaseWeaponBattery, BaseGunWieldable]
id: WeaponPulseCarbine
description: A high tech energy carbine favoured by the NT-ERT operatives.
components:
@ -298,7 +298,7 @@
- type: entity
name: pulse rifle
parent: BaseWeaponBattery
parent: [BaseWeaponBattery, BaseGunWieldable]
id: WeaponPulseRifle
description: A weapon that is almost as infamous as its users.
components:
@ -325,7 +325,7 @@
- type: entity
name: laser cannon
parent: BaseWeaponBattery
parent: [BaseWeaponBattery, BaseGunWieldable]
id: WeaponLaserCannon
description: A heavy duty, high powered laser weapon.
components:
@ -380,7 +380,7 @@
- type: entity
name: x-ray cannon
parent: BaseWeaponBattery
parent: [BaseWeaponBattery, BaseGunWieldable]
id: WeaponXrayCannon
description: An experimental weapon that uses concentrated x-ray energy against its target.
components:

View file

@ -22,7 +22,7 @@
- type: entity
name: china lake
parent: BaseWeaponLauncher
parent: [BaseWeaponLauncher, BaseGunWieldable]
id: WeaponLauncherChinaLake
description: PLOOP
components:

View file

@ -1,6 +1,6 @@
- type: entity
name: BaseWeaponRifle
parent: BaseItem
parent: [BaseItem, BaseGunWieldable]
id: BaseWeaponRifle
description: A rooty tooty point and shooty.
abstract: true

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