Merge remote-tracking branch 'space-wizards/master'

# Conflicts:
#	Content.Shared/Access/Components/AccessReaderComponent.cs
#	Resources/Locale/en-US/_strings/commands/melee-spread-command.ftl
#	Resources/Locale/en-US/_strings/commands/persistence-save-command.ftl
#	Resources/Locale/en-US/_strings/commands/show-access-readers-command.ftl
#	Resources/Locale/en-US/_strings/commands/show-emergency-shuttle-command.ftl
#	Resources/Locale/en-US/_strings/persistence/command.ftl
#	Resources/Prototypes/Catalog/Fills/Crates/armory.yml
#	Resources/Prototypes/Catalog/Fills/Items/toolboxes.yml
#	Resources/Prototypes/Entities/Clothing/Belt/belts.yml
#	Resources/Prototypes/Entities/Clothing/Head/scraphelmet.yml
#	Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml
#	Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml
#	Resources/Prototypes/Entities/Clothing/OuterClothing/scraparmor.yml
#	Resources/Prototypes/Entities/Objects/Fun/pai.yml
#	Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml
#	Resources/Prototypes/Recipes/Crafting/improvised.yml
This commit is contained in:
Vigers Ray 2025-06-09 03:22:11 +03:00
commit 0cbccf6f0e
283 changed files with 2727 additions and 732 deletions

View file

@ -4,39 +4,20 @@ using Robust.Shared.Console;
namespace Content.Client.Access.Commands;
public sealed class ShowAccessReadersCommand : IConsoleCommand
public sealed class ShowAccessReadersCommand : LocalizedEntityCommands
{
public string Command => "showaccessreaders";
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
public string Description => "Toggles showing access reader permissions on the map";
public string Help => """
Overlay Info:
-Disabled | The access reader is disabled
+Unrestricted | The access reader has no restrictions
+Set [Index]: [Tag Name]| A tag in an access set (accessor needs all tags in the set to be allowed by the set)
+Key [StationUid]: [StationRecordKeyId] | A StationRecordKey that is allowed
-Tag [Tag Name] | A tag that is not allowed (takes priority over other allows)
""";
public void Execute(IConsoleShell shell, string argStr, string[] args)
public override string Command => "showaccessreaders";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var collection = IoCManager.Instance;
var existing = _overlay.RemoveOverlay<AccessOverlay>();
if (!existing)
_overlay.AddOverlay(new AccessOverlay(EntityManager, _cache, _xform));
if (collection == null)
return;
var overlay = collection.Resolve<IOverlayManager>();
if (overlay.RemoveOverlay<AccessOverlay>())
{
shell.WriteLine($"Set access reader debug overlay to false");
return;
}
var entManager = collection.Resolve<IEntityManager>();
var cache = collection.Resolve<IResourceCache>();
var xform = entManager.System<SharedTransformSystem>();
overlay.AddOverlay(new AccessOverlay(entManager, cache, xform));
shell.WriteLine($"Set access reader debug overlay to true");
shell.WriteLine(Loc.GetString($"cmd-showaccessreaders-status", ("status", !existing)));
}
}

View file

@ -32,7 +32,6 @@ namespace Content.Client.Actions
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IResourceManager _resources = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
public event Action<EntityUid>? OnActionAdded;

View file

@ -11,8 +11,6 @@ namespace Content.Client.Clothing.Systems;
// All valid items for chameleon are calculated on client startup and stored in dictionary.
public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
{
[Dependency] private readonly IPrototypeManager _proto = default!;
public override void Initialize()
{
base.Initialize();

View file

@ -136,6 +136,8 @@ namespace Content.Client.Entry
_prototypeManager.RegisterIgnore("sponsorLoadout"); // Sunrise-Sponsors
_prototypeManager.RegisterIgnore("holidayGiveawayItem"); // Sunrise-Edit
_prototypeManager.RegisterIgnore("ghostRoleRaffleDecider");
_prototypeManager.RegisterIgnore("codewordGenerator");
_prototypeManager.RegisterIgnore("codewordFaction");
_componentFactory.GenerateNetIds();
_adminManager.Initialize();

View file

@ -50,6 +50,18 @@ namespace Content.Client.Inventory
[ViewVariables]
private readonly EntityUid _virtualHiddenEntity;
/// <summary>
/// The current amount of added hand buttons.
/// </summary>
[ViewVariables]
private int _handCount;
/// <summary>
/// The current shape of the inventory, needed to calculate the window size.
/// </summary>
[ViewVariables]
private Vector2i _inventoryDimensions;
public StrippableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_examine = EntMan.System<ExamineSystem>();
@ -93,6 +105,8 @@ namespace Content.Client.Inventory
return;
_strippingMenu.ClearButtons();
_handCount = 0;
_inventoryDimensions = Vector2i.Zero;
if (EntMan.TryGetComponent<InventoryComponent>(Owner, out var inv))
{
@ -152,9 +166,15 @@ namespace Content.Client.Inventory
// TODO allow windows to resize based on content's desired size
// for now: shit-code
// this breaks for drones (too many hands, lots of empty vertical space), and looks shit for monkeys and the like.
// but the window is realizable, so eh.
_strippingMenu.SetSize = new Vector2(220, snare?.IsEnsnared == true ? 550 : 530);
// calculate the window size manually
// +20 horizontally and vertically from the ContentsContainer margin
// +16 vertically from the BoxContainer margin
// +27 vertically from the window header
var horizontalMenuSize = Math.Max(200, Math.Max(_handCount, _inventoryDimensions.X + 1) * (SlotControl.DefaultButtonSize + ButtonSeparation) + 20);
var verticalMenuSize = Math.Max(200, (_inventoryDimensions.Y + (_handCount > 0 ? 2 : 1)) * (SlotControl.DefaultButtonSize + ButtonSeparation) + 53);
if (snare?.IsEnsnared == true)
verticalMenuSize += 20;
_strippingMenu.SetSize = new Vector2(horizontalMenuSize, verticalMenuSize);
}
private void AddHandButton(Hand hand)
@ -172,6 +192,8 @@ namespace Content.Client.Inventory
UpdateEntityIcon(button, hand.HeldEntity);
_strippingMenu!.HandsContainer.AddChild(button);
LayoutContainer.SetPosition(button, new Vector2i(_handCount, 0) * (SlotControl.DefaultButtonSize + ButtonSeparation));
_handCount++;
}
private void SlotPressed(GUIBoundKeyEventArgs ev, SlotControl slot)
@ -220,6 +242,10 @@ namespace Content.Client.Inventory
UpdateEntityIcon(button, entity);
LayoutContainer.SetPosition(button, slotDef.StrippingWindowPos * (SlotControl.DefaultButtonSize + ButtonSeparation));
if (slotDef.StrippingWindowPos.X > _inventoryDimensions.X)
_inventoryDimensions = new Vector2i(slotDef.StrippingWindowPos.X, _inventoryDimensions.Y);
if (slotDef.StrippingWindowPos.Y > _inventoryDimensions.Y)
_inventoryDimensions = new Vector2i(_inventoryDimensions.X, slotDef.StrippingWindowPos.Y);
}
private void UpdateEntityIcon(SlotControl button, EntityUid? entity)

View file

@ -16,7 +16,6 @@ public sealed class JetpackSystem : SharedJetpackSystem
[Dependency] private readonly ClothingSystem _clothing = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly SpriteSystem _sprite = default!;
public override void Initialize()
{

View file

@ -3,15 +3,15 @@ using Robust.Shared.Console;
namespace Content.Client.Shuttles.Commands;
public sealed class ShowEmergencyShuttleCommand : IConsoleCommand
public sealed class ShowEmergencyShuttleCommand : LocalizedEntityCommands
{
public string Command => "showemergencyshuttle";
public string Description => "Shows the expected position of the emergency shuttle";
public string Help => $"{Command}";
public void Execute(IConsoleShell shell, string argStr, string[] args)
[Dependency] private readonly ShuttleSystem _shuttle = default!;
public override string Command => "showemergencyshuttle";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var tstalker = IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ShuttleSystem>();
tstalker.EnableShuttlePosition ^= true;
shell.WriteLine($"Set emergency shuttle debug to {tstalker.EnableShuttlePosition}");
_shuttle.EnableShuttlePosition ^= true;
shell.WriteLine(Loc.GetString($"cmd-showemergencyshuttle-status", ("status", _shuttle.EnableShuttlePosition)));
}
}

View file

@ -8,7 +8,7 @@ namespace Content.Client.Strip
public sealed class StrippingMenu : DefaultWindow
{
public LayoutContainer InventoryContainer = new();
public BoxContainer HandsContainer = new() { Orientation = LayoutOrientation.Horizontal };
public LayoutContainer HandsContainer = new();
public BoxContainer SnareContainer = new();
public bool Dirty = true;

View file

@ -3,39 +3,33 @@ using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Shared.Console;
using Robust.Shared.Map;
namespace Content.Client.Weapons.Melee;
public sealed class MeleeSpreadCommand : IConsoleCommand
public sealed class MeleeSpreadCommand : LocalizedEntityCommands
{
public string Command => "showmeleespread";
public string Description => "Shows the current weapon's range and arc for debugging";
public string Help => $"{Command}";
public void Execute(IConsoleShell shell, string argStr, string[] args)
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IOverlayManager _overlay = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly MeleeWeaponSystem _meleeSystem = default!;
[Dependency] private readonly SharedCombatModeSystem _combatSystem = default!;
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
public override string Command => "showmeleespread";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var collection = IoCManager.Instance;
if (collection == null)
if (_overlay.RemoveOverlay<MeleeArcOverlay>())
return;
var overlayManager = collection.Resolve<IOverlayManager>();
if (overlayManager.RemoveOverlay<MeleeArcOverlay>())
{
return;
}
var sysManager = collection.Resolve<IEntitySystemManager>();
overlayManager.AddOverlay(new MeleeArcOverlay(
collection.Resolve<IEntityManager>(),
collection.Resolve<IEyeManager>(),
collection.Resolve<IInputManager>(),
collection.Resolve<IPlayerManager>(),
sysManager.GetEntitySystem<MeleeWeaponSystem>(),
sysManager.GetEntitySystem<SharedCombatModeSystem>(),
sysManager.GetEntitySystem<SharedTransformSystem>()));
_overlay.AddOverlay(new MeleeArcOverlay(
EntityManager,
_eyeManager,
_inputManager,
_playerManager,
_meleeSystem,
_combatSystem,
_transformSystem));
}
}

View file

@ -1,9 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.Access
@ -12,6 +12,15 @@ namespace Content.IntegrationTests.Tests.Access
[TestOf(typeof(AccessReaderComponent))]
public sealed class AccessReaderTest
{
[TestPrototypes]
private const string Prototypes = @"
- type: entity
id: TestAccessReader
name: access reader
components:
- type: AccessReader
";
[Test]
public async Task TestTags()
{
@ -19,13 +28,13 @@ namespace Content.IntegrationTests.Tests.Access
var server = pair.Server;
var entityManager = server.ResolveDependency<IEntityManager>();
await server.WaitAssertion(() =>
{
var system = entityManager.System<AccessReaderSystem>();
var ent = entityManager.SpawnEntity("TestAccessReader", MapCoordinates.Nullspace);
var reader = new Entity<AccessReaderComponent>(ent, entityManager.GetComponent<AccessReaderComponent>(ent));
// test empty
var reader = new AccessReaderComponent();
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "Foo" }, reader), Is.True);
@ -34,8 +43,7 @@ namespace Content.IntegrationTests.Tests.Access
});
// test deny
reader = new AccessReaderComponent();
reader.DenyTags.Add("A");
system.AddDenyTag(reader, "A");
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "Foo" }, reader), Is.True);
@ -43,10 +51,10 @@ namespace Content.IntegrationTests.Tests.Access
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "Foo" }, reader), Is.False);
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.True);
});
system.ClearDenyTags(reader);
// test one list
reader = new AccessReaderComponent();
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
system.AddAccess(reader, "A");
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
@ -54,10 +62,10 @@ namespace Content.IntegrationTests.Tests.Access
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
});
system.ClearAccesses(reader);
// test one list - two items
reader = new AccessReaderComponent();
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A", "B" });
system.AddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A", "B" });
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.False);
@ -65,11 +73,14 @@ namespace Content.IntegrationTests.Tests.Access
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.True);
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
});
system.ClearAccesses(reader);
// test two list
reader = new AccessReaderComponent();
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "B", "C" });
var accesses = new List<HashSet<ProtoId<AccessLevelPrototype>>>() {
new HashSet<ProtoId<AccessLevelPrototype>> () { "A" },
new HashSet<ProtoId<AccessLevelPrototype>> () { "B", "C" }
};
system.AddAccesses(reader, accesses);
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
@ -79,11 +90,11 @@ namespace Content.IntegrationTests.Tests.Access
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "C", "B", "A" }, reader), Is.True);
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
});
system.ClearAccesses(reader);
// test deny list
reader = new AccessReaderComponent();
reader.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
reader.DenyTags.Add("B");
system.AddAccess(reader, new HashSet<ProtoId<AccessLevelPrototype>> { "A" });
system.AddDenyTag(reader, "B");
Assert.Multiple(() =>
{
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A" }, reader), Is.True);
@ -91,6 +102,8 @@ namespace Content.IntegrationTests.Tests.Access
Assert.That(system.AreAccessTagsAllowed(new List<ProtoId<AccessLevelPrototype>> { "A", "B" }, reader), Is.False);
Assert.That(system.AreAccessTagsAllowed(Array.Empty<ProtoId<AccessLevelPrototype>>(), reader), Is.False);
});
system.ClearAccesses(reader);
system.ClearDenyTags(reader);
});
await pair.CleanReturnAsync();
}

View file

@ -18,6 +18,7 @@ using Content.Shared.FixedPoint;
using Content.Shared.GameTicking;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory;
using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Systems;
using Content.Shared.NukeOps;
using Content.Shared.Pinpointer;
@ -25,12 +26,16 @@ using Content.Shared.Station.Components;
using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
namespace Content.IntegrationTests.Tests.GameRules;
[TestFixture]
public sealed class NukeOpsTest
{
private static readonly ProtoId<NpcFactionPrototype> SyndicateFaction = "Syndicate";
private static readonly ProtoId<NpcFactionPrototype> NanotrasenFaction = "NanoTrasen";
/// <summary>
/// Check that a nuke ops game mode can start without issue. I.e., that the nuke station and such all get loaded.
/// </summary>
@ -121,8 +126,8 @@ public sealed class NukeOpsTest
Assert.That(entMan.HasComponent<NukeOperativeComponent>(player));
Assert.That(roleSys.MindIsAntagonist(mind));
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mind));
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
Assert.That(factionSys.IsMember(player, SyndicateFaction), Is.True);
Assert.That(factionSys.IsMember(player, NanotrasenFaction), Is.False);
var roles = roleSys.MindGetAllRoleInfo(mind);
var cmdRoles = roles.Where(x => x.Prototype == "NukeopsCommander");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
@ -132,8 +137,8 @@ public sealed class NukeOpsTest
Assert.That(entMan.HasComponent<NukeOperativeComponent>(dummyEnts[1]));
Assert.That(roleSys.MindIsAntagonist(dummyMind));
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(dummyMind));
Assert.That(factionSys.IsMember(dummyEnts[1], "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(dummyEnts[1], "NanoTrasen"), Is.False);
Assert.That(factionSys.IsMember(dummyEnts[1], SyndicateFaction), Is.True);
Assert.That(factionSys.IsMember(dummyEnts[1], NanotrasenFaction), Is.False);
roles = roleSys.MindGetAllRoleInfo(dummyMind);
cmdRoles = roles.Where(x => x.Prototype == "NukeopsMedic");
Assert.That(cmdRoles.Count(), Is.EqualTo(1));
@ -148,8 +153,8 @@ public sealed class NukeOpsTest
Assert.That(entMan.HasComponent<NukeOperativeComponent>(ent), Is.False);
Assert.That(roleSys.MindIsAntagonist(mindCrew), Is.False);
Assert.That(roleSys.MindHasRole<NukeopsRoleComponent>(mindCrew), Is.False);
Assert.That(factionSys.IsMember(ent, "Syndicate"), Is.False);
Assert.That(factionSys.IsMember(ent, "NanoTrasen"), Is.True);
Assert.That(factionSys.IsMember(ent, SyndicateFaction), Is.False);
Assert.That(factionSys.IsMember(ent, NanotrasenFaction), Is.True);
var nukeroles = new List<string>() { "Nukeops", "NukeopsMedic", "NukeopsCommander" };
Assert.That(roleSys.MindGetAllRoleInfo(mindCrew).Any(x => nukeroles.Contains(x.Prototype)), Is.False);
}

View file

@ -8,6 +8,7 @@ using Content.Server.Roles;
using Content.Shared.GameTicking;
using Content.Shared.GameTicking.Components;
using Content.Shared.Mind;
using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Systems;
using Content.Shared.Objectives.Components;
using Robust.Shared.GameObjects;
@ -20,6 +21,8 @@ public sealed class TraitorRuleTest
{
private const string TraitorGameRuleProtoId = "Traitor";
private const string TraitorAntagRoleName = "Traitor";
private static readonly ProtoId<NpcFactionPrototype> SyndicateFaction = "Syndicate";
private static readonly ProtoId<NpcFactionPrototype> NanotrasenFaction = "NanoTrasen";
[Test]
public async Task TestTraitorObjectives()
@ -108,8 +111,8 @@ public sealed class TraitorRuleTest
// Make sure the player is a traitor.
var mind = mindSys.GetMind(player)!.Value;
Assert.That(roleSys.MindIsAntagonist(mind));
Assert.That(factionSys.IsMember(player, "Syndicate"), Is.True);
Assert.That(factionSys.IsMember(player, "NanoTrasen"), Is.False);
Assert.That(factionSys.IsMember(player, SyndicateFaction), Is.True);
Assert.That(factionSys.IsMember(player, NanotrasenFaction), Is.False);
Assert.That(traitorRule.TotalTraitors, Is.EqualTo(1));
Assert.That(traitorRule.TraitorMinds[0], Is.EqualTo(mind));

View file

@ -1,6 +1,7 @@
using Content.Server.Wires;
using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Wires;
namespace Content.Server.Access;
@ -23,23 +24,21 @@ public sealed partial class AccessWireAction : ComponentWireAction<AccessReaderC
public override bool Cut(EntityUid user, Wire wire, AccessReaderComponent comp)
{
WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key);
comp.Enabled = false;
EntityManager.Dirty(wire.Owner, comp);
EntityManager.System<AccessReaderSystem>().SetActive((wire.Owner, comp), false);
return true;
}
public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp)
{
comp.Enabled = true;
EntityManager.Dirty(wire.Owner, comp);
EntityManager.System<AccessReaderSystem>().SetActive((wire.Owner, comp), true);
return true;
}
public override void Pulse(EntityUid user, Wire wire, AccessReaderComponent comp)
{
comp.Enabled = false;
EntityManager.Dirty(wire.Owner, comp);
EntityManager.System<AccessReaderSystem>().SetActive((wire.Owner, comp), false);
WiresSystem.StartWireAction(wire.Owner, _pulseTimeout, PulseTimeoutKey.Key, new TimedWireEvent(AwaitPulseCancel, wire));
}
@ -57,8 +56,7 @@ public sealed partial class AccessWireAction : ComponentWireAction<AccessReaderC
{
if (EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var access))
{
access.Enabled = true;
EntityManager.Dirty(wire.Owner, access);
EntityManager.System<AccessReaderSystem>().SetActive((wire.Owner, access), true);
}
}
}

View file

@ -1,8 +1,8 @@
using Content.Server.Administration;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Administration;
using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax;
namespace Content.Server.Access;
@ -19,7 +19,7 @@ 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);
accessReader.AccessLog.Enqueue(new AccessRecord(accessTime, accessor));
EntityManager.System<AccessReaderSystem>().LogAccess((input, accessReader), accessor, accessTime, true);
ctx.WriteLine($"Successfully added access log to {input} with this information inside:\n " +
$"Time of access: {accessTime}\n " +
$"Accessed by: {accessor}");

View file

@ -37,21 +37,21 @@ public sealed partial class LogWireAction : ComponentWireAction<AccessReaderComp
public override bool Cut(EntityUid user, Wire wire, AccessReaderComponent comp)
{
WiresSystem.TryCancelWireAction(wire.Owner, PulseTimeoutKey.Key);
comp.LoggingDisabled = true;
EntityManager.Dirty(wire.Owner, comp);
EntityManager.System<AccessReaderSystem>().SetLoggingActive((wire.Owner, comp), false);
return true;
}
public override bool Mend(EntityUid user, Wire wire, AccessReaderComponent comp)
{
comp.LoggingDisabled = false;
EntityManager.System<AccessReaderSystem>().SetLoggingActive((wire.Owner, comp), true);
return true;
}
public override void Pulse(EntityUid user, Wire wire, AccessReaderComponent comp)
{
_access.LogAccess((wire.Owner, comp), Loc.GetString(PulseLog));
comp.LoggingDisabled = true;
EntityManager.System<AccessReaderSystem>().SetLoggingActive((wire.Owner, comp), false);
WiresSystem.StartWireAction(wire.Owner, PulseTimeout, PulseTimeoutKey.Key, new TimedWireEvent(AwaitPulseCancel, wire));
}
@ -64,7 +64,7 @@ public sealed partial class LogWireAction : ComponentWireAction<AccessReaderComp
private void AwaitPulseCancel(Wire wire)
{
if (!wire.IsCut && EntityManager.TryGetComponent<AccessReaderComponent>(wire.Owner, out var comp))
comp.LoggingDisabled = false;
EntityManager.System<AccessReaderSystem>().SetLoggingActive((wire.Owner, comp), true);
}
private enum PulseTimeoutKey : byte

View file

@ -168,21 +168,6 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
return accessList;
}
private List<HashSet<ProtoId<AccessLevelPrototype>>> ConvertAccessListToHashSet(List<ProtoId<AccessLevelPrototype>> accessList)
{
List<HashSet<ProtoId<AccessLevelPrototype>>> accessHashsets = new List<HashSet<ProtoId<AccessLevelPrototype>>>();
if (accessList != null && accessList.Any())
{
foreach (ProtoId<AccessLevelPrototype> access in accessList)
{
accessHashsets.Add(new HashSet<ProtoId<AccessLevelPrototype>>() { access });
}
}
return accessHashsets;
}
/// <summary>
/// Called whenever an access button is pressed, adding or removing that access requirement from the target access reader.
/// </summary>
@ -244,12 +229,10 @@ public sealed class AccessOverriderSystem : SharedAccessOverriderSystem
_adminLogger.Add(LogType.Action, LogImpact.High,
$"{ToPrettyString(player):player} has modified {ToPrettyString(accessReaderEnt.Value):entity} with the following allowed access level holders: [{string.Join(", ", addedTags.Union(removedTags))}] [{string.Join(", ", newAccessList)}]");
accessReaderEnt.Value.Comp.AccessLists = ConvertAccessListToHashSet(newAccessList);
_accessReader.SetAccesses(accessReaderEnt.Value, newAccessList);
var ev = new OnAccessOverriderAccessUpdatedEvent(player);
RaiseLocalEvent(component.TargetAccessReaderId, ref ev);
Dirty(accessReaderEnt.Value);
}
/// <summary>

View file

@ -15,7 +15,6 @@ namespace Content.Server.Actions;
public sealed class ActionOnInteractSystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
[Dependency] private readonly SharedChargesSystem _charges = default!;

View file

@ -12,12 +12,10 @@ namespace Content.Server.Administration.Commands;
public sealed class PersistenceSave : LocalizedEntityCommands
{
[Dependency] private readonly IConfigurationManager _config = default!;
[Dependency] private readonly IEntitySystemManager _system = default!;
[Dependency] private readonly SharedMapSystem _map = default!;
[Dependency] private readonly MapLoaderSystem _mapLoader = default!;
public override string Command => "persistencesave";
public override string Description => "Saves server data to a persistence file to be loaded later.";
public override string Help => "persistencesave [mapId] [filePath - default: game.map (CCVar) ]";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
@ -47,8 +45,7 @@ public sealed class PersistenceSave : LocalizedEntityCommands
return;
}
var mapLoader = _system.GetEntitySystem<MapLoaderSystem>();
mapLoader.TrySaveMap(mapId, new ResPath(saveFilePath));
_mapLoader.TrySaveMap(mapId, new ResPath(saveFilePath));
shell.WriteLine(Loc.GetString("cmd-savemap-success"));
}
}

View file

@ -38,18 +38,21 @@ public sealed class SolutionCommand : ToolshedCommand
public SolutionRef AdjReagent(
[PipedArgument] SolutionRef input,
ProtoId<ReagentPrototype> proto,
FixedPoint2 amount
float amount
)
{
_solutionContainer ??= GetSys<SharedSolutionContainerSystem>();
if (amount > 0)
// Convert float to FixedPoint2
var amountFixed = FixedPoint2.New(amount);
if (amountFixed > 0)
{
_solutionContainer.TryAddReagent(input.Solution, proto, amount, out _);
_solutionContainer.TryAddReagent(input.Solution, proto, amountFixed, out _);
}
else if (amount < 0)
else if (amountFixed < 0)
{
_solutionContainer.RemoveReagent(input.Solution, proto, -amount);
_solutionContainer.RemoveReagent(input.Solution, proto, -amountFixed);
}
return input;
@ -59,7 +62,7 @@ public sealed class SolutionCommand : ToolshedCommand
public IEnumerable<SolutionRef> AdjReagent(
[PipedArgument] IEnumerable<SolutionRef> input,
ProtoId<ReagentPrototype> name,
FixedPoint2 amount
float amount
)
=> input.Select(x => AdjReagent(x, name, amount));
}

View file

@ -3,6 +3,7 @@ using Content.Shared.Chat;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Emoting;
using Content.Shared.Speech;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
@ -146,16 +147,16 @@ public partial class ChatSystem
/// Tries to find and play relevant emote sound in emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, EmotePrototype emote)
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, EmotePrototype emote, AudioParams? audioParams = null)
{
return TryPlayEmoteSound(uid, proto, emote.ID);
return TryPlayEmoteSound(uid, proto, emote.ID, audioParams);
}
/// <summary>
/// Tries to find and play relevant emote sound in emote sounds collection.
/// </summary>
/// <returns>True if emote sound was played.</returns>
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, string emoteId)
public bool TryPlayEmoteSound(EntityUid uid, EmoteSoundsPrototype? proto, string emoteId, AudioParams? audioParams = null)
{
if (proto == null)
return false;
@ -169,8 +170,8 @@ public partial class ChatSystem
return false;
}
// if general params for all sounds set - use them
var param = proto.GeneralParams ?? sound.Params;
// optional override params > general params for all sounds in set > individual sound params
var param = audioParams ?? proto.GeneralParams ?? sound.Params;
_audio.PlayPvs(sound, uid, param);
return true;
}

View file

@ -18,7 +18,6 @@ public sealed class ChameleonClothingSystem : SharedChameleonClothingSystem
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly IdentitySystem _identity = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
public override void Initialize()
{

View file

@ -0,0 +1,14 @@
namespace Content.Server.Codewords;
/// <summary>
/// Container for generated codewords.
/// </summary>
[RegisterComponent, Access(typeof(CodewordSystem))]
public sealed partial class CodewordComponent : Component
{
/// <summary>
/// The codewords that were generated.
/// </summary>
[DataField]
public string[] Codewords = [];
}

View file

@ -0,0 +1,20 @@
using Robust.Shared.Prototypes;
namespace Content.Server.Codewords;
/// <summary>
/// This is a prototype for easy access to codewords using identifiers instead of magic strings.
/// </summary>
[Prototype]
public sealed partial class CodewordFactionPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; } = default!;
/// <summary>
/// The generator to use for this faction.
/// </summary>
[DataField(required:true)]
public ProtoId<CodewordGeneratorPrototype> Generator { get; } = default!;
}

View file

@ -0,0 +1,32 @@
using Content.Shared.Dataset;
using Robust.Shared.Prototypes;
namespace Content.Server.Codewords;
/// <summary>
/// This is a prototype for specifying codeword generation
/// </summary>
[Prototype]
public sealed partial class CodewordGeneratorPrototype : IPrototype
{
/// <inheritdoc/>
[IdDataField]
public string ID { get; } = default!;
/// <summary>
/// List of datasets to use for word generation. All values will be concatenated into one list and then randomly chosen from
/// </summary>
[DataField]
public List<ProtoId<LocalizedDatasetPrototype>> Words { get; } =
[
"Adjectives",
"Verbs",
];
/// <summary>
/// How many codewords should be generated?
/// </summary>
[DataField]
public int Amount = 3;
}

View file

@ -0,0 +1,17 @@
using Robust.Shared.Prototypes;
namespace Content.Server.Codewords;
/// <summary>
/// Component that defines <see cref="CodewordGeneratorPrototype"/> to use and keeps track of generated codewords.
/// </summary>
[RegisterComponent, Access(typeof(CodewordSystem))]
public sealed partial class CodewordManagerComponent : Component
{
/// <summary>
/// The generated codewords. The value contains the entity that has the <see cref="CodewordComponent"/>
/// </summary>
[DataField]
[ViewVariables(VVAccess.ReadOnly)]
public Dictionary<ProtoId<CodewordFactionPrototype>, EntityUid> Codewords = new();
}

View file

@ -0,0 +1,90 @@
using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.GameTicking.Events;
using Content.Shared.Database;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Codewords;
/// <summary>
/// Gamerule that provides codewords for other gamerules that rely on them.
/// </summary>
public sealed class CodewordSystem : EntitySystem
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly IRobustRandom _random = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
}
private void OnRoundStart(RoundStartingEvent ev)
{
var manager = Spawn();
AddComp<CodewordManagerComponent>(manager);
}
/// <summary>
/// Retrieves codewords for the faction specified.
/// </summary>
public string[] GetCodewords(ProtoId<CodewordFactionPrototype> faction)
{
var query = EntityQueryEnumerator<CodewordManagerComponent>();
while (query.MoveNext(out _, out var manager))
{
if (!manager.Codewords.TryGetValue(faction, out var codewordEntity))
return GenerateForFaction(faction, ref manager);
return Comp<CodewordComponent>(codewordEntity).Codewords;
}
Log.Warning("Codeword system not initialized. Returning empty array.");
// While throwing in this situation would be cool, that causes a test fail (in SpawnAndDeleteEntityCountTest)
// as the traitor codewords paper gets spawned in and calls this method,
// but the "start round" event never gets called in this test case.
return [];
}
private string[] GenerateForFaction(ProtoId<CodewordFactionPrototype> faction, ref CodewordManagerComponent manager)
{
var factionProto = _prototypeManager.Index<CodewordFactionPrototype>(faction.Id);
var codewords = GenerateCodewords(factionProto.Generator);
var codewordsContainer = EntityManager.Spawn(protoName:null, MapCoordinates.Nullspace);
EnsureComp<CodewordComponent>(codewordsContainer)
.Codewords = codewords;
manager.Codewords[faction] = codewordsContainer;
_adminLogger.Add(LogType.EventStarted, LogImpact.Low, $"Codewords generated for faction {faction}: {string.Join(", ", codewords)}");
return codewords;
}
/// <summary>
/// Generates codewords as specified by the <see cref="CodewordGeneratorPrototype"/> codeword generator.
/// </summary>
public string[] GenerateCodewords(ProtoId<CodewordGeneratorPrototype> generatorId)
{
var generator = _prototypeManager.Index(generatorId);
var codewordPool = new List<string>();
foreach (var dataset in generator.Words
.Select(datasetPrototype => _prototypeManager.Index(datasetPrototype)))
{
codewordPool.AddRange(dataset.Values);
}
var finalCodewordCount = Math.Min(generator.Amount, codewordPool.Count);
var codewords = new string[finalCodewordCount];
for (var i = 0; i < finalCodewordCount; i++)
{
codewords[i] = Loc.GetString(_random.PickAndTake(codewordPool));
}
return codewords;
}
}

View file

@ -48,7 +48,7 @@ public sealed class DoorElectronicsSystem : EntitySystem
DoorElectronicsUpdateConfigurationMessage args)
{
var accessReader = EnsureComp<AccessReaderComponent>(uid);
_accessReader.SetAccesses(uid, accessReader, args.AccessList);
_accessReader.SetAccesses((uid, accessReader), args.AccessList);
}
private void OnAccessReaderChanged(

View file

@ -1,6 +1,7 @@
using Content.Server.Codewords;
using Content.Shared.Dataset;
using Content.Shared.FixedPoint;
using Content.Shared.NPC.Prototypes;
using Content.Shared.NPC.Prototypes;
using Content.Shared.Random;
using Content.Shared.Roles;
using Robust.Shared.Audio;
@ -17,18 +18,15 @@ public sealed partial class TraitorRuleComponent : Component
[DataField]
public ProtoId<AntagPrototype> TraitorPrototypeId = "Traitor";
[DataField]
public ProtoId<CodewordFactionPrototype> CodewordFactionPrototypeId = "Traitor";
[DataField]
public ProtoId<NpcFactionPrototype> NanoTrasenFaction = "NanoTrasen";
[DataField]
public ProtoId<NpcFactionPrototype> SyndicateFaction = "Syndicate";
[DataField]
public ProtoId<LocalizedDatasetPrototype> CodewordAdjectives = "Adjectives";
[DataField]
public ProtoId<LocalizedDatasetPrototype> CodewordVerbs = "Verbs";
[DataField]
public ProtoId<LocalizedDatasetPrototype> ObjectiveIssuers = "TraitorCorporations";
@ -51,7 +49,6 @@ public sealed partial class TraitorRuleComponent : Component
public bool GiveBriefing = true;
public int TotalTraitors => TraitorMinds.Count;
public string[] Codewords = new string[3];
public enum SelectionState
{
@ -77,12 +74,6 @@ public sealed partial class TraitorRuleComponent : Component
[DataField]
public SoundSpecifier GreetSoundNotification = new SoundPathSpecifier("/Audio/Ambience/Antag/traitor_start.ogg");
/// <summary>
/// The amount of codewords that are selected.
/// </summary>
[DataField]
public int CodewordCount = 4;
/// <summary>
/// The amount of TC traitors start with.
/// </summary>

View file

@ -20,6 +20,7 @@ using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using System.Linq;
using System.Text;
using Content.Server.Codewords;
namespace Content.Server.GameTicking.Rules;
@ -27,7 +28,6 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
{
private static readonly Color TraitorCodewordColor = Color.FromHex("#cc3b3b");
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
[Dependency] private readonly AntagSelectionSystem _antag = default!;
[Dependency] private readonly SharedJobSystem _jobs = default!;
[Dependency] private readonly MindSystem _mindSystem = default!;
@ -37,6 +37,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
[Dependency] private readonly SharedRoleCodewordSystem _roleCodewordSystem = default!;
[Dependency] private readonly SharedRoleSystem _roleSystem = default!;
[Dependency] private readonly UplinkSystem _uplink = default!;
[Dependency] private readonly CodewordSystem _codewordSystem = default!;
public override void Initialize()
{
@ -48,41 +49,16 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
SubscribeLocalEvent<TraitorRuleComponent, ObjectivesTextPrependEvent>(OnObjectivesTextPrepend);
}
protected override void Added(EntityUid uid, TraitorRuleComponent component, GameRuleComponent gameRule, GameRuleAddedEvent args)
{
base.Added(uid, component, gameRule, args);
SetCodewords(component, args.RuleEntity);
}
private void AfterEntitySelected(Entity<TraitorRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
{
Log.Debug($"AfterAntagEntitySelected {ToPrettyString(ent)}");
MakeTraitor(args.EntityUid, ent);
}
private void SetCodewords(TraitorRuleComponent component, EntityUid ruleEntity)
{
component.Codewords = GenerateTraitorCodewords(component);
_adminLogger.Add(LogType.EventStarted, LogImpact.Low, $"Codewords generated for game rule {ToPrettyString(ruleEntity)}: {string.Join(", ", component.Codewords)}");
}
public string[] GenerateTraitorCodewords(TraitorRuleComponent component)
{
var adjectives = _prototypeManager.Index(component.CodewordAdjectives).Values;
var verbs = _prototypeManager.Index(component.CodewordVerbs).Values;
var codewordPool = adjectives.Concat(verbs).ToList();
var finalCodewordCount = Math.Min(component.CodewordCount, codewordPool.Count);
string[] codewords = new string[finalCodewordCount];
for (var i = 0; i < finalCodewordCount; i++)
{
codewords[i] = Loc.GetString(_random.PickAndTake(codewordPool));
}
return codewords;
}
public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component)
{
Log.Debug($"MakeTraitor {ToPrettyString(traitor)} - start");
var factionCodewords = _codewordSystem.GetCodewords(component.CodewordFactionPrototypeId);
//Grab the mind if it wasn't provided
if (!_mindSystem.TryGetMind(traitor, out var mindId, out var mind))
@ -96,7 +72,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
if (component.GiveCodewords)
{
Log.Debug($"MakeTraitor {ToPrettyString(traitor)} - added codewords flufftext to briefing");
briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", component.Codewords)));
briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", factionCodewords)));
}
var issuer = _random.Pick(_prototypeManager.Index(component.ObjectiveIssuers));
@ -129,7 +105,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
if (component.GiveCodewords)
{
Log.Debug($"MakeTraitor {ToPrettyString(traitor)} - set codewords from component");
codewords = component.Codewords;
codewords = factionCodewords;
}
if (component.GiveBriefing)
@ -161,7 +137,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
var color = TraitorCodewordColor; // Fall back to a dark red Syndicate color if a prototype is not found
RoleCodewordComponent codewordComp = EnsureComp<RoleCodewordComponent>(mindId);
_roleCodewordSystem.SetRoleCodewords(codewordComp, "traitor", component.Codewords.ToList(), color);
_roleCodewordSystem.SetRoleCodewords(codewordComp, "traitor", factionCodewords.ToList(), color);
// Change the faction
Log.Debug($"MakeTraitor {ToPrettyString(traitor)} - Change faction");
@ -211,7 +187,7 @@ public sealed class TraitorRuleSystem : GameRuleSystem<TraitorRuleComponent>
private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, ref ObjectivesTextPrependEvent args)
{
if(comp.GiveCodewords)
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords)));
args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", _codewordSystem.GetCodewords(comp.CodewordFactionPrototypeId))));
}
// TODO: figure out how to handle this? add priority to briefing event?

View file

@ -25,7 +25,6 @@ public sealed class GatewayGeneratorSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfgManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;

View file

@ -1,6 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Administration;
using Content.Shared.Access.Components;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Server.Player;
@ -60,4 +59,12 @@ public sealed class RenameCommand : LocalizedEntityCommands
entityUid = EntityUid.Invalid;
return false;
}
public override CompletionResult GetCompletion(IConsoleShell shell, string[] args)
{
if (args.Length == 1)
return CompletionResult.FromOptions(CompletionHelper.SessionNames());
return CompletionResult.Empty;
}
}

View file

@ -7,7 +7,6 @@ namespace Content.Server.NPC.Systems;
public sealed class NPCUseActionOnTargetSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
/// <inheritdoc/>

View file

@ -20,7 +20,6 @@ using Content.Shared.Popups;
using Robust.Server.Audio;
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

View file

@ -29,7 +29,6 @@ public sealed partial class DungeonSystem : SharedDungeonSystem
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IConsoleHost _console = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;

View file

@ -1,14 +1,24 @@
using Content.Shared.Security.Components;
using Content.Shared.Security.Systems;
using Content.Shared.Wall;
namespace Content.Server.Security;
public sealed class GenpopSystem : SharedGenpopSystem
{
private const float GenpopIDEjectDistanceFromWall = 1f;
protected override void CreateId(Entity<GenpopLockerComponent> ent, string name, float sentence, string crime)
{
// Default to prisoner locker coordinates for ID spawn
var xform = Transform(ent);
var uid = Spawn(ent.Comp.IdCardProto, xform.Coordinates);
var spawnCoordinates = xform.Coordinates;
// Offset prisoner wall locker coordinates in wallmount direction for ID spawn; avoids spawning ID inside wall
if (TryComp<WallMountComponent>(ent, out var wallMountComponent))
{
var offset = (wallMountComponent.Direction + xform.LocalRotation - Math.PI / 2).ToVec() * GenpopIDEjectDistanceFromWall;
spawnCoordinates = spawnCoordinates.Offset(offset);
}
var uid = Spawn(ent.Comp.IdCardProto, spawnCoordinates);
ent.Comp.LinkedId = uid;
IdCard.TryChangeFullName(uid, name);

View file

@ -48,7 +48,6 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly DockingSystem _dockSystem = default!;
[Dependency] private readonly DungeonSystem _dungeon = default!;
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly FixtureSystem _fixtures = default!;
[Dependency] private readonly MapLoaderSystem _loader = default!;
[Dependency] private readonly MapSystem _mapSystem = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;

View file

@ -1,7 +1,14 @@
using Robust.Shared.Audio;
namespace Content.Server.Speech.Components;
[RegisterComponent]
public sealed partial class MumbleAccentComponent : Component
{
/// <summary>
/// This modifies the audio parameters of emote sounds, screaming, laughing, etc.
/// By default, it reduces the volume and distance of emote sounds.
/// </summary>
[DataField]
public AudioParams EmoteAudioParams = AudioParams.Default.WithVolume(-8f).WithMaxDistance(5);
}

View file

@ -1,9 +1,13 @@
using Content.Server.Chat.Systems;
using Content.Server.Speech.Components;
using Content.Shared.Chat.Prototypes;
using Content.Shared.Speech.Components;
namespace Content.Server.Speech.EntitySystems;
public sealed class MumbleAccentSystem : EntitySystem
{
[Dependency] private readonly ChatSystem _chat = default!;
[Dependency] private readonly ReplacementAccentSystem _replacement = default!;
public override void Initialize()
@ -11,6 +15,19 @@ public sealed class MumbleAccentSystem : EntitySystem
base.Initialize();
SubscribeLocalEvent<MumbleAccentComponent, AccentGetEvent>(OnAccentGet);
SubscribeLocalEvent<MumbleAccentComponent, EmoteEvent>(OnEmote, before: [typeof(VocalSystem)]);
}
private void OnEmote(Entity<MumbleAccentComponent> ent, ref EmoteEvent args)
{
if (args.Handled || !args.Emote.Category.HasFlag(EmoteCategory.Vocal))
return;
if (TryComp<VocalComponent>(ent.Owner, out var vocalComp))
{
// play a muffled version of the vocal emote
args.Handled = _chat.TryPlayEmoteSound(ent.Owner, vocalComp.EmoteSounds, args.Emote, ent.Comp.EmoteAudioParams);
}
}
public string Accentuate(string message, MumbleAccentComponent component)
@ -18,8 +35,8 @@ public sealed class MumbleAccentSystem : EntitySystem
return _replacement.ApplyReplacements(message, "mumble");
}
private void OnAccentGet(EntityUid uid, MumbleAccentComponent component, AccentGetEvent args)
private void OnAccentGet(Entity<MumbleAccentComponent> ent, ref AccentGetEvent args)
{
args.Message = Accentuate(args.Message, component);
args.Message = Accentuate(args.Message, ent.Comp);
}
}

View file

@ -17,7 +17,7 @@ namespace Content.Server.Speech.Muting
{
base.Initialize();
SubscribeLocalEvent<MutedComponent, SpeakAttemptEvent>(OnSpeakAttempt);
SubscribeLocalEvent<MutedComponent, EmoteEvent>(OnEmote, before: new[] { typeof(VocalSystem) });
SubscribeLocalEvent<MutedComponent, EmoteEvent>(OnEmote, before: new[] { typeof(VocalSystem), typeof(MumbleAccentSystem) });
SubscribeLocalEvent<MutedComponent, ScreamActionEvent>(OnScreamAction, before: new[] { typeof(VocalSystem) });
}

View file

@ -1,3 +1,6 @@
using Content.Server.Codewords;
using Robust.Shared.Prototypes;
namespace Content.Server.Traitor.Components;
/// <summary>
@ -6,6 +9,18 @@ namespace Content.Server.Traitor.Components;
[RegisterComponent]
public sealed partial class TraitorCodePaperComponent : Component
{
/// <summary>
/// The faction to get codewords for.
/// </summary>
[DataField]
public ProtoId<CodewordFactionPrototype> CodewordFaction = "Traitor";
/// <summary>
/// The generator to use for the fake words.
/// </summary>
[DataField]
public ProtoId<CodewordGeneratorPrototype> CodewordGenerator = "TraitorCodewordGenerator";
/// <summary>
/// The number of codewords that should be generated on this paper.
/// Will not extend past the max number of available codewords.

View file

@ -7,16 +7,16 @@ using Content.Server.Traitor.Components;
using Robust.Shared.Random;
using Robust.Shared.Utility;
using System.Linq;
using Content.Server.Codewords;
using Content.Shared.Paper;
namespace Content.Server.Traitor.Systems;
public sealed class TraitorCodePaperSystem : EntitySystem
{
[Dependency] private readonly GameTicker _gameTicker = default!;
[Dependency] private readonly TraitorRuleSystem _traitorRuleSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly PaperSystem _paper = default!;
[Dependency] private readonly CodewordSystem _codewordSystem = default!;
public override void Initialize()
{
@ -48,23 +48,12 @@ public sealed class TraitorCodePaperSystem : EntitySystem
traitorCode = null;
var codesMessage = new FormattedMessage();
List<string> codeList = new();
// Find the first nuke that matches the passed location.
if (_gameTicker.IsGameRuleAdded<TraitorRuleComponent>())
{
var ruleEnts = _gameTicker.GetAddedGameRules();
foreach (var ruleEnt in ruleEnts)
{
if (TryComp(ruleEnt, out TraitorRuleComponent? traitorComp))
{
codeList.AddRange(traitorComp.Codewords.ToList());
}
}
}
var codeList = _codewordSystem.GetCodewords(component.CodewordFaction).ToList();
if (codeList.Count == 0)
{
if (component.FakeCodewords)
codeList = _traitorRuleSystem.GenerateTraitorCodewords(new TraitorRuleComponent()).ToList();
codeList = _codewordSystem.GenerateCodewords(component.CodewordGenerator).ToList();
else
codeList = [Loc.GetString("traitor-codes-none")];
}

View file

@ -227,14 +227,13 @@ namespace Content.Server.VendingMachines
}
// Default spawn coordinates
var spawnCoordinates = Transform(uid).Coordinates;
var xform = Transform(uid);
var spawnCoordinates = xform.Coordinates;
//Make sure the wallvends spawn outside of the wall.
if (TryComp<WallMountComponent>(uid, out var wallMountComponent))
{
var offset = wallMountComponent.Direction.ToWorldVec() * WallVendEjectDistanceFromWall;
var offset = (wallMountComponent.Direction + xform.LocalRotation - Math.PI / 2).ToVec() * WallVendEjectDistanceFromWall;
spawnCoordinates = spawnCoordinates.Offset(offset);
}

View file

@ -43,6 +43,7 @@ using Content.Shared.Ghost.Roles.Components;
using Content.Shared.Tag;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Content.Shared.NPC.Prototypes;
namespace Content.Server.Zombies;
@ -73,6 +74,8 @@ public sealed partial class ZombieSystem
private static readonly ProtoId<TagPrototype> InvalidForGlobalSpawnSpellTag = "InvalidForGlobalSpawnSpell";
private static readonly ProtoId<TagPrototype> CannotSuicideTag = "CannotSuicide";
private static readonly ProtoId<NpcFactionPrototype> ZombieFaction = "Zombie";
/// <summary>
/// Handles an entity turning into a zombie when they die or go into crit
/// </summary>
@ -243,7 +246,7 @@ public sealed partial class ZombieSystem
_mobState.ChangeMobState(target, MobState.Alive);
_faction.ClearFactions(target, dirty: false);
_faction.AddFaction(target, "Zombie");
_faction.AddFaction(target, ZombieFaction);
//gives it the funny "Zombie ___" name.
_nameMod.RefreshNameModifiers(target);

View file

@ -1,10 +1,10 @@
using Content.Shared.Access.Systems;
using System.Text.RegularExpressions;
using Content.Shared.StationRecords;
using Content.Shared.Weapons.Melee;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
using Robust.Shared.Toolshed.Syntax;
namespace Content.Shared.Access.Components;
@ -14,6 +14,7 @@ namespace Content.Shared.Access.Components;
/// and allows checking if something or somebody is authorized with these access levels.
/// </summary>
[RegisterComponent, NetworkedComponent]
[Access(typeof(AccessReaderSystem))]
public sealed partial class AccessReaderComponent : Component
{
// Sunrise added start
@ -32,7 +33,7 @@ public sealed partial class AccessReaderComponent : Component
// Sunrise added end
/// <summary>
/// Whether or not the accessreader is enabled.
/// Whether or not the access reader is enabled.
/// If not, it will always let people through.
/// </summary>
[DataField]
@ -41,7 +42,6 @@ public sealed partial class AccessReaderComponent : Component
/// <summary>
/// The set of tags that will automatically deny an allowed check, if any of them are present.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags = new();
@ -49,12 +49,11 @@ public sealed partial class AccessReaderComponent : Component
/// List of access groups that grant access to this reader. Only a single matching group is required to gain access.
/// A group matches if it is a subset of the set being checked against.
/// </summary>
[DataField("access")] [ViewVariables(VVAccess.ReadWrite)]
[DataField("access")]
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists = new();
/// <summary>
/// A list of <see cref="StationRecordKey"/>s that grant access. Only a single matching key is required to gain
/// access.
/// A list of <see cref="StationRecordKey"/>s that grant access. Only a single matching key is required to gain access.
/// </summary>
[DataField]
public HashSet<StationRecordKey> AccessKeys = new();
@ -72,7 +71,7 @@ public sealed partial class AccessReaderComponent : Component
public string? ContainerAccessProvider;
/// <summary>
/// A list of past authentications
/// A list of past authentications.
/// </summary>
[DataField]
public Queue<AccessRecord> AccessLog = new();
@ -80,7 +79,7 @@ public sealed partial class AccessReaderComponent : Component
/// <summary>
/// A limit on the max size of <see cref="AccessLog"/>
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
[DataField]
public int AccessLogLimit = 20;
/// <summary>
@ -113,17 +112,13 @@ public readonly partial record struct AccessRecord(
public sealed class AccessReaderComponentState : ComponentState
{
public bool Enabled;
public HashSet<ProtoId<AccessLevelPrototype>> DenyTags;
public List<HashSet<ProtoId<AccessLevelPrototype>>> AccessLists;
public ProtoId<AccessGroupPrototype>? Group; // Sunrise-alertAccesses, нужно для связывания клиента с сервером
public List<(NetEntity, uint)> AccessKeys;
public Queue<AccessRecord> AccessLog;
public int AccessLogLimit;
public AccessReaderComponentState(bool enabled, HashSet<ProtoId<AccessLevelPrototype>> denyTags,
@ -143,9 +138,4 @@ public sealed class AccessReaderComponentState : ComponentState
}
}
public sealed class AccessReaderConfigurationChangedEvent : EntityEventArgs
{
public AccessReaderConfigurationChangedEvent()
{
}
}
public sealed class AccessReaderConfigurationChangedEvent : EntityEventArgs;

View file

@ -3,17 +3,17 @@ using System.Linq;
using Content.Shared.Access.Components;
using Content.Shared.DeviceLinking.Events;
using Content.Shared.Emag.Systems;
using Content.Shared.GameTicking;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Inventory;
using Content.Shared.NameIdentifier;
using Content.Shared.PDA;
using Content.Shared.StationRecords;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Content.Shared.GameTicking;
using Content.Shared.IdentityManagement;
using Content.Shared.Tag;
using Robust.Shared.Containers;
using Robust.Shared.Collections;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
@ -129,6 +129,11 @@ public sealed class AccessReaderSystem : EntitySystem
return true;
}
/// <summary>
/// Searches an entity for an access reader. This is either the entity itself or an entity in its <see cref="AccessReaderComponent.ContainerAccessProvider"/>.
/// </summary>
/// <param name="uid">The entity being searched for an access reader.</param>
/// <param name="ent">The returned access reader entity.</param>
public bool GetMainAccessReader(EntityUid uid, [NotNullWhen(true)] out Entity<AccessReaderComponent>? ent)
{
ent = null;
@ -158,6 +163,10 @@ public sealed class AccessReaderSystem : EntitySystem
/// <summary>
/// Check whether the given access permissions satisfy an access reader's requirements.
/// </summary>
/// <param name="access">A collection of access permissions being used on the access reader.</param>
/// <param name="stationKeys">A collection of station record keys being used on the access reader.</param>
/// <param name="target">The entity being checked.</param>
/// <param name="reader">The access reader being checked.</param>
public bool IsAllowed(
ICollection<ProtoId<AccessLevelPrototype>> access,
ICollection<StationRecordKey> stationKeys,
@ -210,8 +219,8 @@ public sealed class AccessReaderSystem : EntitySystem
/// <summary>
/// Compares the given tags with the readers access list to see if it is allowed.
/// </summary>
/// <param name="accessTags">A list of access tags</param>
/// <param name="reader">An access reader to check against</param>
/// <param name="accessTags">A list of access tags.</param>
/// <param name="reader">The access reader to check against.</param>
public bool AreAccessTagsAllowed(ICollection<ProtoId<AccessLevelPrototype>> accessTags, AccessReaderComponent reader)
{
if (reader.DenyTags.Overlaps(accessTags))
@ -258,6 +267,8 @@ public sealed class AccessReaderSystem : EntitySystem
/// <summary>
/// Compares the given stationrecordkeys with the accessreader to see if it is allowed.
/// </summary>
/// <param name="keys">The collection of station record keys being used against the access reader.</param>
/// <param name="reader">The access reader that is being checked.</param>
public bool AreStationRecordKeysAllowed(ICollection<StationRecordKey> keys, AccessReaderComponent reader)
{
foreach (var key in reader.AccessKeys)
@ -270,8 +281,9 @@ public sealed class AccessReaderSystem : EntitySystem
}
/// <summary>
/// Finds all the items that could potentially give access to a given entity
/// Finds all the items that could potentially give access to an entity.
/// </summary>
/// <param name="uid">The entity that is being searched.</param>
public HashSet<EntityUid> FindPotentialAccessItems(EntityUid uid)
{
FindAccessItemsInventory(uid, out var items);
@ -291,7 +303,7 @@ public sealed class AccessReaderSystem : EntitySystem
}
/// <summary>
/// Finds the access tags on the given entity
/// Finds the access tags on an entity.
/// </summary>
/// <param name="uid">The entity that is being searched.</param>
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
@ -307,14 +319,14 @@ public sealed class AccessReaderSystem : EntitySystem
FindAccessTagsItem(ent, ref tags, ref owned);
}
return (ICollection<ProtoId<AccessLevelPrototype>>?) tags ?? Array.Empty<ProtoId<AccessLevelPrototype>>();
return (ICollection<ProtoId<AccessLevelPrototype>>?)tags ?? Array.Empty<ProtoId<AccessLevelPrototype>>();
}
/// <summary>
/// Finds the access tags on the given entity
/// Finds any station record keys on an entity.
/// </summary>
/// <param name="uid">The entity that is being searched.</param>
/// <param name="recordKeys"></param>
/// <param name="recordKeys">A collection of the station record keys that were found.</param>
/// <param name="items">All of the items to search for access. If none are passed in, <see cref="FindPotentialAccessItems"/> will be used.</param>
public bool FindStationRecordKeys(EntityUid uid, out ICollection<StationRecordKey> recordKeys, HashSet<EntityUid>? items = null)
{
@ -332,11 +344,12 @@ public sealed class AccessReaderSystem : EntitySystem
}
/// <summary>
/// Try to find <see cref="AccessComponent"/> on this item
/// or inside this item (if it's pda)
/// This version merges into a set or replaces the set.
/// If owned is false, the existing tag-set "isn't ours" and can't be merged with (is read-only).
/// Try to find <see cref="AccessComponent"/> on this item or inside this item (if it's a PDA).
/// This version merges into a set or replaces the set.
/// </summary>
/// <param name="uid">The entity that is being searched.</param>
/// <param name="tags">The access tags being merged or replaced.</param>
/// <param name="owned">If true, the tags will be merged. Otherwise they are replaced.</param>
private void FindAccessTagsItem(EntityUid uid, ref HashSet<ProtoId<AccessLevelPrototype>>? tags, ref bool owned)
{
if (!FindAccessTagsItem(uid, out var targetTags))
@ -363,25 +376,287 @@ public sealed class AccessReaderSystem : EntitySystem
}
}
public void SetAccesses(EntityUid uid, AccessReaderComponent component, List<ProtoId<AccessLevelPrototype>> accesses)
#region: AccessLists API
/// <summary>
/// Clears the entity's <see cref="AccessReaderComponent.AccessLists"/>.
/// </summary>
/// <param name="ent">The access reader entity which is having its access permissions cleared.</param>
public void ClearAccesses(Entity<AccessReaderComponent> ent)
{
component.AccessLists.Clear();
foreach (var access in accesses)
{
component.AccessLists.Add(new HashSet<ProtoId<AccessLevelPrototype>>(){access});
}
Dirty(uid, component);
RaiseLocalEvent(uid, new AccessReaderConfigurationChangedEvent());
ent.Comp.AccessLists.Clear();
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <summary>
/// Replaces the access permissions in an entity's <see cref="AccessReaderComponent.AccessLists"/> with a supplied list.
/// </summary>
/// <param name="ent">The access reader entity which is having its list of access permissions replaced.</param>
/// <param name="accesses">The list of access permissions replacing the original one.</param>
public void SetAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
{
ent.Comp.AccessLists.Clear();
AddAccesses(ent, accesses);
}
/// <inheritdoc cref = "SetAccesses"/>
public void SetAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
{
ent.Comp.AccessLists.Clear();
AddAccesses(ent, accesses);
}
/// <summary>
/// Adds a collection of access permissions to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
/// </summary>
/// <param name="ent">The access reader entity to which the new access permissions are being added.</param>
/// <param name="accesses">The list of access permissions being added.</param>
public void AddAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
{
foreach (var access in accesses)
{
AddAccess(ent, access, false);
}
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <inheritdoc cref = "AddAccesses"/>
public void AddAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
{
foreach (var access in accesses)
{
AddAccess(ent, access, false);
}
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <summary>
/// Adds an access permission to an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
/// </summary>
/// <param name="ent">The access reader entity to which the access permission is being added.</param>
/// <param name="access">The access permission being added.</param>
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
public void AddAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
{
ent.Comp.AccessLists.Add(access);
if (!dirty)
return;
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <inheritdoc cref = "AddAccess"/>
public void AddAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
{
AddAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
}
/// <summary>
/// Removes a collection of access permissions from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
/// </summary>
/// <param name="ent">The access reader entity from which the access permissions are being removed.</param>
/// <param name="accesses">The list of access permissions being removed.</param>
public void RemoveAccesses(Entity<AccessReaderComponent> ent, List<HashSet<ProtoId<AccessLevelPrototype>>> accesses)
{
foreach (var access in accesses)
{
RemoveAccess(ent, access, false);
}
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <inheritdoc cref = "RemoveAccesses"/>
public void RemoveAccesses(Entity<AccessReaderComponent> ent, List<ProtoId<AccessLevelPrototype>> accesses)
{
foreach (var access in accesses)
{
RemoveAccess(ent, access, false);
}
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <summary>
/// Removes an access permission from an access reader entity's <see cref="AccessReaderComponent.AccessLists"/>
/// </summary>
/// <param name="ent">The access reader entity from which the access permission is being removed.</param>
/// <param name="access">The access permission being removed.</param>
/// <param name="dirty">If true, the component will be marked as changed afterward.</param>
public void RemoveAccess(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> access, bool dirty = true)
{
for (int i = ent.Comp.AccessLists.Count - 1; i >= 0; i--)
{
if (ent.Comp.AccessLists[i].SetEquals(access))
{
ent.Comp.AccessLists.RemoveAt(i);
}
}
if (!dirty)
return;
Dirty(ent);
RaiseLocalEvent(ent, new AccessReaderConfigurationChangedEvent());
}
/// <inheritdoc cref = "RemoveAccess"/>
public void RemoveAccess(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> access, bool dirty = true)
{
RemoveAccess(ent, new HashSet<ProtoId<AccessLevelPrototype>>() { access }, dirty);
}
#endregion
#region: AccessKeys API
/// <summary>
/// Clears all access keys from an access reader.
/// </summary>
/// <param name="ent">The access reader entity.</param>
public void ClearAccessKeys(Entity<AccessReaderComponent> ent)
{
ent.Comp.AccessKeys.Clear();
Dirty(ent);
}
/// <summary>
/// Replaces all access keys on an access reader with those from a supplied list.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="keys">The new access keys that are replacing the old ones.</param>
public void SetAccessKeys(Entity<AccessReaderComponent> ent, HashSet<StationRecordKey> keys)
{
ent.Comp.AccessKeys.Clear();
foreach (var key in keys)
{
ent.Comp.AccessKeys.Add(key);
}
Dirty(ent);
}
/// <summary>
/// Adds an access key to an access reader.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="key">The access key being added.</param>
public void AddAccessKey(Entity<AccessReaderComponent> ent, StationRecordKey key)
{
ent.Comp.AccessKeys.Add(key);
Dirty(ent);
}
/// <summary>
/// Removes an access key from an access reader.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="key">The access key being removed.</param>
public void RemoveAccessKey(Entity<AccessReaderComponent> ent, StationRecordKey key)
{
ent.Comp.AccessKeys.Remove(key);
Dirty(ent);
}
#endregion
#region: DenyTags API
/// <summary>
/// Clears all deny tags from an access reader.
/// </summary>
/// <param name="ent">The access reader entity.</param>
public void ClearDenyTags(Entity<AccessReaderComponent> ent)
{
ent.Comp.DenyTags.Clear();
Dirty(ent);
}
/// <summary>
/// Replaces all deny tags on an access reader with those from a supplied list.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="tag">The new tags that are replacing the old.</param>
public void SetDenyTags(Entity<AccessReaderComponent> ent, HashSet<ProtoId<AccessLevelPrototype>> tags)
{
ent.Comp.DenyTags.Clear();
foreach (var tag in tags)
{
ent.Comp.DenyTags.Add(tag);
}
Dirty(ent);
}
/// <summary>
/// Adds a tag to an access reader that will be used to deny access.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="tag">The tag being added.</param>
public void AddDenyTag(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> tag)
{
ent.Comp.DenyTags.Add(tag);
Dirty(ent);
}
/// <summary>
/// Removes a tag from an access reader that denied a user access.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="tag">The tag being removed.</param>
public void RemoveDenyTag(Entity<AccessReaderComponent> ent, ProtoId<AccessLevelPrototype> tag)
{
ent.Comp.DenyTags.Remove(tag);
Dirty(ent);
}
#endregion
/// <summary>
/// Enables/disables the access reader on an entity.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="enabled">Enable/disable the access reader.</param>
public void SetActive(Entity<AccessReaderComponent> ent, bool enabled)
{
ent.Comp.Enabled = enabled;
Dirty(ent);
}
/// <summary>
/// Enables/disables the logging of access attempts on an access reader entity.
/// </summary>
/// <param name="ent">The access reader entity.</param>
/// <param name="enabled">Enable/disable logging.</param>
public void SetLoggingActive(Entity<AccessReaderComponent> ent, bool enabled)
{
ent.Comp.LoggingDisabled = !enabled;
Dirty(ent);
}
/// <summary>
/// Searches an entity's hand and ID slot for any contained items.
/// </summary>
/// <param name="uid">The entity being searched.</param>
/// <param name="items">The collection of found items.</param>
/// <returns>True if one or more items were found.</returns>
public bool FindAccessItemsInventory(EntityUid uid, out HashSet<EntityUid> items)
{
items = new();
foreach (var item in _handsSystem.EnumerateHeld(uid))
{
items.Add(item);
}
items = new(_handsSystem.EnumerateHeld(uid));
// maybe its inside an inventory slot?
if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid))
@ -393,9 +668,11 @@ public sealed class AccessReaderSystem : EntitySystem
}
/// <summary>
/// Try to find <see cref="AccessComponent"/> on this item
/// or inside this item (if it's pda)
/// Try to find <see cref="AccessComponent"/> on this entity or inside it (if it's a PDA).
/// </summary>
/// <param name="uid">The entity being searched.</param>
/// <param name="tags">The access tags that were found.</param>
/// <returns>True if one or more access tags were found.</returns>
private bool FindAccessTagsItem(EntityUid uid, out HashSet<ProtoId<AccessLevelPrototype>> tags)
{
tags = new();
@ -406,9 +683,11 @@ public sealed class AccessReaderSystem : EntitySystem
}
/// <summary>
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this item
/// or inside this item (if it's pda)
/// Try to find <see cref="StationRecordKeyStorageComponent"/> on this entity or inside it (if it's a PDA).
/// </summary>
/// <param name="uid">The entity being searched.</param>
/// <param name="key">The station record key that was found.</param>
/// <returns>True if a station record key was found.</returns>
private bool FindStationRecordKeyItem(EntityUid uid, [NotNullWhen(true)] out StationRecordKey? key)
{
if (TryComp(uid, out StationRecordKeyStorageComponent? storage) && storage.Key != null)
@ -462,15 +741,20 @@ public sealed class AccessReaderSystem : EntitySystem
/// </summary>
/// <param name="ent">The reader to log the access on</param>
/// <param name="name">The name to log as</param>
public void LogAccess(Entity<AccessReaderComponent> ent, string name)
public void LogAccess(Entity<AccessReaderComponent> ent, string name, TimeSpan? accessTime = null, bool force = false)
{
if (IsPaused(ent) || ent.Comp.LoggingDisabled)
return;
if (!force)
{
if (IsPaused(ent) || ent.Comp.LoggingDisabled)
return;
if (ent.Comp.AccessLog.Count >= ent.Comp.AccessLogLimit)
ent.Comp.AccessLog.Dequeue();
if (ent.Comp.AccessLog.Count >= ent.Comp.AccessLogLimit)
ent.Comp.AccessLog.Dequeue();
}
var stationTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
var stationTime = accessTime ?? _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan);
ent.Comp.AccessLog.Enqueue(new AccessRecord(stationTime, name));
Dirty(ent);
}
}

View file

@ -34,7 +34,6 @@ public abstract partial class SharedBuckleSystem
public static ProtoId<AlertCategoryPrototype> BuckledAlertCategory = "Buckled";
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
private void InitializeBuckle()
{
@ -557,7 +556,7 @@ public abstract partial class SharedBuckleSystem
if (!_interaction.InRangeUnobstructed(user.Value, strap.Owner, buckle.Comp.Range, popup: popup))
return false;
if (user.Value != buckle.Owner && !_actionBlocker.CanComplexInteract(user.Value))
if (user.Value != buckle.Owner && !ActionBlocker.CanComplexInteract(user.Value))
return false;
}

View file

@ -170,7 +170,7 @@ public sealed partial class ClimbSystem : VirtualController
private void AddClimbableVerb(EntityUid uid, ClimbableComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanMove(args.User))
if (!args.CanAccess || !args.CanInteract || !_actionBlockerSystem.CanMove(args.User) || !component.Vaultable)
return;
if (!TryComp(args.User, out ClimbingComponent? climbingComponent) || climbingComponent.IsClimbing || !climbingComponent.CanClimb)

View file

@ -17,33 +17,46 @@ namespace Content.Shared.CombatMode.Pacification;
[Access(typeof(PacificationSystem))]
public sealed partial class PacifiedComponent : Component
{
/// <summary>
/// If true, this will prevent you from disarming opponents in combat.
/// </summary>
[DataField]
public bool DisallowDisarm = false;
/// <summary>
/// If true, this will disable combat entirely instead of only disallowing attacking living creatures and harmful things.
/// If true, this will disable combat entirely instead of only disallowing attacking living creatures and harmful things.
/// </summary>
[DataField]
public bool DisallowAllCombat = false;
/// <summary>
/// When attempting attack against the same entity multiple times,
/// don't spam popups every frame and instead have a cooldown.
/// When attempting attack against the same entity multiple times,
/// don't spam popups every frame and instead have a cooldown.
/// </summary>
[DataField]
public TimeSpan PopupCooldown = TimeSpan.FromSeconds(3.0);
/// <summary>
/// Time at which the next popup can be shown.
/// </summary>
[DataField]
[AutoPausedField]
public TimeSpan? NextPopupTime = null;
/// <summary>
/// The last entity attacked, used for popup purposes (avoid spam)
/// The last entity attacked, used for popup purposes (avoid spam)
/// </summary>
[DataField]
public EntityUid? LastAttackedEntity = null;
/// <summary>
/// The alert to show to owners of this component.
/// </summary>
[DataField]
public ProtoId<AlertPrototype> PacifiedAlert = "Pacified";
// Prevent cheat clients from using this to identify thieves and players that cannot fight back.
// This should not matter for prediction reasons since it only blocks user input.
public override bool SendOnlyToOwner => true;
}

View file

@ -1,6 +1,7 @@
using System.Linq;
using System.Numerics;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Light.Components;
@ -25,11 +26,32 @@ public sealed partial class SunShadowCycleComponent : Component
/// Time to have each direction applied. Will lerp from the current value to the next one.
/// </summary>
[DataField, AutoNetworkedField]
public List<(float Ratio, Vector2 Direction, float Alpha)> Directions = new()
public List<SunShadowCycleDirection> Directions = new()
{
(0f, new Vector2(0f, 3f), 0f),
(0.25f, new Vector2(-3f, -0.1f), 0.5f),
(0.5f, new Vector2(0f, -3f), 0.8f),
(0.75f, new Vector2(3f, -0.1f), 0.5f),
new SunShadowCycleDirection(0f, new Vector2(0f, 3f), 0f),
new SunShadowCycleDirection(0.25f, new Vector2(-3f, -0.1f), 0.5f),
new SunShadowCycleDirection(0.5f, new Vector2(0f, -3f), 0.8f),
new SunShadowCycleDirection(0.75f, new Vector2(3f, -0.1f), 0.5f),
};
}
};
[DataDefinition]
[Serializable, NetSerializable]
public partial record struct SunShadowCycleDirection
{
[DataField]
public float Ratio;
[DataField]
public Vector2 Direction;
[DataField]
public float Alpha;
public SunShadowCycleDirection(float ratio, Vector2 direction, float alpha)
{
Ratio = ratio;
Direction = direction;
Alpha = alpha;
}
};

View file

@ -75,7 +75,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Returns whether an entity is a member of a faction.
/// </summary>
public bool IsMember(Entity<NpcFactionMemberComponent?> ent, string faction)
public bool IsMember(Entity<NpcFactionMemberComponent?> ent, [ForbidLiteral] string faction)
{
if (!Resolve(ent, ref ent.Comp, false))
return false;
@ -104,7 +104,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// Returns whether an entity is a member of any listed faction.
/// If the list is empty this returns false.
/// </summary>
public bool IsMemberOfAny(Entity<NpcFactionMemberComponent?> ent, IEnumerable<ProtoId<NpcFactionPrototype>> factions)
public bool IsMemberOfAny(Entity<NpcFactionMemberComponent?> ent, [ForbidLiteral] IEnumerable<ProtoId<NpcFactionPrototype>> factions)
{
if (!Resolve(ent, ref ent.Comp, false))
return false;
@ -121,7 +121,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Adds this entity to the particular faction.
/// </summary>
public void AddFaction(Entity<NpcFactionMemberComponent?> ent, string faction, bool dirty = true)
public void AddFaction(Entity<NpcFactionMemberComponent?> ent, [ForbidLiteral] string faction, bool dirty = true)
{
if (!_proto.HasIndex<NpcFactionPrototype>(faction))
{
@ -140,7 +140,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Adds this entity to the particular faction.
/// </summary>
public void AddFactions(Entity<NpcFactionMemberComponent?> ent, HashSet<ProtoId<NpcFactionPrototype>> factions, bool dirty = true)
public void AddFactions(Entity<NpcFactionMemberComponent?> ent, [ForbidLiteral] HashSet<ProtoId<NpcFactionPrototype>> factions, bool dirty = true)
{
ent.Comp ??= EnsureComp<NpcFactionMemberComponent>(ent);
@ -162,7 +162,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Removes this entity from the particular faction.
/// </summary>
public void RemoveFaction(Entity<NpcFactionMemberComponent?> ent, string faction, bool dirty = true)
public void RemoveFaction(Entity<NpcFactionMemberComponent?> ent, [ForbidLiteral] string faction, bool dirty = true)
{
if (!_proto.HasIndex<NpcFactionPrototype>(faction))
{
@ -221,7 +221,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
return GetNearbyFactions(ent, range, ent.Comp.FriendlyFactions);
}
private IEnumerable<EntityUid> GetNearbyFactions(EntityUid entity, float range, HashSet<ProtoId<NpcFactionPrototype>> factions)
private IEnumerable<EntityUid> GetNearbyFactions(EntityUid entity, float range, [ForbidLiteral] HashSet<ProtoId<NpcFactionPrototype>> factions)
{
var xform = Transform(entity);
foreach (var ent in _lookup.GetEntitiesInRange<NpcFactionMemberComponent>(_xform.GetMapCoordinates((entity, xform)), range))
@ -247,12 +247,12 @@ public sealed partial class NpcFactionSystem : EntitySystem
return ent.Comp.Factions.Overlaps(other.Comp.Factions) || ent.Comp.FriendlyFactions.Overlaps(other.Comp.Factions);
}
public bool IsFactionFriendly(string target, string with)
public bool IsFactionFriendly([ForbidLiteral] string target, [ForbidLiteral] string with)
{
return _factions[target].Friendly.Contains(with) && _factions[with].Friendly.Contains(target);
}
public bool IsFactionFriendly(string target, Entity<NpcFactionMemberComponent?> with)
public bool IsFactionFriendly([ForbidLiteral] string target, Entity<NpcFactionMemberComponent?> with)
{
if (!Resolve(with, ref with.Comp, false))
return false;
@ -261,12 +261,12 @@ public sealed partial class NpcFactionSystem : EntitySystem
with.Comp.FriendlyFactions.Contains(target);
}
public bool IsFactionHostile(string target, string with)
public bool IsFactionHostile([ForbidLiteral] string target, [ForbidLiteral] string with)
{
return _factions[target].Hostile.Contains(with) && _factions[with].Hostile.Contains(target);
}
public bool IsFactionHostile(string target, Entity<NpcFactionMemberComponent?> with)
public bool IsFactionHostile([ForbidLiteral] string target, Entity<NpcFactionMemberComponent?> with)
{
if (!Resolve(with, ref with.Comp, false))
return false;
@ -275,7 +275,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
with.Comp.HostileFactions.Contains(target);
}
public bool IsFactionNeutral(string target, string with)
public bool IsFactionNeutral([ForbidLiteral] string target, [ForbidLiteral] string with)
{
return !IsFactionFriendly(target, with) && !IsFactionHostile(target, with);
}
@ -283,7 +283,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Makes the source faction friendly to the target faction, 1-way.
/// </summary>
public void MakeFriendly(string source, string target)
public void MakeFriendly([ForbidLiteral] string source, [ForbidLiteral] string target)
{
if (!_factions.TryGetValue(source, out var sourceFaction))
{
@ -305,7 +305,7 @@ public sealed partial class NpcFactionSystem : EntitySystem
/// <summary>
/// Makes the source faction hostile to the target faction, 1-way.
/// </summary>
public void MakeHostile(string source, string target)
public void MakeHostile([ForbidLiteral] string source, [ForbidLiteral] string target)
{
if (!_factions.TryGetValue(source, out var sourceFaction))
{

View file

@ -3,17 +3,38 @@ using Robust.Shared.GameStates;
namespace Content.Shared.StationAi;
/// <summary>
/// Attached to entities that grant vision to the station AI, such as cameras.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState, Access(typeof(SharedStationAiSystem))]
public sealed partial class StationAiVisionComponent : Component
{
/// <summary>
/// Determines whether the entity is actively providing vision to the station AI.
/// </summary>
[DataField, AutoNetworkedField]
public bool Enabled = true;
/// <summary>
/// Determines whether the entity's vision is blocked by walls.
/// </summary>
[DataField, AutoNetworkedField]
public bool Occluded = true;
/// <summary>
/// Range in tiles
/// Determines whether the entity needs to be receiving power to provide vision to the station AI.
/// </summary>
[DataField, AutoNetworkedField]
public bool NeedsPower = false;
/// <summary>
/// Determines whether the entity needs to be anchored to provide vision to the station AI.
/// </summary>
[DataField, AutoNetworkedField]
public bool NeedsAnchoring = false;
/// <summary>
/// Vision range in tiles.
/// </summary>
[DataField, AutoNetworkedField]
public float Range = 7.5f;

View file

@ -1,8 +1,8 @@
using Content.Shared.Power.EntitySystems;
using Content.Shared.StationAi;
using Robust.Shared.Map.Components;
using Robust.Shared.Physics;
using Robust.Shared.Threading;
using Robust.Shared.Utility;
namespace Content.Shared.Silicons.StationAi;
@ -18,6 +18,7 @@ public sealed class StationAiVisionSystem : EntitySystem
[Dependency] private readonly EntityLookupSystem _lookup = default!;
[Dependency] private readonly SharedMapSystem _maps = default!;
[Dependency] private readonly SharedTransformSystem _xforms = default!;
[Dependency] private readonly SharedPowerReceiverSystem _power = default!;
private SeedJob _seedJob;
private ViewJob _job;
@ -83,6 +84,12 @@ public sealed class StationAiVisionSystem : EntitySystem
if (!seed.Comp.Enabled)
continue;
if (seed.Comp.NeedsPower && !_power.IsPowered(seed.Owner))
continue;
if (seed.Comp.NeedsAnchoring && !Transform(seed.Owner).Anchored)
continue;
_job.Data.Add(seed);
}
@ -164,6 +171,12 @@ public sealed class StationAiVisionSystem : EntitySystem
if (!seed.Comp.Enabled)
continue;
if (seed.Comp.NeedsPower && !_power.IsPowered(seed.Owner))
continue;
if (seed.Comp.NeedsAnchoring && !Transform(seed.Owner).Anchored)
continue;
_job.Data.Add(seed);
}

View file

@ -13,7 +13,6 @@ namespace Content.Shared.Weather;
public abstract class SharedWeatherSystem : EntitySystem
{
[Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] protected readonly IMapManager MapManager = default!;
[Dependency] protected readonly IPrototypeManager ProtoMan = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefManager = default!;
[Dependency] private readonly MetaDataSystem _metadata = default!;

View file

@ -1163,5 +1163,13 @@ Entries:
id: 140
time: '2025-05-27T23:44:15.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37849
- author: Samuka
changes:
- message: the command solution:adjreagent now actually works and no longer needs
a "FixedPoint2" for the amount
type: Fix
id: 141
time: '2025-06-08T03:47:37.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38134
Name: Admin
Order: 2

View file

@ -1,197 +1,4 @@
Entries:
- author: Vortebo
changes:
- message: Relic station revamped
type: Tweak
id: 8105
time: '2025-03-24T16:36:44.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35507
- author: slarticodefast
changes:
- message: Adjusted thermal regulation again so you no longer overheat in hardsuits.
type: Fix
id: 8106
time: '2025-03-24T23:55:17.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36062
- author: Velcroboy, ErhardSteinhauer, whatston3, MilonPL, Beck, ArtisticRoomba, ScarKy0
changes:
- message: Smuggler stashes! Will get spawned as a round start event and can also
be found in a hacked ClothesMate. Will have loot from a large random pool.
type: Add
- message: Smuggler stashes can now be bought from the syndicate uplink for 2TC.
type: Add
id: 8107
time: '2025-03-26T15:20:15.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/19460
- author: slarticodefast
changes:
- message: Ghosts of paradox clones now have a name modifier so they can be distinguished
by other ghosts.
type: Tweak
id: 8108
time: '2025-03-26T15:30:14.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35940
- author: slarticodefast
changes:
- message: Paradox clones of nuclear operatives and head revolutionaries now have
the corresponding faction icon and need to be killed for a crew major victory.
type: Fix
id: 8109
time: '2025-03-26T15:34:19.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35910
- author: slarticodefast
changes:
- message: Further improved item copying for paradox clones.
type: Tweak
id: 8110
time: '2025-03-26T16:13:03.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35993
- author: Centronias
changes:
- message: Raw meatballs, like steaks, can now be cooked in the microwave or on
a grill.
type: Add
id: 8111
time: '2025-03-27T06:26:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36003
- author: SlamBamActionman
changes:
- message: Liltenhead! Thank you for over 2 years of update videos, and congrats
on the 100th video!
type: Add
id: 8112
time: '2025-03-27T17:19:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36104
- author: metalgearsloth
changes:
- message: Rewrote how mob movement works to make movement more flexible in code.
While this should largely function the same (apart from conveyors now being
able to launch items) please report any bugs found.
type: Tweak
id: 8113
time: '2025-03-27T22:29:03.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35931
- author: ViceEmargo
changes:
- message: Botanist's leather gloves must now be equipped in order to pick up Death
Nettles.
type: Add
- message: Death Nettles will now pierce hardsuits, injecting 5 units of reagent.
type: Tweak
- message: Death Nettles will now "wilt" after 5 hits.
type: Add
- message: Fly Amanita has been changed to contain less Amatoxin.
type: Tweak
id: 8114
time: '2025-03-29T09:35:16.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25253
- author: chromiumboy
changes:
- message: Sentry turrets can potentially be found guarding sensitive areas of the
station. When deployed, they will shoot unauthorized personnel on sight with
either stunning or lethal laser bolts. Note that only cyborgs and robots can
safely pass sentry turrets that protect the station AI core
type: Add
id: 8115
time: '2025-03-29T17:55:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35123
- author: Killerqu00
changes:
- message: Uncuffing someone with combat mode on will shove them down.
type: Add
id: 8116
time: '2025-03-29T20:09:34.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35193
- author: metalgearsloth
changes:
- message: Jetpacks emit particles more frequently.
type: Tweak
id: 8117
time: '2025-03-30T04:06:01.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36093
- author: beck-thompson
changes:
- message: Stethoscopes now automatically start doafters and also can tell if a
patient is losing oxygen damage or gaining it.
type: Add
- message: Moths can no longer eat stethoscopes.
type: Fix
- message: Stethoscopes action button now works properly.
type: Fix
id: 8118
time: '2025-03-31T02:27:08.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36210
- author: Tayrtahn
changes:
- message: Items thrown when someone slips now tend to scatter in the direction
they are moving, and respect the item's mass.
type: Tweak
id: 8119
time: '2025-03-31T22:00:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36232
- author: ScarKy0
changes:
- message: Thieves now start with the thieving satchel instead of their toolbox.
The satchel will get all the selected kits spawned inside of it.
type: Add
- message: Thief Chameleon kit now comes with a backpack and a bonus pair of chameleon
gloves. Be careful, they aren't thieving gloves and can be tough to tell apart!
type: Tweak
- message: Updated smuggler stachel's description to reflect what it's used for.
type: Tweak
- message: Thieving satchel and toolbox now correctly play a sound when their kits
are selected.
type: Fix
id: 8120
time: '2025-03-31T22:32:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36201
- author: Tayrtahn
changes:
- message: Electric grills no longer appear powered when cycled while disconnected
from power.
type: Fix
- message: Interactions with electric grills are now predicted.
type: Tweak
id: 8121
time: '2025-04-01T16:43:19.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36241
- author: MisterImp
changes:
- message: A new recipe has been added for pizza made with world peas, world peazza.
type: Add
id: 8122
time: '2025-04-01T23:26:53.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35191
- author: Fildrance
changes:
- message: fixed missing deconstruct on RCD
type: Fix
id: 8123
time: '2025-04-02T16:11:35.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36255
- author: qwerltaz
changes:
- message: Dragon rifts now shine a different color depending on charge progress.
type: Add
id: 8124
time: '2025-04-02T18:37:35.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36216
- author: aada
changes:
- message: Diphenhydramine now causes light drowsiness.
type: Tweak
id: 8125
time: '2025-04-03T06:29:52.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36212
- author: sowelipililimute
changes:
- message: You can now more easily interact with objects behind faded ones, and
you can look behind fadeable objects in your FOV by hovering them with your
mouse pointer
type: Add
id: 8126
time: '2025-04-03T06:58:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35863
- author: whatston3
changes:
- message: Fancy tables and curtains now respect carpet stacks.
@ -3928,3 +3735,172 @@
id: 8616
time: '2025-06-05T12:52:39.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38080
- author: Orsoniks
changes:
- message: Added more in-hand sprites for food items
type: Add
id: 8617
time: '2025-06-05T21:06:38.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38024
- author: chromiumboy
changes:
- message: Holopads now provide less visual coverage to station AIs (1 tile radius,
down from 7.5). Holopads must also be anchored to the floor to provide vision.
type: Tweak
id: 8618
time: '2025-06-05T23:15:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38059
- author: Simyon
changes:
- message: Sleeper agents no longer have different codewords than round-start traitors.
type: Fix
id: 8619
time: '2025-06-05T23:19:41.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37928
- author: Gentleman-Bird
changes:
- message: Fixed the "create soap" recipe so it can actually be made
type: Fix
id: 8620
time: '2025-06-05T23:20:44.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37923
- author: Hitlinemoss
changes:
- message: The security mime mask has been added to the SecDrobe's manager inventory.
type: Add
id: 8621
time: '2025-06-05T23:23:14.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37890
- author: ArtisticRoomba
changes:
- message: Most syndicate contraband have been given sell prices (depending on the
"power" of the item) to discourage powergaming and encourage Security's interaction
with Departmental Economy.
type: Add
id: 8622
time: '2025-06-05T23:26:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37835
- author: RedBookcase
changes:
- message: The running and walking speed debuffs on equipped gear have been standardized.
type: Tweak
id: 8623
time: '2025-06-05T23:27:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37828
- author: august-sun
changes:
- message: Added individual Bulldog drum magazines for sale in the syndicate uplink.
Ammo types available are pellets and slugs.
type: Add
id: 8624
time: '2025-06-05T23:35:15.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37917
- author: Xeri7
changes:
- message: Added ability to pick up potted plants in two hands, as well as store
them in crates!
type: Add
- message: Added purchasable potted plant crate!
type: Add
id: 8625
time: '2025-06-05T23:36:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37591
- author: K-Dynamic
changes:
- message: Rifle crates with two Lecters and four magazines can be ordered from
Cargo for 8000 spesos.
type: Add
- message: Lethal Weapons gift event now includes a Rifle crate.
type: Tweak
- message: SMG crates are properly described and no longer reference 'semiautomatic
rifles.'
type: Tweak
id: 8626
time: '2025-06-05T23:40:51.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/35535
- author: themias
changes:
- message: Wearing a muzzle now reduces the sound of vocal emotes
type: Tweak
id: 8627
time: '2025-06-05T23:45:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34444
- author: RedBookcase
changes:
- message: Added Scrap Armor and Scrap Helmets.
type: Add
id: 8628
time: '2025-06-06T00:13:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37601
- author: Samuka
changes:
- message: Fire bombs are now minor contra
type: Tweak
- message: Pipe bombs are now minor contra
type: Tweak
id: 8629
time: '2025-06-06T02:28:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38088
- author: Minemoder
changes:
- message: Shark plushies now bite.
type: Tweak
id: 8630
time: '2025-06-06T21:07:10.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38113
- author: themias
changes:
- message: Increased the chance of throwing trash into a disposal unit
type: Tweak
id: 8631
time: '2025-06-06T22:13:21.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38116
- author: spanky-spanky
changes:
- message: Landmines now light up in the dark!
type: Tweak
id: 8632
time: '2025-06-06T23:01:14.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38092
- author: slarticodefast
changes:
- message: Fixed wallmount vending machines dispensing in the wrong direction.
type: Fix
id: 8633
time: '2025-06-06T23:08:16.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38112
- author: hoshizora-sayo
changes:
- message: Added proper name to the chameleon controller implanter
type: Add
id: 8634
time: '2025-06-07T02:29:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38117
- author: K-Dynamic
changes:
- message: Disablers now hold 16 shots instead of 20
type: Tweak
id: 8635
time: '2025-06-07T13:05:25.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/36019
- author: perryprog
changes:
- message: Diamonds can now be ejected from lathes and material silos.
type: Fix
id: 8636
time: '2025-06-07T17:36:58.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38132
- author: slarticodefast
changes:
- message: Fixed the stripping UI layout when having more than 2 hands.
type: Fix
id: 8637
time: '2025-06-07T22:23:46.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/37577
- author: Nox38
changes:
- message: Space Carp ghost roles no longer have a raffle!
type: Tweak
id: 8638
time: '2025-06-08T02:49:44.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/38101

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
cmd-showmeleespread-desc = Shows the current weapon's range and arc for debugging.

View file

@ -0,0 +1,3 @@
cmd-persistencesave-desc = Saves server data to a persistence file to be loaded later.
cmd-persistencesave-usage = persistencesave [mapId] [filePath - default: game.map (CCVar) ]
cmd-persistencesave-no-path = filePath was not specified and CCVar {$cvar} is not set. Manually set the filePath param in order to save the map.

View file

@ -0,0 +1,9 @@
cmd-showaccessreaders-desc = Toggles showing access reader permissions on the map
cmd-showaccessreaders-help =
Overlay Info:
-Disabled | The access reader is disabled
+Unrestricted | The access reader has no restrictions
+Set [Index]: [Tag Name]| A tag in an access set (accessor needs all tags in the set to be allowed by the set)
+Key [StationUid]: [StationRecordKeyId] | A StationRecordKey that is allowed
-Tag [Tag Name] | A tag that is not allowed (takes priority over other allows)
cmd-showaccessreaders-status = Set access reader debug overlay to {$status}.

View file

@ -0,0 +1,2 @@
cmd-showemergencyshuttle-desc = Shows the expected position of the emergency shuttle.
cmd-showemergencyshuttle-status = Set emergency shuttle debug to {$status}.

View file

@ -1 +0,0 @@
cmd-persistencesave-no-path = filePath was not specified and CCVar {$cvar} is not set. Manually set the filePath param in order to save the map.

View file

@ -85,16 +85,22 @@ uplink-shrapnel-grenade-desc = Launches a spray of sharp fragments dealing great
# Ammo
uplink-pistol-magazine-name = Pistol Magazine (.35 auto)
uplink-pistol-magazine-desc = Pistol magazine with 10 catridges. Compatible with the Viper.
uplink-pistol-magazine-desc = Pistol magazine with 10 cartridges. Compatible with the Viper.
uplink-pistol-magazine-c20r-name = SMG magazine (.35 auto)
uplink-pistol-magazine-c20r-desc = Rifle magazine with 30 catridges. Compatible with C-20r.
uplink-pistol-magazine-c20r-desc = Rifle magazine with 30 cartridges. Compatible with C-20r.
uplink-magazine-bulldog-pellet-name = Drum magazine (.50 pellet)
uplink-magazine-bulldog-pellet-desc = Shotgun magazine with 8 shells filled with buckshot. Compatible with the Bulldog.
uplink-magazine-bulldog-slug-name = Drum magazine (.50 slug)
uplink-magazine-bulldog-slug-desc = Shotgun magazine with 8 shells filled with slugs. Compatible with the Bulldog.
uplink-pistol-magazine-caseless-name = Pistol Magazine (.25 caseless)
uplink-pistol-magazine-caseless-desc = Pistol magazine with 10 catridges. Compatible with the Cobra.
uplink-pistol-magazine-caseless-desc = Pistol magazine with 10 cartridges. Compatible with the Cobra.
uplink-speedloader-magnum-name = Speedloader (.45 magnum AP)
uplink-speedloader-magnu-desc = Revolver speedloader with 6 armor-piercing catridges, capable of ignoring armor entirely. Compatible with the Python.
uplink-speedloader-magnu-desc = Revolver speedloader with 6 armor-piercing cartridges, capable of ignoring armor entirely. Compatible with the Python.
uplink-mosin-ammo-name = Ammunition box (.30 rifle)
uplink-mosin-ammo-desc = A box of 60 cartridges for the surplus rifle.

View file

@ -69,6 +69,8 @@ construction-graph-tag-match-stick = match stick
construction-graph-tag-potato = a potato
construction-graph-tag-wheat-bushel = wheat bushel
construction-graph-tag-corgi-hide = corgi hide
construction-graph-tag-apron = an apron
construction-graph-tag-utility-belt = a utility belt
soil-construction-graph-any-mushroom = any mushroom
# toys

View file

@ -67,3 +67,13 @@
cost: 5200
category: cargoproduct-category-name-armory
group: market
- type: cargoProduct
id: ArmoryRifle
icon:
sprite: Objects/Weapons/Guns/Rifles/lecter.rsi
state: icon
product: CrateArmoryRifle
cost: 8000
category: cargoproduct-category-name-armory
group: market

View file

@ -117,7 +117,7 @@
cost: 500
category: cargoproduct-category-name-fun
group: market
- type: cargoProduct
id: FunSharkPlushies
icon:
@ -347,3 +347,13 @@
cost: 1500
category: cargoproduct-category-name-fun
group: market
- type: cargoProduct
id: FunPlants
icon:
sprite: Structures/Furniture/potted_plants.rsi
state: random
product: CratePlants
cost: 1000
category: cargoproduct-category-name-fun
group: market

View file

@ -2,7 +2,7 @@
# id: CrateArmorySMG
# parent: [ CrateWeaponSecure, BaseSecurityContraband ]
# name: SMG crate
# description: Contains two high-powered, semiautomatic rifles with four mags. Requires Armory access to open.
# description: Contains two SMGs with four mags. Requires Armory access to open.
# components:
# - type: StorageFill
# contents:
@ -91,3 +91,16 @@
amount: 2
- id: RiotShield
amount: 2
- type: entity
id: CrateArmoryRifle
parent: [ CrateWeaponSecure, BaseSecurityContraband ]
name: rifle crate
description: Contains two high-powered assault rifles with four mags. Requires Armory access to open.
components:
- type: StorageFill
contents:
- id: WeaponRifleLecter
amount: 2
- id: MagazineRifle
amount: 4

View file

@ -66,6 +66,49 @@
- id: PlushieRedfox
# Sunrise-end
- type: entityTable
id: AllPottedPlantsTable
table: !type:GroupSelector
children:
- id: PottedPlant0
- id: PottedPlant1
- id: PottedPlant2
- id: PottedPlant3
- id: PottedPlant4
- id: PottedPlant5
- id: PottedPlant6
- id: PottedPlant7
- id: PottedPlant8
- id: PottedPlant10
- id: PottedPlant11
- id: PottedPlant12
- id: PottedPlant13
- id: PottedPlant14
- id: PottedPlant15
- id: PottedPlant16
- id: PottedPlant17
- id: PottedPlant18
- id: PottedPlant19
- id: PottedPlant20
- id: PottedPlant21
- id: PottedPlant22
- id: PottedPlant23
- id: PottedPlant24
- id: PottedPlant26
- type: entity
id: CratePlants
parent: CrateGenericSteel
name: plant crate
description: A variety pack of potted plants to spruce up your station!
components:
- type: EntityTableContainerFill
containers:
entity_storage: !type:NestedSelector
tableId: AllPottedPlantsTable
rolls: !type:ConstantNumberSelector
value: 5
- type: entity
id: CrateFunPlushie
parent: CrateGenericSteel

View file

@ -135,6 +135,8 @@
- id: Multitool
- id: ClothingHandsGlovesCombat
- id: ClothingEyesGlassesWelding #Sunrise-edit: rebalance toolbox
- type: StaticPrice
price: 1000
- type: entity
id: ToolboxGoldFilled

View file

@ -31,6 +31,7 @@
PepperSprayBottleBlue: 2 # Sunrise-Edit
contrabandInventory:
ClothingMaskClownSecurity: 1
ClothingMaskMimeSecurity: 1
ToyFigurineSecurity: 1
ToyFigurineWarden: 1
ToyFigurineHeadOfSecurity: 1

View file

@ -592,6 +592,29 @@
- AssaultOpsUplink
#Sunrise-end
# For the Bulldog
- type: listing
id: UplinkMagazineShotgunPellet
name: uplink-magazine-bulldog-pellet-name
description: uplink-magazine-bulldog-pellet-desc
icon: { sprite: /Textures/Objects/Weapons/Guns/Ammunition/Magazine/Shotgun/m12.rsi, state: pellets }
productEntity: MagazineShotgun
cost:
Telecrystal: 2
categories:
- UplinkAmmo
- type: listing
id: UplinkMagazineShotgunSlug
name: uplink-magazine-bulldog-slug-name
description: uplink-magazine-bulldog-slug-desc
icon: { sprite: /Textures/Objects/Weapons/Guns/Ammunition/Magazine/Shotgun/m12.rsi, state: slug }
productEntity: MagazineShotgunSlug
cost:
Telecrystal: 3
categories:
- UplinkAmmo
# For the Cobra
- type: listing
id: UplinkMagazinePistolCaselessRifle

View file

@ -0,0 +1,3 @@
- type: codewordFaction
id: Traitor
generator: TraitorCodewordGenerator

View file

@ -0,0 +1,6 @@
- type: codewordGenerator
id: TraitorCodewordGenerator
words:
- Adjectives
- Verbs
amount: 4

View file

@ -284,6 +284,8 @@
grid:
- 0,0,7,3
- 8,1,8,3
- type: StaticPrice
price: 1000
#Special
- type: entity

View file

@ -97,11 +97,10 @@
- Multitool
sprite: Clothing/Belt/belt_overlay.rsi
- type: Appearance
# Sunrise-Start
- type: Tag
tags:
- UtilityBelt
# Sunrise-End
- WhitelistChameleon
- type: entity
parent: [ClothingBeltStorageBase, BaseClothingBeltSounds] # Sunrise
@ -671,6 +670,8 @@
- Gun
- BallisticAmmoProvider
- CartridgeAmmo
- type: StaticPrice
price: 500
- type: entity
parent: [ ClothingBeltStorageBase, BaseSecurityContraband ]
@ -717,6 +718,8 @@
sprite: Clothing/Belt/militarywebbing.rsi
- type: ExplosionResistance
damageCoefficient: 0.1
- type: StaticPrice
price: 500
- type: entity
parent: ClothingBeltMilitaryWebbing

View file

@ -124,6 +124,8 @@
sprite: Clothing/Eyes/Glasses/outlawglasses.rsi
- type: VisionCorrection
- type: IdentityBlocker
- type: StaticPrice
price: 500
- type: entity
parent: ClothingEyesBase

View file

@ -421,7 +421,7 @@
enum.MeleeSpeechUiKey.Key:
type: MeleeSpeechBoundUserInterface
- type: StaticPrice
price: 0
price: 2500
- type: Tag
tags:
- Kangaroo
@ -559,6 +559,8 @@
tags:
- WhitelistChameleon
- Kangaroo
- type: StaticPrice
price: 2000
- type: entity
name: stun knuckle dusters

View file

@ -37,6 +37,8 @@
sprite: Clothing/Head/Helmets/eva_syndicate.rsi
- type: Clothing
sprite: Clothing/Head/Helmets/eva_syndicate.rsi
- type: StaticPrice
price: 500 # Suit is 1000
#Cosmonaut Helmet
- type: entity

View file

@ -66,11 +66,6 @@
- type: Tag
tags:
- WhitelistChameleon
- type: HideLayerClothing
layers:
Hair: HEAD
HeadTop: HEAD
HeadSide: HEAD
- type: entity
parent: ClothingHeadHatHardhatBase

View file

@ -41,7 +41,7 @@
- type: Tag
tags:
- ClothMade
- Recyclable
- Recyclable
- WhitelistChameleon
- type: entity
@ -383,6 +383,8 @@
sprite: Clothing/Head/Hats/outlawhat.rsi
- type: Clothing
sprite: Clothing/Head/Hats/outlawhat.rsi
- type: StaticPrice
price: 500
- type: entity
parent: ClothingHeadBase
@ -477,8 +479,8 @@
- state: icon-nobeard
map: [ "foldedLayer" ]
visible: true
- type: entity
parent: ClothingHeadBase

View file

@ -218,6 +218,8 @@
sprite: Clothing/Head/Hats/catears.rsi
- type: AddAccentClothing
accent: OwOAccent
- type: StaticPrice
price: 15000
- type: entity
parent: [ClothingHeadHatCatEars, BaseToggleClothing]

View file

@ -52,7 +52,7 @@
# The helmet itself
- type: entity
parent: [ClothingHeadHelmetBase, BaseMajorContraband]
id: ClothingHeadHelmetScrap
id: ClothingHeadHelmetScrap #When we get the tech for it this bad boy needs to be given a vision reduction when equipped. 1-2 tiles less than normal should be good.
name: scrap helmet
description: A cobbled-together helmet made from cabling, steel, and a bucket.
components:
@ -70,8 +70,8 @@
- type: Armor
modifiers:
coefficients:
Blunt: 0.85
Slash: 0.8
Blunt: 0.9
Slash: 0.9
Piercing: 0.9
Heat: 0.9
Shock: 1.05

View file

@ -582,6 +582,24 @@
- type: Clothing
sprite: Clothing/Mask/scaredmime.rsi
- type: entity
parent: [ClothingMaskMime, BaseSecurityContraband]
id: ClothingMaskMimeSecurity
name: security mime mask
description: You have the right to remain silent.
components:
- type: Sprite
sprite: Clothing/Mask/mime_security.rsi
- type: Clothing
sprite: Clothing/Mask/mime_security.rsi
- type: Armor
modifiers:
coefficients:
Blunt: 0.95
Slash: 0.95
Piercing: 0.95
Heat: 0.95
- type: entity
parent: ClothingMaskBase
id: ClothingMaskItalianMoustache

View file

@ -96,6 +96,8 @@
sprite: Clothing/Neck/Scarfs/syndiegreen.rsi
- type: Clothing
sprite: Clothing/Neck/Scarfs/syndiegreen.rsi
- type: StaticPrice
price: 500
- type: entity
parent: [ ClothingScarfBase, BaseSyndicateContraband ]
@ -107,6 +109,8 @@
sprite: Clothing/Neck/Scarfs/syndiered.rsi
- type: Clothing
sprite: Clothing/Neck/Scarfs/syndiered.rsi
- type: StaticPrice
price: 500
- type: entity
parent: [ ClothingScarfBase, BaseCentcommContraband ]

View file

@ -167,6 +167,8 @@
Heat: 0.9
- type: ExplosionResistance
damageCoefficient: 0.9
- type: StaticPrice
price: 1500
#Elite web vest
- type: entity
@ -195,6 +197,8 @@
damageCoefficient: 0.5
- type: FireProtection
reduction: 0.85
- type: StaticPrice
price: 2500
#Mercenary web vest
- type: entity
@ -468,7 +472,7 @@
Heat: 0.9
Radiation: 0.8
- type: ClothingSpeedModifier
walkModifier: 0.7
walkModifier: 0.65
sprintModifier: 0.65
- type: HeldSpeedModifier
- type: ExplosionResistance
@ -501,6 +505,7 @@
Piercing: 0.4
- type: ClothingSpeedModifier
walkModifier: 0.8
sprintModifier: 0.8
- type: HeldSpeedModifier
- type: ExplosionResistance
damageCoefficient: 0.4

View file

@ -138,7 +138,7 @@
heatingCoefficient: 0.01
coolingCoefficient: 0.01
- type: ClothingSpeedModifier
walkModifier: 0.4
walkModifier: 0.6
sprintModifier: 0.6
- type: HeldSpeedModifier
- type: Item

View file

@ -19,7 +19,7 @@
zombificationResistanceCoefficient: 0.35
- type: GroupExamine
- type: ClothingSpeedModifier
walkModifier: 1
walkModifier: 0.95
sprintModifier: 0.95
# Sunrise-Start
- type: Tag

View file

@ -92,7 +92,7 @@
Radiation: 0.3 #salv is supposed to have radiation hazards in the future
Caustic: 0.8
- type: ClothingSpeedModifier
walkModifier: 0.9
walkModifier: 0.8
sprintModifier: 0.8
- type: HeldSpeedModifier
- type: ToggleableClothing
@ -375,7 +375,7 @@
Radiation: 0.0
Caustic: 0.7
- type: ClothingSpeedModifier
walkModifier: 0.75
walkModifier: 0.8
sprintModifier: 0.8
- type: HeldSpeedModifier
- type: ToggleableClothing
@ -402,7 +402,7 @@
- type: ZombificationResistance
zombificationResistanceCoefficient: 0.4
- type: ClothingSpeedModifier
walkModifier: 0.9
walkModifier: 0.95
sprintModifier: 0.95
- type: HeldSpeedModifier
- type: ToggleableClothing
@ -512,7 +512,7 @@
Radiation: 0.5
Caustic: 0.8
- type: ClothingSpeedModifier
walkModifier: 0.85
walkModifier: 0.9
sprintModifier: 0.9
- type: HeldSpeedModifier
- type: ToggleableClothing
@ -559,6 +559,8 @@
- MonkeyWearable
- Hardsuit
- WhitelistChameleon
- type: StaticPrice
price: 5000
# Syndicate Medic Hardsuit
- type: entity
@ -613,8 +615,8 @@
- type: Item
size: Huge
- type: ClothingSpeedModifier
walkModifier: 1.0
sprintModifier: 0.90
walkModifier: 0.9
sprintModifier: 0.9
- type: HeldSpeedModifier
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitSyndieElite
@ -681,7 +683,7 @@
Radiation: 0.2
Caustic: 0.2
- type: ClothingSpeedModifier
walkModifier: 0.9
walkModifier: 0.65
sprintModifier: 0.65
- type: HeldSpeedModifier
- type: ToggleableClothing

View file

@ -8,28 +8,26 @@
sprite: Clothing/OuterClothing/Misc/apron.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Misc/apron.rsi
#Sunrise-Start #If merge Scrap Armor PR Delete
- type: Tag
tags:
- Apron
#Sunrise-End #If merge Scrap Armor PR Delete
- WhitelistChameleon
- type: entity
parent: [ClothingOuterStorageBase, BaseClothingOuterSounds] # Sunrise
id: ClothingOuterApronBar
name: apron
suffix: Bartender
name: apron
description: A darker apron designed for bartenders.
components:
- type: Sprite
sprite: Clothing/OuterClothing/Misc/apronbar.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Misc/apronbar.rsi
#Sunrise-Start #If merge Scrap Armor PR Delete
- type: Tag
tags:
- Apron
#Sunrise-End #If merge Scrap Armor PR Delete
- WhitelistChameleon
- type: entity
parent: [ClothingOuterStorageBase, BaseClothingOuterSounds] # Sunrise
@ -42,11 +40,10 @@
sprite: Clothing/OuterClothing/Misc/apronbotanist.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Misc/apronbotanist.rsi
#Sunrise-Start #If merge Scrap Armor PR Delete
- type: Tag
tags:
- Apron
#Sunrise-End #If merge Scrap Armor PR Delete
- WhitelistChameleon
- type: entity
parent: [ClothingOuterStorageBase, BaseClothingOuterSounds] # Sunrise
@ -59,11 +56,10 @@
sprite: Clothing/OuterClothing/Misc/apronchef.rsi
- type: Clothing
sprite: Clothing/OuterClothing/Misc/apronchef.rsi
#Sunrise-Start #If merge Scrap Armor PR Delete
- type: Tag
tags:
- Apron
#Sunrise-End #If merge Scrap Armor PR Delete
- WhitelistChameleon
- type: entity
parent: [ClothingOuterStorageBase, BaseClothingOuterSounds] # Sunrise

View file

@ -51,7 +51,7 @@
# The armor itself
- type: entity
parent: [ClothingOuterArmorHeavy, BaseMajorContraband]
parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing, BaseMajorContraband]
id: ClothingOuterArmorScrap
name: scrap armor
description: A tider's gleaming plate mail. Bail up, or you're a dead man.
@ -73,18 +73,13 @@
Slash: 0.5
Piercing: 0.5 #Some nukie tier physical protection...
Heat: 0.8
Shock: 1.8 # #Hey, it's a bunch of solid steel. Bzzzzz
Radiation: 0.8 #Hey, it's a bunch of solid steel.
- type: ExplosionResistance
damageCoefficient: 0.80
- type: StaminaResistance
damageCoefficient: 1.35 # Тяжело в нем явно
- type: ClothingSpeedModifier #But that protection comes at a price.
walkModifier: 0.7
sprintModifier: 0.7
walkModifier: 0.6
sprintModifier: 0.6
- type: GroupExamine
- type: ProtectedFromStepTriggers
slots: WITHOUT_POCKET
- type: Construction
graph: scraparmor
node: scraparmorfinished

View file

@ -31,6 +31,8 @@
- SuitEVA
- MonkeyWearable
- WhitelistChameleon
- type: StaticPrice
price: 1000 # Helmet is 500
#Emergency EVA
- type: entity

View file

@ -65,7 +65,7 @@
Heat: 0.8
Cold: 0.8
- type: ClothingSpeedModifier
walkModifier: 0.8
walkModifier: 0.7
sprintModifier: 0.7
- type: HeldSpeedModifier
- type: GroupExamine
@ -348,3 +348,6 @@
coolingCoefficient: 0.01
- type: ToggleableClothing
clothingPrototype: ClothingHeadHelmetHardsuitCarp
- type: StaticPrice
price: 1500

View file

@ -24,7 +24,7 @@
prefixOn: on
- type: Magboots
- type: ClothingSpeedModifier
walkModifier: 0.85
walkModifier: 0.8
sprintModifier: 0.8
- type: Appearance
- type: GenericVisualizer
@ -82,8 +82,8 @@
description: These would look fetching on a fetcher like you.
components:
- type: ClothingSpeedModifier
walkModifier: 1.10 #PVS isn't too much of an issue when you are blind...
sprintModifier: 1.10
walkModifier: 1.1 #PVS isn't too much of an issue when you are blind...
sprintModifier: 1.1
- type: StaticPrice
price: 3000
@ -99,7 +99,7 @@
- type: Clothing
sprite: Clothing/Shoes/Boots/magboots-syndicate.rsi
- type: ClothingSpeedModifier
walkModifier: 0.95
walkModifier: 0.9
sprintModifier: 0.9
- type: GasTank
outputPressure: 42.6
@ -113,6 +113,8 @@
- type: Item
sprite: null
size: Normal
- type: StaticPrice
price: 1500
- type: entity
parent: BaseAction

View file

@ -138,7 +138,7 @@
- type: Magboots # always have gravity because le suction cups
- type: ClothingSpeedModifier
# ninja are masters of sneaking around relatively quickly, won't break cloak
walkModifier: 1.1
walkModifier: 1.3
sprintModifier: 1.3
- type: FootstepModifier
footstepSoundCollection: null
@ -272,7 +272,7 @@
size: Small
sprite: Clothing/Shoes/Specific/large_clown.rsi
- type: ClothingSpeedModifier
walkModifier: 0.85
walkModifier: 0.8
sprintModifier: 0.8
- type: entity

View file

@ -521,6 +521,8 @@
sprite: Clothing/Uniforms/Jumpskirt/operative_s.rsi
- type: Clothing
sprite: Clothing/Uniforms/Jumpskirt/operative_s.rsi
- type: StaticPrice
price: 500
- type: entity
parent: ClothingUniformSkirtBase

View file

@ -855,6 +855,8 @@
sprite: Clothing/Uniforms/Jumpsuit/operative.rsi
- type: Clothing
sprite: Clothing/Uniforms/Jumpsuit/operative.rsi
- type: StaticPrice
price: 500
- type: entity
parent: ClothingUniformBase

View file

@ -181,8 +181,6 @@
rules: ghost-role-information-space-dragon-summoned-carp-rules
mindRoles:
- MindRoleGhostRoleTeamAntagonistFlock
raffle:
settings: short
- type: GhostTakeoverAvailable
- type: HTN
rootTask:

View file

@ -96,6 +96,8 @@
- type: Sprite
layers:
- state: margherita-slice
- type: Item
heldPrefix: margherita-slice
- type: entity
name: meat pizza
@ -134,6 +136,8 @@
- type: Sprite
layers:
- state: meat-slice
- type: Item
heldPrefix: meat-slice
- type: Tag
tags:
- Meat
@ -172,6 +176,8 @@
- type: Sprite
layers:
- state: mushroom-slice
- type: Item
heldPrefix: mushroom-slice
# Tastes like crust, tomato, cheese, mushroom.
- type: entity
@ -223,6 +229,8 @@
- type: Sprite
layers:
- state: vegetable-slice
- type: Item
heldPrefix: vegetable-slice
- type: SolutionContainerManager
solutions:
food:
@ -280,6 +288,8 @@
- type: Sprite
layers:
- state: donkpocket-slice
- type: Item
heldPrefix: donkpocket-slice
- type: SolutionContainerManager
solutions:
food:
@ -340,6 +350,8 @@
- type: Sprite
layers:
- state: dank-slice
- type: Item
heldPrefix: dank-slice
- type: SolutionContainerManager
solutions:
food:
@ -388,6 +400,8 @@
- type: Sprite
layers:
- state: sassysage-slice
- type: Item
heldPrefix: sassysage-slice
- type: Tag
tags:
- Meat
@ -434,6 +448,8 @@
- type: Sprite
layers:
- state: pineapple-slice
- type: Item
heldPrefix: pineapple-slice
- type: Tag
tags:
- Meat
@ -494,6 +510,8 @@
- type: Sprite
layers:
- state: arnold-slice
- type: Item
heldPrefix: arnold-slice
- type: SolutionContainerManager
solutions:
food:
@ -529,6 +547,8 @@
- type: Sprite
layers:
- state: moldy-slice
- type: Item
heldPrefix: moldy-slice
- type: Tag
tags:
- Trash
@ -597,6 +617,8 @@
- type: Sprite
layers:
- state: uranium-slice
- type: Item
heldPrefix: uranium-slice
- type: Tag
tags:
- Meat
@ -665,6 +687,8 @@
- type: Sprite
layers:
- state: cotton-slice
- type: Item
heldPrefix: cotton-slice
- type: Tag
tags:
- ClothMade
@ -722,6 +746,8 @@
- type: Sprite
layers:
- state: worldpeas-slice
- type: Item
heldPrefix: worldpeas-slice
- type: SolutionContainerManager
solutions:
food:

View file

@ -19,6 +19,11 @@
shape:
- 0,0,1,0
storedOffset: 0,-6
inhandVisuals:
left:
- state: plate-inhand-left
right:
- state: plate-inhand-right
- type: DamageOnLand
damage:
types:
@ -86,6 +91,11 @@
state: plate-small
- type: Item
storedOffset: 0,-3
inhandVisuals:
left:
- state: plate-inhand-left
right:
- state: plate-inhand-right
# Needs the full thing because inherting is dumb sometimes.
- type: Destructible
thresholds:
@ -145,6 +155,11 @@
shape:
- 0,0,1,0
storedOffset: 0,-6
inhandVisuals:
left:
- state: plate-plastic-inhand-left
right:
- state: plate-plastic-inhand-right
- type: Tag
tags:
- Trash
@ -162,6 +177,11 @@
shape:
- 0,0,1,0
storedOffset: 0,-3
inhandVisuals:
left:
- state: plate-plastic-inhand-left
right:
- state: plate-plastic-inhand-right
- type: Tag
tags:
- Trash

View file

@ -720,6 +720,12 @@
entries:
Taco: CheeseTaco
Burger: CheeseBurger
- type: Item
inhandVisuals:
left:
- state: cheesewedge-inhand-left
right:
- state: cheesewedge-inhand-right
- type: entity
name: chèvre log

View file

@ -109,6 +109,12 @@
- type: Tag
tags:
- Meat
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
- type: entity
name: raw human meat
@ -127,6 +133,12 @@
- type: SliceableFood
count: 3
slice: FoodMeatCutlet
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
- type: entity
name: raw carp fillet
@ -155,6 +167,12 @@
reagents:
- ReagentId: CarpoToxin
Quantity: 5
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw bacon
@ -185,6 +203,12 @@
graph: Bacon
node: start
defaultTarget: bacon
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw bear meat
@ -209,6 +233,14 @@
graph: BearSteak
node: start
defaultTarget: filet migrawr
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#934C64"
right:
- state: generic-pink-inhand-right
color: "#934C64"
- type: entity
name: raw penguin meat
@ -233,6 +265,12 @@
graph: PenguinSteak
node: start
defaultTarget: cooked penguin
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw chicken meat
@ -259,6 +297,12 @@
graph: ChickenSteak
node: start
defaultTarget: cooked chicken
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw duck meat
@ -283,6 +327,12 @@
graph: DuckSteak
node: start
defaultTarget: cooked duck
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: prime-cut corgi meat
@ -308,6 +358,12 @@
price: 750
- type: StealTarget
stealGroup: FoodMeatCorgi
- type: Item
inhandVisuals:
left:
- state: corgi-inhand-left
right:
- state: corgi-inhand-right
- type: entity
name: raw crab meat
@ -355,6 +411,12 @@
graph: GoliathSteak
node: start
defaultTarget: goliath steak
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
- type: entity
name: dragon flesh
@ -389,6 +451,12 @@
graph: DragonSteak
node: start
defaultTarget: dragon steak
- type: Item
inhandVisuals:
left:
- state: dragon-inhand-left
right:
- state: dragon-inhand-right
- type: entity
name: raw rat meat
@ -409,6 +477,12 @@
- type: SliceableFood
count: 3
slice: FoodMeatCutlet
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
- type: entity
name: raw lizard meat
@ -433,6 +507,14 @@
graph: LizardSteak
node: start
defaultTarget: lizard steak
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
color: "#6EFF41"
right:
- state: plain-inhand-right
color: "#6EFF41"
- type: entity
name: raw plant meat
@ -467,6 +549,12 @@
Quantity: 4
- ReagentId: Fat
Quantity: 4
- type: Item
inhandVisuals:
left:
- state: rotten-inhand-left
right:
- state: rotten-inhand-right
- type: entity
name: raw spider meat
@ -487,6 +575,8 @@
- type: SliceableFood
count: 3
slice: FoodMeatSpiderCutlet
- type: Item
heldPrefix: spider
- type: entity
name: raw spider leg
@ -504,6 +594,14 @@
Quantity: 10
- ReagentId: Fat
Quantity: 3
- type: Item
inhandVisuals:
left:
- state: snake-inhand-left
color: "#333333"
right:
- state: snake-inhand-right
color: "#333333"
- type: entity
name: meatwheat clump
@ -522,6 +620,14 @@
reagents:
- ReagentId: UncookedAnimalProteins
Quantity: 1
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#934C64"
right:
- state: generic-pink-inhand-right
color: "#934C64"
- type: entity
name: raw snake meat
@ -543,6 +649,12 @@
Quantity: 10
- ReagentId: Toxin
Quantity: 2
- type: Item
inhandVisuals:
left:
- state: snake-inhand-left
right:
- state: snake-inhand-right
- type: entity
name: raw xeno meat
@ -570,6 +682,14 @@
- type: SliceableFood
count: 3
slice: FoodMeatXenoCutlet
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
color: "#6EFF41"
right:
- state: plain-inhand-right
color: "#6EFF41"
- type: entity
name: raw rouny meat
@ -599,6 +719,12 @@
graph: RounySteak
node: start
defaultTarget: rouny steak
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
- type: entity
name: killer tomato meat
@ -613,6 +739,12 @@
slice: FoodMeatTomatoCutlet
- type: StaticPrice
price: 100
- type: Item
inhandVisuals:
left:
- state: tomato-inhand-left
right:
- state: tomato-inhand-right
- type: entity
name: salami
@ -695,6 +827,8 @@
graph: CookedPatty
node: start
defaultTarget: cooked meat patty
- type: Item
heldPrefix: generic-pink
- type: entity
name: slimeball
@ -716,6 +850,12 @@
Quantity: 10
- type: Sprite
state: slime
- type: Item
inhandVisuals:
left:
- state: slime-inhand-left
right:
- state: slime-inhand-right
- type: entity
name: raw snail meat
@ -736,6 +876,14 @@
Quantity: 3
- ReagentId: Water
Quantity: 4 #It makes saline if you add salt!
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#E2AE7C"
right:
- state: generic-pink-inhand-right
color: "#E2AE7C"
- type: entity
name: anomalous meat mass
@ -766,6 +914,12 @@
- type: Tag
tags:
- Meat
- type: Item
inhandVisuals:
left:
- state: plain-inhand-left
right:
- state: plain-inhand-right
# Cooked
@ -833,6 +987,12 @@
entries:
Burger: MeatSteak
Taco: MeatSteak
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: bacon
@ -868,6 +1028,14 @@
entries:
Burger: MeatBacon
Taco: MeatBacon
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3E2A"
right:
- state: generic-pink-inhand-right
color: "#5B3E2A"
- type: entity
name: cooked bear
@ -901,6 +1069,8 @@
entries:
Burger: MeatBearBurger
Taco: MeatBear
- type: Item
heldPrefix: meatball
- type: entity
name: penguin filet
@ -933,6 +1103,14 @@
entries:
Burger: MeatPenguinBurger
Taco: MeatPenguin
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
color: "#F7E3A3"
right:
- state: plain-cooked-inhand-right
color: "#F7E3A3"
- type: entity
name: cooked chicken
@ -965,6 +1143,14 @@
entries:
Burger: MeatChicken
Taco: MeatChicken
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
color: "#F7E3A3"
right:
- state: plain-cooked-inhand-right
color: "#F7E3A3"
- type: entity
name: fried chicken
@ -997,6 +1183,14 @@
entries:
Burger: MeatChicken
Taco: MeatChicken
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
color: "#F7E3A3"
right:
- state: plain-cooked-inhand-right
color: "#F7E3A3"
- type: entity
name: cooked duck
@ -1029,6 +1223,14 @@
entries:
Burger: MeatDuck
Taco: MeatDuck
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
color: "#F7E3A3"
right:
- state: plain-cooked-inhand-right
color: "#F7E3A3"
- type: entity
name: cooked crab
@ -1061,6 +1263,12 @@
entries:
Burger: MeatCrabBurger
Taco: MeatCrab
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: goliath steak
@ -1091,6 +1299,12 @@
entries:
Burger: MeatGoliathBurger
Taco: MeatGoliath
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: rouny steak
@ -1125,6 +1339,12 @@
entries:
Burger: MeatXeno
Taco: MeatXeno
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: lizard steak
@ -1158,6 +1378,12 @@
entries:
Burger: MeatLizardBurger
Taco: MeatLizard
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: boiled spider leg
@ -1184,6 +1410,14 @@
entries:
Burger: MeatSpiderBurger
Taco: MeatSpider
- type: Item
inhandVisuals:
left:
- state: snake-inhand-left
color: "#44201A"
right:
- state: snake-inhand-right
color: "#44201A"
- type: entity
name: meatball
@ -1212,6 +1446,8 @@
- type: Construction
graph: MeatMeatballCooked
node: meatball cooked
- type: Item
heldPrefix: meatball
- type: entity
name: cooked meat patty
@ -1241,6 +1477,8 @@
entries:
Burger: MeatPatty
Taco: MeatPatty
- type: Item
heldPrefix: meatball
- type: entity
name: boiled snail
@ -1270,6 +1508,14 @@
entries:
Burger: MeatSnail
Taco: MeatSnail
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3E2A"
right:
- state: generic-pink-inhand-right
color: "#5B3E2A"
- type: entity
name: anomalous steak
@ -1299,6 +1545,12 @@
- type: Construction
graph: AnomalyMeatSteak
node: anomaly steak
- type: Item
inhandVisuals:
left:
- state: plain-cooked-inhand-left
right:
- state: plain-cooked-inhand-right
- type: entity
name: dragon steak
@ -1334,6 +1586,12 @@
entries:
Burger: DragonSteak
Taco: DragonSteak
- type: Item
inhandVisuals:
left:
- state: dragon-cooked-inhand-left
right:
- state: dragon-cooked-inhand-right
# Cutlets
@ -1364,6 +1622,12 @@
graph: Cutlet
node: start
defaultTarget: cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw bear cutlet
@ -1393,6 +1657,14 @@
graph: BearCutlet
node: start
defaultTarget: bear cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: brown
right:
- state: generic-pink-inhand-right
color: brown
- type: entity
name: raw penguin cutlet
@ -1420,6 +1692,14 @@
graph: PenguinCutlet
node: start
defaultTarget: penguin cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: white
right:
- state: generic-pink-inhand-right
color: white
- type: entity
name: raw chicken cutlet
@ -1447,6 +1727,12 @@
graph: ChickenCutlet
node: start
defaultTarget: chicken cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw duck cutlet
@ -1474,6 +1760,12 @@
graph: DuckCutlet
node: start
defaultTarget: duck cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
right:
- state: generic-pink-inhand-right
- type: entity
name: raw lizard cutlet
@ -1504,6 +1796,14 @@
graph: LizardCutlet
node: start
defaultTarget: lizard cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: green
right:
- state: generic-pink-inhand-right
color: green
- type: entity
name: raw spider cutlet
@ -1530,6 +1830,14 @@
graph: SpiderCutlet
node: start
defaultTarget: spider cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: green
right:
- state: generic-pink-inhand-right
color: green
- type: entity
name: raw xeno cutlet
@ -1558,6 +1866,14 @@
graph: XenoCutlet
node: start
defaultTarget: xeno cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: green
right:
- state: generic-pink-inhand-right
color: green
- type: entity
name: raw killer tomato cutlet
@ -1623,6 +1939,14 @@
graph: DragonCutlet
node: start
defaultTarget: dragon cutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#D127A7"
right:
- state: generic-pink-inhand-right
color: "#D127A7"
# Cooked
@ -1654,6 +1978,14 @@
entries:
Burger: MeatCutlet
Taco: MeatCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3614"
right:
- state: generic-pink-inhand-right
color: "#5B3614"
- type: entity
name: bear cutlet
@ -1686,6 +2018,14 @@
entries:
Burger: BearCutletBurger
Taco: BearCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3614"
right:
- state: generic-pink-inhand-right
color: "#5B3614"
- type: entity
name: penguin cutlet
@ -1716,6 +2056,14 @@
entries:
Burger: PenguinCutletBurger
Taco: PenguinCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3614"
right:
- state: generic-pink-inhand-right
color: "#5B3614"
- type: entity
name: chicken cutlet
@ -1746,6 +2094,14 @@
entries:
Burger: ChickenCutlet
Taco: ChickenCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3614"
right:
- state: generic-pink-inhand-right
color: "#5B3614"
- type: entity
name: duck cutlet
@ -1776,6 +2132,14 @@
entries:
Burger: DuckCutlet
Taco: DuckCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#5B3614"
right:
- state: generic-pink-inhand-right
color: "#5B3614"
- type: entity
name: lizard cutlet
@ -1807,6 +2171,14 @@
entries:
Burger: LizardCutletBurger
Taco: LizardCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#153F06"
right:
- state: generic-pink-inhand-right
color: "#153F06"
- type: entity
name: spider cutlet
@ -1836,6 +2208,14 @@
entries:
Burger: SpiderCutletBurger
Taco: SpiderCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#153F06"
right:
- state: generic-pink-inhand-right
color: "#153F06"
- type: entity
name: xeno cutlet
@ -1865,6 +2245,14 @@
entries:
Burger: XenoCutlet
Taco: XenoCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#153F06"
right:
- state: generic-pink-inhand-right
color: "#153F06"
- type: entity
name: dragon cutlet
@ -1896,3 +2284,11 @@
entries:
Burger: DragonCutlet
Taco: DragonCutlet
- type: Item
inhandVisuals:
left:
- state: generic-pink-inhand-left
color: "#7A1763"
right:
- state: generic-pink-inhand-right
color: "#7A1763"

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