Merge remote-tracking branch 'upstream/master' into ed-22-12-2024-upstream

This commit is contained in:
Ed
2024-12-30 15:05:05 +03:00
155 changed files with 59567 additions and 41267 deletions

12
.github/CODEOWNERS vendored
View File

@@ -3,17 +3,17 @@
# Sorting by path instead of by who added it one day :(
# this isn't how codeowners rules work pls read the first comment instead of trying to force a sorting order
/Resources/ConfigPresets/WizardsDen/ @nikthechampiongr
/Content.*/Administration/ @DrSmugleaf @nikthechampiongr
/Resources/ServerInfo/ @nikthechampiongr
/Resources/ServerInfo/Guidebook/ServerRules/ @nikthechampiongr
/Resources/ConfigPresets/WizardsDen/ @nikthechampiongr @crazybrain23
/Content.*/Administration/ @DrSmugleaf @nikthechampiongr @crazybrain23
/Resources/ServerInfo/ @nikthechampiongr @crazybrain23
/Resources/ServerInfo/Guidebook/ServerRules/ @nikthechampiongr @crazybrain23
/Resources/Prototypes/Maps/** @Emisse
/Resources/Prototypes/Body/ @DrSmugleaf # suffering
/Resources/Prototypes/Entities/Mobs/Player/ @DrSmugleaf
/Resources/Prototypes/Entities/Mobs/Species/ @DrSmugleaf
/Resources/Prototypes/Guidebook/rules.yml @nikthechampiongr
/Resources/Prototypes/Guidebook/rules.yml @nikthechampiongr @crazybrain23
/Content.*/Body/ @DrSmugleaf
/Content.YAMLLinter @DrSmugleaf
/Content.Shared/Damage/ @DrSmugleaf
@@ -25,7 +25,7 @@
# SKREEEE
/Content.*.Database/ @PJB3005 @DrSmugleaf
/Content.Shared.Database/Log*.cs @PJB3005 @DrSmugleaf @nikthechampiongr
/Content.Shared.Database/Log*.cs @PJB3005 @DrSmugleaf @nikthechampiongr @crazybrain23
/Pow3r/ @PJB3005
/Content.Server/Power/Pow3r/ @PJB3005

View File

@@ -1,17 +1,62 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'comms-console-menu-title'}"
MinSize="400 225">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="5">
<TextEdit Name="MessageInput" HorizontalExpand="True" VerticalExpand="True" Margin="0 0 0 5" MinHeight="100" />
<Button Name="AnnounceButton" Text="{Loc 'comms-console-menu-announcement-button'}" ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}" StyleClasses="OpenLeft" Access="Public" />
<Button Name="BroadcastButton" Text="{Loc 'comms-console-menu-broadcast-button'}" ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}" StyleClasses="OpenLeft" Access="Public" />
MinSize="400 300">
<OptionButton Name="AlertLevelButton" ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}" StyleClasses="OpenRight" Access="Public" />
<!-- Main Container -->
<BoxContainer Orientation="Vertical"
HorizontalExpand="False"
VerticalExpand="True"
Margin="6 6 6 5">
<Control MinSize="10 10" />
<TextEdit Name="MessageInput"
VerticalExpand="True"
HorizontalExpand="True"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
MinHeight="100"/>
<RichTextLabel Name="CountdownLabel" VerticalExpand="True" />
<Button Name="EmergencyShuttleButton" Text="Placeholder Text" ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}" Access="Public" />
<!-- ButtonsPart -->
<BoxContainer Orientation="Vertical"
VerticalAlignment="Bottom"
SeparationOverride="4">
<!-- AnnouncePart -->
<BoxContainer Orientation="Vertical"
Margin="0 2">
<Button Name="AnnounceButton"
Access="Public"
Text="{Loc 'comms-console-menu-announcement-button'}"
ToolTip="{Loc 'comms-console-menu-announcement-button-tooltip'}"
StyleClasses="OpenLeft"
Margin="0 0 1 0"
Disabled="True"/>
<Button Name="BroadcastButton"
Access="Public"
Text="{Loc 'comms-console-menu-broadcast-button'}"
ToolTip="{Loc 'comms-console-menu-broadcast-button-tooltip'}"
StyleClasses="OpenBoth"/>
<OptionButton Name="AlertLevelButton"
Access="Public"
ToolTip="{Loc 'comms-console-menu-alert-level-button-tooltip'}"
StyleClasses="OpenRight"/>
</BoxContainer>
<!-- EmergencyPart -->
<BoxContainer Orientation="Vertical"
SeparationOverride="6">
<RichTextLabel Name="CountdownLabel"/>
<Button Name="EmergencyShuttleButton"
Access="Public"
Text="Placeholder Text"
ToolTip="{Loc 'comms-console-menu-emergency-shuttle-button-tooltip'}"/>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -27,7 +27,11 @@
<!-- Header text -->
<BoxContainer MinHeight="60" Orientation="Vertical" VerticalAlignment="Center">
<Label Name="CallStatusText" Margin="10 5 10 0" ReservesSpace="False"/>
<RichTextLabel Name="CallerIdText" HorizontalAlignment="Center" Margin="0 0 0 0" ReservesSpace="False"/>
<BoxContainer Name="CallerIdContainer" Orientation="Vertical" ReservesSpace="False">
<RichTextLabel Name="CallerIdText" HorizontalAlignment="Center" Margin="0 0 0 0"/>
<Label Text="{Loc 'holopad-window-relay-label'}" Margin="10 5 10 0" ReservesSpace="False"/>
<RichTextLabel Name="HolopadIdText" HorizontalAlignment="Center" Margin="0 0 0 10"/>
</BoxContainer>
</BoxContainer>
<!-- Controls (the answer call button is absent when the phone is not ringing) -->
@@ -68,18 +72,25 @@
<PanelContainer Name="HolopadContactListHeaderPanel">
<Label Text="{Loc 'holopad-window-select-contact-from-list'}" HorizontalAlignment="Center" Margin="0 3 0 3"/>
</PanelContainer>
<PanelContainer Name="HolopadContactListPanel">
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="8, 8, 8, 8" MinHeight="256">
<BoxContainer Orientation="Vertical">
<!-- If there is no data yet, this will be displayed -->
<BoxContainer Name="FetchingAvailableHolopadsContainer" HorizontalAlignment="Center" HorizontalExpand="True" VerticalExpand="True" ReservesSpace="False">
<Label Text="{Loc 'holopad-window-fetching-contacts-list'}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</BoxContainer>
<!-- Contact filter -->
<LineEdit Name="SearchLineEdit" HorizontalExpand="True" Margin="4, 4, 4, 0"
PlaceHolder="{Loc holopad-window-filter-line-placeholder}" />
<!-- Container for the contacts -->
<BoxContainer Name="ContactsList" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="10 0 10 0"/>
</ScrollContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" Margin="8, 8, 8, 8" MinHeight="256">
<!-- If there is no data yet, this will be displayed -->
<BoxContainer Name="FetchingAvailableHolopadsContainer" HorizontalAlignment="Center" HorizontalExpand="True" VerticalExpand="True" ReservesSpace="False">
<Label Text="{Loc 'holopad-window-fetching-contacts-list'}" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</BoxContainer>
<!-- Container for the contacts -->
<BoxContainer Name="ContactsList" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="10 0 10 0"/>
</ScrollContainer>
</BoxContainer>
</PanelContainer>
</BoxContainer>

View File

@@ -171,8 +171,10 @@ public sealed partial class HolopadWindow : FancyWindow
// Caller ID text
var callerId = _telephoneSystem.GetFormattedCallerIdForEntity(telephone.LastCallerId.Item1, telephone.LastCallerId.Item2, Color.LightGray, "Default", 11);
var holoapdId = _telephoneSystem.GetFormattedDeviceIdForEntity(telephone.LastCallerId.Item3, Color.LightGray, "Default", 11);
CallerIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
HolopadIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(holoapdId));
LockOutIdText.SetMessage(FormattedMessage.FromMarkupOrThrow(callerId));
// Sort holopads alphabetically
@@ -236,10 +238,13 @@ public sealed partial class HolopadWindow : FancyWindow
// Make / update required children
foreach (var child in ContactsList.Children)
{
if (child is not HolopadContactButton)
if (child is not HolopadContactButton contactButton)
continue;
var contactButton = (HolopadContactButton)child;
var passesFilter = string.IsNullOrEmpty(SearchLineEdit.Text) ||
contactButton.Text?.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) == true;
contactButton.Visible = passesFilter;
contactButton.Disabled = (_currentState != TelephoneState.Idle || lockButtons);
}
@@ -290,7 +295,7 @@ public sealed partial class HolopadWindow : FancyWindow
FetchingAvailableHolopadsContainer.Visible = (ContactsList.ChildCount == 0);
ActiveCallControlsContainer.Visible = (_currentState != TelephoneState.Idle || _currentUiKey == HolopadUiKey.AiRequestWindow);
CallPlacementControlsContainer.Visible = !ActiveCallControlsContainer.Visible;
CallerIdText.Visible = (_currentState == TelephoneState.Ringing);
CallerIdContainer.Visible = (_currentState == TelephoneState.Ringing);
AnswerCallButton.Visible = (_currentState == TelephoneState.Ringing);
}
@@ -316,6 +321,7 @@ public sealed partial class HolopadWindow : FancyWindow
HorizontalExpand = true;
SetHeight = 32;
Margin = new Thickness(0f, 1f, 0f, 1f);
ReservesSpace = false;
}
public void UpdateValues(NetEntity netEntity, string label)

View File

@@ -28,6 +28,7 @@ public sealed partial class SensorMonitoringWindow : FancyWindow, IComputerWindo
public SensorMonitoringWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
public void UpdateState(ConsoleUIState state)

View File

@@ -104,7 +104,7 @@ public sealed class TippyUIController : UIController
? -WaddleRotation
: WaddleRotation;
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step))
if (EntityManager.TryGetComponent(_entity, out FootstepModifierComponent? step) && step.FootstepSoundCollection != null)
{
var audioParams = step.FootstepSoundCollection.Params
.AddVolume(-7f)

View File

@@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using Robust.Shared;
using Robust.Shared.Audio.Components;
using Robust.Shared.Configuration;
using Robust.Shared.GameObjects;
using Robust.Shared.Log;
@@ -216,14 +217,17 @@ namespace Content.IntegrationTests.Tests
/// generally not spawn unrelated / detached entities. Any entities that do get spawned should be parented to
/// the spawned entity (e.g., in a container). If an entity needs to spawn an entity somewhere in null-space,
/// it should delete that entity when it is no longer required. This test mainly exists to prevent "entity leak"
/// bugs, where spawning some entity starts spawning unrelated entities in null space.
/// bugs, where spawning some entity starts spawning unrelated entities in null space that stick around after
/// the original entity is gone.
///
/// Note that this isn't really a strict requirement, and there are probably quite a few edge cases. Its a pretty
/// crude test to try catch issues like this, and possibly should just be disabled.
/// </remarks>
[Test]
public async Task SpawnAndDeleteEntityCountTest()
{
var settings = new PoolSettings { Connected = true, Dirty = true };
await using var pair = await PoolManager.GetServerClient(settings);
var mapManager = pair.Server.ResolveDependency<IMapManager>();
var mapSys = pair.Server.System<SharedMapSystem>();
var server = pair.Server;
var client = pair.Client;
@@ -261,6 +265,9 @@ namespace Content.IntegrationTests.Tests
await pair.RunTicksSync(3);
// We consider only non-audio entities, as some entities will just play sounds when they spawn.
int Count(IEntityManager ent) => ent.EntityCount - ent.Count<AudioComponent>();
foreach (var protoId in protoIds)
{
// TODO fix ninja
@@ -268,8 +275,8 @@ namespace Content.IntegrationTests.Tests
if (protoId == "MobHumanSpaceNinja")
continue;
var count = server.EntMan.EntityCount;
var clientCount = client.EntMan.EntityCount;
var count = Count(server.EntMan);
var clientCount = Count(client.EntMan);
EntityUid uid = default;
await server.WaitPost(() => uid = server.EntMan.SpawnEntity(protoId, coords));
await pair.RunTicksSync(3);
@@ -277,30 +284,30 @@ namespace Content.IntegrationTests.Tests
// If the entity deleted itself, check that it didn't spawn other entities
if (!server.EntMan.EntityExists(uid))
{
if (server.EntMan.EntityCount != count)
if (Count(server.EntMan) != count)
{
Assert.Fail($"Server prototype {protoId} failed on deleting itself");
}
if (client.EntMan.EntityCount != clientCount)
if (Count(client.EntMan) != clientCount)
{
Assert.Fail($"Client prototype {protoId} failed on deleting itself\n" +
$"Expected {clientCount} and found {client.EntMan.EntityCount}.\n" +
$"Expected {clientCount} and found {Count(client.EntMan)}.\n" +
$"Server was {count}.");
}
continue;
}
// Check that the number of entities has increased.
if (server.EntMan.EntityCount <= count)
if (Count(server.EntMan) <= count)
{
Assert.Fail($"Server prototype {protoId} failed on spawning as entity count didn't increase");
}
if (client.EntMan.EntityCount <= clientCount)
if (Count(client.EntMan) <= clientCount)
{
Assert.Fail($"Client prototype {protoId} failed on spawning as entity count didn't increase" +
$"Expected at least {clientCount} and found {client.EntMan.EntityCount}. " +
$"Expected at least {clientCount} and found {Count(client.EntMan)}. " +
$"Server was {count}");
}
@@ -308,15 +315,15 @@ namespace Content.IntegrationTests.Tests
await pair.RunTicksSync(3);
// Check that the number of entities has gone back to the original value.
if (server.EntMan.EntityCount != count)
if (Count(server.EntMan) != count)
{
Assert.Fail($"Server prototype {protoId} failed on deletion count didn't reset properly");
}
if (client.EntMan.EntityCount != clientCount)
if (Count(client.EntMan) != clientCount)
{
Assert.Fail($"Client prototype {protoId} failed on deletion count didn't reset properly:\n" +
$"Expected {clientCount} and found {client.EntMan.EntityCount}.\n" +
$"Expected {clientCount} and found {Count(client.EntMan)}.\n" +
$"Server was {count}.");
}
}

View File

@@ -79,11 +79,11 @@ public sealed class StoreTests
var discountComponent = entManager.GetComponent<StoreDiscountComponent>(pda);
Assert.That(
discountComponent.Discounts,
Has.Exactly(3).Items,
$"After applying discount total discounted items count was expected to be '3' "
Has.Exactly(6).Items,
$"After applying discount total discounted items count was expected to be '6' "
+ $"but was actually {discountComponent.Discounts.Count}- this can be due to discount "
+ $"categories settings (maxItems, weight) not being realistically set, or default "
+ $"discounted count being changed from '3' in StoreDiscountSystem.InitializeDiscounts."
+ $"discounted count being changed from '6' in StoreDiscountSystem.InitializeDiscounts."
);
var discountedListingItems = storeComponent.FullListingsCatalog
.Where(x => x.IsCostModified)

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Content.Server.Administration.Managers;
using Robust.Shared.Toolshed;
namespace Content.IntegrationTests.Tests.Toolshed;
@@ -10,10 +11,23 @@ public sealed class AdminTest : ToolshedTest
[Test]
public async Task AllCommandsHavePermissions()
{
var toolMan = Server.ResolveDependency<ToolshedManager>();
var admin = Server.ResolveDependency<IAdminManager>();
var ignored = new HashSet<Assembly>()
{typeof(LocTest).Assembly, typeof(Robust.UnitTesting.Shared.Toolshed.LocTest).Assembly};
await Server.WaitAssertion(() =>
{
Assert.That(InvokeCommand("cmd:list where { acmd:perms isnull }", out var res));
Assert.That((IEnumerable<CommandSpec>) res, Is.Empty, "All commands must have admin permissions set up.");
Assert.Multiple(() =>
{
foreach (var cmd in toolMan.DefaultEnvironment.AllCommands())
{
if (ignored.Contains(cmd.Cmd.GetType().Assembly))
continue;
Assert.That(admin.TryGetCommandFlags(cmd, out _), $"Command does not have admin permissions set up: {cmd.FullName()}");
}
});
});
}
}

View File

@@ -1,6 +1,6 @@
using System.Collections.Generic;
using System.Globalization;
using Robust.Shared.IoC;
using System.Reflection;
using Robust.Shared.Localization;
using Robust.Shared.Toolshed;
@@ -14,10 +14,27 @@ public sealed class LocTest : ToolshedTest
[Test]
public async Task AllCommandsHaveDescriptions()
{
var locMan = Server.ResolveDependency<ILocalizationManager>();
var toolMan = Server.ResolveDependency<ToolshedManager>();
var locStrings = new HashSet<string>();
var ignored = new HashSet<Assembly>()
{typeof(LocTest).Assembly, typeof(Robust.UnitTesting.Shared.Toolshed.LocTest).Assembly};
await Server.WaitAssertion(() =>
{
Assert.That(InvokeCommand("cmd:list where { cmd:descloc loc:tryloc isnull }", out var res));
Assert.That((IEnumerable<CommandSpec>)res!, Is.Empty, "All commands must have localized descriptions.");
Assert.Multiple(() =>
{
foreach (var cmd in toolMan.DefaultEnvironment.AllCommands())
{
if (ignored.Contains(cmd.Cmd.GetType().Assembly))
continue;
var descLoc = cmd.DescLocStr();
Assert.That(locStrings.Add(descLoc), $"Duplicate command description key: {descLoc}");
Assert.That(locMan.TryGetString(descLoc, out _), $"Failed to get command description for command {cmd.FullName()}");
}
});
});
}
}

View File

@@ -74,15 +74,15 @@ public abstract class ToolshedTest : IInvocationContext
return (T) res!;
}
protected void ParseCommand(string command, Type? inputType = null, Type? expectedType = null, bool once = false)
protected void ParseCommand(string command, Type? inputType = null, Type? expectedType = null)
{
var parser = new ParserContext(command, Toolshed);
var success = CommandRun.TryParse(false, parser, inputType, expectedType, once, out _, out _, out var error);
var success = CommandRun.TryParse(parser, inputType, expectedType, out _);
if (error is not null)
ReportError(error);
if (parser.Error is not null)
ReportError(parser.Error);
if (error is null)
if (parser.Error is null)
Assert.That(success, $"Parse failed despite no error being reported. Parsed {command}");
}
@@ -153,11 +153,28 @@ public abstract class ToolshedTest : IInvocationContext
return _errors;
}
public bool HasErrors => _errors.Count > 0;
public void ClearErrors()
{
_errors.Clear();
}
public object? ReadVar(string name)
{
return Variables.GetValueOrDefault(name);
}
public void WriteVar(string name, object? value)
{
Variables[name] = value;
}
public IEnumerable<string> GetVars()
{
return Variables.Keys;
}
public Dictionary<string, object?> Variables { get; } = new();
protected void ExpectError(Type err)

View File

@@ -10,11 +10,7 @@ namespace Content.Server.Access;
public sealed class AddAccessLogCommand : ToolshedCommand
{
[CommandImplementation]
public void AddAccessLog(
[CommandInvocationContext] IInvocationContext ctx,
[CommandArgument] EntityUid input,
[CommandArgument] float seconds,
[CommandArgument] ValueRef<string> accessor)
public void AddAccessLog(IInvocationContext ctx, EntityUid input, float seconds, string accessor)
{
var accessReader = EnsureComp<AccessReaderComponent>(input);
@@ -23,19 +19,14 @@ public sealed class AddAccessLogCommand : ToolshedCommand
ctx.WriteLine($"WARNING: Surpassing the limit of the log by {accessLogCount - accessReader.AccessLogLimit+1} entries!");
var accessTime = TimeSpan.FromSeconds(seconds);
var accessName = accessor.Evaluate(ctx)!;
accessReader.AccessLog.Enqueue(new AccessRecord(accessTime, accessName));
accessReader.AccessLog.Enqueue(new AccessRecord(accessTime, accessor));
ctx.WriteLine($"Successfully added access log to {input} with this information inside:\n " +
$"Time of access: {accessTime}\n " +
$"Accessed by: {accessName}");
$"Accessed by: {accessor}");
}
[CommandImplementation]
public void AddAccessLogPiped(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] float seconds,
[CommandArgument] ValueRef<string> accessor)
public void AddAccessLogPiped(IInvocationContext ctx, [PipedArgument] EntityUid input, float seconds, string accessor)
{
AddAccessLog(ctx, input, seconds, accessor);
}

View File

@@ -408,6 +408,17 @@ namespace Content.Server.Administration.Managers
}
private async Task<(AdminData dat, int? rankId, bool specialLogin)?> LoadAdminData(ICommonSession session)
{
var result = await LoadAdminDataCore(session);
// Make sure admin didn't disconnect while data was loading.
if (session.Status != SessionStatus.InGame)
return null;
return result;
}
private async Task<(AdminData dat, int? rankId, bool specialLogin)?> LoadAdminDataCore(ICommonSession session)
{
var promoteHost = IsLocal(session) && _cfg.GetCVar(CCVars.ConsoleLoginLocal)
|| _promotedPlayers.Contains(session.UserId)

View File

@@ -7,7 +7,7 @@ namespace Content.Server.Administration.Toolshed;
public sealed class MarkedCommand : ToolshedCommand
{
[CommandImplementation]
public IEnumerable<EntityUid> Marked([CommandInvocationContext] IInvocationContext ctx)
public IEnumerable<EntityUid> Marked(IInvocationContext ctx)
{
var res = (IEnumerable<EntityUid>?)ctx.ReadVar("marked");
res ??= Array.Empty<EntityUid>();

View File

@@ -23,7 +23,7 @@ public sealed class RejuvenateCommand : ToolshedCommand
}
[CommandImplementation]
public void Rejuvenate([CommandInvocationContext] IInvocationContext ctx)
public void Rejuvenate(IInvocationContext ctx)
{
_rejuvenate ??= GetSys<RejuvenateSystem>();
if (ExecutingEntity(ctx) is not { } ent)

View File

@@ -8,6 +8,7 @@ using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers;
using System.Linq;
using Robust.Shared.Prototypes;
namespace Content.Server.Administration.Toolshed;
@@ -17,48 +18,38 @@ public sealed class SolutionCommand : ToolshedCommand
private SharedSolutionContainerSystem? _solutionContainer;
[CommandImplementation("get")]
public SolutionRef? Get(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string> name
)
public SolutionRef? Get([PipedArgument] EntityUid input, string name)
{
_solutionContainer ??= GetSys<SharedSolutionContainerSystem>();
if (_solutionContainer.TryGetSolution(input, name.Evaluate(ctx)!, out var solution))
if (_solutionContainer.TryGetSolution(input, name, out var solution))
return new SolutionRef(solution.Value);
return null;
}
[CommandImplementation("get")]
public IEnumerable<SolutionRef> Get(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ValueRef<string> name
)
public IEnumerable<SolutionRef> Get([PipedArgument] IEnumerable<EntityUid> input, string name)
{
return input.Select(x => Get(ctx, x, name)).Where(x => x is not null).Cast<SolutionRef>();
return input.Select(x => Get(x, name)).Where(x => x is not null).Cast<SolutionRef>();
}
[CommandImplementation("adjreagent")]
public SolutionRef AdjReagent(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] SolutionRef input,
[CommandArgument] Prototype<ReagentPrototype> name,
[CommandArgument] ValueRef<FixedPoint2> amountRef
ProtoId<ReagentPrototype> proto,
FixedPoint2 amount
)
{
_solutionContainer ??= GetSys<SharedSolutionContainerSystem>();
var amount = amountRef.Evaluate(ctx);
if (amount > 0)
{
_solutionContainer.TryAddReagent(input.Solution, name.Value.ID, amount, out _);
_solutionContainer.TryAddReagent(input.Solution, proto, amount, out _);
}
else if (amount < 0)
{
_solutionContainer.RemoveReagent(input.Solution, name.Value.ID, -amount);
_solutionContainer.RemoveReagent(input.Solution, proto, -amount);
}
return input;
@@ -66,12 +57,11 @@ public sealed class SolutionCommand : ToolshedCommand
[CommandImplementation("adjreagent")]
public IEnumerable<SolutionRef> AdjReagent(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<SolutionRef> input,
[CommandArgument] Prototype<ReagentPrototype> name,
[CommandArgument] ValueRef<FixedPoint2> amountRef
ProtoId<ReagentPrototype> name,
FixedPoint2 amount
)
=> input.Select(x => AdjReagent(ctx, x, name, amountRef));
=> input.Select(x => AdjReagent(x, name, amount));
}
public readonly record struct SolutionRef(Entity<SolutionComponent> Solution)

View File

@@ -36,82 +36,50 @@ public sealed class TagCommand : ToolshedCommand
}
[CommandImplementation("add")]
public EntityUid Add(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<TagPrototype>> @ref
)
public EntityUid Add([PipedArgument] EntityUid input, ProtoId<TagPrototype> tag)
{
_tag ??= GetSys<TagSystem>();
_tag.AddTag(input, @ref.Evaluate(ctx)!);
_tag.AddTag(input, tag);
return input;
}
[CommandImplementation("add")]
public IEnumerable<EntityUid> Add(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ValueRef<string, Prototype<TagPrototype>> @ref
)
=> input.Select(x => Add(ctx, x, @ref));
public IEnumerable<EntityUid> Add([PipedArgument] IEnumerable<EntityUid> input, ProtoId<TagPrototype> tag)
=> input.Select(x => Add(x, tag));
[CommandImplementation("rm")]
public EntityUid Rm(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string, Prototype<TagPrototype>> @ref
)
public EntityUid Rm([PipedArgument] EntityUid input, ProtoId<TagPrototype> tag)
{
_tag ??= GetSys<TagSystem>();
_tag.RemoveTag(input, @ref.Evaluate(ctx)!);
_tag.RemoveTag(input, tag);
return input;
}
[CommandImplementation("rm")]
public IEnumerable<EntityUid> Rm(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ValueRef<string, Prototype<TagPrototype>> @ref
)
=> input.Select(x => Rm(ctx, x, @ref));
public IEnumerable<EntityUid> Rm([PipedArgument] IEnumerable<EntityUid> input, ProtoId<TagPrototype> tag)
=> input.Select(x => Rm(x, tag));
[CommandImplementation("addmany")]
public EntityUid AddMany(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
public EntityUid AddMany([PipedArgument] EntityUid input, IEnumerable<ProtoId<TagPrototype>> tags)
{
_tag ??= GetSys<TagSystem>();
_tag.AddTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
_tag.AddTags(input, tags);
return input;
}
[CommandImplementation("addmany")]
public IEnumerable<EntityUid> AddMany(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
=> input.Select(x => AddMany(ctx, x, @ref));
public IEnumerable<EntityUid> AddMany([PipedArgument] IEnumerable<EntityUid> input, IEnumerable<ProtoId<TagPrototype>> tags)
=> input.Select(x => AddMany(x, tags.ToArray()));
[CommandImplementation("rmmany")]
public EntityUid RmMany(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
public EntityUid RmMany([PipedArgument] EntityUid input, IEnumerable<ProtoId<TagPrototype>> tags)
{
_tag ??= GetSys<TagSystem>();
_tag.RemoveTags(input, (IEnumerable<ProtoId<TagPrototype>>)@ref.Evaluate(ctx)!);
_tag.RemoveTags(input, tags);
return input;
}
[CommandImplementation("rmmany")]
public IEnumerable<EntityUid> RmMany(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ValueRef<IEnumerable<string>, IEnumerable<string>> @ref
)
=> input.Select(x => RmMany(ctx, x, @ref));
public IEnumerable<EntityUid> RmMany([PipedArgument] IEnumerable<EntityUid> input, IEnumerable<ProtoId<TagPrototype>> tags)
=> input.Select(x => RmMany(x, tags.ToArray()));
}

View File

@@ -14,7 +14,7 @@ public sealed class DeleteChatMessageCommand : ToolshedCommand
[Dependency] private readonly IEntitySystemManager _manager = default!;
[CommandImplementation("id")]
public void DeleteChatMessage([CommandInvocationContext] IInvocationContext ctx, [CommandArgument] uint messageId)
public void DeleteChatMessage(IInvocationContext ctx, uint messageId)
{
if (!_manager.GetEntitySystem<ChatRepositorySystem>().Delete(messageId))
{

View File

@@ -14,7 +14,7 @@ public sealed class NukeChatMessagesCommand : ToolshedCommand
[Dependency] private readonly IEntitySystemManager _manager = default!;
[CommandImplementation("usernames")]
public void Command([CommandInvocationContext] IInvocationContext ctx, [CommandArgument] string usernamesCsv)
public void Command(IInvocationContext ctx, string usernamesCsv)
{
var usernames = usernamesCsv.Split(',');

View File

@@ -151,8 +151,7 @@ public sealed class HolopadSystem : SharedHolopadSystem
if (IsHolopadControlLocked(entity, args.Actor))
return;
if (entityTelephone.CurrentState != TelephoneState.EndingCall && entityTelephone.CurrentState != TelephoneState.Idle)
_telephoneSystem.EndTelephoneCalls((entity, entityTelephone));
_telephoneSystem.EndTelephoneCalls((entity, entityTelephone));
// If the user is an AI, end all calls originating from its
// associated core to ensure that any broadcasts will end
@@ -160,8 +159,7 @@ public sealed class HolopadSystem : SharedHolopadSystem
!_stationAiSystem.TryGetStationAiCore((args.Actor, stationAiHeld), out var stationAiCore))
return;
if (TryComp<TelephoneComponent>(stationAiCore, out var telephone) &&
telephone.CurrentState != TelephoneState.EndingCall && telephone.CurrentState != TelephoneState.Idle)
if (TryComp<TelephoneComponent>(stationAiCore, out var telephone))
_telephoneSystem.EndTelephoneCalls((stationAiCore.Value, telephone));
}
@@ -215,7 +213,8 @@ public sealed class HolopadSystem : SharedHolopadSystem
{
var receiver = new Entity<TelephoneComponent>(receiverUid, receiverTelephone);
if (!_telephoneSystem.IsSourceAbleToReachReceiver(source, receiver))
// Check if the core can reach the call source, rather than the other way around
if (!_telephoneSystem.IsSourceAbleToReachReceiver(receiver, source))
continue;
if (_telephoneSystem.IsTelephoneEngaged(receiver))
@@ -230,10 +229,9 @@ public sealed class HolopadSystem : SharedHolopadSystem
LinkHolopadToUser(entity, args.Actor);
}
if (!reachableAiCores.Any())
return;
_telephoneSystem.BroadcastCallToTelephones(source, reachableAiCores, args.Actor);
// Ignore range so that holopads that ignore other devices on the same grid can request the AI
var options = new TelephoneCallOptions { IgnoreRange = true };
_telephoneSystem.BroadcastCallToTelephones(source, reachableAiCores, args.Actor, options);
}
#endregion
@@ -354,6 +352,9 @@ public sealed class HolopadSystem : SharedHolopadSystem
private void OnHolopadShutdown(Entity<HolopadComponent> entity, ref ComponentShutdown args)
{
if (TryComp<TelephoneComponent>(entity, out var telphone) && _telephoneSystem.IsTelephoneEngaged((entity.Owner, telphone)))
_telephoneSystem.EndTelephoneCalls((entity, telphone));
ShutDownHolopad(entity);
SetHolopadAmbientState(entity, false);
}
@@ -610,14 +611,8 @@ public sealed class HolopadSystem : SharedHolopadSystem
UnlinkHolopadFromUser(entity, entity.Comp.User.Value);
if (TryComp<StationAiCoreComponent>(entity, out var stationAiCore))
{
_stationAiSystem.SwitchRemoteEntityMode((entity.Owner, stationAiCore), true);
if (TryComp<TelephoneComponent>(entity, out var stationAiCoreTelphone) &&
stationAiCoreTelphone.CurrentState != TelephoneState.EndingCall && stationAiCoreTelphone.CurrentState != TelephoneState.Idle)
_telephoneSystem.EndTelephoneCalls((entity, stationAiCoreTelphone));
}
Dirty(entity);
}
@@ -668,8 +663,12 @@ public sealed class HolopadSystem : SharedHolopadSystem
var source = new Entity<TelephoneComponent>(stationAiCore.Value, stationAiTelephone);
// Check if the AI is unable to activate the projector (unlikely this will ever pass; its just a safeguard)
if (!_telephoneSystem.IsSourceInRangeOfReceiver(source, receiver))
{
_popupSystem.PopupEntity(Loc.GetString("holopad-ai-is-unable-to-activate-projector"), receiver, user);
return;
}
// Terminate any calls that the core is hosting and immediately connect to the receiver
_telephoneSystem.TerminateTelephoneCalls(source);
@@ -714,7 +713,6 @@ public sealed class HolopadSystem : SharedHolopadSystem
var receiverTelephoneEntity = new Entity<TelephoneComponent>(receiver, receiverTelephone);
if (sourceTelephoneEntity == receiverTelephoneEntity ||
receiverTelephone.UnlistedNumber ||
!_telephoneSystem.IsSourceAbleToReachReceiver(sourceTelephoneEntity, receiverTelephoneEntity))
continue;

View File

@@ -23,7 +23,6 @@ using Content.Shared.Timing;
using Content.Shared.Toggleable;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Timing;
namespace Content.Server.Medical;
@@ -32,7 +31,6 @@ namespace Content.Server.Medical;
/// </summary>
public sealed class DefibrillatorSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ChatSystem _chatManager = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly DoAfterSystem _doAfter = default!;
@@ -44,9 +42,9 @@ public sealed class DefibrillatorSystem : EntitySystem
[Dependency] private readonly MobThresholdSystem _mobThreshold = default!;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
/// <inheritdoc/>
public override void Initialize()
@@ -59,6 +57,7 @@ public sealed class DefibrillatorSystem : EntitySystem
{
if (args.Handled || args.Target is not { } target)
return;
args.Handled = TryStartZap(uid, target, args.User, component);
}
@@ -102,7 +101,7 @@ public sealed class DefibrillatorSystem : EntitySystem
return false;
}
if (_timing.CurTime < component.NextZapTime)
if (!TryComp(uid, out UseDelayComponent? useDelay) || _useDelay.IsDelayed((uid, useDelay), component.DelayId))
return false;
if (!TryComp<MobStateComponent>(target, out var mobState))
@@ -181,8 +180,10 @@ public sealed class DefibrillatorSystem : EntitySystem
_audio.PlayPvs(component.ZapSound, uid);
_electrocution.TryDoElectrocution(target, null, component.ZapDamage, component.WritheDuration, true, ignoreInsulation: true);
component.NextZapTime = _timing.CurTime + component.ZapDelay;
_appearance.SetData(uid, DefibrillatorVisuals.Ready, false);
if (!TryComp<UseDelayComponent>(uid, out var useDelay))
return;
_useDelay.SetLength((uid, useDelay), component.ZapDelay, component.DelayId);
_useDelay.TryResetDelay((uid, useDelay), id: component.DelayId);
ICommonSession? session = null;
@@ -240,20 +241,4 @@ public sealed class DefibrillatorSystem : EntitySystem
var ev = new TargetDefibrillatedEvent(user, (uid, component));
RaiseLocalEvent(target, ref ev);
}
public override void Update(float frameTime)
{
base.Update(frameTime);
var query = EntityQueryEnumerator<DefibrillatorComponent>();
while (query.MoveNext(out var uid, out var defib))
{
if (defib.NextZapTime == null || _timing.CurTime < defib.NextZapTime)
continue;
_audio.PlayPvs(defib.ReadySound, uid);
_appearance.SetData(uid, DefibrillatorVisuals.Ready, true);
defib.NextZapTime = null;
}
}
}

View File

@@ -29,19 +29,10 @@ public sealed class MindCommand : ToolshedCommand
}
[CommandImplementation("control")]
public EntityUid Control(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid target,
[CommandArgument] ValueRef<ICommonSession> playerRef)
public EntityUid Control(IInvocationContext ctx, [PipedArgument] EntityUid target, ICommonSession player)
{
_mind ??= GetSys<SharedMindSystem>();
var player = playerRef.Evaluate(ctx);
if (player is null)
{
ctx.ReportError(new NotForServerConsoleError());
return target;
}
if (!_mind.TryGetMind(player, out var mindId, out var mind))
{

View File

@@ -165,6 +165,9 @@ public sealed class DrinkSystem : SharedDrinkSystem
if (!HasComp<BodyComponent>(target))
return false;
if (!_body.TryGetBodyOrganEntityComps<StomachComponent>(target, out var stomachs))
return false;
if (_openable.IsClosed(item, user))
return true;

View File

@@ -45,10 +45,7 @@ public sealed class HelpProgressConditionSystem : EntitySystem
return;
}
var traitors = _traitorRule.GetOtherTraitorMindsAliveAndConnected(args.Mind)
.Select(pair => pair.Item1)
.ToHashSet();
var removeList = new List<EntityUid>();
var traitors = _traitorRule.GetOtherTraitorMindsAliveAndConnected(args.Mind).ToHashSet();
// cant help anyone who is tasked with helping:
// 1. thats boring
@@ -56,19 +53,26 @@ public sealed class HelpProgressConditionSystem : EntitySystem
foreach (var traitor in traitors)
{
// TODO: replace this with TryComp<ObjectivesComponent>(traitor) or something when objectives are moved out of mind
if (!TryComp<MindComponent>(traitor, out var mind))
if (!TryComp<MindComponent>(traitor.Id, out var mind))
continue;
foreach (var objective in mind.Objectives)
{
if (HasComp<HelpProgressConditionComponent>(objective))
removeList.Add(traitor);
traitors.RemoveWhere(x => x.Mind == mind);
}
}
foreach (var tot in removeList)
// Can't have multiple objectives to help/save the same person
foreach (var objective in args.Mind.Objectives)
{
traitors.Remove(tot);
if (HasComp<RandomTraitorAliveComponent>(objective) || HasComp<RandomTraitorProgressComponent>(objective))
{
if (TryComp<TargetObjectiveComponent>(objective, out var help))
{
traitors.RemoveWhere(x => x.Id == help.Target);
}
}
}
// no more helpable traitors
@@ -78,7 +82,7 @@ public sealed class HelpProgressConditionSystem : EntitySystem
return;
}
_target.SetTarget(uid, _random.Pick(traitors), target);
_target.SetTarget(uid, _random.Pick(traitors).Id, target);
}
private float GetProgress(EntityUid target)

View File

@@ -44,7 +44,19 @@ public sealed class KeepAliveConditionSystem : EntitySystem
return;
}
var traitors = Enumerable.ToList<(EntityUid Id, MindComponent Mind)>(_traitorRule.GetOtherTraitorMindsAliveAndConnected(args.Mind));
var traitors = _traitorRule.GetOtherTraitorMindsAliveAndConnected(args.Mind).ToHashSet();
// Can't have multiple objectives to help/save the same person
foreach (var objective in args.Mind.Objectives)
{
if (HasComp<RandomTraitorAliveComponent>(objective) || HasComp<RandomTraitorProgressComponent>(objective))
{
if (TryComp<TargetObjectiveComponent>(objective, out var help))
{
traitors.RemoveWhere(x => x.Id == help.Target);
}
}
}
// You are the first/only traitor.
if (traitors.Count == 0)

View File

@@ -6,6 +6,7 @@ using Content.Shared.Mind;
using Content.Shared.Objectives.Components;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
using System.Linq;
namespace Content.Server.Objectives.Systems;
@@ -52,8 +53,18 @@ public sealed class KillPersonConditionSystem : EntitySystem
if (target.Target != null)
return;
// no other humans to kill
var allHumans = _mind.GetAliveHumans(args.MindId);
// Can't have multiple objectives to kill the same person
foreach (var objective in args.Mind.Objectives)
{
if (HasComp<KillPersonConditionComponent>(objective) && TryComp<TargetObjectiveComponent>(objective, out var kill))
{
allHumans.RemoveWhere(x => x.Owner == kill.Target);
}
}
// no other humans to kill
if (allHumans.Count == 0)
{
args.Cancelled = true;

View File

@@ -20,7 +20,7 @@ public sealed class PolymorphCommand : ToolshedCommand
[CommandImplementation]
public EntityUid? Polymorph(
[PipedArgument] EntityUid input,
[CommandArgument] ProtoId<PolymorphPrototype> protoId
ProtoId<PolymorphPrototype> protoId
)
{
_system ??= GetSys<PolymorphSystem>();
@@ -34,7 +34,7 @@ public sealed class PolymorphCommand : ToolshedCommand
[CommandImplementation]
public IEnumerable<EntityUid> Polymorph(
[PipedArgument] IEnumerable<EntityUid> input,
[CommandArgument] ProtoId<PolymorphPrototype> protoId
ProtoId<PolymorphPrototype> protoId
)
=> input.Select(x => Polymorph(x, protoId)).Where(x => x is not null).Select(x => (EntityUid)x!);
}

View File

@@ -30,7 +30,7 @@ public sealed class JobsCommand : ToolshedCommand
=> stations.SelectMany(Jobs);
[CommandImplementation("job")]
public JobSlotRef Job([PipedArgument] EntityUid station, [CommandArgument] Prototype<JobPrototype> job)
public JobSlotRef Job([PipedArgument] EntityUid station, Prototype<JobPrototype> job)
{
_jobs ??= GetSys<StationJobsSystem>();
@@ -38,7 +38,7 @@ public sealed class JobsCommand : ToolshedCommand
}
[CommandImplementation("job")]
public IEnumerable<JobSlotRef> Job([PipedArgument] IEnumerable<EntityUid> stations, [CommandArgument] Prototype<JobPrototype> job)
public IEnumerable<JobSlotRef> Job([PipedArgument] IEnumerable<EntityUid> stations, Prototype<JobPrototype> job)
=> stations.Select(x => Job(x, job));
[CommandImplementation("isinfinite")]
@@ -50,63 +50,41 @@ public sealed class JobsCommand : ToolshedCommand
=> jobs.Select(x => IsInfinite(x, inverted));
[CommandImplementation("adjust")]
public JobSlotRef Adjust(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] JobSlotRef @ref,
[CommandArgument] ValueRef<int> by
)
public JobSlotRef Adjust([PipedArgument] JobSlotRef @ref, int by)
{
_jobs ??= GetSys<StationJobsSystem>();
_jobs.TryAdjustJobSlot(@ref.Station, @ref.Job, by.Evaluate(ctx), true, true);
_jobs.TryAdjustJobSlot(@ref.Station, @ref.Job, by, true, true);
return @ref;
}
[CommandImplementation("adjust")]
public IEnumerable<JobSlotRef> Adjust(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<JobSlotRef> @ref,
[CommandArgument] ValueRef<int> by
)
=> @ref.Select(x => Adjust(ctx, x, by));
public IEnumerable<JobSlotRef> Adjust([PipedArgument] IEnumerable<JobSlotRef> @ref, int by)
=> @ref.Select(x => Adjust(x, by));
[CommandImplementation("set")]
public JobSlotRef Set(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] JobSlotRef @ref,
[CommandArgument] ValueRef<int> by
)
public JobSlotRef Set([PipedArgument] JobSlotRef @ref, int by)
{
_jobs ??= GetSys<StationJobsSystem>();
_jobs.TrySetJobSlot(@ref.Station, @ref.Job, by.Evaluate(ctx), true);
_jobs.TrySetJobSlot(@ref.Station, @ref.Job, by, true);
return @ref;
}
[CommandImplementation("set")]
public IEnumerable<JobSlotRef> Set(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<JobSlotRef> @ref,
[CommandArgument] ValueRef<int> by
)
=> @ref.Select(x => Set(ctx, x, by));
public IEnumerable<JobSlotRef> Set([PipedArgument] IEnumerable<JobSlotRef> @ref, int by)
=> @ref.Select(x => Set(x, by));
[CommandImplementation("amount")]
public int Amount(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] JobSlotRef @ref
)
public int Amount([PipedArgument] JobSlotRef @ref)
{
_jobs ??= GetSys<StationJobsSystem>();
_jobs.TryGetJobSlot(@ref.Station, @ref.Job, out var slots);
return (int)(slots ?? 0);
return slots ?? 0;
}
[CommandImplementation("amount")]
public IEnumerable<int> Amount(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] IEnumerable<JobSlotRef> @ref
)
=> @ref.Select(x => Amount(ctx, x));
public IEnumerable<int> Amount([PipedArgument] IEnumerable<JobSlotRef> @ref)
=> @ref.Select(Amount);
}
// Used for Toolshed queries.

View File

@@ -27,7 +27,7 @@ public sealed class StationsCommand : ToolshedCommand
}
[CommandImplementation("get")]
public EntityUid Get([CommandInvocationContext] IInvocationContext ctx)
public EntityUid Get(IInvocationContext ctx)
{
_station ??= GetSys<StationSystem>();
@@ -54,7 +54,6 @@ public sealed class StationsCommand : ToolshedCommand
public EntityUid? LargestGrid([PipedArgument] EntityUid input)
{
_station ??= GetSys<StationSystem>();
return _station.GetLargestGrid(Comp<StationDataComponent>(input));
}
@@ -80,46 +79,30 @@ public sealed class StationsCommand : ToolshedCommand
=> input.Select(Config);
[CommandImplementation("addgrid")]
public void AddGrid(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<EntityUid> grid
)
public void AddGrid([PipedArgument] EntityUid input, EntityUid grid)
{
_station ??= GetSys<StationSystem>();
_station.AddGridToStation(input, grid.Evaluate(ctx));
_station.AddGridToStation(input, grid);
}
[CommandImplementation("rmgrid")]
public void RmGrid(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<EntityUid> grid
)
public void RmGrid([PipedArgument] EntityUid input, EntityUid grid)
{
_station ??= GetSys<StationSystem>();
_station.RemoveGridFromStation(input, grid.Evaluate(ctx));
_station.RemoveGridFromStation(input, grid);
}
[CommandImplementation("rename")]
public void Rename([CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input,
[CommandArgument] ValueRef<string> name
)
public void Rename([PipedArgument] EntityUid input, string name)
{
_station ??= GetSys<StationSystem>();
_station.RenameStation(input, name.Evaluate(ctx)!);
_station.RenameStation(input, name);
}
[CommandImplementation("rerollBounties")]
public void RerollBounties([CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] EntityUid input)
public void RerollBounties([PipedArgument] EntityUid input)
{
_cargo ??= GetSys<CargoSystem>();
_cargo.RerollBountyDatabase(input);
}
}

View File

@@ -94,7 +94,7 @@ namespace Content.Server.StationEvents
/// to even exist) so I think it's fine.
/// </remarks>
[CommandImplementation("simulate")]
public IEnumerable<(string, float)> Simulate([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] int rounds, [CommandArgument] int playerCount, [CommandArgument] float roundEndMean, [CommandArgument] float roundEndStdDev)
public IEnumerable<(string, float)> Simulate(EntityPrototype eventScheduler, int rounds, int playerCount, float roundEndMean, float roundEndStdDev)
{
_stationEvent ??= GetSys<EventManagerSystem>();
_entityTable ??= GetSys<EntityTableSystem>();
@@ -146,7 +146,7 @@ namespace Content.Server.StationEvents
}
[CommandImplementation("lsprob")]
public IEnumerable<(string, float)> LsProb([CommandArgument] EntityPrototype eventScheduler)
public IEnumerable<(string, float)> LsProb(EntityPrototype eventScheduler)
{
_compFac ??= IoCManager.Resolve<IComponentFactory>();
_stationEvent ??= GetSys<EventManagerSystem>();
@@ -166,7 +166,7 @@ namespace Content.Server.StationEvents
}
[CommandImplementation("lsprobtime")]
public IEnumerable<(string, float)> LsProbTime([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] float time)
public IEnumerable<(string, float)> LsProbTime(EntityPrototype eventScheduler, float time)
{
_compFac ??= IoCManager.Resolve<IComponentFactory>();
_stationEvent ??= GetSys<EventManagerSystem>();
@@ -188,7 +188,7 @@ namespace Content.Server.StationEvents
}
[CommandImplementation("prob")]
public float Prob([CommandArgument] EntityPrototype eventScheduler, [CommandArgument] string eventId)
public float Prob(EntityPrototype eventScheduler, string eventId)
{
_compFac ??= IoCManager.Resolve<IComponentFactory>();
_stationEvent ??= GetSys<EventManagerSystem>();

View File

@@ -16,6 +16,7 @@ using Robust.Shared.Containers;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Prototypes;
using Content.Server.Shuttles.Components;
namespace Content.Server.Storage.EntitySystems;
@@ -47,6 +48,8 @@ public sealed class BluespaceLockerSystem : EntitySystem
if (component.BehaviorProperties.BluespaceEffectOnInit)
BluespaceEffect(uid, component, component, true);
EnsureComp<ArrivalsBlacklistComponent>(uid); // To stop people getting to arrivals terminal
}
public void BluespaceEffect(EntityUid effectTargetUid, BluespaceLockerComponent effectSourceComponent, BluespaceLockerComponent? effectTargetComponent, bool bypassLimit = false)

View File

@@ -71,7 +71,7 @@ public sealed class StoreDiscountSystem : EntitySystem
private IReadOnlyList<StoreDiscountData> InitializeDiscounts(
IReadOnlyCollection<ListingDataWithCostModifiers> listings,
int totalAvailableDiscounts = 3
int totalAvailableDiscounts = 6
)
{
// Get list of categories with cumulative weights.

View File

@@ -151,7 +151,7 @@ public sealed class TelephoneSystem : SharedTelephoneSystem
break;
// Try to hang up if their has been no recent in-call activity
// Try to hang up if there has been no recent in-call activity
case TelephoneState.InCall:
if (_timing.CurTime > telephone.StateStartTime + TimeSpan.FromSeconds(telephone.IdlingTimeout))
EndTelephoneCalls(entity);
@@ -194,7 +194,7 @@ public sealed class TelephoneSystem : SharedTelephoneSystem
private bool TryCallTelephone(Entity<TelephoneComponent> source, Entity<TelephoneComponent> receiver, EntityUid user, TelephoneCallOptions? options = null)
{
if (!IsSourceAbleToReachReceiver(source, receiver))
if (!IsSourceAbleToReachReceiver(source, receiver) && options?.IgnoreRange != true)
return false;
if (IsTelephoneEngaged(receiver) &&
@@ -214,7 +214,8 @@ public sealed class TelephoneSystem : SharedTelephoneSystem
source.Comp.LinkedTelephones.Add(receiver);
source.Comp.Muted = options?.MuteSource == true;
receiver.Comp.LastCallerId = GetNameAndJobOfCallingEntity(user); // This will be networked when the state changes
var callerInfo = GetNameAndJobOfCallingEntity(user);
receiver.Comp.LastCallerId = (callerInfo.Item1, callerInfo.Item2, Name(source)); // This will be networked when the state changes
receiver.Comp.LinkedTelephones.Add(source);
receiver.Comp.Muted = options?.MuteReceiver == true;

View File

@@ -22,13 +22,9 @@ public sealed class ACmdCommand : ToolshedCommand
}
[CommandImplementation("caninvoke")]
public bool CanInvoke(
[CommandInvocationContext] IInvocationContext ctx,
[PipedArgument] CommandSpec command,
[CommandArgument] ValueRef<ICommonSession> player
)
public bool CanInvoke(IInvocationContext ctx, [PipedArgument] CommandSpec command, ICommonSession player)
{
// Deliberately discard the error.
return ((IPermissionController) _adminManager).CheckInvokable(command, player.Evaluate(ctx), out var err);
return ((IPermissionController) _adminManager).CheckInvokable(command, player, out _);
}
}

View File

@@ -15,10 +15,10 @@ public sealed class RunVerbAsCommand : ToolshedCommand
[CommandImplementation]
public IEnumerable<NetEntity> RunVerbAs(
[CommandInvocationContext] IInvocationContext ctx,
IInvocationContext ctx,
[PipedArgument] IEnumerable<NetEntity> input,
[CommandArgument] ValueRef<NetEntity> runner,
[CommandArgument] string verb
EntityUid runner,
string verb
)
{
_verb ??= GetSys<SharedVerbSystem>();
@@ -26,17 +26,14 @@ public sealed class RunVerbAsCommand : ToolshedCommand
foreach (var i in input)
{
var runnerNet = runner.Evaluate(ctx);
var runnerEid = EntityManager.GetEntity(runnerNet);
if (EntityManager.Deleted(runnerEid) && runnerEid.IsValid())
ctx.ReportError(new DeadEntity(runnerEid));
if (EntityManager.Deleted(runner) && runner.IsValid())
ctx.ReportError(new DeadEntity(runner));
if (ctx.GetErrors().Any())
yield break;
var eId = EntityManager.GetEntity(i);
var verbs = _verb.GetLocalVerbs(eId, runnerEid, Verb.VerbTypes, true);
var verbs = _verb.GetLocalVerbs(eId, runner, Verb.VerbTypes, true);
// if the "verb name" is actually a verb-type, try run any verb of that type.
var verbType = Verb.VerbTypes.FirstOrDefault(x => x.Name == verb);
@@ -45,7 +42,7 @@ public sealed class RunVerbAsCommand : ToolshedCommand
var verbTy = verbs.FirstOrDefault(v => v.GetType() == verbType);
if (verbTy != null)
{
_verb.ExecuteVerb(verbTy, runnerEid, eId, forced: true);
_verb.ExecuteVerb(verbTy, runner, eId, forced: true);
yield return i;
}
}
@@ -54,7 +51,7 @@ public sealed class RunVerbAsCommand : ToolshedCommand
{
if (verbTy.Text.ToLowerInvariant() == verb)
{
_verb.ExecuteVerb(verbTy, runnerEid, eId, forced: true);
_verb.ExecuteVerb(verbTy, runner, eId, forced: true);
yield return i;
}
}

View File

@@ -16,7 +16,7 @@ public sealed class VisualizeCommand : ToolshedCommand
[CommandImplementation]
public void VisualizeEntities(
[CommandInvocationContext] IInvocationContext ctx,
IInvocationContext ctx,
[PipedArgument] IEnumerable<EntityUid> input
)
{

View File

@@ -15,6 +15,7 @@ public sealed partial class GunSystem
{
var existing = component.Entities[^1];
component.Entities.RemoveAt(component.Entities.Count - 1);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
Containers.Remove(existing, component.Container);
EnsureShootable(existing);
@@ -22,6 +23,7 @@ public sealed partial class GunSystem
else if (component.UnspawnedCount > 0)
{
component.UnspawnedCount--;
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
ent = Spawn(component.Proto, coordinates);
EnsureShootable(ent.Value);
}

View File

@@ -39,8 +39,9 @@ public sealed partial class GunSystem
if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out _, out solution))
{
component.Shots = shots;
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));
component.MaxShots = maxShots;
Dirty(uid, component);
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));
return;
}
@@ -48,8 +49,10 @@ public sealed partial class GunSystem
maxShots = (int) (solution.MaxVolume / component.FireCost);
component.Shots = shots;
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.Shots));
component.MaxShots = maxShots;
Dirty(uid, component);
DirtyField(uid, component, nameof(SolutionAmmoProviderComponent.MaxShots));
UpdateSolutionAppearance(uid, component);
}

View File

@@ -534,7 +534,7 @@ namespace Content.Shared.Cuffs
{
_popup.PopupClient(Loc.GetString("handcuff-component-start-cuffing-target-message",
("targetName", Identity.Name(target, EntityManager, user))), user, user);
_popup.PopupClient(Loc.GetString("handcuff-component-start-cuffing-by-other-message",
_popup.PopupEntity(Loc.GetString("handcuff-component-start-cuffing-by-other-message",
("otherName", Identity.Name(user, EntityManager, target))), target, target);
}
@@ -642,10 +642,14 @@ namespace Content.Shared.Cuffs
_adminLog.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(user)} is trying to uncuff {ToPrettyString(target)}");
_popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-observer",
("user", Identity.Name(user, EntityManager)), ("target", Identity.Name(target, EntityManager))),
target, Filter.Pvs(target, entityManager: EntityManager)
.RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user), true);
_popup.PopupEntity(
Loc.GetString("cuffable-component-start-uncuffing-observer",
("user", Identity.Name(user, EntityManager)),
("target", Identity.Name(target, EntityManager))),
target,
Filter.Pvs(target, entityManager: EntityManager)
.RemoveWhere(e => e.AttachedEntity == target || e.AttachedEntity == user),
true);
if (target == user)
{
@@ -654,9 +658,13 @@ namespace Content.Shared.Cuffs
else
{
_popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-target-message",
("targetName", Identity.Name(target, EntityManager, user))), user, user);
_popup.PopupClient(Loc.GetString("cuffable-component-start-uncuffing-by-other-message",
("otherName", Identity.Name(user, EntityManager, target))), target, target);
("targetName", Identity.Name(target, EntityManager, user))),
user,
user);
_popup.PopupEntity(Loc.GetString("cuffable-component-start-uncuffing-by-other-message",
("otherName", Identity.Name(user, EntityManager, target))),
target,
target);
}
_audio.PlayPredicted(isOwner ? cuff.StartBreakoutSound : cuff.StartUncuffSound, target, user);

View File

@@ -12,22 +12,9 @@ namespace Content.Shared.Medical;
/// person back into the world of the living.
/// Uses <c>ItemToggleComponent</c>
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause]
[RegisterComponent, NetworkedComponent]
public sealed partial class DefibrillatorComponent : Component
{
/// <summary>
/// The time at which the zap cooldown will be completed
/// </summary>
[DataField("nextZapTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)]
[AutoPausedField]
public TimeSpan? NextZapTime;
/// <summary>
/// The minimum time between zaps
/// </summary>
[DataField("zapDelay"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan ZapDelay = TimeSpan.FromSeconds(5);
/// <summary>
/// How much damage is healed from getting zapped.
/// </summary>
@@ -46,6 +33,18 @@ public sealed partial class DefibrillatorComponent : Component
[DataField("writheDuration"), ViewVariables(VVAccess.ReadWrite)]
public TimeSpan WritheDuration = TimeSpan.FromSeconds(3);
/// <summary>
/// ID of the cooldown use delay.
/// </summary>
[DataField]
public string DelayId = "defib-delay";
/// <summary>
/// Cooldown after using the defibrillator.
/// </summary>
[DataField]
public TimeSpan ZapDelay = TimeSpan.FromSeconds(5);
/// <summary>
/// How long the doafter for zapping someone takes
/// </summary>
@@ -80,12 +79,6 @@ public sealed partial class DefibrillatorComponent : Component
public SoundSpecifier? ReadySound = new SoundPathSpecifier("/Audio/Items/Defib/defib_ready.ogg");
}
[Serializable, NetSerializable]
public enum DefibrillatorVisuals : byte
{
Ready
}
[Serializable, NetSerializable]
public sealed partial class DefibrillatorZapDoAfterEvent : SimpleDoAfterEvent
{

View File

@@ -9,6 +9,6 @@ namespace Content.Shared.Movement.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class FootstepModifierComponent : Component
{
[DataField(required: true), AutoNetworkedField]
public SoundSpecifier FootstepSoundCollection = default!;
[DataField, AutoNetworkedField]
public SoundSpecifier? FootstepSoundCollection;
}

View File

@@ -0,0 +1,20 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Movement.Components;
/// <summary>
/// Plays a sound whenever InputMover is running.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class MovementSoundComponent : Component
{
/// <summary>
/// Sound to play when InputMover has inputs.
/// </summary>
[DataField(required: true), AutoNetworkedField]
public SoundSpecifier? Sound;
[DataField, AutoNetworkedField]
public EntityUid? SoundEntity;
}

View File

@@ -0,0 +1,44 @@
using Content.Shared.Movement.Components;
using Content.Shared.Movement.Events;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Shared.Movement.Systems;
/// <summary>
/// Plays a sound on MoveInputEvent.
/// </summary>
public sealed class MovementSoundSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MovementSoundComponent, MoveInputEvent>(OnMoveInput);
}
private void OnMoveInput(Entity<MovementSoundComponent> ent, ref MoveInputEvent args)
{
if (!_timing.IsFirstTimePredicted)
return;
var oldMoving = (SharedMoverController.GetNormalizedMovement(args.OldMovement) & MoveButtons.AnyDirection) != MoveButtons.None;
var moving = (SharedMoverController.GetNormalizedMovement(args.Entity.Comp.HeldMoveButtons) & MoveButtons.AnyDirection) != MoveButtons.None;
if (oldMoving == moving)
return;
if (moving)
{
DebugTools.Assert(ent.Comp.SoundEntity == null);
ent.Comp.SoundEntity = _audio.PlayPredicted(ent.Comp.Sound, ent.Owner, ent.Owner)?.Entity;
}
else
{
ent.Comp.SoundEntity = _audio.Stop(ent.Comp.SoundEntity);
}
}
}

View File

@@ -439,14 +439,14 @@ public abstract partial class SharedMoverController : VirtualController
if (FootstepModifierQuery.TryComp(uid, out var moverModifier))
{
sound = moverModifier.FootstepSoundCollection;
return true;
return sound != null;
}
if (_inventory.TryGetSlotEntity(uid, "shoes", out var shoes) &&
FootstepModifierQuery.TryComp(shoes, out var modifier))
{
sound = modifier.FootstepSoundCollection;
return true;
return sound != null;
}
return TryGetFootstepSound(uid, xform, shoes != null, out sound, tileDef: tileDef);
@@ -467,10 +467,9 @@ public abstract partial class SharedMoverController : VirtualController
if (FootstepModifierQuery.TryComp(xform.MapUid, out var modifier))
{
sound = modifier.FootstepSoundCollection;
return true;
}
return false;
return sound != null;
}
var position = grid.LocalToTile(xform.Coordinates);
@@ -493,7 +492,7 @@ public abstract partial class SharedMoverController : VirtualController
if (FootstepModifierQuery.TryComp(maybeFootstep, out var footstep))
{
sound = footstep.FootstepSoundCollection;
return true;
return sound != null;
}
}

View File

@@ -10,7 +10,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Generic;
namespace Content.Shared.Nutrition.Components;
[RegisterComponent, NetworkedComponent, Access(typeof(HungerSystem))]
[AutoGenerateComponentState, AutoGenerateComponentPause]
[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
public sealed partial class HungerComponent : Component
{
/// <summary>

View File

@@ -7,7 +7,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Nutrition.Components;
[RegisterComponent, NetworkedComponent, Access(typeof(ThirstSystem))]
[AutoGenerateComponentState, AutoGenerateComponentPause]
[AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
public sealed partial class ThirstComponent : Component
{
// Base stuff

View File

@@ -122,7 +122,7 @@ public sealed class HungerSystem : EntitySystem
{
entity.Comp.LastAuthoritativeHungerChangeTime = _timing.CurTime;
entity.Comp.LastAuthoritativeHungerValue = ClampHungerWithinThresholds(entity.Comp, value);
Dirty(entity);
DirtyField(entity.Owner, entity.Comp, nameof(HungerComponent.LastAuthoritativeHungerChangeTime));
}
private void UpdateCurrentThreshold(EntityUid uid, HungerComponent? component = null)
@@ -133,6 +133,7 @@ public sealed class HungerSystem : EntitySystem
var calculatedHungerThreshold = GetHungerThreshold(component);
if (calculatedHungerThreshold == component.CurrentThreshold)
return;
component.CurrentThreshold = calculatedHungerThreshold;
DoHungerThresholdEffects(uid, component);
}

View File

@@ -102,7 +102,8 @@ public sealed class ThirstSystem : EntitySystem
component.ThirstThresholds[ThirstThreshold.Dead],
component.ThirstThresholds[ThirstThreshold.OverHydrated]
);
Dirty(uid, component);
EntityManager.DirtyField(uid, component, nameof(ThirstComponent.CurrentThirst));
}
private bool IsMovementThreshold(ThirstThreshold threshold)

View File

@@ -16,13 +16,6 @@ public sealed partial class SprayPainterComponent : Component
[DataField]
public TimeSpan PipeSprayTime = TimeSpan.FromSeconds(1);
/// <summary>
/// DoAfterId for airlock spraying.
/// Pipes do not track doafters so you can spray multiple at once.
/// </summary>
[DataField]
public DoAfterId? AirlockDoAfter;
/// <summary>
/// Pipe color chosen to spray with.
/// </summary>

View File

@@ -60,8 +60,6 @@ public abstract class SharedSprayPainterSystem : EntitySystem
private void OnDoorDoAfter(Entity<SprayPainterComponent> ent, ref SprayPainterDoorDoAfterEvent args)
{
ent.Comp.AirlockDoAfter = null;
if (args.Handled || args.Cancelled)
return;
@@ -116,7 +114,7 @@ public abstract class SharedSprayPainterSystem : EntitySystem
if (args.Handled)
return;
if (!TryComp<SprayPainterComponent>(args.Used, out var painter) || painter.AirlockDoAfter != null)
if (!TryComp<SprayPainterComponent>(args.Used, out var painter))
return;
var group = Proto.Index<AirlockGroupPrototype>(ent.Comp.Group);
@@ -138,9 +136,6 @@ public abstract class SharedSprayPainterSystem : EntitySystem
if (!DoAfter.TryStartDoAfter(doAfterEventArgs, out var id))
return;
// since we are now spraying an airlock prevent spraying more at the same time
// pipes ignore this
painter.AirlockDoAfter = id;
args.Handled = true;
// Log the attempt

View File

@@ -36,4 +36,21 @@ public abstract class SharedTelephoneSystem : EntitySystem
return callerId;
}
public string GetFormattedDeviceIdForEntity(string? deviceName, Color fontColor, string fontType = "Default", int fontSize = 12)
{
if (deviceName == null)
{
return Loc.GetString("chat-telephone-unknown-device",
("color", fontColor),
("fontType", fontType),
("fontSize", fontSize));
}
return Loc.GetString("chat-telephone-device-id",
("deviceName", deviceName),
("color", fontColor),
("fontType", fontType),
("fontSize", fontSize));
}
}

View File

@@ -127,9 +127,10 @@ public sealed partial class TelephoneComponent : Component
/// <summary>
/// The presumed name and/or job of the last person to call this telephone
/// and the name of the device that they used to do so
/// </summary>
[ViewVariables, AutoNetworkedField]
public (string?, string?) LastCallerId;
public (string?, string?, string?) LastCallerId;
}
#region: Telephone events
@@ -181,6 +182,7 @@ public readonly record struct TelephoneMessageReceivedEvent(string Message, MsgC
[Serializable, NetSerializable]
public struct TelephoneCallOptions
{
public bool IgnoreRange; // The source can always reach its target
public bool ForceConnect; // The source immediately starts a call with the receiver, potentially interrupting a call that is already in progress
public bool ForceJoin; // The source smoothly joins a call in progress, or starts a normal call with the receiver if there is none
public bool MuteSource; // Chatter from the source is not transmitted - could be used for eavesdropping when combined with 'ForceJoin'

View File

@@ -1,6 +1,7 @@
using Content.Shared.Administration.Logs;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Maps;
@@ -41,6 +42,7 @@ public abstract partial class SharedToolSystem : EntitySystem
InitializeTile();
InitializeWelder();
SubscribeLocalEvent<ToolComponent, ToolDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<ToolComponent, ExaminedEvent>(OnExamine);
}
private void OnDoAfter(EntityUid uid, ToolComponent tool, ToolDoAfterEvent args)
@@ -57,6 +59,34 @@ public abstract partial class SharedToolSystem : EntitySystem
RaiseLocalEvent((object) ev);
}
private void OnExamine(Entity<ToolComponent> ent, ref ExaminedEvent args)
{
// If the tool has no qualities, exit early
if (ent.Comp.Qualities.Count == 0)
return;
var message = new FormattedMessage();
// Create a list to store tool quality names
var toolQualities = new List<string>();
// Loop through tool qualities and add localized names to the list
foreach (var toolQuality in ent.Comp.Qualities)
{
if (_protoMan.TryIndex<ToolQualityPrototype>(toolQuality ?? string.Empty, out var protoToolQuality))
{
toolQualities.Add(Loc.GetString(protoToolQuality.Name));
}
}
// Combine the qualities into a single string and localize the final message
var qualitiesString = string.Join(", ", toolQualities);
// Add the localized message to the FormattedMessage object
message.AddMarkupPermissive(Loc.GetString("tool-component-qualities", ("qualities", qualitiesString)));
args.PushMessage(message);
}
public void PlayToolSound(EntityUid uid, ToolComponent tool, EntityUid? user)
{
if (tool.UseSound == null)

View File

@@ -13,27 +13,27 @@ public partial class AmmoComponent : Component, IShootable
{
// Muzzle flash stored on ammo because if we swap a gun to whatever we may want to override it.
[ViewVariables(VVAccess.ReadWrite), DataField("muzzleFlash", customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string? MuzzleFlash = "MuzzleFlashEffect";
[DataField]
public EntProtoId? MuzzleFlash = "MuzzleFlashEffect";
}
/// <summary>
/// Spawns another prototype to be shot instead of itself.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true)]
public sealed partial class CartridgeAmmoComponent : AmmoComponent
{
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Prototype = default!;
[ViewVariables(VVAccess.ReadWrite), DataField("proto", required: true)]
public EntProtoId Prototype;
[ViewVariables(VVAccess.ReadWrite), DataField("spent")]
[ViewVariables(VVAccess.ReadWrite), DataField]
[AutoNetworkedField]
public bool Spent = false;
public bool Spent;
/// <summary>
/// Caseless ammunition.
/// </summary>
[DataField("deleteOnSpawn")]
[DataField]
public bool DeleteOnSpawn;
[DataField("soundEject")]

View File

@@ -7,13 +7,13 @@ using Robust.Shared.Prototypes;
namespace Content.Shared.Weapons.Ranged.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedGunSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), Access(typeof(SharedGunSystem))]
public sealed partial class BallisticAmmoProviderComponent : Component
{
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField]
public SoundSpecifier? SoundRack = new SoundPathSpecifier("/Audio/Weapons/Guns/Cock/smg_cock.ogg");
[ViewVariables(VVAccess.ReadWrite), DataField]
[DataField]
public SoundSpecifier? SoundInsert = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/bullet_insert.ogg");
[ViewVariables(VVAccess.ReadWrite), DataField]

View File

@@ -8,7 +8,7 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Weapons.Ranged.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), AutoGenerateComponentPause]
[Access(typeof(SharedGunSystem))]
public sealed partial class GunComponent : Component
{

View File

@@ -5,38 +5,38 @@ using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototy
namespace Content.Shared.Weapons.Ranged.Components;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedGunSystem))]
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(fieldDeltas: true), Access(typeof(SharedGunSystem))]
public sealed partial class SolutionAmmoProviderComponent : Component
{
/// <summary>
/// The solution where reagents are extracted from for the projectile.
/// </summary>
[DataField("solutionId", required: true), AutoNetworkedField]
[DataField(required: true), AutoNetworkedField]
public string SolutionId = default!;
/// <summary>
/// How much reagent it costs to fire once.
/// </summary>
[DataField("fireCost"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField]
[DataField, AutoNetworkedField]
public float FireCost = 5;
/// <summary>
/// The amount of shots currently available.
/// used for network predictions.
/// </summary>
[DataField("shots"), ViewVariables, AutoNetworkedField]
[DataField, AutoNetworkedField]
public int Shots;
/// <summary>
/// The max amount of shots the gun can fire.
/// used for network prediction
/// </summary>
[DataField("maxShots"), ViewVariables, AutoNetworkedField]
[DataField, AutoNetworkedField]
public int MaxShots;
/// <summary>
/// The prototype that's fired by the gun.
/// </summary>
[DataField("proto", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>)), ViewVariables(VVAccess.ReadWrite)]
public string Prototype = default!;
[DataField("proto")]
public EntProtoId Prototype;
}

View File

@@ -57,7 +57,7 @@ public abstract partial class SharedGunSystem
Audio.PlayPredicted(component.SoundInsert, uid, args.User);
args.Handled = true;
UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
}
private void OnBallisticAfterInteract(EntityUid uid, BallisticAmmoProviderComponent component, AfterInteractEvent args)
@@ -194,10 +194,9 @@ public abstract partial class SharedGunSystem
!Paused(uid))
{
gunComp.NextFire = Timing.CurTime + TimeSpan.FromSeconds(1 / gunComp.FireRateModified);
Dirty(uid, gunComp);
DirtyField(uid, gunComp, nameof(GunComponent.NextFire));
}
Dirty(uid, component);
Audio.PlayPredicted(component.SoundRack, uid, user);
var shots = GetBallisticShots(component);
@@ -228,7 +227,7 @@ public abstract partial class SharedGunSystem
{
component.UnspawnedCount = Math.Max(0, component.Capacity - component.Container.ContainedEntities.Count);
UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
}
}
@@ -249,18 +248,19 @@ public abstract partial class SharedGunSystem
args.Ammo.Add((entity, EnsureShootable(entity)));
component.Entities.RemoveAt(component.Entities.Count - 1);
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.Entities));
Containers.Remove(entity, component.Container);
}
else if (component.UnspawnedCount > 0)
{
component.UnspawnedCount--;
DirtyField(uid, component, nameof(BallisticAmmoProviderComponent.UnspawnedCount));
entity = Spawn(component.Proto, args.Coordinates);
args.Ammo.Add((entity, EnsureShootable(entity)));
}
}
UpdateBallisticAppearance(uid, component);
Dirty(uid, component);
}
private void OnBallisticAmmoCount(EntityUid uid, BallisticAmmoProviderComponent component, ref GetAmmoCountEvent args)

View File

@@ -119,7 +119,7 @@ public abstract partial class SharedGunSystem : EntitySystem
if (melee.NextAttack > component.NextFire)
{
component.NextFire = melee.NextAttack;
Dirty(uid, component);
EntityManager.DirtyField(uid, component, nameof(MeleeWeaponComponent.NextAttack));
}
}
@@ -200,7 +200,7 @@ public abstract partial class SharedGunSystem : EntitySystem
gun.ShotCounter = 0;
gun.ShootCoordinates = null;
gun.Target = null;
Dirty(uid, gun);
EntityManager.DirtyField(uid, gun, nameof(GunComponent.ShotCounter));
}
/// <summary>
@@ -211,6 +211,7 @@ public abstract partial class SharedGunSystem : EntitySystem
gun.ShootCoordinates = toCoordinates;
AttemptShoot(user, gunUid, gun);
gun.ShotCounter = 0;
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));
}
/// <summary>
@@ -228,7 +229,9 @@ public abstract partial class SharedGunSystem : EntitySystem
{
if (gun.FireRateModified <= 0f ||
!_actionBlockerSystem.CanAttack(user))
{
return;
}
var toCoordinates = gun.ShootCoordinates;
@@ -277,7 +280,7 @@ public abstract partial class SharedGunSystem : EntitySystem
}
// NextFire has been touched regardless so need to dirty the gun.
Dirty(gunUid, gun);
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.NextFire));
// Get how many shots we're actually allowed to make, due to clip size or otherwise.
// Don't do this in the loop so we still reset NextFire.
@@ -331,6 +334,7 @@ public abstract partial class SharedGunSystem : EntitySystem
// Even if we don't actually shoot update the ShotCounter. This is to avoid spamming empty sounds
// where the gun may be SemiAuto or Burst.
gun.ShotCounter += shots;
EntityManager.DirtyField(gunUid, gun, nameof(GunComponent.ShotCounter));
if (ev.Ammo.Count <= 0)
{
@@ -387,8 +391,6 @@ public abstract partial class SharedGunSystem : EntitySystem
if (_gravity.IsWeightless(user, userPhysics))
CauseImpulse(fromCoordinates, toCoordinates.Value, user, userPhysics);
}
Dirty(gunUid, gun);
}
public void Shoot(
@@ -442,7 +444,7 @@ public abstract partial class SharedGunSystem : EntitySystem
protected void SetCartridgeSpent(EntityUid uid, CartridgeAmmoComponent cartridge, bool spent)
{
if (cartridge.Spent != spent)
Dirty(uid, cartridge);
DirtyField(uid, cartridge, nameof(CartridgeAmmoComponent.Spent));
cartridge.Spent = spent;
Appearance.SetData(uid, AmmoVisuals.Spent, spent);
@@ -541,17 +543,59 @@ public abstract partial class SharedGunSystem : EntitySystem
RaiseLocalEvent(gun, ref ev);
comp.SoundGunshotModified = ev.SoundGunshot;
comp.CameraRecoilScalarModified = ev.CameraRecoilScalar;
comp.AngleIncreaseModified = ev.AngleIncrease;
comp.AngleDecayModified = ev.AngleDecay;
comp.MaxAngleModified = ev.MaxAngle;
comp.MinAngleModified = ev.MinAngle;
comp.ShotsPerBurstModified = ev.ShotsPerBurst;
comp.FireRateModified = ev.FireRate;
comp.ProjectileSpeedModified = ev.ProjectileSpeed;
if (comp.SoundGunshotModified != ev.SoundGunshot)
{
comp.SoundGunshotModified = ev.SoundGunshot;
DirtyField(gun, nameof(GunComponent.SoundGunshotModified));
}
Dirty(gun);
if (!MathHelper.CloseTo(comp.CameraRecoilScalarModified, ev.CameraRecoilScalar))
{
comp.CameraRecoilScalarModified = ev.CameraRecoilScalar;
DirtyField(gun, nameof(GunComponent.CameraRecoilScalarModified));
}
if (!comp.AngleIncreaseModified.EqualsApprox(ev.AngleIncrease))
{
comp.AngleIncreaseModified = ev.AngleIncrease;
DirtyField(gun, nameof(GunComponent.AngleIncreaseModified));
}
if (!comp.AngleDecayModified.EqualsApprox(ev.AngleDecay))
{
comp.AngleDecayModified = ev.AngleDecay;
DirtyField(gun, nameof(GunComponent.AngleDecayModified));
}
if (!comp.MaxAngleModified.EqualsApprox(ev.MinAngle))
{
comp.MaxAngleModified = ev.MaxAngle;
DirtyField(gun, nameof(GunComponent.MaxAngleModified));
}
if (!comp.MinAngleModified.EqualsApprox(ev.MinAngle))
{
comp.MinAngleModified = ev.MinAngle;
DirtyField(gun, nameof(GunComponent.MinAngleModified));
}
if (comp.ShotsPerBurstModified != ev.ShotsPerBurst)
{
comp.ShotsPerBurstModified = ev.ShotsPerBurst;
DirtyField(gun, nameof(GunComponent.ShotsPerBurstModified));
}
if (!MathHelper.CloseTo(comp.FireRateModified, ev.FireRate))
{
comp.FireRateModified = ev.FireRate;
DirtyField(gun, nameof(GunComponent.FireRateModified));
}
if (!MathHelper.CloseTo(comp.ProjectileSpeedModified, ev.ProjectileSpeed))
{
comp.ProjectileSpeedModified = ev.ProjectileSpeed;
DirtyField(gun, nameof(GunComponent.ProjectileSpeedModified));
}
}
protected abstract void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null);

View File

@@ -1 +0,0 @@
countdown.ogg is created by qwertyquerty and licensed under CC-BY-SA-3.0. It is taken from https://github.com/BeeStation/BeeStation-Hornet at commit 79b8cc23cfb347cf23ea70fc5f6f39afedf9cde7.

View File

@@ -3,11 +3,6 @@
copyright: "Created by Bolgarich"
source: "https://www.youtube.com/watch?v=SzEp2nv6oZ4"
- files: ["clearly_nuclear.ogg"]
license: "CC-BY-3.0"
copyright: "Created by mryikes"
source: "https://www.youtube.com/watch?v=chix8uz-oUQ"
- files: ["sound_station_14.ogg"]
license: "CC-BY-3.0"
copyright: "Created by Donchan"
@@ -17,3 +12,8 @@
license: "CC-BY-3.0"
copyright: "Created by mrjajkes"
source: "https://www.youtube.com/watch?v=gLSyt7AaqQM"
- files: ["countdown.ogg"]
license: "CC-BY-SA-3.0"
copyright: "Created by qwertyquerty"
source: "https://github.com/BeeStation/BeeStation-Hornet/commit/7f48971438492805af286023a72e7609a729234a"

View File

@@ -643,5 +643,26 @@ Entries:
id: 80
time: '2024-12-18T13:15:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33879
- author: ElectroJr
changes:
- message: Some toolshed command permissions have changed. The "emplace" and "iterate"
command no longer require QUER` permissions, they now match the "do" command
and only require DEBUG. Several previously unrestricted commands now require
the DEBUG flag.
type: Tweak
- message: Toolshed command parsing has changed. In particular, command substitution
(using the output of a command in place of another command's argument) now requires
that the command be wrapped in curly braces
type: Tweak
id: 81
time: '2024-12-21T07:02:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33980
- author: lzk228
changes:
- message: Fixed spray painter using while being aghost.
type: Fix
id: 82
time: '2024-12-24T02:25:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34001
Name: Admin
Order: 1

View File

@@ -1,203 +1,4 @@
Entries:
- author: deltanedas
changes:
- message: You can now build carp statues with luxury materials.
type: Add
id: 7237
time: '2024-08-28T13:08:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31261
- author: PopGamer46
changes:
- message: Fixed shuttles not being able to FTL onto the station
type: Fix
id: 7238
time: '2024-08-28T13:22:21.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31569
- author: themias
changes:
- message: Defibs batteries no longer drain when switched off
type: Fix
id: 7239
time: '2024-08-28T17:31:47.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31593
- author: themias
changes:
- message: Fixed the nuke disk being marked 'left behind' when escaping with it
on the shuttle
type: Fix
id: 7240
time: '2024-08-28T20:05:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31602
- author: Beck Thompson
changes:
- message: Gold and silver ring, gold and silver diamond ring, gold and silver gem
ring. They all can be obtained in salvage loot pools.
type: Add
id: 7241
time: '2024-08-28T20:48:46.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31372
- author: RumiTiger
changes:
- message: Cherry has been added to the game!
type: Add
- message: The recipe for cherry pie has been reintroduced to the game!
type: Add
id: 7242
time: '2024-08-29T01:30:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28962
- author: SlamBamActionman, Graded
changes:
- message: Added administration glasses to Captain and HoP lockers!
type: Add
id: 7243
time: '2024-08-29T01:58:16.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30447
- author: osjarw
changes:
- message: Fix air alarms not checking sensor states upon power returning.
type: Fix
id: 7244
time: '2024-08-29T02:43:27.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29857
- author: Winkarst-cpu
changes:
- message: Now railings render over tables.
type: Tweak
id: 7245
time: '2024-08-29T03:04:43.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31589
- author: metalgearsloth
changes:
- message: Fix storage UI being buggy.
type: Fix
id: 7246
time: '2024-08-29T03:23:37.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31616
- author: MisterMecky
changes:
- message: Changed strange pill possible reagents. They are no longer mostly composed
of amatoxin and space mirage.
type: Tweak
id: 7247
time: '2024-08-29T13:21:06.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30524
- author: slarticodefast
changes:
- message: Fixed energy shield visuals.
type: Fix
id: 7248
time: '2024-08-30T01:43:34.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31619
- author: DieselMohawk
changes:
- message: Added Armband to back of Security Jumpsuit
type: Fix
id: 7249
time: '2024-08-30T01:46:46.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31635
- author: Winkarst-cpu
changes:
- message: Potted plants now fade their sprites, just like trees.
type: Tweak
id: 7250
time: '2024-08-30T10:34:25.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31628
- author: AutoOtter
changes:
- message: Greatly reduced meteorite wall health for easier cleanup and repair.
type: Tweak
id: 7251
time: '2024-08-30T23:24:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31651
- author: slarticodefast
changes:
- message: The revenant can now fly through walls again.
type: Fix
id: 7252
time: '2024-08-31T03:02:58.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31670
- author: metalgearsloth
changes:
- message: Fix AI eye getting deleted by singulo.
type: Fix
id: 7253
time: '2024-08-31T08:24:12.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31556
- author: slarticodefast
changes:
- message: Fixed toggleable pointlights for the toy sword, lighters, welders and
arabian lamp.
type: Fix
id: 7254
time: '2024-08-31T08:28:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31655
- author: juliangiebel
changes:
- message: Adds the station anchor. It anchors stations in space and prevents them
from moving.
type: Add
id: 7255
time: '2024-08-31T14:40:28.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26098
- author: Moomoobeef
changes:
- message: medibelts are found in the medidrobe instead of in lockers.
type: Tweak
id: 7256
time: '2024-08-31T23:22:06.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31470
- author: EmoGarbage404
changes:
- message: Removed the reclaimer shuttle.
type: Remove
- message: Removed fultons and fulton beacons from the autolathe
type: Remove
- message: Adjusted equipment inside salvage lockers and vendors.
type: Tweak
id: 7257
time: '2024-08-31T23:39:32.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31333
- author: Moomoobeef
changes:
- message: Added flavors to an array of previously indescribable things.
type: Add
id: 7258
time: '2024-09-01T00:03:30.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31685
- author: Ilya246
changes:
- message: Fixed tip 26 being misinformation about the tesla. It now displays truthful
information.
type: Fix
id: 7259
time: '2024-09-01T11:03:23.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31705
- author: yuitop
changes:
- message: space dragon fire breath ability now has cursor indicator
type: Tweak
id: 7260
time: '2024-09-01T19:28:12.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31725
- author: EmoGarbage404
changes:
- message: The grappling gun is now available inside the salvage vendor. Additional
ones can be scavenged in space.
type: Add
- message: Removed the grappling gun from science research and lathes.
type: Remove
- message: Fixed issue that made the rope from the grappling gun not appear.
type: Fix
id: 7261
time: '2024-09-02T04:33:25.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31737
- author: yuitop
changes:
- message: added in-hand sprite for Smile the Slime
type: Add
id: 7262
time: '2024-09-02T04:36:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31731
- author: EmoGarbage404
changes:
- message: Space Carp and Sharkminnows are a bit weaker overall.
@@ -3938,3 +3739,202 @@
id: 7736
time: '2024-12-19T17:21:28.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33414
- author: Piras314
changes:
- message: Removed the nuke song "Clearly Nuclear" on request of the author.
type: Remove
id: 7737
time: '2024-12-20T14:35:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33971
- author: VlaDOS1408
changes:
- message: The Communication Console UI is now resizable.
type: Fix
id: 7738
time: '2024-12-20T16:17:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33655
- author: RatIRL
changes:
- message: Added All-Hostile ballistic turret.
type: Add
id: 7739
time: '2024-12-20T20:34:53.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33970
- author: Beck Thompson
changes:
- message: Defibrillator cooldowns are now clearly visible.
type: Tweak
id: 7740
time: '2024-12-20T21:26:56.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31251
- author: J C Denton
changes:
- message: Syndicate and NanoTrasen NPCs and turrets are now hostile to Dragons
and Carps
type: Tweak
id: 7741
time: '2024-12-20T21:38:27.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32515
- author: lzk228
changes:
- message: Item's tool function now shows on examine.
type: Add
id: 7742
time: '2024-12-20T22:15:40.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32436
- author: Pinkbat5
changes:
- message: Diona can now chirp.
type: Add
- message: Nymphs can scream and laugh like adult diona.
type: Add
id: 7743
time: '2024-12-20T22:34:44.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32511
- author: ScarKy0
changes:
- message: Syndicate uplinks now have 6 discounts instead of 3.
type: Tweak
id: 7744
time: '2024-12-21T02:14:08.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33950
- author: JustinWinningham
changes:
- message: Wood walls no longer require girders and are built from barricades instead.
type: Tweak
id: 7745
time: '2024-12-21T03:28:46.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33902
- author: ElectroJr
changes:
- message: Toolshed console commands have been reworked. Some old commands may no
longer work.
type: Tweak
id: 7746
time: '2024-12-21T06:45:48.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33598
- author: muburu
changes:
- message: Space Ninjas now have silent footsteps.
type: Tweak
id: 7747
time: '2024-12-23T14:24:10.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33280
- author: amatwiedle
changes:
- message: Borgs can no longer drink from tools provided by modules.
type: Fix
id: 7748
time: '2024-12-23T19:54:18.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/32964
- author: Booblesnoot42
changes:
- message: On Cog, an unnecessary protolathe was removed from cargo.
type: Remove
id: 7749
time: '2024-12-23T23:24:47.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34026
- author: Booblesnoot42
changes:
- message: On Amber, an unnecessary protolathe was removed from cargo.
type: Remove
id: 7750
time: '2024-12-23T23:24:54.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34027
- author: TheShuEd
changes:
- message: You can now select candles in trinkets loadout
type: Add
id: 7751
time: '2024-12-24T00:24:19.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33193
- author: lzk228
changes:
- message: Now you are allowed to paint multiple airlocks with the spray painter.
Along with that you can cancel the doafter by clicking on the door you are painting.
type: Tweak
id: 7752
time: '2024-12-24T02:25:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34001
- author: ArtisticRoomba
changes:
- message: Reinforced tables now require welding to construct and deconstruct.
type: Tweak
id: 7753
time: '2024-12-26T22:47:23.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33992
- author: crazybrain
changes:
- message: Bluespace lockers and quantum spin inverters can no longer go on the
arrivals shuttle.
type: Tweak
id: 7754
time: '2024-12-27T12:34:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34072
- author: Plykiya
changes:
- message: You now see a popup when being cuffed or uncuffed again.
type: Fix
id: 7755
time: '2024-12-27T13:34:32.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33639
- author: Alpaccalypse
changes:
- message: Power monitoring computer boards can no longer be researched or printed,
as originally intended.
type: Remove
id: 7756
time: '2024-12-28T10:13:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34078
- author: psykana
changes:
- message: Traitor can no longer get multiple objectives to save/help/kill the same
person
type: Fix
id: 7757
time: '2024-12-28T14:49:03.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33704
- author: chromiumboy
changes:
- message: The holoapd UI has been updated to include a text-based filter for the
contacts list, and also to specify the name of the holopad that incoming calls
originate from
type: Tweak
id: 7758
time: '2024-12-28T23:33:16.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34055
- author: zHonys
changes:
- message: Smile can now use hats
type: Add
id: 7759
time: '2024-12-29T01:49:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33924
- author: ewokswagger
changes:
- message: Pizza deliveries are now guaranteed to have at least one cotton pizza.
type: Tweak
id: 7760
time: '2024-12-29T01:50:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33997
- author: ArtisticRoomba, JuneSzalkowska
changes:
- message: New cotton dough slices and cotton dough rolls.
type: Add
- message: New cotton baguette, cotton crostini, cotton chevre-chaud, cotton bagel,
and cotton croissant recipes. You can make them by following the recipes for
regular baguettes, bagels, etc, but use cotton dough instead.
type: Add
- message: Slicing dough into thirds now divides the nutriment value into thirds.
Previously you could slice dough to triple your nutriment.
type: Fix
id: 7761
time: '2024-12-29T02:02:25.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33508
- author: Velcroboy
changes:
- message: Rolling joints no longer requires a cigarette filter.
type: Tweak
id: 7762
time: '2024-12-29T03:25:40.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34106

View File

@@ -41,3 +41,8 @@ alert.min_players_sharing_connection = 2
[atmos]
max_explosion_range = 5
[status]
privacy_policy_link = "https://account.spacestation14.com/Home/Privacy"
privacy_policy_identifier = "wizden"
privacy_policy_version = "2024-12-22"

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
action-name-toggle-wagging = Wagging Tail
action-description-toggle-wagging = Start or stop wagging tail.

View File

@@ -6,6 +6,7 @@ holopad-window-options = [color=darkgray][font size=10][italic]Please select an
# Call status
holopad-window-no-calls-in-progress = No holo-calls in progress
holopad-window-incoming-call = Incoming holo-call from:
holopad-window-relay-label = Originating at:
holopad-window-outgoing-call = Attempting to establish a connection...
holopad-window-call-in-progress = Holo-call in progress
holopad-window-call-ending = Disconnecting...
@@ -28,6 +29,7 @@ holopad-window-access-denied = Access denied
holopad-window-select-contact-from-list = Select a contact to initiate a holo-call
holopad-window-fetching-contacts-list = No holopads are currently contactable
holopad-window-contact-label = {CAPITALIZE($label)}
holopad-window-filter-line-placeholder = Search for a contact
# Flavor
holopad-window-flavor-left = ⚠ Do not enter while projector is active
@@ -39,6 +41,7 @@ holopad-hologram-name = hologram of {THE($name)}
# Holopad actions
holopad-activate-projector-verb = Activate holopad projector
holopad-ai-is-unable-to-reach-holopad = You are unable to interface with the source of the call, it is too far from your core.
holopad-ai-is-unable-to-activate-projector = You are unable to activate the holopad's projector, it is too far from your core.
# Mapping prototypes
# General
@@ -69,6 +72,8 @@ holopad-command-hos = Command - HoS
# Science
holopad-science-anomaly = Science - Anomaly
holopad-science-artifact = Science - Artifact
holopad-science-artifact-north = Science - Artifact North
holopad-science-artifact-south = Science - Artifact South
holopad-science-robotics = Science - Robotics
holopad-science-rnd = Science - R&D
holopad-science-front = Science - Front
@@ -84,6 +89,7 @@ holopad-medical-paramedic = Medical - Paramedic
holopad-medical-virology = Medical - Virology
holopad-medical-front = Medical - Front
holopad-medical-breakroom = Medical - Breakroom
holopad-medical-clinic = Medical - Clinic
# Cargo
holopad-cargo-front = Cargo - Front
@@ -92,6 +98,7 @@ holopad-cargo-salvage-bay = Cargo - Salvage Bay
holopad-cargo-breakroom = Cargo - Breakroom
holopad-cargo-ats = Cargo - ATS
holopad-cargo-shuttle = Cargo - Shuttle
holopad-cargo-mailroom = Cargo - Mailroom
# Engineering
holopad-engineering-atmos-front = Atmos - Front
@@ -104,6 +111,7 @@ holopad-engineering-telecoms = Engineering - Telecoms
holopad-engineering-tech-vault = Engineering - Tech Vault
holopad-engineering-ame = Engineering - AME
holopad-engineering-power = Engineering - Power
holopad-engineering-main = Engineering - Main
# Security
holopad-security-front = Security - Front
@@ -118,6 +126,8 @@ holopad-security-lawyer = Security - Lawyer
holopad-security-armory = Security - Armory
holopad-security-locker-room = Security - Locker Room
holopad-security-brig-med = Security - Brig Med
holopad-security-evac-checkpoint = Security - Evac Checkpoint
holopad-security-arrivals-checkpoint = Security - Arrivals Checkpoint
# Service
holopad-service-janitor = Service - Janitor

View File

@@ -9,6 +9,7 @@ station-beacon-hop = HOP
station-beacon-security = Security
station-beacon-brig = Brig
station-beacon-brig-med = Brig Med
station-beacon-warden = Warden
station-beacon-hos = HOS
station-beacon-armory = Armory
@@ -25,6 +26,8 @@ station-beacon-cryonics = Cryopods
station-beacon-cmo = CMO
station-beacon-morgue = Morgue
station-beacon-surgery = Surgery
station-beacon-psychology = Psychology
station-beacon-clinic = Clinic
station-beacon-science = Science
station-beacon-research-and-development = Research
@@ -62,12 +65,16 @@ station-beacon-janitor = Janitor
station-beacon-ai = AI
station-beacon-ai-sat = AI Sat
station-beacon-ai-core = AI Core
station-beacon-ai-upload = AI Upload
station-beacon-ai-power = AI Power
station-beacon-arrivals = Arrivals
station-beacon-evac = Evac
station-beacon-docking-arm = Docking Arm
station-beacon-eva-storage = EVA Storage
station-beacon-chapel = Chapel
station-beacon-library = Library
station-beacon-reporter = Reporter
station-beacon-dorms = Dorms
station-beacon-theater = Theater
station-beacon-tools = Tools

View File

@@ -5,4 +5,6 @@ chat-telephone-message-wrap-bold = [color={$color}][bold]{$name}[/bold] {$verb},
# Caller ID
chat-telephone-unknown-caller = [color={$color}][font={$fontType} size={$fontSize}][bolditalic]Unknown caller[/bolditalic][/font][/color]
chat-telephone-caller-id-with-job = [color={$color}][font={$fontType} size={$fontSize}][bold]{CAPITALIZE($callerName)} ({CAPITALIZE($callerJob)})[/bold][/font][/color]
chat-telephone-caller-id-without-job = [color={$color}][font={$fontType} size={$fontSize}][bold]{CAPITALIZE($callerName)}[/bold][/font][/color]
chat-telephone-caller-id-without-job = [color={$color}][font={$fontType} size={$fontSize}][bold]{CAPITALIZE($callerName)}[/bold][/font][/color]
chat-telephone-unknown-device = [color={$color}][font={$fontType} size={$fontSize}][bolditalic]Unknown device[/bolditalic][/font][/color]
chat-telephone-device-id = [color={$color}][font={$fontType} size={$fontSize}][bold]{CAPITALIZE($deviceName)}[/bold][/font][/color]

View File

@@ -0,0 +1 @@
tool-component-qualities = This item can be used for [color=yellow]{ $qualities }[/color].

File diff suppressed because it is too large Load Diff

View File

@@ -169,6 +169,10 @@ entities:
rot: 3.141592653589793 rad
pos: 0.5,-7.5
parent: 2
- type: DeviceList
devices:
- 144
- 95
- proto: AirCanister
entities:
- uid: 147
@@ -647,6 +651,9 @@ entities:
rot: -1.5707963267948966 rad
pos: 1.5,-6.5
parent: 2
- type: DeviceNetwork
deviceLists:
- 145
- proto: GasVentScrubber
entities:
- uid: 144
@@ -655,6 +662,9 @@ entities:
rot: -1.5707963267948966 rad
pos: 1.5,-0.5
parent: 2
- type: DeviceNetwork
deviceLists:
- 145
- proto: GeneratorBasic15kW
entities:
- uid: 96

View File

@@ -47,6 +47,11 @@ entities:
bodyType: Dynamic
- type: Fixtures
fixtures: {}
- type: DeviceNetwork
configurators: []
deviceLists: []
transmitFrequencyId: ShuttleTimer
deviceNetId: Wireless
- type: OccluderTree
- type: SpreaderGrid
- type: Shuttle

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

@@ -15493,7 +15493,7 @@ entities:
pos: 26.5,17.5
parent: 12
- type: Door
secondsUntilStateChange: -9377.86
secondsUntilStateChange: -9854.435
state: Opening
- type: DeviceLinkSink
invokeCounter: 1
@@ -157521,11 +157521,6 @@ entities:
- type: Transform
pos: -23.5,-21.5
parent: 12
- uid: 4165
components:
- type: Transform
pos: 57.5,-18.5
parent: 12
- uid: 7312
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

View File

@@ -59,7 +59,7 @@ tilemap:
122: FloorWoodTile
123: Lattice
124: Plating
126: PlatingBurnt
126: PlatingDamaged
129: TrainLattice
entities:
- proto: ""
@@ -32250,11 +32250,6 @@ entities:
- type: Transform
pos: -4.5,-312.5
parent: 2
- uid: 4726
components:
- type: Transform
pos: 4.5,-355.5
parent: 2
- uid: 13772
components:
- type: Transform
@@ -35082,6 +35077,12 @@ entities:
rot: -1.5707963267948966 rad
pos: -6.5,-146.5
parent: 2
- uid: 7565
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 5.5,-356.5
parent: 2
- proto: ChairFolding
entities:
- uid: 5222
@@ -36452,6 +36453,13 @@ entities:
- type: Transform
pos: -5.086961,-272.51526
parent: 2
- proto: ClothingEyesBlindfold
entities:
- uid: 7570
components:
- type: Transform
pos: 4.544596,-355.42102
parent: 2
- proto: ClothingEyesEyepatchHudBeer
entities:
- uid: 5427
@@ -37280,13 +37288,6 @@ entities:
rot: -1.5707963267948966 rad
pos: 8.5,-279.5
parent: 2
- proto: ComputerShuttleSalvage
entities:
- uid: 5560
components:
- type: Transform
pos: -5.5,-270.5
parent: 2
- proto: ComputerSolarControl
entities:
- uid: 5561
@@ -49489,7 +49490,7 @@ entities:
parent: 2
- type: Fixtures
fixtures: {}
- proto: FloraTree01
- proto: FloraTree
entities:
- uid: 7528
components:
@@ -49497,21 +49498,17 @@ entities:
rot: 3.141592653589793 rad
pos: 2.7296805,-40.53731
parent: 2
- proto: FloraTree05
entities:
- uid: 7529
components:
- type: Transform
pos: 11.2466135,-200.43379
parent: 2
- proto: FloraTree06
entities:
- uid: 7530
components:
- type: Transform
pos: 9.820292,-197.55566
parent: 2
- proto: FloraTreeLarge01
- proto: FloraTreeLarge
entities:
- uid: 7531
components:
@@ -49802,13 +49799,6 @@ entities:
parent: 2
- proto: GasMixer
entities:
- uid: 7565
components:
- type: Transform
pos: 5.5,-356.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 13428
components:
- type: Transform
@@ -49898,14 +49888,6 @@ entities:
- type: Transform
pos: -25.5,-253.5
parent: 2
- uid: 7570
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 7.5,-357.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 7571
components:
- type: Transform
@@ -50494,14 +50476,6 @@ entities:
parent: 2
- type: AtmosPipeColor
color: '#990000FF'
- uid: 7659
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 4.5,-356.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 7660
components:
- type: Transform
@@ -50596,14 +50570,6 @@ entities:
parent: 2
- type: AtmosPipeColor
color: '#990000FF'
- uid: 7672
components:
- type: Transform
rot: 3.141592653589793 rad
pos: 5.5,-357.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 7673
components:
- type: Transform
@@ -58329,14 +58295,6 @@ entities:
rot: 1.5707963267948966 rad
pos: -17.5,-252.5
parent: 2
- uid: 8644
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: 6.5,-357.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 8645
components:
- type: Transform
@@ -64747,20 +64705,6 @@ entities:
rot: 1.5707963267948966 rad
pos: -21.5,-245.5
parent: 2
- uid: 9446
components:
- type: Transform
pos: 5.5,-355.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 9447
components:
- type: Transform
pos: 4.5,-355.5
parent: 2
- type: AtmosPipeColor
color: '#FFD800FF'
- uid: 9450
components:
- type: Transform
@@ -76306,7 +76250,7 @@ entities:
pos: 8.5,-176.5
parent: 2
- type: Door
secondsUntilStateChange: -147491.25
secondsUntilStateChange: -148220.45
state: Closing
- uid: 11227
components:
@@ -78491,6 +78435,10 @@ entities:
showEnts: False
occludes: True
ent: 11564
item_slot: !type:ContainerSlot
showEnts: False
occludes: True
ent: null
- proto: MopItem
entities:
- uid: 627
@@ -78657,13 +78605,6 @@ entities:
- type: Transform
pos: -13.5,-257.5
parent: 2
- proto: NitrousOxideCanister
entities:
- uid: 11591
components:
- type: Transform
pos: 5.5,-355.5
parent: 2
- proto: NoticeBoard
entities:
- uid: 11592
@@ -91037,6 +90978,16 @@ entities:
parent: 2
- proto: TableReinforced
entities:
- uid: 4726
components:
- type: Transform
pos: 5.5,-355.5
parent: 2
- uid: 5560
components:
- type: Transform
pos: 4.5,-355.5
parent: 2
- uid: 11786
components:
- type: Transform
@@ -92596,6 +92547,13 @@ entities:
- type: Transform
pos: 4.883979,-282.15594
parent: 2
- proto: ToyFigurineChaplain
entities:
- uid: 7659
components:
- type: Transform
pos: 5.399611,-355.25436
parent: 2
- proto: ToyFigurineChemist
entities:
- uid: 13901

View File

@@ -317,8 +317,8 @@
- type: entity
id: ActionToggleWagging
name: action-name-toggle-wagging
description: action-description-toggle-wagging
name: Wagging Tail
description: Start or stop wagging your tail.
components:
- type: InstantAction
icon: { sprite: Mobs/Customization/reptilian_parts.rsi, state: tail_smooth_behind }

View File

@@ -7,7 +7,8 @@
- type: StorageFill
contents:
- id: FoodBoxPizzaFilled
amount: 4
amount: 3
- id: FoodBoxPizzaCotton
- id: LidSalami
prob: 0.01
@@ -20,7 +21,8 @@
- type: StorageFill
contents:
- id: FoodBoxPizzaFilled
amount: 16
amount: 15
- id: FoodBoxPizzaCotton
- id: LidSalami
prob: 0.04

View File

@@ -1,7 +1,7 @@
- type: discountCategory
id: rareDiscounts # Dirty-cheap items that are rarely used and can be discounted to 0-ish cost to encourage usage.
weight: 18
maxItems: 2
maxItems: 4
- type: discountCategory
id: usualDiscounts # Cheap items that are used not very often.
@@ -10,4 +10,4 @@
- type: discountCategory
id: veryRareDiscounts # Casually used items that are widely used but can be (rarely) discounted for epic lulz.
weight: 2
maxItems: 1
maxItems: 2

View File

@@ -136,6 +136,8 @@
# ninja are masters of sneaking around relatively quickly, won't break cloak
walkModifier: 1.1
sprintModifier: 1.3
- type: FootstepModifier
footstepSoundCollection: null
- type: entity
parent: ClothingShoesBaseButcherable

View File

@@ -3458,6 +3458,13 @@
gender: epicene
- type: Speech
speechVerb: Plant
speechSounds: Alto
allowedEmotes: ['Chirp']
- type: Vocal
sounds:
Male: UnisexDiona
Female: UnisexDiona
Unsexed: UnisexDiona
- type: Tag
tags:
- DoorBumpOpener

View File

@@ -712,7 +712,7 @@
- type: entity
name: Smile
id: MobSlimesPet
parent: MobAdultSlimes
parent: [MobAdultSlimes, StripableInventoryBase]
description: This masterpiece has gone through thousands of experiments. But it is the sweetest creature in the world. Smile Slime!
components:
- type: Sprite
@@ -722,6 +722,16 @@
- map: [ "enum.DamageStateVisualLayers.BaseUnshaded" ]
state: aslime-_3
shader: unshaded
- map: [ "head" ]
- type: Inventory
speciesId: slime
templateId: head
displacements:
head:
sizeMaps:
32:
sprite: Mobs/Pets/Smile/smile_displacement.rsi
state: head
- type: MobThresholds
thresholds:
0: Alive
@@ -767,7 +777,7 @@
Caustic: 1
- type: MultiHandedItem
- type: Item
sprite: Mobs/Pets/smile.rsi
sprite: Mobs/Pets/Smile/smile.rsi
size: Huge
- type: SentienceTarget
flavorKind: station-event-random-sentience-flavor-slime

View File

@@ -86,6 +86,7 @@
- MobLayer
- type: Speech
speechVerb: Plant
allowedEmotes: ['Chirp']
- type: Vocal
sounds:
Male: UnisexDiona

View File

@@ -47,3 +47,31 @@
Quantity: 5
- ReagentId: Nutriment
Quantity: 5
- type: entity
id: FoodBagelCotton
parent: FoodBagelBase
name: cotton bagel
description: A delicious bagel made with cotton dough.
components:
- type: FlavorProfile
flavors:
- bread
- cotton
- type: Sprite
state: bagel-cottondough
- type: Food
requiresSpecialDigestion: true
- type: Tag
tags:
- ClothMade
- type: SolutionContainerManager
solutions:
food:
maxVol: 12
reagents:
- ReagentId: Nutriment
Quantity: 2.5
- ReagentId: Fiber
Quantity: 2.5

View File

@@ -702,6 +702,46 @@
Blunt: 1 # bonk
# Tastes like France.
- type: entity
name: cotton baguette
parent: FoodBreadBaguette
id: FoodBreadBaguetteCotton
description: Bon azzétit!
components:
- type: Sprite
state: baguette-cotton
- type: SliceableFood
slice: FoodBreadBaguetteCottonSlice
- type: Food
requiresSpecialDigestion: true
- type: Tag
tags:
- Bread
- ClothMade
- type: Clothing
equippedPrefix: baguette-cotton
- type: Item
inhandVisuals:
left:
- state: baguette-cotton-inhand-left
right:
- state: baguette-cotton-inhand-right
- type: SolutionContainerManager
solutions:
food:
maxVol: 15
reagents:
- ReagentId: Nutriment
Quantity: 3
- ReagentId: Fiber
Quantity: 3
- ReagentId: Vitamin
Quantity: 1
- ReagentId: TableSalt
Quantity: 1
- ReagentId: Blackpepper
Quantity: 1
- type: entity
name: crostini
parent: FoodBreadSliceBase
@@ -724,6 +764,37 @@
- ReagentId: Blackpepper
Quantity: 0.1
- type: entity
name: cotton crostini
parent: FoodBreadBaguetteSlice
id: FoodBreadBaguetteCottonSlice
description: Bon az-zetite!
components:
- type: Sprite
state: crostini-cotton
- type: Food
requiresSpecialDigestion: true
- type: Tag
tags:
- Bread
- Slice
- ClothMade
- type: SolutionContainerManager
solutions:
food:
maxVol: 2
reagents:
- ReagentId: Nutriment
Quantity: 0.25
- ReagentId: Fiber
Quantity: 0.25
- ReagentId: Vitamin
Quantity: 0.1
- ReagentId: TableSalt
Quantity: 0.1
- ReagentId: Blackpepper
Quantity: 0.1
- type: entity
name: buttered toast
parent: FoodBreadSliceBase

View File

@@ -28,7 +28,7 @@
description: A delicious and spongy little cake.
components:
- type: Food
trash:
trash:
- FoodPlateMuffinTin
- type: Sprite
sprite: Objects/Consumable/Food/Baked/misc.rsi
@@ -609,6 +609,38 @@
- ReagentId: Vitamin
Quantity: 0.5
- type: entity
name: cotton chèvre chaud
parent: FoodBakedChevreChaud
id: FoodBakedChevreChaudCotton
description: A disk of slightly melted chèvre flopped on top of a... cotton crostini, and toasted all-round.
components:
- type: FlavorProfile
flavors:
- bread
- nutty
- creamy
- smokey
- cotton
- type: Sprite
state: chevrechaud-cotton
- type: Food
requiresSpecialDigestion: true
- type: Tag
tags:
- ClothMade
- type: SolutionContainerManager
solutions:
food:
maxVol: 5
reagents:
- ReagentId: Nutriment
Quantity: 1
- ReagentId: Fiber
Quantity: 1
- ReagentId: Vitamin
Quantity: 0.5
- type: entity
name: brownies
parent: FoodBakedBase
@@ -771,3 +803,35 @@
damage:
types:
Blunt: 0 # so the damage stats icon doesn't immediately give away the syndie ones
- type: entity
name: cotton croissant
parent: FoodBakedCroissant
id: FoodBakedCroissantCotton
description: Buttery, flaky, fibery goodness.
components:
- type: FlavorProfile
flavors:
- bread
- butter
- cotton
- type: Sprite
state: croissant-cotton
- type: Food
requiresSpecialDigestion: true
- type: Tag
tags:
- ClothMade
- type: SolutionContainerManager
solutions:
food:
maxVol: 7
reagents:
- ReagentId: Nutriment
Quantity: 1.5
- ReagentId: Fiber
Quantity: 1.5
- ReagentId: Butter
Quantity: 2
- ReagentId: Vitamin
Quantity: 1

View File

@@ -274,6 +274,17 @@
prob: 0.10
orGroup: Pizza
- id: KnifePlastic
- type: entity
name: pizza box
parent: FoodBoxPizzaFilled
id: FoodBoxPizzaCotton
suffix: Cotton Pizza
components:
- type: StorageFill
contents:
- id: FoodPizzaCotton
- id: KnifePlastic
# Nugget

View File

@@ -315,6 +315,13 @@
- type: Construction
graph: DoughRope
node: start
- type: SolutionContainerManager
solutions:
food:
maxVol: 6
reagents:
- ReagentId: Nutriment
Quantity: 5
- type: entity
name: dough rope
@@ -330,6 +337,13 @@
- type: Construction
graph: DoughRope
node: rolled
- type: SolutionContainerManager
solutions:
food:
maxVol: 6
reagents:
- ReagentId: Nutriment
Quantity: 5
- type: entity
name: cornmeal dough
@@ -426,9 +440,9 @@
- cotton
- type: Sprite
state: cotton-dough
# - type: SliceableFood # TODO add it
# count: 3
# slice: FoodDoughCottonSlice
- type: SliceableFood
count: 3
slice: FoodDoughCottonSlice
- type: Construction
graph: CottonPizza
node: start
@@ -446,6 +460,59 @@
- ReagentId: Fiber
Quantity: 10
- type: entity
name: cotton dough slice
parent: FoodBakingBase
id: FoodDoughCottonSlice
description: A slice of cotton dough.
components:
- type: FlavorProfile
flavors:
- dough
- cotton
- type: Sprite
state: cotton-dough-slice
- type: Tag
tags:
- Slice
- type: Construction
graph: DoughRopeCotton
node: start
- type: SolutionContainerManager
solutions:
food:
maxVol: 6
reagents:
- ReagentId: Nutriment
Quantity: 1.5
- ReagentId: Fiber
Quantity: 3.5
- type: entity
name: dough rope
parent: FoodBakingBase
id: FoodDoughCottonRope
description: A thin noodle of cotton dough. Can be cooked into a cotton bagel.
components:
- type: FlavorProfile
flavors:
- dough
- cotton
- type: Sprite
state: cotton-dough-rope
- type: Construction
graph: DoughRopeCotton
node: rolled
- type: SolutionContainerManager
solutions:
food:
maxVol: 6
reagents:
- ReagentId: Nutriment
Quantity: 1.5
- ReagentId: Fiber
Quantity: 3.5
- type: entity
name: raw pastry base
parent: FoodBakingBase
@@ -499,6 +566,9 @@
- type: Construction
graph: CottonPizza
node: flat
- type: SliceableFood
count: 3
slice: FoodCroissantRawCotton
- type: entity
name: pizza bread
@@ -818,3 +888,16 @@
reagents:
- ReagentId: Nutriment
Quantity: 3
- type: entity
name: raw cotton croissant
parent: FoodCroissantRaw
id: FoodCroissantRawCotton
description: Buttery, flaky, fibery goodness waiting to happen.
components:
- type: FlavorProfile
flavors:
- dough
- cotton
- type: Sprite
state: croissant-raw-cotton

View File

@@ -24,15 +24,19 @@
name: atmospheric alerts computer board
description: A computer printed circuit board for an atmospheric alerts computer.
components:
- type: Sprite
state: cpu_engineering
- type: ComputerBoard
prototype: ComputerAlert
- type: entity
parent: BaseComputerCircuitboard
id: AtmosMonitoringComputerCircuitboard
name: atmospheric network monitor board
description: A computer printed circuit board for an atmospheric network monitor.
components:
- type: Sprite
state: cpu_engineering
- type: ComputerBoard
prototype: ComputerAtmosMonitoring

View File

@@ -20,7 +20,7 @@
suffix: Admeme
parent: BaseItem
name: interdimensional teleporter
description: allows you to open stable portal gates that are not limited by distance
description: Allows you to open stable portal gates that are not limited by distance.
components:
- type: Sprite
sprite: /Textures/Objects/Devices/hand_teleporter.rsi
@@ -29,4 +29,4 @@
color: green
- type: HandTeleporter
firstPortalPrototype: PortalGatewayBlue
secondPortalPrototype: PortalGatewayOrange
secondPortalPrototype: PortalGatewayOrange

View File

@@ -178,6 +178,14 @@
- type: NavMapBeacon
defaultText: station-beacon-brig
- type: entity
parent: DefaultStationBeaconSecurity
id: DefaultStationBeaconBrigMed
suffix: Brig Med
components:
- type: NavMapBeacon
defaultText: station-beacon-brig-med
- type: entity
parent: DefaultStationBeaconSecurity
id: DefaultStationBeaconWardensOffice
@@ -299,6 +307,22 @@
- type: NavMapBeacon
defaultText: station-beacon-surgery
- type: entity
parent: DefaultStationBeaconMedical
id: DefaultStationBeaconPsychology
suffix: Psychology
components:
- type: NavMapBeacon
defaultText: station-beacon-psychology
- type: entity
parent: DefaultStationBeaconMedical
id: DefaultStationBeaconClinic
suffix: Clinic
components:
- type: NavMapBeacon
defaultText: station-beacon-clinic
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconScience
@@ -560,6 +584,22 @@
- type: NavMapBeacon
defaultText: station-beacon-ai-core
- type: entity
parent: DefaultStationBeaconAI
id: DefaultStationBeaconAIUpload
suffix: AI Upload
components:
- type: NavMapBeacon
defaultText: station-beacon-ai-upload
- type: entity
parent: DefaultStationBeaconAI
id: DefaultStationBeaconAIPower
suffix: AI Power
components:
- type: NavMapBeacon
defaultText: station-beacon-ai-power
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconArrivals
@@ -576,6 +616,14 @@
- type: NavMapBeacon
defaultText: station-beacon-evac
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconDockingArm
suffix: Docking Arm
components:
- type: NavMapBeacon
defaultText: station-beacon-docking-arm
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconEVAStorage
@@ -600,6 +648,14 @@
- type: NavMapBeacon
defaultText: station-beacon-library
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconReporter
suffix: Reporter
components:
- type: NavMapBeacon
defaultText: station-beacon-reporter
- type: entity
parent: DefaultStationBeacon
id: DefaultStationBeaconTheater

View File

@@ -12,6 +12,7 @@
- type: Item
size: Small
- type: Appearance
- type: ArrivalsBlacklist
- type: SwapTeleporter
teleporterWhitelist:
tags:

View File

@@ -13,9 +13,6 @@
map: [ "enum.ToggleVisuals.Layer" ]
visible: false
shader: unshaded
- state: ready
map: ["enum.PowerDeviceVisualLayers.Powered"]
shader: unshaded
- type: Appearance
- type: GenericVisualizer
visuals:
@@ -23,10 +20,6 @@
enum.ToggleVisuals.Layer:
True: { visible: true }
False: { visible: false }
enum.DefibrillatorVisuals.Ready:
enum.PowerDeviceVisualLayers.Powered:
True: { visible: true }
False: { visible: false }
- type: Item
size: Large
- type: Speech

View File

@@ -195,6 +195,15 @@
factions:
- SimpleHostile
- type: entity
parent: BaseWeaponTurret
id: WeaponTurretAllHostile
suffix: All hostile
components:
- type: NpcFactionMember
factions:
- AllHostile
- type: entity
name: xeno turret
description: Shoots 9mm acid projectiles.

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