diff --git a/.editorconfig b/.editorconfig index 58d0d332bbe..3e44d1a2811 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,9 +9,10 @@ indent_style = space tab_width = 4 # New line preferences -end_of_line = crlf:suggestion +#end_of_line = crlf insert_final_newline = true trim_trailing_whitespace = true +max_line_length = 120 #### .NET Coding Conventions #### @@ -104,7 +105,6 @@ csharp_preferred_modifier_order = public, private, protected, internal, new, abs # 'using' directive preferences csharp_using_directive_placement = outside_namespace:silent -csharp_style_namespace_declarations = file_scoped:suggestion #### C# Formatting Rules #### @@ -337,7 +337,11 @@ dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter # ReSharper properties resharper_braces_for_ifelse = required_for_multiline +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_csharp_wrap_parameters_style = chop_if_long resharper_keep_existing_attribute_arrangement = true +resharper_wrap_chained_binary_patterns = chop_if_long +resharper_wrap_chained_method_calls = chop_if_long [*.{csproj,xml,yml,yaml,dll.config,msbuildproj,targets,props}] indent_size = 2 diff --git a/.github/labeler.yml b/.github/labeler.yml index eb01eeecc4f..6b87aa26558 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -1,39 +1,56 @@ "Changes: Audio": - - "**/*.ogg" - + - changed-files: + - any-glob-to-any-file: "**/*.ogg" + "Changes: C#": - - "**/*.cs" + - changed-files: + - any-glob-to-any-file: "**/*.cs" "Changes: Config": - - "**/*.toml" - - "**/*.config" - - "*.json" - - ".github/*.yml" - - ".github/*.json" - - ".vscode/*.json" - - ".editorconfig" +- changed-files: + - any-glob-to-any-file: + - "**/*.toml" + - "**/*.config" + - "*.json" + - ".github/*.yml" + - ".github/*.json" + - ".vscode/*.json" + - ".editorconfig" "Changes: Documentation": - - "**/*.xml" - - "**/*.md" + - changed-files: + - any-glob-to-any-file: + - "**/*.xml" + - "**/*.md" "Changes: Localization": -- 'Resources/Locale/**/*.ftl' + - changed-files: + - any-glob-to-any-file: 'Resources/Locale/**/*.ftl' "Changes: Map": - - "Resources/Maps/**/*.yml" - - "Resources/Prototypes/Maps/**/*.yml" + - changed-files: + - any-glob-to-any-file: + - "Resources/Maps/**/*.yml" + - "Resources/Prototypes/Maps/**/*.yml" "Changes: Sprite": - - "**/*.rsi/*.png" - - "**/*.rsi/*.json" + - changed-files: + - any-glob-to-any-file: + - "**/*.rsi/*.png" + - "**/*.rsi/*.json" "Changes: UI": - - "**/*.xaml*" + - changed-files: + - any-glob-to-any-file: "**/*.xaml*" "Changes: YML": - - any: ["**/*.yml"] - all: ["!Resources/Maps/**/*.yml", "!Resources/Prototypes/Maps/**/*.yml"] + - changed-files: + - any-glob-to-any-file: + - "**/*.yml" + - all-globs-to-all-files: + - "!Resources/Maps/**/*.yml", + - "!Resources/Prototypes/Maps/**/*.yml" "Changes: Workflow": - - ".github/workflows/*.yml" + - changed-files: + - any-glob-to-any-file: ".github/workflows/*.yml" diff --git a/.github/workflows/conflict-labeler.yml b/.github/workflows/conflict-labeler.yml index 152d3a9f3c8..1bba6770222 100644 --- a/.github/workflows/conflict-labeler.yml +++ b/.github/workflows/conflict-labeler.yml @@ -1,18 +1,20 @@ name: Check Merge Conflicts on: - push: - branches: - - master pull_request_target: + types: + - opened + - synchronize + - reopened + - ready_for_review jobs: Label: - if: github.actor != 'PJBot' && github.actor != 'DeltaV-Bot' && github.actor != 'SimpleStation14' + if: ( github.event.pull_request.draft == false ) && ( github.actor != 'PJBot' && github.actor != 'DeltaV-Bot' && github.actor != 'SimpleStation14' ) runs-on: ubuntu-latest steps: - name: Check for Merge Conflicts - uses: ike709/actions-label-merge-conflict@9eefdd17e10566023c46d2dc6dc04fcb8ec76142 + uses: eps1lon/actions-label-merge-conflict@v3.0.0 with: dirtyLabel: "Status: Merge Conflict" repoToken: "${{ secrets.GITHUB_TOKEN }}" diff --git a/.github/workflows/labeler-pr.yml b/.github/workflows/labeler-pr.yml index efb051f4ccf..2fd754b15ee 100644 --- a/.github/workflows/labeler-pr.yml +++ b/.github/workflows/labeler-pr.yml @@ -6,8 +6,9 @@ on: jobs: labeler: if: github.actor != 'PJBot' && github.actor != 'DeltaV-Bot' && github.actor != 'SimpleStation14' + permissions: + contents: read + pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v3 - with: - repo-token: "${{ secrets.GITHUB_TOKEN }}" + - uses: actions/labeler@v5 diff --git a/Content.Client/Access/IdCardSystem.cs b/Content.Client/Access/IdCardSystem.cs index fcf2bf57de3..e0c02976f7b 100644 --- a/Content.Client/Access/IdCardSystem.cs +++ b/Content.Client/Access/IdCardSystem.cs @@ -2,6 +2,4 @@ namespace Content.Client.Access; -public sealed class IdCardSystem : SharedIdCardSystem -{ -} +public sealed class IdCardSystem : SharedIdCardSystem; diff --git a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs index 73f18aec8d6..c3fac8cb92a 100644 --- a/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs +++ b/Content.Client/Access/UI/AgentIDCardBoundUserInterface.cs @@ -40,9 +40,9 @@ private void OnJobChanged(string newJob) SendMessage(new AgentIDCardJobChangedMessage(newJob)); } - public void OnJobIconChanged(string newJobIcon) + public void OnJobIconChanged(string newJobIconId) { - SendMessage(new AgentIDCardJobIconChangedMessage(newJobIcon)); + SendMessage(new AgentIDCardJobIconChangedMessage(newJobIconId)); } /// @@ -57,7 +57,7 @@ protected override void UpdateState(BoundUserInterfaceState state) _window.SetCurrentName(cast.CurrentName); _window.SetCurrentJob(cast.CurrentJob); - _window.SetAllowedIcons(cast.Icons); + _window.SetAllowedIcons(cast.Icons, cast.CurrentJobIconId); } protected override void Dispose(bool disposing) diff --git a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs index beca0c41ba9..9a38c0c4853 100644 --- a/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs +++ b/Content.Client/Access/UI/AgentIDCardWindow.xaml.cs @@ -38,7 +38,7 @@ public AgentIDCardWindow(AgentIDCardBoundUserInterface bui) JobLineEdit.OnFocusExit += e => OnJobChanged?.Invoke(e.Text); } - public void SetAllowedIcons(HashSet icons) + public void SetAllowedIcons(HashSet icons, string currentJobIconId) { IconGrid.DisposeAllChildren(); @@ -79,6 +79,10 @@ public void SetAllowedIcons(HashSet icons) jobIconButton.AddChild(jobIconTexture); jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIcon.ID); IconGrid.AddChild(jobIconButton); + + if (jobIconId.Equals(currentJobIconId)) + jobIconButton.Pressed = true; + i++; } } diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 90158ba81e6..0bc65eb9358 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -249,7 +249,10 @@ public void TriggerAction(EntityUid actionId, BaseActionComponent action) if (action.ClientExclusive) { if (instantAction.Event != null) + { instantAction.Event.Performer = user; + instantAction.Event.Action = actionId; + } PerformAction(user, actions, actionId, instantAction, instantAction.Event, GameTiming.CurTime); } diff --git a/Content.Client/Administration/Components/HeadstandComponent.cs b/Content.Client/Administration/Components/HeadstandComponent.cs index d95e74576bf..a4e3bfc5aaf 100644 --- a/Content.Client/Administration/Components/HeadstandComponent.cs +++ b/Content.Client/Administration/Components/HeadstandComponent.cs @@ -3,7 +3,7 @@ namespace Content.Client.Administration.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent] public sealed partial class HeadstandComponent : SharedHeadstandComponent { diff --git a/Content.Client/Administration/Components/KillSignComponent.cs b/Content.Client/Administration/Components/KillSignComponent.cs index 1cf47b93ff5..91c44ef3f27 100644 --- a/Content.Client/Administration/Components/KillSignComponent.cs +++ b/Content.Client/Administration/Components/KillSignComponent.cs @@ -3,6 +3,5 @@ namespace Content.Client.Administration.Components; -[NetworkedComponent, RegisterComponent] -public sealed partial class KillSignComponent : SharedKillSignComponent -{ } +[RegisterComponent] +public sealed partial class KillSignComponent : SharedKillSignComponent; diff --git a/Content.Client/Administration/Managers/ClientAdminManager.cs b/Content.Client/Administration/Managers/ClientAdminManager.cs index fdd62fb6a2d..0f740c81045 100644 --- a/Content.Client/Administration/Managers/ClientAdminManager.cs +++ b/Content.Client/Administration/Managers/ClientAdminManager.cs @@ -126,12 +126,15 @@ void IPostInjectInit.PostInject() public AdminData? GetAdminData(EntityUid uid, bool includeDeAdmin = false) { - return uid == _player.LocalEntity ? _adminData : null; + if (uid == _player.LocalEntity && (_adminData?.Active ?? includeDeAdmin)) + return _adminData; + + return null; } public AdminData? GetAdminData(ICommonSession session, bool includeDeAdmin = false) { - if (_player.LocalUser == session.UserId) + if (_player.LocalUser == session.UserId && (_adminData?.Active ?? includeDeAdmin)) return _adminData; return null; diff --git a/Content.Client/Administration/Systems/AdminVerbSystem.cs b/Content.Client/Administration/Systems/AdminVerbSystem.cs index e0f84bc4f03..dced59bbf2e 100644 --- a/Content.Client/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Client/Administration/Systems/AdminVerbSystem.cs @@ -1,3 +1,6 @@ +using Content.Shared.Administration; +using Content.Shared.Administration.Managers; +using Content.Shared.Mind.Components; using Content.Shared.Verbs; using Robust.Client.Console; using Robust.Shared.Utility; @@ -11,10 +14,12 @@ sealed class AdminVerbSystem : EntitySystem { [Dependency] private readonly IClientConGroupController _clientConGroupController = default!; [Dependency] private readonly IClientConsoleHost _clientConsoleHost = default!; + [Dependency] private readonly ISharedAdminManager _admin = default!; public override void Initialize() { SubscribeLocalEvent>(AddAdminVerbs); + } private void AddAdminVerbs(GetVerbsEvent args) @@ -33,6 +38,24 @@ private void AddAdminVerbs(GetVerbsEvent args) }; args.Verbs.Add(verb); } + + if (!_admin.IsAdmin(args.User)) + return; + + if (_admin.HasAdminFlag(args.User, AdminFlags.Admin)) + args.ExtraCategories.Add(VerbCategory.Admin); + + if (_admin.HasAdminFlag(args.User, AdminFlags.Fun) && HasComp(args.Target)) + args.ExtraCategories.Add(VerbCategory.Antag); + + if (_admin.HasAdminFlag(args.User, AdminFlags.Debug)) + args.ExtraCategories.Add(VerbCategory.Debug); + + if (_admin.HasAdminFlag(args.User, AdminFlags.Fun)) + args.ExtraCategories.Add(VerbCategory.Smite); + + if (_admin.HasAdminFlag(args.User, AdminFlags.Admin)) + args.ExtraCategories.Add(VerbCategory.Tricks); } } } diff --git a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs index 1f32640f7dd..dc263d6055c 100644 --- a/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs +++ b/Content.Client/Administration/UI/BanPanel/BanPanel.xaml.cs @@ -3,6 +3,7 @@ using System.Net.Sockets; using Content.Client.Administration.UI.CustomControls; using Content.Shared.Administration; +using Content.Shared.CCVar; using Content.Shared.Database; using Content.Shared.Roles; using Robust.Client.AutoGenerated; @@ -11,6 +12,7 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Shared.Configuration; using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -32,8 +34,11 @@ public sealed partial class BanPanel : DefaultWindow // This is less efficient than just holding a reference to the root control and enumerating children, but you // have to know how the controls are nested, which makes the code more complicated. private readonly List _roleCheckboxes = new(); + private readonly ISawmill _banpanelSawmill; [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly ILogManager _logManager = default!; private enum TabNumbers { @@ -65,6 +70,7 @@ public BanPanel() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); + _banpanelSawmill = _logManager.GetSawmill("admin.banpanel"); PlayerList.OnSelectionChanged += OnPlayerSelectionChanged; PlayerNameLine.OnFocusExit += _ => OnPlayerNameChanged(); PlayerCheckbox.OnPressed += _ => @@ -104,6 +110,11 @@ public BanPanel() }; SubmitButton.OnPressed += SubmitButtonOnOnPressed; + IpCheckbox.Pressed = _cfg.GetCVar(CCVars.ServerBanIpBanDefault); + HwidCheckbox.Pressed = _cfg.GetCVar(CCVars.ServerBanHwidBanDefault); + LastConnCheckbox.Pressed = _cfg.GetCVar(CCVars.ServerBanUseLastDetails); + EraseCheckbox.Pressed = _cfg.GetCVar(CCVars.ServerBanErasePlayer); + SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-none"), (int) NoteSeverity.None); SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-low"), (int) NoteSeverity.Minor); SeverityOption.AddItem(Loc.GetString("admin-note-editor-severity-medium"), (int) NoteSeverity.Medium); @@ -175,6 +186,39 @@ private void CreateRoleGroup(string roleName, IEnumerable roleList, Colo c.Pressed = args.Pressed; } } + + if (args.Pressed) + { + if (!Enum.TryParse(_cfg.GetCVar(CCVars.DepartmentBanDefaultSeverity), true, out NoteSeverity newSeverity)) + { + _banpanelSawmill + .Warning("Departmental role ban severity could not be parsed from config!"); + return; + } + SeverityOption.SelectId((int) newSeverity); + } + else + { + foreach (var childContainer in RolesContainer.Children) + { + if (childContainer is Container) + { + foreach (var child in childContainer.Children) + { + if (child is CheckBox { Pressed: true }) + return; + } + } + } + + if (!Enum.TryParse(_cfg.GetCVar(CCVars.RoleBanDefaultSeverity), true, out NoteSeverity newSeverity)) + { + _banpanelSawmill + .Warning("Role ban severity could not be parsed from config!"); + return; + } + SeverityOption.SelectId((int) newSeverity); + } }; outerContainer.AddChild(innerContainer); foreach (var role in roleList) @@ -353,6 +397,35 @@ private void OnTypeChanged() { TypeOption.ModulateSelfOverride = null; Tabs.SetTabVisible((int) TabNumbers.Roles, TypeOption.SelectedId == (int) Types.Role); + NoteSeverity? newSeverity = null; + switch (TypeOption.SelectedId) + { + case (int)Types.Server: + if (Enum.TryParse(_cfg.GetCVar(CCVars.ServerBanDefaultSeverity), true, out NoteSeverity serverSeverity)) + newSeverity = serverSeverity; + else + { + _banpanelSawmill + .Warning("Server ban severity could not be parsed from config!"); + } + + break; + case (int) Types.Role: + + if (Enum.TryParse(_cfg.GetCVar(CCVars.RoleBanDefaultSeverity), true, out NoteSeverity roleSeverity)) + { + newSeverity = roleSeverity; + } + else + { + _banpanelSawmill + .Warning("Role ban severity could not be parsed from config!"); + } + break; + } + + if (newSeverity != null) + SeverityOption.SelectId((int) newSeverity.Value); } private void UpdateSubmitEnabled() diff --git a/Content.Client/Animations/TrackUserComponent.cs b/Content.Client/Animations/TrackUserComponent.cs new file mode 100644 index 00000000000..374c187398d --- /dev/null +++ b/Content.Client/Animations/TrackUserComponent.cs @@ -0,0 +1,17 @@ +using System.Numerics; + +namespace Content.Client.Animations; + +/// +/// Entities with this component tracks the user's world position every frame. +/// +[RegisterComponent] +public sealed partial class TrackUserComponent : Component +{ + public EntityUid? User; + + /// + /// Offset in the direction of the entity's rotation. + /// + public Vector2 Offset = Vector2.Zero; +} diff --git a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs index b105e629cfa..b54af3a5871 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerWindow.xaml.cs @@ -163,6 +163,26 @@ private void GenerateGasDisplay(GasMixEntry gasMix, Control parent) parent.AddChild(panel); panel.AddChild(dataContainer); + // Volume label + var volBox = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal }; + + volBox.AddChild(new Label + { + Text = Loc.GetString("gas-analyzer-window-volume-text") + }); + volBox.AddChild(new Control + { + MinSize = new Vector2(10, 0), + HorizontalExpand = true + }); + volBox.AddChild(new Label + { + Text = Loc.GetString("gas-analyzer-window-volume-val-text", ("volume", $"{gasMix.Volume:0.##}")), + Align = Label.AlignMode.Right, + HorizontalExpand = true + }); + dataContainer.AddChild(volBox); + // Pressure label var presBox = new BoxContainer { Orientation = BoxContainer.LayoutOrientation.Horizontal }; diff --git a/Content.Client/Audio/Jukebox/JukeboxSystem.cs b/Content.Client/Audio/Jukebox/JukeboxSystem.cs index 53bde82a784..dd4a5bbb9b0 100644 --- a/Content.Client/Audio/Jukebox/JukeboxSystem.cs +++ b/Content.Client/Audio/Jukebox/JukeboxSystem.cs @@ -11,6 +11,7 @@ public sealed class JukeboxSystem : SharedJukeboxSystem [Dependency] private readonly IPrototypeManager _protoManager = default!; [Dependency] private readonly AnimationPlayerSystem _animationPlayer = default!; [Dependency] private readonly SharedAppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; public override void Initialize() { @@ -35,13 +36,10 @@ private void OnProtoReload(PrototypesReloadedEventArgs obj) var query = AllEntityQuery(); - while (query.MoveNext(out _, out var ui)) + while (query.MoveNext(out var uid, out _, out var ui)) { - if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) || - baseBui is not JukeboxBoundUserInterface bui) - { + if (!_uiSystem.TryGetOpenUi((uid, ui), JukeboxUiKey.Key, out var bui)) continue; - } bui.PopulateMusic(); } @@ -49,15 +47,9 @@ private void OnProtoReload(PrototypesReloadedEventArgs obj) private void OnJukeboxAfterState(Entity ent, ref AfterAutoHandleStateEvent args) { - if (!TryComp(ent, out UserInterfaceComponent? ui)) + if (!_uiSystem.TryGetOpenUi(ent.Owner, JukeboxUiKey.Key, out var bui)) return; - if (!ui.OpenInterfaces.TryGetValue(JukeboxUiKey.Key, out var baseBui) || - baseBui is not JukeboxBoundUserInterface bui) - { - return; - } - bui.Reload(); } diff --git a/Content.Client/CardboardBox/CardboardBoxSystem.cs b/Content.Client/CardboardBox/CardboardBoxSystem.cs index 90a21d8e41b..925013db109 100644 --- a/Content.Client/CardboardBox/CardboardBoxSystem.cs +++ b/Content.Client/CardboardBox/CardboardBoxSystem.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Shared.Body.Components; using Content.Shared.CardboardBox; using Content.Shared.CardboardBox.Components; using Content.Shared.Examine; @@ -13,9 +14,14 @@ public sealed class CardboardBoxSystem : SharedCardboardBoxSystem [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly ExamineSystemShared _examine = default!; + private EntityQuery _bodyQuery; + public override void Initialize() { base.Initialize(); + + _bodyQuery = GetEntityQuery(); + SubscribeNetworkEvent(OnBoxEffect); } @@ -59,6 +65,10 @@ private void OnBoxEffect(PlayBoxEffectMessage msg) if (!_examine.InRangeUnOccluded(sourcePos, mapPos, box.Distance, null)) continue; + // no effect for anything too exotic + if (!_bodyQuery.HasComp(mob)) + continue; + var ent = Spawn(box.Effect, mapPos); if (!xformQuery.TryGetComponent(ent, out var entTransform) || !TryComp(ent, out var sprite)) diff --git a/Content.Client/Cargo/UI/BountyEntry.xaml.cs b/Content.Client/Cargo/UI/BountyEntry.xaml.cs index 027d7b3e801..31c417117ad 100644 --- a/Content.Client/Cargo/UI/BountyEntry.xaml.cs +++ b/Content.Client/Cargo/UI/BountyEntry.xaml.cs @@ -7,7 +7,6 @@ using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; using Robust.Shared.Timing; -using Serilog; namespace Content.Client.Cargo.UI; diff --git a/Content.Client/Changelog/ChangelogWindow.xaml.cs b/Content.Client/Changelog/ChangelogWindow.xaml.cs index e5f492900c2..9b7fd754369 100644 --- a/Content.Client/Changelog/ChangelogWindow.xaml.cs +++ b/Content.Client/Changelog/ChangelogWindow.xaml.cs @@ -87,14 +87,12 @@ private void TabsUpdated() if (!tab.AdminOnly || isAdmin) { Tabs.SetTabVisible(i, true); - tab.Visible = true; visibleTabs++; firstVisible ??= i; } else { Tabs.SetTabVisible(i, false); - tab.Visible = false; } } diff --git a/Content.Client/Chat/UI/EmotesMenu.xaml b/Content.Client/Chat/UI/EmotesMenu.xaml new file mode 100644 index 00000000000..cc4d5bb77e9 --- /dev/null +++ b/Content.Client/Chat/UI/EmotesMenu.xaml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/Chat/UI/EmotesMenu.xaml.cs b/Content.Client/Chat/UI/EmotesMenu.xaml.cs new file mode 100644 index 00000000000..a26d319920b --- /dev/null +++ b/Content.Client/Chat/UI/EmotesMenu.xaml.cs @@ -0,0 +1,112 @@ +using System.Numerics; +using Content.Client.UserInterface.Controls; +using Content.Shared.Chat.Prototypes; +using Content.Shared.Speech; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Player; +using Robust.Shared.Prototypes; + +namespace Content.Client.Chat.UI; + +[GenerateTypedNameReferences] +public sealed partial class EmotesMenu : RadialMenu +{ + [Dependency] private readonly EntityManager _entManager = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ISharedPlayerManager _playerManager = default!; + + private readonly SpriteSystem _spriteSystem; + + public event Action>? OnPlayEmote; + + public EmotesMenu() + { + IoCManager.InjectDependencies(this); + RobustXamlLoader.Load(this); + + _spriteSystem = _entManager.System(); + + var main = FindControl("Main"); + + var emotes = _prototypeManager.EnumeratePrototypes(); + foreach (var emote in emotes) + { + var player = _playerManager.LocalSession?.AttachedEntity; + if (emote.Category == EmoteCategory.Invalid || + emote.ChatTriggers.Count == 0 || + !(player.HasValue && (emote.Whitelist?.IsValid(player.Value, _entManager) ?? true)) || + (emote.Blacklist?.IsValid(player.Value, _entManager) ?? false)) + continue; + + if (!emote.Available && + _entManager.TryGetComponent(player.Value, out var speech) && + !speech.AllowedEmotes.Contains(emote.ID)) + continue; + + var parent = FindControl(emote.Category.ToString()); + + var button = new EmoteMenuButton + { + StyleClasses = { "RadialMenuButton" }, + SetSize = new Vector2(64f, 64f), + ToolTip = Loc.GetString(emote.Name), + ProtoId = emote.ID, + }; + + var tex = new TextureRect + { + VerticalAlignment = VAlignment.Center, + HorizontalAlignment = HAlignment.Center, + Texture = _spriteSystem.Frame0(emote.Icon), + TextureScale = new Vector2(2f, 2f), + }; + + button.AddChild(tex); + parent.AddChild(button); + foreach (var child in main.Children) + { + if (child is not RadialMenuTextureButton castChild) + continue; + + if (castChild.TargetLayer == emote.Category.ToString()) + { + castChild.Visible = true; + break; + } + } + } + + + // Set up menu actions + foreach (var child in Children) + { + if (child is not RadialContainer container) + continue; + AddEmoteClickAction(container); + } + } + + private void AddEmoteClickAction(RadialContainer container) + { + foreach (var child in container.Children) + { + if (child is not EmoteMenuButton castChild) + continue; + + castChild.OnButtonUp += _ => + { + OnPlayEmote?.Invoke(castChild.ProtoId); + Close(); + }; + } + } +} + + +public sealed class EmoteMenuButton : RadialMenuTextureButton +{ + public ProtoId ProtoId { get; set; } +} diff --git a/Content.Client/Chemistry/Components/SolutionItemStatusComponent.cs b/Content.Client/Chemistry/Components/SolutionItemStatusComponent.cs new file mode 100644 index 00000000000..58c5a05894b --- /dev/null +++ b/Content.Client/Chemistry/Components/SolutionItemStatusComponent.cs @@ -0,0 +1,22 @@ +using Content.Client.Chemistry.EntitySystems; +using Content.Client.Chemistry.UI; + +namespace Content.Client.Chemistry.Components; + +/// +/// Exposes a solution container's contents via a basic item status control. +/// +/// +/// Shows the solution volume, max volume, and transfer amount. +/// +/// +/// +[RegisterComponent] +public sealed partial class SolutionItemStatusComponent : Component +{ + /// + /// The ID of the solution that will be shown on the item status control. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; +} diff --git a/Content.Client/Chemistry/EntitySystems/SolutionItemStatusSystem.cs b/Content.Client/Chemistry/EntitySystems/SolutionItemStatusSystem.cs new file mode 100644 index 00000000000..76aab516a77 --- /dev/null +++ b/Content.Client/Chemistry/EntitySystems/SolutionItemStatusSystem.cs @@ -0,0 +1,22 @@ +using Content.Client.Chemistry.Components; +using Content.Client.Chemistry.UI; +using Content.Client.Items; +using Content.Shared.Chemistry.EntitySystems; + +namespace Content.Client.Chemistry.EntitySystems; + +/// +/// Wires up item status logic for . +/// +/// +public sealed class SolutionItemStatusSystem : EntitySystem +{ + [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!; + + public override void Initialize() + { + base.Initialize(); + Subs.ItemStatus( + entity => new SolutionStatusControl(entity, EntityManager, _solutionContainerSystem)); + } +} diff --git a/Content.Client/Chemistry/UI/ButtonGrid.cs b/Content.Client/Chemistry/UI/ButtonGrid.cs new file mode 100644 index 00000000000..0abd9ef8a43 --- /dev/null +++ b/Content.Client/Chemistry/UI/ButtonGrid.cs @@ -0,0 +1,119 @@ +using System; +using Robust.Client.Graphics; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.Chemistry.UI; + +/// +/// Creates a grid of buttons given a comma-seperated list of Text +/// +public sealed class ButtonGrid : GridContainer +{ + private string _buttonList = ""; + + /// + /// A comma-seperated list of text to use for each button. These will be inserted sequentially. + /// + public string ButtonList + { + get => _buttonList; + set + { + _buttonList = value; + Update(); + } + } + + public bool RadioGroup { get; set; } = false; + + private string? _selected; + + /// + /// Which button is currently selected. Only matters when is true. + /// + public string? Selected + { + get => _selected; + set + { + _selected = value; + Update(); + } + } + + public Action? OnButtonPressed; + + /// + /// + /// + public new int Columns + { + get => base.Columns; + set + { + base.Columns = value; + Update(); + } + } + + /// + /// + /// + public new int Rows + { + get => base.Rows; + set + { + base.Rows = value; + Update(); + } + } + + private void Update() + { + if (ButtonList == "") + return; + + this.Children.Clear(); + var i = 0; + var list = ButtonList.Split(","); + + var group = new ButtonGroup(); + + foreach (var button in list) + { + var btn = new Button(); + btn.Text = button; + btn.OnPressed += _ => + { + if (RadioGroup) + btn.Pressed = true; + Selected = button; + OnButtonPressed?.Invoke(button); + }; + if (button == Selected) + btn.Pressed = true; + var sep = HSeparationOverride ?? 0; + // ReSharper disable once PossibleLossOfFraction + // btn.SetWidth = (this.PixelWidth - sep * (Columns - 1)) / 3; + btn.Group = group; + + var row = i / Columns; + var col = i % Columns; + var last = i == list.Length - 1; + var lastCol = i == Columns - 1; + var lastRow = row == list.Length / Columns - 1; + + if (row == 0 && (lastCol || last)) + btn.AddStyleClass("OpenLeft"); + else if (col == 0 && lastRow) + btn.AddStyleClass("OpenRight"); + else + btn.AddStyleClass("OpenBoth"); + + this.Children.Add(btn); + + i++; + } + } +} diff --git a/Content.Client/Chemistry/UI/InjectorStatusControl.cs b/Content.Client/Chemistry/UI/InjectorStatusControl.cs index ba1f97cd1e4..f9b0d90e205 100644 --- a/Content.Client/Chemistry/UI/InjectorStatusControl.cs +++ b/Content.Client/Chemistry/UI/InjectorStatusControl.cs @@ -32,7 +32,7 @@ protected override void FrameUpdate(FrameEventArgs args) { base.FrameUpdate(args); - if (!_solutionContainers.TryGetSolution(_parent.Owner, InjectorComponent.SolutionName, out _, out var solution)) + if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.SolutionName, out _, out var solution)) return; // only updates the UI if any of the details are different than they previously were diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml b/Content.Client/Chemistry/UI/ReagentCardControl.xaml new file mode 100644 index 00000000000..966c7301406 --- /dev/null +++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml @@ -0,0 +1,37 @@ + + + + + + + diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs new file mode 100644 index 00000000000..60336143fc7 --- /dev/null +++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs @@ -0,0 +1,30 @@ +using Content.Shared.Chemistry; +using Robust.Client.AutoGenerated; +using Robust.Client.Graphics; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.XAML; + +namespace Content.Client.Chemistry.UI; + +[GenerateTypedNameReferences] +public sealed partial class ReagentCardControl : Control +{ + public string StorageSlotId { get; } + public Action? OnPressed; + public Action? OnEjectButtonPressed; + + public ReagentCardControl(ReagentInventoryItem item) + { + RobustXamlLoader.Load(this); + + StorageSlotId = item.StorageSlotId; + ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor }; + ReagentNameLabel.Text = item.ReagentLabel; + ReagentNameLabel.FontColorOverride = Color.White; + FillLabel.Text = item.StoredAmount; + EjectButtonIcon.Text = Loc.GetString("reagent-dispenser-window-eject-container-button"); + + MainButton.OnPressed += args => OnPressed?.Invoke(StorageSlotId); + EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageSlotId); + } +} diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs index 8244e3e6edb..99e5a3d3953 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs @@ -1,3 +1,4 @@ +using Content.Client.Guidebook.Components; using Content.Shared.Chemistry; using Content.Shared.Containers.ItemSlots; using JetBrains.Annotations; @@ -34,6 +35,7 @@ protected override void Open() _window = new() { Title = EntMan.GetComponent(Owner).EntityName, + HelpGuidebookIds = EntMan.GetComponent(Owner).Guides }; _window.OpenCentered(); @@ -42,38 +44,11 @@ protected override void Open() // Setup static button actions. _window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName)); _window.ClearButton.OnPressed += _ => SendMessage(new ReagentDispenserClearContainerSolutionMessage()); - _window.DispenseButton1.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U1)); - _window.DispenseButton5.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U5)); - _window.DispenseButton10.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U10)); - _window.DispenseButton15.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U15)); - _window.DispenseButton20.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U20)); - _window.DispenseButton25.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U25)); - _window.DispenseButton30.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U30)); - _window.DispenseButton50.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U50)); - _window.DispenseButton100.OnPressed += _ => SendMessage(new ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount.U100)); - // Setup reagent button actions. - _window.OnDispenseReagentButtonPressed += (args, button) => SendMessage(new ReagentDispenserDispenseReagentMessage(button.ReagentId)); - _window.OnDispenseReagentButtonMouseEntered += (args, button) => - { - if (_lastState is not null) - _window.UpdateContainerInfo(_lastState); - }; - _window.OnDispenseReagentButtonMouseExited += (args, button) => - { - if (_lastState is not null) - _window.UpdateContainerInfo(_lastState); - }; + _window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s)); - _window.OnEjectJugButtonPressed += (args, button) => SendMessage(new ItemSlotButtonPressedEvent(button.ReagentId)); - _window.OnEjectJugButtonMouseEntered += (args, button) => { - if (_lastState is not null) - _window.UpdateContainerInfo(_lastState); - }; - _window.OnEjectJugButtonMouseExited += (args, button) => { - if (_lastState is not null) - _window.UpdateContainerInfo(_lastState); - }; + _window.OnDispenseReagentButtonPressed += (id) => SendMessage(new ReagentDispenserDispenseReagentMessage(id)); + _window.OnEjectJugButtonPressed += (id) => SendMessage(new ItemSlotButtonPressedEvent(id)); } /// diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml index 3b812ba56b2..c900d7ecf2d 100644 --- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml +++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml @@ -1,53 +1,77 @@ - - - - [GenerateTypedNameReferences] - public sealed partial class ReagentDispenserWindow : DefaultWindow + public sealed partial class ReagentDispenserWindow : FancyWindow { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IEntityManager _entityManager = default!; - public event Action? OnDispenseReagentButtonPressed; - public event Action? OnDispenseReagentButtonMouseEntered; - public event Action? OnDispenseReagentButtonMouseExited; - - public event Action? OnEjectJugButtonPressed; - public event Action? OnEjectJugButtonMouseEntered; - public event Action? OnEjectJugButtonMouseExited; + public event Action? OnDispenseReagentButtonPressed; + public event Action? OnEjectJugButtonPressed; /// /// Create and initialize the dispenser UI client-side. Creates the basic layout, @@ -35,44 +29,27 @@ public ReagentDispenserWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); - - var dispenseAmountGroup = new ButtonGroup(); - DispenseButton1.Group = dispenseAmountGroup; - DispenseButton5.Group = dispenseAmountGroup; - DispenseButton10.Group = dispenseAmountGroup; - DispenseButton15.Group = dispenseAmountGroup; - DispenseButton20.Group = dispenseAmountGroup; - DispenseButton25.Group = dispenseAmountGroup; - DispenseButton30.Group = dispenseAmountGroup; - DispenseButton50.Group = dispenseAmountGroup; - DispenseButton100.Group = dispenseAmountGroup; } /// /// Update the button grid of reagents which can be dispensed. /// /// Reagents which can be dispensed by this dispenser - public void UpdateReagentsList(List>> inventory) + public void UpdateReagentsList(List inventory) { - if (ChemicalList == null) + if (ReagentList == null) return; - ChemicalList.Children.Clear(); + ReagentList.Children.Clear(); //Sort inventory by reagentLabel - inventory.Sort((x, y) => x.Value.Key.CompareTo(y.Value.Key)); + inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel)); - foreach (KeyValuePair> entry in inventory) + foreach (var item in inventory) { - var button = new DispenseReagentButton(entry.Key, entry.Value.Key, entry.Value.Value); - button.OnPressed += args => OnDispenseReagentButtonPressed?.Invoke(args, button); - button.OnMouseEntered += args => OnDispenseReagentButtonMouseEntered?.Invoke(args, button); - button.OnMouseExited += args => OnDispenseReagentButtonMouseExited?.Invoke(args, button); - ChemicalList.AddChild(button); - var ejectButton = new EjectJugButton(entry.Key); - ejectButton.OnPressed += args => OnEjectJugButtonPressed?.Invoke(args, ejectButton); - ejectButton.OnMouseEntered += args => OnEjectJugButtonMouseEntered?.Invoke(args, ejectButton); - ejectButton.OnMouseExited += args => OnEjectJugButtonMouseExited?.Invoke(args, ejectButton); - ChemicalList.AddChild(ejectButton); + var card = new ReagentCardControl(item); + card.OnPressed += OnDispenseReagentButtonPressed; + card.OnEjectButtonPressed += OnEjectJugButtonPressed; + ReagentList.Children.Add(card); } } @@ -93,36 +70,7 @@ public void UpdateState(BoundUserInterfaceState state) ClearButton.Disabled = castState.OutputContainer is null; EjectButton.Disabled = castState.OutputContainer is null; - switch (castState.SelectedDispenseAmount) - { - case ReagentDispenserDispenseAmount.U1: - DispenseButton1.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U5: - DispenseButton5.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U10: - DispenseButton10.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U15: - DispenseButton15.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U20: - DispenseButton20.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U25: - DispenseButton25.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U30: - DispenseButton30.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U50: - DispenseButton50.Pressed = true; - break; - case ReagentDispenserDispenseAmount.U100: - DispenseButton100.Pressed = true; - break; - } + AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString(); } /// @@ -137,23 +85,15 @@ public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state) if (state.OutputContainer is null) { + ContainerInfoName.Text = ""; + ContainerInfoFill.Text = ""; ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") }); return; } - ContainerInfo.Children.Add(new BoxContainer // Name of the container and its fill status (Ex: 44/100u) - { - Orientation = LayoutOrientation.Horizontal, - Children = - { - new Label {Text = $"{state.OutputContainer.DisplayName}: "}, - new Label - { - Text = $"{state.OutputContainer.CurrentVolume}/{state.OutputContainer.MaxVolume}", - StyleClasses = {StyleNano.StyleClassLabelSecondaryColor} - } - } - }); + // Set Name of the container and its fill status (Ex: 44/100u) + ContainerInfoName.Text = state.OutputContainer.DisplayName; + ContainerInfoFill.Text = state.OutputContainer.CurrentVolume + "/" + state.OutputContainer.MaxVolume; foreach (var (reagent, quantity) in state.OutputContainer.Reagents!) { diff --git a/Content.Client/Chemistry/UI/SolutionStatusControl.cs b/Content.Client/Chemistry/UI/SolutionStatusControl.cs new file mode 100644 index 00000000000..1a33ffb0e14 --- /dev/null +++ b/Content.Client/Chemistry/UI/SolutionStatusControl.cs @@ -0,0 +1,59 @@ +using Content.Client.Chemistry.Components; +using Content.Client.Chemistry.EntitySystems; +using Content.Client.Items.UI; +using Content.Client.Message; +using Content.Client.Stylesheets; +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.FixedPoint; +using Robust.Client.UserInterface.Controls; + +namespace Content.Client.Chemistry.UI; + +/// +/// Displays basic solution information for . +/// +/// +public sealed class SolutionStatusControl : PollingItemStatusControl +{ + private readonly Entity _parent; + private readonly IEntityManager _entityManager; + private readonly SharedSolutionContainerSystem _solutionContainers; + private readonly RichTextLabel _label; + + public SolutionStatusControl( + Entity parent, + IEntityManager entityManager, + SharedSolutionContainerSystem solutionContainers) + { + _parent = parent; + _entityManager = entityManager; + _solutionContainers = solutionContainers; + _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } }; + AddChild(_label); + } + + protected override Data PollData() + { + if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.Solution, out _, out var solution)) + return default; + + FixedPoint2? transferAmount = null; + if (_entityManager.TryGetComponent(_parent.Owner, out SolutionTransferComponent? transfer)) + transferAmount = transfer.TransferAmount; + + return new Data(solution.Volume, solution.MaxVolume, transferAmount); + } + + protected override void Update(in Data data) + { + var markup = Loc.GetString("solution-status-volume", + ("currentVolume", data.Volume), + ("maxVolume", data.MaxVolume)); + if (data.TransferVolume is { } transferVolume) + markup += "\n" + Loc.GetString("solution-status-transfer", ("volume", transferVolume)); + _label.SetMarkup(markup); + } + + public readonly record struct Data(FixedPoint2 Volume, FixedPoint2 MaxVolume, FixedPoint2? TransferVolume); +} diff --git a/Content.Client/Clothing/ClientClothingSystem.cs b/Content.Client/Clothing/ClientClothingSystem.cs index 7e78ac7d707..dd69521f483 100644 --- a/Content.Client/Clothing/ClientClothingSystem.cs +++ b/Content.Client/Clothing/ClientClothingSystem.cs @@ -11,6 +11,7 @@ using Robust.Client.GameObjects; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; +using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Utility; using static Robust.Client.GameObjects.SpriteComponent; @@ -46,6 +47,7 @@ public sealed class ClientClothingSystem : ClothingSystem }; [Dependency] private readonly IResourceCache _cache = default!; + [Dependency] private readonly ISerializationManager _serialization = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; public override void Initialize() @@ -265,6 +267,7 @@ private void RenderEquipment(EntityUid equipee, EntityUid equipment, string slot // temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a // bookmark to determine where in the list of layers we should insert the clothing layers. bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index); + var displacementData = inventory.Displacements.GetValueOrDefault(slot); // add the new layers foreach (var (key, layerData) in ev.Layers) @@ -308,6 +311,28 @@ private void RenderEquipment(EntityUid equipee, EntityUid equipment, string slot sprite.LayerSetData(index, layerData); layer.Offset += slotDef.Offset; + + if (displacementData != null) + { + if (displacementData.ShaderOverride != null) + sprite.LayerSetShader(index, displacementData.ShaderOverride); + + var displacementKey = $"{key}-displacement"; + if (!revealedLayers.Add(displacementKey)) + { + Log.Warning($"Duplicate key for clothing visuals DISPLACEMENT: {displacementKey}."); + continue; + } + + var displacementLayer = _serialization.CreateCopy(displacementData.Layer, notNullableOverride: true); + displacementLayer.CopyToShaderParameters!.LayerKey = key; + + // Add before main layer for this item. + sprite.AddLayer(displacementLayer, index); + sprite.LayerMapSet(displacementKey, index); + + revealedLayers.Add(displacementKey); + } } RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true); diff --git a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs index 90643e45cf7..4d8dd86a4dc 100644 --- a/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs +++ b/Content.Client/Communications/UI/CommunicationsConsoleMenu.xaml.cs @@ -1,7 +1,9 @@ using Content.Client.UserInterface.Controls; using System.Threading; +using Content.Shared.CCVar; using Robust.Client.AutoGenerated; using Robust.Client.UserInterface.XAML; +using Robust.Shared.Configuration; using Robust.Shared.Utility; using Timer = Robust.Shared.Timing.Timer; @@ -13,6 +15,8 @@ public sealed partial class CommunicationsConsoleMenu : FancyWindow private CommunicationsConsoleBoundUserInterface Owner { get; set; } private readonly CancellationTokenSource _timerCancelTokenSource = new(); + [Dependency] private readonly IConfigurationManager _cfg = default!; + public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) { IoCManager.InjectDependencies(this); @@ -23,6 +27,22 @@ public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner) var loc = IoCManager.Resolve(); MessageInput.Placeholder = new Rope.Leaf(loc.GetString("comms-console-menu-announcement-placeholder")); + var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); + MessageInput.OnTextChanged += (args) => + { + if (args.Control.TextLength > maxAnnounceLength) + { + AnnounceButton.Disabled = true; + AnnounceButton.ToolTip = Loc.GetString("comms-console-message-too-long"); + } + else + { + AnnounceButton.Disabled = !owner.CanAnnounce; + AnnounceButton.ToolTip = null; + + } + }; + AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope)); AnnounceButton.Disabled = !owner.CanAnnounce; diff --git a/Content.Client/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs b/Content.Client/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs new file mode 100644 index 00000000000..21fccc880da --- /dev/null +++ b/Content.Client/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs @@ -0,0 +1,7 @@ +using Content.Shared.CriminalRecords.Systems; + +namespace Content.Client.CriminalRecords.Systems; + +public sealed class CriminalRecordsHackerSystem : SharedCriminalRecordsHackerSystem +{ +} diff --git a/Content.Client/DeviceNetwork/JammerSystem.cs b/Content.Client/DeviceNetwork/JammerSystem.cs new file mode 100644 index 00000000000..c7dbf8c8fec --- /dev/null +++ b/Content.Client/DeviceNetwork/JammerSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Radio.EntitySystems; + +namespace Content.Client.DeviceNetwork; + +public sealed class JammerSystem : SharedJammerSystem +{ + +} diff --git a/Content.Client/DoAfter/DoAfterOverlay.cs b/Content.Client/DoAfter/DoAfterOverlay.cs index 2e23dd44cac..45981159f06 100644 --- a/Content.Client/DoAfter/DoAfterOverlay.cs +++ b/Content.Client/DoAfter/DoAfterOverlay.cs @@ -21,7 +21,7 @@ public sealed class DoAfterOverlay : Overlay private readonly ProgressColorSystem _progressColor; private readonly Texture _barTexture; - private readonly ShaderInstance _shader; + private readonly ShaderInstance _unshadedShader; /// /// Flash time for cancelled DoAfters @@ -45,7 +45,7 @@ public DoAfterOverlay(IEntityManager entManager, IPrototypeManager protoManager, var sprite = new SpriteSpecifier.Rsi(new("/Textures/Interface/Misc/progress_bar.rsi"), "icon"); _barTexture = _entManager.EntitySysManager.GetEntitySystem().Frame0(sprite); - _shader = protoManager.Index("unshaded").Instance(); + _unshadedShader = protoManager.Index("unshaded").Instance(); } protected override void Draw(in OverlayDrawArgs args) @@ -58,7 +58,6 @@ protected override void Draw(in OverlayDrawArgs args) const float scale = 1f; var scaleMatrix = Matrix3.CreateScale(new Vector2(scale, scale)); var rotationMatrix = Matrix3.CreateRotation(-rotation); - handle.UseShader(_shader); var curTime = _timing.CurTime; @@ -79,6 +78,13 @@ protected override void Draw(in OverlayDrawArgs args) if (!bounds.Contains(worldPosition)) continue; + // shades the do-after bar if the do-after bar belongs to other players + // does not shade do-afters belonging to the local player + if (uid != localEnt) + handle.UseShader(null); + else + handle.UseShader(_unshadedShader); + // If the entity is paused, we will draw the do-after as it was when the entity got paused. var meta = metaQuery.GetComponent(uid); var time = meta.EntityPaused diff --git a/Content.Client/Entry/EntryPoint.cs b/Content.Client/Entry/EntryPoint.cs index 7f921fc1a6b..1ab213ae0a3 100644 --- a/Content.Client/Entry/EntryPoint.cs +++ b/Content.Client/Entry/EntryPoint.cs @@ -12,10 +12,10 @@ using Content.Client.Input; using Content.Client.IoC; using Content.Client.Launcher; +using Content.Client.Lobby; using Content.Client.MainMenu; using Content.Client.Parallax.Managers; using Content.Client.Players.PlayTimeTracking; -using Content.Client.Preferences; using Content.Client.Radiation.Overlays; using Content.Client.Replay; using Content.Client.Screenshot; @@ -124,6 +124,7 @@ public override void Init() _prototypeManager.RegisterIgnore("alertLevels"); _prototypeManager.RegisterIgnore("nukeopsRole"); _prototypeManager.RegisterIgnore("stationGoal"); + _prototypeManager.RegisterIgnore("ghostRoleRaffleDecider"); _componentFactory.GenerateNetIds(); _adminManager.Initialize(); diff --git a/Content.Client/Extinguisher/FireExtinguisherComponent.cs b/Content.Client/Extinguisher/FireExtinguisherComponent.cs index 126c172924b..324b05a93d4 100644 --- a/Content.Client/Extinguisher/FireExtinguisherComponent.cs +++ b/Content.Client/Extinguisher/FireExtinguisherComponent.cs @@ -3,7 +3,5 @@ namespace Content.Client.Extinguisher; -[NetworkedComponent, RegisterComponent] -public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent -{ -} +[RegisterComponent] +public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent; diff --git a/Content.Client/Eye/EyeLerpingSystem.cs b/Content.Client/Eye/EyeLerpingSystem.cs index 78e1b851fcb..ac32299dca7 100644 --- a/Content.Client/Eye/EyeLerpingSystem.cs +++ b/Content.Client/Eye/EyeLerpingSystem.cs @@ -86,7 +86,7 @@ public void RemoveEye(EntityUid uid) private void HandleMapChange(EntityUid uid, LerpingEyeComponent component, ref EntParentChangedMessage args) { // Is this actually a map change? If yes, stop any lerps - if (args.OldMapId != args.Transform.MapID) + if (args.OldMapId != args.Transform.MapUid) component.LastRotation = GetRotation(uid, args.Transform); } diff --git a/Content.Client/Fax/System/FaxVisualsSystem.cs b/Content.Client/Fax/System/FaxVisualsSystem.cs new file mode 100644 index 00000000000..892aec1d954 --- /dev/null +++ b/Content.Client/Fax/System/FaxVisualsSystem.cs @@ -0,0 +1,48 @@ +using Robust.Client.GameObjects; +using Content.Shared.Fax.Components; +using Content.Shared.Fax; +using Robust.Client.Animations; + +namespace Content.Client.Fax.System; + +/// +/// Visualizer for the fax machine which displays the correct sprite based on the inserted entity. +/// +public sealed class FaxVisualsSystem : EntitySystem +{ + [Dependency] private readonly AnimationPlayerSystem _player = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAppearanceChanged); + } + + private void OnAppearanceChanged(EntityUid uid, FaxMachineComponent component, ref AppearanceChangeEvent args) + { + if (args.Sprite == null) + return; + + if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && visuals == FaxMachineVisualState.Inserting) + { + _player.Play(uid, new Animation() + { + Length = TimeSpan.FromSeconds(2.4), + AnimationTracks = + { + new AnimationTrackSpriteFlick() + { + LayerKey = FaxMachineVisuals.VisualState, + KeyFrames = + { + new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f), + new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f), + } + } + } + }, "faxecute"); + } + } +} diff --git a/Content.Client/Fax/UI/FaxBoundUi.cs b/Content.Client/Fax/UI/FaxBoundUi.cs index 9b57595d7b4..a95066a3b58 100644 --- a/Content.Client/Fax/UI/FaxBoundUi.cs +++ b/Content.Client/Fax/UI/FaxBoundUi.cs @@ -40,7 +40,7 @@ private async void OnFileButtonPressed() { if (_dialogIsOpen) return; - + _dialogIsOpen = true; var filters = new FileDialogFilters(new FileDialogFilters.Group("txt")); await using var file = await _fileDialogManager.OpenFile(filters); @@ -52,8 +52,27 @@ private async void OnFileButtonPressed() } using var reader = new StreamReader(file); + + var firstLine = await reader.ReadLineAsync(); + string? label = null; var content = await reader.ReadToEndAsync(); - SendMessage(new FaxFileMessage(content[..Math.Min(content.Length, FaxFileMessageValidation.MaxContentSize)], _window.OfficePaper)); + + if (firstLine is { }) + { + if (firstLine.StartsWith('#')) + { + label = firstLine[1..].Trim(); + } + else + { + content = firstLine + "\n" + content; + } + } + + SendMessage(new FaxFileMessage( + label?[..Math.Min(label.Length, FaxFileMessageValidation.MaxLabelSize)], + content[..Math.Min(content.Length, FaxFileMessageValidation.MaxContentSize)], + _window.OfficePaper)); } private void OnSendButtonPressed() diff --git a/Content.Client/GameTicking/Managers/ClientGameTicker.cs b/Content.Client/GameTicking/Managers/ClientGameTicker.cs index df709e94446..309db2eb4e6 100644 --- a/Content.Client/GameTicking/Managers/ClientGameTicker.cs +++ b/Content.Client/GameTicking/Managers/ClientGameTicker.cs @@ -1,3 +1,4 @@ +using Content.Client.Administration.Managers; using Content.Client.Gameplay; using Content.Client.Lobby; using Content.Client.RoundEnd; @@ -6,7 +7,7 @@ using JetBrains.Annotations; using Robust.Client.Graphics; using Robust.Client.State; -using Robust.Shared.Utility; +using Robust.Client.UserInterface; namespace Content.Client.GameTicking.Managers { @@ -14,17 +15,14 @@ namespace Content.Client.GameTicking.Managers public sealed class ClientGameTicker : SharedGameTicker { [Dependency] private readonly IStateManager _stateManager = default!; - [Dependency] private readonly IEntityManager _entityManager = default!; + [Dependency] private readonly IClientAdminManager _admin = default!; + [Dependency] private readonly IClyde _clyde = default!; + [Dependency] private readonly SharedMapSystem _map = default!; + [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; - [ViewVariables] private bool _initialized; private Dictionary> _jobsAvailable = new(); private Dictionary _stationNames = new(); - /// - /// The current round-end window. Could be used to support re-opening the window after closing it. - /// - private RoundEndSummaryWindow? _window; - [ViewVariables] public bool AreWeReady { get; private set; } [ViewVariables] public bool IsGameStarted { get; private set; } [ViewVariables] public string? RestartSound { get; private set; } @@ -44,8 +42,6 @@ public sealed class ClientGameTicker : SharedGameTicker public override void Initialize() { - DebugTools.Assert(!_initialized); - SubscribeNetworkEvent(JoinLobby); SubscribeNetworkEvent(JoinGame); SubscribeNetworkEvent(ConnectionStatus); @@ -53,14 +49,33 @@ public override void Initialize() SubscribeNetworkEvent(LobbyInfo); SubscribeNetworkEvent(LobbyCountdown); SubscribeNetworkEvent(RoundEnd); - SubscribeNetworkEvent(msg => - { - IoCManager.Resolve().RequestWindowAttention(); - }); + SubscribeNetworkEvent(OnAttentionRequest); SubscribeNetworkEvent(LateJoinStatus); SubscribeNetworkEvent(UpdateJobsAvailable); - _initialized = true; + _admin.AdminStatusUpdated += OnAdminUpdated; + OnAdminUpdated(); + } + + public override void Shutdown() + { + _admin.AdminStatusUpdated -= OnAdminUpdated; + base.Shutdown(); + } + + private void OnAdminUpdated() + { + // Hide some map/grid related logs from clients. This is to try prevent some easy metagaming by just + // reading the console. E.g., logs like this one could leak the nuke station/grid: + // > Grid NT-Arrivals 1101 (122/n25896) changed parent. Old parent: map 10 (121/n25895). New parent: FTL (123/n26470) +#if !DEBUG + _map.Log.Level = _admin.IsAdmin() ? LogLevel.Info : LogLevel.Warning; +#endif + } + + private void OnAttentionRequest(RequestWindowAttentionEvent ev) + { + _clyde.RequestWindowAttention(); } private void LateJoinStatus(TickerLateJoinStatusEvent message) @@ -132,12 +147,7 @@ private void RoundEnd(RoundEndMessageEvent message) // Force an update in the event of this song being the same as the last. RestartSound = message.RestartSound; - // Don't open duplicate windows (mainly for replays). - if (_window?.RoundId == message.RoundId) - return; - - //This is not ideal at all, but I don't see an immediately better fit anywhere else. - _window = new RoundEndSummaryWindow(message.GamemodeTitle, message.RoundEndText, message.RoundDuration, message.RoundId, message.AllPlayersEndInfo, _entityManager); + _userInterfaceManager.GetUIController().OpenRoundEndSummaryWindow(message); } } } diff --git a/Content.Client/Ghost/Commands/ToggleGhostVisibilityCommand.cs b/Content.Client/Ghost/Commands/ToggleGhostVisibilityCommand.cs new file mode 100644 index 00000000000..480da6ad8d9 --- /dev/null +++ b/Content.Client/Ghost/Commands/ToggleGhostVisibilityCommand.cs @@ -0,0 +1,26 @@ +using Robust.Shared.Console; + +namespace Content.Client.Ghost.Commands; + +public sealed class ToggleGhostVisibilityCommand : IConsoleCommand +{ + [Dependency] private readonly IEntitySystemManager _entSysMan = default!; + + public string Command => "toggleghostvisibility"; + public string Description => "Toggles ghost visibility on the client."; + public string Help => "toggleghostvisibility [bool]"; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + var ghostSystem = _entSysMan.GetEntitySystem(); + + if (args.Length != 0 && bool.TryParse(args[0], out var visibility)) + { + ghostSystem.ToggleGhostVisibility(visibility); + } + else + { + ghostSystem.ToggleGhostVisibility(); + } + } +} diff --git a/Content.Client/Ghost/GhostSystem.cs b/Content.Client/Ghost/GhostSystem.cs index c42e7cd0e0c..94872a58ef9 100644 --- a/Content.Client/Ghost/GhostSystem.cs +++ b/Content.Client/Ghost/GhostSystem.cs @@ -3,7 +3,6 @@ using Content.Shared.Ghost; using Robust.Client.Console; using Robust.Client.GameObjects; -using Robust.Client.Graphics; using Robust.Client.Player; using Robust.Shared.Player; @@ -177,9 +176,9 @@ public void OpenGhostRoles() _console.RemoteExecuteCommand(null, "ghostroles"); } - public void ToggleGhostVisibility() + public void ToggleGhostVisibility(bool? visibility = null) { - GhostVisibility = !GhostVisibility; + GhostVisibility = visibility ?? !GhostVisibility; } } } diff --git a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs index e2b09386dfb..537494933bc 100644 --- a/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs +++ b/Content.Client/Guidebook/Controls/GuideReagentEmbed.xaml.cs @@ -4,6 +4,7 @@ using Content.Client.Guidebook.Richtext; using Content.Client.Message; using Content.Client.UserInterface.ControlExtensions; +using Content.Shared.Body.Prototypes; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; using JetBrains.Annotations; @@ -128,7 +129,7 @@ private void GenerateControl(ReagentPrototype reagent) var groupLabel = new RichTextLabel(); groupLabel.SetMarkup(Loc.GetString("guidebook-reagent-effects-metabolism-group-rate", - ("group", group), ("rate", effect.MetabolismRate))); + ("group", _prototype.Index(group).LocalizedName), ("rate", effect.MetabolismRate))); var descriptionLabel = new RichTextLabel { Margin = new Thickness(25, 0, 10, 0) diff --git a/Content.Client/Guidebook/GuideEntry.cs b/Content.Client/Guidebook/GuideEntry.cs index b3c004267db..b7b3b3309e6 100644 --- a/Content.Client/Guidebook/GuideEntry.cs +++ b/Content.Client/Guidebook/GuideEntry.cs @@ -42,7 +42,7 @@ public class GuideEntry } [Prototype("guideEntry")] -public sealed class GuideEntryPrototype : GuideEntry, IPrototype +public sealed partial class GuideEntryPrototype : GuideEntry, IPrototype { public string ID => Id; } diff --git a/Content.Client/Guidebook/GuidebookSystem.cs b/Content.Client/Guidebook/GuidebookSystem.cs index cb13d4ca6e5..0aa2c85142e 100644 --- a/Content.Client/Guidebook/GuidebookSystem.cs +++ b/Content.Client/Guidebook/GuidebookSystem.cs @@ -80,6 +80,11 @@ private void OnGetVerbs(EntityUid uid, GuideHelpComponent component, GetVerbsEve }); } + public void OpenHelp(List guides) + { + OnGuidebookOpen?.Invoke(guides, null, null, true, guides[0]); + } + private void OnInteract(EntityUid uid, GuideHelpComponent component, ActivateInWorldEvent args) { if (!_timing.IsFirstTimePredicted) diff --git a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs index 0cb3ad144d7..fcf6d4551fd 100644 --- a/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs +++ b/Content.Client/HealthAnalyzer/UI/HealthAnalyzerWindow.xaml.cs @@ -139,7 +139,7 @@ private void DrawDiagnosticGroups( var groupTitleText = $"{Loc.GetString( "health-analyzer-window-damage-group-text", - ("damageGroup", Loc.GetString("health-analyzer-window-damage-group-" + damageGroupId)), + ("damageGroup", _prototypes.Index(damageGroupId).LocalizedName), ("amount", damageAmount) )}"; @@ -170,7 +170,7 @@ private void DrawDiagnosticGroups( var damageString = Loc.GetString( "health-analyzer-window-damage-type-text", - ("damageType", Loc.GetString("health-analyzer-window-damage-type-" + type)), + ("damageType", _prototypes.Index(type).LocalizedName), ("amount", typeAmount) ); diff --git a/Content.Client/Implants/UI/ImplanterStatusControl.cs b/Content.Client/Implants/UI/ImplanterStatusControl.cs index f3f0cdea7d7..e2ffabd17d9 100644 --- a/Content.Client/Implants/UI/ImplanterStatusControl.cs +++ b/Content.Client/Implants/UI/ImplanterStatusControl.cs @@ -1,5 +1,6 @@ using Content.Client.Message; using Content.Client.Stylesheets; +using Content.Client.UserInterface.Controls; using Content.Shared.Implants.Components; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; @@ -17,7 +18,7 @@ public ImplanterStatusControl(ImplanterComponent parent) _parent = parent; _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } }; _label.MaxWidth = 350; - AddChild(_label); + AddChild(new ClipControl { Children = { _label } }); Update(); } @@ -42,17 +43,12 @@ private void Update() _ => Loc.GetString("injector-invalid-injector-toggle-mode") }; - var (implantName, implantDescription) = _parent.ImplanterSlot.HasItem switch - { - false => (Loc.GetString("implanter-empty-text"), ""), - true => (_parent.ImplantData.Item1, _parent.ImplantData.Item2), - }; - + var implantName = _parent.ImplanterSlot.HasItem + ? _parent.ImplantData.Item1 + : Loc.GetString("implanter-empty-text"); _label.SetMarkup(Loc.GetString("implanter-label", ("implantName", implantName), - ("implantDescription", implantDescription), - ("modeString", modeStringLocalized), - ("lineBreak", "\n"))); + ("modeString", modeStringLocalized))); } } diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs index 0e56153752d..dfc00eff88b 100644 --- a/Content.Client/Input/ContentContexts.cs +++ b/Content.Client/Input/ContentContexts.cs @@ -38,6 +38,7 @@ public static void SetupContexts(IInputContextContainer contexts) common.AddFunction(ContentKeyFunctions.ZoomIn); common.AddFunction(ContentKeyFunctions.ResetZoom); common.AddFunction(ContentKeyFunctions.InspectEntity); + common.AddFunction(ContentKeyFunctions.ToggleRoundEndSummaryWindow); // Not in engine, because engine cannot check for sanbox/admin status before starting placement. common.AddFunction(ContentKeyFunctions.EditorCopyObject); @@ -59,6 +60,7 @@ public static void SetupContexts(IInputContextContainer contexts) human.AddFunction(ContentKeyFunctions.UseItemInHand); human.AddFunction(ContentKeyFunctions.AltUseItemInHand); human.AddFunction(ContentKeyFunctions.OpenCharacterMenu); + human.AddFunction(ContentKeyFunctions.OpenEmotesMenu); human.AddFunction(ContentKeyFunctions.OpenLanguageMenu); human.AddFunction(ContentKeyFunctions.ActivateItemInWorld); human.AddFunction(ContentKeyFunctions.ThrowItemInHand); diff --git a/Content.Client/Inventory/ClientInventorySystem.cs b/Content.Client/Inventory/ClientInventorySystem.cs index 7b98513a929..87cea4e3d2f 100644 --- a/Content.Client/Inventory/ClientInventorySystem.cs +++ b/Content.Client/Inventory/ClientInventorySystem.cs @@ -199,7 +199,7 @@ public void UIInventoryActivate(string slot) public void UIInventoryStorageActivate(string slot) { - EntityManager.EntityNetManager?.SendSystemNetworkMessage(new OpenSlotStorageNetworkMessage(slot)); + EntityManager.RaisePredictiveEvent(new OpenSlotStorageNetworkMessage(slot)); } public void UIInventoryExamine(string slot, EntityUid uid) @@ -251,6 +251,7 @@ public sealed class SlotData public string SlotGroup => SlotDef.SlotGroup; public string SlotDisplayName => SlotDef.DisplayName; public string TextureName => "Slots/" + SlotDef.TextureName; + public string FullTextureName => SlotDef.FullTextureName; public SlotData(SlotDefinition slotDef, ContainerSlot? container = null, bool highlighted = false, bool blocked = false) diff --git a/Content.Client/Inventory/StrippableBoundUserInterface.cs b/Content.Client/Inventory/StrippableBoundUserInterface.cs index 4bb49fecc14..4ccede7f5d4 100644 --- a/Content.Client/Inventory/StrippableBoundUserInterface.cs +++ b/Content.Client/Inventory/StrippableBoundUserInterface.cs @@ -222,7 +222,7 @@ private void UpdateEntityIcon(SlotControl button, EntityUid? entity) if (entity == null) { - button.SpriteView.SetEntity(null); + button.SetEntity(null); return; } @@ -234,7 +234,7 @@ private void UpdateEntityIcon(SlotControl button, EntityUid? entity) else return; - button.SpriteView.SetEntity(viewEnt); + button.SetEntity(viewEnt); } } } diff --git a/Content.Client/IoC/ClientContentIoC.cs b/Content.Client/IoC/ClientContentIoC.cs index 01c8f382819..8c2b676c2e2 100644 --- a/Content.Client/IoC/ClientContentIoC.cs +++ b/Content.Client/IoC/ClientContentIoC.cs @@ -4,23 +4,20 @@ using Content.Client.Clickable; using Content.Client.DiscordAuth; using Content.Client.JoinQueue; -using Content.Client.Options; using Content.Client.Eui; using Content.Client.GhostKick; using Content.Client.Info; using Content.Client.Launcher; using Content.Client.Parallax.Managers; using Content.Client.Players.PlayTimeTracking; -using Content.Client.Preferences; using Content.Client.Screenshot; using Content.Client.Fullscreen; using Content.Client.Stylesheets; using Content.Client.Viewport; using Content.Client.Voting; -using Content.Shared.Administration; using Content.Shared.Administration.Logs; -using Content.Shared.Module; using Content.Client.Guidebook; +using Content.Client.Lobby; using Content.Client.Replay; using Content.Shared.Administration.Managers; using Content.Shared.Players.PlayTimeTracking; diff --git a/Content.Client/Items/UI/PollingItemStatusControl.cs b/Content.Client/Items/UI/PollingItemStatusControl.cs new file mode 100644 index 00000000000..39cffb06f6a --- /dev/null +++ b/Content.Client/Items/UI/PollingItemStatusControl.cs @@ -0,0 +1,28 @@ +using Robust.Client.UserInterface; +using Robust.Shared.Timing; + +namespace Content.Client.Items.UI; + +/// +/// A base for item status controls that poll data every frame. Avoids UI updates if data didn't change. +/// +/// The full status control data that is polled every frame. +public abstract class PollingItemStatusControl : Control where TData : struct, IEquatable +{ + private TData _lastData; + + protected override void FrameUpdate(FrameEventArgs args) + { + base.FrameUpdate(args); + + var newData = PollData(); + if (newData.Equals(_lastData)) + return; + + _lastData = newData; + Update(newData); + } + + protected abstract TData PollData(); + protected abstract void Update(in TData data); +} diff --git a/Content.Client/Labels/EntitySystems/HandLabelerSystem.cs b/Content.Client/Labels/EntitySystems/HandLabelerSystem.cs new file mode 100644 index 00000000000..e956014b2e1 --- /dev/null +++ b/Content.Client/Labels/EntitySystems/HandLabelerSystem.cs @@ -0,0 +1,18 @@ +using Content.Client.Labels.UI; +using Content.Shared.Labels; +using Content.Shared.Labels.Components; +using Content.Shared.Labels.EntitySystems; + +namespace Content.Client.Labels.EntitySystems; + +public sealed class HandLabelerSystem : SharedHandLabelerSystem +{ + protected override void UpdateUI(Entity ent) + { + if (UserInterfaceSystem.TryGetOpenUi(ent.Owner, HandLabelerUiKey.Key, out var bui) + && bui is HandLabelerBoundUserInterface cBui) + { + cBui.Reload(); + } + } +} diff --git a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs index d393c43f936..555f1ff09e6 100644 --- a/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs +++ b/Content.Client/Labels/UI/HandLabelerBoundUserInterface.cs @@ -1,4 +1,5 @@ using Content.Shared.Labels; +using Content.Shared.Labels.Components; using Robust.Client.GameObjects; namespace Content.Client.Labels.UI @@ -8,11 +9,14 @@ namespace Content.Client.Labels.UI /// public sealed class HandLabelerBoundUserInterface : BoundUserInterface { + [Dependency] private readonly IEntityManager _entManager = default!; + [ViewVariables] private HandLabelerWindow? _window; public HandLabelerBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey) { + IoCManager.InjectDependencies(this); } protected override void Open() @@ -27,24 +31,25 @@ protected override void Open() _window.OnClose += Close; _window.OnLabelChanged += OnLabelChanged; + Reload(); } private void OnLabelChanged(string newLabel) { - SendMessage(new HandLabelerLabelChangedMessage(newLabel)); + // Focus moment + if (_entManager.TryGetComponent(Owner, out HandLabelerComponent? labeler) && + labeler.AssignedLabel.Equals(newLabel)) + return; + + SendPredictedMessage(new HandLabelerLabelChangedMessage(newLabel)); } - /// - /// Update the UI state based on server-sent info - /// - /// - protected override void UpdateState(BoundUserInterfaceState state) + public void Reload() { - base.UpdateState(state); - if (_window == null || state is not HandLabelerBoundUserInterfaceState cast) + if (_window == null || !_entManager.TryGetComponent(Owner, out HandLabelerComponent? component)) return; - _window.SetCurrentLabel(cast.CurrentLabel); + _window.SetCurrentLabel(component.AssignedLabel); } protected override void Dispose(bool disposing) diff --git a/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs b/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs index 7706c31f85a..6482cdc1cc2 100644 --- a/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs +++ b/Content.Client/Labels/UI/HandLabelerWindow.xaml.cs @@ -9,17 +9,40 @@ public sealed partial class HandLabelerWindow : DefaultWindow { public event Action? OnLabelChanged; + /// + /// Is the user currently entering text into the control? + /// + private bool _focused; + // TODO LineEdit Make this a bool on the LineEdit control + + private string _label = string.Empty; + public HandLabelerWindow() { RobustXamlLoader.Load(this); - LabelLineEdit.OnTextEntered += e => OnLabelChanged?.Invoke(e.Text); - LabelLineEdit.OnFocusExit += e => OnLabelChanged?.Invoke(e.Text); + LabelLineEdit.OnTextEntered += e => + { + _label = e.Text; + OnLabelChanged?.Invoke(_label); + }; + + LabelLineEdit.OnFocusEnter += _ => _focused = true; + LabelLineEdit.OnFocusExit += _ => + { + _focused = false; + LabelLineEdit.Text = _label; + }; } public void SetCurrentLabel(string label) { - LabelLineEdit.Text = label; + if (label == _label) + return; + + _label = label; + if (!_focused) + LabelLineEdit.Text = label; } } } diff --git a/Content.Client/LateJoin/LateJoinGui.cs b/Content.Client/LateJoin/LateJoinGui.cs index 1351aa9e86a..1b2a87be726 100644 --- a/Content.Client/LateJoin/LateJoinGui.cs +++ b/Content.Client/LateJoin/LateJoinGui.cs @@ -2,15 +2,14 @@ using System.Numerics; using Content.Client.CrewManifest; using Content.Client.GameTicking.Managers; +using Content.Client.Lobby; using Content.Client.UserInterface.Controls; using Content.Client.Players.PlayTimeTracking; -using Content.Client.Preferences; using Content.Shared.CCVar; using Content.Shared.Customization.Systems; using Content.Shared.Preferences; using Content.Shared.Roles; using Content.Shared.StatusIcon; -using Microsoft.Win32.SafeHandles; using Robust.Client.Console; using Robust.Client.GameObjects; using Robust.Client.UserInterface; diff --git a/Content.Client/Lathe/UI/LatheMenu.xaml.cs b/Content.Client/Lathe/UI/LatheMenu.xaml.cs index ca8d2561270..9e15f8239e5 100644 --- a/Content.Client/Lathe/UI/LatheMenu.xaml.cs +++ b/Content.Client/Lathe/UI/LatheMenu.xaml.cs @@ -10,6 +10,8 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; +using Robust.Client.ResourceManagement; +using Robust.Client.Graphics; using Robust.Shared.Prototypes; namespace Content.Client.Lathe.UI; @@ -19,6 +21,8 @@ public sealed partial class LatheMenu : DefaultWindow { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IResourceCache _resources = default!; + private EntityUid _owner; private readonly SpriteSystem _spriteSystem; private readonly LatheSystem _lathe; @@ -104,12 +108,21 @@ public void PopulateRecipes() RecipeList.Children.Clear(); foreach (var prototype in sortedRecipesToShow) { - var icon = prototype.Icon == null - ? _spriteSystem.GetPrototypeIcon(prototype.Result).Default - : _spriteSystem.Frame0(prototype.Icon); + List textures; + if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto) && entityProto != null) + { + textures = SpriteComponent.GetPrototypeTextures(entityProto, _resources).Select(o => o.Default).ToList(); + } + else + { + textures = prototype.Icon == null + ? new List { _spriteSystem.GetPrototypeIcon(prototype.Result).Default } + : new List { _spriteSystem.Frame0(prototype.Icon) }; + } + var canProduce = _lathe.CanProduce(_owner, prototype, quantity); - var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, icon); + var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, textures); control.OnButtonPressed += s => { if (!int.TryParse(AmountLineEdit.Text, out var amount) || amount <= 0) diff --git a/Content.Client/Lathe/UI/RecipeControl.xaml b/Content.Client/Lathe/UI/RecipeControl.xaml index 2e02c8a6147..d1371a026a2 100644 --- a/Content.Client/Lathe/UI/RecipeControl.xaml +++ b/Content.Client/Lathe/UI/RecipeControl.xaml @@ -5,11 +5,15 @@ Margin="0" StyleClasses="ButtonSquare"> - + CanShrink="true" + /> diff --git a/Content.Client/Lathe/UI/RecipeControl.xaml.cs b/Content.Client/Lathe/UI/RecipeControl.xaml.cs index bf85ff7d938..47b6b5932c4 100644 --- a/Content.Client/Lathe/UI/RecipeControl.xaml.cs +++ b/Content.Client/Lathe/UI/RecipeControl.xaml.cs @@ -2,8 +2,8 @@ using Robust.Client.AutoGenerated; using Robust.Client.Graphics; using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.Graphics; namespace Content.Client.Lathe.UI; @@ -13,12 +13,12 @@ public sealed partial class RecipeControl : Control public Action? OnButtonPressed; public Func TooltipTextSupplier; - public RecipeControl(LatheRecipePrototype recipe, Func tooltipTextSupplier, bool canProduce, Texture? texture = null) + public RecipeControl(LatheRecipePrototype recipe, Func tooltipTextSupplier, bool canProduce, List textures) { RobustXamlLoader.Load(this); RecipeName.Text = recipe.Name; - RecipeTexture.Texture = texture; + RecipeTextures.Textures = textures; Button.Disabled = !canProduce; TooltipTextSupplier = tooltipTextSupplier; Button.TooltipSupplier = SupplyTooltip; diff --git a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs index a2a7fb2531c..80774067301 100644 --- a/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs +++ b/Content.Client/Light/EntitySystems/ExpendableLightSystem.cs @@ -52,7 +52,7 @@ protected override void OnAppearanceChange(EntityUid uid, ExpendableLightCompone case ExpendableLightState.Lit: _audioSystem.Stop(comp.PlayingStream); comp.PlayingStream = _audioSystem.PlayPvs( - comp.LoopedSound, uid, SharedExpendableLightComponent.LoopedSoundParams)?.Entity; + comp.LoopedSound, uid)?.Entity; if (args.Sprite.LayerMapTryGet(ExpendableLightVisualLayers.Overlay, out var layerIdx, true)) { diff --git a/Content.Client/Preferences/ClientPreferencesManager.cs b/Content.Client/Lobby/ClientPreferencesManager.cs similarity index 99% rename from Content.Client/Preferences/ClientPreferencesManager.cs rename to Content.Client/Lobby/ClientPreferencesManager.cs index aca7159504d..29269686579 100644 --- a/Content.Client/Preferences/ClientPreferencesManager.cs +++ b/Content.Client/Lobby/ClientPreferencesManager.cs @@ -10,7 +10,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Utility; -namespace Content.Client.Preferences +namespace Content.Client.Lobby { /// /// Receives and from the server during the initial diff --git a/Content.Client/Preferences/IClientPreferencesManager.cs b/Content.Client/Lobby/IClientPreferencesManager.cs similarity index 94% rename from Content.Client/Preferences/IClientPreferencesManager.cs rename to Content.Client/Lobby/IClientPreferencesManager.cs index e55d6b600ca..1b72593ad04 100644 --- a/Content.Client/Preferences/IClientPreferencesManager.cs +++ b/Content.Client/Lobby/IClientPreferencesManager.cs @@ -1,7 +1,7 @@ using System; using Content.Shared.Preferences; -namespace Content.Client.Preferences +namespace Content.Client.Lobby { public interface IClientPreferencesManager { diff --git a/Content.Client/Lobby/LobbyState.cs b/Content.Client/Lobby/LobbyState.cs index bed52217a99..2e728f552a5 100644 --- a/Content.Client/Lobby/LobbyState.cs +++ b/Content.Client/Lobby/LobbyState.cs @@ -3,8 +3,6 @@ using Content.Client.LateJoin; using Content.Client.Lobby.UI; using Content.Client.Message; -using Content.Client.Preferences; -using Content.Client.Preferences.UI; using Content.Client.UserInterface.Systems.Chat; using Content.Client.Voting; using Robust.Client; @@ -12,8 +10,6 @@ using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controls; -using Robust.Shared.Configuration; -using Robust.Shared.Prototypes; using Robust.Shared.Timing; @@ -25,59 +21,39 @@ public sealed class LobbyState : Robust.Client.State.State [Dependency] private readonly IClientConsoleHost _consoleHost = default!; [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IResourceCache _resourceCache = default!; - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; - [Dependency] private readonly IClientPreferencesManager _preferencesManager = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IVoteManager _voteManager = default!; - [Dependency] private readonly IConfigurationManager _configurationManager = default!; - - [ViewVariables] private CharacterSetupGui? _characterSetup; private ClientGameTicker _gameTicker = default!; private ContentAudioSystem _contentAudioSystem = default!; protected override Type? LinkedScreenType { get; } = typeof(LobbyGui); - private LobbyGui? _lobby; + public LobbyGui? Lobby; protected override void Startup() { if (_userInterfaceManager.ActiveScreen == null) return; - _lobby = (LobbyGui) _userInterfaceManager.ActiveScreen; + Lobby = (LobbyGui) _userInterfaceManager.ActiveScreen; var chatController = _userInterfaceManager.GetUIController(); _gameTicker = _entityManager.System(); _contentAudioSystem = _entityManager.System(); _contentAudioSystem.LobbySoundtrackChanged += UpdateLobbySoundtrackInfo; - _characterSetup = new CharacterSetupGui(_entityManager, _resourceCache, _preferencesManager, - _prototypeManager, _configurationManager); - LayoutContainer.SetAnchorPreset(_characterSetup, LayoutContainer.LayoutPreset.Wide); - _lobby.CharacterSetupState.AddChild(_characterSetup); chatController.SetMainChat(true); - _voteManager.SetPopupContainer(_lobby.VoteContainer); - - _characterSetup.CloseButton.OnPressed += _ => - { - _lobby.SwitchState(LobbyGui.LobbyGuiState.Default); - }; + _voteManager.SetPopupContainer(Lobby.VoteContainer); + LayoutContainer.SetAnchorPreset(Lobby, LayoutContainer.LayoutPreset.Wide); + Lobby.ServerName.Text = _baseClient.GameInfo?.ServerName; // The eye of refactor gazes upon you... - _characterSetup.SaveButton.OnPressed += _ => - { - _characterSetup.Save(); - _userInterfaceManager.GetUIController().UpdateCharacterUI(); - }; - - LayoutContainer.SetAnchorPreset(_lobby, LayoutContainer.LayoutPreset.Wide); - _lobby.ServerName.Text = _baseClient.GameInfo?.ServerName; //The eye of refactor gazes upon you... UpdateLobbyUi(); - _lobby.CharacterPreview.CharacterSetupButton.OnPressed += OnSetupPressed; - _lobby.ReadyButton.OnPressed += OnReadyPressed; - _lobby.ReadyButton.OnToggled += OnReadyToggled; + Lobby.CharacterPreview.CharacterSetupButton.OnPressed += OnSetupPressed; + Lobby.ReadyButton.OnPressed += OnReadyPressed; + Lobby.ReadyButton.OnToggled += OnReadyToggled; _gameTicker.InfoBlobUpdated += UpdateLobbyUi; _gameTicker.LobbyStatusUpdated += LobbyStatusUpdated; @@ -95,20 +71,23 @@ protected override void Shutdown() _voteManager.ClearPopupContainer(); - _lobby!.CharacterPreview.CharacterSetupButton.OnPressed -= OnSetupPressed; - _lobby!.ReadyButton.OnPressed -= OnReadyPressed; - _lobby!.ReadyButton.OnToggled -= OnReadyToggled; + Lobby!.CharacterPreview.CharacterSetupButton.OnPressed -= OnSetupPressed; + Lobby!.ReadyButton.OnPressed -= OnReadyPressed; + Lobby!.ReadyButton.OnToggled -= OnReadyToggled; - _lobby = null; + Lobby = null; + } - _characterSetup?.Dispose(); - _characterSetup = null; + public void SwitchState(LobbyGui.LobbyGuiState state) + { + // Yeah I hate this but LobbyState contains all the badness for now + Lobby?.SwitchState(state); } private void OnSetupPressed(BaseButton.ButtonEventArgs args) { SetReady(false); - _lobby!.SwitchState(LobbyGui.LobbyGuiState.CharacterSetup); + Lobby?.SwitchState(LobbyGui.LobbyGuiState.CharacterSetup); } private void OnReadyPressed(BaseButton.ButtonEventArgs args) @@ -128,20 +107,20 @@ public override void FrameUpdate(FrameEventArgs e) { if (_gameTicker.IsGameStarted) { - _lobby!.StartTime.Text = string.Empty; + Lobby!.StartTime.Text = string.Empty; var roundTime = _gameTiming.CurTime.Subtract(_gameTicker.RoundStartTimeSpan); - _lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-time", ("hours", roundTime.Hours), ("minutes", roundTime.Minutes)); + Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-time", ("hours", roundTime.Hours), ("minutes", roundTime.Minutes)); return; } - _lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started"); + Lobby!.StationTime.Text = Loc.GetString("lobby-state-player-status-round-not-started"); string text; if (_gameTicker.Paused) text = Loc.GetString("lobby-state-paused"); else if (_gameTicker.StartTime < _gameTiming.CurTime) { - _lobby!.StartTime.Text = Loc.GetString("lobby-state-soon"); + Lobby!.StartTime.Text = Loc.GetString("lobby-state-soon"); return; } else @@ -156,7 +135,7 @@ public override void FrameUpdate(FrameEventArgs e) text = $"{difference.Minutes}:{difference.Seconds:D2}"; } - _lobby!.StartTime.Text = Loc.GetString("lobby-state-round-start-countdown-text", ("timeLeft", text)); + Lobby!.StartTime.Text = Loc.GetString("lobby-state-round-start-countdown-text", ("timeLeft", text)); } private void LobbyStatusUpdated() @@ -167,36 +146,36 @@ private void LobbyStatusUpdated() private void LobbyLateJoinStatusUpdated() { - _lobby!.ReadyButton.Disabled = _gameTicker.DisallowedLateJoin; + Lobby!.ReadyButton.Disabled = _gameTicker.DisallowedLateJoin; } private void UpdateLobbyUi() { if (_gameTicker.IsGameStarted) { - _lobby!.ReadyButton.Text = Loc.GetString("lobby-state-ready-button-join-state"); - _lobby!.ReadyButton.ToggleMode = false; - _lobby!.ReadyButton.Pressed = false; - _lobby!.ObserveButton.Disabled = false; + Lobby!.ReadyButton.Text = Loc.GetString("lobby-state-ready-button-join-state"); + Lobby!.ReadyButton.ToggleMode = false; + Lobby!.ReadyButton.Pressed = false; + Lobby!.ObserveButton.Disabled = false; } else { - _lobby!.StartTime.Text = string.Empty; - _lobby!.ReadyButton.Text = Loc.GetString(_lobby!.ReadyButton.Pressed ? "lobby-state-player-status-ready": "lobby-state-player-status-not-ready"); - _lobby!.ReadyButton.ToggleMode = true; - _lobby!.ReadyButton.Disabled = false; - _lobby!.ReadyButton.Pressed = _gameTicker.AreWeReady; - _lobby!.ObserveButton.Disabled = true; + Lobby!.StartTime.Text = string.Empty; + Lobby!.ReadyButton.Text = Loc.GetString(Lobby!.ReadyButton.Pressed ? "lobby-state-player-status-ready": "lobby-state-player-status-not-ready"); + Lobby!.ReadyButton.ToggleMode = true; + Lobby!.ReadyButton.Disabled = false; + Lobby!.ReadyButton.Pressed = _gameTicker.AreWeReady; + Lobby!.ObserveButton.Disabled = true; } if (_gameTicker.ServerInfoBlob != null) - _lobby!.ServerInfo.SetInfoBlob(_gameTicker.ServerInfoBlob); + Lobby!.ServerInfo.SetInfoBlob(_gameTicker.ServerInfoBlob); } private void UpdateLobbySoundtrackInfo(LobbySoundtrackChangedEvent ev) { if (ev.SoundtrackFilename == null) - _lobby!.LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text")); + Lobby!.LobbySong.SetMarkup(Loc.GetString("lobby-state-song-no-song-text")); else if (ev.SoundtrackFilename != null && _resourceCache.TryGetResource(ev.SoundtrackFilename, out var lobbySongResource)) { @@ -214,16 +193,16 @@ private void UpdateLobbySoundtrackInfo(LobbySoundtrackChangedEvent ev) ("songTitle", title), ("songArtist", artist)); - _lobby!.LobbySong.SetMarkup(markup); + Lobby!.LobbySong.SetMarkup(markup); } } private void UpdateLobbyBackground() { if (_gameTicker.LobbyBackground != null) - _lobby!.Background.Texture = _resourceCache.GetResource(_gameTicker.LobbyBackground); + Lobby!.Background.Texture = _resourceCache.GetResource(_gameTicker.LobbyBackground); else - _lobby!.Background.Texture = null; + Lobby!.Background.Texture = null; } diff --git a/Content.Client/Lobby/LobbyUIController.cs b/Content.Client/Lobby/LobbyUIController.cs index 47ab651c10e..ccefbb0aa4b 100644 --- a/Content.Client/Lobby/LobbyUIController.cs +++ b/Content.Client/Lobby/LobbyUIController.cs @@ -3,156 +3,250 @@ using Content.Client.Inventory; using Content.Client.Lobby.UI; using Content.Client.Players.PlayTimeTracking; -using Content.Client.Preferences; -using Content.Client.Preferences.UI; +using Content.Shared.CCVar; +using Content.Shared.Clothing.Loadouts.Prototypes; using Content.Shared.Clothing.Loadouts.Systems; using Content.Shared.GameTicking; -using Content.Shared.Humanoid; +using Content.Shared.Humanoid.Markings; using Content.Shared.Humanoid.Prototypes; using Content.Shared.Preferences; using Content.Shared.Roles; +using Content.Shared.Traits; +using Robust.Client.Player; +using Robust.Client.ResourceManagement; using Robust.Client.State; using Robust.Client.UserInterface; using Robust.Client.UserInterface.Controllers; +using Robust.Shared.Configuration; using Robust.Shared.Map; using Robust.Shared.Prototypes; +using Robust.Shared.Utility; +using static Content.Shared.Humanoid.SharedHumanoidAppearanceSystem; +using CharacterSetupGui = Content.Client.Lobby.UI.CharacterSetupGui; +using HumanoidProfileEditor = Content.Client.Lobby.UI.HumanoidProfileEditor; namespace Content.Client.Lobby; public sealed class LobbyUIController : UIController, IOnStateEntered, IOnStateExited { [Dependency] private readonly IClientPreferencesManager _preferencesManager = default!; - [Dependency] private readonly IStateManager _stateManager = default!; + [Dependency] private readonly IConfigurationManager _configurationManager = default!; + [Dependency] private readonly IFileDialogManager _dialogManager = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IResourceCache _resourceCache = default!; + [Dependency] private readonly IStateManager _stateManager = default!; + [Dependency] private readonly JobRequirementsManager _requirements = default!; + [Dependency] private readonly MarkingManager _markings = default!; [Dependency] private readonly JobRequirementsManager _jobRequirements = default!; [UISystemDependency] private readonly HumanoidAppearanceSystem _humanoid = default!; [UISystemDependency] private readonly ClientInventorySystem _inventory = default!; [UISystemDependency] private readonly LoadoutSystem _loadouts = default!; - private LobbyCharacterPanel? _previewPanel; + private CharacterSetupGui? _characterSetup; private HumanoidProfileEditor? _profileEditor; - /* - * Each character profile has its own dummy. There is also a dummy for the lobby screen + character editor - * that is shared too. - */ + /// This is the character preview panel in the chat. This should only update if their character updates + private LobbyCharacterPreviewPanel? PreviewPanel => GetLobbyPreview(); - /// - /// Preview dummy for role gear. - /// - private EntityUid? _previewDummy; + /// This is the modified profile currently being edited + private HumanoidCharacterProfile? EditedProfile => _profileEditor?.Profile; + private int? EditedSlot => _profileEditor?.CharacterSlot; - [Access(typeof(HumanoidProfileEditor))] - public bool UpdateClothes = true; - [Access(typeof(HumanoidProfileEditor))] - public bool ShowClothes = true; - [Access(typeof(HumanoidProfileEditor))] - public bool ShowLoadouts = true; - - // TODO: Load the species directly and don't update entity ever. - public event Action? PreviewDummyUpdated; public override void Initialize() { base.Initialize(); + _prototypeManager.PrototypesReloaded += OnPrototypesReloaded; _preferencesManager.OnServerDataLoaded += PreferencesDataLoaded; - } + _requirements.Updated += OnRequirementsUpdated; - private void PreferencesDataLoaded() - { - if (_previewDummy != null) - EntityManager.DeleteEntity(_previewDummy); + _configurationManager.OnValueChanged(CCVars.FlavorText, _ => _profileEditor?.RefreshFlavorText()); + _configurationManager.OnValueChanged(CCVars.GameRoleTimers, + _ => + { + _profileEditor?.RefreshAntags(); + _profileEditor?.RefreshJobs(); + }); - UpdateCharacterUI(); + _preferencesManager.OnServerDataLoaded += PreferencesDataLoaded; } public void OnStateEntered(LobbyState state) { + PreviewPanel?.SetLoaded(_preferencesManager.ServerDataLoaded); + ReloadCharacterSetup(); } public void OnStateExited(LobbyState state) { - EntityManager.DeleteEntity(_previewDummy); - _previewDummy = null; + PreviewPanel?.SetLoaded(false); + _characterSetup?.Dispose(); + _profileEditor?.Dispose(); + _characterSetup = null; + _profileEditor = null; } - public void SetPreviewPanel(LobbyCharacterPanel? panel) + + private void PreferencesDataLoaded() { - _previewPanel = panel; - UpdateCharacterUI(); + PreviewPanel?.SetLoaded(true); + + if (_stateManager.CurrentState is not LobbyState) + return; + + ReloadCharacterSetup(); } - public void SetProfileEditor(HumanoidProfileEditor? editor) + private LobbyCharacterPreviewPanel? GetLobbyPreview() { - _profileEditor = editor; - UpdateCharacterUI(); + return _stateManager.CurrentState is LobbyState lobby ? lobby.Lobby?.CharacterPreview : null; } - public void UpdateCharacterUI() + private void OnRequirementsUpdated() { - // Test moment - if (_stateManager.CurrentState is not LobbyState) + if (_profileEditor == null) return; - if (!_preferencesManager.ServerDataLoaded) - { - _previewPanel?.SetLoaded(false); + _profileEditor.RefreshAntags(); + _profileEditor.RefreshJobs(); + } + + private void OnPrototypesReloaded(PrototypesReloadedEventArgs obj) + { + if (_profileEditor == null) return; - } - var maybeProfile = _profileEditor?.Profile ?? (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter; + if (obj.WasModified()) + _profileEditor.RefreshSpecies(); + + if (obj.WasModified()) + _profileEditor.RefreshAntags(); + + if (obj.WasModified() + || obj.WasModified()) + _profileEditor.RefreshJobs(); + + if (obj.WasModified()) + _profileEditor.UpdateTraits(null, true); + + if (obj.WasModified()) + _profileEditor.UpdateLoadouts(null, true); + } + + + /// Reloads every single character setup control + public void ReloadCharacterSetup() + { + RefreshLobbyPreview(); + var (characterGui, profileEditor) = EnsureGui(); + characterGui.ReloadCharacterPickers(); + profileEditor.SetProfile( + (HumanoidCharacterProfile?) _preferencesManager.Preferences?.SelectedCharacter, + _preferencesManager.Preferences?.SelectedCharacterIndex); + } + + /// Refreshes the character preview in the lobby chat + private void RefreshLobbyPreview() + { + if (PreviewPanel == null) + return; - if (_previewDummy == null - || maybeProfile.Species != EntityManager.GetComponent(_previewDummy.Value).Species) + // Get selected character, load it, then set it + var character = _preferencesManager.Preferences?.SelectedCharacter; + + if (character is not HumanoidCharacterProfile humanoid) { - RespawnDummy(maybeProfile); - _previewPanel?.SetSprite(_previewDummy!.Value); + PreviewPanel.SetSprite(EntityUid.Invalid); + PreviewPanel.SetSummaryText(string.Empty); + return; } - _previewPanel?.SetLoaded(true); + var dummy = LoadProfileEntity(humanoid, true); + PreviewPanel.SetSprite(dummy); + PreviewPanel.SetSummaryText(humanoid.Summary); + } + + private void SaveProfile() + { + DebugTools.Assert(EditedProfile != null); - if (_previewDummy == null) + if (EditedProfile == null || EditedSlot == null) return; - _previewPanel?.SetSummaryText(maybeProfile.Summary); - _humanoid.LoadProfile(_previewDummy.Value, maybeProfile); + var selected = _preferencesManager.Preferences?.SelectedCharacterIndex; + if (selected == null) + return; + _preferencesManager.UpdateCharacter(EditedProfile, EditedSlot.Value); + ReloadCharacterSetup(); + } - if (UpdateClothes) + private (CharacterSetupGui, HumanoidProfileEditor) EnsureGui() + { + if (_characterSetup != null && _profileEditor != null) { - RemoveDummyClothes(_previewDummy.Value); - if (ShowClothes) - GiveDummyJobClothes(_previewDummy.Value, GetPreferredJob(maybeProfile), maybeProfile); - if (ShowLoadouts) - _loadouts.ApplyCharacterLoadout(_previewDummy.Value, GetPreferredJob(maybeProfile), maybeProfile, - _jobRequirements.GetRawPlayTimeTrackers(), _jobRequirements.IsWhitelisted()); - UpdateClothes = false; + _characterSetup.Visible = true; + _profileEditor.Visible = true; + return (_characterSetup, _profileEditor); } - PreviewDummyUpdated?.Invoke(_previewDummy.Value); - } + _profileEditor = new HumanoidProfileEditor( + _preferencesManager, + _configurationManager, + EntityManager, + _dialogManager, + _playerManager, + _prototypeManager, + _requirements, + _markings); + _characterSetup = new CharacterSetupGui(EntityManager, _prototypeManager, _resourceCache, _preferencesManager, _profileEditor); - public void RespawnDummy(HumanoidCharacterProfile profile) - { - if (_previewDummy != null) - RemoveDummyClothes(_previewDummy.Value); + _characterSetup.CloseButton.OnPressed += _ => + { + // Reset sliders etc. + _profileEditor.SetProfile(null, null); + _profileEditor.Visible = false; + if (_stateManager.CurrentState is LobbyState lobbyGui) + { + lobbyGui.SwitchState(LobbyGui.LobbyGuiState.Default); + } + }; + + _profileEditor.Save += SaveProfile; + + _characterSetup.SelectCharacter += args => + { + _preferencesManager.SelectCharacter(args); + ReloadCharacterSetup(); + }; + + _characterSetup.DeleteCharacter += args => + { + _preferencesManager.DeleteCharacter(args); - EntityManager.DeleteEntity(_previewDummy); - _previewDummy = EntityManager.SpawnEntity( - _prototypeManager.Index(profile.Species).DollPrototype, MapCoordinates.Nullspace); + if (EditedSlot == args) + // Reload everything + ReloadCharacterSetup(); + else + // Only need to reload character pickers + _characterSetup?.ReloadCharacterPickers(); + }; - UpdateClothes = true; + if (_stateManager.CurrentState is LobbyState lobby) + lobby.Lobby?.CharacterSetupState.AddChild(_characterSetup); + + return (_characterSetup, _profileEditor); } - /// - /// Gets the highest priority job for the profile. - /// + #region Helpers + + /// Gets the highest priority job for the profile. public JobPrototype GetPreferredJob(HumanoidCharacterProfile profile) { var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key; - // ReSharper disable once NullCoalescingConditionIsAlwaysNotNullAccordingToAPIContract (what is ReSharper smoking?) return _prototypeManager.Index(highPriorityJob ?? SharedGameTicker.FallbackOverflowJob); } @@ -166,9 +260,7 @@ public void RemoveDummyClothes(EntityUid dummy) EntityManager.DeleteEntity(unequippedItem.Value); } - /// - /// Applies the highest priority job's clothes and loadouts to the dummy. - /// + /// Applies the highest priority job's clothes and loadouts to the dummy. public void GiveDummyJobClothesLoadout(EntityUid dummy, HumanoidCharacterProfile profile) { var job = GetPreferredJob(profile); @@ -176,9 +268,7 @@ public void GiveDummyJobClothesLoadout(EntityUid dummy, HumanoidCharacterProfile _loadouts.ApplyCharacterLoadout(dummy, job, profile, _jobRequirements.GetRawPlayTimeTrackers(), _jobRequirements.IsWhitelisted()); } - /// - /// Applies the specified job's clothes to the dummy. - /// + /// Applies the specified job's clothes to the dummy. public void GiveDummyJobClothes(EntityUid dummy, JobPrototype job, HumanoidCharacterProfile profile) { if (!_inventory.TryGetSlots(dummy, out var slots) @@ -202,8 +292,28 @@ public void GiveDummyJobClothes(EntityUid dummy, JobPrototype job, HumanoidChara } } - public EntityUid? GetPreviewDummy() + /// Loads the profile onto a dummy entity + public EntityUid LoadProfileEntity(HumanoidCharacterProfile? humanoid, bool jobClothes) { - return _previewDummy; + EntityUid dummyEnt; + + if (humanoid is not null) + { + var dummy = _prototypeManager.Index(humanoid.Species).DollPrototype; + dummyEnt = EntityManager.SpawnEntity(dummy, MapCoordinates.Nullspace); + } + else + dummyEnt = EntityManager.SpawnEntity( + _prototypeManager.Index(DefaultSpecies).DollPrototype, + MapCoordinates.Nullspace); + + _humanoid.LoadProfile(dummyEnt, humanoid); + + if (humanoid != null && jobClothes) + GiveDummyJobClothesLoadout(dummyEnt, humanoid); + + return dummyEnt; } + + #endregion } diff --git a/Content.Client/Lobby/UI/CharacterPickerButton.xaml b/Content.Client/Lobby/UI/CharacterPickerButton.xaml new file mode 100644 index 00000000000..fa428b9b61f --- /dev/null +++ b/Content.Client/Lobby/UI/CharacterPickerButton.xaml @@ -0,0 +1,11 @@ + + + + + [GenerateTypedNameReferences] + public sealed partial class CharacterSetupGui : Control + { + private readonly IClientPreferencesManager _preferencesManager; + private readonly IEntityManager _entManager; + private readonly IPrototypeManager _protomanager; + + private readonly Button _createNewCharacterButton; + + public event Action? SelectCharacter; + public event Action? DeleteCharacter; + + public CharacterSetupGui( + IEntityManager entManager, + IPrototypeManager protoManager, + IResourceCache resourceCache, + IClientPreferencesManager preferencesManager, + HumanoidProfileEditor profileEditor) + { + RobustXamlLoader.Load(this); + _preferencesManager = preferencesManager; + _entManager = entManager; + _protomanager = protoManager; + + var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png"); + var back = new StyleBoxTexture + { + Texture = panelTex, + Modulate = new Color(37, 37, 42) + }; + back.SetPatchMargin(StyleBox.Margin.All, 10); + + BackgroundPanel.PanelOverride = back; + + _createNewCharacterButton = new Button + { + Text = Loc.GetString("character-setup-gui-create-new-character-button"), + }; + + _createNewCharacterButton.OnPressed += args => + { + preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random()); + ReloadCharacterPickers(); + args.Event.Handle(); + }; + + CharEditor.AddChild(profileEditor); + RulesButton.OnPressed += _ => new RulesAndInfoWindow().Open(); + + StatsButton.OnPressed += _ => new PlaytimeStatsWindow().OpenCentered(); + } + + /// + /// Disposes and reloads all character picker buttons from the preferences data. + /// + public void ReloadCharacterPickers() + { + _createNewCharacterButton.Orphan(); + Characters.DisposeAllChildren(); + + var numberOfFullSlots = 0; + var characterButtonsGroup = new ButtonGroup(); + + if (!_preferencesManager.ServerDataLoaded) + { + return; + } + + _createNewCharacterButton.ToolTip = + Loc.GetString("character-setup-gui-create-new-character-button-tooltip", + ("maxCharacters", _preferencesManager.Settings!.MaxCharacterSlots)); + + var selectedSlot = _preferencesManager.Preferences?.SelectedCharacterIndex; + + foreach (var (slot, character) in _preferencesManager.Preferences!.Characters) + { + numberOfFullSlots++; + var characterPickerButton = new CharacterPickerButton(_entManager, + _protomanager, + characterButtonsGroup, + character, + slot == selectedSlot); + + Characters.AddChild(characterPickerButton); + + characterPickerButton.OnPressed += args => + { + SelectCharacter?.Invoke(slot); + }; + + characterPickerButton.OnDeletePressed += () => + { + DeleteCharacter?.Invoke(slot); + }; + } + + _createNewCharacterButton.Disabled = numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots; + Characters.AddChild(_createNewCharacterButton); + } + } +} diff --git a/Content.Client/Preferences/UI/HighlightedContainer.xaml b/Content.Client/Lobby/UI/HighlightedContainer.xaml similarity index 100% rename from Content.Client/Preferences/UI/HighlightedContainer.xaml rename to Content.Client/Lobby/UI/HighlightedContainer.xaml diff --git a/Content.Client/Preferences/UI/HighlightedContainer.xaml.cs b/Content.Client/Lobby/UI/HighlightedContainer.xaml.cs similarity index 88% rename from Content.Client/Preferences/UI/HighlightedContainer.xaml.cs rename to Content.Client/Lobby/UI/HighlightedContainer.xaml.cs index 68294d0f059..084c1c37098 100644 --- a/Content.Client/Preferences/UI/HighlightedContainer.xaml.cs +++ b/Content.Client/Lobby/UI/HighlightedContainer.xaml.cs @@ -2,7 +2,7 @@ using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; -namespace Content.Client.Preferences.UI; +namespace Content.Client.Lobby.UI; [GenerateTypedNameReferences] public sealed partial class HighlightedContainer : PanelContainer diff --git a/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml new file mode 100644 index 00000000000..256e6d888d4 --- /dev/null +++ b/Content.Client/Lobby/UI/HumanoidProfileEditor.xaml @@ -0,0 +1,212 @@ + + + + + + + + + + + + + @@ -36,13 +52,13 @@ - + - + diff --git a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml.cs b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml.cs index 90732f814f8..2890bb3dbf7 100644 --- a/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml.cs +++ b/Content.Client/Xenoarchaeology/Ui/AnalysisConsoleMenu.xaml.cs @@ -3,6 +3,7 @@ using Content.Shared.Xenoarchaeology.Equipment; using Robust.Client.AutoGenerated; using Robust.Client.GameObjects; +using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -19,6 +20,8 @@ public sealed partial class AnalysisConsoleMenu : FancyWindow public event Action? OnScanButtonPressed; public event Action? OnPrintButtonPressed; public event Action? OnExtractButtonPressed; + public event Action? OnUpBiasButtonPressed; + public event Action? OnDownBiasButtonPressed; // For rendering the progress bar, updated from BUI state private TimeSpan? _startTime; @@ -36,6 +39,12 @@ public AnalysisConsoleMenu() ScanButton.OnPressed += _ => OnScanButtonPressed?.Invoke(); PrintButton.OnPressed += _ => OnPrintButtonPressed?.Invoke(); ExtractButton.OnPressed += _ => OnExtractButtonPressed?.Invoke(); + UpBiasButton.OnPressed += _ => OnUpBiasButtonPressed?.Invoke(); + DownBiasButton.OnPressed += _ => OnDownBiasButtonPressed?.Invoke(); + + var buttonGroup = new ButtonGroup(false); + UpBiasButton.Group = buttonGroup; + DownBiasButton.Group = buttonGroup; } protected override void FrameUpdate(FrameEventArgs args) @@ -60,25 +69,55 @@ protected override void FrameUpdate(FrameEventArgs args) ProgressBar.Value = Math.Clamp(1.0f - (float) remaining.Divide(total), 0.0f, 1.0f); } - public void SetButtonsDisabled(AnalysisConsoleScanUpdateState state) + public void SetButtonsDisabled(AnalysisConsoleUpdateState state) { ScanButton.Disabled = !state.CanScan; PrintButton.Disabled = !state.CanPrint; + if (state.IsTraversalDown) + DownBiasButton.Pressed = true; + else + UpBiasButton.Pressed = true; - var disabled = !state.ServerConnected || !state.CanScan || state.PointAmount <= 0; - - ExtractButton.Disabled = disabled; + ExtractButton.Disabled = false; + if (!state.ServerConnected) + { + ExtractButton.Disabled = true; + ExtractButton.ToolTip = Loc.GetString("analysis-console-no-server-connected"); + } + else if (!state.CanScan) + { + ExtractButton.Disabled = true; + + // CanScan can be false if either there's no analyzer connected or if there's + // no entity on the scanner. The `Information` text will always tell the user + // of the former case, but in the latter, it'll only show a message if a scan + // has never been performed, so add a tooltip to indicate that the artifact + // is gone. + if (state.AnalyzerConnected) + { + ExtractButton.ToolTip = Loc.GetString("analysis-console-no-artifact-placed"); + } + else + { + ExtractButton.ToolTip = null; + } + } + else if (state.PointAmount <= 0) + { + ExtractButton.Disabled = true; + ExtractButton.ToolTip = Loc.GetString("analysis-console-no-points-to-extract"); + } - if (disabled) + if (ExtractButton.Disabled) { ExtractButton.RemoveStyleClass("ButtonColorGreen"); } else { ExtractButton.AddStyleClass("ButtonColorGreen"); + ExtractButton.ToolTip = null; } } - private void UpdateArtifactIcon(EntityUid? uid) { if (uid == null) @@ -91,7 +130,7 @@ private void UpdateArtifactIcon(EntityUid? uid) ArtifactDisplay.SetEntity(uid); } - public void UpdateInformationDisplay(AnalysisConsoleScanUpdateState state) + public void UpdateInformationDisplay(AnalysisConsoleUpdateState state) { var message = new FormattedMessage(); @@ -129,7 +168,7 @@ public void UpdateInformationDisplay(AnalysisConsoleScanUpdateState state) Information.SetMessage(message); } - public void UpdateProgressBar(AnalysisConsoleScanUpdateState state) + public void UpdateProgressBar(AnalysisConsoleUpdateState state) { ProgressBar.Visible = state.Scanning; ProgressLabel.Visible = state.Scanning; diff --git a/Content.IntegrationTests/Pair/TestPair.Recycle.cs b/Content.IntegrationTests/Pair/TestPair.Recycle.cs index 52fdf600bb4..c0f4b3b745f 100644 --- a/Content.IntegrationTests/Pair/TestPair.Recycle.cs +++ b/Content.IntegrationTests/Pair/TestPair.Recycle.cs @@ -131,7 +131,7 @@ public async Task CleanPooledPair(PoolSettings settings, TextWriter testOut) // Move to pre-round lobby. Required to toggle dummy ticker on and off if (gameTicker.RunLevel != GameRunLevel.PreRoundLobby) { - await testOut.WriteLineAsync($"Recycling: {Watch.Elapsed.TotalMilliseconds} ms: Restarting server."); + await testOut.WriteLineAsync($"Recycling: {Watch.Elapsed.TotalMilliseconds} ms: Restarting round."); Assert.That(gameTicker.DummyTicker, Is.False); Server.CfgMan.SetCVar(CCVars.GameLobbyEnabled, true); await Server.WaitPost(() => gameTicker.RestartRound()); @@ -146,6 +146,7 @@ public async Task CleanPooledPair(PoolSettings settings, TextWriter testOut) // Restart server. await testOut.WriteLineAsync($"Recycling: {Watch.Elapsed.TotalMilliseconds} ms: Restarting server again"); + await Server.WaitPost(() => Server.EntMan.FlushEntities()); await Server.WaitPost(() => gameTicker.RestartRound()); await RunTicksSync(1); diff --git a/Content.IntegrationTests/Pair/TestPair.Timing.cs b/Content.IntegrationTests/Pair/TestPair.Timing.cs index 3487ea68010..e0859660d42 100644 --- a/Content.IntegrationTests/Pair/TestPair.Timing.cs +++ b/Content.IntegrationTests/Pair/TestPair.Timing.cs @@ -1,5 +1,4 @@ #nullable enable -using Robust.Shared.Timing; namespace Content.IntegrationTests.Pair; @@ -19,6 +18,22 @@ public async Task RunTicksSync(int ticks) } } + /// + /// Convert a time interval to some number of ticks. + /// + public int SecondsToTicks(float seconds) + { + return (int) Math.Ceiling(seconds / Server.Timing.TickPeriod.TotalSeconds); + } + + /// + /// Run the server & client in sync for some amount of time + /// + public async Task RunSeconds(float seconds) + { + await RunTicksSync(SecondsToTicks(seconds)); + } + /// /// Runs the server-client pair in sync, but also ensures they are both idle each tick. /// @@ -59,4 +74,4 @@ public async Task SyncTicks(int targetDelta = 1) delta = cTick - sTick; Assert.That(delta, Is.EqualTo(targetDelta)); } -} \ No newline at end of file +} diff --git a/Content.IntegrationTests/PoolManager.Cvars.cs b/Content.IntegrationTests/PoolManager.Cvars.cs index 327ec627f52..aa6b4dffdcc 100644 --- a/Content.IntegrationTests/PoolManager.Cvars.cs +++ b/Content.IntegrationTests/PoolManager.Cvars.cs @@ -22,6 +22,7 @@ private static readonly (string cvar, string value)[] TestCvars = (CVars.ThreadParallelCount.Name, "1"), (CCVars.GameRoleTimers.Name, "false"), (CCVars.GridFill.Name, "false"), + (CCVars.PreloadGrids.Name, "false"), (CCVars.ArrivalsShuttles.Name, "false"), (CCVars.EmergencyShuttleEnabled.Name, "false"), (CCVars.ProcgenPreload.Name, "false"), @@ -32,6 +33,7 @@ private static readonly (string cvar, string value)[] TestCvars = (CCVars.GameLobbyEnabled.Name, "false"), (CCVars.ConfigPresetDevelopment.Name, "false"), (CCVars.AdminLogsEnabled.Name, "false"), + (CCVars.AutosaveEnabled.Name, "false"), (CVars.NetBufferSize.Name, "0") }; diff --git a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs index 16744d83dce..c40b8ed286f 100644 --- a/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs +++ b/Content.IntegrationTests/Tests/Damageable/DamageableTest.cs @@ -19,36 +19,45 @@ public sealed class DamageableTest # Define some damage groups - type: damageType id: TestDamage1 + name: damage-type-blunt - type: damageType id: TestDamage2a + name: damage-type-blunt - type: damageType id: TestDamage2b + name: damage-type-blunt - type: damageType id: TestDamage3a + name: damage-type-blunt - type: damageType id: TestDamage3b + name: damage-type-blunt - type: damageType id: TestDamage3c + name: damage-type-blunt # Define damage Groups with 1,2,3 damage types - type: damageGroup id: TestGroup1 + name: damage-group-brute damageTypes: - TestDamage1 - type: damageGroup id: TestGroup2 + name: damage-group-brute damageTypes: - TestDamage2a - TestDamage2b - type: damageGroup id: TestGroup3 + name: damage-group-brute damageTypes: - TestDamage3a - TestDamage3b diff --git a/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs b/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs index 12292f4652d..7ff92423984 100644 --- a/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs +++ b/Content.IntegrationTests/Tests/Destructible/DestructibleTestPrototypes.cs @@ -12,24 +12,31 @@ public static class DestructibleTestPrototypes public const string DamagePrototypes = $@" - type: damageType id: TestBlunt + name: damage-type-blunt - type: damageType id: TestSlash + name: damage-type-slash - type: damageType id: TestPiercing + name: damage-type-piercing - type: damageType id: TestHeat + name: damage-type-heat - type: damageType id: TestShock + name: damage-type-shock - type: damageType id: TestCold + name: damage-type-cold - type: damageGroup id: TestBrute + name: damage-group-brute damageTypes: - TestBlunt - TestSlash @@ -37,6 +44,7 @@ public static class DestructibleTestPrototypes - type: damageGroup id: TestBurn + name: damage-group-burn damageTypes: - TestHeat - TestShock diff --git a/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs b/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs index d47eb13273f..0ebd17d8879 100644 --- a/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs +++ b/Content.IntegrationTests/Tests/DoAfter/DoAfterCancellationTests.cs @@ -3,8 +3,6 @@ using Content.IntegrationTests.Tests.Interaction; using Content.IntegrationTests.Tests.Weldable; using Content.Shared.Tools.Components; -using Content.Server.Tools.Components; -using Content.Shared.DoAfter; namespace Content.IntegrationTests.Tests.DoAfter; diff --git a/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs new file mode 100644 index 00000000000..1fed226beee --- /dev/null +++ b/Content.IntegrationTests/Tests/GameRules/FailAndStartPresetTest.cs @@ -0,0 +1,152 @@ +#nullable enable +using Content.Server.GameTicking; +using Content.Server.GameTicking.Components; +using Content.Server.GameTicking.Presets; +using Content.Shared.CCVar; +using Content.Shared.GameTicking; +using Robust.Shared.GameObjects; + +namespace Content.IntegrationTests.Tests.GameRules; + +[TestFixture] +public sealed class FailAndStartPresetTest +{ + [TestPrototypes] + private const string Prototypes = @" +- type: gamePreset + id: TestPreset + alias: + - nukeops + name: Test Preset + description: """" + showInVote: false + rules: + - TestRule + +- type: gamePreset + id: TestPresetTenPlayers + alias: + - nukeops + name: Test Preset 10 players + description: """" + showInVote: false + rules: + - TestRuleTenPlayers + +- type: entity + id: TestRule + parent: BaseGameRule + noSpawn: true + components: + - type: GameRule + minPlayers: 0 + - type: TestRule + +- type: entity + id: TestRuleTenPlayers + parent: BaseGameRule + noSpawn: true + components: + - type: GameRule + minPlayers: 10 + - type: TestRule +"; + + /// + /// Test that a nuke ops gamemode can start after failing to start once. + /// + [Test] + public async Task FailAndStartTest() + { + await using var pair = await PoolManager.GetServerClient(new PoolSettings + { + Dirty = true, + DummyTicker = false, + Connected = true, + InLobby = true + }); + + var server = pair.Server; + var client = pair.Client; + var entMan = server.EntMan; + var ticker = server.System(); + server.System().Run = true; + + Assert.That(server.CfgMan.GetCVar(CCVars.GridFill), Is.False); + Assert.That(server.CfgMan.GetCVar(CCVars.GameLobbyFallbackEnabled), Is.True); + Assert.That(server.CfgMan.GetCVar(CCVars.GameLobbyDefaultPreset), Is.EqualTo("secret")); + server.CfgMan.SetCVar(CCVars.GridFill, true); + server.CfgMan.SetCVar(CCVars.GameLobbyFallbackEnabled, false); + server.CfgMan.SetCVar(CCVars.GameLobbyDefaultPreset, "TestPreset"); + + // Initially in the lobby + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); + Assert.That(client.AttachedEntity, Is.Null); + Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay)); + + // Try to start nukeops without readying up + await pair.WaitCommand("setgamepreset TestPresetTenPlayers"); + await pair.WaitCommand("startround"); + await pair.RunTicksSync(10); + + // Game should not have started + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); + Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.NotReadyToPlay)); + Assert.That(!client.EntMan.EntityExists(client.AttachedEntity)); + var player = pair.Player!.AttachedEntity; + Assert.That(!entMan.EntityExists(player)); + + // Ready up and start nukeops + await pair.WaitClientCommand("toggleready True"); + Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.ReadyToPlay)); + await pair.WaitCommand("setgamepreset TestPreset"); + await pair.WaitCommand("startround"); + await pair.RunTicksSync(10); + + // Game should have started + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.InRound)); + Assert.That(ticker.PlayerGameStatuses[client.User!.Value], Is.EqualTo(PlayerGameStatus.JoinedGame)); + Assert.That(client.EntMan.EntityExists(client.AttachedEntity)); + player = pair.Player!.AttachedEntity!.Value; + Assert.That(entMan.EntityExists(player)); + + ticker.SetGamePreset((GamePresetPrototype?)null); + server.CfgMan.SetCVar(CCVars.GridFill, false); + server.CfgMan.SetCVar(CCVars.GameLobbyFallbackEnabled, true); + server.CfgMan.SetCVar(CCVars.GameLobbyDefaultPreset, "secret"); + server.System().Run = false; + await pair.CleanReturnAsync(); + } +} + +public sealed class TestRuleSystem : EntitySystem +{ + public bool Run; + + public override void Initialize() + { + SubscribeLocalEvent(OnRoundStartAttempt); + } + + private void OnRoundStartAttempt(RoundStartAttemptEvent args) + { + if (!Run) + return; + + if (args.Forced || args.Cancelled) + return; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out _, out _, out var gameRule)) + { + var minPlayers = gameRule.MinPlayers; + if (args.Players.Length >= minPlayers) + continue; + + args.Cancel(); + } + } +} + +[RegisterComponent] +public sealed partial class TestRuleComponent : Component; diff --git a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs index 62fa93c9997..822f7967cfd 100644 --- a/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/NukeOpsTest.cs @@ -18,6 +18,7 @@ using Content.Shared.GameTicking; using Content.Shared.Hands.Components; using Content.Shared.Inventory; +using Content.Shared.NPC.Systems; using Content.Shared.NukeOps; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; @@ -125,8 +126,14 @@ public async Task TryStopNukeOpsFromConstantlyFailing() Assert.That(entMan.HasComponent(grid)); Assert.That(entMan.HasComponent(grid)); } + Assert.That(entMan.EntityExists(rule.NukieOutpost)); + Assert.That(entMan.EntityExists(rule.NukieShuttle)); Assert.That(entMan.EntityExists(rule.TargetStation)); + Assert.That(entMan.HasComponent(rule.NukieOutpost)); + Assert.That(entMan.HasComponent(rule.NukieShuttle)); + + Assert.That(entMan.HasComponent(rule.NukieOutpost)); Assert.That(entMan.HasComponent(rule.TargetStation)); var nukieShuttlEnt = entMan.AllComponents().FirstOrDefault().Uid; @@ -145,11 +152,14 @@ public async Task TryStopNukeOpsFromConstantlyFailing() Assert.That(entMan.EntityExists(nukieStationEnt)); var nukieStation = entMan.GetComponent(nukieStationEnt!.Value); + var nukieStation = entMan.GetComponent(rule.NukieOutpost!.Value); Assert.That(entMan.EntityExists(nukieStation.Station)); Assert.That(nukieStation.Station, Is.Not.EqualTo(rule.TargetStation)); Assert.That(server.MapMan.MapExists(mapRule.Map)); var nukieMap = mapSys.GetMap(mapRule.Map!.Value); + Assert.That(server.MapMan.MapExists(rule.NukiePlanet)); + var nukieMap = mapSys.GetMap(rule.NukiePlanet!.Value); var targetStation = entMan.GetComponent(rule.TargetStation!.Value); var targetGrid = targetStation.Grids.First(); @@ -159,6 +169,8 @@ public async Task TryStopNukeOpsFromConstantlyFailing() Assert.That(entMan.GetComponent(player).MapUid, Is.EqualTo(nukieMap)); Assert.That(entMan.GetComponent(nukieStationEnt.Value).MapUid, Is.EqualTo(nukieMap)); Assert.That(entMan.GetComponent(nukieShuttlEnt).MapUid, Is.EqualTo(nukieMap)); + Assert.That(entMan.GetComponent(rule.NukieOutpost!.Value).MapUid, Is.EqualTo(nukieMap)); + Assert.That(entMan.GetComponent(rule.NukieShuttle!.Value).MapUid, Is.EqualTo(nukieMap)); // The maps are all map-initialized, including the player // Yes, this is necessary as this has repeatedly been broken somehow. @@ -173,6 +185,8 @@ public async Task TryStopNukeOpsFromConstantlyFailing() Assert.That(LifeStage(targetMap), Is.GreaterThan(EntityLifeStage.Initialized)); Assert.That(LifeStage(nukieStationEnt.Value), Is.GreaterThan(EntityLifeStage.Initialized)); Assert.That(LifeStage(nukieShuttlEnt), Is.GreaterThan(EntityLifeStage.Initialized)); + Assert.That(LifeStage(rule.NukieOutpost), Is.GreaterThan(EntityLifeStage.Initialized)); + Assert.That(LifeStage(rule.NukieShuttle), Is.GreaterThan(EntityLifeStage.Initialized)); Assert.That(LifeStage(rule.TargetStation), Is.GreaterThan(EntityLifeStage.Initialized)); // Make sure the player has hands. We've had fucking disarmed nukies before. diff --git a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs index ffaff3b8ded..20a157e33e8 100644 --- a/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs +++ b/Content.IntegrationTests/Tests/GameRules/RuleMaxTimeRestartTest.cs @@ -20,6 +20,9 @@ public async Task RestartTest() await using var pair = await PoolManager.GetServerClient(new PoolSettings { InLobby = true }); var server = pair.Server; + Assert.That(server.EntMan.Count(), Is.Zero); + Assert.That(server.EntMan.Count(), Is.Zero); + var entityManager = server.ResolveDependency(); var sGameTicker = server.ResolveDependency().GetEntitySystem(); var sGameTiming = server.ResolveDependency(); @@ -27,6 +30,9 @@ public async Task RestartTest() sGameTicker.StartGameRule("MaxTimeRestart", out var ruleEntity); Assert.That(entityManager.TryGetComponent(ruleEntity, out var maxTime)); + Assert.That(server.EntMan.Count(), Is.EqualTo(1)); + Assert.That(server.EntMan.Count(), Is.EqualTo(1)); + await server.WaitAssertion(() => { Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.PreRoundLobby)); @@ -34,6 +40,9 @@ await server.WaitAssertion(() => sGameTicker.StartRound(); }); + Assert.That(server.EntMan.Count(), Is.EqualTo(1)); + Assert.That(server.EntMan.Count(), Is.EqualTo(1)); + await server.WaitAssertion(() => { Assert.That(sGameTicker.RunLevel, Is.EqualTo(GameRunLevel.InRound)); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs index 414cf4bb56f..37dca721373 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifier.cs @@ -3,6 +3,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; +using static Robust.UnitTesting.RobustIntegrationTest; namespace Content.IntegrationTests.Tests.Interaction; @@ -54,7 +55,7 @@ public static implicit operator EntitySpecifier((string, int) tuple) /// /// Convert applicable entity prototypes into stack prototypes. /// - public void ConvertToStack(IPrototypeManager protoMan, IComponentFactory factory) + public async Task ConvertToStack(IPrototypeManager protoMan, IComponentFactory factory, ServerIntegrationInstance server) { if (Converted) return; @@ -73,11 +74,14 @@ public void ConvertToStack(IPrototypeManager protoMan, IComponentFactory factory return; } - if (entProto.TryGetComponent(factory.GetComponentName(typeof(StackComponent)), - out var stackComp)) + StackComponent? stack = null; + await server.WaitPost(() => { - Prototype = stackComp.StackTypeId; - } + entProto.TryGetComponent(factory.GetComponentName(typeof(StackComponent)), out stack); + }); + + if (stack != null) + Prototype = stack.StackTypeId; } } @@ -100,11 +104,14 @@ await Server.WaitPost(() => return default; } - if (entProto.TryGetComponent(Factory.GetComponentName(typeof(StackComponent)), - out var stackComp)) + StackComponent? stack = null; + await Server.WaitPost(() => { - return await SpawnEntity((stackComp.StackTypeId, spec.Quantity), coords); - } + entProto.TryGetComponent(Factory.GetComponentName(typeof(StackComponent)), out stack); + }); + + if (stack != null) + return await SpawnEntity((stack.StackTypeId, spec.Quantity), coords); Assert.That(spec.Quantity, Is.EqualTo(1), "SpawnEntity only supports returning a singular entity"); await Server.WaitPost(() => uid = SEntMan.SpawnEntity(spec.Prototype, coords)); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifierCollection.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifierCollection.cs index 520d2699c14..7f7de3318b4 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifierCollection.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.EntitySpecifierCollection.cs @@ -5,6 +5,7 @@ using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Utility; +using static Robust.UnitTesting.RobustIntegrationTest; namespace Content.IntegrationTests.Tests.Interaction; @@ -111,7 +112,7 @@ public EntitySpecifierCollection Clone() /// /// Convert applicable entity prototypes into stack prototypes. /// - public void ConvertToStacks(IPrototypeManager protoMan, IComponentFactory factory) + public async Task ConvertToStacks(IPrototypeManager protoMan, IComponentFactory factory, ServerIntegrationInstance server) { if (Converted) return; @@ -130,14 +131,17 @@ public void ConvertToStacks(IPrototypeManager protoMan, IComponentFactory factor continue; } - if (!entProto.TryGetComponent(factory.GetComponentName(typeof(StackComponent)), - out var stackComp)) + StackComponent? stack = null; + await server.WaitPost(() => { + entProto.TryGetComponent(factory.GetComponentName(typeof(StackComponent)), out stack); + }); + + if (stack == null) continue; - } toRemove.Add(id); - toAdd.Add((stackComp.StackTypeId, quantity)); + toAdd.Add((stack.StackTypeId, quantity)); } foreach (var id in toRemove) diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs index 480fd9cde6f..19ca83a9715 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.Helpers.cs @@ -5,12 +5,9 @@ using System.Numerics; using System.Reflection; using Content.Client.Construction; -using Content.Server.Atmos; -using Content.Server.Atmos.Components; using Content.Server.Atmos.EntitySystems; using Content.Server.Construction.Components; using Content.Server.Gravity; -using Content.Server.Item; using Content.Server.Power.Components; using Content.Shared.Atmos; using Content.Shared.Construction.Prototypes; @@ -634,7 +631,7 @@ protected async Task AssertEntityLookup( var entities = await DoEntityLookup(flags); var found = ToEntityCollection(entities); expected.Remove(found); - expected.ConvertToStacks(ProtoMan, Factory); + await expected.ConvertToStacks(ProtoMan, Factory, Server); if (expected.Entities.Count == 0) return; @@ -670,7 +667,7 @@ protected async Task FindEntity( LookupFlags flags = LookupFlags.Uncontained | LookupFlags.Contained, bool shouldSucceed = true) { - spec.ConvertToStack(ProtoMan, Factory); + await spec.ConvertToStack(ProtoMan, Factory, Server); var entities = await DoEntityLookup(flags); foreach (var uid in entities) @@ -767,14 +764,9 @@ protected async Task RunTicks(int ticks) await Pair.RunTicksSync(ticks); } - protected int SecondsToTicks(float seconds) - { - return (int) Math.Ceiling(seconds / TickPeriod); - } - protected async Task RunSeconds(float seconds) { - await RunTicks(SecondsToTicks(seconds)); + await Pair.RunSeconds(seconds); } #endregion @@ -825,7 +817,7 @@ protected bool TryGetBui(Enum key, [NotNullWhen(true)] out BoundUserInterface? b return false; } - if (!ui.OpenInterfaces.TryGetValue(key, out bui)) + if (!ui.ClientOpenInterfaces.TryGetValue(key, out bui)) { if (shouldSucceed) Assert.Fail($"Entity {SEntMan.ToPrettyString(SEntMan.GetEntity(target.Value))} does not have an open bui with key {key.GetType()}.{key}."); diff --git a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs index a4ed31e9983..42f64b344cd 100644 --- a/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs +++ b/Content.IntegrationTests/Tests/Interaction/InteractionTest.cs @@ -12,7 +12,6 @@ using Content.Shared.DoAfter; using Content.Shared.Hands.Components; using Content.Shared.Interaction; -using Content.Server.Item; using Content.Shared.Mind; using Content.Shared.Players; using Robust.Client.Input; diff --git a/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs b/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs index 4abe2839fba..60501a781fc 100644 --- a/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs +++ b/Content.IntegrationTests/Tests/Lobby/CharacterCreationTest.cs @@ -1,5 +1,4 @@ using Content.Client.Lobby; -using Content.Client.Preferences; using Content.Server.Preferences.Managers; using Content.Shared.Preferences; using Robust.Client.State; diff --git a/Content.IntegrationTests/Tests/Mapping/MappingTests.cs b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs new file mode 100644 index 00000000000..287e30eb8b1 --- /dev/null +++ b/Content.IntegrationTests/Tests/Mapping/MappingTests.cs @@ -0,0 +1,102 @@ +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Mapping; + +[TestFixture] +public sealed class MappingTests +{ + /// + /// Checks that the mapping command creates paused & uninitialized maps. + /// + [Test] + public async Task MappingTest() + { + await using var pair = await PoolManager.GetServerClient(new PoolSettings {Dirty = true, Connected = true, DummyTicker = false}); + + var server = pair.Server; + var entMan = server.EntMan; + var mapSys = server.System(); + + await pair.RunTicksSync(5); + var mapId = 1; + while (mapSys.MapExists(new(mapId))) + { + mapId++; + } + + await pair.WaitClientCommand($"mapping {mapId}"); + var map = mapSys.GetMap(new MapId(mapId)); + + var mapXform = server.Transform(map); + Assert.That(mapXform.MapUid, Is.EqualTo(map)); + Assert.That(mapXform.MapID, Is.EqualTo(new MapId(mapId))); + + var xform = server.Transform(pair.Player!.AttachedEntity!.Value); + + Assert.That(xform.MapUid, Is.EqualTo(map)); + Assert.That(mapSys.IsInitialized(map), Is.False); + Assert.That(mapSys.IsPaused(map), Is.True); + Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized)); + Assert.That(server.MetaData(map).EntityPaused, Is.True); + + // Spawn a new entity + EntityUid ent = default; + await server.WaitPost(() => + { + ent = entMan.Spawn(null, new MapCoordinates(default, new(mapId))); + }); + await pair.RunTicksSync(5); + Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized)); + Assert.That(server.MetaData(ent).EntityPaused, Is.True); + + // Save the map + var file = $"{nameof(MappingTest)}.yml"; + await pair.WaitClientCommand($"savemap {mapId} {file}"); + + // Mapinitialize it + await pair.WaitClientCommand($"mapinit {mapId}"); + Assert.That(mapSys.IsInitialized(map), Is.True); + Assert.That(mapSys.IsPaused(map), Is.False); + Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(server.MetaData(map).EntityPaused, Is.False); + Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(server.MetaData(ent).EntityPaused, Is.False); + + await server.WaitPost(() => entMan.DeleteEntity(map)); + + // Load the saved map + mapId++; + while (mapSys.MapExists(new(mapId))) + { + mapId++; + } + + await pair.WaitClientCommand($"mapping {mapId} {file}"); + map = mapSys.GetMap(new MapId(mapId)); + + // And it should all be paused and un-initialized + xform = server.Transform(pair.Player!.AttachedEntity!.Value); + Assert.That(xform.MapUid, Is.EqualTo(map)); + Assert.That(mapSys.IsInitialized(map), Is.False); + Assert.That(mapSys.IsPaused(map), Is.True); + Assert.That(server.MetaData(map).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized)); + Assert.That(server.MetaData(map).EntityPaused, Is.True); + + mapXform = server.Transform(map); + Assert.That(mapXform.MapUid, Is.EqualTo(map)); + Assert.That(mapXform.MapID, Is.EqualTo(new MapId(mapId))); + Assert.That(mapXform.ChildCount, Is.EqualTo(2)); + + mapXform.ChildEnumerator.MoveNext(out ent); + if (ent == pair.Player.AttachedEntity) + mapXform.ChildEnumerator.MoveNext(out ent); + + Assert.That(server.MetaData(ent).EntityLifeStage, Is.EqualTo(EntityLifeStage.Initialized)); + Assert.That(server.MetaData(ent).EntityPaused, Is.True); + + await server.WaitPost(() => entMan.DeleteEntity(map)); + await pair.CleanReturnAsync(); + } +} diff --git a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs index a2faef0dd4d..7f9c02fc13b 100644 --- a/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs +++ b/Content.IntegrationTests/Tests/MaterialArbitrageTest.cs @@ -1,22 +1,23 @@ +using System.Collections.Generic; using Content.Server.Cargo.Systems; using Content.Server.Construction.Completions; using Content.Server.Construction.Components; using Content.Server.Destructible; using Content.Server.Destructible.Thresholds.Behaviors; using Content.Server.Stack; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Construction.Components; using Content.Shared.Construction.Prototypes; using Content.Shared.Construction.Steps; +using Content.Shared.FixedPoint; using Content.Shared.Lathe; +using Content.Shared.Materials; using Content.Shared.Research.Prototypes; using Content.Shared.Stacks; using Robust.Shared.GameObjects; using Robust.Shared.Map; using Robust.Shared.Prototypes; -using System.Collections.Generic; -using Content.Shared.Chemistry.Reagent; -using Content.Shared.Construction.Components; -using Content.Shared.FixedPoint; -using Content.Shared.Materials; +using Robust.Shared.Utility; namespace Content.IntegrationTests.Tests; @@ -52,10 +53,10 @@ public async Task NoMaterialArbitrage() var destructibleName = compFact.GetComponentName(typeof(DestructibleComponent)); // construct inverted lathe recipe dictionary - Dictionary latheRecipes = new(); + Dictionary> latheRecipes = new(); foreach (var proto in protoManager.EnumeratePrototypes()) { - latheRecipes.Add(proto.Result, proto); + latheRecipes.GetOrNew(proto.Result).Add(proto); } // Lets assume the possible lathe for resource multipliers: @@ -183,16 +184,19 @@ public async Task NoMaterialArbitrage() var spawnedPrice = await GetSpawnedPrice(spawnedEnts); var price = await GetPrice(id); if (spawnedPrice > 0 && price > 0) - Assert.That(spawnedPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after being destroyed"); + Assert.That(spawnedPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after being destroyed\nEntities spawned on destruction: {string.Join(',', spawnedEnts)}"); // Check lathe production - if (latheRecipes.TryGetValue(id, out var recipe)) + if (latheRecipes.TryGetValue(id, out var recipes)) { - foreach (var (matId, amount) in recipe.RequiredMaterials) + foreach (var recipe in recipes) { - var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); - if (spawnedMats.TryGetValue(matId, out var numSpawned)) - Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"destroying a {id} spawns more {matId} than required to produce via an (upgraded) lathe."); + foreach (var (matId, amount) in recipe.RequiredMaterials) + { + var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); + if (spawnedMats.TryGetValue(matId, out var numSpawned)) + Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"destroying a {id} spawns more {matId} than required to produce via an (upgraded) lathe."); + } } } @@ -263,13 +267,16 @@ public async Task NoMaterialArbitrage() Assert.That(deconstructedPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after being deconstructed"); // Check lathe production - if (latheRecipes.TryGetValue(id, out var recipe)) + if (latheRecipes.TryGetValue(id, out var recipes)) { - foreach (var (matId, amount) in recipe.RequiredMaterials) + foreach (var recipe in recipes) { - var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); - if (deconstructedMats.TryGetValue(matId, out var numSpawned)) - Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"deconstructing {id} spawns more {matId} than required to produce via an (upgraded) lathe."); + foreach (var (matId, amount) in recipe.RequiredMaterials) + { + var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); + if (deconstructedMats.TryGetValue(matId, out var numSpawned)) + Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"deconstructing {id} spawns more {matId} than required to produce via an (upgraded) lathe."); + } } } @@ -315,13 +322,16 @@ public async Task NoMaterialArbitrage() Assert.That(sumPrice, Is.LessThanOrEqualTo(price), $"{id} increases in price after decomposed into raw materials"); // Check lathe production - if (latheRecipes.TryGetValue(id, out var recipe)) + if (latheRecipes.TryGetValue(id, out var recipes)) { - foreach (var (matId, amount) in recipe.RequiredMaterials) + foreach (var recipe in recipes) { - var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); - if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned)) - Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"The physical composition of {id} has more {matId} than required to produce via an (upgraded) lathe."); + foreach (var (matId, amount) in recipe.RequiredMaterials) + { + var actualAmount = SharedLatheSystem.AdjustMaterial(amount, recipe.ApplyMaterialDiscount, multiplier); + if (compositionComponent.MaterialComposition.TryGetValue(matId, out var numSpawned)) + Assert.That(numSpawned, Is.LessThanOrEqualTo(actualAmount), $"The physical composition of {id} has more {matId} than required to produce via an (upgraded) lathe."); + } } } @@ -359,7 +369,7 @@ await server.WaitPost(() => { var ent = entManager.SpawnEntity(id, testMap.GridCoords); stackSys.SetCount(ent, 1); - priceCache[id] = price = pricing.GetPrice(ent); + priceCache[id] = price = pricing.GetPrice(ent, false); entManager.DeleteEntity(ent); }); } diff --git a/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs b/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs index ca97e435a7f..150bc951f8c 100644 --- a/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs +++ b/Content.IntegrationTests/Tests/Minds/GhostRoleTests.cs @@ -1,5 +1,6 @@ #nullable enable using System.Linq; +using Content.IntegrationTests.Pair; using Content.Server.Ghost.Roles; using Content.Server.Ghost.Roles.Components; using Content.Server.Players; @@ -26,7 +27,7 @@ public sealed class GhostRoleTests "; /// - /// This is a simple test that just checks if a player can take a ghost roll and then regain control of their + /// This is a simple test that just checks if a player can take a ghost role and then regain control of their /// original entity without encountering errors. /// [Test] @@ -34,12 +35,15 @@ public async Task TakeRoleAndReturn() { await using var pair = await PoolManager.GetServerClient(new PoolSettings { + Dirty = true, DummyTicker = false, Connected = true }); var server = pair.Server; var client = pair.Client; + var mapData = await pair.CreateTestMap(); + var entMan = server.ResolveDependency(); var sPlayerMan = server.ResolveDependency(); var conHost = client.ResolveDependency(); @@ -51,7 +55,7 @@ public async Task TakeRoleAndReturn() EntityUid originalMob = default; await server.WaitPost(() => { - originalMob = entMan.SpawnEntity(null, MapCoordinates.Nullspace); + originalMob = entMan.SpawnEntity(null, mapData.GridCoords); mindSystem.TransferTo(originalMindId, originalMob, true); }); @@ -69,12 +73,12 @@ await server.WaitPost(() => Assert.That(entMan.HasComponent(ghost)); Assert.That(ghost, Is.Not.EqualTo(originalMob)); Assert.That(session.ContentData()?.Mind, Is.EqualTo(originalMindId)); - Assert.That(originalMind.OwnedEntity, Is.EqualTo(originalMob)); + Assert.That(originalMind.OwnedEntity, Is.EqualTo(originalMob), $"Original mob: {originalMob}, Ghost: {ghost}"); Assert.That(originalMind.VisitingEntity, Is.EqualTo(ghost)); // Spawn ghost takeover entity. EntityUid ghostRole = default; - await server.WaitPost(() => ghostRole = entMan.SpawnEntity("GhostRoleTestEntity", MapCoordinates.Nullspace)); + await server.WaitPost(() => ghostRole = entMan.SpawnEntity("GhostRoleTestEntity", mapData.GridCoords)); // Take the ghost role await server.WaitPost(() => diff --git a/Content.IntegrationTests/Tests/Minds/GhostTests.cs b/Content.IntegrationTests/Tests/Minds/GhostTests.cs new file mode 100644 index 00000000000..ad9d53a70db --- /dev/null +++ b/Content.IntegrationTests/Tests/Minds/GhostTests.cs @@ -0,0 +1,159 @@ +using System.Numerics; +using Content.IntegrationTests.Pair; +using Content.Shared.Ghost; +using Content.Shared.Mind; +using Content.Shared.Players; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; +using Robust.Shared.Player; +using Robust.UnitTesting; + +namespace Content.IntegrationTests.Tests.Minds; + +[TestFixture] +public sealed class GhostTests +{ + struct GhostTestData + { + public IEntityManager SEntMan; + public Robust.Server.Player.IPlayerManager SPlayerMan; + public Server.Mind.MindSystem SMindSys; + public SharedTransformSystem STransformSys = default!; + + public TestPair Pair = default!; + + public TestMapData MapData => Pair.TestMap!; + + public RobustIntegrationTest.ServerIntegrationInstance Server => Pair.Server; + public RobustIntegrationTest.ClientIntegrationInstance Client => Pair.Client; + + /// + /// Initial player coordinates. Note that this does not necessarily correspond to the position of the + /// entity. + /// + public NetCoordinates PlayerCoords = default!; + + public NetEntity Player = default!; + public EntityUid SPlayerEnt = default!; + + public ICommonSession ClientSession = default!; + public ICommonSession ServerSession = default!; + + public GhostTestData() + { + } + } + + private async Task SetupData() + { + var data = new GhostTestData(); + + // Client is needed to create a session for the ghost system. Creating a dummy session was too difficult. + data.Pair = await PoolManager.GetServerClient(new PoolSettings + { + DummyTicker = false, + Connected = true, + Dirty = true + }); + + data.SEntMan = data.Pair.Server.ResolveDependency(); + data.SPlayerMan = data.Pair.Server.ResolveDependency(); + data.SMindSys = data.SEntMan.System(); + data.STransformSys = data.SEntMan.System(); + + // Setup map. + await data.Pair.CreateTestMap(); + data.PlayerCoords = data.SEntMan.GetNetCoordinates(data.MapData.GridCoords.Offset(new Vector2(0.5f, 0.5f)).WithEntityId(data.MapData.MapUid, data.STransformSys, data.SEntMan)); + + if (data.Client.Session == null) + Assert.Fail("No player"); + data.ClientSession = data.Client.Session!; + data.ServerSession = data.SPlayerMan.GetSessionById(data.ClientSession.UserId); + + Entity mind = default!; + await data.Pair.Server.WaitPost(() => + { + data.Player = data.SEntMan.GetNetEntity(data.SEntMan.SpawnEntity(null, data.SEntMan.GetCoordinates(data.PlayerCoords))); + mind = data.SMindSys.CreateMind(data.ServerSession.UserId, "DummyPlayerEntity"); + data.SPlayerEnt = data.SEntMan.GetEntity(data.Player); + data.SMindSys.TransferTo(mind, data.SPlayerEnt, mind: mind.Comp); + data.Server.PlayerMan.SetAttachedEntity(data.ServerSession, data.SPlayerEnt); + }); + + await data.Pair.RunTicksSync(5); + + Assert.Multiple(() => + { + Assert.That(data.ServerSession.ContentData()?.Mind, Is.EqualTo(mind.Owner)); + Assert.That(data.ServerSession.AttachedEntity, Is.EqualTo(data.SPlayerEnt)); + Assert.That(data.ServerSession.AttachedEntity, Is.EqualTo(mind.Comp.CurrentEntity), + "Player is not attached to the mind's current entity."); + Assert.That(data.SEntMan.EntityExists(mind.Comp.OwnedEntity), + "The mind's current entity does not exist"); + Assert.That(mind.Comp.VisitingEntity == null || data.SEntMan.EntityExists(mind.Comp.VisitingEntity), + "The minds visited entity does not exist."); + }); + + Assert.That(data.SPlayerEnt, Is.Not.EqualTo(null)); + + return data; + } + + /// + /// Test that a ghost gets created when the player entity is deleted. + /// 1. Delete mob + /// 2. Assert is ghost + /// + [Test] + public async Task TestGridGhostOnDelete() + { + var data = await SetupData(); + + var oldPosition = data.SEntMan.GetComponent(data.SPlayerEnt).Coordinates; + + Assert.That(!data.SEntMan.HasComponent(data.SPlayerEnt), "Player was initially a ghost?"); + + // Delete entity + await data.Server.WaitPost(() => data.SEntMan.DeleteEntity(data.SPlayerEnt)); + await data.Pair.RunTicksSync(5); + + var ghost = data.ServerSession.AttachedEntity!.Value; + Assert.That(data.SEntMan.HasComponent(ghost), "Player did not become a ghost"); + + // Ensure the position is the same + var ghostPosition = data.SEntMan.GetComponent(ghost).Coordinates; + Assert.That(ghostPosition, Is.EqualTo(oldPosition)); + + await data.Pair.CleanReturnAsync(); + } + + /// + /// Test that a ghost gets created when the player entity is queue deleted. + /// 1. Delete mob + /// 2. Assert is ghost + /// + [Test] + public async Task TestGridGhostOnQueueDelete() + { + var data = await SetupData(); + + var oldPosition = data.SEntMan.GetComponent(data.SPlayerEnt).Coordinates; + + Assert.That(!data.SEntMan.HasComponent(data.SPlayerEnt), "Player was initially a ghost?"); + + // Delete entity + await data.Server.WaitPost(() => data.SEntMan.QueueDeleteEntity(data.SPlayerEnt)); + await data.Pair.RunTicksSync(5); + + var ghost = data.ServerSession.AttachedEntity!.Value; + Assert.That(data.SEntMan.HasComponent(ghost), "Player did not become a ghost"); + + // Ensure the position is the same + var ghostPosition = data.SEntMan.GetComponent(ghost).Coordinates; + Assert.That(ghostPosition, Is.EqualTo(oldPosition)); + + await data.Pair.CleanReturnAsync(); + } + +} diff --git a/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs b/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs index 2ebe750f98d..de7739b2ad7 100644 --- a/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs +++ b/Content.IntegrationTests/Tests/Minds/MindTests.EntityDeletion.cs @@ -1,3 +1,4 @@ +#nullable enable using System.Linq; using Content.Server.GameTicking; using Content.Shared.Ghost; @@ -77,7 +78,7 @@ public async Task TestGhostOnDeleteMap() await using var pair = await SetupPair(dirty: true); var server = pair.Server; var testMap = await pair.CreateTestMap(); - var coordinates = testMap.GridCoords; + var testMap2 = await pair.CreateTestMap(); var entMan = server.ResolveDependency(); var mapManager = server.ResolveDependency(); @@ -91,7 +92,7 @@ public async Task TestGhostOnDeleteMap() MindComponent mind = default!; await server.WaitAssertion(() => { - playerEnt = entMan.SpawnEntity(null, coordinates); + playerEnt = entMan.SpawnEntity(null, testMap.GridCoords); mindId = player.ContentData()!.Mind!.Value; mind = entMan.GetComponent(mindId); mindSystem.TransferTo(mindId, playerEnt); @@ -100,14 +101,20 @@ await server.WaitAssertion(() => }); await pair.RunTicksSync(5); - await server.WaitPost(() => mapManager.DeleteMap(testMap.MapId)); + await server.WaitAssertion(() => mapManager.DeleteMap(testMap.MapId)); await pair.RunTicksSync(5); await server.WaitAssertion(() => { #pragma warning disable NUnit2045 // Interdependent assertions. - Assert.That(entMan.EntityExists(mind.CurrentEntity), Is.True); - Assert.That(mind.CurrentEntity, Is.Not.EqualTo(playerEnt)); + // Spawn ghost on the second map + var attachedEntity = player.AttachedEntity; + Assert.That(entMan.EntityExists(attachedEntity), Is.True); + Assert.That(attachedEntity, Is.Not.EqualTo(playerEnt)); + Assert.That(entMan.HasComponent(attachedEntity)); + var transform = entMan.GetComponent(attachedEntity.Value); + Assert.That(transform.MapID, Is.Not.EqualTo(MapId.Nullspace)); + Assert.That(transform.MapID, Is.Not.EqualTo(testMap.MapId)); #pragma warning restore NUnit2045 }); diff --git a/Content.IntegrationTests/Tests/PostMapInitTest.cs b/Content.IntegrationTests/Tests/PostMapInitTest.cs index 6cddd866ebb..a42e9df1b51 100644 --- a/Content.IntegrationTests/Tests/PostMapInitTest.cs +++ b/Content.IntegrationTests/Tests/PostMapInitTest.cs @@ -153,7 +153,10 @@ public async Task NoSavedPostMapInitTest() [Test, TestCaseSource(nameof(GameMaps))] public async Task GameMapsLoadableTest(string mapProto) { - await using var pair = await PoolManager.GetServerClient(); + await using var pair = await PoolManager.GetServerClient(new PoolSettings + { + Dirty = true // Stations spawn a bunch of nullspace entities and maps like centcomm. + }); var server = pair.Server; var mapManager = server.ResolveDependency(); diff --git a/Content.IntegrationTests/Tests/Power/PowerTest.cs b/Content.IntegrationTests/Tests/Power/PowerTest.cs index a6af3e6a65b..a94e94489c0 100644 --- a/Content.IntegrationTests/Tests/Power/PowerTest.cs +++ b/Content.IntegrationTests/Tests/Power/PowerTest.cs @@ -143,8 +143,8 @@ public sealed class PowerTest anchored: true - type: UserInterface interfaces: - - key: enum.ApcUiKey.Key - type: ApcBoundUserInterface + enum.ApcUiKey.Key: + type: ApcBoundUserInterface - type: AccessReader access: [['Engineering']] diff --git a/Content.IntegrationTests/Tests/Preferences/ServerDbSqliteTests.cs b/Content.IntegrationTests/Tests/Preferences/ServerDbSqliteTests.cs index b4417200242..47b5a84f8f4 100644 --- a/Content.IntegrationTests/Tests/Preferences/ServerDbSqliteTests.cs +++ b/Content.IntegrationTests/Tests/Preferences/ServerDbSqliteTests.cs @@ -3,6 +3,7 @@ using Content.Server.Database; using Content.Shared.GameTicking; using Content.Shared.Humanoid; +using Content.Shared.Humanoid.Markings; using Content.Shared.Preferences; using Microsoft.Data.Sqlite; using Microsoft.EntityFrameworkCore; @@ -37,36 +38,21 @@ public sealed class ServerDbSqliteTests private static HumanoidCharacterProfile CharlieCharlieson() { - return new( - "Charlie Charlieson", - "The biggest boy around.", - "Human", - 1, - 1, - 21, - Sex.Male, - Gender.Epicene, - new HumanoidCharacterAppearance( + return new HumanoidCharacterProfile + { + Name = "Charlie Charlieson", + FlavorText = "The biggest boy around.", + Species = "Human", + Age = 21, + Appearance = new( "Afro", Color.Aqua, "Shaved", Color.Aquamarine, Color.Azure, Color.Beige, - new () - ), - ClothingPreference.Jumpskirt, - BackpackPreference.Backpack, - SpawnPriorityPreference.None, - new Dictionary - { - {SharedGameTicker.FallbackOverflowJob, JobPriority.High} - }, - PreferenceUnavailableMode.StayInLobby, - antagPreferences: new List(), - traitPreferences: new List(), - loadoutPreferences: new List() - ); + new List()), + }; } private static ServerDbSqlite GetDb(RobustIntegrationTest.ServerIntegrationInstance server) diff --git a/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs b/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs new file mode 100644 index 00000000000..9e925a451a5 --- /dev/null +++ b/Content.IntegrationTests/Tests/Station/EvacShuttleTest.cs @@ -0,0 +1,127 @@ +using System.Linq; +using Content.Server.GameTicking; +using Content.Server.Shuttles.Components; +using Content.Server.Shuttles.Systems; +using Content.Server.Station.Components; +using Content.Shared.CCVar; +using Content.Shared.Shuttles.Components; +using Robust.Shared.GameObjects; +using Robust.Shared.Map.Components; + +namespace Content.IntegrationTests.Tests.Station; + +[TestFixture] +[TestOf(typeof(EmergencyShuttleSystem))] +public sealed class EvacShuttleTest +{ + /// + /// Ensure that the emergency shuttle can be called, and that it will travel to centcomm + /// + [Test] + public async Task EmergencyEvacTest() + { + await using var pair = await PoolManager.GetServerClient(new PoolSettings { DummyTicker = true, Dirty = true }); + var server = pair.Server; + var entMan = server.EntMan; + var ticker = server.System(); + + // Dummy ticker tests should not have centcomm + Assert.That(entMan.Count(), Is.Zero); + + Assert.That(pair.Server.CfgMan.GetCVar(CCVars.GridFill), Is.False); + pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, true); + pair.Server.CfgMan.SetCVar(CCVars.GameDummyTicker, false); + var gameMap = pair.Server.CfgMan.GetCVar(CCVars.GameMap); + pair.Server.CfgMan.SetCVar(CCVars.GameMap, "Saltern"); + + await server.WaitPost(() => ticker.RestartRound()); + await pair.RunTicksSync(25); + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.InRound)); + + // Find the station, centcomm, and shuttle, and ftl map. + + Assert.That(entMan.Count(), Is.EqualTo(1)); + Assert.That(entMan.Count(), Is.EqualTo(1)); + Assert.That(entMan.Count(), Is.EqualTo(1)); + Assert.That(entMan.Count(), Is.EqualTo(1)); + Assert.That(entMan.Count(), Is.EqualTo(0)); + + var station = (Entity) entMan.AllComponentsList().Single(); + var data = entMan.GetComponent(station); + var shuttleData = entMan.GetComponent(station); + + var saltern = data.Grids.Single(); + Assert.That(entMan.HasComponent(saltern)); + + var shuttle = shuttleData.EmergencyShuttle!.Value; + Assert.That(entMan.HasComponent(shuttle)); + Assert.That(entMan.HasComponent(shuttle)); + + var centcomm = station.Comp.Entity!.Value; + Assert.That(entMan.HasComponent(centcomm)); + + var centcommMap = station.Comp.MapEntity!.Value; + Assert.That(entMan.HasComponent(centcommMap)); + Assert.That(server.Transform(centcomm).MapUid, Is.EqualTo(centcommMap)); + + var salternXform = server.Transform(saltern); + Assert.That(salternXform.MapUid, Is.Not.Null); + Assert.That(salternXform.MapUid, Is.Not.EqualTo(centcommMap)); + + var shuttleXform = server.Transform(shuttle); + Assert.That(shuttleXform.MapUid, Is.Not.Null); + Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap)); + + // All of these should have been map-initialized. + var mapSys = entMan.System(); + Assert.That(mapSys.IsInitialized(centcommMap), Is.True); + Assert.That(mapSys.IsInitialized(salternXform.MapUid), Is.True); + Assert.That(mapSys.IsPaused(centcommMap), Is.False); + Assert.That(mapSys.IsPaused(salternXform.MapUid!.Value), Is.False); + + EntityLifeStage LifeStage(EntityUid uid) => entMan.GetComponent(uid).EntityLifeStage; + Assert.That(LifeStage(saltern), Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(LifeStage(shuttle), Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(LifeStage(centcomm), Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(LifeStage(centcommMap), Is.EqualTo(EntityLifeStage.MapInitialized)); + Assert.That(LifeStage(salternXform.MapUid.Value), Is.EqualTo(EntityLifeStage.MapInitialized)); + + // Set up shuttle timing + var shuttleSys = server.System(); + var evacSys = server.System(); + evacSys.TransitTime = shuttleSys.DefaultTravelTime; // Absolute minimum transit time, so the test has to run for at least this long + // TODO SHUTTLE fix spaghetti + + var dockTime = server.CfgMan.GetCVar(CCVars.EmergencyShuttleDockTime); + server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, 2); + + // Call evac shuttle. + await pair.WaitCommand("callshuttle 0:02"); + await pair.RunSeconds(3); + + // Shuttle should have arrived on the station + Assert.That(shuttleXform.MapUid, Is.EqualTo(salternXform.MapUid)); + + await pair.RunSeconds(2); + + // Shuttle should be FTLing back to centcomm + Assert.That(entMan.Count(), Is.EqualTo(1)); + var ftl = (Entity) entMan.AllComponentsList().Single(); + Assert.That(entMan.HasComponent(ftl)); + Assert.That(ftl.Owner, Is.Not.EqualTo(centcommMap)); + Assert.That(ftl.Owner, Is.Not.EqualTo(salternXform.MapUid)); + Assert.That(shuttleXform.MapUid, Is.EqualTo(ftl.Owner)); + + // Shuttle should have arrived at centcomm + await pair.RunSeconds(shuttleSys.DefaultTravelTime); + Assert.That(shuttleXform.MapUid, Is.EqualTo(centcommMap)); + + // Round should be ending now + Assert.That(ticker.RunLevel, Is.EqualTo(GameRunLevel.PostRound)); + + server.CfgMan.SetCVar(CCVars.EmergencyShuttleDockTime, dockTime); + pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, false); + pair.Server.CfgMan.SetCVar(CCVars.GameMap, gameMap); + await pair.CleanReturnAsync(); + } +} diff --git a/Content.IntegrationTests/Tests/StorageTest.cs b/Content.IntegrationTests/Tests/StorageTest.cs index 659b310661b..2d28534347d 100644 --- a/Content.IntegrationTests/Tests/StorageTest.cs +++ b/Content.IntegrationTests/Tests/StorageTest.cs @@ -92,23 +92,32 @@ public async Task TestSufficientSpaceForFill() var allSizes = protoMan.EnumeratePrototypes().ToList(); allSizes.Sort(); - Assert.Multiple(() => + await Assert.MultipleAsync(async () => { foreach (var proto in pair.GetPrototypesWithComponent()) { if (proto.HasComponent(compFact)) continue; - if (!proto.TryGetComponent("Storage", out var storage)) + StorageComponent? storage = null; + ItemComponent? item = null; + StorageFillComponent fill = default!; + var size = 0; + await server.WaitAssertion(() => { - Assert.Fail($"Entity {proto.ID} has storage-fill without a storage component!"); - continue; - } + if (!proto.TryGetComponent("Storage", out storage)) + { + Assert.Fail($"Entity {proto.ID} has storage-fill without a storage component!"); + return; + } - proto.TryGetComponent("Item", out var item); + proto.TryGetComponent("Item", out item); + fill = (StorageFillComponent) proto.Components[id].Component; + size = GetFillSize(fill, false, protoMan, itemSys); + }); - var fill = (StorageFillComponent) proto.Components[id].Component; - var size = GetFillSize(fill, false, protoMan, itemSys); + if (storage == null) + continue; var maxSize = storage.MaxItemSize; if (storage.MaxItemSize == null) @@ -138,7 +147,13 @@ public async Task TestSufficientSpaceForFill() if (!protoMan.TryIndex(entry.PrototypeId, out var fillItem)) continue; - if (!fillItem.TryGetComponent("Item", out var entryItem)) + ItemComponent? entryItem = null; + await server.WaitPost(() => + { + fillItem.TryGetComponent("Item", out entryItem); + }); + + if (entryItem == null) continue; Assert.That(protoMan.Index(entryItem.Size).Weight, @@ -164,25 +179,25 @@ public async Task TestSufficientSpaceForEntityStorageFill() var itemSys = entMan.System(); - Assert.Multiple(() => + foreach (var proto in pair.GetPrototypesWithComponent()) { - foreach (var proto in pair.GetPrototypesWithComponent()) - { - if (proto.HasComponent(compFact)) - continue; + if (proto.HasComponent(compFact)) + continue; - if (!proto.TryGetComponent("EntityStorage", out var entStorage)) - { + await server.WaitAssertion(() => + { + if (!proto.TryGetComponent("EntityStorage", out EntityStorageComponent? entStorage)) Assert.Fail($"Entity {proto.ID} has storage-fill without a storage component!"); - continue; - } + + if (entStorage == null) + return; var fill = (StorageFillComponent) proto.Components[id].Component; var size = GetFillSize(fill, true, protoMan, itemSys); Assert.That(size, Is.LessThanOrEqualTo(entStorage.Capacity), $"{proto.ID} storage fill is too large."); - } - }); + }); + } await pair.CleanReturnAsync(); } diff --git a/Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs b/Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs index 6b47ec4d8eb..19b25816fa3 100644 --- a/Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs +++ b/Content.IntegrationTests/Tests/Utility/EntityWhitelistTest.cs @@ -64,7 +64,8 @@ public async Task Test() var testMap = await pair.CreateTestMap(); var mapCoordinates = testMap.MapCoords; - var sEntities = server.ResolveDependency(); + var sEntities = server.EntMan; + var sys = server.System(); await server.WaitAssertion(() => { @@ -80,22 +81,14 @@ await server.WaitAssertion(() => Components = new[] { $"{ValidComponent}" }, Tags = new() { "WhitelistTestValidTag" } }; - whitelistInst.UpdateRegistrations(); - Assert.That(whitelistInst, Is.Not.Null); Assert.Multiple(() => { - Assert.That(whitelistInst.Components, Is.Not.Null); - Assert.That(whitelistInst.Tags, Is.Not.Null); - }); - - Assert.Multiple(() => - { - Assert.That(whitelistInst.IsValid(validComponent), Is.True); - Assert.That(whitelistInst.IsValid(WhitelistTestValidTag), Is.True); + Assert.That(sys.IsValid(whitelistInst, validComponent), Is.True); + Assert.That(sys.IsValid(whitelistInst, WhitelistTestValidTag), Is.True); - Assert.That(whitelistInst.IsValid(invalidComponent), Is.False); - Assert.That(whitelistInst.IsValid(WhitelistTestInvalidTag), Is.False); + Assert.That(sys.IsValid(whitelistInst, invalidComponent), Is.False); + Assert.That(sys.IsValid(whitelistInst, WhitelistTestInvalidTag), Is.False); }); // Test from serialized @@ -111,11 +104,11 @@ await server.WaitAssertion(() => Assert.Multiple(() => { - Assert.That(whitelistSer.IsValid(validComponent), Is.True); - Assert.That(whitelistSer.IsValid(WhitelistTestValidTag), Is.True); + Assert.That(sys.IsValid(whitelistSer, validComponent), Is.True); + Assert.That(sys.IsValid(whitelistSer, WhitelistTestValidTag), Is.True); - Assert.That(whitelistSer.IsValid(invalidComponent), Is.False); - Assert.That(whitelistSer.IsValid(WhitelistTestInvalidTag), Is.False); + Assert.That(sys.IsValid(whitelistSer, invalidComponent), Is.False); + Assert.That(sys.IsValid(whitelistSer, WhitelistTestInvalidTag), Is.False); }); }); await pair.CleanReturnAsync(); diff --git a/Content.Server/Access/Components/IdExaminableComponent.cs b/Content.Server/Access/Components/IdExaminableComponent.cs deleted file mode 100644 index 2def517f408..00000000000 --- a/Content.Server/Access/Components/IdExaminableComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -using Content.Server.Access.Systems; - -namespace Content.Server.Access.Components; - -[RegisterComponent, Access(typeof(IdExaminableSystem))] -public sealed partial class IdExaminableComponent : Component -{ -} diff --git a/Content.Server/Access/Systems/AccessOverriderSystem.cs b/Content.Server/Access/Systems/AccessOverriderSystem.cs index d0b8c31ab69..6c1b22137de 100644 --- a/Content.Server/Access/Systems/AccessOverriderSystem.cs +++ b/Content.Server/Access/Systems/AccessOverriderSystem.cs @@ -69,16 +69,13 @@ private void AfterInteractOn(EntityUid uid, AccessOverriderComponent component, private void OnDoAfter(EntityUid uid, AccessOverriderComponent component, AccessOverriderDoAfterEvent args) { - if (!TryComp(args.User, out ActorComponent? actor)) - return; - if (args.Handled || args.Cancelled) return; if (args.Args.Target != null) { component.TargetAccessReaderId = args.Args.Target.Value; - _userInterface.TryOpen(uid, AccessOverriderUiKey.Key, actor.PlayerSession); + _userInterface.OpenUi(uid, AccessOverriderUiKey.Key, args.User); UpdateUserInterface(uid, component, args); } @@ -95,7 +92,7 @@ private void OnClose(EntityUid uid, AccessOverriderComponent component, BoundUIC private void OnWriteToTargetAccessReaderIdMessage(EntityUid uid, AccessOverriderComponent component, WriteToTargetAccessReaderIdMessage args) { - if (args.Session.AttachedEntity is not { Valid: true } player) + if (args.Actor is not { Valid: true } player) return; TryWriteToTargetAccessReaderId(uid, args.AccessList, player, component); @@ -155,22 +152,19 @@ private void UpdateUserInterface(EntityUid uid, AccessOverriderComponent compone targetLabel, targetLabelColor); - _userInterface.TrySetUiState(uid, AccessOverriderUiKey.Key, newState); + _userInterface.SetUiState(uid, AccessOverriderUiKey.Key, newState); } private List> ConvertAccessHashSetsToList(List>> accessHashsets) { - List> accessList = new List>(); + var accessList = new List>(); + + if (accessHashsets.Count <= 0) + return accessList; - if (accessHashsets != null && accessHashsets.Any()) + foreach (var hashSet in accessHashsets) { - foreach (HashSet> hashSet in accessHashsets) - { - foreach (ProtoId hash in hashSet.ToArray()) - { - accessList.Add(hash); - } - } + accessList.AddRange(hashSet); } return accessList; diff --git a/Content.Server/Access/Systems/AgentIDCardSystem.cs b/Content.Server/Access/Systems/AgentIDCardSystem.cs index bd4d3b3f233..d5e9dc357dd 100644 --- a/Content.Server/Access/Systems/AgentIDCardSystem.cs +++ b/Content.Server/Access/Systems/AgentIDCardSystem.cs @@ -61,14 +61,14 @@ private void OnAfterInteract(EntityUid uid, AgentIDCardComponent component, Afte private void AfterUIOpen(EntityUid uid, AgentIDCardComponent component, AfterActivatableUIOpenEvent args) { - if (!_uiSystem.TryGetUi(uid, AgentIDCardUiKey.Key, out var ui)) + if (!_uiSystem.HasUi(uid, AgentIDCardUiKey.Key)) return; if (!TryComp(uid, out var idCard)) return; - var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.JobTitle ?? "", component.Icons); - _uiSystem.SetUiState(ui, state, args.Session); + var state = new AgentIDCardBoundUserInterfaceState(idCard.FullName ?? "", idCard.JobTitle ?? "", idCard.JobIcon ?? "", component.Icons); + _uiSystem.SetUiState(uid, AgentIDCardUiKey.Key, state); } private void OnJobChanged(EntityUid uid, AgentIDCardComponent comp, AgentIDCardJobChangedMessage args) @@ -94,7 +94,7 @@ private void OnJobIconChanged(EntityUid uid, AgentIDCardComponent comp, AgentIDC return; } - if (!_prototypeManager.TryIndex(args.JobIcon, out var jobIcon)) + if (!_prototypeManager.TryIndex(args.JobIconId, out var jobIcon)) { return; } diff --git a/Content.Server/Access/Systems/IdCardConsoleSystem.cs b/Content.Server/Access/Systems/IdCardConsoleSystem.cs index db8b9d036e8..e680b0c6f40 100644 --- a/Content.Server/Access/Systems/IdCardConsoleSystem.cs +++ b/Content.Server/Access/Systems/IdCardConsoleSystem.cs @@ -41,7 +41,7 @@ public override void Initialize() private void OnWriteToTargetIdMessage(EntityUid uid, IdCardConsoleComponent component, WriteToTargetIdMessage args) { - if (args.Session.AttachedEntity is not { Valid: true } player) + if (args.Actor is not { Valid: true } player) return; TryWriteToTargetId(uid, args.FullName, args.JobTitle, args.AccessList, args.JobPrototype, player, component); @@ -104,7 +104,7 @@ private void UpdateUserInterface(EntityUid uid, IdCardConsoleComponent component Name(targetId)); } - _userInterface.TrySetUiState(uid, IdCardConsoleUiKey.Key, newState); + _userInterface.SetUiState(uid, IdCardConsoleUiKey.Key, newState); } /// diff --git a/Content.Server/Access/Systems/IdCardSystem.cs b/Content.Server/Access/Systems/IdCardSystem.cs index 6b3d8db595f..9cd9976cea9 100644 --- a/Content.Server/Access/Systems/IdCardSystem.cs +++ b/Content.Server/Access/Systems/IdCardSystem.cs @@ -7,8 +7,6 @@ using Content.Shared.Access.Systems; using Content.Shared.Database; using Content.Shared.Popups; -using Content.Shared.Roles; -using Content.Shared.StatusIcon; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -20,20 +18,13 @@ public sealed class IdCardSystem : SharedIdCardSystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; - [Dependency] private readonly MetaDataSystem _metaSystem = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnMicrowaved); } - private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args) - { - UpdateEntityName(uid, id); - } - private void OnMicrowaved(EntityUid uid, IdCardComponent component, BeingMicrowavedEvent args) { if (TryComp(uid, out var access)) @@ -81,143 +72,4 @@ private void OnMicrowaved(EntityUid uid, IdCardComponent component, BeingMicrowa $"{ToPrettyString(args.Microwave)} added {random.ID} access to {ToPrettyString(uid):entity}"); } } - - /// - /// Attempts to change the job title of a card. - /// Returns true/false. - /// - /// - /// If provided with a player's EntityUid to the player parameter, adds the change to the admin logs. - /// - public bool TryChangeJobTitle(EntityUid uid, string? jobTitle, IdCardComponent? id = null, EntityUid? player = null) - { - if (!Resolve(uid, ref id)) - return false; - - if (!string.IsNullOrWhiteSpace(jobTitle)) - { - jobTitle = jobTitle.Trim(); - - if (jobTitle.Length > IdCardConsoleComponent.MaxJobTitleLength) - jobTitle = jobTitle[..IdCardConsoleComponent.MaxJobTitleLength]; - } - else - { - jobTitle = null; - } - - if (id.JobTitle == jobTitle) - return true; - id.JobTitle = jobTitle; - Dirty(uid, id); - UpdateEntityName(uid, id); - - if (player != null) - { - _adminLogger.Add(LogType.Identity, LogImpact.Low, - $"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(uid):entity} to {jobTitle} "); - } - return true; - } - - public bool TryChangeJobIcon(EntityUid uid, StatusIconPrototype jobIcon, IdCardComponent? id = null, EntityUid? player = null) - { - if (!Resolve(uid, ref id)) - { - return false; - } - - if (id.JobIcon == jobIcon.ID) - { - return true; - } - - id.JobIcon = jobIcon.ID; - Dirty(uid, id); - - if (player != null) - { - _adminLogger.Add(LogType.Identity, LogImpact.Low, - $"{ToPrettyString(player.Value):player} has changed the job icon of {ToPrettyString(uid):entity} to {jobIcon} "); - } - - return true; - } - - public bool TryChangeJobDepartment(EntityUid uid, JobPrototype job, IdCardComponent? id = null) - { - if (!Resolve(uid, ref id)) - return false; - - id.JobDepartments.Clear(); - foreach (var department in _prototypeManager.EnumeratePrototypes()) - { - if (department.Roles.Contains(job.ID)) - id.JobDepartments.Add("department-" + department.ID); - } - - Dirty(uid, id); - - return true; - } - - /// - /// Attempts to change the full name of a card. - /// Returns true/false. - /// - /// - /// If provided with a player's EntityUid to the player parameter, adds the change to the admin logs. - /// - public bool TryChangeFullName(EntityUid uid, string? fullName, IdCardComponent? id = null, EntityUid? player = null) - { - if (!Resolve(uid, ref id)) - return false; - - if (!string.IsNullOrWhiteSpace(fullName)) - { - fullName = fullName.Trim(); - if (fullName.Length > IdCardConsoleComponent.MaxFullNameLength) - fullName = fullName[..IdCardConsoleComponent.MaxFullNameLength]; - } - else - { - fullName = null; - } - - if (id.FullName == fullName) - return true; - id.FullName = fullName; - Dirty(uid, id); - UpdateEntityName(uid, id); - - if (player != null) - { - _adminLogger.Add(LogType.Identity, LogImpact.Low, - $"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(uid):entity} to {fullName} "); - } - return true; - } - - /// - /// Changes the name of the id's owner. - /// - /// - /// If either or is empty, it's replaced by placeholders. - /// If both are empty, the original entity's name is restored. - /// - private void UpdateEntityName(EntityUid uid, IdCardComponent? id = null) - { - if (!Resolve(uid, ref id)) - return; - - var jobSuffix = string.IsNullOrWhiteSpace(id.JobTitle) ? string.Empty : $" ({id.JobTitle})"; - - var val = string.IsNullOrWhiteSpace(id.FullName) - ? Loc.GetString("access-id-card-component-owner-name-job-title-text", - ("jobSuffix", jobSuffix)) - : Loc.GetString("access-id-card-component-owner-full-name-job-title-text", - ("fullName", id.FullName), - ("jobSuffix", jobSuffix)); - _metaSystem.SetEntityName(uid, val); - } } diff --git a/Content.Server/Actions/ActionOnInteractSystem.cs b/Content.Server/Actions/ActionOnInteractSystem.cs index c9a5f4b5d09..b6eec0ce0f6 100644 --- a/Content.Server/Actions/ActionOnInteractSystem.cs +++ b/Content.Server/Actions/ActionOnInteractSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Shared.Actions; using Content.Shared.Interaction; using Robust.Shared.Random; @@ -38,16 +39,27 @@ private void OnMapInit(EntityUid uid, ActionOnInteractComponent component, MapIn private void OnActivate(EntityUid uid, ActionOnInteractComponent component, ActivateInWorldEvent args) { - if (args.Handled || component.ActionEntities == null) + if (args.Handled) return; - var options = GetValidActions(component.ActionEntities); + if (component.ActionEntities is not {} actionEnts) + { + if (!TryComp(uid, out var actionsContainerComponent)) + return; + + actionEnts = actionsContainerComponent.Container.ContainedEntities.ToList(); + } + + var options = GetValidActions(actionEnts); if (options.Count == 0) return; var (actId, act) = _random.Pick(options); if (act.Event != null) + { act.Event.Performer = args.User; + act.Event.Action = actId; + } _actions.PerformAction(args.User, null, actId, act, act.Event, _timing.CurTime, false); args.Handled = true; @@ -55,16 +67,24 @@ private void OnActivate(EntityUid uid, ActionOnInteractComponent component, Acti private void OnAfterInteract(EntityUid uid, ActionOnInteractComponent component, AfterInteractEvent args) { - if (args.Handled || component.ActionEntities == null) + if (args.Handled) return; + if (component.ActionEntities is not {} actionEnts) + { + if (!TryComp(uid, out var actionsContainerComponent)) + return; + + actionEnts = actionsContainerComponent.Container.ContainedEntities.ToList(); + } + // First, try entity target actions if (args.Target != null) { - var entOptions = GetValidActions(component.ActionEntities, args.CanReach); + var entOptions = GetValidActions(actionEnts, args.CanReach); for (var i = entOptions.Count - 1; i >= 0; i--) { - var action = entOptions[i].Comp; + var action = entOptions[i]; if (!_actions.ValidateEntityTarget(args.User, args.Target.Value, action)) entOptions.RemoveAt(i); } @@ -75,6 +95,7 @@ private void OnAfterInteract(EntityUid uid, ActionOnInteractComponent component, if (entAct.Event != null) { entAct.Event.Performer = args.User; + entAct.Event.Action = entActId; entAct.Event.Target = args.Target.Value; } @@ -88,7 +109,7 @@ private void OnAfterInteract(EntityUid uid, ActionOnInteractComponent component, var options = GetValidActions(component.ActionEntities, args.CanReach); for (var i = options.Count - 1; i >= 0; i--) { - var action = options[i].Comp; + var action = options[i]; if (!_actions.ValidateWorldTarget(args.User, args.ClickLocation, action)) options.RemoveAt(i); } @@ -100,6 +121,7 @@ private void OnAfterInteract(EntityUid uid, ActionOnInteractComponent component, if (act.Event != null) { act.Event.Performer = args.User; + act.Event.Action = actId; act.Event.Target = args.ClickLocation; } diff --git a/Content.Server/Administration/BanList/BanListEui.cs b/Content.Server/Administration/BanList/BanListEui.cs index 3a86a42d531..8ddc7459d7b 100644 --- a/Content.Server/Administration/BanList/BanListEui.cs +++ b/Content.Server/Administration/BanList/BanListEui.cs @@ -65,13 +65,23 @@ private async Task LoadBans(NetUserId userId) unban = new SharedServerUnban(unbanningAdmin, ban.Unban.UnbanTime.UtcDateTime); } + (string, int cidrMask)? ip = ("*Hidden*", 0); + var hwid = "*Hidden*"; + + if (_admins.HasAdminFlag(Player, AdminFlags.Pii)) + { + ip = ban.Address is { } address + ? (address.address.ToString(), address.cidrMask) + : null; + + hwid = ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan()); + } + Bans.Add(new SharedServerBan( ban.Id, ban.UserId, - ban.Address is { } address - ? (address.address.ToString(), address.cidrMask) - : null, - ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan()), + ip, + hwid, ban.BanTime.UtcDateTime, ban.ExpirationTime?.UtcDateTime, ban.Reason, @@ -96,13 +106,22 @@ private async Task LoadRoleBans(NetUserId userId) unban = new SharedServerUnban(unbanningAdmin, ban.Unban.UnbanTime.UtcDateTime); } + (string, int cidrMask)? ip = ("*Hidden*", 0); + var hwid = "*Hidden*"; + + if (_admins.HasAdminFlag(Player, AdminFlags.Pii)) + { + ip = ban.Address is { } address + ? (address.address.ToString(), address.cidrMask) + : null; + + hwid = ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan()); + } RoleBans.Add(new SharedServerRoleBan( ban.Id, ban.UserId, - ban.Address is { } address - ? (address.address.ToString(), address.cidrMask) - : null, - ban.HWId == null ? null : Convert.ToBase64String(ban.HWId.Value.AsSpan()), + ip, + hwid, ban.BanTime.UtcDateTime, ban.ExpirationTime?.UtcDateTime, ban.Reason, diff --git a/Content.Server/Administration/Components/HeadstandComponent.cs b/Content.Server/Administration/Components/HeadstandComponent.cs index 8472b5ad368..2ab097fad49 100644 --- a/Content.Server/Administration/Components/HeadstandComponent.cs +++ b/Content.Server/Administration/Components/HeadstandComponent.cs @@ -3,7 +3,7 @@ namespace Content.Server.Administration.Components; -[RegisterComponent, NetworkedComponent] +[RegisterComponent] public sealed partial class HeadstandComponent : SharedHeadstandComponent { diff --git a/Content.Server/Administration/Components/KillSignComponent.cs b/Content.Server/Administration/Components/KillSignComponent.cs index e29ce202dda..11479c32fc4 100644 --- a/Content.Server/Administration/Components/KillSignComponent.cs +++ b/Content.Server/Administration/Components/KillSignComponent.cs @@ -3,6 +3,5 @@ namespace Content.Server.Administration.Components; -[NetworkedComponent, RegisterComponent] -public sealed partial class KillSignComponent : SharedKillSignComponent -{ } +[RegisterComponent] +public sealed partial class KillSignComponent : SharedKillSignComponent; diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs index 8ee52ad03e7..4e6af6ceea5 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.Smites.cs @@ -18,7 +18,6 @@ using Content.Server.Storage.EntitySystems; using Content.Server.Tabletop; using Content.Server.Tabletop.Components; -using Content.Server.Terminator.Systems; using Content.Shared.Administration; using Content.Shared.Administration.Components; using Content.Shared.Body.Components; @@ -31,7 +30,6 @@ using Content.Shared.Electrocution; using Content.Shared.Interaction.Components; using Content.Shared.Inventory; -using Content.Shared.Mind.Components; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; @@ -74,7 +72,6 @@ public sealed partial class AdminVerbSystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly SharedPhysicsSystem _physics = default!; [Dependency] private readonly TabletopSystem _tabletopSystem = default!; - [Dependency] private readonly TerminatorSystem _terminator = default!; [Dependency] private readonly VomitSystem _vomitSystem = default!; [Dependency] private readonly WeldableSystem _weldableSystem = default!; [Dependency] private readonly SharedContentEyeSystem _eyeSystem = default!; @@ -152,7 +149,7 @@ private void AddSmiteVerbs(GetVerbsEvent args) Act = () => { // Fuck you. Burn Forever. - flammable.FireStacks = FlammableSystem.MaximumFireStacks; + flammable.FireStacks = flammable.MaximumFireStacks; _flammableSystem.Ignite(args.Target, args.User); var xform = Transform(args.Target); _popupSystem.PopupEntity(Loc.GetString("admin-smite-set-alight-self"), args.Target, @@ -824,27 +821,5 @@ private void AddSmiteVerbs(GetVerbsEvent args) Impact = LogImpact.Extreme, }; args.Verbs.Add(superBonk); - - Verb terminate = new() - { - Text = "Terminate", - Category = VerbCategory.Smite, - Icon = new SpriteSpecifier.Rsi(new ("Mobs/Species/Terminator/parts.rsi"), "skull_icon"), - Act = () => - { - if (!TryComp(args.Target, out var mindContainer) || mindContainer.Mind == null) - return; - - var coords = Transform(args.Target).Coordinates; - var mindId = mindContainer.Mind.Value; - _terminator.CreateSpawner(coords, mindId); - - _popupSystem.PopupEntity(Loc.GetString("admin-smite-terminate-prompt"), args.Target, - args.Target, PopupType.LargeCaution); - }, - Impact = LogImpact.Extreme, - Message = Loc.GetString("admin-smite-terminate-description") - }; - args.Verbs.Add(terminate); } } diff --git a/Content.Server/Administration/Systems/AdminVerbSystem.cs b/Content.Server/Administration/Systems/AdminVerbSystem.cs index f5b237b4492..5bb75b4c99c 100644 --- a/Content.Server/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Server/Administration/Systems/AdminVerbSystem.cs @@ -463,7 +463,7 @@ private void AddDebugVerbs(GetVerbsEvent args) Text = Loc.GetString("configure-verb-get-data-text"), Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/settings.svg.192dpi.png")), Category = VerbCategory.Debug, - Act = () => _uiSystem.TryOpen(args.Target, ConfigurationUiKey.Key, actor.PlayerSession) + Act = () => _uiSystem.OpenUi(args.Target, ConfigurationUiKey.Key, actor.PlayerSession) }; args.Verbs.Add(verb); } diff --git a/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs index 939fc9a2dbb..6b771578200 100644 --- a/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs +++ b/Content.Server/Advertise/EntitySystems/SpeakOnUIClosedSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Chat; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using ActivatableUIComponent = Content.Shared.UserInterface.ActivatableUIComponent; namespace Content.Server.Advertise; diff --git a/Content.Server/AlertLevel/AlertLevelSystem.cs b/Content.Server/AlertLevel/AlertLevelSystem.cs index b290d95a5c1..46b02c0e977 100644 --- a/Content.Server/AlertLevel/AlertLevelSystem.cs +++ b/Content.Server/AlertLevel/AlertLevelSystem.cs @@ -98,6 +98,16 @@ private void OnPrototypeReload(PrototypesReloadedEventArgs args) RaiseLocalEvent(new AlertLevelPrototypeReloadedEvent()); } + public string GetLevel(EntityUid station, AlertLevelComponent? alert = null) + { + if (!Resolve(station, ref alert)) + { + return string.Empty; + } + + return alert.CurrentLevel; + } + public float GetAlertLevelDelay(EntityUid station, AlertLevelComponent? alert = null) { if (!Resolve(station, ref alert)) diff --git a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs index 5bf78bde857..1b323d66437 100644 --- a/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs +++ b/Content.Server/Ame/EntitySystems/AmeControllerSystem.cs @@ -129,11 +129,11 @@ public void UpdateUi(EntityUid uid, AmeControllerComponent? controller = null) if (!Resolve(uid, ref controller)) return; - if (!_userInterfaceSystem.TryGetUi(uid, AmeControllerUiKey.Key, out var bui)) + if (!_userInterfaceSystem.HasUi(uid, AmeControllerUiKey.Key)) return; var state = GetUiState(uid, controller); - _userInterfaceSystem.SetUiState(bui, state); + _userInterfaceSystem.SetUiState(uid, AmeControllerUiKey.Key, state); controller.NextUIUpdate = _gameTiming.CurTime + controller.UpdateUIPeriod; } @@ -324,7 +324,7 @@ private void OnPowerChanged(EntityUid uid, AmeControllerComponent comp, ref Powe private void OnUiButtonPressed(EntityUid uid, AmeControllerComponent comp, UiButtonPressedMessage msg) { - var user = msg.Session.AttachedEntity; + var user = msg.Actor; if (!Exists(user)) return; @@ -334,7 +334,7 @@ private void OnUiButtonPressed(EntityUid uid, AmeControllerComponent comp, UiBut _ => true, }; - if (!PlayerCanUseController(uid, user!.Value, needsPower, comp)) + if (!PlayerCanUseController(uid, user, needsPower, comp)) return; _audioSystem.PlayPvs(comp.ClickSound, uid, AudioParams.Default.WithVolume(-2f)); diff --git a/Content.Server/Anomaly/AnomalySystem.Generator.cs b/Content.Server/Anomaly/AnomalySystem.Generator.cs index 7aa1a8935f3..056a985cbe2 100644 --- a/Content.Server/Anomaly/AnomalySystem.Generator.cs +++ b/Content.Server/Anomaly/AnomalySystem.Generator.cs @@ -61,7 +61,7 @@ public void UpdateGeneratorUi(EntityUid uid, AnomalyGeneratorComponent component var materialAmount = _material.GetMaterialAmount(uid, component.RequiredMaterial); var state = new AnomalyGeneratorUserInterfaceState(component.CooldownEndTime, materialAmount, component.MaterialPerAnomaly); - _ui.TrySetUiState(uid, AnomalyGeneratorUiKey.Key, state); + _ui.SetUiState(uid, AnomalyGeneratorUiKey.Key, state); } public void TryGeneratorCreateAnomaly(EntityUid uid, AnomalyGeneratorComponent? component = null) diff --git a/Content.Server/Anomaly/AnomalySystem.Scanner.cs b/Content.Server/Anomaly/AnomalySystem.Scanner.cs index bce508903d0..39c0d08b55e 100644 --- a/Content.Server/Anomaly/AnomalySystem.Scanner.cs +++ b/Content.Server/Anomaly/AnomalySystem.Scanner.cs @@ -31,7 +31,8 @@ private void OnScannerAnomalyShutdown(ref AnomalyShutdownEvent args) { if (component.ScannedAnomaly != args.Anomaly) continue; - _ui.TryCloseAll(uid, AnomalyScannerUiKey.Key); + + _ui.CloseUi(uid, AnomalyScannerUiKey.Key); } } @@ -108,7 +109,7 @@ private void OnDoAfter(EntityUid uid, AnomalyScannerComponent component, DoAfter Popup.PopupEntity(Loc.GetString("anomaly-scanner-component-scan-complete"), uid); UpdateScannerWithNewAnomaly(uid, args.Args.Target.Value, component); - if (TryComp(args.Args.User, out var actor)) _ui.TryOpen(uid, AnomalyScannerUiKey.Key, actor.PlayerSession); + _ui.OpenUi(uid, AnomalyScannerUiKey.Key, args.User); args.Handled = true; } @@ -123,7 +124,7 @@ public void UpdateScannerUi(EntityUid uid, AnomalyScannerComponent? component = nextPulse = anomalyComponent.NextPulseTime; var state = new AnomalyScannerUserInterfaceState(GetScannerMessage(component), nextPulse); - _ui.TrySetUiState(uid, AnomalyScannerUiKey.Key, state); + _ui.SetUiState(uid, AnomalyScannerUiKey.Key, state); } public void UpdateScannerWithNewAnomaly(EntityUid scanner, EntityUid anomaly, AnomalyScannerComponent? scannerComp = null, AnomalyComponent? anomalyComp = null) diff --git a/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs b/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs index 0824d48ae27..0c7e257d2bd 100644 --- a/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs +++ b/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs @@ -23,7 +23,7 @@ public sealed partial class MobReplacementRuleComponent : Component /// Chance per-entity. /// [DataField] - public float Chance = 0.001f; + public float Chance = 0.004f; [DataField] public bool DoAnnouncement = true; diff --git a/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs b/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs index ef69600783b..cd22f1f6d31 100644 --- a/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs +++ b/Content.Server/Arcade/BlockGame/BlockGame.Ui.cs @@ -157,39 +157,37 @@ private void InputTick(float frameTime) /// The message to broadcase to all players/spectators. private void SendMessage(BoundUserInterfaceMessage message) { - if (_uiSystem.TryGetUi(_owner, BlockGameUiKey.Key, out var bui)) - _uiSystem.SendUiMessage(bui, message); + _uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message); } /// /// Handles sending a message to a specific player/spectator. /// /// The message to send to a specific player/spectator. - /// The target recipient. - private void SendMessage(BoundUserInterfaceMessage message, ICommonSession session) + /// The target recipient. + private void SendMessage(BoundUserInterfaceMessage message, EntityUid actor) { - if (_uiSystem.TryGetUi(_owner, BlockGameUiKey.Key, out var bui)) - _uiSystem.TrySendUiMessage(bui, message, session); + _uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message, actor); } /// /// Handles sending the current state of the game to a player that has just opened the UI. /// - /// The target recipient. - public void UpdateNewPlayerUI(ICommonSession session) + /// The target recipient. + public void UpdateNewPlayerUI(EntityUid actor) { if (_gameOver) { - SendMessage(new BlockGameMessages.BlockGameGameOverScreenMessage(Points, _highScorePlacement?.LocalPlacement, _highScorePlacement?.GlobalPlacement), session); + SendMessage(new BlockGameMessages.BlockGameGameOverScreenMessage(Points, _highScorePlacement?.LocalPlacement, _highScorePlacement?.GlobalPlacement), actor); return; } if (Paused) - SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Pause, Started), session); + SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Pause, Started), actor); else - SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Game, Started), session); + SendMessage(new BlockGameMessages.BlockGameSetScreenMessage(BlockGameMessages.BlockGameScreen.Game, Started), actor); - FullUpdate(session); + FullUpdate(actor); } /// @@ -209,14 +207,14 @@ private void FullUpdate() /// Handles broadcasting the full player-visible game state to a specific player/spectator. /// /// The target recipient. - private void FullUpdate(ICommonSession session) + private void FullUpdate(EntityUid actor) { - UpdateFieldUI(session); - SendNextPieceUpdate(session); - SendHoldPieceUpdate(session); - SendLevelUpdate(session); - SendPointsUpdate(session); - SendHighscoreUpdate(session); + UpdateFieldUI(actor); + SendNextPieceUpdate(actor); + SendHoldPieceUpdate(actor); + SendLevelUpdate(actor); + SendPointsUpdate(actor); + SendHighscoreUpdate(actor); } /// @@ -234,14 +232,13 @@ public void UpdateFieldUI() /// /// Handles broadcasting the current location of all of the blocks in the playfield + the active piece to a specific player/spectator. /// - /// The target recipient. - public void UpdateFieldUI(ICommonSession session) + public void UpdateFieldUI(EntityUid actor) { if (!Started) return; var computedField = ComputeField(); - SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(computedField.ToArray(), BlockGameMessages.BlockGameVisualType.GameField), session); + SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(computedField.ToArray(), BlockGameMessages.BlockGameVisualType.GameField), actor); } /// @@ -282,10 +279,9 @@ private void SendNextPieceUpdate() /// /// Broadcasts the state of the next queued piece to a specific viewer. /// - /// The target recipient. - private void SendNextPieceUpdate(ICommonSession session) + private void SendNextPieceUpdate(EntityUid actor) { - SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(NextPiece.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.NextBlock), session); + SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(NextPiece.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.NextBlock), actor); } /// @@ -302,13 +298,12 @@ private void SendHoldPieceUpdate() /// /// Broadcasts the state of the currently held piece to a specific viewer. /// - /// The target recipient. - private void SendHoldPieceUpdate(ICommonSession session) + private void SendHoldPieceUpdate(EntityUid actor) { if (HeldPiece.HasValue) - SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(HeldPiece.Value.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.HoldBlock), session); + SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(HeldPiece.Value.BlocksForPreview(), BlockGameMessages.BlockGameVisualType.HoldBlock), actor); else - SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(Array.Empty(), BlockGameMessages.BlockGameVisualType.HoldBlock), session); + SendMessage(new BlockGameMessages.BlockGameVisualUpdateMessage(Array.Empty(), BlockGameMessages.BlockGameVisualType.HoldBlock), actor); } /// @@ -322,10 +317,9 @@ private void SendLevelUpdate() /// /// Broadcasts the current game level to a specific viewer. /// - /// The target recipient. - private void SendLevelUpdate(ICommonSession session) + private void SendLevelUpdate(EntityUid actor) { - SendMessage(new BlockGameMessages.BlockGameLevelUpdateMessage(Level), session); + SendMessage(new BlockGameMessages.BlockGameLevelUpdateMessage(Level), actor); } /// @@ -339,10 +333,9 @@ private void SendPointsUpdate() /// /// Broadcasts the current game score to a specific viewer. /// - /// The target recipient. - private void SendPointsUpdate(ICommonSession session) + private void SendPointsUpdate(EntityUid actor) { - SendMessage(new BlockGameMessages.BlockGameScoreUpdateMessage(Points), session); + SendMessage(new BlockGameMessages.BlockGameScoreUpdateMessage(Points), actor); } /// @@ -356,9 +349,8 @@ private void SendHighscoreUpdate() /// /// Broadcasts the current game high score positions to a specific viewer. /// - /// The target recipient. - private void SendHighscoreUpdate(ICommonSession session) + private void SendHighscoreUpdate(EntityUid actor) { - SendMessage(new BlockGameMessages.BlockGameHighScoreUpdateMessage(_arcadeSystem.GetLocalHighscores(), _arcadeSystem.GetGlobalHighscores()), session); + SendMessage(new BlockGameMessages.BlockGameHighScoreUpdateMessage(_arcadeSystem.GetLocalHighscores(), _arcadeSystem.GetGlobalHighscores()), actor); } } diff --git a/Content.Server/Arcade/BlockGame/BlockGame.cs b/Content.Server/Arcade/BlockGame/BlockGame.cs index 675776828f8..a6707af408e 100644 --- a/Content.Server/Arcade/BlockGame/BlockGame.cs +++ b/Content.Server/Arcade/BlockGame/BlockGame.cs @@ -10,8 +10,8 @@ public sealed partial class BlockGame { [Dependency] private readonly IEntityManager _entityManager = default!; [Dependency] private readonly IRobustRandom _random = default!; - private readonly ArcadeSystem _arcadeSystem = default!; - private readonly UserInterfaceSystem _uiSystem = default!; + private readonly ArcadeSystem _arcadeSystem; + private readonly UserInterfaceSystem _uiSystem; /// /// What entity is currently hosting this game of NT-BG. @@ -79,7 +79,7 @@ private void InvokeGameover() _gameOver = true; if (_entityManager.TryGetComponent(_owner, out var cabinet) - && _entityManager.TryGetComponent(cabinet.Player?.AttachedEntity, out var meta)) + && _entityManager.TryGetComponent(cabinet.Player, out var meta)) { _highScorePlacement = _arcadeSystem.RegisterHighScore(meta.EntityName, Points); SendHighscoreUpdate(); diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs index 5613d915444..75952b0a33b 100644 --- a/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs +++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeComponent.cs @@ -13,10 +13,10 @@ public sealed partial class BlockGameArcadeComponent : Component /// /// The player currently playing the active session of NT-BG. /// - public ICommonSession? Player = null; + public EntityUid? Player = null; /// /// The players currently viewing (but not playing) the active session of NT-BG. /// - public readonly List Spectators = new(); + public readonly List Spectators = new(); } diff --git a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs index ad65c5cca6b..561cad8d7ee 100644 --- a/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs +++ b/Content.Server/Arcade/BlockGame/BlockGameArcadeSystem.cs @@ -37,14 +37,12 @@ public override void Update(float frameTime) } } - private void UpdatePlayerStatus(EntityUid uid, ICommonSession session, PlayerBoundUserInterface? bui = null, BlockGameArcadeComponent? blockGame = null) + private void UpdatePlayerStatus(EntityUid uid, EntityUid actor, BlockGameArcadeComponent? blockGame = null) { if (!Resolve(uid, ref blockGame)) return; - if (bui == null && !_uiSystem.TryGetUi(uid, BlockGameUiKey.Key, out bui)) - return; - _uiSystem.TrySendUiMessage(bui, new BlockGameMessages.BlockGameUserStatusMessage(blockGame.Player == session), session); + _uiSystem.ServerSendUiMessage(uid, BlockGameUiKey.Key, new BlockGameMessages.BlockGameUserStatusMessage(blockGame.Player == actor), actor); } private void OnComponentInit(EntityUid uid, BlockGameArcadeComponent component, ComponentInit args) @@ -54,33 +52,21 @@ private void OnComponentInit(EntityUid uid, BlockGameArcadeComponent component, private void OnAfterUIOpen(EntityUid uid, BlockGameArcadeComponent component, AfterActivatableUIOpenEvent args) { - if (!TryComp(args.User, out var actor)) - return; - if (!_uiSystem.TryGetUi(uid, BlockGameUiKey.Key, out var bui)) - return; - - var session = actor.PlayerSession; - if (!bui.SubscribedSessions.Contains(session)) - return; - if (component.Player == null) - component.Player = session; + component.Player = args.Actor; else - component.Spectators.Add(session); + component.Spectators.Add(args.Actor); - UpdatePlayerStatus(uid, session, bui, component); - component.Game?.UpdateNewPlayerUI(session); + UpdatePlayerStatus(uid, args.Actor, component); + component.Game?.UpdateNewPlayerUI(args.Actor); } private void OnAfterUiClose(EntityUid uid, BlockGameArcadeComponent component, BoundUIClosedEvent args) { - if (args.Session is not { } session) - return; - - if (component.Player != session) + if (component.Player != args.Actor) { - component.Spectators.Remove(session); - UpdatePlayerStatus(uid, session, blockGame: component); + component.Spectators.Remove(args.Actor); + UpdatePlayerStatus(uid, args.Actor, blockGame: component); return; } @@ -88,11 +74,11 @@ private void OnAfterUiClose(EntityUid uid, BlockGameArcadeComponent component, B if (component.Spectators.Count > 0) { component.Player = component.Spectators[0]; - component.Spectators.Remove(component.Player); - UpdatePlayerStatus(uid, component.Player, blockGame: component); + component.Spectators.Remove(component.Player.Value); + UpdatePlayerStatus(uid, component.Player.Value, blockGame: component); } - UpdatePlayerStatus(uid, temp, blockGame: component); + UpdatePlayerStatus(uid, temp.Value, blockGame: component); } private void OnBlockPowerChanged(EntityUid uid, BlockGameArcadeComponent component, ref PowerChangedEvent args) @@ -100,8 +86,7 @@ private void OnBlockPowerChanged(EntityUid uid, BlockGameArcadeComponent compone if (args.Powered) return; - if (_uiSystem.TryGetUi(uid, BlockGameUiKey.Key, out var bui)) - _uiSystem.CloseAll(bui); + _uiSystem.CloseUi(uid, BlockGameUiKey.Key); component.Player = null; component.Spectators.Clear(); } @@ -112,7 +97,7 @@ private void OnPlayerAction(EntityUid uid, BlockGameArcadeComponent component, B return; if (!BlockGameUiKey.Key.Equals(msg.UiKey)) return; - if (msg.Session != component.Player) + if (msg.Actor != component.Player) return; if (msg.PlayerAction == BlockGamePlayerAction.NewGame) diff --git a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs index a5ca626d131..07a4d044cab 100644 --- a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs +++ b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainArcadeSystem.cs @@ -77,8 +77,7 @@ private void OnSVPlayerAction(EntityUid uid, SpaceVillainArcadeComponent compone if (!TryComp(uid, out var power) || !power.Powered) return; - if (msg.Session.AttachedEntity != null) - RaiseLocalEvent(msg.Session.AttachedEntity.Value, new MoodEffectEvent("ArcadePlay")); + RaiseLocalEvent(EntityManager.GetEntity(msg.Entity), new MoodEffectEvent("ArcadePlay")); switch (msg.PlayerAction) { @@ -94,12 +93,10 @@ private void OnSVPlayerAction(EntityUid uid, SpaceVillainArcadeComponent compone _audioSystem.PlayPvs(component.NewGameSound, uid, AudioParams.Default.WithVolume(-4f)); component.Game = new SpaceVillainGame(uid, component, this); - if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui)) - _uiSystem.SendUiMessage(bui, component.Game.GenerateMetaDataMessage()); + _uiSystem.ServerSendUiMessage(uid, SpaceVillainArcadeUiKey.Key, component.Game.GenerateMetaDataMessage()); break; case PlayerAction.RequestData: - if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out bui)) - _uiSystem.SendUiMessage(bui, component.Game.GenerateMetaDataMessage()); + _uiSystem.ServerSendUiMessage(uid, SpaceVillainArcadeUiKey.Key, component.Game.GenerateMetaDataMessage()); break; } } @@ -114,7 +111,6 @@ private void OnSVillainPower(EntityUid uid, SpaceVillainArcadeComponent componen if (TryComp(uid, out var power) && power.Powered) return; - if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui)) - _uiSystem.CloseAll(bui); + _uiSystem.CloseUi(uid, SpaceVillainArcadeUiKey.Key); } } diff --git a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainGame.Ui.cs b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainGame.Ui.cs index 890e9888a79..ebcfb8e3f64 100644 --- a/Content.Server/Arcade/SpaceVillainGame/SpaceVillainGame.Ui.cs +++ b/Content.Server/Arcade/SpaceVillainGame/SpaceVillainGame.Ui.cs @@ -9,8 +9,7 @@ public sealed partial class SpaceVillainGame /// private void UpdateUi(EntityUid uid, bool metadata = false) { - if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui)) - _uiSystem.SendUiMessage(bui, metadata ? GenerateMetaDataMessage() : GenerateUpdateMessage()); + _uiSystem.ServerSendUiMessage(uid, SpaceVillainArcadeUiKey.Key, metadata ? GenerateMetaDataMessage() : GenerateUpdateMessage()); } private void UpdateUi(EntityUid uid, string message1, string message2, bool metadata = false) diff --git a/Content.Server/Atmos/Components/BreathToolComponent.cs b/Content.Server/Atmos/Components/BreathToolComponent.cs index f3688ef7ffc..ae17a5d872f 100644 --- a/Content.Server/Atmos/Components/BreathToolComponent.cs +++ b/Content.Server/Atmos/Components/BreathToolComponent.cs @@ -12,9 +12,10 @@ public sealed partial class BreathToolComponent : Component /// /// Tool is functional only in allowed slots /// - [DataField("allowedSlots")] + [DataField] public SlotFlags AllowedSlots = SlotFlags.MASK | SlotFlags.HEAD; public bool IsFunctional; + public EntityUid? ConnectedInternalsEntity; } } diff --git a/Content.Server/Atmos/Components/FlammableComponent.cs b/Content.Server/Atmos/Components/FlammableComponent.cs index 33a163228f1..9f39af540dd 100644 --- a/Content.Server/Atmos/Components/FlammableComponent.cs +++ b/Content.Server/Atmos/Components/FlammableComponent.cs @@ -11,49 +11,65 @@ public sealed partial class FlammableComponent : Component [ViewVariables(VVAccess.ReadWrite)] [DataField] - public bool OnFire { get; set; } + public bool OnFire; [ViewVariables(VVAccess.ReadWrite)] [DataField] - public float FireStacks { get; set; } + public float FireStacks; [ViewVariables(VVAccess.ReadWrite)] - [DataField("fireSpread")] + [DataField] + public float MaximumFireStacks = 10f; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float MinimumFireStacks = -10f; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public string FlammableFixtureID = "flammable"; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public float MinIgnitionTemperature = 373.15f; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] public bool FireSpread { get; private set; } = false; [ViewVariables(VVAccess.ReadWrite)] - [DataField("canResistFire")] + [DataField] public bool CanResistFire { get; private set; } = false; - [DataField("damage", required: true)] + [DataField(required: true)] [ViewVariables(VVAccess.ReadWrite)] public DamageSpecifier Damage = new(); // Empty by default, we don't want any funny NREs. /// /// Used for the fixture created to handle passing firestacks when two flammable objects collide. /// - [DataField("flammableCollisionShape")] + [DataField] public IPhysShape FlammableCollisionShape = new PhysShapeCircle(0.35f); /// /// Should the component be set on fire by interactions with isHot entities /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("alwaysCombustible")] + [DataField] public bool AlwaysCombustible = false; /// /// Can the component anyhow lose its FireStacks? /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("canExtinguish")] + [DataField] public bool CanExtinguish = true; /// /// How many firestacks should be applied to component when being set on fire? /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("firestacksOnIgnite")] + [DataField] public float FirestacksOnIgnite = 2.0f; /// diff --git a/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs index 9d533f6ec4d..98feb433468 100644 --- a/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs +++ b/Content.Server/Atmos/Components/GasMixtureHolderComponent.cs @@ -1,4 +1,6 @@ -namespace Content.Server.Atmos.Components +using Content.Shared.Atmos; + +namespace Content.Server.Atmos.Components { [RegisterComponent] public sealed partial class GasMixtureHolderComponent : Component, IGasMixtureHolder diff --git a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs index 6bdef901d44..bdd05e78494 100644 --- a/Content.Server/Atmos/Components/MapAtmosphereComponent.cs +++ b/Content.Server/Atmos/Components/MapAtmosphereComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.EntitySystems; diff --git a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs index 758fde88f13..5d040cd7b37 100644 --- a/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs +++ b/Content.Server/Atmos/Consoles/AtmosAlertsComputerSystem.cs @@ -49,7 +49,7 @@ public override void Initialize() SubscribeLocalEvent(OnDeviceAnchorChanged); } - #region Event handling + #region Event handling private void OnConsoleInit(EntityUid uid, AtmosAlertsComputerComponent component, ComponentInit args) { @@ -197,7 +197,7 @@ public void UpdateUIState var focusAlarmData = GetFocusAlarmData(uid, GetEntity(component.FocusDevice), gridUid); // Set the UI state - _uiSystem.TrySetUiState(uid, AtmosAlertsComputerUiKey.Key, + _uiSystem.SetUiState(uid, AtmosAlertsComputerUiKey.Key, new AtmosAlertsComputerBoundInterfaceState(airAlarmStateData, fireAlarmStateData, focusAlarmData)); } diff --git a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs index 152fba8fc4d..cd07da71127 100644 --- a/Content.Server/Atmos/EntitySystems/AirtightSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AirtightSystem.cs @@ -12,6 +12,7 @@ public sealed class AirtightSystem : EntitySystem [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; [Dependency] private readonly ExplosionSystem _explosionSystem = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; public override void Initialize() { @@ -24,16 +25,19 @@ public override void Initialize() private void OnAirtightInit(Entity airtight, ref ComponentInit args) { - var xform = EntityManager.GetComponent(airtight); - - if (airtight.Comp.FixAirBlockedDirectionInitialize) + // TODO AIRTIGHT what FixAirBlockedDirectionInitialize even for? + if (!airtight.Comp.FixAirBlockedDirectionInitialize) { - var moveEvent = new MoveEvent(airtight, default, default, Angle.Zero, xform.LocalRotation, xform, false); - if (AirtightMove(airtight, ref moveEvent)) - return; + UpdatePosition(airtight); + return; } - UpdatePosition(airtight); + var xform = Transform(airtight); + airtight.Comp.CurrentAirBlockedDirection = + (int) Rotate((AtmosDirection) airtight.Comp.InitialAirBlockedDirection, xform.LocalRotation); + UpdatePosition(airtight, xform); + var airtightEv = new AirtightChanged(airtight, airtight, false, default); + RaiseLocalEvent(airtight, ref airtightEv, true); } private void OnAirtightShutdown(Entity airtight, ref ComponentShutdown args) @@ -41,13 +45,8 @@ private void OnAirtightShutdown(Entity airtight, ref Componen var xform = Transform(airtight); // If the grid is deleting no point updating atmos. - if (HasComp(xform.GridUid) && - MetaData(xform.GridUid.Value).EntityLifeStage > EntityLifeStage.MapInitialized) - { - return; - } - - SetAirblocked(airtight, false, xform); + if (xform.GridUid != null && LifeStage(xform.GridUid.Value) <= EntityLifeStage.MapInitialized) + SetAirblocked(airtight, false, xform); } private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight, ref AnchorStateChangedEvent args) @@ -59,12 +58,14 @@ private void OnAirtightPositionChanged(EntityUid uid, AirtightComponent airtight var gridId = xform.GridUid; var coords = xform.Coordinates; - - var tilePos = grid.TileIndicesFor(coords); + var tilePos = _mapSystem.TileIndicesFor(gridId.Value, grid, coords); // Update and invalidate new position. airtight.LastPosition = (gridId.Value, tilePos); InvalidatePosition(gridId.Value, tilePos); + + var airtightEv = new AirtightChanged(uid, airtight, false, (gridId.Value, tilePos)); + RaiseLocalEvent(uid, ref airtightEv, true); } private void OnAirtightReAnchor(EntityUid uid, AirtightComponent airtight, ref ReAnchorEvent args) @@ -74,24 +75,20 @@ private void OnAirtightReAnchor(EntityUid uid, AirtightComponent airtight, ref R // Update and invalidate new position. airtight.LastPosition = (gridId, args.TilePos); InvalidatePosition(gridId, args.TilePos); - } - } - private void OnAirtightMoved(Entity airtight, ref MoveEvent ev) - { - AirtightMove(airtight, ref ev); + var airtightEv = new AirtightChanged(uid, airtight, false, (gridId, args.TilePos)); + RaiseLocalEvent(uid, ref airtightEv, true); + } } - private bool AirtightMove(Entity ent, ref MoveEvent ev) + private void OnAirtightMoved(Entity ent, ref MoveEvent ev) { var (owner, airtight) = ent; - airtight.CurrentAirBlockedDirection = (int) Rotate((AtmosDirection)airtight.InitialAirBlockedDirection, ev.NewRotation); var pos = airtight.LastPosition; UpdatePosition(ent, ev.Component); - var airtightEv = new AirtightChanged(owner, airtight, pos); + var airtightEv = new AirtightChanged(owner, airtight, false, pos); RaiseLocalEvent(owner, ref airtightEv, true); - return true; } public void SetAirblocked(Entity airtight, bool airblocked, TransformComponent? xform = null) @@ -105,7 +102,7 @@ public void SetAirblocked(Entity airtight, bool airblocked, T var pos = airtight.Comp.LastPosition; airtight.Comp.AirBlocked = airblocked; UpdatePosition(airtight, xform); - var airtightEv = new AirtightChanged(airtight, airtight, pos); + var airtightEv = new AirtightChanged(airtight, airtight, true, pos); RaiseLocalEvent(airtight, ref airtightEv, true); } @@ -152,7 +149,13 @@ private AtmosDirection Rotate(AtmosDirection myDirection, Angle myAngle) } } + /// + /// Raised upon the airtight status being changed via anchoring, movement, etc. + /// + /// + /// + /// Whether the changed + /// [ByRefEvent] - public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight, - (EntityUid Grid, Vector2i Tile) Position); + public readonly record struct AirtightChanged(EntityUid Entity, AirtightComponent Airtight, bool AirBlockedChanged, (EntityUid Grid, Vector2i Tile) Position); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs index 9590b9aa548..39469e993f0 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosExposedSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Atmos; using Robust.Shared.Map; namespace Content.Server.Atmos.EntitySystems diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs index 614d550c2f7..df31db6ba07 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.API.cs @@ -1,10 +1,10 @@ using System.Linq; using Content.Server.Atmos.Components; using Content.Server.Atmos.Piping.Components; -using Content.Server.Atmos.Reactions; using Content.Server.NodeContainer.NodeGroups; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.Reactions; using Robust.Shared.Map.Components; using Robust.Shared.Utility; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs index f8ee4f41923..70c4639e481 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Gases.cs @@ -2,6 +2,7 @@ using System.Runtime.CompilerServices; using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using Robust.Shared.Prototypes; using DependencyAttribute = Robust.Shared.IoC.DependencyAttribute; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs index 4b9ef49a406..3830745f68c 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.GridAtmosphere.cs @@ -2,6 +2,7 @@ using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.Reactions; using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Utility; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index 7163b4cd44c..db952237338 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -2,6 +2,7 @@ using Content.Server.Atmos.Reactions; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; +using Content.Shared.Atmos.Reactions; using Content.Shared.Audio; using Content.Shared.Database; using Robust.Shared.Audio; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs index 25b3b801f76..4b77d9c70da 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Map.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos.Components; +using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Robust.Shared.GameStates; using Robust.Shared.Map.Components; diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index 7890b7751ac..ec0e7b07092 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -12,6 +12,7 @@ using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Interaction; +using Content.Shared.Inventory; using Content.Shared.Physics; using Content.Shared.Popups; using Content.Shared.Projectiles; @@ -42,18 +43,18 @@ public sealed class FlammableSystem : EntitySystem [Dependency] private readonly AlertsSystem _alertsSystem = default!; [Dependency] private readonly FixtureSystem _fixture = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly UseDelaySystem _useDelay = default!; [Dependency] private readonly AudioSystem _audio = default!; [Dependency] private readonly IRobustRandom _random = default!; - public const float MinimumFireStacks = -10f; - public const float MaximumFireStacks = 20f; - private const float UpdateTime = 1f; + private EntityQuery _inventoryQuery; + private EntityQuery _physicsQuery; - public const float MinIgnitionTemperature = 373.15f; - public const string FlammableFixtureID = "flammable"; + // This should probably be moved to the component, requires a rewrite, all fires tick at the same time + private const float UpdateTime = 1f; private float _timer; @@ -63,6 +64,9 @@ public override void Initialize() { UpdatesAfter.Add(typeof(AtmosphereSystem)); + _inventoryQuery = GetEntityQuery(); + _physicsQuery = GetEntityQuery(); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnCollide); @@ -131,7 +135,7 @@ private void OnMapInit(EntityUid uid, FlammableComponent component, MapInitEvent if (!TryComp(uid, out var body)) return; - _fixture.TryCreateFixture(uid, component.FlammableCollisionShape, FlammableFixtureID, hard: false, + _fixture.TryCreateFixture(uid, component.FlammableCollisionShape, component.FlammableFixtureID, hard: false, collisionMask: (int) CollisionGroup.FullTileLayer, body: body); } @@ -189,7 +193,7 @@ private void OnCollide(EntityUid uid, FlammableComponent flammable, ref StartCol // Normal hard collisions, though this isn't generally possible since most flammable things are mobs // which don't collide with one another, shouldn't work here. - if (args.OtherFixtureId != FlammableFixtureID && args.OurFixtureId != FlammableFixtureID) + if (args.OtherFixtureId != flammable.FlammableFixtureID && args.OurFixtureId != flammable.FlammableFixtureID) return; if (!flammable.FireSpread) @@ -204,7 +208,17 @@ private void OnCollide(EntityUid uid, FlammableComponent flammable, ref StartCol if (flammable.OnFire && otherFlammable.OnFire) { // Both are on fire -> equalize fire stacks. - var avg = (flammable.FireStacks + otherFlammable.FireStacks) / 2; + // Weight each thing's firestacks by its mass + var mass1 = 1f; + var mass2 = 1f; + if (_physicsQuery.TryComp(uid, out var physics) && _physicsQuery.TryComp(otherUid, out var otherPhys)) + { + mass1 = physics.Mass; + mass2 = otherPhys.Mass; + } + + var total = mass1 + mass2; + var avg = (flammable.FireStacks * mass1 + otherFlammable.FireStacks * mass2) / total; flammable.FireStacks = flammable.CanExtinguish ? avg : Math.Max(flammable.FireStacks, avg); otherFlammable.FireStacks = otherFlammable.CanExtinguish ? avg : Math.Max(otherFlammable.FireStacks, avg); UpdateAppearance(uid, flammable); @@ -213,25 +227,24 @@ private void OnCollide(EntityUid uid, FlammableComponent flammable, ref StartCol } // Only one is on fire -> attempt to spread the fire. - if (flammable.OnFire) + var (srcUid, srcFlammable, destUid, destFlammable) = flammable.OnFire + ? (uid, flammable, otherUid, otherFlammable) + : (otherUid, otherFlammable, uid, flammable); + + // if the thing on fire has less mass, spread less firestacks and vice versa + var ratio = 0.5f; + if (_physicsQuery.TryComp(srcUid, out var srcPhysics) && _physicsQuery.TryComp(destUid, out var destPhys)) { - otherFlammable.FireStacks += flammable.FireStacks / 2; - Ignite(otherUid, uid, otherFlammable); - if (flammable.CanExtinguish) - { - flammable.FireStacks /= 2; - UpdateAppearance(uid, flammable); - } + ratio *= srcPhysics.Mass / destPhys.Mass; } - else + + var lost = srcFlammable.FireStacks * ratio; + destFlammable.FireStacks += lost; + Ignite(destUid, srcUid, destFlammable); + if (srcFlammable.CanExtinguish) { - flammable.FireStacks += otherFlammable.FireStacks / 2; - Ignite(uid, otherUid, flammable); - if (otherFlammable.CanExtinguish) - { - otherFlammable.FireStacks /= 2; - UpdateAppearance(otherUid, otherFlammable); - } + srcFlammable.FireStacks -= lost; + UpdateAppearance(srcUid, srcFlammable); } } @@ -242,7 +255,7 @@ private void OnIsHot(EntityUid uid, FlammableComponent flammable, IsHotEvent arg private void OnTileFire(Entity ent, ref TileFireEvent args) { - var tempDelta = args.Temperature - MinIgnitionTemperature; + var tempDelta = args.Temperature - ent.Comp.MinIgnitionTemperature; _fireEvents.TryGetValue(ent, out var maxTemp); @@ -278,7 +291,7 @@ public void AdjustFireStacks(EntityUid uid, float relativeFireStacks, FlammableC if (relativeFireStacks > 0) relativeFireStacks *= flammable.FireStackIncreaseMultiplier; - flammable.FireStacks = MathF.Min(MathF.Max(MinimumFireStacks, flammable.FireStacks + relativeFireStacks), MaximumFireStacks); + flammable.FireStacks = MathF.Min(MathF.Max(flammable.MinimumFireStacks, flammable.FireStacks + relativeFireStacks), flammable.MaximumFireStacks); if (flammable.OnFire && flammable.FireStacks <= 0) Extinguish(uid, flammable); @@ -429,15 +442,20 @@ public override void Update(float frameTime) continue; } - EnsureComp(uid); - _ignitionSourceSystem.SetIgnited(uid); - - var damageScale = MathF.Min( flammable.FireStacks, 5); + var source = EnsureComp(uid); + _ignitionSourceSystem.SetIgnited((uid, source)); if (TryComp(uid, out TemperatureComponent? temp)) - _temperatureSystem.ChangeHeat(uid, 12500 * damageScale, false, temp); + _temperatureSystem.ChangeHeat(uid, 12500 * flammable.FireStacks, false, temp); + + var ev = new GetFireProtectionEvent(); + // let the thing on fire handle it + RaiseLocalEvent(uid, ref ev); + // and whatever it's wearing + if (_inventoryQuery.TryComp(uid, out var inv)) + _inventory.RelayEvent((uid, inv), ref ev); - _damageableSystem.TryChangeDamage(uid, flammable.Damage * damageScale, interruptsDoAfters: false); + _damageableSystem.TryChangeDamage(uid, flammable.Damage * flammable.FireStacks * ev.Multiplier, interruptsDoAfters: false); AdjustFireStacks(uid, flammable.FirestackFade * (flammable.Resisting ? 10f : 1f), flammable); } diff --git a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs index 552ee142329..65977f8c140 100644 --- a/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasAnalyzerSystem.cs @@ -95,9 +95,9 @@ private void ActivateAnalyzer(EntityUid uid, GasAnalyzerComponent component, Ent component.Enabled = true; Dirty(component); UpdateAppearance(uid, component); - if(!HasComp(uid)) - AddComp(uid); + EnsureComp(uid); UpdateAnalyzer(uid, component); + OpenUserInterface(uid, user, component); } /// @@ -118,8 +118,7 @@ private void DisableAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nu if (!Resolve(uid, ref component)) return; - if (user != null && TryComp(user, out var actor)) - _userInterface.TryClose(uid, GasAnalyzerUiKey.Key, actor.PlayerSession); + _userInterface.CloseUi(uid, GasAnalyzerUiKey.Key, user); component.Enabled = false; Dirty(component); @@ -132,8 +131,6 @@ private void DisableAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nu /// private void OnDisabledMessage(EntityUid uid, GasAnalyzerComponent component, GasAnalyzerDisableMessage message) { - if (message.Session.AttachedEntity is not {Valid: true}) - return; DisableAnalyzer(uid, component); } @@ -142,10 +139,7 @@ private void OpenUserInterface(EntityUid uid, EntityUid user, GasAnalyzerCompone if (!Resolve(uid, ref component, false)) return; - if (!TryComp(user, out var actor)) - return; - - _userInterface.TryOpen(uid, GasAnalyzerUiKey.Key, actor.PlayerSession); + _userInterface.OpenUi(uid, GasAnalyzerUiKey.Key, user); } /// @@ -169,7 +163,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul // Check if position is out of range => don't update and disable if (!component.LastPosition.Value.InRange(EntityManager, _transform, userPos, SharedInteractionSystem.InteractionRange)) { - if(component.User is { } userId && component.Enabled) + if (component.User is { } userId && component.Enabled) _popup.PopupEntity(Loc.GetString("gas-analyzer-shutoff"), userId, userId); DisableAnalyzer(uid, component, component.User); return false; @@ -182,13 +176,13 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul var tileMixture = _atmo.GetContainingMixture(uid, true); if (tileMixture != null) { - gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), tileMixture.Pressure, tileMixture.Temperature, + gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), tileMixture.Volume, tileMixture.Pressure, tileMixture.Temperature, GenerateGasEntryArray(tileMixture))); } else { // No gases were found - gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), 0f, 0f)); + gasMixList.Add(new GasMixEntry(Loc.GetString("gas-analyzer-window-environment-tab-label"), 0f, 0f, 0f)); } var deviceFlipped = false; @@ -209,8 +203,8 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul { foreach (var mixes in ev.GasMixtures) { - if(mixes.Value != null) - gasMixList.Add(new GasMixEntry(mixes.Key, mixes.Value.Pressure, mixes.Value.Temperature, GenerateGasEntryArray(mixes.Value))); + if (mixes.Item2 != null) + gasMixList.Add(new GasMixEntry(mixes.Item1, mixes.Item2.Volume, mixes.Item2.Pressure, mixes.Item2.Temperature, GenerateGasEntryArray(mixes.Item2))); } deviceFlipped = ev.DeviceFlipped; @@ -223,7 +217,16 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul foreach (var pair in node.Nodes) { if (pair.Value is PipeNode pipeNode) - gasMixList.Add(new GasMixEntry(pair.Key, pipeNode.Air.Pressure, pipeNode.Air.Temperature, GenerateGasEntryArray(pipeNode.Air))); + { + // check if the volume is zero for some reason so we don't divide by zero + if (pipeNode.Air.Volume == 0f) + continue; + // only display the gas in the analyzed pipe element, not the whole system + var pipeAir = pipeNode.Air.Clone(); + pipeAir.Multiply(pipeNode.Volume / pipeNode.Air.Volume); + pipeAir.Volume = pipeNode.Volume; + gasMixList.Add(new GasMixEntry(pair.Key, pipeAir.Volume, pipeAir.Pressure, pipeAir.Temperature, GenerateGasEntryArray(pipeAir))); + } } } } @@ -233,7 +236,7 @@ private bool UpdateAnalyzer(EntityUid uid, GasAnalyzerComponent? component = nul if (gasMixList.Count == 0) return false; - _userInterface.TrySendUiMessage(uid, GasAnalyzerUiKey.Key, + _userInterface.ServerSendUiMessage(uid, GasAnalyzerUiKey.Key, new GasAnalyzerUserMessage(gasMixList.ToArray(), component.Target != null ? Name(component.Target.Value) : string.Empty, GetNetEntity(component.Target) ?? NetEntity.Invalid, @@ -286,9 +289,9 @@ private GasEntry[] GenerateGasEntryArray(GasMixture? mixture) public sealed class GasAnalyzerScanEvent : EntityEventArgs { /// - /// Key is the mix name (ex "pipe", "inlet", "filter"), value is the pipe direction and GasMixture. Add all mixes that should be reported when scanned. + /// The string is for the name (ex "pipe", "inlet", "filter"), GasMixture for the corresponding gas mix. Add all mixes that should be reported when scanned. /// - public Dictionary? GasMixtures; + public List<(string, GasMixture?)>? GasMixtures; /// /// If the device is flipped. Flipped is defined as when the inline input is 90 degrees CW to the side input diff --git a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs index 80842416e8b..07594820fcc 100644 --- a/Content.Server/Atmos/EntitySystems/GasTankSystem.cs +++ b/Content.Server/Atmos/EntitySystems/GasTankSystem.cs @@ -75,7 +75,7 @@ private void OnGasTankSetPressure(Entity ent, ref GasTankSetPr public void UpdateUserInterface(Entity ent, bool initialUpdate = false) { var (owner, component) = ent; - _ui.TrySetUiState(owner, SharedGasTankUiKey.Key, + _ui.SetUiState(owner, SharedGasTankUiKey.Key, new GasTankBoundUserInterfaceState { TankPressure = component.Air?.Pressure ?? 0, @@ -359,7 +359,8 @@ public void CheckStatus(Entity ent) /// private void OnAnalyzed(EntityUid uid, GasTankComponent component, GasAnalyzerScanEvent args) { - args.GasMixtures = new Dictionary { {Name(uid), component.Air} }; + args.GasMixtures ??= new List<(string, GasMixture?)>(); + args.GasMixtures.Add((Name(uid), component.Air)); } private void OnGasTankPrice(EntityUid uid, GasTankComponent component, ref PriceCalculationEvent args) diff --git a/Content.Server/Atmos/IGasMixtureHolder.cs b/Content.Server/Atmos/IGasMixtureHolder.cs index 96efa6b9836..65d7ba69a76 100644 --- a/Content.Server/Atmos/IGasMixtureHolder.cs +++ b/Content.Server/Atmos/IGasMixtureHolder.cs @@ -1,4 +1,6 @@ -namespace Content.Server.Atmos +using Content.Shared.Atmos; + +namespace Content.Server.Atmos { public interface IGasMixtureHolder { diff --git a/Content.Server/Atmos/IGasReactionEffect.cs b/Content.Server/Atmos/IGasReactionEffect.cs index bd229694bb1..9fc9231908c 100644 --- a/Content.Server/Atmos/IGasReactionEffect.cs +++ b/Content.Server/Atmos/IGasReactionEffect.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Atmos.Reactions; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; namespace Content.Server.Atmos { diff --git a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs index 7030d607a6e..93f704fe21b 100644 --- a/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs +++ b/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs @@ -24,8 +24,6 @@ public sealed partial class AirAlarmComponent : Component public readonly Dictionary ScrubberData = new(); public readonly Dictionary SensorData = new(); - public HashSet ActivePlayers = new(); - public bool CanSync = true; /// diff --git a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs index 240f21ad42e..04a9023c1dd 100644 --- a/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs +++ b/Content.Server/Atmos/Monitor/Systems/AirAlarmSystem.cs @@ -223,8 +223,7 @@ private void OnPowerChanged(EntityUid uid, AirAlarmComponent component, ref Powe private void OnClose(EntityUid uid, AirAlarmComponent component, BoundUIClosedEvent args) { - component.ActivePlayers.Remove(args.Session.UserId); - if (component.ActivePlayers.Count == 0) + if (!_ui.IsUiOpen(uid, SharedAirAlarmInterfaceKey.Key)) RemoveActiveInterface(uid); } @@ -247,9 +246,6 @@ private void OnShutdown(EntityUid uid, AirAlarmComponent component, ComponentShu private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWorldEvent args) { - if (!TryComp(args.User, out var actor)) - return; - if (TryComp(uid, out var panel) && panel.Open) { args.Handled = false; @@ -259,10 +255,7 @@ private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWo if (!this.IsPowered(uid, EntityManager)) return; - var ui = _ui.GetUiOrNull(uid, SharedAirAlarmInterfaceKey.Key); - if (ui != null) - _ui.OpenUi(ui, actor.PlayerSession); - component.ActivePlayers.Add(actor.PlayerSession.UserId); + _ui.OpenUi(uid, SharedAirAlarmInterfaceKey.Key, args.User); AddActiveInterface(uid); SyncAllDevices(uid); UpdateUI(uid, component); @@ -270,7 +263,7 @@ private void OnActivate(EntityUid uid, AirAlarmComponent component, ActivateInWo private void OnResyncAll(EntityUid uid, AirAlarmComponent component, AirAlarmResyncAllDevicesMessage args) { - if (!AccessCheck(uid, args.Session.AttachedEntity, component)) + if (!AccessCheck(uid, args.Actor, component)) { return; } @@ -285,7 +278,7 @@ private void OnResyncAll(EntityUid uid, AirAlarmComponent component, AirAlarmRes private void OnUpdateAlarmMode(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmModeMessage args) { - if (AccessCheck(uid, args.Session.AttachedEntity, component)) + if (AccessCheck(uid, args.Actor, component)) { var addr = string.Empty; if (TryComp(uid, out var netConn)) @@ -309,7 +302,7 @@ private void OnUpdateAutoMode(EntityUid uid, AirAlarmComponent component, AirAla private void OnUpdateThreshold(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateAlarmThresholdMessage args) { - if (AccessCheck(uid, args.Session.AttachedEntity, component)) + if (AccessCheck(uid, args.Actor, component)) SetThreshold(uid, args.Address, args.Type, args.Threshold, args.Gas); else UpdateUI(uid, component); @@ -317,7 +310,7 @@ private void OnUpdateThreshold(EntityUid uid, AirAlarmComponent component, AirAl private void OnUpdateDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmUpdateDeviceDataMessage args) { - if (AccessCheck(uid, args.Session.AttachedEntity, component) + if (AccessCheck(uid, args.Actor, component) && _deviceList.ExistsInDeviceList(uid, args.Address)) { SetDeviceData(uid, args.Address, args.Data); @@ -330,7 +323,7 @@ private void OnUpdateDeviceData(EntityUid uid, AirAlarmComponent component, AirA private void OnCopyDeviceData(EntityUid uid, AirAlarmComponent component, AirAlarmCopyDeviceDataMessage args) { - if (!AccessCheck(uid, args.Session.AttachedEntity, component)) + if (!AccessCheck(uid, args.Actor, component)) { UpdateUI(uid, component); return; @@ -377,7 +370,7 @@ private bool AccessCheck(EntityUid uid, EntityUid? user, AirAlarmComponent? comp private void OnAtmosAlarm(EntityUid uid, AirAlarmComponent component, AtmosAlarmEvent args) { - if (component.ActivePlayers.Count != 0) + if (_ui.IsUiOpen(uid, SharedAirAlarmInterfaceKey.Key)) { SyncAllDevices(uid); } @@ -571,7 +564,7 @@ private void RemoveActiveInterface(EntityUid uid) /// private void ForceCloseAllInterfaces(EntityUid uid) { - _ui.TryCloseAll(uid, SharedAirAlarmInterfaceKey.Key); + _ui.CloseUi(uid, SharedAirAlarmInterfaceKey.Key); } private void OnAtmosUpdate(EntityUid uid, AirAlarmComponent alarm, ref AtmosDeviceUpdateEvent args) @@ -654,7 +647,7 @@ public void UpdateUI(EntityUid uid, AirAlarmComponent? alarm = null, DeviceNetwo highestAlarm = AtmosAlarmType.Normal; } - _ui.TrySetUiState( + _ui.SetUiState( uid, SharedAirAlarmInterfaceKey.Key, new AirAlarmUIState(devNet.Address, deviceCount, pressure, temperature, dataToSend, alarm.CurrentMode, alarm.CurrentTab, highestAlarm.Value, alarm.AutoMode)); diff --git a/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs index fb7ee6d5cf9..315362383c3 100644 --- a/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs +++ b/Content.Server/Atmos/Piping/Binary/Components/GasPortComponent.cs @@ -1,3 +1,5 @@ +using Content.Shared.Atmos; + namespace Content.Server.Atmos.Piping.Binary.Components { [RegisterComponent] diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs index af25d04df92..83b7b67ba46 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasPressurePumpSystem.cs @@ -98,7 +98,7 @@ private void OnPumpLeaveAtmosphere(EntityUid uid, GasPressurePumpComponent pump, UpdateAppearance(uid, pump); DirtyUI(uid, pump); - _userInterfaceSystem.TryCloseAll(uid, GasPressurePumpUiKey.Key); + _userInterfaceSystem.CloseUi(uid, GasPressurePumpUiKey.Key); } private void OnPumpActivate(EntityUid uid, GasPressurePumpComponent pump, ActivateInWorldEvent args) @@ -108,7 +108,7 @@ private void OnPumpActivate(EntityUid uid, GasPressurePumpComponent pump, Activa if (Transform(uid).Anchored) { - _userInterfaceSystem.TryOpen(uid, GasPressurePumpUiKey.Key, actor.PlayerSession); + _userInterfaceSystem.OpenUi(uid, GasPressurePumpUiKey.Key, actor.PlayerSession); DirtyUI(uid, pump); } else @@ -123,7 +123,7 @@ private void OnToggleStatusMessage(EntityUid uid, GasPressurePumpComponent pump, { pump.Enabled = args.Enabled; _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); + $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); DirtyUI(uid, pump); UpdateAppearance(uid, pump); } @@ -132,7 +132,7 @@ private void OnOutputPressureChangeMessage(EntityUid uid, GasPressurePumpCompone { pump.TargetPressure = Math.Clamp(args.Pressure, 0f, Atmospherics.MaxOutputPressure); _adminLogger.Add(LogType.AtmosPressureChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa"); + $"{ToPrettyString(args.Actor):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa"); DirtyUI(uid, pump); } @@ -142,7 +142,7 @@ private void DirtyUI(EntityUid uid, GasPressurePumpComponent? pump) if (!Resolve(uid, ref pump)) return; - _userInterfaceSystem.TrySetUiState(uid, GasPressurePumpUiKey.Key, + _userInterfaceSystem.SetUiState(uid, GasPressurePumpUiKey.Key, new GasPressurePumpBoundUserInterfaceState(EntityManager.GetComponent(uid).EntityName, pump.TargetPressure, pump.Enabled)); } diff --git a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs index e4767c4061a..cbcd1f4fa3b 100644 --- a/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs +++ b/Content.Server/Atmos/Piping/Binary/EntitySystems/GasVolumePumpSystem.cs @@ -128,7 +128,7 @@ private void OnVolumePumpLeaveAtmosphere(EntityUid uid, GasVolumePumpComponent p UpdateAppearance(uid, pump); DirtyUI(uid, pump); - _userInterfaceSystem.TryCloseAll(uid, GasVolumePumpUiKey.Key); + _userInterfaceSystem.CloseUi(uid, GasVolumePumpUiKey.Key); } private void OnPumpActivate(EntityUid uid, GasVolumePumpComponent pump, ActivateInWorldEvent args) @@ -138,7 +138,7 @@ private void OnPumpActivate(EntityUid uid, GasVolumePumpComponent pump, Activate if (Transform(uid).Anchored) { - _userInterfaceSystem.TryOpen(uid, GasVolumePumpUiKey.Key, actor.PlayerSession); + _userInterfaceSystem.OpenUi(uid, GasVolumePumpUiKey.Key, actor.PlayerSession); DirtyUI(uid, pump); } else @@ -153,7 +153,7 @@ private void OnToggleStatusMessage(EntityUid uid, GasVolumePumpComponent pump, G { pump.Enabled = args.Enabled; _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); + $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); DirtyUI(uid, pump); UpdateAppearance(uid, pump); } @@ -162,7 +162,7 @@ private void OnTransferRateChangeMessage(EntityUid uid, GasVolumePumpComponent p { pump.TransferRate = Math.Clamp(args.TransferRate, 0f, pump.MaxTransferRate); _adminLogger.Add(LogType.AtmosVolumeChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the transfer rate on {ToPrettyString(uid):device} to {args.TransferRate}"); + $"{ToPrettyString(args.Actor):player} set the transfer rate on {ToPrettyString(uid):device} to {args.TransferRate}"); DirtyUI(uid, pump); } @@ -171,7 +171,7 @@ private void DirtyUI(EntityUid uid, GasVolumePumpComponent? pump) if (!Resolve(uid, ref pump)) return; - _userInterfaceSystem.TrySetUiState(uid, GasVolumePumpUiKey.Key, + _userInterfaceSystem.SetUiState(uid, GasVolumePumpUiKey.Key, new GasVolumePumpBoundUserInterfaceState(Name(uid), pump.TransferRate, pump.Enabled)); } diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs index fbd42604694..007d304e98e 100644 --- a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs +++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasFilterSystem.cs @@ -73,7 +73,7 @@ private void OnFilterUpdated(EntityUid uid, GasFilterComponent filter, ref Atmos if (filter.FilteredGas.HasValue) { - var filteredOut = new GasMixture() {Temperature = removed.Temperature}; + var filteredOut = new GasMixture() { Temperature = removed.Temperature }; filteredOut.SetMoles(filter.FilteredGas.Value, removed.GetMoles(filter.FilteredGas.Value)); removed.SetMoles(filter.FilteredGas.Value, 0f); @@ -94,7 +94,7 @@ private void OnFilterLeaveAtmosphere(EntityUid uid, GasFilterComponent filter, r _ambientSoundSystem.SetAmbience(uid, false); DirtyUI(uid, filter); - _userInterfaceSystem.TryCloseAll(uid, GasFilterUiKey.Key); + _userInterfaceSystem.CloseUi(uid, GasFilterUiKey.Key); } private void OnFilterActivate(EntityUid uid, GasFilterComponent filter, ActivateInWorldEvent args) @@ -104,7 +104,7 @@ private void OnFilterActivate(EntityUid uid, GasFilterComponent filter, Activate if (EntityManager.GetComponent(uid).Anchored) { - _userInterfaceSystem.TryOpen(uid, GasFilterUiKey.Key, actor.PlayerSession); + _userInterfaceSystem.OpenUi(uid, GasFilterUiKey.Key, actor.PlayerSession); DirtyUI(uid, filter); } else @@ -120,7 +120,7 @@ private void DirtyUI(EntityUid uid, GasFilterComponent? filter) if (!Resolve(uid, ref filter)) return; - _userInterfaceSystem.TrySetUiState(uid, GasFilterUiKey.Key, + _userInterfaceSystem.SetUiState(uid, GasFilterUiKey.Key, new GasFilterBoundUserInterfaceState(MetaData(uid).EntityName, filter.TransferRate, filter.Enabled, filter.FilteredGas)); } @@ -136,7 +136,7 @@ private void OnToggleStatusMessage(EntityUid uid, GasFilterComponent filter, Gas { filter.Enabled = args.Enabled; _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); + $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); DirtyUI(uid, filter); UpdateAppearance(uid, filter); } @@ -145,7 +145,7 @@ private void OnTransferRateChangeMessage(EntityUid uid, GasFilterComponent filte { filter.TransferRate = Math.Clamp(args.Rate, 0f, filter.MaxTransferRate); _adminLogger.Add(LogType.AtmosVolumeChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the transfer rate on {ToPrettyString(uid):device} to {args.Rate}"); + $"{ToPrettyString(args.Actor):player} set the transfer rate on {ToPrettyString(uid):device} to {args.Rate}"); DirtyUI(uid, filter); } @@ -158,7 +158,7 @@ private void OnSelectGasMessage(EntityUid uid, GasFilterComponent filter, GasFil { filter.FilteredGas = parsedGas; _adminLogger.Add(LogType.AtmosFilterChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the filter on {ToPrettyString(uid):device} to {parsedGas.ToString()}"); + $"{ToPrettyString(args.Actor):player} set the filter on {ToPrettyString(uid):device} to {parsedGas.ToString()}"); DirtyUI(uid, filter); } else @@ -170,7 +170,7 @@ private void OnSelectGasMessage(EntityUid uid, GasFilterComponent filter, GasFil { filter.FilteredGas = null; _adminLogger.Add(LogType.AtmosFilterChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the filter on {ToPrettyString(uid):device} to none"); + $"{ToPrettyString(args.Actor):player} set the filter on {ToPrettyString(uid):device} to none"); DirtyUI(uid, filter); } } @@ -180,17 +180,30 @@ private void OnSelectGasMessage(EntityUid uid, GasFilterComponent filter, GasFil /// private void OnFilterAnalyzed(EntityUid uid, GasFilterComponent component, GasAnalyzerScanEvent args) { - if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - args.GasMixtures ??= new Dictionary(); + args.GasMixtures ??= new List<(string, GasMixture?)>(); - if(_nodeContainer.TryGetNode(nodeContainer, component.InletName, out PipeNode? inlet)) - args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-inlet"), inlet.Air); - if(_nodeContainer.TryGetNode(nodeContainer, component.FilterName, out PipeNode? filterNode)) - args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-filter"), filterNode.Air); - if(_nodeContainer.TryGetNode(nodeContainer, component.OutletName, out PipeNode? outlet)) - args.GasMixtures.Add(Loc.GetString("gas-analyzer-window-text-outlet"), outlet.Air); + // multiply by volume fraction to make sure to send only the gas inside the analyzed pipe element, not the whole pipe system + if (_nodeContainer.TryGetNode(uid, component.InletName, out PipeNode? inlet) && inlet.Air.Volume != 0f) + { + var inletAirLocal = inlet.Air.Clone(); + inletAirLocal.Multiply(inlet.Volume / inlet.Air.Volume); + inletAirLocal.Volume = inlet.Volume; + args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-inlet"), inletAirLocal)); + } + if (_nodeContainer.TryGetNode(uid, component.FilterName, out PipeNode? filterNode) && filterNode.Air.Volume != 0f) + { + var filterNodeAirLocal = filterNode.Air.Clone(); + filterNodeAirLocal.Multiply(filterNode.Volume / filterNode.Air.Volume); + filterNodeAirLocal.Volume = filterNode.Volume; + args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-filter"), filterNodeAirLocal)); + } + if (_nodeContainer.TryGetNode(uid, component.OutletName, out PipeNode? outlet) && outlet.Air.Volume != 0f) + { + var outletAirLocal = outlet.Air.Clone(); + outletAirLocal.Multiply(outlet.Volume / outlet.Air.Volume); + outletAirLocal.Volume = outlet.Volume; + args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-outlet"), outletAirLocal)); + } args.DeviceFlipped = inlet != null && filterNode != null && inlet.CurrentPipeDirection.ToDirection() == filterNode.CurrentPipeDirection.ToDirection().GetClockwise90Degrees(); } diff --git a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs index ba8ebf3c9ae..4ab8572843b 100644 --- a/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs +++ b/Content.Server/Atmos/Piping/Trinary/EntitySystems/GasMixerSystem.cs @@ -134,7 +134,7 @@ private void OnMixerLeaveAtmosphere(EntityUid uid, GasMixerComponent mixer, ref DirtyUI(uid, mixer); UpdateAppearance(uid, mixer); - _userInterfaceSystem.TryCloseAll(uid, GasFilterUiKey.Key); + _userInterfaceSystem.CloseUi(uid, GasFilterUiKey.Key); } private void OnMixerActivate(EntityUid uid, GasMixerComponent mixer, ActivateInWorldEvent args) @@ -144,7 +144,7 @@ private void OnMixerActivate(EntityUid uid, GasMixerComponent mixer, ActivateInW if (Transform(uid).Anchored) { - _userInterfaceSystem.TryOpen(uid, GasMixerUiKey.Key, actor.PlayerSession); + _userInterfaceSystem.OpenUi(uid, GasMixerUiKey.Key, actor.PlayerSession); DirtyUI(uid, mixer); } else @@ -160,7 +160,7 @@ private void DirtyUI(EntityUid uid, GasMixerComponent? mixer) if (!Resolve(uid, ref mixer)) return; - _userInterfaceSystem.TrySetUiState(uid, GasMixerUiKey.Key, + _userInterfaceSystem.SetUiState(uid, GasMixerUiKey.Key, new GasMixerBoundUserInterfaceState(EntityManager.GetComponent(uid).EntityName, mixer.TargetPressure, mixer.Enabled, mixer.InletOneConcentration)); } @@ -176,7 +176,7 @@ private void OnToggleStatusMessage(EntityUid uid, GasMixerComponent mixer, GasMi { mixer.Enabled = args.Enabled; _adminLogger.Add(LogType.AtmosPowerChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); + $"{ToPrettyString(args.Actor):player} set the power on {ToPrettyString(uid):device} to {args.Enabled}"); DirtyUI(uid, mixer); UpdateAppearance(uid, mixer); } @@ -185,7 +185,7 @@ private void OnOutputPressureChangeMessage(EntityUid uid, GasMixerComponent mixe { mixer.TargetPressure = Math.Clamp(args.Pressure, 0f, mixer.MaxTargetPressure); _adminLogger.Add(LogType.AtmosPressureChanged, LogImpact.Medium, - $"{ToPrettyString(args.Session.AttachedEntity!.Value):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa"); + $"{ToPrettyString(args.Actor):player} set the pressure on {ToPrettyString(uid):device} to {args.Pressure}kPa"); DirtyUI(uid, mixer); } @@ -196,7 +196,7 @@ private void OnChangeNodePercentageMessage(EntityUid uid, GasMixerComponent mixe mixer.InletOneConcentration = nodeOne; mixer.InletTwoConcentration = 1.0f - mixer.InletOneConcentration; _adminLogger.Add(LogType.AtmosRatioChanged, LogImpact.Medium, - $"{EntityManager.ToPrettyString(args.Session.AttachedEntity!.Value):player} set the ratio on {EntityManager.ToPrettyString(uid):device} to {mixer.InletOneConcentration}:{mixer.InletTwoConcentration}"); + $"{EntityManager.ToPrettyString(args.Actor):player} set the ratio on {EntityManager.ToPrettyString(uid):device} to {mixer.InletOneConcentration}:{mixer.InletTwoConcentration}"); DirtyUI(uid, mixer); } @@ -205,19 +205,31 @@ private void OnChangeNodePercentageMessage(EntityUid uid, GasMixerComponent mixe /// private void OnMixerAnalyzed(EntityUid uid, GasMixerComponent component, GasAnalyzerScanEvent args) { - if (!EntityManager.TryGetComponent(uid, out NodeContainerComponent? nodeContainer)) - return; - - var gasMixDict = new Dictionary(); + args.GasMixtures ??= new List<(string, GasMixture?)>(); - if(_nodeContainer.TryGetNode(nodeContainer, component.InletOneName, out PipeNode? inletOne)) - gasMixDict.Add($"{inletOne.CurrentPipeDirection} {Loc.GetString("gas-analyzer-window-text-inlet")}", inletOne.Air); - if(_nodeContainer.TryGetNode(nodeContainer, component.InletTwoName, out PipeNode? inletTwo)) - gasMixDict.Add($"{inletTwo.CurrentPipeDirection} {Loc.GetString("gas-analyzer-window-text-inlet")}", inletTwo.Air); - if(_nodeContainer.TryGetNode(nodeContainer, component.OutletName, out PipeNode? outlet)) - gasMixDict.Add(Loc.GetString("gas-analyzer-window-text-outlet"), outlet.Air); + // multiply by volume fraction to make sure to send only the gas inside the analyzed pipe element, not the whole pipe system + if (_nodeContainer.TryGetNode(uid, component.InletOneName, out PipeNode? inletOne) && inletOne.Air.Volume != 0f) + { + var inletOneAirLocal = inletOne.Air.Clone(); + inletOneAirLocal.Multiply(inletOne.Volume / inletOne.Air.Volume); + inletOneAirLocal.Volume = inletOne.Volume; + args.GasMixtures.Add(($"{inletOne.CurrentPipeDirection} {Loc.GetString("gas-analyzer-window-text-inlet")}", inletOneAirLocal)); + } + if (_nodeContainer.TryGetNode(uid, component.InletTwoName, out PipeNode? inletTwo) && inletTwo.Air.Volume != 0f) + { + var inletTwoAirLocal = inletTwo.Air.Clone(); + inletTwoAirLocal.Multiply(inletTwo.Volume / inletTwo.Air.Volume); + inletTwoAirLocal.Volume = inletTwo.Volume; + args.GasMixtures.Add(($"{inletTwo.CurrentPipeDirection} {Loc.GetString("gas-analyzer-window-text-inlet")}", inletTwoAirLocal)); + } + if (_nodeContainer.TryGetNode(uid, component.OutletName, out PipeNode? outlet) && outlet.Air.Volume != 0f) + { + var outletAirLocal = outlet.Air.Clone(); + outletAirLocal.Multiply(outlet.Volume / outlet.Air.Volume); + outletAirLocal.Volume = outlet.Volume; + args.GasMixtures.Add((Loc.GetString("gas-analyzer-window-text-outlet"), outletAirLocal)); + } - args.GasMixtures = gasMixDict; args.DeviceFlipped = inletOne != null && inletTwo != null && inletOne.CurrentPipeDirection.ToDirection() == inletTwo.CurrentPipeDirection.ToDirection().GetClockwise90Degrees(); } } diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs index d53e29c9499..60ae230b1ba 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasCanisterSystem.cs @@ -101,7 +101,7 @@ private void DirtyUI(EntityUid uid, tankPressure = tankComponent.Air.Pressure; } - _ui.TrySetUiState(uid, GasCanisterUiKey.Key, + _ui.SetUiState(uid, GasCanisterUiKey.Key, new GasCanisterBoundUserInterfaceState(Name(uid), canister.Air.Pressure, portStatus, tankLabel, tankPressure, canister.ReleasePressure, canister.ReleaseValve, canister.MinReleasePressure, canister.MaxReleasePressure)); @@ -109,19 +109,19 @@ private void DirtyUI(EntityUid uid, private void OnHoldingTankEjectMessage(EntityUid uid, GasCanisterComponent canister, GasCanisterHoldingTankEjectMessage args) { - if (canister.GasTankSlot.Item == null || args.Session.AttachedEntity == null) + if (canister.GasTankSlot.Item == null) return; var item = canister.GasTankSlot.Item; - _slots.TryEjectToHands(uid, canister.GasTankSlot, args.Session.AttachedEntity); - _adminLogger.Add(LogType.CanisterTankEjected, LogImpact.Medium, $"Player {ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} ejected tank {ToPrettyString(item):tank} from {ToPrettyString(uid):canister}"); + _slots.TryEjectToHands(uid, canister.GasTankSlot, args.Actor); + _adminLogger.Add(LogType.CanisterTankEjected, LogImpact.Medium, $"Player {ToPrettyString(args.Actor):player} ejected tank {ToPrettyString(item):tank} from {ToPrettyString(uid):canister}"); } private void OnCanisterChangeReleasePressure(EntityUid uid, GasCanisterComponent canister, GasCanisterChangeReleasePressureMessage args) { var pressure = Math.Clamp(args.Pressure, canister.MinReleasePressure, canister.MaxReleasePressure); - _adminLogger.Add(LogType.CanisterPressure, LogImpact.Medium, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the release pressure on {ToPrettyString(uid):canister} to {args.Pressure}"); + _adminLogger.Add(LogType.CanisterPressure, LogImpact.Medium, $"{ToPrettyString(args.Actor):player} set the release pressure on {ToPrettyString(uid):canister} to {args.Pressure}"); canister.ReleasePressure = pressure; DirtyUI(uid, canister); @@ -134,14 +134,14 @@ private void OnCanisterChangeReleaseValve(EntityUid uid, GasCanisterComponent ca impact = canister.GasTankSlot.HasItem ? LogImpact.Medium : LogImpact.High; var containedGasDict = new Dictionary(); - var containedGasArray = Gas.GetValues(typeof(Gas)); + var containedGasArray = Enum.GetValues(typeof(Gas)); for (int i = 0; i < containedGasArray.Length; i++) { containedGasDict.Add((Gas)i, canister.Air[i]); } - _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Session.AttachedEntity.GetValueOrDefault()):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); + _adminLogger.Add(LogType.CanisterValve, impact, $"{ToPrettyString(args.Actor):player} set the valve on {ToPrettyString(uid):canister} to {args.Valve:valveState} while it contained [{string.Join(", ", containedGasDict)}]"); canister.ReleaseValve = args.Valve; DirtyUI(uid, canister); @@ -222,7 +222,7 @@ private void OnCanisterActivate(EntityUid uid, GasCanisterComponent component, A if (args.Handled) return; - _ui.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); + _ui.OpenUi(uid, GasCanisterUiKey.Key, actor.PlayerSession); args.Handled = true; } @@ -234,7 +234,7 @@ private void OnCanisterInteractHand(EntityUid uid, GasCanisterComponent componen if (CheckLocked(uid, component, args.User)) return; - _ui.TryOpen(uid, GasCanisterUiKey.Key, actor.PlayerSession); + _ui.OpenUi(uid, GasCanisterUiKey.Key, actor.PlayerSession); args.Handled = true; } @@ -316,9 +316,17 @@ private void CalculateCanisterPrice(EntityUid uid, GasCanisterComponent componen /// /// Returns the gas mixture for the gas analyzer /// - private void OnAnalyzed(EntityUid uid, GasCanisterComponent component, GasAnalyzerScanEvent args) + private void OnAnalyzed(EntityUid uid, GasCanisterComponent canisterComponent, GasAnalyzerScanEvent args) { - args.GasMixtures = new Dictionary { {Name(uid), component.Air} }; + args.GasMixtures ??= new List<(string, GasMixture?)>(); + args.GasMixtures.Add((Name(uid), canisterComponent.Air)); + // if a tank is inserted show it on the analyzer as well + if (canisterComponent.GasTankSlot.Item != null) + { + var tank = canisterComponent.GasTankSlot.Item.Value; + var tankComponent = Comp(tank); + args.GasMixtures.Add((Name(tank), tankComponent.Air)); + } } /// diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs index 720fd5b5b91..01eab560a16 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasThermoMachineSystem.cs @@ -144,7 +144,7 @@ private bool IsHeater(GasThermoMachineComponent comp) private void OnToggleMessage(EntityUid uid, GasThermoMachineComponent thermoMachine, GasThermomachineToggleMessage args) { var powerState = _power.TryTogglePower(uid); - _adminLogger.Add(LogType.AtmosPowerChanged, $"{ToPrettyString(args.Session.AttachedEntity)} turned {(powerState ? "On" : "Off")} {ToPrettyString(uid)}"); + _adminLogger.Add(LogType.AtmosPowerChanged, $"{ToPrettyString(args.Actor)} turned {(powerState ? "On" : "Off")} {ToPrettyString(uid)}"); DirtyUI(uid, thermoMachine); } @@ -155,7 +155,7 @@ private void OnChangeTemperature(EntityUid uid, GasThermoMachineComponent thermo else thermoMachine.TargetTemperature = MathF.Max(args.Temperature, thermoMachine.MinTemperature); thermoMachine.TargetTemperature = MathF.Max(thermoMachine.TargetTemperature, Atmospherics.TCMB); - _adminLogger.Add(LogType.AtmosTemperatureChanged, $"{ToPrettyString(args.Session.AttachedEntity)} set temperature on {ToPrettyString(uid)} to {thermoMachine.TargetTemperature}"); + _adminLogger.Add(LogType.AtmosTemperatureChanged, $"{ToPrettyString(args.Actor)} set temperature on {ToPrettyString(uid)} to {thermoMachine.TargetTemperature}"); DirtyUI(uid, thermoMachine); } @@ -168,8 +168,8 @@ private void DirtyUI(EntityUid uid, GasThermoMachineComponent? thermoMachine, Us if (!Resolve(uid, ref powerReceiver)) return; - _userInterfaceSystem.TrySetUiState(uid, ThermomachineUiKey.Key, - new GasThermomachineBoundUserInterfaceState(thermoMachine.MinTemperature, thermoMachine.MaxTemperature, thermoMachine.TargetTemperature, !powerReceiver.PowerDisabled, IsHeater(thermoMachine)), null, ui); + _userInterfaceSystem.SetUiState(uid, ThermomachineUiKey.Key, + new GasThermomachineBoundUserInterfaceState(thermoMachine.MinTemperature, thermoMachine.MaxTemperature, thermoMachine.TargetTemperature, !powerReceiver.PowerDisabled, IsHeater(thermoMachine))); } private void OnExamined(EntityUid uid, GasThermoMachineComponent thermoMachine, ExaminedEvent args) diff --git a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs index a986385f5e9..7c12cf3f77f 100644 --- a/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs +++ b/Content.Server/Atmos/Piping/Unary/EntitySystems/GasVentPumpSystem.cs @@ -80,7 +80,7 @@ private void OnGasVentPumpUpdated(EntityUid uid, GasVentPumpComponent vent, ref return; } - var timeDelta = args.dt; + var timeDelta = args.dt; var pressureDelta = timeDelta * vent.TargetPressureChange; if (vent.PumpDirection == VentPumpDirection.Releasing && pipe.Air.Pressure > 0) @@ -292,7 +292,7 @@ private void OnExamine(EntityUid uid, GasVentPumpComponent component, ExaminedEv /// private void OnAnalyzed(EntityUid uid, GasVentPumpComponent component, GasAnalyzerScanEvent args) { - var gasMixDict = new Dictionary(); + args.GasMixtures ??= new List<(string, GasMixture?)>(); // these are both called pipe, above it switches using this so I duplicated that...? var nodeName = component.PumpDirection switch @@ -301,10 +301,14 @@ private void OnAnalyzed(EntityUid uid, GasVentPumpComponent component, GasAnalyz VentPumpDirection.Siphoning => component.Outlet, _ => throw new ArgumentOutOfRangeException() }; - if (_nodeContainer.TryGetNode(uid, nodeName, out PipeNode? pipe)) - gasMixDict.Add(nodeName, pipe.Air); - - args.GasMixtures = gasMixDict; + // multiply by volume fraction to make sure to send only the gas inside the analyzed pipe element, not the whole pipe system + if (_nodeContainer.TryGetNode(uid, nodeName, out PipeNode? pipe) && pipe.Air.Volume != 0f) + { + var pipeAirLocal = pipe.Air.Clone(); + pipeAirLocal.Multiply(pipe.Volume / pipe.Air.Volume); + pipeAirLocal.Volume = pipe.Volume; + args.GasMixtures.Add((nodeName, pipeAirLocal)); + } } private void OnWeldChanged(EntityUid uid, GasVentPumpComponent component, ref WeldableChangedEvent args) diff --git a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs index f657d713d28..fbe40deedb1 100644 --- a/Content.Server/Atmos/Portable/PortableScrubberSystem.cs +++ b/Content.Server/Atmos/Portable/PortableScrubberSystem.cs @@ -14,6 +14,7 @@ using Content.Server.Administration.Logs; using Content.Server.Construction; using Content.Server.NodeContainer.EntitySystems; +using Content.Shared.Atmos; using Content.Shared.Database; namespace Content.Server.Atmos.Portable @@ -154,10 +155,8 @@ private void UpdateAppearance(EntityUid uid, bool isFull, bool isRunning) /// private void OnScrubberAnalyzed(EntityUid uid, PortableScrubberComponent component, GasAnalyzerScanEvent args) { - args.GasMixtures ??= new Dictionary { { Name(uid), component.Air } }; - // If it's connected to a port, include the port side - if (_nodeContainer.TryGetNode(uid, component.PortName, out PipeNode? port)) - args.GasMixtures.Add(component.PortName, port.Air); + args.GasMixtures ??= new List<(string, GasMixture?)>(); + args.GasMixtures.Add((Name(uid), component.Air)); } private void OnRefreshParts(EntityUid uid, PortableScrubberComponent component, RefreshPartsEvent args) diff --git a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs index 8094b0e1a66..70eea2d9b78 100644 --- a/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs +++ b/Content.Server/Atmos/Portable/SpaceHeaterSystem.cs @@ -163,7 +163,7 @@ private void DirtyUI(EntityUid uid, SpaceHeaterComponent? spaceHeater) { return; } - _userInterfaceSystem.TrySetUiState(uid, SpaceHeaterUiKey.Key, + _userInterfaceSystem.SetUiState(uid, SpaceHeaterUiKey.Key, new SpaceHeaterBoundUserInterfaceState(spaceHeater.MinTemperature, spaceHeater.MaxTemperature, thermoMachine.TargetTemperature, !powerReceiver.PowerDisabled, spaceHeater.Mode, spaceHeater.PowerLevel)); } diff --git a/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs index 197034ce545..2c071afab1e 100644 --- a/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs +++ b/Content.Server/Atmos/Reactions/AmmoniaOxygenReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions; diff --git a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs index 051ee8202db..475c149cf37 100644 --- a/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs +++ b/Content.Server/Atmos/Reactions/FrezonCoolantReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions; diff --git a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs index 4ffd9c2f5b3..e3d3ece6b6a 100644 --- a/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs +++ b/Content.Server/Atmos/Reactions/FrezonProductionReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions; diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs index 0ee29de3bf1..48a113bb9a2 100644 --- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs +++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs @@ -1,22 +1,10 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using Robust.Shared.Prototypes; namespace Content.Server.Atmos.Reactions { - [Flags] - public enum ReactionResult : byte - { - NoReaction = 0, - Reacting = 1, - StopReactions = 2, - } - - public enum GasReaction : byte - { - Fire = 0, - } - [Prototype("gasReaction")] public sealed partial class GasReactionPrototype : IPrototype { diff --git a/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs index 7fce663dc31..367c0eb7b9c 100644 --- a/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs +++ b/Content.Server/Atmos/Reactions/N2ODecompositionReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions; diff --git a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs index e7ab7835fd9..98d567d4ed5 100644 --- a/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs +++ b/Content.Server/Atmos/Reactions/PlasmaFireReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs index 7103859a90f..3ad0a4b04de 100644 --- a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs +++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.EntitySystems; using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using JetBrains.Annotations; namespace Content.Server.Atmos.Reactions diff --git a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs index 8db8fdbd66d..e06c4b75ff9 100644 --- a/Content.Server/Atmos/Reactions/WaterVaporReaction.cs +++ b/Content.Server/Atmos/Reactions/WaterVaporReaction.cs @@ -1,5 +1,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Fluids.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Atmos.Reactions; using Content.Shared.Chemistry.Components; using Content.Shared.FixedPoint; using Content.Shared.Maps; diff --git a/Content.Server/Atmos/Rotting/RottingSystem.cs b/Content.Server/Atmos/Rotting/RottingSystem.cs index 5070b3f197f..40bdf657439 100644 --- a/Content.Server/Atmos/Rotting/RottingSystem.cs +++ b/Content.Server/Atmos/Rotting/RottingSystem.cs @@ -46,6 +46,29 @@ private void OnTempIsRotting(EntityUid uid, TemperatureComponent component, ref args.Handled = component.CurrentTemperature < Atmospherics.T0C + 0.85f; } + + public void ReduceAccumulator(EntityUid uid, TimeSpan time) + { + if (!TryComp(uid, out var perishable)) + return; + + if (!TryComp(uid, out var rotting)) + { + perishable.RotAccumulator -= time; + return; + } + var total = (rotting.TotalRotTime + perishable.RotAccumulator) - time; + + if (total < perishable.RotAfter) + { + RemCompDeferred(uid, rotting); + perishable.RotAccumulator = total; + } + + else + rotting.TotalRotTime = total - perishable.RotAfter; + } + /// /// Is anything speeding up the decay? /// e.g. buried in a grave diff --git a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs index 00be83e86d9..5b30d65e48e 100644 --- a/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs +++ b/Content.Server/Atmos/Serialization/TileAtmosCollectionSerializer.cs @@ -1,4 +1,5 @@ using System.Globalization; +using Content.Shared.Atmos; using Robust.Shared.Serialization; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Markdown; diff --git a/Content.Server/Atmos/TileMixtureEnumerator.cs b/Content.Server/Atmos/TileMixtureEnumerator.cs index 20440032dab..5601615f509 100644 --- a/Content.Server/Atmos/TileMixtureEnumerator.cs +++ b/Content.Server/Atmos/TileMixtureEnumerator.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Content.Shared.Atmos; namespace Content.Server.Atmos; diff --git a/Content.Server/Audio/Jukebox/JukeboxSystem.cs b/Content.Server/Audio/Jukebox/JukeboxSystem.cs index bfb9b2099a4..cc9235e3d7a 100644 --- a/Content.Server/Audio/Jukebox/JukeboxSystem.cs +++ b/Content.Server/Audio/Jukebox/JukeboxSystem.cs @@ -5,6 +5,7 @@ using Robust.Shared.Audio; using Robust.Shared.Audio.Components; using Robust.Shared.Audio.Systems; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using JukeboxComponent = Content.Shared.Audio.Jukebox.JukeboxComponent; @@ -66,8 +67,11 @@ private void OnJukeboxPause(Entity ent, ref JukeboxPauseMessag private void OnJukeboxSetTime(EntityUid uid, JukeboxComponent component, JukeboxSetTimeMessage args) { - var offset = (args.Session.Channel.Ping * 1.5f) / 1000f; - Audio.SetPlaybackPosition(component.AudioStream, args.SongTime + offset); + if (TryComp(args.Actor, out ActorComponent? actorComp)) + { + var offset = actorComp.PlayerSession.Channel.Ping * 1.5f / 1000f; + Audio.SetPlaybackPosition(component.AudioStream, args.SongTime + offset); + } } private void OnPowerChanged(Entity entity, ref PowerChangedEvent args) diff --git a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs index 2e7f8c4235a..1369fa20f11 100644 --- a/Content.Server/Bed/Cryostorage/CryostorageSystem.cs +++ b/Content.Server/Bed/Cryostorage/CryostorageSystem.cs @@ -79,9 +79,7 @@ private void OnBeforeUIOpened(Entity ent, ref BeforeActiva private void OnRemoveItemBuiMessage(Entity ent, ref CryostorageRemoveItemBuiMessage args) { var (_, comp) = ent; - if (args.Session.AttachedEntity is not { } attachedEntity) - return; - + var attachedEntity = args.Actor; var cryoContained = GetEntity(args.StoredEntity); if (!comp.StoredPlayers.Contains(cryoContained) || !IsInPausedMap(cryoContained)) @@ -114,6 +112,7 @@ private void OnRemoveItemBuiMessage(Entity ent, ref Cryost AdminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(attachedEntity):player} removed item {ToPrettyString(entity)} from cryostorage-contained player " + $"{ToPrettyString(cryoContained):player}, stored in cryostorage {ToPrettyString(ent)}"); + _container.TryRemoveFromContainer(entity.Value); _transform.SetCoordinates(entity.Value, Transform(attachedEntity).Coordinates); _hands.PickupOrDrop(attachedEntity, entity.Value); @@ -122,8 +121,8 @@ private void OnRemoveItemBuiMessage(Entity ent, ref Cryost private void UpdateCryostorageUIState(Entity ent) { - var state = new CryostorageBuiState(GetAllContainedData(ent).ToList()); - _ui.TrySetUiState(ent, CryostorageUIKey.Key, state); + var state = new CryostorageBuiState(GetAllContainedData(ent)); + _ui.SetUiState(ent.Owner, CryostorageUIKey.Key, state); } private void OnPlayerSpawned(Entity ent, ref PlayerSpawnCompleteEvent args) @@ -293,12 +292,17 @@ protected override void OnInsertedContainer(Entity ent, re _chatManager.ChatMessageToOne(ChatChannel.Server, msg, msg, uid, false, actor.PlayerSession.Channel); } - private IEnumerable GetAllContainedData(Entity ent) + private List GetAllContainedData(Entity ent) { + var data = new List(); + data.EnsureCapacity(ent.Comp.StoredPlayers.Count); + foreach (var contained in ent.Comp.StoredPlayers) { - yield return GetContainedData(contained); + data.Add(GetContainedData(contained)); } + + return data; } private CryostorageContainedPlayerData GetContainedData(EntityUid uid) diff --git a/Content.Server/Body/Systems/BloodstreamSystem.cs b/Content.Server/Body/Systems/BloodstreamSystem.cs index 91ed7a24808..2c571ce603f 100644 --- a/Content.Server/Body/Systems/BloodstreamSystem.cs +++ b/Content.Server/Body/Systems/BloodstreamSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Chemistry.ReactionEffects; using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics; -using Content.Server.HealthExaminable; using Content.Server.Popups; using Content.Shared.Alert; using Content.Shared.Chemistry.Components; @@ -13,6 +12,7 @@ using Content.Shared.Damage.Prototypes; using Content.Shared.Drunk; using Content.Shared.FixedPoint; +using Content.Shared.HealthExaminable; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; using Content.Shared.Rejuvenate; diff --git a/Content.Server/Body/Systems/InternalsSystem.cs b/Content.Server/Body/Systems/InternalsSystem.cs index 9607a808f65..db078e2f291 100644 --- a/Content.Server/Body/Systems/InternalsSystem.cs +++ b/Content.Server/Body/Systems/InternalsSystem.cs @@ -8,6 +8,7 @@ using Content.Shared.Hands.Components; using Content.Shared.Internals; using Content.Shared.Inventory; +using Content.Shared.Roles; using Content.Shared.Verbs; using Robust.Shared.Containers; using Robust.Shared.Utility; @@ -23,17 +24,29 @@ public sealed class InternalsSystem : EntitySystem [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] private readonly PopupSystem _popupSystem = default!; - public const SlotFlags InventorySlots = SlotFlags.POCKET | SlotFlags.BELT; + private EntityQuery _internalsQuery; public override void Initialize() { base.Initialize(); + _internalsQuery = GetEntityQuery(); + SubscribeLocalEvent(OnInhaleLocation); SubscribeLocalEvent(OnInternalsStartup); SubscribeLocalEvent(OnInternalsShutdown); SubscribeLocalEvent>(OnGetInteractionVerbs); SubscribeLocalEvent(OnDoAfter); + + SubscribeLocalEvent(OnStartingGear); + } + + private void OnStartingGear(ref StartingGearEquippedEvent ev) + { + if (!_internalsQuery.TryComp(ev.Entity, out var internals) || internals.BreathToolEntity == null) + return; + + ToggleInternals(ev.Entity, ev.Entity, force: false, internals); } private void OnGetInteractionVerbs( @@ -218,7 +231,7 @@ private short GetSeverity(InternalsComponent component) if (component.BreathToolEntity is null || !AreInternalsWorking(component)) return 2; - // If pressure in the tank is below low pressure threshhold, flash warning on internals UI + // If pressure in the tank is below low pressure threshold, flash warning on internals UI if (TryComp(component.GasTankEntity, out var gasTank) && gasTank.IsLowPressure) { diff --git a/Content.Server/Botany/SeedPrototype.cs b/Content.Server/Botany/SeedPrototype.cs index 2644da2a3b0..dd3555f143f 100644 --- a/Content.Server/Botany/SeedPrototype.cs +++ b/Content.Server/Botany/SeedPrototype.cs @@ -2,16 +2,16 @@ using Content.Server.Botany.Systems; using Content.Shared.Atmos; using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; using Robust.Shared.Utility; -using Robust.Shared.Audio; namespace Content.Server.Botany; [Prototype("seed")] -public sealed class SeedPrototype : SeedData, IPrototype +public sealed partial class SeedPrototype : SeedData, IPrototype { [IdDataField] public string ID { get; private init; } = default!; } @@ -70,7 +70,7 @@ public partial struct SeedChemQuantity /// When chemicals are added to produce, the potency of the seed is divided with this value. Final chemical amount is the result plus the `Min` value. /// Example: PotencyDivisor of 20 with seed potency of 55 results in 2.75, 55/20 = 2.75. If minimum is 1 then final result will be 3.75 of that chemical, 55/20+1 = 3.75. /// - [DataField("PotencyDivisor")] public int PotencyDivisor; + [DataField] public int PotencyDivisor; /// /// Inherent chemical is one that is NOT result of mutation or crossbreeding. These chemicals are removed if species mutation is executed. diff --git a/Content.Server/Botany/Systems/PlantHolderSystem.cs b/Content.Server/Botany/Systems/PlantHolderSystem.cs index 721536a7c07..c8842e14939 100644 --- a/Content.Server/Botany/Systems/PlantHolderSystem.cs +++ b/Content.Server/Botany/Systems/PlantHolderSystem.cs @@ -6,6 +6,7 @@ using Content.Server.Ghost.Roles.Components; using Content.Server.Kitchen.Components; using Content.Server.Popups; +using Content.Shared.Atmos; using Content.Shared.Botany; using Content.Shared.Burial.Components; using Content.Shared.Chemistry.Reagent; diff --git a/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs b/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs index c30db08bbe5..2e3b2c21157 100644 --- a/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs +++ b/Content.Server/Cargo/Components/StationCargoOrderDatabaseComponent.cs @@ -1,4 +1,6 @@ +using Content.Server.Station.Components; using Content.Shared.Cargo; +using Content.Shared.Cargo.Components; using Content.Shared.Cargo.Prototypes; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -38,3 +40,17 @@ public sealed partial class StationCargoOrderDatabaseComponent : Component [DataField] public EntProtoId PrinterOutput = "PaperCargoInvoice"; } + +/// +/// Event broadcast before a cargo order is fulfilled, allowing alternate systems to fulfill the order. +/// +[ByRefEvent] +public record struct FulfillCargoOrderEvent(Entity Station, CargoOrderData Order, Entity OrderConsole) +{ + public Entity OrderConsole = OrderConsole; + public Entity Station = Station; + public CargoOrderData Order = Order; + + public EntityUid? FulfillmentEntity; + public bool Handled = false; +} diff --git a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs index 22e5c67e175..e132e4f12a3 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Bounty.cs @@ -52,7 +52,7 @@ private void OnBountyConsoleOpened(EntityUid uid, CargoBountyConsoleComponent co return; var untilNextSkip = bountyDb.NextSkipTime - _timing.CurTime; - _uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, untilNextSkip)); + _uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(bountyDb.Bounties, untilNextSkip)); } private void OnPrintLabelMessage(EntityUid uid, CargoBountyConsoleComponent component, BountyPrintLabelMessage args) @@ -83,7 +83,7 @@ private void OnSkipBountyMessage(EntityUid uid, CargoBountyConsoleComponent comp if (!TryGetBountyFromId(station, args.BountyId, out var bounty)) return; - if (args.Session.AttachedEntity is not { Valid: true } mob) + if (args.Actor is not { Valid: true } mob) return; if (TryComp(uid, out var accessReaderComponent) && @@ -99,7 +99,7 @@ private void OnSkipBountyMessage(EntityUid uid, CargoBountyConsoleComponent comp FillBountyDatabase(station); db.NextSkipTime = _timing.CurTime + db.SkipDelay; var untilNextSkip = db.NextSkipTime - _timing.CurTime; - _uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip)); + _uiSystem.SetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip)); _audio.PlayPvs(component.SkipSound, uid); } @@ -462,10 +462,12 @@ public void UpdateBountyConsoles() { if (_station.GetOwningStation(uid) is not { } station || !TryComp(station, out var db)) + { continue; + } var untilNextSkip = db.NextSkipTime - _timing.CurTime; - _uiSystem.TrySetUiState(uid, CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip), ui: ui); + _uiSystem.SetUiState((uid, ui), CargoConsoleUiKey.Bounty, new CargoBountyConsoleState(db.Bounties, untilNextSkip)); } } diff --git a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs index d8b55a7237f..8978e6b2bfb 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Orders.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Orders.cs @@ -102,12 +102,12 @@ private void UpdateConsole(float frameTime) private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent component, CargoConsoleApproveOrderMessage args) { - if (args.Session.AttachedEntity is not { Valid: true } player) + if (args.Actor is not { Valid: true } player) return; if (!_accessReaderSystem.IsAllowed(player, uid)) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-order-not-allowed")); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-order-not-allowed")); PlayDenySound(uid, component); return; } @@ -119,7 +119,7 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com !TryComp(station, out StationDataComponent? stationData) || !TryGetOrderDatabase(station, out var orderDatabase)) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-station-not-found")); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-station-not-found")); PlayDenySound(uid, component); return; } @@ -134,7 +134,7 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com // Invalid order if (!_protoMan.HasIndex(order.ProductId)) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-invalid-product")); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-invalid-product")); PlayDenySound(uid, component); return; } @@ -145,7 +145,7 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com // Too many orders, avoid them getting spammed in the UI. if (amount >= capacity) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-too-many")); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-too-many")); PlayDenySound(uid, component); return; } @@ -156,7 +156,7 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com if (cappedAmount != order.OrderQuantity) { order.OrderQuantity = cappedAmount; - ConsolePopup(args.Session, Loc.GetString("cargo-console-snip-snip")); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-snip-snip")); PlayDenySound(uid, component); } @@ -165,18 +165,25 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com // Not enough balance if (cost > bank.Balance) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-insufficient-funds", ("cost", cost))); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-insufficient-funds", ("cost", cost))); PlayDenySound(uid, component); return; } - var tradeDestination = TryFulfillOrder(stationData, order, orderDatabase); + var ev = new FulfillCargoOrderEvent((station.Value, stationData), order, (uid, component)); + RaiseLocalEvent(ref ev); + ev.FulfillmentEntity ??= station.Value; - if (tradeDestination == null) + if (!ev.Handled) { - ConsolePopup(args.Session, Loc.GetString("cargo-console-unfulfilled")); - PlayDenySound(uid, component); - return; + ev.FulfillmentEntity = TryFulfillOrder((station.Value, stationData), order, orderDatabase); + + if (ev.FulfillmentEntity == null) + { + ConsolePopup(args.Actor, Loc.GetString("cargo-console-unfulfilled")); + PlayDenySound(uid, component); + return; + } } _idCardSystem.TryFindIdCard(player, out var idCard); @@ -184,7 +191,16 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com order.SetApproverData(idCard.Comp?.FullName, idCard.Comp?.JobTitle); _audio.PlayPvs(component.ConfirmSound, uid); - ConsolePopup(args.Session, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(tradeDestination.Value).EntityName))); + var approverName = idCard.Comp?.FullName ?? Loc.GetString("access-reader-unknown-id"); + var approverJob = idCard.Comp?.JobTitle ?? Loc.GetString("access-reader-unknown-id"); + var message = Loc.GetString("cargo-console-unlock-approved-order-broadcast", + ("productName", Loc.GetString(order.ProductName)), + ("orderAmount", order.OrderQuantity), + ("approverName", approverName), + ("approverJob", approverJob), + ("cost", cost)); + _radio.SendRadioMessage(uid, message, component.AnnouncementChannel, uid, escapeMarkup: false); + ConsolePopup(args.Actor, Loc.GetString("cargo-console-trade-station", ("destination", MetaData(ev.FulfillmentEntity.Value).EntityName))); // Log order approval _adminLogger.Add(LogType.Action, LogImpact.Low, @@ -192,10 +208,10 @@ private void OnApproveOrderMessage(EntityUid uid, CargoOrderConsoleComponent com orderDatabase.Orders.Remove(order); DeductFunds(bank, cost); - UpdateOrders(station.Value, orderDatabase); + UpdateOrders(station.Value); } - private EntityUid? TryFulfillOrder(StationDataComponent stationData, CargoOrderData order, StationCargoOrderDatabaseComponent orderDatabase) + private EntityUid? TryFulfillOrder(Entity stationData, CargoOrderData order, StationCargoOrderDatabaseComponent orderDatabase) { // No slots at the trade station _listEnts.Clear(); @@ -257,7 +273,7 @@ private void OnRemoveOrderMessage(EntityUid uid, CargoOrderConsoleComponent comp private void OnAddOrderMessage(EntityUid uid, CargoOrderConsoleComponent component, CargoConsoleAddOrderMessage args) { - if (args.Session.AttachedEntity is not { Valid: true } player) + if (args.Actor is not { Valid: true } player) return; if (args.Amount <= 0) @@ -305,9 +321,9 @@ private void UpdateOrderState(EntityUid consoleUid, EntityUid? station) !TryComp(station, out var orderDatabase) || !TryComp(station, out var bankAccount)) return; - if (_uiSystem.TryGetUi(consoleUid, CargoConsoleUiKey.Orders, out var bui)) + if (_uiSystem.HasUi(consoleUid, CargoConsoleUiKey.Orders)) { - _uiSystem.SetUiState(bui, new CargoConsoleInterfaceState( + _uiSystem.SetUiState(consoleUid, CargoConsoleUiKey.Orders, new CargoConsoleInterfaceState( MetaData(station.Value).EntityName, GetOutstandingOrderCount(orderDatabase), orderDatabase.Capacity, @@ -317,9 +333,9 @@ private void UpdateOrderState(EntityUid consoleUid, EntityUid? station) } } - private void ConsolePopup(ICommonSession session, string text) + private void ConsolePopup(EntityUid actor, string text) { - _popup.PopupCursor(text, session); + _popup.PopupCursor(text, actor); } private void PlayDenySound(EntityUid uid, CargoOrderConsoleComponent component) @@ -329,7 +345,7 @@ private void PlayDenySound(EntityUid uid, CargoOrderConsoleComponent component) private static CargoOrderData GetOrderData(CargoConsoleAddOrderMessage args, CargoProductPrototype cargoProduct, int id) { - return new CargoOrderData(id, cargoProduct.Product, cargoProduct.Cost, args.Amount, args.Requester, args.Reason); + return new CargoOrderData(id, cargoProduct.Product, cargoProduct.Name, cargoProduct.Cost, args.Amount, args.Requester, args.Reason); } public static int GetOutstandingOrderCount(StationCargoOrderDatabaseComponent component) @@ -350,7 +366,7 @@ public static int GetOutstandingOrderCount(StationCargoOrderDatabaseComponent co /// Updates all of the cargo-related consoles for a particular station. /// This should be called whenever orders change. /// - private void UpdateOrders(EntityUid dbUid, StationCargoOrderDatabaseComponent _) + private void UpdateOrders(EntityUid dbUid) { // Order added so all consoles need updating. var orderQuery = AllEntityQuery(); @@ -378,19 +394,20 @@ private void UpdateOrders(EntityUid dbUid, StationCargoOrderDatabaseComponent _) public bool AddAndApproveOrder( EntityUid dbUid, string spawnId, + string name, int cost, int qty, string sender, string description, string dest, StationCargoOrderDatabaseComponent component, - StationDataComponent stationData + Entity stationData ) { DebugTools.Assert(_protoMan.HasIndex(spawnId)); // Make an order var id = GenerateOrderId(component); - var order = new CargoOrderData(id, spawnId, cost, qty, sender, description); + var order = new CargoOrderData(id, spawnId, name, cost, qty, sender, description); // Approve it now order.SetApproverData(dest, sender); @@ -406,7 +423,7 @@ StationDataComponent stationData private bool TryAddOrder(EntityUid dbUid, CargoOrderData data, StationCargoOrderDatabaseComponent component) { component.Orders.Add(data); - UpdateOrders(dbUid, component); + UpdateOrders(dbUid); return true; } @@ -424,7 +441,7 @@ public void RemoveOrder(EntityUid dbUid, int index, StationCargoOrderDatabaseCom { orderDB.Orders.RemoveAt(sequenceIdx); } - UpdateOrders(dbUid, orderDB); + UpdateOrders(dbUid); } public void ClearOrders(StationCargoOrderDatabaseComponent component) diff --git a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs index 0484e05ced1..1c5c7ed1c0d 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Shuttle.cs @@ -79,21 +79,20 @@ private void UpdateCargoShuttleConsoles(EntityUid shuttleUid, CargoShuttleCompon private void UpdatePalletConsoleInterface(EntityUid uid) { - var bui = _uiSystem.GetUi(uid, CargoPalletConsoleUiKey.Sale); if (Transform(uid).GridUid is not EntityUid gridUid) { - _uiSystem.SetUiState(bui, + _uiSystem.SetUiState(uid, CargoPalletConsoleUiKey.Sale, new CargoPalletConsoleInterfaceState(0, 0, false)); return; } GetPalletGoods(gridUid, out var toSell, out var amount); - _uiSystem.SetUiState(bui, + _uiSystem.SetUiState(uid, CargoPalletConsoleUiKey.Sale, new CargoPalletConsoleInterfaceState((int) amount, toSell.Count, true)); } private void OnPalletUIOpen(EntityUid uid, CargoPalletConsoleComponent component, BoundUIOpenedEvent args) { - var player = args.Session.AttachedEntity; + var player = args.Actor; if (player == null) return; @@ -111,7 +110,7 @@ private void OnPalletUIOpen(EntityUid uid, CargoPalletConsoleComponent component private void OnPalletAppraise(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletAppraiseMessage args) { - var player = args.Session.AttachedEntity; + var player = args.Actor; if (player == null) return; @@ -133,8 +132,8 @@ private void UpdateShuttleState(EntityUid uid, EntityUid? station = null) var orders = GetProjectedOrders(station ?? EntityUid.Invalid, orderDatabase, shuttle); var shuttleName = orderDatabase?.Shuttle != null ? MetaData(orderDatabase.Shuttle.Value).EntityName : string.Empty; - if (_uiSystem.TryGetUi(uid, CargoConsoleUiKey.Shuttle, out var bui)) - _uiSystem.SetUiState(bui, new CargoShuttleConsoleBoundUserInterfaceState( + if (_uiSystem.HasUi(uid, CargoConsoleUiKey.Shuttle)) + _uiSystem.SetUiState(uid, CargoConsoleUiKey.Shuttle, new CargoShuttleConsoleBoundUserInterfaceState( station != null ? MetaData(station.Value).EntityName : Loc.GetString("cargo-shuttle-console-station-unknown"), string.IsNullOrEmpty(shuttleName) ? Loc.GetString("cargo-shuttle-console-shuttle-not-found") : shuttleName, orders @@ -179,7 +178,7 @@ private List GetProjectedOrders( // We won't be able to fit the whole order on, so make one // which represents the space we do have left: var reducedOrder = new CargoOrderData(order.OrderId, - order.ProductId, order.Price, spaceRemaining, order.Requester, order.Reason); + order.ProductId, order.ProductName, order.Price, spaceRemaining, order.Requester, order.Reason); orders.Add(reducedOrder); } else @@ -339,17 +338,16 @@ private bool CanSell(EntityUid uid, TransformComponent xform) private void OnPalletSale(EntityUid uid, CargoPalletConsoleComponent component, CargoPalletSellMessage args) { - var player = args.Session.AttachedEntity; + var player = args.Actor; if (player == null) return; - var bui = _uiSystem.GetUi(uid, CargoPalletConsoleUiKey.Sale); var xform = Transform(uid); if (xform.GridUid is not EntityUid gridUid) { - _uiSystem.SetUiState(bui, + _uiSystem.SetUiState(uid, CargoPalletConsoleUiKey.Sale, new CargoPalletConsoleInterfaceState(0, 0, false)); return; } diff --git a/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs index 1c25b0e79d2..223dd2ac329 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.Telepad.cs @@ -1,11 +1,15 @@ +using System.Linq; using Content.Server.Cargo.Components; using Content.Server.Construction; using Content.Server.Paper; using Content.Server.Power.Components; +using Content.Server.Power.EntitySystems; +using Content.Server.Station.Components; using Content.Shared.Cargo; using Content.Shared.Cargo.Components; using Content.Shared.DeviceLinking; using Robust.Shared.Audio; +using Robust.Shared.Random; using Robust.Shared.Utility; namespace Content.Server.Cargo.Systems; @@ -17,10 +21,44 @@ private void InitializeTelepad() SubscribeLocalEvent(OnInit); SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent(OnUpgradeExamine); + SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnTelepadPowerChange); // Shouldn't need re-anchored event SubscribeLocalEvent(OnTelepadAnchorChange); + SubscribeLocalEvent(OnTelepadFulfillCargoOrder); } + + private void OnTelepadFulfillCargoOrder(ref FulfillCargoOrderEvent args) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var tele, out var xform)) + { + if (tele.CurrentState != CargoTelepadState.Idle) + continue; + + if (!this.IsPowered(uid, EntityManager)) + continue; + + if (_station.GetOwningStation(uid, xform) != args.Station) + continue; + + // todo cannot be fucking asked to figure out device linking rn but this shouldn't just default to the first port. + if (!TryComp(uid, out var sinkComponent) || + sinkComponent.LinkedSources.FirstOrNull() is not { } console || + console != args.OrderConsole.Owner) + continue; + + for (var i = 0; i < args.Order.OrderQuantity; i++) + { + tele.CurrentOrders.Add(args.Order); + } + tele.Accumulator = tele.Delay; + args.Handled = true; + args.FulfillmentEntity = uid; + return; + } + } + private void UpdateTelepad(float frameTime) { var query = EntityQueryEnumerator(); @@ -37,14 +75,6 @@ private void UpdateTelepad(float frameTime) continue; } - if (!TryComp(uid, out var sinkComponent) || - sinkComponent.LinkedSources.FirstOrNull() is not { } console || - !HasComp(console)) - { - comp.Accumulator = comp.Delay; - continue; - } - comp.Accumulator -= frameTime; // Uhh listen teleporting takes time and I just want the 1 float. @@ -55,21 +85,22 @@ private void UpdateTelepad(float frameTime) continue; } - var station = _station.GetOwningStation(console); - - if (!TryComp(station, out var orderDatabase) || - orderDatabase.Orders.Count == 0) + if (comp.CurrentOrders.Count == 0) { comp.Accumulator += comp.Delay; continue; } var xform = Transform(uid); - if (FulfillNextOrder(orderDatabase, xform.Coordinates, comp.PrinterOutput)) + var currentOrder = comp.CurrentOrders.First(); + if (FulfillOrder(currentOrder, xform.Coordinates, comp.PrinterOutput)) { _audio.PlayPvs(_audio.GetSound(comp.TeleportSound), uid, AudioParams.Default.WithVolume(-8f)); - UpdateOrders(station.Value, orderDatabase); + if (_station.GetOwningStation(uid) is { } station) + UpdateOrders(station); + + comp.CurrentOrders.Remove(currentOrder); comp.CurrentState = CargoTelepadState.Teleporting; _appearance.SetData(uid, CargoTelepadVisuals.State, CargoTelepadState.Teleporting, appearance); } @@ -94,6 +125,29 @@ private void OnUpgradeExamine(EntityUid uid, CargoTelepadComponent component, Up args.AddPercentageUpgrade("cargo-telepad-delay-upgrade", component.Delay / component.BaseDelay); } + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + if (ent.Comp.CurrentOrders.Count == 0) + return; + + if (_station.GetStations().Count == 0) + return; + + if (_station.GetOwningStation(ent) is not { } station) + { + station = _random.Pick(_station.GetStations().Where(HasComp).ToList()); + } + + if (!TryComp(station, out var db) || + !TryComp(station, out var data)) + return; + + foreach (var order in ent.Comp.CurrentOrders) + { + TryFulfillOrder((station, data), order, db); + } + } + private void SetEnabled(EntityUid uid, CargoTelepadComponent component, ApcPowerReceiverComponent? receiver = null, TransformComponent? xform = null) { diff --git a/Content.Server/Cargo/Systems/CargoSystem.cs b/Content.Server/Cargo/Systems/CargoSystem.cs index 3d6fc964725..e593299321e 100644 --- a/Content.Server/Cargo/Systems/CargoSystem.cs +++ b/Content.Server/Cargo/Systems/CargoSystem.cs @@ -8,6 +8,7 @@ using Content.Server.Station.Systems; using Content.Shared.Access.Systems; using Content.Shared.Administration.Logs; +using Content.Server.Radio.EntitySystems; using Content.Shared.Cargo; using Content.Shared.Cargo.Components; using Content.Shared.Containers.ItemSlots; @@ -44,6 +45,7 @@ public sealed partial class CargoSystem : SharedCargoSystem [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; [Dependency] private readonly MetaDataSystem _metaSystem = default!; + [Dependency] private readonly RadioSystem _radio = default!; [Dependency] private readonly IConfigurationManager _cfgManager = default!; [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IComponentFactory _factory = default!; diff --git a/Content.Server/Cargo/Systems/PricingSystem.cs b/Content.Server/Cargo/Systems/PricingSystem.cs index 9e1970d63c9..f878eeee75c 100644 --- a/Content.Server/Cargo/Systems/PricingSystem.cs +++ b/Content.Server/Cargo/Systems/PricingSystem.cs @@ -199,7 +199,7 @@ public double GetEstimatedPrice(EntityPrototype prototype) /// This fires off an event to calculate the price. /// Calculating the price of an entity that somehow contains itself will likely hang. /// - public double GetPrice(EntityUid uid) + public double GetPrice(EntityUid uid, bool includeContents = true) { var ev = new PriceCalculationEvent(); RaiseLocalEvent(uid, ref ev); @@ -222,7 +222,7 @@ public double GetPrice(EntityUid uid) price += GetStaticPrice(uid); } - if (TryComp(uid, out var containers)) + if (includeContents && TryComp(uid, out var containers)) { foreach (var container in containers.Containers.Values) { diff --git a/Content.Server/Carrying/CarryingSystem.cs b/Content.Server/Carrying/CarryingSystem.cs index 3e37366a2e5..857c3861a74 100644 --- a/Content.Server/Carrying/CarryingSystem.cs +++ b/Content.Server/Carrying/CarryingSystem.cs @@ -146,7 +146,7 @@ private void OnThrow(EntityUid uid, CarryingComponent component, ref BeforeThrow private void OnParentChanged(EntityUid uid, CarryingComponent component, ref EntParentChangedMessage args) { var xform = Transform(uid); - if (xform.MapID != args.OldMapId || xform.ParentUid == xform.GridUid) + if (xform.MapUid != args.OldMapId || xform.ParentUid == xform.GridUid) return; DropCarried(uid, component.Carried); diff --git a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs index 4a76aef911f..7896a7822e2 100644 --- a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs +++ b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs @@ -103,12 +103,12 @@ public void UpdateUiState(EntityUid loaderUid, ICommonSession? session, Cartridg if (!Resolve(loaderUid, ref loader)) return; - if (!_userInterfaceSystem.TryGetUi(loaderUid, loader.UiKey, out var ui)) + if (!_userInterfaceSystem.HasUi(loaderUid, loader.UiKey)) return; var programs = GetAvailablePrograms(loaderUid, loader); var state = new CartridgeLoaderUiState(programs, GetNetEntity(loader.ActiveProgram)); - _userInterfaceSystem.SetUiState(ui, state, session); + _userInterfaceSystem.SetUiState(loaderUid, loader.UiKey, state); } /// @@ -127,8 +127,8 @@ public void UpdateCartridgeUiState(EntityUid loaderUid, BoundUserInterfaceState if (!Resolve(loaderUid, ref loader)) return; - if (_userInterfaceSystem.TryGetUi(loaderUid, loader.UiKey, out var ui)) - _userInterfaceSystem.SetUiState(ui, state, session); + if (_userInterfaceSystem.HasUi(loaderUid, loader.UiKey)) + _userInterfaceSystem.SetUiState(loaderUid, loader.UiKey, state); } /// diff --git a/Content.Server/Chat/Commands/AdminChatCommand.cs b/Content.Server/Chat/Commands/AdminChatCommand.cs index 979051e9d3e..1a7ae050b66 100644 --- a/Content.Server/Chat/Commands/AdminChatCommand.cs +++ b/Content.Server/Chat/Commands/AdminChatCommand.cs @@ -5,7 +5,7 @@ namespace Content.Server.Chat.Commands { - [AdminCommand(AdminFlags.Admin)] + [AdminCommand(AdminFlags.Adminchat)] internal sealed class AdminChatCommand : IConsoleCommand { public string Command => "asay"; diff --git a/Content.Server/Chat/Systems/ChatSystem.Emote.cs b/Content.Server/Chat/Systems/ChatSystem.Emote.cs index c18b945ec6f..7b8a81c34f5 100644 --- a/Content.Server/Chat/Systems/ChatSystem.Emote.cs +++ b/Content.Server/Chat/Systems/ChatSystem.Emote.cs @@ -2,6 +2,7 @@ using System.Linq; using Content.Shared.Chat; using Content.Shared.Chat.Prototypes; +using Content.Shared.Speech; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -83,6 +84,16 @@ public void TryEmoteWithChat( bool ignoreActionBlocker = false ) { + if (!(emote.Whitelist?.IsValid(source, EntityManager) ?? true)) + return; + if (emote.Blacklist?.IsValid(source, EntityManager) ?? false) + return; + + if (!emote.Available && + TryComp(source, out var speech) && + !speech.AllowedEmotes.Contains(emote.ID)) + return; + // check if proto has valid message for chat if (emote.ChatMessages.Count != 0) { diff --git a/Content.Server/Chat/V2/Commands/DeleteChatMessageCommand.cs b/Content.Server/Chat/V2/Commands/DeleteChatMessageCommand.cs new file mode 100644 index 00000000000..1f9203d299f --- /dev/null +++ b/Content.Server/Chat/V2/Commands/DeleteChatMessageCommand.cs @@ -0,0 +1,36 @@ +using System.Diagnostics; +using Content.Server.Administration; +using Content.Server.Chat.V2.Repository; +using Content.Shared.Administration; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Errors; +using Robust.Shared.Utility; + +namespace Content.Server.Chat.V2.Commands; + +[ToolshedCommand, AdminCommand(AdminFlags.Admin)] +public sealed class DeleteChatMessageCommand : ToolshedCommand +{ + [Dependency] private readonly IEntitySystemManager _manager = default!; + + [CommandImplementation("id")] + public void DeleteChatMessage([CommandInvocationContext] IInvocationContext ctx, [CommandArgument] uint messageId) + { + if (!_manager.GetEntitySystem().Delete(messageId)) + { + ctx.ReportError(new MessageIdDoesNotExist()); + } + } +} + +public record struct MessageIdDoesNotExist() : IConError +{ + public FormattedMessage DescribeInner() + { + return FormattedMessage.FromUnformatted(Loc.GetString("command-error-deletechatmessage-id-notexist")); + } + + public string? Expression { get; set; } + public Vector2i? IssueSpan { get; set; } + public StackTrace? Trace { get; set; } +} diff --git a/Content.Server/Chat/V2/Commands/NukeChatMessagesCommand.cs b/Content.Server/Chat/V2/Commands/NukeChatMessagesCommand.cs new file mode 100644 index 00000000000..3d8b69dd765 --- /dev/null +++ b/Content.Server/Chat/V2/Commands/NukeChatMessagesCommand.cs @@ -0,0 +1,41 @@ +using System.Diagnostics; +using Content.Server.Administration; +using Content.Server.Chat.V2.Repository; +using Content.Shared.Administration; +using Robust.Shared.Toolshed; +using Robust.Shared.Toolshed.Errors; +using Robust.Shared.Utility; + +namespace Content.Server.Chat.V2.Commands; + +[ToolshedCommand, AdminCommand(AdminFlags.Admin)] +public sealed class NukeChatMessagesCommand : ToolshedCommand +{ + [Dependency] private readonly IEntitySystemManager _manager = default!; + + [CommandImplementation("usernames")] + public void Command([CommandInvocationContext] IInvocationContext ctx, [CommandArgument] string usernamesCsv) + { + var usernames = usernamesCsv.Split(','); + + foreach (var username in usernames) + { + if (!_manager.GetEntitySystem().NukeForUsername(username, out var reason)) + { + ctx.ReportError(new NukeMessagesForUsernameError(reason)); + } + } + } +} + +public record struct NukeMessagesForUsernameError(string Reason) : IConError +{ + public FormattedMessage DescribeInner() + { + return FormattedMessage.FromUnformatted(Reason); + } + + public string? Expression { get; set; } + public Vector2i? IssueSpan { get; set; } + public StackTrace? Trace { get; set; } +} diff --git a/Content.Server/Chat/V2/Messages.cs b/Content.Server/Chat/V2/Messages.cs new file mode 100644 index 00000000000..31a563cbebf --- /dev/null +++ b/Content.Server/Chat/V2/Messages.cs @@ -0,0 +1,94 @@ +using Content.Shared.Chat.Prototypes; +using Content.Shared.Chat.V2; +using Content.Shared.Radio; + +namespace Content.Server.Chat.V2; + +/// +/// Raised locally when a comms announcement is made. +/// +public sealed class CommsAnnouncementCreatedEvent(EntityUid sender, EntityUid console, string message) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = sender; + public string Message { get; set; } = message; + public MessageType Type => MessageType.Announcement; + public EntityUid Console = console; +} + +/// +/// Raised locally when a character speaks in Dead Chat. +/// +public sealed class DeadChatCreatedEvent(EntityUid speaker, string message, bool isAdmin) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = speaker; + public string Message { get; set; } = message; + public MessageType Type => MessageType.DeadChat; + public bool IsAdmin = isAdmin; +} + +/// +/// Raised locally when a character emotes. +/// +public sealed class EmoteCreatedEvent(EntityUid sender, string message, float range) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = sender; + public string Message { get; set; } = message; + public MessageType Type => MessageType.Emote; + public float Range = range; +} + +/// +/// Raised locally when a character talks in local. +/// +public sealed class LocalChatCreatedEvent(EntityUid speaker, string message, float range) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = speaker; + public string Message { get; set; } = message; + public MessageType Type => MessageType.Local; + public float Range = range; +} + +/// +/// Raised locally when a character speaks in LOOC. +/// +public sealed class LoocCreatedEvent(EntityUid speaker, string message) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = speaker; + public string Message { get; set; } = message; + public MessageType Type => MessageType.Looc; +} + +/// +/// Raised locally when a character speaks on the radio. +/// +public sealed class RadioCreatedEvent( + EntityUid speaker, + string message, + RadioChannelPrototype channel) + : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = speaker; + public string Message { get; set; } = message; + public RadioChannelPrototype Channel = channel; + public MessageType Type => MessageType.Radio; +} + +/// +/// Raised locally when a character whispers. +/// +public sealed class WhisperCreatedEvent(EntityUid speaker, string message, float minRange, float maxRange) : IChatEvent +{ + public uint Id { get; set; } + public EntityUid Sender { get; set; } = speaker; + public string Message { get; set; } = message; + public MessageType Type => MessageType.Whisper; + public float MinRange = minRange; + public float MaxRange = maxRange; +} + diff --git a/Content.Server/Chat/V2/Repository/ChatRepository.cs b/Content.Server/Chat/V2/Repository/ChatRepository.cs new file mode 100644 index 00000000000..06de37128f5 --- /dev/null +++ b/Content.Server/Chat/V2/Repository/ChatRepository.cs @@ -0,0 +1,196 @@ +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Runtime.InteropServices; +using Content.Shared.Chat.V2; +using Content.Shared.Chat.V2.Repository; +using Robust.Server.Player; +using Robust.Shared.Network; +using Robust.Shared.Replays; + +namespace Content.Server.Chat.V2.Repository; + +/// +/// Stores , gives them UIDs, and issues . +/// Allows for deletion of messages. +/// +public sealed class ChatRepositorySystem : EntitySystem +{ + [Dependency] private readonly IReplayRecordingManager _replay = default!; + [Dependency] private readonly IPlayerManager _player = default!; + + // Clocks should start at 1, as 0 indicates "clock not set" or "clock forgotten to be set by bad programmer". + private uint _nextMessageId = 1; + private Dictionary _messages = new(); + private Dictionary> _playerMessages = new(); + + public override void Initialize() + { + Refresh(); + + _replay.RecordingFinished += _ => + { + // TODO: resolve https://github.com/space-wizards/space-station-14/issues/25485 so we can dump the chat to disc. + Refresh(); + }; + } + + /// + /// Adds an to the repo and raises it with a UID for consumption elsewhere. + /// + /// The event to store and raise + /// If storing and raising succeeded. + public bool Add(IChatEvent ev) + { + if (!_player.TryGetSessionByEntity(ev.Sender, out var session)) + { + return false; + } + + var messageId = _nextMessageId; + + _nextMessageId++; + + ev.Id = messageId; + + var storedEv = new ChatRecord + { + UserName = session.Name, + UserId = session.UserId, + EntityName = Name(ev.Sender), + StoredEvent = ev + }; + + _messages[messageId] = storedEv; + + CollectionsMarshal.GetValueRefOrAddDefault(_playerMessages, storedEv.UserId, out _)?.Add(messageId); + + RaiseLocalEvent(ev.Sender, new MessageCreatedEvent(ev), true); + + return true; + } + + /// + /// Returns the event associated with a UID, if it exists. + /// + /// The UID of a event. + /// The event, if it exists. + public IChatEvent? GetEventFor(uint id) + { + return _messages.TryGetValue(id, out var record) ? record.StoredEvent : null; + } + + /// + /// Edits a specific message and issues a that says this happened both locally and + /// on the network. Note that this doesn't replay the message (yet), so translators and mutators won't act on it. + /// + /// The ID to edit + /// The new message to send + /// If patching did anything did anything + /// Should be used for admining and admemeing only. + public bool Patch(uint id, string message) + { + if (!_messages.TryGetValue(id, out var ev)) + { + return false; + } + + ev.StoredEvent.Message = message; + + RaiseLocalEvent(new MessagePatchedEvent(id, message)); + + return true; + } + + /// + /// Deletes a message from the repository and issues a that says this has happened + /// both locally and on the network. + /// + /// The ID to delete + /// If deletion did anything + /// Should only be used for adminning + public bool Delete(uint id) + { + if (!_messages.TryGetValue(id, out var ev)) + { + return false; + } + + _messages.Remove(id); + + if (_playerMessages.TryGetValue(ev.UserId, out var set)) + { + set.Remove(id); + } + + RaiseLocalEvent(new MessageDeletedEvent(id)); + + return true; + } + + /// + /// Nukes a user's entire chat history from the repo and issues a saying this has + /// happened. + /// + /// The user ID to nuke. + /// Why nuking failed, if it did. + /// If nuking did anything. + /// Note that this could be a very large event, as we send every single event ID over the wire. + /// By necessity we can't leak the player-source of chat messages (or if they even have the same origin) because of + /// client modders who could use that information to cheat/metagrudge/etc >:( + public bool NukeForUsername(string userName, [NotNullWhen(false)] out string? reason) + { + if (!_player.TryGetUserId(userName, out var userId)) + { + reason = Loc.GetString("command-error-nukechatmessages-usernames-usernamenotexist", ("username", userName)); + + return false; + } + + return NukeForUserId(userId, out reason); + } + + /// + /// Nukes a user's entire chat history from the repo and issues a saying this has + /// happened. + /// + /// The user ID to nuke. + /// Why nuking failed, if it did. + /// If nuking did anything. + /// Note that this could be a very large event, as we send every single event ID over the wire. + /// By necessity we can't leak the player-source of chat messages (or if they even have the same origin) because of + /// client modders who could use that information to cheat/metagrudge/etc >:( + public bool NukeForUserId(NetUserId userId, [NotNullWhen(false)] out string? reason) + { + if (!_playerMessages.TryGetValue(userId, out var dict)) + { + reason = Loc.GetString("command-error-nukechatmessages-usernames-usernamenomessages", ("userId", userId.UserId.ToString())); + + return false; + } + + foreach (var id in dict) + { + _messages.Remove(id); + } + + var ev = new MessagesNukedEvent(dict); + + CollectionsMarshal.GetValueRefOrAddDefault(_playerMessages, userId, out _)?.Clear(); + + RaiseLocalEvent(ev); + + reason = null; + + return true; + } + + /// + /// Dumps held chat storage data and refreshes the repo. + /// + public void Refresh() + { + _nextMessageId = 1; + _messages.Clear(); + _playerMessages.Clear(); + } +} diff --git a/Content.Server/Chemistry/Components/ReagentTankComponent.cs b/Content.Server/Chemistry/Components/ReagentTankComponent.cs deleted file mode 100644 index cc0d2657d7d..00000000000 --- a/Content.Server/Chemistry/Components/ReagentTankComponent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Content.Shared.FixedPoint; - - -namespace Content.Server.Chemistry.Components -{ - [RegisterComponent] - public sealed partial class ReagentTankComponent : Component - { - [DataField("transferAmount")] - [ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 TransferAmount { get; set; } = FixedPoint2.New(10); - - [DataField("tankType")] - [ViewVariables(VVAccess.ReadWrite)] - public ReagentTankType TankType { get; set; } = ReagentTankType.Unspecified; - } - - public enum ReagentTankType : byte - { - Unspecified, - Fuel - } -} diff --git a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs index 755312554c2..3d99db1129c 100644 --- a/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs +++ b/Content.Server/Chemistry/Containers/EntitySystems/SolutionContainerSystem.cs @@ -9,180 +9,37 @@ namespace Content.Server.Chemistry.Containers.EntitySystems; +[Obsolete("This is being depreciated. Use SharedSolutionContainerSystem instead!")] public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem { - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnComponentShutdown); - SubscribeLocalEvent(OnComponentShutdown); - } - - + [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")] public Solution EnsureSolution(Entity entity, string name) => EnsureSolution(entity, name, out _); + [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")] public Solution EnsureSolution(Entity entity, string name, out bool existed) => EnsureSolution(entity, name, FixedPoint2.Zero, out existed); + [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")] public Solution EnsureSolution(Entity entity, string name, FixedPoint2 maxVol, out bool existed) => EnsureSolution(entity, name, maxVol, null, out existed); + [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")] public Solution EnsureSolution(Entity entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed) { - var (uid, meta) = entity; - if (!Resolve(uid, ref meta)) - throw new InvalidOperationException("Attempted to ensure solution on invalid entity."); - - var manager = EnsureComp(uid); - if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized) - return EnsureSolutionEntity((uid, manager), name, maxVol, prototype, out existed).Comp.Solution; - else - return EnsureSolutionPrototype((uid, manager), name, maxVol, prototype, out existed); - } - - public void EnsureAllSolutions(Entity entity) - { - if (entity.Comp.Solutions is not { } prototypes) - return; - - foreach (var (name, prototype) in prototypes) - { - EnsureSolutionEntity((entity.Owner, entity.Comp), name, prototype.MaxVolume, prototype, out _); - } - - entity.Comp.Solutions = null; - Dirty(entity); - } - - public Entity EnsureSolutionEntity(Entity entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed) - { - existed = true; - - var (uid, container) = entity; - - var solutionSlot = ContainerSystem.EnsureContainer(uid, $"solution@{name}", out existed); - if (!Resolve(uid, ref container, logMissing: false)) - { - existed = false; - container = AddComp(uid); - container.Containers.Add(name); - } - else if (!existed) - { - container.Containers.Add(name); - Dirty(uid, container); - } - - var needsInit = false; - SolutionComponent solutionComp; - if (solutionSlot.ContainedEntity is not { } solutionId) - { - prototype ??= new() { MaxVolume = maxVol }; - prototype.Name = name; - (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, maxVol, prototype); - existed = false; - needsInit = true; - Dirty(uid, container); - } - else - { - solutionComp = Comp(solutionId); - DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name); - DebugTools.Assert(solutionComp.Solution.Name == name); - - var solution = solutionComp.Solution; - solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol); - - // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions. - // We want the reagents from the prototype to exist even if something else already created the solution. - if (prototype is { Volume.Value: > 0 }) - solution.AddSolution(prototype, PrototypeManager); - - Dirty(solutionId, solutionComp); - } - - if (needsInit) - EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID); - - return (solutionId, solutionComp); - } - - private Solution EnsureSolutionPrototype(Entity entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed) - { - existed = true; - - var (uid, container) = entity; - if (!Resolve(uid, ref container, logMissing: false)) - { - container = AddComp(uid); - existed = false; - } - - if (container.Solutions is null) - container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity); - - if (!container.Solutions.TryGetValue(name, out var solution)) - { - solution = prototype ?? new() { Name = name, MaxVolume = maxVol }; - container.Solutions.Add(name, solution); - existed = false; - } - else - solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol); - - Dirty(uid, container); - return solution; + EnsureSolution(entity, name, maxVol, prototype, out existed, out var solution); + return solution!;//solution is only ever null on the client, so we can suppress this } - - private Entity SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 maxVol, Solution prototype) + [Obsolete("This is being depreciated. Use the ensure methods in SharedSolutionContainerSystem instead!")] + public Entity EnsureSolutionEntity( + Entity entity, + string name, + FixedPoint2 maxVol, + Solution? prototype, + out bool existed) { - var coords = new EntityCoordinates(container.Owner, Vector2.Zero); - var uid = EntityManager.CreateEntityUninitialized(null, coords, null); - - var solution = new SolutionComponent() { Solution = prototype }; - AddComp(uid, solution); - - var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name }; - AddComp(uid, relation); - - MetaData.SetEntityName(uid, $"solution - {name}"); - ContainerSystem.Insert(uid, container, force: true); - - return (uid, solution, relation); + EnsureSolutionEntity(entity, name, out existed, out var solEnt, maxVol, prototype); + return solEnt!.Value;//solEnt is only ever null on the client, so we can suppress this } - - #region Event Handlers - - private void OnMapInit(Entity entity, ref MapInitEvent args) - { - EnsureAllSolutions(entity); - } - - private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) - { - foreach (var name in entity.Comp.Containers) - { - if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer)) - ContainerSystem.ShutdownContainer(solutionContainer); - } - entity.Comp.Containers.Clear(); - } - - private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) - { - if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container)) - { - container.Containers.Remove(entity.Comp.ContainerName); - Dirty(entity.Comp.Container, container); - } - - if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer)) - ContainerSystem.ShutdownContainer(solutionContainer); - } - - #endregion Event Handlers } diff --git a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs index ab910445749..289db759816 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemMasterSystem.cs @@ -80,7 +80,7 @@ private void UpdateUiState(Entity ent, bool updateLabel = f chemMaster.Mode, BuildInputContainerInfo(inputContainer), BuildOutputContainerInfo(outputContainer), bufferReagents, bufferCurrentVolume, chemMaster.PillType, chemMaster.PillDosageLimit, updateLabel); - _userInterfaceSystem.TrySetUiState(owner, ChemMasterUiKey.Key, state); + _userInterfaceSystem.SetUiState(owner, ChemMasterUiKey.Key, state); } private void OnSetModeMessage(Entity chemMaster, ref ChemMasterSetModeMessage message) @@ -179,7 +179,7 @@ private void DiscardReagents(Entity chemMaster, ReagentId i private void OnCreatePillsMessage(Entity chemMaster, ref ChemMasterCreatePillsMessage message) { - var user = message.Session.AttachedEntity; + var user = message.Actor; var maybeContainer = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.OutputSlotName); if (maybeContainer is not { Valid: true } container || !TryComp(container, out StorageComponent? storage)) @@ -218,18 +218,9 @@ private void OnCreatePillsMessage(Entity chemMaster, ref Ch pill.PillType = chemMaster.Comp.PillType; Dirty(item, pill); - if (user.HasValue) - { - // Log pill creation by a user - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(user.Value):user} printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}"); - } - else - { - // Log pill creation by magic? This should never happen... right? - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"Unknown printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}"); - } + // Log pill creation by a user + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(user):user} printed {ToPrettyString(item):pill} {SharedSolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}"); } UpdateUiState(chemMaster); @@ -238,7 +229,7 @@ private void OnCreatePillsMessage(Entity chemMaster, ref Ch private void OnOutputToBottleMessage(Entity chemMaster, ref ChemMasterOutputToBottleMessage message) { - var user = message.Session.AttachedEntity; + var user = message.Actor; var maybeContainer = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.OutputSlotName); if (maybeContainer is not { Valid: true } container || !_solutionContainerSystem.TryGetSolution(container, SharedChemMaster.BottleSolutionName, out var soln, out var solution)) @@ -260,18 +251,9 @@ private void OnOutputToBottleMessage(Entity chemMaster, ref _labelSystem.Label(container, message.Label); _solutionContainerSystem.TryAddSolution(soln.Value, withdrawal); - if (user.HasValue) - { - // Log bottle creation by a user - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(user.Value):user} bottled {ToPrettyString(container):bottle} {SolutionContainerSystem.ToPrettyString(solution)}"); - } - else - { - // Log bottle creation by magic? This should never happen... right? - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"Unknown bottled {ToPrettyString(container):bottle} {SolutionContainerSystem.ToPrettyString(solution)}"); - } + // Log bottle creation by a user + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(user):user} bottled {ToPrettyString(container):bottle} {SharedSolutionContainerSystem.ToPrettyString(solution)}"); UpdateUiState(chemMaster); ClickSound(chemMaster); diff --git a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs index a6d13b2f7cd..9dd1d429b7c 100644 --- a/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/InjectorSystem.cs @@ -124,7 +124,7 @@ private void InjectDoAfter(Entity injector, EntityUid target, Popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, user); } - if (!SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution)) + if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, out var solution)) return; var actualDelay = MathHelper.Max(injector.Comp.Delay, TimeSpan.FromSeconds(1)); @@ -252,7 +252,7 @@ private void TryInjectIntoBloodstream(Entity injector, Entity private void TryInject(Entity injector, EntityUid targetEntity, Entity targetSolution, EntityUid user, bool asRefill) { - if (!SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, + if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var soln, out var solution) || solution.Volume == 0) return; @@ -294,7 +294,7 @@ private void TryInject(Entity injector, EntityUid targetEntit private void AfterInject(Entity injector, EntityUid target) { // Automatically set syringe to draw after completely draining it. - if (SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, + if (SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, out var solution) && solution.Volume == 0) { SetMode(injector, InjectorToggleMode.Draw); @@ -308,7 +308,7 @@ private void AfterInject(Entity injector, EntityUid target) private void AfterDraw(Entity injector, EntityUid target) { // Automatically set syringe to inject after completely filling it. - if (SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, + if (SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out _, out var solution) && solution.AvailableVolume == 0) { SetMode(injector, InjectorToggleMode.Inject); @@ -322,7 +322,7 @@ private void AfterDraw(Entity injector, EntityUid target) private void TryDraw(Entity injector, Entity target, Entity targetSolution, EntityUid user) { - if (!SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, + if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var soln, out var solution) || solution.AvailableVolume == 0) { return; diff --git a/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs b/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs index 032374d4a55..d5f7655f884 100644 --- a/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReactionMixerSystem.cs @@ -30,7 +30,7 @@ private void OnAfterInteract(Entity entity, ref AfterInt return; } - if (!_solutionContainers.TryGetMixableSolution(args.Target.Value, out var solution)) + if (!_solutionContainers.TryGetMixableSolution(args.Target.Value, out var solution, out _)) return; _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User); diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs index d6433da56a0..c48bf086d39 100644 --- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs @@ -62,7 +62,7 @@ private void UpdateUiState(Entity reagentDispenser) var inventory = GetInventory(reagentDispenser); var state = new ReagentDispenserBoundUserInterfaceState(outputContainerInfo, GetNetEntity(outputContainer), inventory, reagentDispenser.Comp.DispenseAmount); - _userInterfaceSystem.TrySetUiState(reagentDispenser, ReagentDispenserUiKey.Key, state); + _userInterfaceSystem.SetUiState(reagentDispenser.Owner, ReagentDispenserUiKey.Key, state); } private ContainerInfo? BuildOutputContainerInfo(EntityUid? container) @@ -81,9 +81,9 @@ private void UpdateUiState(Entity reagentDispenser) return null; } - private List>> GetInventory(Entity reagentDispenser) + private List GetInventory(Entity reagentDispenser) { - var inventory = new List>>(); + var inventory = new List(); for (var i = 0; i < reagentDispenser.Comp.NumSlots; i++) { @@ -99,15 +99,17 @@ private List>> GetInventory(En else continue; - // Add volume remaining label + // Get volume remaining and color of solution FixedPoint2 quantity = 0f; + var reagentColor = Color.White; if (storedContainer != null && _solutionContainerSystem.TryGetDrainableSolution(storedContainer.Value, out _, out var sol)) { quantity = sol.Volume; + reagentColor = sol.GetColor(_prototypeManager); } var storedAmount = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)); - inventory.Add(new KeyValuePair>(storageSlotId, new KeyValuePair(reagentLabel, storedAmount))); + inventory.Add(new ReagentInventoryItem(storageSlotId, reagentLabel, storedAmount, reagentColor)); } return inventory; diff --git a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs index 94a3fe21861..c375d97b8c3 100644 --- a/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/TransformableContainerSystem.cs @@ -20,7 +20,7 @@ public override void Initialize() SubscribeLocalEvent(OnSolutionChange); } - private void OnMapInit(Entity entity, ref MapInitEvent args) + private void OnMapInit(Entity entity, ref MapInitEvent args) { var meta = MetaData(entity.Owner); if (string.IsNullOrEmpty(entity.Comp.InitialName)) diff --git a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs index 3b7bffb9cff..4ae13b6a6e4 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/OrganType.cs @@ -1,4 +1,4 @@ -using Content.Server.Body.Components; +using Content.Server.Body.Components; using Content.Shared.Body.Prototypes; using Content.Shared.Chemistry.Reagent; using Robust.Shared.Prototypes; @@ -35,7 +35,7 @@ public override bool Condition(ReagentEffectArgs args) public override string GuidebookExplanation(IPrototypeManager prototype) { return Loc.GetString("reagent-effect-condition-guidebook-organ-type", - ("name", prototype.Index(Type).Name), + ("name", prototype.Index(Type).LocalizedName), ("shouldhave", ShouldHave)); } } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs index 50be89581fb..061af2b3aef 100644 --- a/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs +++ b/Content.Server/Chemistry/ReagentEffectConditions/ReagentThreshold.cs @@ -1,4 +1,4 @@ -using Content.Shared.Chemistry.Reagent; +using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; @@ -43,7 +43,7 @@ public override string GuidebookExplanation(IPrototypeManager prototype) prototype.TryIndex(Reagent, out reagentProto); return Loc.GetString("reagent-effect-condition-guidebook-reagent-threshold", - ("reagent", reagentProto?.LocalizedName ?? "this reagent"), + ("reagent", reagentProto?.LocalizedName ?? Loc.GetString("reagent-effect-condition-guidebook-this-reagent")), ("max", Max == FixedPoint2.MaxValue ? (float) int.MaxValue : Max.Float()), ("min", Min.Float())); } diff --git a/Content.Server/Chemistry/ReagentEffectConditions/TotalHunger.cs b/Content.Server/Chemistry/ReagentEffectConditions/TotalHunger.cs new file mode 100644 index 00000000000..1dd12e632a7 --- /dev/null +++ b/Content.Server/Chemistry/ReagentEffectConditions/TotalHunger.cs @@ -0,0 +1,35 @@ +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Nutrition.Components; +using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; + +namespace Content.Server.Chemistry.ReagentEffectConditions +{ + public sealed partial class Hunger : ReagentEffectCondition + { + [DataField] + public float Max = float.PositiveInfinity; + + [DataField] + public float Min = 0; + + public override bool Condition(ReagentEffectArgs args) + { + if (args.EntityManager.TryGetComponent(args.SolutionEntity, out HungerComponent? hunger)) + { + var total = hunger.CurrentHunger; + if (total > Min && total < Max) + return true; + } + + return false; + } + + public override string GuidebookExplanation(IPrototypeManager prototype) + { + return Loc.GetString("reagent-effect-condition-guidebook-total-hunger", + ("max", float.IsPositiveInfinity(Max) ? (float) int.MaxValue : Max), + ("min", Min)); + } + } +} diff --git a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs index e70626f1d3e..16d69edd9aa 100644 --- a/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs +++ b/Content.Server/Chemistry/ReagentEffects/AdjustReagent.cs @@ -1,4 +1,4 @@ -using Content.Shared.Body.Prototypes; +using Content.Shared.Body.Prototypes; using Content.Shared.Chemistry.Reagent; using Content.Shared.FixedPoint; using JetBrains.Annotations; @@ -74,7 +74,7 @@ public override void Effect(ReagentEffectArgs args) return Loc.GetString("reagent-effect-guidebook-adjust-reagent-group", ("chance", Probability), ("deltasign", MathF.Sign(Amount.Float())), - ("group", groupProto.ID), + ("group", groupProto.LocalizedName), ("amount", MathF.Abs(Amount.Float()))); } diff --git a/Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs b/Content.Server/Chemistry/ReagentEffects/ChemCleanBloodstream.cs similarity index 100% rename from Content.Server/Chemistry/ReagentEffects/ChemCleanBoodstream.cs rename to Content.Server/Chemistry/ReagentEffects/ChemCleanBloodstream.cs diff --git a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs index 2a6181c7f35..24880cfd371 100644 --- a/Content.Server/Chemistry/ReagentEffects/HealthChange.cs +++ b/Content.Server/Chemistry/ReagentEffects/HealthChange.cs @@ -74,7 +74,7 @@ protected override string ReagentEffectGuidebookText(IPrototypeManager prototype damages.Add( Loc.GetString("health-change-display", - ("kind", group.ID), + ("kind", group.LocalizedName), ("amount", MathF.Abs(amount.Float())), ("deltasign", sign) )); @@ -96,7 +96,7 @@ protected override string ReagentEffectGuidebookText(IPrototypeManager prototype damages.Add( Loc.GetString("health-change-display", - ("kind", kind), + ("kind", prototype.Index(kind).LocalizedName), ("amount", MathF.Abs(amount.Float())), ("deltasign", sign) )); diff --git a/Content.Server/Chemistry/ReagentEffects/ReduceRotting.cs b/Content.Server/Chemistry/ReagentEffects/ReduceRotting.cs new file mode 100644 index 00000000000..cea4f853321 --- /dev/null +++ b/Content.Server/Chemistry/ReagentEffects/ReduceRotting.cs @@ -0,0 +1,31 @@ +using Content.Shared.Chemistry.Reagent; +using JetBrains.Annotations; +using Robust.Shared.Prototypes; +using Content.Server.Atmos.Rotting; + +namespace Content.Server.Chemistry.ReagentEffects +{ + /// + /// Reduces the rotting accumulator on the patient, making them revivable. + /// + [UsedImplicitly] + public sealed partial class ReduceRotting : ReagentEffect + { + [DataField("seconds")] + public double RottingAmount = 10; + + protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys) + => Loc.GetString("reagent-effect-guidebook-reduce-rotting", + ("chance", Probability), + ("time", RottingAmount)); + public override void Effect(ReagentEffectArgs args) + { + if (args.Scale != 1f) + return; + + var rottingSys = args.EntityManager.EntitySysManager.GetEntitySystem(); + + rottingSys.ReduceAccumulator(args.SolutionEntity, TimeSpan.FromSeconds(RottingAmount)); + } + } +} diff --git a/Content.Server/Cloning/CloningConsoleSystem.cs b/Content.Server/Cloning/CloningConsoleSystem.cs index 524cbe80e48..c0685024aae 100644 --- a/Content.Server/Cloning/CloningConsoleSystem.cs +++ b/Content.Server/Cloning/CloningConsoleSystem.cs @@ -138,17 +138,17 @@ private void OnAnchorChanged(EntityUid uid, CloningConsoleComponent component, r public void UpdateUserInterface(EntityUid consoleUid, CloningConsoleComponent consoleComponent) { - if (!_uiSystem.TryGetUi(consoleUid, CloningConsoleUiKey.Key, out var ui)) + if (!_uiSystem.HasUi(consoleUid, CloningConsoleUiKey.Key)) return; if (!_powerReceiverSystem.IsPowered(consoleUid)) { - _uiSystem.CloseAll(ui); + _uiSystem.CloseUis(consoleUid); return; } var newState = GetUserInterfaceState(consoleComponent); - _uiSystem.SetUiState(ui, newState); + _uiSystem.SetUiState(consoleUid, CloningConsoleUiKey.Key, newState); } public void TryClone(EntityUid uid, EntityUid cloningPodUid, EntityUid scannerUid, CloningPodComponent cloningPod, MedicalScannerComponent? scannerComp = null, CloningConsoleComponent? consoleComponent = null) diff --git a/Content.Server/Clothing/MagbootsSystem.cs b/Content.Server/Clothing/MagbootsSystem.cs index bc6880552fc..f12558389e3 100644 --- a/Content.Server/Clothing/MagbootsSystem.cs +++ b/Content.Server/Clothing/MagbootsSystem.cs @@ -1,7 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Alert; using Content.Shared.Clothing; -using Content.Shared.Inventory.Events; namespace Content.Server.Clothing; @@ -13,8 +12,8 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); } protected override void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bool state, MagbootsComponent? component) @@ -38,19 +37,13 @@ protected override void UpdateMagbootEffects(EntityUid parent, EntityUid uid, bo } } - private void OnGotUnequipped(EntityUid uid, MagbootsComponent component, GotUnequippedEvent args) + private void OnGotUnequipped(EntityUid uid, MagbootsComponent component, ref ClothingGotUnequippedEvent args) { - if (args.Slot == "shoes") - { - UpdateMagbootEffects(args.Equipee, uid, false, component); - } + UpdateMagbootEffects(args.Wearer, uid, false, component); } - private void OnGotEquipped(EntityUid uid, MagbootsComponent component, GotEquippedEvent args) + private void OnGotEquipped(EntityUid uid, MagbootsComponent component, ref ClothingGotEquippedEvent args) { - if (args.Slot == "shoes") - { - UpdateMagbootEffects(args.Equipee, uid, true, component); - } + UpdateMagbootEffects(args.Wearer, uid, true, component); } } diff --git a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs index 6fbfd9f3673..e20a6c3da97 100644 --- a/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs +++ b/Content.Server/Clothing/Systems/ChameleonClothingSystem.cs @@ -64,7 +64,7 @@ private void UpdateUi(EntityUid uid, ChameleonClothingComponent? component = nul return; var state = new ChameleonBoundUserInterfaceState(component.Slot, component.Default); - _uiSystem.TrySetUiState(uid, ChameleonUiKey.Key, state); + _uiSystem.SetUiState(uid, ChameleonUiKey.Key, state); } /// diff --git a/Content.Server/Communications/CommunicationsConsoleSystem.cs b/Content.Server/Communications/CommunicationsConsoleSystem.cs index b68a952105e..1cffcf5816a 100644 --- a/Content.Server/Communications/CommunicationsConsoleSystem.cs +++ b/Content.Server/Communications/CommunicationsConsoleSystem.cs @@ -86,8 +86,8 @@ public override void Update(float frameTime) comp.UIUpdateAccumulator -= UIUpdateInterval; - if (_uiSystem.TryGetUi(uid, CommunicationsConsoleUiKey.Key, out var ui) && ui.SubscribedSessions.Count > 0) - UpdateCommsConsoleInterface(uid, comp, ui); + if (_uiSystem.IsUiOpen(uid, CommunicationsConsoleUiKey.Key)) + UpdateCommsConsoleInterface(uid, comp); } base.Update(frameTime); @@ -140,11 +140,8 @@ public void UpdateCommsConsoleInterface() /// /// Updates the UI for a particular comms console. /// - public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComponent comp, PlayerBoundUserInterface? ui = null) + public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComponent comp) { - if (ui == null && !_uiSystem.TryGetUi(uid, CommunicationsConsoleUiKey.Key, out ui)) - return; - var stationUid = _stationSystem.GetOwningStation(uid); List? levels = null; string currentLevel = default!; @@ -172,7 +169,7 @@ public void UpdateCommsConsoleInterface(EntityUid uid, CommunicationsConsoleComp } } - _uiSystem.SetUiState(ui, new CommunicationsConsoleInterfaceState( + _uiSystem.SetUiState(uid, CommunicationsConsoleUiKey.Key, new CommunicationsConsoleInterfaceState( CanAnnounce(comp), CanCallOrRecall(comp), levels, @@ -223,12 +220,12 @@ private bool CanCallOrRecall(CommunicationsConsoleComponent comp) private void OnSelectAlertLevelMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleSelectAlertLevelMessage message) { - if (message.Session.AttachedEntity is not { Valid: true } mob) + if (message.Actor is not { Valid: true } mob) return; if (!CanUse(mob, uid)) { - _popupSystem.PopupCursor(Loc.GetString("comms-console-permission-denied"), message.Session, PopupType.Medium); + _popupSystem.PopupCursor(Loc.GetString("comms-console-permission-denied"), message.Actor, PopupType.Medium); return; } @@ -245,7 +242,7 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength); var msg = SharedChatSystem.SanitizeAnnouncement(message.Message, maxLength); var author = Loc.GetString("comms-console-announcement-unknown-sender"); - if (message.Session.AttachedEntity is { Valid: true } mob) + if (message.Actor is { Valid: true } mob) { if (!CanAnnounce(comp)) { @@ -254,7 +251,7 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com if (!CanUse(mob, uid)) { - _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session); + _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Actor); return; } @@ -267,7 +264,7 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com comp.AnnouncementCooldownRemaining = comp.Delay; UpdateCommsConsoleInterface(uid, comp); - var ev = new CommunicationConsoleAnnouncementEvent(uid, comp, msg, message.Session.AttachedEntity); + var ev = new CommunicationConsoleAnnouncementEvent(uid, comp, msg, message.Actor); RaiseLocalEvent(ref ev); // allow admemes with vv @@ -279,17 +276,16 @@ private void OnAnnounceMessage(EntityUid uid, CommunicationsConsoleComponent com { _announcer.SendAnnouncement("announce", Filter.Broadcast(), msg, title, comp.Color); - if (message.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following global announcement: {msg}"); - + _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Actor):player} has sent the following global announcement: {msg}"); return; } + if (TryComp(_stationSystem.GetOwningStation(uid), out var stationData)) _announcer.SendAnnouncement("announce", _stationSystem.GetInStation(stationData), msg, title, comp.Color); - if (message.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following station announcement: {msg}"); + _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(message.Actor):player} has sent the following station announcement: {msg}"); + } private void OnBroadcastMessage(EntityUid uid, CommunicationsConsoleComponent component, CommunicationsConsoleBroadcastMessage message) @@ -304,8 +300,7 @@ private void OnBroadcastMessage(EntityUid uid, CommunicationsConsoleComponent co _deviceNetworkSystem.QueuePacket(uid, null, payload, net.TransmitFrequency); - if (message.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceNetwork, LogImpact.Low, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} has sent the following broadcast: {message.Message:msg}"); + _adminLogger.Add(LogType.DeviceNetwork, LogImpact.Low, $"{ToPrettyString(message.Actor):player} has sent the following broadcast: {message.Message:msg}"); } private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent comp, CommunicationsConsoleCallEmergencyShuttleMessage message) @@ -313,12 +308,11 @@ private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent if (!CanCallOrRecall(comp)) return; - if (message.Session.AttachedEntity is not { Valid: true } mob) - return; + var mob = message.Actor; if (!CanUse(mob, uid)) { - _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session); + _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Actor); return; } @@ -326,7 +320,7 @@ private void OnCallShuttleMessage(EntityUid uid, CommunicationsConsoleComponent RaiseLocalEvent(ref ev); if (ev.Cancelled) { - _popupSystem.PopupEntity(ev.Reason ?? Loc.GetString("comms-console-shuttle-unavailable"), uid, message.Session); + _popupSystem.PopupEntity(ev.Reason ?? Loc.GetString("comms-console-shuttle-unavailable"), uid, message.Actor); return; } @@ -339,17 +333,14 @@ private void OnRecallShuttleMessage(EntityUid uid, CommunicationsConsoleComponen if (!CanCallOrRecall(comp)) return; - if (message.Session.AttachedEntity is not { Valid: true } mob) - return; - - if (!CanUse(mob, uid)) + if (!CanUse(message.Actor, uid)) { - _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Session); + _popupSystem.PopupEntity(Loc.GetString("comms-console-permission-denied"), uid, message.Actor); return; } _roundEndSystem.CancelRoundEndCountdown(uid); - _adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(mob):player} has recalled the shuttle."); + _adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(message.Actor):player} has recalled the shuttle."); } } diff --git a/Content.Server/Configurable/ConfigurationSystem.cs b/Content.Server/Configurable/ConfigurationSystem.cs index eb31149ecae..2683bf4e095 100644 --- a/Content.Server/Configurable/ConfigurationSystem.cs +++ b/Content.Server/Configurable/ConfigurationSystem.cs @@ -30,10 +30,7 @@ private void OnInteractUsing(EntityUid uid, ConfigurationComponent component, In if (!TryComp(args.Used, out ToolComponent? tool) || !tool.Qualities.Contains(component.QualityNeeded)) return; - if (!TryComp(args.User, out ActorComponent? actor)) - return; - - args.Handled = _uiSystem.TryOpen(uid, ConfigurationUiKey.Key, actor.PlayerSession); + args.Handled = _uiSystem.TryOpenUi(uid, ConfigurationUiKey.Key, args.User); } private void OnStartup(EntityUid uid, ConfigurationComponent component, ComponentStartup args) @@ -43,8 +40,8 @@ private void OnStartup(EntityUid uid, ConfigurationComponent component, Componen private void UpdateUi(EntityUid uid, ConfigurationComponent component) { - if (_uiSystem.TryGetUi(uid, ConfigurationUiKey.Key, out var ui)) - _uiSystem.SetUiState(ui, new ConfigurationBoundUserInterfaceState(component.Config)); + if (_uiSystem.HasUi(uid, ConfigurationUiKey.Key)) + _uiSystem.SetUiState(uid, ConfigurationUiKey.Key, new ConfigurationBoundUserInterfaceState(component.Config)); } private void OnUpdate(EntityUid uid, ConfigurationComponent component, ConfigurationUpdatedMessage args) diff --git a/Content.Server/Construction/Components/WelderRefinableComponent.cs b/Content.Server/Construction/Components/WelderRefinableComponent.cs index dc3074f1958..31b029e2415 100644 --- a/Content.Server/Construction/Components/WelderRefinableComponent.cs +++ b/Content.Server/Construction/Components/WelderRefinableComponent.cs @@ -2,22 +2,24 @@ using Content.Shared.Storage; using Robust.Shared.Prototypes; -namespace Content.Server.Construction.Components +namespace Content.Server.Construction.Components; + +/// +/// Used for something that can be refined by welder. +/// For example, glass shard can be refined to glass sheet. +/// +[RegisterComponent] +public sealed partial class WelderRefinableComponent : Component { - /// - /// Used for something that can be refined by welder. - /// For example, glass shard can be refined to glass sheet. - /// - [RegisterComponent] - public sealed partial class WelderRefinableComponent : Component - { - [DataField] - public List RefineResult = new(); + [DataField] + public HashSet? RefineResult; + + [DataField] + public float RefineTime = 2f; - [DataField] - public float RefineTime = 2f; + [DataField] + public float RefineFuel; - [DataField] - public ProtoId QualityNeeded = "Welding"; - } + [DataField] + public ProtoId QualityNeeded = "Welding"; } diff --git a/Content.Server/Construction/Conditions/Locked.cs b/Content.Server/Construction/Conditions/Locked.cs index fde704b161b..0b8c9118dc7 100644 --- a/Content.Server/Construction/Conditions/Locked.cs +++ b/Content.Server/Construction/Conditions/Locked.cs @@ -15,7 +15,7 @@ public sealed partial class Locked : IGraphCondition public bool Condition(EntityUid uid, IEntityManager entityManager) { if (!entityManager.TryGetComponent(uid, out LockComponent? lockcomp)) - return false; + return true; return lockcomp.Locked == IsLocked; } @@ -25,7 +25,8 @@ public bool DoExamine(ExaminedEvent args) var entMan = IoCManager.Resolve(); var entity = args.Examined; - if (!entMan.TryGetComponent(entity, out LockComponent? lockcomp)) return false; + if (!entMan.TryGetComponent(entity, out LockComponent? lockcomp)) + return true; switch (IsLocked) { diff --git a/Content.Server/Construction/ConstructionSystem.Guided.cs b/Content.Server/Construction/ConstructionSystem.Guided.cs index fe7f9152c0b..e096bc02c31 100644 --- a/Content.Server/Construction/ConstructionSystem.Guided.cs +++ b/Content.Server/Construction/ConstructionSystem.Guided.cs @@ -41,6 +41,18 @@ private void AddDeconstructVerb(EntityUid uid, ConstructionComponent component, component.Node == component.DeconstructionNode) return; + if (!_prototypeManager.TryIndex(component.Graph, out ConstructionGraphPrototype? graph)) + return; + + if (component.DeconstructionNode == null) + return; + + if (GetCurrentNode(uid, component) is not {} currentNode) + return; + + if (graph.Path(currentNode.Name, component.DeconstructionNode) is not {} path || path.Length == 0) + return; + Verb verb = new(); //verb.Category = VerbCategories.Construction; //TODO VERBS add more construction verbs? Until then, removing construction category diff --git a/Content.Server/Construction/ConstructionSystem.Interactions.cs b/Content.Server/Construction/ConstructionSystem.Interactions.cs index 946aaa0d3ee..5361b65b1ff 100644 --- a/Content.Server/Construction/ConstructionSystem.Interactions.cs +++ b/Content.Server/Construction/ConstructionSystem.Interactions.cs @@ -11,10 +11,8 @@ using Content.Shared.Interaction; using Content.Shared.Prying.Systems; using Content.Shared.Radio.EntitySystems; -using Content.Shared.Tools.Components; using Content.Shared.Tools.Systems; using Robust.Shared.Containers; -using Robust.Shared.Map; using Robust.Shared.Utility; #if EXCEPTION_TOLERANCE // ReSharper disable once RedundantUsingDirective @@ -370,7 +368,8 @@ private HandleResult HandleInteraction(EntityUid uid, object ev, ConstructionGra TimeSpan.FromSeconds(toolInsertStep.DoAfter), new [] { toolInsertStep.Tool }, new ConstructionInteractDoAfterEvent(EntityManager, interactUsing), - out var doAfter); + out var doAfter, + toolInsertStep.Fuel); return result && doAfter != null ? HandleResult.DoAfter : HandleResult.False; } diff --git a/Content.Server/Construction/RefiningSystem.cs b/Content.Server/Construction/RefiningSystem.cs index d4df8b0916b..2ca32baf906 100644 --- a/Content.Server/Construction/RefiningSystem.cs +++ b/Content.Server/Construction/RefiningSystem.cs @@ -2,43 +2,50 @@ using Content.Server.Stack; using Content.Shared.Construction; using Content.Shared.Interaction; +using Content.Shared.Stacks; using Content.Shared.Storage; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; -namespace Content.Server.Construction +namespace Content.Server.Construction; + +public sealed class RefiningSystem : EntitySystem { - public sealed class RefiningSystem : EntitySystem + [Dependency] private readonly SharedToolSystem _toolSystem = default!; + [Dependency] private readonly StackSystem _stackSystem = default!; + + public override void Initialize() { - [Dependency] private readonly SharedToolSystem _toolSystem = default!; - public override void Initialize() - { - base.Initialize(); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnDoAfter); - } + base.Initialize(); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnDoAfter); + } - private void OnInteractUsing(EntityUid uid, WelderRefinableComponent component, InteractUsingEvent args) - { - if (args.Handled) - return; + private void OnInteractUsing(EntityUid uid, WelderRefinableComponent component, InteractUsingEvent args) + { + if (args.Handled) + return; - args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, component.RefineTime, component.QualityNeeded, new WelderRefineDoAfterEvent()); - } + args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, component.RefineTime, component.QualityNeeded, new WelderRefineDoAfterEvent(), fuel: component.RefineFuel); + } + + private void OnDoAfter(EntityUid uid, WelderRefinableComponent component, WelderRefineDoAfterEvent args) + { + if (args.Cancelled) + return; + + // Get last owner coordinates and delete it + var resultPosition = Transform(uid).Coordinates; + EntityManager.DeleteEntity(uid); - private void OnDoAfter(EntityUid uid, WelderRefinableComponent component, WelderRefineDoAfterEvent args) + // Spawn each result after refine + foreach (var ent in EntitySpawnCollection.GetSpawns(component.RefineResult ?? new())) { - if (args.Cancelled) - return; - - // get last owner coordinates and delete it - var resultPosition = Transform(uid).Coordinates; - EntityManager.DeleteEntity(uid); - - // spawn each result after refine - foreach (var ent in EntitySpawnCollection.GetSpawns(component.RefineResult)) - { - Spawn(ent, resultPosition); - } + var droppedEnt = Spawn(ent, resultPosition); + + // TODO: If something has a stack... Just use a prototype with a single thing in the stack. + // This is not a good way to do it. + if (TryComp(droppedEnt, out var stack)) + _stackSystem.SetCount(droppedEnt, 1, stack); } } } diff --git a/Content.Server/Containers/ThrowInsertContainerComponent.cs b/Content.Server/Containers/ThrowInsertContainerComponent.cs new file mode 100644 index 00000000000..7eb5f4657d0 --- /dev/null +++ b/Content.Server/Containers/ThrowInsertContainerComponent.cs @@ -0,0 +1,35 @@ +using Robust.Shared.Audio; + +namespace Content.Server.Containers; + +/// +/// Allows objects to fall inside the Container when thrown +/// +[RegisterComponent] +[Access(typeof(ThrowInsertContainerSystem))] +public sealed partial class ThrowInsertContainerComponent : Component +{ + [DataField(required: true)] + public string ContainerId = string.Empty; + + /// + /// Throw chance of hitting into the container + /// + [DataField] + public float Probability = 0.75f; + + /// + /// Sound played when an object is throw into the container. + /// + [DataField] + public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg"); + + /// + /// Sound played when an item is thrown and misses the container. + /// + [DataField] + public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"); + + [DataField] + public LocId MissLocString = "container-thrown-missed"; +} diff --git a/Content.Server/Containers/ThrowInsertContainerSystem.cs b/Content.Server/Containers/ThrowInsertContainerSystem.cs new file mode 100644 index 00000000000..12bb602811a --- /dev/null +++ b/Content.Server/Containers/ThrowInsertContainerSystem.cs @@ -0,0 +1,50 @@ +using Content.Server.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Popups; +using Content.Shared.Throwing; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Containers; +using Robust.Shared.Random; + +namespace Content.Server.Containers; + +public sealed class ThrowInsertContainerSystem : EntitySystem +{ + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedContainerSystem _containerSystem = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnThrowCollide); + } + + private void OnThrowCollide(Entity ent, ref ThrowHitByEvent args) + { + var container = _containerSystem.GetContainer(ent, ent.Comp.ContainerId); + + if (!_containerSystem.CanInsert(args.Thrown, container)) + return; + + + var rand = _random.NextFloat(); + if (_random.Prob(ent.Comp.Probability)) + { + _audio.PlayPvs(ent.Comp.MissSound, ent); + _popup.PopupEntity(Loc.GetString(ent.Comp.MissLocString), ent); + return; + } + + if (!_containerSystem.Insert(args.Thrown, container)) + throw new InvalidOperationException("Container insertion failed but CanInsert returned true"); + + _audio.PlayPvs(ent.Comp.InsertSound, ent); + + if (args.Component.Thrower != null) + _adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(ent)}"); + } +} diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj index 8782454eacb..70e404fdef0 100644 --- a/Content.Server/Content.Server.csproj +++ b/Content.Server/Content.Server.csproj @@ -28,7 +28,6 @@ - diff --git a/Content.Server/Crayon/CrayonSystem.cs b/Content.Server/Crayon/CrayonSystem.cs index 32bb96e9e28..07a13d8a34a 100644 --- a/Content.Server/Crayon/CrayonSystem.cs +++ b/Content.Server/Crayon/CrayonSystem.cs @@ -90,19 +90,14 @@ private void OnCrayonUse(EntityUid uid, CrayonComponent component, UseInHandEven if (args.Handled) return; - if (!TryComp(args.User, out var actor) || - !_uiSystem.TryGetUi(uid, SharedCrayonComponent.CrayonUiKey.Key, out var ui)) + if (!_uiSystem.HasUi(uid, SharedCrayonComponent.CrayonUiKey.Key)) { return; } - _uiSystem.ToggleUi(ui, actor.PlayerSession); - if (ui.SubscribedSessions.Contains(actor.PlayerSession)) - { - // Tell the user interface the selected stuff - _uiSystem.SetUiState(ui, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color)); - } + _uiSystem.TryToggleUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User); + _uiSystem.SetUiState(uid, SharedCrayonComponent.CrayonUiKey.Key, new CrayonBoundUserInterfaceState(component.SelectedState, component.SelectableColor, component.Color)); args.Handled = true; } @@ -140,8 +135,8 @@ private void OnCrayonInit(EntityUid uid, CrayonComponent component, ComponentIni private void OnCrayonDropped(EntityUid uid, CrayonComponent component, DroppedEvent args) { - if (TryComp(args.User, out var actor)) - _uiSystem.TryClose(uid, SharedCrayonComponent.CrayonUiKey.Key, actor.PlayerSession); + // TODO: Use the existing event. + _uiSystem.CloseUi(uid, SharedCrayonComponent.CrayonUiKey.Key, args.User); } private void UseUpCrayon(EntityUid uid, EntityUid user) diff --git a/Content.Server/CrewManifest/CrewManifestSystem.cs b/Content.Server/CrewManifest/CrewManifestSystem.cs index 8b4cbac5c15..e7424560159 100644 --- a/Content.Server/CrewManifest/CrewManifestSystem.cs +++ b/Content.Server/CrewManifest/CrewManifestSystem.cs @@ -100,12 +100,12 @@ private void OnBoundUiClose(EntityUid uid, CrewManifestViewerComponent component return; var owningStation = _stationSystem.GetOwningStation(uid); - if (owningStation == null || ev.Session is not { } session) + if (owningStation == null || !TryComp(ev.Actor, out ActorComponent? actorComp)) { return; } - CloseEui(owningStation.Value, session, uid); + CloseEui(owningStation.Value, actorComp.PlayerSession, uid); } /// @@ -136,12 +136,12 @@ private void OpenEuiFromBui(EntityUid uid, CrewManifestViewerComponent component { Log.Error( "{User} tried to open crew manifest from wrong UI: {Key}. Correct owned is {ExpectedKey}", - msg.Session, msg.UiKey, component.OwnerKey); + msg.Actor, msg.UiKey, component.OwnerKey); return; } var owningStation = _stationSystem.GetOwningStation(uid); - if (owningStation == null || msg.Session is not { } session) + if (owningStation == null || !TryComp(msg.Actor, out ActorComponent? actorComp)) { return; } @@ -151,7 +151,7 @@ private void OpenEuiFromBui(EntityUid uid, CrewManifestViewerComponent component return; } - OpenEui(owningStation.Value, session, uid); + OpenEui(owningStation.Value, actorComp.PlayerSession, uid); } /// diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs index 4290726cc40..4389c68c049 100644 --- a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs +++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs @@ -77,7 +77,7 @@ private void OnChangeStatus(Entity ent, ref Cri msg.Status == SecurityStatus.Suspected != (msg.Reason != null)) return; - if (!CheckSelected(ent, msg.Session, out var mob, out var key)) + if (!CheckSelected(ent, msg.Actor, out var mob, out var key)) return; if (!_stationRecords.TryGetRecord(key.Value, out var record) || record.Status == msg.Status) @@ -150,7 +150,7 @@ private void OnChangeStatus(Entity ent, ref Cri private void OnAddHistory(Entity ent, ref CriminalRecordAddHistory msg) { - if (!CheckSelected(ent, msg.Session, out _, out var key)) + if (!CheckSelected(ent, msg.Actor, out _, out var key)) return; var line = msg.Line.Trim(); @@ -167,7 +167,7 @@ private void OnAddHistory(Entity ent, ref Crimi private void OnDeleteHistory(Entity ent, ref CriminalRecordDeleteHistory msg) { - if (!CheckSelected(ent, msg.Session, out _, out var key)) + if (!CheckSelected(ent, msg.Actor, out _, out var key)) return; if (!_criminalRecords.TryDeleteHistory(key.Value, msg.Index)) @@ -185,7 +185,7 @@ private void UpdateUserInterface(Entity ent) if (!TryComp(owningStation, out var stationRecords)) { - _ui.TrySetUiState(uid, CriminalRecordsConsoleKey.Key, new CriminalRecordsConsoleState()); + _ui.SetUiState(uid, CriminalRecordsConsoleKey.Key, new CriminalRecordsConsoleState()); return; } @@ -201,24 +201,22 @@ private void UpdateUserInterface(Entity ent) state.SelectedKey = id; } - _ui.TrySetUiState(uid, CriminalRecordsConsoleKey.Key, state); + _ui.SetUiState(uid, CriminalRecordsConsoleKey.Key, state); } /// /// Boilerplate that most actions use, if they require that a record be selected. /// Obviously shouldn't be used for selecting records. /// - private bool CheckSelected(Entity ent, ICommonSession session, + private bool CheckSelected(Entity ent, EntityUid user, [NotNullWhen(true)] out EntityUid? mob, [NotNullWhen(true)] out StationRecordKey? key) { key = null; mob = null; - if (session.AttachedEntity is not { } user) - return false; if (!_access.IsAllowed(user, ent)) { - _popup.PopupEntity(Loc.GetString("criminal-records-permission-denied"), ent, session); + _popup.PopupEntity(Loc.GetString("criminal-records-permission-denied"), ent, user); return false; } @@ -253,6 +251,8 @@ public void CheckNewIdentity(EntityUid uid) { var name = Identity.Name(uid, EntityManager); var xform = Transform(uid); + + // TODO use the entity's station? Not the station of the map that it happens to currently be on? var station = _station.GetStationInMap(xform.MapID); if (station != null && _stationRecords.GetRecordByName(station.Value, name) is { } id) diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs new file mode 100644 index 00000000000..91285a1ca73 --- /dev/null +++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsHackerSystem.cs @@ -0,0 +1,62 @@ +using Content.Server.Chat.Systems; +using Content.Server.Station.Systems; +using Content.Server.StationRecords.Systems; +using Content.Shared.CriminalRecords; +using Content.Shared.CriminalRecords.Components; +using Content.Shared.CriminalRecords.Systems; +using Content.Shared.Dataset; +using Content.Shared.Security; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.CriminalRecords.Systems; + +public sealed class CriminalRecordsHackerSystem : SharedCriminalRecordsHackerSystem +{ + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly StationRecordsSystem _records = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDoAfter); + } + + private void OnDoAfter(Entity ent, ref CriminalRecordsHackDoAfterEvent args) + { + if (args.Cancelled || args.Handled || args.Target == null) + return; + + if (_station.GetOwningStation(ent) is not {} station) + return; + + var reasons = _proto.Index(ent.Comp.Reasons); + foreach (var (key, record) in _records.GetRecordsOfType(station)) + { + var reason = _random.Pick(reasons.Values); + record.Status = SecurityStatus.Wanted; + record.Reason = reason; + // no radio message since spam + // no history since lazy and its easy to remove anyway + // main damage with this is existing arrest warrants are lost and to anger beepsky + } + + _chat.DispatchGlobalAnnouncement(Loc.GetString(ent.Comp.Announcement), playSound: true, colorOverride: Color.Red); + + // once is enough + RemComp(ent); + + var ev = new CriminalRecordsHackedEvent(ent, args.Target.Value); + RaiseLocalEvent(args.User, ref ev); + } +} + +/// +/// Raised on the user after hacking a criminal records console. +/// +[ByRefEvent] +public record struct CriminalRecordsHackedEvent(EntityUid User, EntityUid Target); diff --git a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs index 264ec4a8ec4..42676c1891c 100644 --- a/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs +++ b/Content.Server/Damage/Systems/DamageOnToolInteractSystem.cs @@ -1,7 +1,5 @@ using Content.Server.Administration.Logs; using Content.Server.Damage.Components; -using Content.Server.Tools.Components; -using Content.Shared.Item; using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Interaction; diff --git a/Content.Server/Database/ServerDbBase.cs b/Content.Server/Database/ServerDbBase.cs index af9220ee6db..d44c3b483d9 100644 --- a/Content.Server/Database/ServerDbBase.cs +++ b/Content.Server/Database/ServerDbBase.cs @@ -31,9 +31,11 @@ public ServerDbBase(ISawmill opsLog) } #region Preferences - public async Task GetPlayerPreferencesAsync(NetUserId userId) + public async Task GetPlayerPreferencesAsync( + NetUserId userId, + CancellationToken cancel = default) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); var prefs = await db.DbContext .Preference @@ -42,7 +44,7 @@ public ServerDbBase(ISawmill opsLog) .Include(p => p.Profiles).ThenInclude(h => h.Traits) .Include(p => p.Profiles).ThenInclude(h => h.Loadouts) .AsSingleQuery() - .SingleOrDefaultAsync(p => p.UserId == userId.UserId); + .SingleOrDefaultAsync(p => p.UserId == userId.UserId, cancel); if (prefs is null) return null; @@ -221,8 +223,7 @@ private static HumanoidCharacterProfile ConvertProfiles(Profile profile) profile.Age, sex, gender, - new HumanoidCharacterAppearance - ( + new HumanoidCharacterAppearance( profile.HairName, Color.FromHex(profile.HairColor), profile.FacialHairName, @@ -231,14 +232,14 @@ private static HumanoidCharacterProfile ConvertProfiles(Profile profile) Color.FromHex(profile.SkinColor), markings ), - clothing, - backpack, spawnPriority, jobs, + clothing, + backpack, (PreferenceUnavailableMode) profile.PreferenceUnavailable, - antags.ToList(), - traits.ToList(), - loadouts.ToList() + antags.ToHashSet(), + traits.ToHashSet(), + loadouts.ToHashSet() ); } @@ -480,13 +481,13 @@ public async Task EditServerRoleBan(int id, string reason, NoteSeverity severity #endregion #region Playtime - public async Task> GetPlayTimes(Guid player) + public async Task> GetPlayTimes(Guid player, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); return await db.DbContext.PlayTime .Where(p => p.PlayerId == player) - .ToListAsync(); + .ToListAsync(cancel); } public async Task UpdatePlayTimes(IReadOnlyCollection updates) @@ -638,7 +639,7 @@ public async Task AddServerBanHitsAsync(int connection, IEnumerable GetAdminDataForAsync(NetUserId userId, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); return await db.DbContext.Admin .Include(p => p.Flags) @@ -653,7 +654,7 @@ public async Task AddServerBanHitsAsync(int connection, IEnumerable GetAdminRankDataForAsync(int id, CancellationToken cancel = default) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); return await db.DbContext.AdminRank .Include(r => r.Flags) @@ -662,7 +663,7 @@ public async Task AddServerBanHitsAsync(int connection, IEnumerable a.UserId == userId.UserId, cancel); db.DbContext.Admin.Remove(admin); @@ -672,7 +673,7 @@ public async Task RemoveAdminAsync(NetUserId userId, CancellationToken cancel) public async Task AddAdminAsync(Admin admin, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); db.DbContext.Admin.Add(admin); @@ -681,7 +682,7 @@ public async Task AddAdminAsync(Admin admin, CancellationToken cancel) public async Task UpdateAdminAsync(Admin admin, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); var existing = await db.DbContext.Admin.Include(a => a.Flags).SingleAsync(a => a.UserId == admin.UserId, cancel); existing.Flags = admin.Flags; @@ -693,7 +694,7 @@ public async Task UpdateAdminAsync(Admin admin, CancellationToken cancel) public async Task RemoveAdminRankAsync(int rankId, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); var admin = await db.DbContext.AdminRank.SingleAsync(a => a.Id == rankId, cancel); db.DbContext.AdminRank.Remove(admin); @@ -703,7 +704,7 @@ public async Task RemoveAdminRankAsync(int rankId, CancellationToken cancel) public async Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); db.DbContext.AdminRank.Add(rank); @@ -776,7 +777,7 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id} public async Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel) { - await using var db = await GetDb(); + await using var db = await GetDb(cancel); var existing = await db.DbContext.AdminRank .Include(r => r.Flags) @@ -1559,7 +1560,9 @@ public async Task HasPendingModelChanges() return db.DbContext.Database.HasPendingModelChanges(); } - protected abstract Task GetDb([CallerMemberName] string? name = null); + protected abstract Task GetDb( + CancellationToken cancel = default, + [CallerMemberName] string? name = null); protected void LogDbOp(string? name) { diff --git a/Content.Server/Database/ServerDbManager.cs b/Content.Server/Database/ServerDbManager.cs index 554dd307437..01d15267274 100644 --- a/Content.Server/Database/ServerDbManager.cs +++ b/Content.Server/Database/ServerDbManager.cs @@ -29,7 +29,11 @@ public interface IServerDbManager void Shutdown(); #region Preferences - Task InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile); + Task InitPrefsAsync( + NetUserId userId, + ICharacterProfile defaultProfile, + CancellationToken cancel); + Task SaveSelectedCharacterIndexAsync(NetUserId userId, int index); Task SaveCharacterSlotAsync(NetUserId userId, ICharacterProfile? profile, int slot); @@ -38,7 +42,7 @@ public interface IServerDbManager // Single method for two operations for transaction. Task DeleteSlotAndSetSelectedIndex(NetUserId userId, int deleteSlot, int newSlot); - Task GetPlayerPreferencesAsync(NetUserId userId); + Task GetPlayerPreferencesAsync(NetUserId userId, CancellationToken cancel); #endregion #region User Ids @@ -157,8 +161,9 @@ public Task EditServerRoleBan( /// Look up a player's role timers. /// /// The player to get the role timer information from. + /// /// All role timers belonging to the player. - Task> GetPlayTimes(Guid player); + Task> GetPlayTimes(Guid player, CancellationToken cancel = default); /// /// Update play time information in bulk. @@ -346,7 +351,10 @@ public void Shutdown() _sqliteInMemoryConnection?.Dispose(); } - public Task InitPrefsAsync(NetUserId userId, ICharacterProfile defaultProfile) + public Task InitPrefsAsync( + NetUserId userId, + ICharacterProfile defaultProfile, + CancellationToken cancel) { DbWriteOpsMetric.Inc(); return RunDbCommand(() => _db.InitPrefsAsync(userId, defaultProfile)); @@ -376,10 +384,10 @@ public Task SaveAdminOOCColorAsync(NetUserId userId, Color color) return RunDbCommand(() => _db.SaveAdminOOCColorAsync(userId, color)); } - public Task GetPlayerPreferencesAsync(NetUserId userId) + public Task GetPlayerPreferencesAsync(NetUserId userId, CancellationToken cancel) { DbReadOpsMetric.Inc(); - return RunDbCommand(() => _db.GetPlayerPreferencesAsync(userId)); + return RunDbCommand(() => _db.GetPlayerPreferencesAsync(userId, cancel)); } public Task AssignUserIdAsync(string name, NetUserId userId) @@ -487,10 +495,10 @@ public Task EditServerRoleBan(int id, string reason, NoteSeverity severity, Date #region Playtime - public Task> GetPlayTimes(Guid player) + public Task> GetPlayTimes(Guid player, CancellationToken cancel) { DbReadOpsMetric.Inc(); - return RunDbCommand(() => _db.GetPlayTimes(player)); + return RunDbCommand(() => _db.GetPlayTimes(player, cancel)); } public Task UpdatePlayTimes(IReadOnlyCollection updates) diff --git a/Content.Server/Database/ServerDbPostgres.cs b/Content.Server/Database/ServerDbPostgres.cs index c81e735868a..fd4699fff4e 100644 --- a/Content.Server/Database/ServerDbPostgres.cs +++ b/Content.Server/Database/ServerDbPostgres.cs @@ -527,22 +527,26 @@ protected override DateTime NormalizeDatabaseTime(DateTime time) return time; } - private async Task GetDbImpl([CallerMemberName] string? name = null) + private async Task GetDbImpl( + CancellationToken cancel = default, + [CallerMemberName] string? name = null) { LogDbOp(name); await _dbReadyTask; - await _prefsSemaphore.WaitAsync(); + await _prefsSemaphore.WaitAsync(cancel); if (_msLag > 0) - await Task.Delay(_msLag); + await Task.Delay(_msLag, cancel); return new DbGuardImpl(this, new PostgresServerDbContext(_options)); } - protected override async Task GetDb([CallerMemberName] string? name = null) + protected override async Task GetDb( + CancellationToken cancel = default, + [CallerMemberName] string? name = null) { - return await GetDbImpl(name); + return await GetDbImpl(cancel, name); } private sealed class DbGuardImpl : DbGuard diff --git a/Content.Server/Database/ServerDbSqlite.cs b/Content.Server/Database/ServerDbSqlite.cs index 88ecf820020..ffec90bb43d 100644 --- a/Content.Server/Database/ServerDbSqlite.cs +++ b/Content.Server/Database/ServerDbSqlite.cs @@ -439,7 +439,7 @@ public override async Task AddConnectionLogAsync( public override async Task<((Admin, string? lastUserName)[] admins, AdminRank[])> GetAllAdminAndRanksAsync( CancellationToken cancel) { - await using var db = await GetDbImpl(); + await using var db = await GetDbImpl(cancel); var admins = await db.SqliteDbContext.Admin .Include(a => a.Flags) @@ -514,23 +514,27 @@ protected override DateTime NormalizeDatabaseTime(DateTime time) return DateTime.SpecifyKind(time, DateTimeKind.Utc); } - private async Task GetDbImpl([CallerMemberName] string? name = null) + private async Task GetDbImpl( + CancellationToken cancel = default, + [CallerMemberName] string? name = null) { LogDbOp(name); await _dbReadyTask; if (_msDelay > 0) - await Task.Delay(_msDelay); + await Task.Delay(_msDelay, cancel); - await _prefsSemaphore.WaitAsync(); + await _prefsSemaphore.WaitAsync(cancel); var dbContext = new SqliteServerDbContext(_options()); return new DbGuardImpl(this, dbContext); } - protected override async Task GetDb([CallerMemberName] string? name = null) + protected override async Task GetDb( + CancellationToken cancel = default, + [CallerMemberName] string? name = null) { - return await GetDbImpl(name).ConfigureAwait(false); + return await GetDbImpl(cancel, name).ConfigureAwait(false); } private sealed class DbGuardImpl : DbGuard @@ -569,9 +573,9 @@ public ConcurrencySemaphore(int maxCount, bool synchronous) _semaphore = new SemaphoreSlim(maxCount, maxCount); } - public Task WaitAsync() + public Task WaitAsync(CancellationToken cancel = default) { - var task = _semaphore.WaitAsync(); + var task = _semaphore.WaitAsync(cancel); if (_synchronous) { diff --git a/Content.Server/Database/UserDbDataManager.cs b/Content.Server/Database/UserDbDataManager.cs index f8b1611fd57..c58c594dbad 100644 --- a/Content.Server/Database/UserDbDataManager.cs +++ b/Content.Server/Database/UserDbDataManager.cs @@ -2,6 +2,7 @@ using System.Threading.Tasks; using Content.Server.Players.PlayTimeTracking; using Content.Server.Preferences.Managers; +using Robust.Server.Player; using Robust.Shared.Network; using Robust.Shared.Player; using Robust.Shared.Utility; @@ -16,17 +17,22 @@ namespace Content.Server.Database; /// Actual loading code is handled by separate managers such as . /// This manager is simply a centralized "is loading done" controller for other code to rely on. /// -public sealed class UserDbDataManager +public sealed class UserDbDataManager : IPostInjectInit { [Dependency] private readonly IServerPreferencesManager _prefs = default!; + [Dependency] private readonly ILogManager _logManager = default!; [Dependency] private readonly PlayTimeTrackingManager _playTimeTracking = default!; private readonly Dictionary _users = new(); + private ISawmill _sawmill = default!; + // TODO: Ideally connected/disconnected would be subscribed to IPlayerManager directly, // but this runs into ordering issues with game ticker. public void ClientConnected(ICommonSession session) { + _sawmill.Verbose($"Initiating load for user {session}"); + DebugTools.Assert(!_users.ContainsKey(session.UserId), "We should not have any cached data on client connect."); var cts = new CancellationTokenSource(); @@ -51,11 +57,52 @@ public void ClientDisconnected(ICommonSession session) private async Task Load(ICommonSession session, CancellationToken cancel) { - await Task.WhenAll( - _prefs.LoadData(session, cancel), - _playTimeTracking.LoadData(session, cancel)); + // The task returned by this function is only ever observed by callers of WaitLoadComplete, + // which doesn't even happen currently if the lobby is enabled. + // As such, this task must NOT throw a non-cancellation error! + try + { + await Task.WhenAll( + _prefs.LoadData(session, cancel), + _playTimeTracking.LoadData(session, cancel)); + + cancel.ThrowIfCancellationRequested(); + _prefs.FinishLoad(session); + + _sawmill.Verbose($"Load complete for user {session}"); + } + catch (OperationCanceledException) + { + _sawmill.Debug($"Load cancelled for user {session}"); + + // We can rethrow the cancellation. + // This will make the task returned by WaitLoadComplete() also return a cancellation. + throw; + } + catch (Exception e) + { + // Must catch all exceptions here, otherwise task may go unobserved. + _sawmill.Error($"Load of user data failed: {e}"); + + // Kick them from server, since something is hosed. Let them try again I guess. + session.Channel.Disconnect("Loading of server user data failed, this is a bug."); + + // We throw a OperationCanceledException so users of WaitLoadComplete() always see cancellation here. + throw new OperationCanceledException("Load of user data cancelled due to unknown error"); + } } + /// + /// Wait for all on-database data for a user to be loaded. + /// + /// + /// The task returned by this function may end up in a cancelled state + /// (throwing ) if the user disconnects while loading or an error occurs. + /// + /// + /// + /// A task that completes when all on-database data for a user has finished loading. + /// public Task WaitLoadComplete(ICommonSession session) { return _users[session.UserId].Task; @@ -63,7 +110,7 @@ public Task WaitLoadComplete(ICommonSession session) public bool IsLoadComplete(ICommonSession session) { - return GetLoadTask(session).IsCompleted; + return GetLoadTask(session).IsCompletedSuccessfully; } public Task GetLoadTask(ICommonSession session) @@ -71,5 +118,10 @@ public Task GetLoadTask(ICommonSession session) return _users[session.UserId].Task; } + void IPostInjectInit.PostInject() + { + _sawmill = _logManager.GetSawmill("userdb"); + } + private sealed record UserData(CancellationTokenSource Cancel, Task Task); } diff --git a/Content.Server/DeltaV/Implants/SubdermalBionicSyrinxImplantSystem.cs b/Content.Server/DeltaV/Implants/SubdermalBionicSyrinxImplantSystem.cs index 30a894a2d11..952b88344da 100644 --- a/Content.Server/DeltaV/Implants/SubdermalBionicSyrinxImplantSystem.cs +++ b/Content.Server/DeltaV/Implants/SubdermalBionicSyrinxImplantSystem.cs @@ -63,17 +63,14 @@ private void OnChangeName(EntityUid uid, SyrinxVoiceMaskComponent component, Voi { if (message.Name.Length > HumanoidCharacterProfile.MaxNameLength || message.Name.Length <= 0) { - _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-failure"), uid, message.Session, PopupType.SmallCaution); + _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-failure"), uid, message.Actor, PopupType.SmallCaution); return; } component.VoiceName = message.Name; - if (message.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} set voice of {ToPrettyString(uid):mask}: {component.VoiceName}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"Voice of {ToPrettyString(uid):mask} set: {component.VoiceName}"); + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(message.Actor):player} set voice of {ToPrettyString(uid):mask}: {component.VoiceName}"); - _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), uid, message.Session); + _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), uid, message.Actor); TrySetLastKnownName(uid, message.Name); UpdateUI(uid, component); } @@ -98,8 +95,8 @@ private void UpdateUI(EntityUid owner, SyrinxVoiceMaskComponent? component = nul if (!Resolve(owner, ref component, logMissing: false)) return; - if (_uiSystem.TryGetUi(owner, VoiceMaskUIKey.Key, out var bui)) - _uiSystem.SetUiState(bui, new VoiceMaskBuiState(component.VoiceName, null)); + if (_uiSystem.TryGetOpenUi(owner, VoiceMaskUIKey.Key, out _)) + _uiSystem.SetUiState(new(owner, null), VoiceMaskUIKey.Key, new VoiceMaskBuiState(component.VoiceName, null)); } /// diff --git a/Content.Server/DeltaV/ParadoxAnomaly/Systems/ParadoxAnomalySystem.cs b/Content.Server/DeltaV/ParadoxAnomaly/Systems/ParadoxAnomalySystem.cs index 477a3c56590..142669f84a2 100644 --- a/Content.Server/DeltaV/ParadoxAnomaly/Systems/ParadoxAnomalySystem.cs +++ b/Content.Server/DeltaV/ParadoxAnomaly/Systems/ParadoxAnomalySystem.cs @@ -6,7 +6,6 @@ using Content.Server.Psionics; using Content.Server.Spawners.Components; using Content.Server.Station.Systems; -using Content.Server.Terminator.Systems; using Content.Shared.Abilities.Psionics; using Content.Shared.Humanoid; using Content.Shared.Humanoid.Prototypes; @@ -38,7 +37,6 @@ public sealed class ParadoxAnomalySystem : EntitySystem [Dependency] private readonly SharedRoleSystem _role = default!; [Dependency] private readonly StationSystem _station = default!; [Dependency] private readonly StationSpawningSystem _stationSpawning = default!; - [Dependency] private readonly TerminatorSystem _terminator = default!; public override void Initialize() { @@ -123,7 +121,7 @@ private bool TrySpawnParadoxAnomaly(string rule, [NotNullWhen(true)] out EntityU var spawned = Spawn(species.Prototype, destination); // Set the kill target to the chosen player - _terminator.SetTarget(spawned, mindId); + // _terminator.SetTarget(spawned, mindId); _genericAntag.MakeAntag(spawned, rule); ////////////////////////// diff --git a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs index 28c4b2ef16e..f0499dc6a2d 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/BurnBodyBehavior.cs @@ -17,12 +17,12 @@ public void Execute(EntityUid bodyId, DestructibleSystem system, EntityUid? caus var inventorySystem = system.EntityManager.System(); var sharedPopupSystem = system.EntityManager.System(); - if (!system.EntityManager.TryGetComponent(bodyId, out var comp)) - return; - - foreach (var item in inventorySystem.GetHandOrInventoryEntities(bodyId)) + if (system.EntityManager.TryGetComponent(bodyId, out var comp)) { - transformSystem.DropNextTo(item, bodyId); + foreach (var item in inventorySystem.GetHandOrInventoryEntities(bodyId)) + { + transformSystem.DropNextTo(item, bodyId); + } } sharedPopupSystem.PopupCoordinates(Loc.GetString("bodyburn-text-others", ("name", bodyId)), transformSystem.GetMoverCoordinates(bodyId), PopupType.LargeCaution); diff --git a/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs index 59589c19aa7..1d7ce24f600 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/PopupBehavior.cs @@ -1,6 +1,6 @@ using Content.Shared.Popups; -namespace Content.Server.Destructible.Thresholds.Behaviors; +namespace Content.Server.Destructible.Thresholds.Behaviors; /// /// Shows a popup for everyone. diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs index fec93a87f45..81fb07ecfc9 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SpawnGasBehavior.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos; +using Content.Shared.Atmos; using JetBrains.Annotations; namespace Content.Server.Destructible.Thresholds.Behaviors; diff --git a/Content.Server/DeviceLinking/Components/PowerSensorComponent.cs b/Content.Server/DeviceLinking/Components/PowerSensorComponent.cs index d9599546aea..b67a2fcd950 100644 --- a/Content.Server/DeviceLinking/Components/PowerSensorComponent.cs +++ b/Content.Server/DeviceLinking/Components/PowerSensorComponent.cs @@ -1,5 +1,6 @@ using Content.Server.DeviceLinking.Systems; using Content.Shared.DeviceLinking; +using Content.Shared.Power.Generator; using Content.Shared.Tools; using Robust.Shared.Audio; using Robust.Shared.Prototypes; diff --git a/Content.Server/DeviceLinking/Systems/SignalTimerSystem.cs b/Content.Server/DeviceLinking/Systems/SignalTimerSystem.cs index 0e214ee865a..14e0c75d962 100644 --- a/Content.Server/DeviceLinking/Systems/SignalTimerSystem.cs +++ b/Content.Server/DeviceLinking/Systems/SignalTimerSystem.cs @@ -48,9 +48,9 @@ private void OnAfterActivatableUIOpen(EntityUid uid, SignalTimerComponent compon { var time = TryComp(uid, out var active) ? active.TriggerTime : TimeSpan.Zero; - if (_ui.TryGetUi(uid, SignalTimerUiKey.Key, out var bui)) + if (_ui.HasUi(uid, SignalTimerUiKey.Key)) { - _ui.SetUiState(bui, new SignalTimerBoundUserInterfaceState(component.Label, + _ui.SetUiState(uid, SignalTimerUiKey.Key, new SignalTimerBoundUserInterfaceState(component.Label, TimeSpan.FromSeconds(component.Delay).Minutes.ToString("D2"), TimeSpan.FromSeconds(component.Delay).Seconds.ToString("D2"), component.CanEditLabel, @@ -70,9 +70,9 @@ public void Trigger(EntityUid uid, SignalTimerComponent signalTimer) _audio.PlayPvs(signalTimer.DoneSound, uid); _signalSystem.InvokePort(uid, signalTimer.TriggerPort); - if (_ui.TryGetUi(uid, SignalTimerUiKey.Key, out var bui)) + if (_ui.HasUi(uid, SignalTimerUiKey.Key)) { - _ui.SetUiState(bui, new SignalTimerBoundUserInterfaceState(signalTimer.Label, + _ui.SetUiState(uid, SignalTimerUiKey.Key, new SignalTimerBoundUserInterfaceState(signalTimer.Label, TimeSpan.FromSeconds(signalTimer.Delay).Minutes.ToString("D2"), TimeSpan.FromSeconds(signalTimer.Delay).Seconds.ToString("D2"), signalTimer.CanEditLabel, @@ -117,10 +117,7 @@ private void UpdateTimer() /// The entity that is interacted with. private bool IsMessageValid(EntityUid uid, BoundUserInterfaceMessage message) { - if (message.Session.AttachedEntity is not { Valid: true } mob) - return false; - - if (!_accessReader.IsAllowed(mob, uid)) + if (!_accessReader.IsAllowed(message.Actor, uid)) return false; return true; diff --git a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs index 9a038f1c78a..dc1bf499df5 100644 --- a/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs +++ b/Content.Server/DeviceNetwork/Systems/NetworkConfiguratorSystem.cs @@ -62,7 +62,6 @@ public override void Initialize() SubscribeLocalEvent(OnClearLinks); SubscribeLocalEvent(OnToggleLinks); SubscribeLocalEvent(OnConfigButtonPressed); - SubscribeLocalEvent(OnUiOpenAttempt); SubscribeLocalEvent(OnComponentRemoved); } @@ -89,7 +88,7 @@ public override void Update(float frameTime) continue; //The network configurator is a handheld device. There can only ever be an ui session open for the player holding the device. - _uiSystem.TryCloseAll(uid, NetworkConfiguratorUiKey.Configure); + _uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure); } } @@ -215,7 +214,7 @@ private bool AccessCheck(EntityUid target, EntityUid? user, NetworkConfiguratorC private void OnComponentRemoved(EntityUid uid, DeviceListComponent component, ComponentRemove args) { - _uiSystem.TryCloseAll(uid, NetworkConfiguratorUiKey.Configure); + _uiSystem.CloseUi(uid, NetworkConfiguratorUiKey.Configure); } /// @@ -433,7 +432,7 @@ private void OpenDeviceLinkUi(EntityUid configuratorUid, EntityUid? targetUid, E return; - _uiSystem.TryOpen(configuratorUid, NetworkConfiguratorUiKey.Link, actor.PlayerSession); + _uiSystem.OpenUi(configuratorUid, NetworkConfiguratorUiKey.Link, actor.PlayerSession); configurator.DeviceLinkTarget = targetUid; @@ -464,7 +463,7 @@ private void UpdateLinkUiState(EntityUid configuratorUid, EntityUid sourceUid, E var sinkAddress = Resolve(sinkUid, ref sinkNetworkComponent, false) ? sinkNetworkComponent.Address : ""; var state = new DeviceLinkUserInterfaceState(sources, sinks, links, sourceAddress, sinkAddress, defaults); - _uiSystem.TrySetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state); + _uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Link, state); } /// @@ -478,7 +477,7 @@ private void OpenDeviceListUi(EntityUid configuratorUid, EntityUid? targetUid, E if (Delay(configurator)) return; - if (!targetUid.HasValue || !TryComp(userUid, out ActorComponent? actor) || !AccessCheck(targetUid.Value, userUid, configurator)) + if (!targetUid.HasValue || !AccessCheck(targetUid.Value, userUid, configurator)) return; if (!TryComp(targetUid, out DeviceListComponent? list)) @@ -488,14 +487,13 @@ private void OpenDeviceListUi(EntityUid configuratorUid, EntityUid? targetUid, E configurator.ActiveDeviceList = targetUid; Dirty(configuratorUid, configurator); - if (!_uiSystem.TryGetUi(configuratorUid, NetworkConfiguratorUiKey.Configure, out var bui)) - return; - - if (_uiSystem.OpenUi(bui, actor.PlayerSession)) - _uiSystem.SetUiState(bui, new DeviceListUserInterfaceState( + if (_uiSystem.TryOpenUi(configuratorUid, NetworkConfiguratorUiKey.Configure, userUid)) + { + _uiSystem.SetUiState(configuratorUid, NetworkConfiguratorUiKey.Configure, new DeviceListUserInterfaceState( _deviceListSystem.GetDeviceList(configurator.ActiveDeviceList.Value) .Select(v => (v.Key, MetaData(v.Value).EntityName)).ToHashSet() )); + } } /// @@ -523,8 +521,7 @@ private void UpdateListUiState(EntityUid uid, NetworkConfiguratorComponent compo component.Devices.Remove(invalidDevice); } - if (_uiSystem.TryGetUi(uid, NetworkConfiguratorUiKey.List, out var bui)) - _uiSystem.SetUiState(bui, new NetworkConfiguratorUserInterfaceState(devices)); + _uiSystem.SetUiState(uid, NetworkConfiguratorUiKey.List, new NetworkConfiguratorUserInterfaceState(devices)); } /// @@ -565,10 +562,10 @@ public void OnDeviceListShutdown(Entity conf, Ent /// private void OnRemoveDevice(EntityUid uid, NetworkConfiguratorComponent component, NetworkConfiguratorRemoveDeviceMessage args) { - if (component.Devices.TryGetValue(args.Address, out var removedDevice) && args.Session.AttachedEntity != null) + if (component.Devices.TryGetValue(args.Address, out var removedDevice)) { _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} removed buffered device {ToPrettyString(removedDevice):subject} from {ToPrettyString(uid):tool}"); + $"{ToPrettyString(args.Actor):actor} removed buffered device {ToPrettyString(removedDevice):subject} from {ToPrettyString(uid):tool}"); } component.Devices.Remove(args.Address); @@ -583,10 +580,8 @@ private void OnRemoveDevice(EntityUid uid, NetworkConfiguratorComponent componen /// private void OnClearDevice(EntityUid uid, NetworkConfiguratorComponent component, NetworkConfiguratorClearDevicesMessage args) { - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared buffered devices from {ToPrettyString(uid):tool}"); - + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} cleared buffered devices from {ToPrettyString(uid):tool}"); ClearDevices(uid, component); UpdateListUiState(uid, component); @@ -609,9 +604,8 @@ private void OnClearLinks(EntityUid uid, NetworkConfiguratorComponent configurat if (!configurator.ActiveDeviceLink.HasValue || !configurator.DeviceLinkTarget.HasValue) return; - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared links between {ToPrettyString(configurator.ActiveDeviceLink.Value):subject} and {ToPrettyString(configurator.DeviceLinkTarget.Value):subject2} with {ToPrettyString(uid):tool}"); + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} cleared links between {ToPrettyString(configurator.ActiveDeviceLink.Value):subject} and {ToPrettyString(configurator.DeviceLinkTarget.Value):subject2} with {ToPrettyString(uid):tool}"); if (HasComp(configurator.ActiveDeviceLink) && HasComp(configurator.DeviceLinkTarget)) { @@ -649,7 +643,7 @@ private void OnToggleLinks(EntityUid uid, NetworkConfiguratorComponent configura if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(configurator.DeviceLinkTarget, out DeviceLinkSinkComponent? targetSink)) { _deviceLinkSystem.ToggleLink( - args.Session.AttachedEntity, + args.Actor, configurator.ActiveDeviceLink.Value, configurator.DeviceLinkTarget.Value, args.Source, args.Sink, @@ -660,7 +654,7 @@ private void OnToggleLinks(EntityUid uid, NetworkConfiguratorComponent configura else if (TryComp(configurator.DeviceLinkTarget, out DeviceLinkSourceComponent? targetSource) && TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink)) { _deviceLinkSystem.ToggleLink( - args.Session.AttachedEntity, + args.Actor, configurator.DeviceLinkTarget.Value, configurator.ActiveDeviceLink.Value, args.Source, args.Sink, @@ -687,7 +681,7 @@ private void OnSaveLinks(EntityUid uid, NetworkConfiguratorComponent configurato if (TryComp(configurator.ActiveDeviceLink, out DeviceLinkSourceComponent? activeSource) && TryComp(configurator.DeviceLinkTarget, out DeviceLinkSinkComponent? targetSink)) { _deviceLinkSystem.SaveLinks( - args.Session.AttachedEntity, + args.Actor, configurator.ActiveDeviceLink.Value, configurator.DeviceLinkTarget.Value, args.Links, @@ -705,7 +699,7 @@ private void OnSaveLinks(EntityUid uid, NetworkConfiguratorComponent configurato else if (TryComp(configurator.DeviceLinkTarget, out DeviceLinkSourceComponent? targetSource) && TryComp(configurator.ActiveDeviceLink, out DeviceLinkSinkComponent? activeSink)) { _deviceLinkSystem.SaveLinks( - args.Session.AttachedEntity, + args.Actor, configurator.DeviceLinkTarget.Value, configurator.ActiveDeviceLink.Value, args.Links, @@ -735,29 +729,25 @@ private void OnConfigButtonPressed(EntityUid uid, NetworkConfiguratorComponent c switch (args.ButtonKey) { case NetworkConfiguratorButtonKey.Set: - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} set device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} set device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet(component.Devices.Values)); break; case NetworkConfiguratorButtonKey.Add: - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} added device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} added device links to {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet(component.Devices.Values), true); break; case NetworkConfiguratorButtonKey.Clear: - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} cleared device links from {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} cleared device links from {ToPrettyString(component.ActiveDeviceList.Value):subject} with {ToPrettyString(uid):tool}"); result = _deviceListSystem.UpdateDeviceList(component.ActiveDeviceList.Value, new HashSet()); break; case NetworkConfiguratorButtonKey.Copy: - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} copied devices from {ToPrettyString(component.ActiveDeviceList.Value):subject} to {ToPrettyString(uid):tool}"); + _adminLogger.Add(LogType.DeviceLinking, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} copied devices from {ToPrettyString(component.ActiveDeviceList.Value):subject} to {ToPrettyString(uid):tool}"); ClearDevices(uid, component); @@ -783,8 +773,8 @@ private void OnConfigButtonPressed(EntityUid uid, NetworkConfiguratorComponent c _ => "error" }; - _popupSystem.PopupCursor(Loc.GetString(resultText), args.Session, PopupType.Medium); - _uiSystem.TrySetUiState( + _popupSystem.PopupCursor(Loc.GetString(resultText), args.Actor, PopupType.Medium); + _uiSystem.SetUiState( uid, NetworkConfiguratorUiKey.Configure, new DeviceListUserInterfaceState( diff --git a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs index 001abad3dcd..8e9c9e4ba73 100644 --- a/Content.Server/Disposal/Mailing/MailingUnitSystem.cs +++ b/Content.Server/Disposal/Mailing/MailingUnitSystem.cs @@ -159,8 +159,7 @@ private void HandleActivate(EntityUid uid, MailingUnitComponent component, Activ args.Handled = true; UpdateTargetList(uid, component); - if (_userInterfaceSystem.TryGetUi(uid, MailingUnitUiKey.Key, out var bui)) - _userInterfaceSystem.OpenUi(bui, actor.PlayerSession); + _userInterfaceSystem.OpenUi(uid, MailingUnitUiKey.Key, actor.PlayerSession); } /// @@ -178,8 +177,7 @@ private void UpdateUserInterface(EntityUid uid, MailingUnitComponent component) return; var state = new MailingUnitBoundUserInterfaceState(component.DisposalUnitInterfaceState, component.Target, component.TargetList, component.Tag); - if (_userInterfaceSystem.TryGetUi(uid, MailingUnitUiKey.Key, out var bui)) - _userInterfaceSystem.SetUiState(bui, state); + _userInterfaceSystem.SetUiState(uid, MailingUnitUiKey.Key, state); } private void OnTargetSelected(EntityUid uid, MailingUnitComponent component, TargetSelectedMessage args) diff --git a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs index 6c0bced53e0..f0f6e9142c6 100644 --- a/Content.Server/Disposal/Tube/DisposalTubeSystem.cs +++ b/Content.Server/Disposal/Tube/DisposalTubeSystem.cs @@ -101,8 +101,9 @@ private void OnUiAction(EntityUid uid, DisposalTaggerComponent tagger, SharedDis /// A user interface message from the client. private void OnUiAction(EntityUid uid, DisposalRouterComponent router, SharedDisposalRouterComponent.UiActionMessage msg) { - if (!EntityManager.EntityExists(msg.Session.AttachedEntity)) + if (!EntityManager.EntityExists(msg.Actor)) return; + if (TryComp(uid, out var physBody) && physBody.BodyType != BodyType.Static) return; @@ -279,9 +280,9 @@ private void OnOpenRouterUI(EntityUid uid, DisposalRouterComponent router, Bound private void OnOpenTaggerUI(EntityUid uid, DisposalTaggerComponent tagger, BoundUIOpenedEvent args) { - if (_uiSystem.TryGetUi(uid, DisposalTaggerUiKey.Key, out var bui)) + if (_uiSystem.HasUi(uid, DisposalTaggerUiKey.Key)) { - _uiSystem.SetUiState(bui, + _uiSystem.SetUiState(uid, DisposalTaggerUiKey.Key, new DisposalTaggerUserInterfaceState(tagger.Tag)); } } @@ -292,13 +293,9 @@ private void OnOpenTaggerUI(EntityUid uid, DisposalTaggerComponent tagger, Bound /// Returns a private void UpdateRouterUserInterface(EntityUid uid, DisposalRouterComponent router) { - var bui = _uiSystem.GetUiOrNull(uid, DisposalRouterUiKey.Key); - if (bui == null) - return; - if (router.Tags.Count <= 0) { - _uiSystem.SetUiState(bui, new DisposalRouterUserInterfaceState("")); + _uiSystem.SetUiState(uid, DisposalRouterUiKey.Key, new DisposalRouterUserInterfaceState("")); return; } @@ -312,7 +309,7 @@ private void UpdateRouterUserInterface(EntityUid uid, DisposalRouterComponent ro taglist.Remove(taglist.Length - 2, 2); - _uiSystem.SetUiState(bui, new DisposalRouterUserInterfaceState(taglist.ToString())); + _uiSystem.SetUiState(uid, DisposalRouterUiKey.Key, new DisposalRouterUserInterfaceState(taglist.ToString())); } private void OnAnchorChange(EntityUid uid, DisposalTubeComponent component, ref AnchorStateChangedEvent args) diff --git a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs index 3df2182b41e..690b33968b0 100644 --- a/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs +++ b/Content.Server/Disposal/Unit/Components/DisposalHolderComponent.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos; using Content.Server.Disposal.Tube.Components; +using Content.Shared.Atmos; using Robust.Shared.Containers; namespace Content.Server.Disposal.Unit.Components diff --git a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs index d6647bbf2eb..84ba25d9b1d 100644 --- a/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs +++ b/Content.Server/Disposal/Unit/EntitySystems/DisposalUnitSystem.cs @@ -73,8 +73,6 @@ public override void Initialize() SubscribeLocalEvent(OnPowerChange); SubscribeLocalEvent(OnDisposalInit); - SubscribeLocalEvent(OnThrowCollide); - SubscribeLocalEvent(OnActivate); SubscribeLocalEvent(OnAfterInteractUsing); SubscribeLocalEvent(OnDragDropOn); @@ -143,6 +141,9 @@ private void AddClimbInsideVerb(EntityUid uid, SharedDisposalUnitComponent compo return; } + if (!CanInsert(uid, component, args.User)) + return; + // Add verb to climb inside of the unit, Verb verb = new() { @@ -219,7 +220,7 @@ public override void Update(float frameTime) #region UI Handlers private void OnUiButtonPressed(EntityUid uid, SharedDisposalUnitComponent component, SharedDisposalUnitComponent.UiButtonPressedMessage args) { - if (args.Session.AttachedEntity is not { Valid: true } player) + if (args.Actor is not { Valid: true } player) { return; } @@ -235,7 +236,7 @@ private void OnUiButtonPressed(EntityUid uid, SharedDisposalUnitComponent compon _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} hit flush button on {ToPrettyString(uid)}, it's now {(component.Engaged ? "on" : "off")}"); break; case SharedDisposalUnitComponent.UiButton.Power: - _power.TryTogglePower(uid, user: args.Session.AttachedEntity); + _power.TryTogglePower(uid, user: args.Actor); break; default: throw new ArgumentOutOfRangeException($"{ToPrettyString(player):player} attempted to hit a nonexistant button on {ToPrettyString(uid)}"); @@ -268,7 +269,7 @@ private void OnActivate(EntityUid uid, SharedDisposalUnitComponent component, Ac } args.Handled = true; - _ui.TryOpen(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession); + _ui.OpenUi(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession); } private void OnAfterInteractUsing(EntityUid uid, SharedDisposalUnitComponent component, AfterInteractUsingEvent args) @@ -291,40 +292,6 @@ private void OnAfterInteractUsing(EntityUid uid, SharedDisposalUnitComponent com args.Handled = true; } - /// - /// Thrown items have a chance of bouncing off the unit and not going in. - /// - private void OnThrowCollide(EntityUid uid, SharedDisposalUnitComponent component, ThrowHitByEvent args) - { - var canInsert = CanInsert(uid, component, args.Thrown); - var randDouble = _robustRandom.NextDouble(); - - if (!canInsert) - { - return; - } - - if (randDouble > 0.75) - { - _audioSystem.PlayPvs(component.MissSound, uid); - - _popupSystem.PopupEntity(Loc.GetString("disposal-unit-thrown-missed"), uid); - return; - } - - var inserted = _containerSystem.Insert(args.Thrown, component.Container); - - if (!inserted) - { - throw new InvalidOperationException("Container insertion failed but CanInsert returned true"); - } - - if (args.Component.Thrower != null) - _adminLogger.Add(LogType.Landed, LogImpact.Low, $"{ToPrettyString(args.Thrown)} thrown by {ToPrettyString(args.Component.Thrower.Value):player} landed in {ToPrettyString(uid)}"); - - AfterInsert(uid, component, args.Thrown); - } - private void OnDisposalInit(EntityUid uid, SharedDisposalUnitComponent component, ComponentInit args) { component.Container = _containerSystem.EnsureContainer(uid, SharedDisposalUnitComponent.ContainerId); @@ -598,7 +565,7 @@ public void UpdateInterface(EntityUid uid, SharedDisposalUnitComponent component var compState = GetState(uid, component); var stateString = Loc.GetString($"disposal-unit-state-{compState}"); var state = new SharedDisposalUnitComponent.DisposalUnitBoundUserInterfaceState(Name(uid), stateString, EstimatedFullPressure(uid, component), powered, component.Engaged); - _ui.TrySetUiState(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, state); + _ui.SetUiState(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, state); var stateUpdatedEvent = new DisposalUnitUIStateUpdatedEvent(state); RaiseLocalEvent(uid, stateUpdatedEvent); @@ -803,10 +770,7 @@ public void AfterInsert(EntityUid uid, SharedDisposalUnitComponent component, En QueueAutomaticEngage(uid, component); - if (TryComp(inserted, out ActorComponent? actor)) - { - _ui.TryClose(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, actor.PlayerSession); - } + _ui.CloseUi(uid, SharedDisposalUnitComponent.DisposalUnitUiKey.Key, inserted); // Maybe do pullable instead? Eh still fine. Joints.RecursiveClearJoints(inserted); diff --git a/Content.Server/Doors/Electronics/Systems/DoorElectronicsSystem.cs b/Content.Server/Doors/Electronics/Systems/DoorElectronicsSystem.cs index 56e8bd50b32..af9ccadd91c 100644 --- a/Content.Server/Doors/Electronics/Systems/DoorElectronicsSystem.cs +++ b/Content.Server/Doors/Electronics/Systems/DoorElectronicsSystem.cs @@ -39,7 +39,7 @@ public void UpdateUserInterface(EntityUid uid, DoorElectronicsComponent componen } var state = new DoorElectronicsConfigurationState(accesses); - _uiSystem.TrySetUiState(uid, DoorElectronicsConfigurationUiKey.Key, state); + _uiSystem.SetUiState(uid, DoorElectronicsConfigurationUiKey.Key, state); } private void OnChangeConfiguration( diff --git a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs index 65a539eb08e..4ef07a0cca8 100644 --- a/Content.Server/Electrocution/Components/ElectrifiedComponent.cs +++ b/Content.Server/Electrocution/Components/ElectrifiedComponent.cs @@ -85,4 +85,7 @@ public sealed partial class ElectrifiedComponent : Component [DataField("shockVolume")] public float ShockVolume = 20; + + [DataField] + public float Probability = 1f; } diff --git a/Content.Server/Electrocution/ElectrocutionSystem.cs b/Content.Server/Electrocution/ElectrocutionSystem.cs index ba20f4e32f3..4db815a3944 100644 --- a/Content.Server/Electrocution/ElectrocutionSystem.cs +++ b/Content.Server/Electrocution/ElectrocutionSystem.cs @@ -215,6 +215,9 @@ public bool TryDoElectrifiedAct(EntityUid uid, EntityUid targetUid, if (!IsPowered(uid, electrified, transform)) return false; + if (!_random.Prob(electrified.Probability)) + return false; + EnsureComp(uid); _appearance.SetData(uid, ElectrifiedVisuals.IsPowered, true); diff --git a/Content.Server/Entry/IgnoredComponents.cs b/Content.Server/Entry/IgnoredComponents.cs index fe073da7a49..d9b81c8e5a5 100644 --- a/Content.Server/Entry/IgnoredComponents.cs +++ b/Content.Server/Entry/IgnoredComponents.cs @@ -14,12 +14,13 @@ public static class IgnoredComponents "Icon", "HandheldGPS", "CableVisualizer", + "SolutionItemStatus", "UIFragment", "PdaBorderColor", "InventorySlots", "LightFade", "HolidayRsiSwap", - "OptionsVisualizer", + "OptionsVisualizer" }; } } diff --git a/Content.Server/Explosion/Components/ExplosiveComponent.cs b/Content.Server/Explosion/Components/ExplosiveComponent.cs index 04a08955a35..2b27a89d9db 100644 --- a/Content.Server/Explosion/Components/ExplosiveComponent.cs +++ b/Content.Server/Explosion/Components/ExplosiveComponent.cs @@ -81,6 +81,13 @@ public sealed partial class ExplosiveComponent : Component [DataField("deleteAfterExplosion")] public bool? DeleteAfterExplosion; + /// + /// Whether to not set to true, allowing it to explode multiple times. + /// This should never be used if it is damageable. + /// + [DataField] + public bool Repeatable; + /// /// Avoid somehow double-triggering this explosion (e.g. by damaging this entity from its own explosion. /// diff --git a/Content.Server/Explosion/Components/RepeatingTriggerComponent.cs b/Content.Server/Explosion/Components/RepeatingTriggerComponent.cs new file mode 100644 index 00000000000..cc08de53f90 --- /dev/null +++ b/Content.Server/Explosion/Components/RepeatingTriggerComponent.cs @@ -0,0 +1,25 @@ +using Content.Server.Explosion.EntitySystems; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Server.Explosion.Components; + +/// +/// Constantly triggers after being added to an entity. +/// +[RegisterComponent, Access(typeof(TriggerSystem))] +[AutoGenerateComponentPause] +public sealed partial class RepeatingTriggerComponent : Component +{ + /// + /// How long to wait between triggers. + /// The first trigger starts this long after the component is added. + /// + [DataField] + public TimeSpan Delay = TimeSpan.FromSeconds(1); + + /// + /// When the next trigger will be. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoPausedField] + public TimeSpan NextTrigger; +} diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs index 1f031093333..3332d3a4f59 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs @@ -11,7 +11,8 @@ public sealed partial class ExplosionSystem : EntitySystem public int ThrowLimit { get; private set; } public bool SleepNodeSys { get; private set; } public bool IncrementalTileBreaking { get; private set; } - public int SingleTickAreaLimit {get; private set; } + public int SingleTickAreaLimit { get; private set; } + public bool CanCreateVacuum { get; private set; } private void SubscribeCvars() { @@ -23,5 +24,6 @@ private void SubscribeCvars() Subs.CVar(_cfg, CCVars.ExplosionMaxProcessingTime, value => MaxProcessingTime = value, true); Subs.CVar(_cfg, CCVars.ExplosionIncrementalTileBreaking, value => IncrementalTileBreaking = value, true); Subs.CVar(_cfg, CCVars.ExplosionSingleTickAreaLimit, value => SingleTickAreaLimit = value, true); + Subs.CVar(_cfg, CCVars.ExplosionCanCreateVacuum, value => CanCreateVacuum = value, true); } } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 14a149074dc..835e3174fcd 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -1,4 +1,5 @@ using System.Numerics; +using Content.Server.Atmos.EntitySystems; using Content.Shared.CCVar; using Content.Shared.Damage; using Content.Shared.Explosion; @@ -16,7 +17,6 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; -using Content.Server.Atmos.EntitySystems; namespace Content.Server.Explosion.EntitySystems; @@ -474,7 +474,9 @@ public void DamageFloorTile(TileRef tileRef, if (_tileDefinitionManager[tileRef.Tile.TypeId] is not ContentTileDefinition tileDef) return; - if (tileDef.MapAtmosphere) + if (!CanCreateVacuum) + canCreateVacuum = false; + else if (tileDef.MapAtmosphere) canCreateVacuum = true; // is already a vacuum. int tileBreakages = 0; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index 607a514e63c..71f3025748a 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -160,7 +160,7 @@ public void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null if (explosive.Exploded) return; - explosive.Exploded = true; + explosive.Exploded = !explosive.Repeatable; // Override the explosion intensity if optional arguments were provided. if (radius != null) diff --git a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs index 94f55855362..8e0a75ea24f 100644 --- a/Content.Server/Explosion/EntitySystems/TriggerSystem.cs +++ b/Content.Server/Explosion/EntitySystems/TriggerSystem.cs @@ -94,6 +94,7 @@ public override void Initialize() SubscribeLocalEvent(OnStepTriggered); SubscribeLocalEvent(OnSlipTriggered); SubscribeLocalEvent(OnEmptyTriggered); + SubscribeLocalEvent(OnRepeatInit); SubscribeLocalEvent(OnSpawnTrigger); SubscribeLocalEvent(HandleDeleteTrigger); @@ -153,7 +154,7 @@ private void HandleExplodeTrigger(EntityUid uid, ExplodeOnTriggerComponent compo private void HandleFlashTrigger(EntityUid uid, FlashOnTriggerComponent component, TriggerEvent args) { // TODO Make flash durations sane ffs. - _flashSystem.FlashArea(uid, args.User, component.Range, component.Duration * 1000f); + _flashSystem.FlashArea(uid, args.User, component.Range, component.Duration * 1000f, probability: component.Probability); args.Handled = true; } @@ -241,6 +242,11 @@ private void OnEmptyTriggered(EntityUid uid, TriggerWhenEmptyComponent component Trigger(uid, args.EmptyGun); } + private void OnRepeatInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextTrigger = _timing.CurTime + ent.Comp.Delay; + } + public bool Trigger(EntityUid trigger, EntityUid? user = null) { var triggerEvent = new TriggerEvent(trigger, user); @@ -323,6 +329,7 @@ public override void Update(float frameTime) UpdateProximity(); UpdateTimer(frameTime); UpdateTimedCollide(frameTime); + UpdateRepeat(); } private void UpdateTimer(float frameTime) @@ -357,5 +364,19 @@ private void UpdateTimer(float frameTime) _appearance.SetData(uid, TriggerVisuals.VisualState, TriggerVisualState.Unprimed, appearance); } } + + private void UpdateRepeat() + { + var now = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + if (comp.NextTrigger > now) + continue; + + comp.NextTrigger = now + comp.Delay; + Trigger(uid); + } + } } } diff --git a/Content.Server/Extinguisher/FireExtinguisherComponent.cs b/Content.Server/Extinguisher/FireExtinguisherComponent.cs index fe10b4a574a..991fc76c62e 100644 --- a/Content.Server/Extinguisher/FireExtinguisherComponent.cs +++ b/Content.Server/Extinguisher/FireExtinguisherComponent.cs @@ -3,7 +3,7 @@ namespace Content.Server.Extinguisher; -[NetworkedComponent, RegisterComponent] +[RegisterComponent] [Access(typeof(FireExtinguisherSystem))] public sealed partial class FireExtinguisherComponent : SharedFireExtinguisherComponent { diff --git a/Content.Server/Eye/Blinding/ActivatableUIRequiresVisionSystem.cs b/Content.Server/Eye/Blinding/ActivatableUIRequiresVisionSystem.cs index b51efc2f5e1..7b937cf0d81 100644 --- a/Content.Server/Eye/Blinding/ActivatableUIRequiresVisionSystem.cs +++ b/Content.Server/Eye/Blinding/ActivatableUIRequiresVisionSystem.cs @@ -5,6 +5,7 @@ using Content.Shared.Eye.Blinding.Systems; using Robust.Shared.Player; using Robust.Server.GameObjects; +using Robust.Shared.Collections; namespace Content.Server.Eye.Blinding; @@ -37,24 +38,19 @@ private void OnBlindnessChanged(EntityUid uid, BlindableComponent component, ref if (!args.Blind) return; - if (!TryComp(uid, out var actor)) - return; - - var uiList = _userInterfaceSystem.GetAllUIsForSession(actor.PlayerSession); - if (uiList == null) - return; - - Queue closeList = new(); // foreach collection modified moment + var toClose = new ValueList<(EntityUid Entity, Enum Key)>(); - foreach (var ui in uiList) + foreach (var bui in _userInterfaceSystem.GetActorUis(uid)) { - if (HasComp(ui.Owner)) - closeList.Enqueue(ui); + if (HasComp(bui.Entity)) + { + toClose.Add(bui); + } } - foreach (var ui in closeList) + foreach (var bui in toClose) { - _userInterfaceSystem.CloseUi(ui, actor.PlayerSession); + _userInterfaceSystem.CloseUi(bui.Entity, bui.Key, uid); } } } diff --git a/Content.Server/Fax/AdminUI/AdminFaxEui.cs b/Content.Server/Fax/AdminUI/AdminFaxEui.cs index c8be6618e45..452fc593d95 100644 --- a/Content.Server/Fax/AdminUI/AdminFaxEui.cs +++ b/Content.Server/Fax/AdminUI/AdminFaxEui.cs @@ -1,6 +1,7 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.EUI; using Content.Shared.Eui; +using Content.Shared.Fax.Components; using Content.Shared.Fax; using Content.Shared.Follower; using Content.Shared.Ghost; @@ -54,7 +55,7 @@ public override void HandleMessage(EuiMessageBase msg) } case AdminFaxEuiMsg.Send sendData: { - var printout = new FaxPrintout(sendData.Content, sendData.Title, null, sendData.StampState, + var printout = new FaxPrintout(sendData.Content, sendData.Title, null, null, sendData.StampState, new() { new StampDisplayInfo { StampedName = sendData.From, StampedColor = sendData.StampColor } }); _faxSystem.Receive(_entityManager.GetEntity(sendData.Target), printout); break; diff --git a/Content.Server/Fax/FaxConstants.cs b/Content.Server/Fax/FaxConstants.cs index 102510bd46e..24ed7cbcf32 100644 --- a/Content.Server/Fax/FaxConstants.cs +++ b/Content.Server/Fax/FaxConstants.cs @@ -23,6 +23,7 @@ public static class FaxConstants public const string FaxNameData = "fax_data_name"; public const string FaxPaperNameData = "fax_data_title"; + public const string FaxPaperLabelData = "fax_data_label"; public const string FaxPaperPrototypeData = "fax_data_prototype"; public const string FaxPaperContentData = "fax_data_content"; public const string FaxPaperStampStateData = "fax_data_stamp_state"; diff --git a/Content.Server/Fax/FaxSystem.cs b/Content.Server/Fax/FaxSystem.cs index 3ff139466f5..e86dbca4a13 100644 --- a/Content.Server/Fax/FaxSystem.cs +++ b/Content.Server/Fax/FaxSystem.cs @@ -4,6 +4,7 @@ using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.DeviceNetwork.Systems; +using Content.Server.Labels; using Content.Server.Paper; using Content.Server.Popups; using Content.Server.Power.Components; @@ -16,7 +17,11 @@ using Content.Shared.Emag.Components; using Content.Shared.Emag.Systems; using Content.Shared.Fax; +using Content.Shared.Fax.Systems; +using Content.Shared.Fax.Components; using Content.Shared.Interaction; +using Content.Shared.Labels.Components; +using Content.Shared.Mobs.Components; using Content.Shared.Paper; using Robust.Server.GameObjects; using Robust.Shared.Audio; @@ -36,12 +41,14 @@ public sealed class FaxSystem : EntitySystem [Dependency] private readonly PopupSystem _popupSystem = default!; [Dependency] private readonly DeviceNetworkSystem _deviceNetworkSystem = default!; [Dependency] private readonly PaperSystem _paperSystem = default!; + [Dependency] private readonly LabelSystem _labelSystem = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly ToolSystem _toolSystem = default!; [Dependency] private readonly QuickDialogSystem _quickDialog = default!; [Dependency] private readonly UserInterfaceSystem _userInterface = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly FaxecuteSystem _faxecute = default!; private const string PaperSlotId = "Paper"; @@ -51,7 +58,7 @@ public sealed class FaxSystem : EntitySystem /// [ValidatePrototypeId] private const string DefaultPaperPrototypeId = "Paper"; - + [ValidatePrototypeId] private const string OfficePaperPrototypeId = "PaperOffice"; @@ -236,7 +243,7 @@ private void OnInteractUsing(EntityUid uid, FaxMachineComponent component, Inter } _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.User):user} renamed {ToPrettyString(uid)} from \"{component.FaxName}\" to \"{newName}\""); + $"{ToPrettyString(args.User):user} renamed {ToPrettyString(uid):tool} from \"{component.FaxName}\" to \"{newName}\""); component.FaxName = newName; _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-name-set"), uid); UpdateUserInterface(uid, component); @@ -288,11 +295,12 @@ private void OnPacketReceived(EntityUid uid, FaxMachineComponent component, Devi !args.Data.TryGetValue(FaxConstants.FaxPaperContentData, out string? content)) return; + args.Data.TryGetValue(FaxConstants.FaxPaperLabelData, out string? label); args.Data.TryGetValue(FaxConstants.FaxPaperStampStateData, out string? stampState); args.Data.TryGetValue(FaxConstants.FaxPaperStampedByData, out List? stampedBy); args.Data.TryGetValue(FaxConstants.FaxPaperPrototypeData, out string? prototypeId); - var printout = new FaxPrintout(content, name, prototypeId, stampState, stampedBy); + var printout = new FaxPrintout(content, name, label, prototypeId, stampState, stampedBy); Receive(uid, printout, args.SenderAddress); break; @@ -307,18 +315,25 @@ private void OnToggleInterface(EntityUid uid, FaxMachineComponent component, Aft private void OnFileButtonPressed(EntityUid uid, FaxMachineComponent component, FaxFileMessage args) { + args.Label = args.Label?[..Math.Min(args.Label.Length, FaxFileMessageValidation.MaxLabelSize)]; args.Content = args.Content[..Math.Min(args.Content.Length, FaxFileMessageValidation.MaxContentSize)]; PrintFile(uid, component, args); } private void OnCopyButtonPressed(EntityUid uid, FaxMachineComponent component, FaxCopyMessage args) { - Copy(uid, component, args); + if (HasComp(component.PaperSlot.Item)) + _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. + else + Copy(uid, component, args); } private void OnSendButtonPressed(EntityUid uid, FaxMachineComponent component, FaxSendMessage args) { - Send(uid, component, args.Session.AttachedEntity); + if (HasComp(component.PaperSlot.Item)) + _faxecute.Faxecute(uid, component); /// when button pressed it will hurt the mob. + else + Send(uid, component, args); } private void OnRefreshButtonPressed(EntityUid uid, FaxMachineComponent component, FaxRefreshMessage args) @@ -336,14 +351,20 @@ private void UpdateAppearance(EntityUid uid, FaxMachineComponent? component = nu if (!Resolve(uid, ref component)) return; + if (TryComp(component.PaperSlot.Item, out var faxable)) + component.InsertingState = faxable.InsertingState; + + if (component.InsertingTimeRemaining > 0) + { _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Inserting); + Dirty(uid, component); + } else if (component.PrintingTimeRemaining > 0) _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Printing); else _appearanceSystem.SetData(uid, FaxMachineVisuals.VisualState, FaxMachineVisualState.Normal); } - private void UpdateUserInterface(EntityUid uid, FaxMachineComponent? component = null) { if (!Resolve(uid, ref component)) @@ -358,7 +379,7 @@ private void UpdateUserInterface(EntityUid uid, FaxMachineComponent? component = component.SendTimeoutRemaining <= 0 && component.InsertingTimeRemaining <= 0; var state = new FaxUiState(component.FaxName, component.KnownFaxes, canSend, canCopy, isPaperInserted, component.DestinationFaxAddress); - _userInterface.TrySetUiState(uid, FaxUiKey.Key, state); + _userInterface.SetUiState(uid, FaxUiKey.Key, state); } /// @@ -409,20 +430,20 @@ public void PrintFile(EntityUid uid, FaxMachineComponent component, FaxFileMessa else prototype = DefaultPaperPrototypeId; - var name = Loc.GetString("fax-machine-printed-paper-name"); - - var printout = new FaxPrintout(args.Content, name, prototype); + var name = Loc.GetString("fax-machine-printed-paper-name"); + + var printout = new FaxPrintout(args.Content, name, args.Label, prototype); component.PrintingQueue.Enqueue(printout); component.SendTimeoutRemaining += component.SendTimeout; UpdateUserInterface(uid, component); - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} added print job to {ToPrettyString(uid):tool} with text: {args.Content}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"Someone added print job to {ToPrettyString(uid):tool} with text: {args.Content}"); + // Unfortunately, since a paper entity does not yet exist, we have to emulate what LabelSystem will do. + var nameWithLabel = (args.Label is { } label) ? $"{name} ({label})" : name; + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} " + + $"added print job to \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"of {nameWithLabel}: {args.Content}"); } /// @@ -442,9 +463,12 @@ public void Copy(EntityUid uid, FaxMachineComponent? component, FaxCopyMessage a !TryComp(sendEntity, out var paper)) return; + TryComp(sendEntity, out var labelComponent); + // TODO: See comment in 'Send()' about not being able to copy whole entities var printout = new FaxPrintout(paper.Content, - metadata.EntityName, + labelComponent?.OriginalName ?? metadata.EntityName, + labelComponent?.CurrentLabel, metadata.EntityPrototype?.ID ?? DefaultPaperPrototypeId, paper.StampState, paper.StampedBy); @@ -457,16 +481,17 @@ public void Copy(EntityUid uid, FaxMachineComponent? component, FaxCopyMessage a UpdateUserInterface(uid, component); - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):actor} added copy job to {ToPrettyString(uid):tool} with text: {ToPrettyString(component.PaperSlot.Item):subject}"); + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} " + + $"added copy job to \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"of {ToPrettyString(sendEntity):subject}: {printout.Content}"); } /// /// Sends message to addressee if paper is set and a known fax is selected /// A timeout is set after sending, which is shared by the copy button. /// - public void Send(EntityUid uid, FaxMachineComponent? component = null, EntityUid? sender = null) + public void Send(EntityUid uid, FaxMachineComponent? component, FaxSendMessage args) { if (!Resolve(uid, ref component)) return; @@ -482,13 +507,16 @@ public void Send(EntityUid uid, FaxMachineComponent? component = null, EntityUid return; if (!TryComp(sendEntity, out var metadata) || - !TryComp(sendEntity, out var paper)) + !TryComp(sendEntity, out var paper)) return; + TryComp(sendEntity, out var labelComponent); + var payload = new NetworkPayload() { { DeviceNetworkConstants.Command, FaxConstants.FaxPrintCommand }, - { FaxConstants.FaxPaperNameData, metadata.EntityName }, + { FaxConstants.FaxPaperNameData, labelComponent?.OriginalName ?? metadata.EntityName }, + { FaxConstants.FaxPaperLabelData, labelComponent?.CurrentLabel }, { FaxConstants.FaxPaperContentData, paper.Content }, }; @@ -509,7 +537,11 @@ public void Send(EntityUid uid, FaxMachineComponent? component = null, EntityUid _deviceNetworkSystem.QueuePacket(uid, component.DestinationFaxAddress, payload); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"{(sender != null ? ToPrettyString(sender.Value) : "Unknown"):user} sent fax from \"{component.FaxName}\" {ToPrettyString(uid)} to {faxName} ({component.DestinationFaxAddress}): {paper.Content}"); + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(args.Actor):actor} " + + $"sent fax from \"{component.FaxName}\" {ToPrettyString(uid):tool} " + + $"to \"{faxName}\" ({component.DestinationFaxAddress}) " + + $"of {ToPrettyString(sendEntity):subject}: {paper.Content}"); component.SendTimeoutRemaining += component.SendTimeout; @@ -565,7 +597,13 @@ private void SpawnPaperFromQueue(EntityUid uid, FaxMachineComponent? component = } _metaData.SetEntityName(printed, printout.Name); - _adminLogger.Add(LogType.Action, LogImpact.Low, $"\"{component.FaxName}\" {ToPrettyString(uid)} printed {ToPrettyString(printed)}: {printout.Content}"); + + if (printout.Label is { } label) + { + _labelSystem.Label(printed, label); + } + + _adminLogger.Add(LogType.Action, LogImpact.Low, $"\"{component.FaxName}\" {ToPrettyString(uid):tool} printed {ToPrettyString(printed):subject}: {printout.Content}"); } private void NotifyAdmins(string faxName) diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index 7706bfec4ea..bc91a307b08 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -18,6 +18,7 @@ using Robust.Server.Audio; using Robust.Server.GameObjects; using Robust.Shared.Audio; +using Robust.Shared.Random; using Robust.Shared.Timing; using InventoryComponent = Content.Shared.Inventory.InventoryComponent; using Content.Shared.Traits.Assorted.Components; @@ -67,7 +68,7 @@ private void OnFlashMeleeHit(EntityUid uid, FlashComponent comp, MeleeHitEvent a args.Handled = true; foreach (var e in args.HitEntities) { - Flash(e, args.User, uid, comp.FlashDuration, comp.SlowTo, melee: true); + Flash(e, args.User, uid, comp.FlashDuration, comp.SlowTo, melee: true, stunDuration: comp.MeleeStunDuration); } } @@ -77,7 +78,7 @@ private void OnFlashUseInHand(EntityUid uid, FlashComponent comp, UseInHandEvent return; args.Handled = true; - FlashArea(uid, args.User, comp.Range, comp.AoeFlashDuration, comp.SlowTo, true); + FlashArea(uid, args.User, comp.Range, comp.AoeFlashDuration, comp.SlowTo, true, comp.Probability); } private bool UseFlash(EntityUid uid, FlashComponent comp, EntityUid user) @@ -117,7 +118,8 @@ public void Flash(EntityUid target, float slowTo, bool displayPopup = true, FlashableComponent? flashable = null, - bool melee = false) + bool melee = false, + TimeSpan? stunDuration = null) { if (!Resolve(target, ref flashable, false)) return; @@ -148,41 +150,46 @@ public void Flash(EntityUid target, && _random.Prob(flashable.EyeDamageChance)) _blindingSystem.AdjustEyeDamage((target, blindable), flashable.EyeDamage); - _stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration/1000f), true, + if (stunDuration != null) + { + _stun.TryParalyze(target, stunDuration.Value, true); + } + else + { + _stun.TrySlowdown(target, TimeSpan.FromSeconds(flashDuration/1000f), true, slowTo, slowTo); + } if (displayPopup && user != null && target != user && Exists(user.Value)) { _popup.PopupEntity(Loc.GetString("flash-component-user-blinds-you", ("user", Identity.Entity(user.Value, EntityManager))), target, target); } - } - public void FlashArea(EntityUid source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, SoundSpecifier? sound = null) + public void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { - var transform = EntityManager.GetComponent(source); + var transform = Transform(source); var mapPosition = _transform.GetMapCoordinates(transform); var flashableQuery = GetEntityQuery(); foreach (var entity in _entityLookup.GetEntitiesInRange(transform.Coordinates, range)) { - if (!flashableQuery.TryGetComponent(entity, out var flashable)) + if (!_random.Prob(probability)) continue; + if (!flashableQuery.TryGetComponent(entity, out var flashable)) + continue; // Check for unobstructed entities while ignoring the mobs with flashable components. - if (!_interaction.InRangeUnobstructed(entity, mapPosition, range, flashable.CollisionGroup, (e) => e == source)) + if (!_interaction.InRangeUnobstructed(entity, mapPosition, range, flashable.CollisionGroup, predicate: (e) => flashableQuery.HasComponent(e) || e == source.Owner)) continue; // They shouldn't have flash removed in between right? Flash(entity, user, source, duration, slowTo, displayPopup, flashableQuery.GetComponent(entity)); } - if (sound != null) - { - _audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f)); - } + _audio.PlayPvs(sound, source, AudioParams.Default.WithVolume(1f).WithMaxDistance(3f)); } private void OnInventoryFlashAttempt(EntityUid uid, InventoryComponent component, FlashAttemptEvent args) diff --git a/Content.Server/Fluids/EntitySystems/DrainSystem.cs b/Content.Server/Fluids/EntitySystems/DrainSystem.cs index 19cb650db7c..27ad2178f93 100644 --- a/Content.Server/Fluids/EntitySystems/DrainSystem.cs +++ b/Content.Server/Fluids/EntitySystems/DrainSystem.cs @@ -87,19 +87,25 @@ private void Empty(EntityUid container, SpillableComponent spillable, EntityUid // Try to transfer as much solution as possible to the drain - var transferSolution = _solutionContainerSystem.SplitSolution(containerSoln.Value, - FixedPoint2.Min(containerSolution.Volume, drainSolution.AvailableVolume)); + var amountToPutInDrain = drainSolution.AvailableVolume; + var amountToSpillOnGround = containerSolution.Volume - drainSolution.AvailableVolume; - _solutionContainerSystem.TryAddSolution(drain.Solution.Value, transferSolution); + if (amountToPutInDrain > 0) + { + var solutionToPutInDrain = _solutionContainerSystem.SplitSolution(containerSoln.Value, amountToPutInDrain); + _solutionContainerSystem.TryAddSolution(drain.Solution.Value, solutionToPutInDrain); + + _audioSystem.PlayPvs(drain.ManualDrainSound, target); + _ambientSoundSystem.SetAmbience(target, true); + } - _audioSystem.PlayPvs(drain.ManualDrainSound, target); - _ambientSoundSystem.SetAmbience(target, true); - // If drain is full, spill + // Spill the remainder. - if (drainSolution.MaxVolume == drainSolution.Volume) + if (amountToSpillOnGround > 0) { - _puddleSystem.TrySpillAt(Transform(target).Coordinates, containerSolution, out _); + var solutionToSpill = _solutionContainerSystem.SplitSolution(containerSoln.Value, amountToSpillOnGround); + _puddleSystem.TrySpillAt(Transform(target).Coordinates, solutionToSpill, out _); _popupSystem.PopupEntity( Loc.GetString("drain-component-empty-verb-target-is-full-message", ("object", target)), container); diff --git a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs index 7780e5d4676..d02dd44e81f 100644 --- a/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs +++ b/Content.Server/Fluids/EntitySystems/PuddleSystem.Spillable.cs @@ -1,16 +1,14 @@ using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Fluids.Components; using Content.Shared.Chemistry.Components; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Chemistry.Reaction; using Content.Shared.Chemistry.Reagent; -using Content.Shared.Clothing.Components; +using Content.Shared.Clothing; using Content.Shared.CombatMode.Pacification; using Content.Shared.Database; using Content.Shared.FixedPoint; using Content.Shared.Fluids.Components; using Content.Shared.IdentityManagement; -using Content.Shared.Inventory.Events; using Content.Shared.Nutrition.EntitySystems; using Content.Shared.Popups; using Content.Shared.Spillable; @@ -29,8 +27,8 @@ protected override void InitializeSpillable() SubscribeLocalEvent(SpillOnLand); // Openable handles the event if it's closed SubscribeLocalEvent(SplashOnMeleeHit, after: [typeof(OpenableSystem)]); - SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); SubscribeLocalEvent(OnOverflow); SubscribeLocalEvent(OnDoAfter); SubscribeLocalEvent(OnAttemptPacifiedThrow); @@ -99,20 +97,11 @@ private void SplashOnMeleeHit(Entity entity, ref MeleeHitEve } } - private void OnGotEquipped(Entity entity, ref GotEquippedEvent args) + private void OnGotEquipped(Entity entity, ref ClothingGotEquippedEvent args) { if (!entity.Comp.SpillWorn) return; - if (!TryComp(entity, out ClothingComponent? clothing)) - return; - - // check if entity was actually used as clothing - // not just taken in pockets or something - var isCorrectSlot = clothing.Slots.HasFlag(args.SlotFlags); - if (!isCorrectSlot) - return; - if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution)) return; @@ -124,10 +113,10 @@ private void OnGotEquipped(Entity entity, ref GotEquippedEve // spill all solution on the player var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume); - TrySplashSpillAt(entity.Owner, Transform(args.Equipee).Coordinates, drainedSolution, out _); + TrySplashSpillAt(entity.Owner, Transform(args.Wearer).Coordinates, drainedSolution, out _); } - private void OnGotUnequipped(Entity entity, ref GotUnequippedEvent args) + private void OnGotUnequipped(Entity entity, ref ClothingGotUnequippedEvent args) { if (!entity.Comp.SpillWorn) return; diff --git a/Content.Server/Fluids/EntitySystems/SpraySystem.cs b/Content.Server/Fluids/EntitySystems/SpraySystem.cs index f7621aec626..5499070738f 100644 --- a/Content.Server/Fluids/EntitySystems/SpraySystem.cs +++ b/Content.Server/Fluids/EntitySystems/SpraySystem.cs @@ -144,7 +144,7 @@ private void OnAfterInteract(Entity entity, ref AfterInteractEve _audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f)); - _useDelay.SetDelay((entity, useDelay), TimeSpan.FromSeconds(cooldownTime)); + _useDelay.SetLength(entity.Owner, TimeSpan.FromSeconds(cooldownTime)); _useDelay.TryResetDelay((entity, useDelay)); } } diff --git a/Content.Server/Forensics/Components/ForensicScannerComponent.cs b/Content.Server/Forensics/Components/ForensicScannerComponent.cs index ad262138482..3ad805cbbf8 100644 --- a/Content.Server/Forensics/Components/ForensicScannerComponent.cs +++ b/Content.Server/Forensics/Components/ForensicScannerComponent.cs @@ -1,4 +1,5 @@ using System.Threading; +using Content.Shared.Forensics; using Robust.Shared.Audio; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; diff --git a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs index 0d3168fd4e0..e83cde7456c 100644 --- a/Content.Server/Forensics/Systems/ForensicScannerSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicScannerSystem.cs @@ -52,8 +52,7 @@ private void UpdateUserInterface(EntityUid uid, ForensicScannerComponent compone component.PrintCooldown, component.PrintReadyAt); - if (!_uiSystem.TrySetUiState(uid, ForensicScannerUiKey.Key, state)) - Log.Warning($"{ToPrettyString(uid)} was unable to set UI state."); + _uiSystem.SetUiState(uid, ForensicScannerUiKey.Key, state); } private void OnDoAfter(EntityUid uid, ForensicScannerComponent component, DoAfterEvent args) @@ -164,23 +163,14 @@ private void OnBeforeActivatableUIOpen(EntityUid uid, ForensicScannerComponent c private void OpenUserInterface(EntityUid user, Entity scanner) { - if (!TryComp(user, out var actor)) - return; - UpdateUserInterface(scanner, scanner.Comp); - _uiSystem.TryOpen(scanner, ForensicScannerUiKey.Key, actor.PlayerSession); + _uiSystem.OpenUi(scanner.Owner, ForensicScannerUiKey.Key, user); } private void OnPrint(EntityUid uid, ForensicScannerComponent component, ForensicScannerPrintMessage args) { - if (!args.Session.AttachedEntity.HasValue) - { - Log.Warning($"{ToPrettyString(uid)} got OnPrint without Session.AttachedEntity"); - return; - } - - var user = args.Session.AttachedEntity.Value; + var user = args.Actor; if (_gameTiming.CurTime < component.PrintReadyAt) { @@ -192,7 +182,7 @@ private void OnPrint(EntityUid uid, ForensicScannerComponent component, Forensic // Spawn a piece of paper. var printed = EntityManager.SpawnEntity(component.MachineOutput, Transform(uid).Coordinates); - _handsSystem.PickupOrDrop(args.Session.AttachedEntity, printed, checkActionBlocker: false); + _handsSystem.PickupOrDrop(args.Actor, printed, checkActionBlocker: false); if (!HasComp(printed)) { @@ -241,9 +231,6 @@ private void OnPrint(EntityUid uid, ForensicScannerComponent component, Forensic private void OnClear(EntityUid uid, ForensicScannerComponent component, ForensicScannerClearMessage args) { - if (!args.Session.AttachedEntity.HasValue) - return; - component.Fingerprints = new(); component.Fibers = new(); component.DNAs = new(); diff --git a/Content.Server/Forensics/Systems/ForensicsSystem.cs b/Content.Server/Forensics/Systems/ForensicsSystem.cs index dff134a5113..b26a361d5ae 100644 --- a/Content.Server/Forensics/Systems/ForensicsSystem.cs +++ b/Content.Server/Forensics/Systems/ForensicsSystem.cs @@ -131,7 +131,7 @@ public void CopyForensicsFrom(ForensicsComponent src, EntityUid target) private void OnAfterInteract(EntityUid uid, CleansForensicsComponent component, AfterInteractEvent args) { - if (args.Handled) + if (args.Handled || !args.CanReach) return; if (TryComp(args.Target, out var forensicsComp) diff --git a/Content.Server/GameTicking/GameTicker.GamePreset.cs b/Content.Server/GameTicking/GameTicker.GamePreset.cs index b97a16ab993..fffacb59dee 100644 --- a/Content.Server/GameTicking/GameTicker.GamePreset.cs +++ b/Content.Server/GameTicking/GameTicker.GamePreset.cs @@ -100,7 +100,7 @@ private void InitializeGamePreset() SetGamePreset(LobbyEnabled ? _configurationManager.GetCVar(CCVars.GameLobbyDefaultPreset) : "sandbox"); } - public void SetGamePreset(GamePresetPrototype preset, bool force = false) + public void SetGamePreset(GamePresetPrototype? preset, bool force = false) { // Do nothing if this game ticker is a dummy! if (DummyTicker) @@ -274,35 +274,13 @@ public bool OnGhostAttempt(EntityUid mindId, bool canReturnGlobal, bool viaComma } } - var xformQuery = GetEntityQuery(); - var coords = _transform.GetMoverCoordinates(position, xformQuery); - - var ghost = Spawn(ObserverPrototypeName, coords); - - // Try setting the ghost entity name to either the character name or the player name. - // If all else fails, it'll default to the default entity prototype name, "observer". - // However, that should rarely happen. - if (!string.IsNullOrWhiteSpace(mind.CharacterName)) - _metaData.SetEntityName(ghost, mind.CharacterName); - else if (!string.IsNullOrWhiteSpace(mind.Session?.Name)) - _metaData.SetEntityName(ghost, mind.Session.Name); - - var ghostComponent = Comp(ghost); - - if (mind.TimeOfDeath.HasValue) - { - _ghost.SetTimeOfDeath(ghost, mind.TimeOfDeath!.Value, ghostComponent); - } + var ghost = _ghost.SpawnGhost((mindId, mind), position, canReturn); + if (ghost == null) + return false; if (playerEntity != null) _adminLogger.Add(LogType.Mind, $"{EntityManager.ToPrettyString(playerEntity.Value):player} ghosted{(!canReturn ? " (non-returnable)" : "")}"); - _ghost.SetCanReturnToBody(ghostComponent, canReturn); - - if (canReturn) - _mind.Visit(mindId, ghost, mind); - else - _mind.TransferTo(mindId, ghost, mind: mind); return true; } diff --git a/Content.Server/GameTicking/GameTicker.Player.cs b/Content.Server/GameTicking/GameTicker.Player.cs index be52137d4fc..2e003742055 100644 --- a/Content.Server/GameTicking/GameTicker.Player.cs +++ b/Content.Server/GameTicking/GameTicker.Player.cs @@ -142,13 +142,30 @@ private async void PlayerStatusChanged(object? sender, SessionStatusEventArgs ar async void SpawnWaitDb() { - await _userDb.WaitLoadComplete(session); + try + {await _userDb.WaitLoadComplete(session);} + catch (OperationCanceledException) + { + // Bail, user must've disconnected or something. + Log.Debug($"Database load cancelled while waiting to spawn {session}"); + return; + } SpawnPlayer(session, EntityUid.Invalid); } async void SpawnObserverWaitDb() { - await _userDb.WaitLoadComplete(session); + try + { + await _userDb.WaitLoadComplete(session); + } + catch (OperationCanceledException) + { + // Bail, user must've disconnected or something. + Log.Debug($"Database load cancelled while waiting to spawn {session}"); + return; + } + JoinAsObserver(session); } diff --git a/Content.Server/GameTicking/GameTicker.RoundFlow.cs b/Content.Server/GameTicking/GameTicker.RoundFlow.cs index 0fc984abeda..889a8a5a2b6 100644 --- a/Content.Server/GameTicking/GameTicker.RoundFlow.cs +++ b/Content.Server/GameTicking/GameTicker.RoundFlow.cs @@ -167,7 +167,7 @@ public IReadOnlyList LoadGameMap(GameMapPrototype map, MapId targetMa var gridIds = _map.LoadMap(targetMapId, ev.GameMap.MapPath.ToString(), ev.Options); - _metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), "Station map"); + _metaData.SetEntityName(_mapManager.GetMapEntityId(targetMapId), $"station map - {map.MapName}"); var gridUids = gridIds.ToList(); RaiseLocalEvent(new PostGameMapLoad(map, targetMapId, gridUids, stationName)); @@ -269,7 +269,10 @@ public void StartRound(bool force = false) var origReadyPlayers = readyPlayers.ToArray(); if (!StartPreset(origReadyPlayers, force)) + { + _startingRound = false; return; + } // MapInitialize *before* spawning players, our codebase is too shit to do it afterwards... _mapManager.DoMapInitialize(DefaultMap); diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index bd7d9b53932..aaaa291bd00 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -8,6 +8,7 @@ using Content.Server.Station.Components; using Content.Shared.CCVar; using Content.Shared.Database; +using Content.Shared.Mind; using Content.Shared.Players; using Content.Shared.Preferences; using Content.Shared.Roles; @@ -55,7 +56,9 @@ public List GetSpawnableStations() return spawnableStations; } - private void SpawnPlayers(List readyPlayers, Dictionary profiles, bool force) + private void SpawnPlayers(List readyPlayers, + Dictionary profiles, + bool force) { // Allow game rules to spawn players by themselves if needed. (For example, nuke ops or wizard) RaiseLocalEvent(new RulePlayerSpawningEvent(readyPlayers, profiles, force)); @@ -116,10 +119,17 @@ private void SpawnPlayers(List readyPlayers, Dictionary _playerManager.GetSessionById(x)).ToArray(), profiles, force)); + RaiseLocalEvent(new RulePlayerJobsAssignedEvent( + assignedJobs.Keys.Select(x => _playerManager.GetSessionById(x)).ToArray(), + profiles, + force)); } - private void SpawnPlayer(ICommonSession player, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) + private void SpawnPlayer(ICommonSession player, + EntityUid station, + string? jobId = null, + bool lateJoin = true, + bool silent = false) { var character = GetPlayerProfile(player); @@ -132,7 +142,12 @@ private void SpawnPlayer(ICommonSession player, EntityUid station, string? jobId SpawnPlayer(player, character, station, jobId, lateJoin, silent); } - private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile character, EntityUid station, string? jobId = null, bool lateJoin = true, bool silent = false) + private void SpawnPlayer(ICommonSession player, + HumanoidCharacterProfile character, + EntityUid station, + string? jobId = null, + bool lateJoin = true, + bool silent = false) { // Can't spawn players with a dummy ticker! if (DummyTicker) @@ -176,7 +191,9 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact restrictedRoles.UnionWith(jobBans); // Pick best job best on prefs. - jobId ??= _stationJobs.PickBestAvailableJobWithPriority(station, character.JobPriorities, true, + jobId ??= _stationJobs.PickBestAvailableJobWithPriority(station, + character.JobPriorities, + true, restrictedRoles); // If no job available, stay in lobby, or if no lobby spawn as observer if (jobId is null) @@ -185,7 +202,9 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact { JoinAsObserver(player); } - _chatManager.DispatchServerMessage(player, Loc.GetString("game-ticker-player-no-jobs-available-when-joining")); + + _chatManager.DispatchServerMessage(player, + Loc.GetString("game-ticker-player-no-jobs-available-when-joining")); return; } @@ -199,7 +218,7 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact _mind.SetUserId(newMind, data.UserId); var jobPrototype = _prototypeManager.Index(jobId); - var job = new JobComponent { Prototype = jobId }; + var job = new JobComponent {Prototype = jobId}; _roles.MindAddRole(newMind, job, silent: silent); var jobName = _jobs.MindTryGetJobName(newMind); @@ -222,11 +241,10 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact if (lateJoin && !silent) { _chatSystem.DispatchStationAnnouncement(station, - Loc.GetString( - "latejoin-arrival-announcement", - ("character", MetaData(mob).EntityName), - ("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName)) - ), Loc.GetString("latejoin-arrival-sender"), + Loc.GetString("latejoin-arrival-announcement", + ("character", MetaData(mob).EntityName), + ("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName))), + Loc.GetString("latejoin-arrival-sender"), playDefaultSound: false); } @@ -238,14 +256,17 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact _stationJobs.TryAssignJob(station, jobPrototype, player.UserId); if (lateJoin) - _adminLogger.Add(LogType.LateJoin, LogImpact.Medium, $"Player {player.Name} late joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}."); + _adminLogger.Add(LogType.LateJoin, + LogImpact.Medium, + $"Player {player.Name} late joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}."); else - _adminLogger.Add(LogType.RoundStartJoin, LogImpact.Medium, $"Player {player.Name} joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}."); + _adminLogger.Add(LogType.RoundStartJoin, + LogImpact.Medium, + $"Player {player.Name} joined as {character.Name:characterName} on station {Name(station):stationName} with {ToPrettyString(mob):entity} as a {jobName:jobName}."); // Make sure they're aware of extended access. if (Comp(station).ExtendedAccess - && (jobPrototype.ExtendedAccess.Count > 0 - || jobPrototype.ExtendedAccessGroups.Count > 0)) + && (jobPrototype.ExtendedAccess.Count > 0 || jobPrototype.ExtendedAccessGroups.Count > 0)) { _chatManager.DispatchServerMessage(player, Loc.GetString("job-greet-crew-shortages")); } @@ -267,14 +288,20 @@ private void SpawnPlayer(ICommonSession player, HumanoidCharacterProfile charact } else { - _chatManager.DispatchServerMessage(player, Loc.GetString("latejoin-arrivals-direction-time", - ("time", $"{arrival:mm\\:ss}"))); + _chatManager.DispatchServerMessage(player, + Loc.GetString("latejoin-arrivals-direction-time", ("time", $"{arrival:mm\\:ss}"))); } } // We raise this event directed to the mob, but also broadcast it so game rules can do something now. PlayersJoinedRoundNormally++; - var aev = new PlayerSpawnCompleteEvent(mob, player, jobId, lateJoin, PlayersJoinedRoundNormally, station, character); + var aev = new PlayerSpawnCompleteEvent(mob, + player, + jobId, + lateJoin, + PlayersJoinedRoundNormally, + station, + character); RaiseLocalEvent(mob, aev, true); } @@ -329,31 +356,24 @@ public void SpawnObserver(ICommonSession player) if (DummyTicker) return; - var mind = player.GetMind(); + Entity? mind = player.GetMind(); if (mind == null) { - mind = _mind.CreateMind(player.UserId); + var name = GetPlayerProfile(player).Name; + var (mindId, mindComp) = _mind.CreateMind(player.UserId, name); + mind = (mindId, mindComp); _mind.SetUserId(mind.Value, player.UserId); _roles.MindAddRole(mind.Value, new ObserverRoleComponent()); } - var name = GetPlayerProfile(player).Name; - var ghost = SpawnObserverMob(); - _metaData.SetEntityName(ghost, name); - _ghost.SetCanReturnToBody(ghost, false); - _mind.TransferTo(mind.Value, ghost); - _adminLogger.Add(LogType.LateJoin, LogImpact.Low, $"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}."); - } - - #region Mob Spawning Helpers - private EntityUid SpawnObserverMob() - { - var coordinates = GetObserverSpawnPoint(); - return EntityManager.SpawnEntity(ObserverPrototypeName, coordinates); + var ghost = _ghost.SpawnGhost(mind.Value); + _adminLogger.Add(LogType.LateJoin, + LogImpact.Low, + $"{player.Name} late joined the round as an Observer with {ToPrettyString(ghost):entity}."); } - #endregion #region Spawn Points + public EntityCoordinates GetObserverSpawnPoint() { _possiblePositions.Clear(); @@ -374,8 +394,7 @@ public EntityCoordinates GetObserverSpawnPoint() var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var grid)) { - if (!metaQuery.TryGetComponent(uid, out var meta) || - meta.EntityPaused) + if (!metaQuery.TryGetComponent(uid, out var meta) || meta.EntityPaused || TerminatingOrDeleted(uid)) { continue; } @@ -396,8 +415,7 @@ public EntityCoordinates GetObserverSpawnPoint() { var gridXform = Transform(gridUid); - return new EntityCoordinates(gridUid, - gridXform.InvWorldMatrix.Transform(toMap.Position)); + return new EntityCoordinates(gridUid, gridXform.InvWorldMatrix.Transform(toMap.Position)); } return spawn; @@ -413,8 +431,9 @@ public EntityCoordinates GetObserverSpawnPoint() { var mapUid = _mapManager.GetMapEntityId(map); - if (!metaQuery.TryGetComponent(mapUid, out var meta) || - meta.EntityPaused) + if (!metaQuery.TryGetComponent(mapUid, out var meta) + || meta.EntityPaused + || TerminatingOrDeleted(mapUid)) { continue; } @@ -427,6 +446,7 @@ public EntityCoordinates GetObserverSpawnPoint() _sawmill.Warning("Found no observer spawn points!"); return EntityCoordinates.Invalid; } + #endregion } @@ -444,7 +464,11 @@ public sealed class PlayerBeforeSpawnEvent : HandledEntityEventArgs public bool LateJoin { get; } public EntityUid Station { get; } - public PlayerBeforeSpawnEvent(ICommonSession player, HumanoidCharacterProfile profile, string? jobId, bool lateJoin, EntityUid station) + public PlayerBeforeSpawnEvent(ICommonSession player, + HumanoidCharacterProfile profile, + string? jobId, + bool lateJoin, + EntityUid station) { Player = player; Profile = profile; @@ -472,7 +496,13 @@ public sealed class PlayerSpawnCompleteEvent : EntityEventArgs // Ex. If this is the 27th person to join, this will be 27. public int JoinOrder { get; } - public PlayerSpawnCompleteEvent(EntityUid mob, ICommonSession player, string? jobId, bool lateJoin, int joinOrder, EntityUid station, HumanoidCharacterProfile profile) + public PlayerSpawnCompleteEvent(EntityUid mob, + ICommonSession player, + string? jobId, + bool lateJoin, + int joinOrder, + EntityUid station, + HumanoidCharacterProfile profile) { Mob = mob; Player = player; diff --git a/Content.Server/GameTicking/Rules/Components/LoadMapRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/LoadMapRuleComponent.cs index 463aecbff54..b7aef0c61dc 100644 --- a/Content.Server/GameTicking/Rules/Components/LoadMapRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/LoadMapRuleComponent.cs @@ -1,4 +1,6 @@ using Content.Server.Maps; +using Content.Shared.GridPreloader.Prototypes; +using Content.Shared.Storage; using Content.Shared.Whitelist; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -16,11 +18,14 @@ public sealed partial class LoadMapRuleComponent : Component public MapId? Map; [DataField] - public ProtoId? GameMap ; + public ProtoId? GameMap; [DataField] public ResPath? MapPath; + [DataField] + public ProtoId? PreloadedGrid; + [DataField] public List MapGrids = new(); diff --git a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs index f64947e286e..7862b38e592 100644 --- a/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/NukeopsRuleComponent.cs @@ -5,11 +5,7 @@ using Content.Shared.Roles; using Robust.Shared.Audio; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -using Robust.Shared.Utility; - namespace Content.Server.GameTicking.Rules.Components; diff --git a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs index dd359969b6f..47a4adeaf34 100644 --- a/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs +++ b/Content.Server/GameTicking/Rules/Components/TraitorRuleComponent.cs @@ -31,6 +31,9 @@ public sealed partial class TraitorRuleComponent : Component [DataField] public ProtoId CodewordVerbs = "verbs"; + [DataField] + public ProtoId ObjectiveIssuers = "TraitorCorporations"; + public int TotalTraitors => TraitorMinds.Count; public string[] Codewords = new string[3]; diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs index 27a9edbad71..cbd981e99e6 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.Utility.cs @@ -1,7 +1,10 @@ using System.Diagnostics.CodeAnalysis; +using System.Linq; using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; using Content.Server.Station.Components; +using Content.Shared.Random.Helpers; +using Robust.Server.GameObjects; using Robust.Shared.Collections; using Robust.Shared.Map; using Robust.Shared.Map.Components; @@ -82,17 +85,23 @@ protected bool TryFindRandomTileOnStation(Entity station, targetCoords = EntityCoordinates.Invalid; targetGrid = EntityUid.Invalid; - var possibleTargets = station.Comp.Grids; - if (possibleTargets.Count == 0) + // Weight grid choice by tilecount + var weights = new Dictionary, float>(); + foreach (var possibleTarget in station.Comp.Grids) + { + if (!TryComp(possibleTarget, out var comp)) + continue; + + weights.Add((possibleTarget, comp), _map.GetAllTiles(possibleTarget, comp).Count()); + } + + if (weights.Count == 0) { targetGrid = EntityUid.Invalid; return false; } - targetGrid = RobustRandom.Pick(possibleTargets); - - if (!TryComp(targetGrid, out var gridComp)) - return false; + (targetGrid, var gridComp) = RobustRandom.Pick(weights); var found = false; var aabb = gridComp.LocalAABB; diff --git a/Content.Server/GameTicking/Rules/GameRuleSystem.cs b/Content.Server/GameTicking/Rules/GameRuleSystem.cs index c167ae7b6c7..05374aa1396 100644 --- a/Content.Server/GameTicking/Rules/GameRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/GameRuleSystem.cs @@ -26,7 +26,7 @@ public override void Initialize() SubscribeLocalEvent(OnGameRuleAdded); SubscribeLocalEvent(OnGameRuleStarted); SubscribeLocalEvent(OnGameRuleEnded); - SubscribeLocalEvent(OnRoundEndTextAppend); + SubscribeLocalEvent(OnRoundEndTextAppend); } private void OnStartAttempt(RoundStartAttemptEvent args) @@ -70,11 +70,16 @@ private void OnGameRuleEnded(EntityUid uid, T component, ref GameRuleEndedEvent Ended(uid, component, ruleData, args); } - private void OnRoundEndTextAppend(Entity ent, ref RoundEndTextAppendEvent args) + private void OnRoundEndTextAppend(RoundEndTextAppendEvent ev) { - if (!TryComp(ent, out var ruleData)) - return; - AppendRoundEndText(ent, ent, ruleData, ref args); + var query = AllEntityQuery(); + while (query.MoveNext(out var uid, out var comp)) + { + if (!TryComp(uid, out var ruleData)) + continue; + + AppendRoundEndText(uid, comp, ruleData, ref ev); + } } /// diff --git a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs index aba9ed9e583..3a80d82fd92 100644 --- a/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/LoadMapRuleSystem.cs @@ -1,9 +1,11 @@ using Content.Server.Antag; using Content.Server.GameTicking.Components; using Content.Server.GameTicking.Rules.Components; +using Content.Server.GridPreloader; using Content.Server.Spawners.Components; using Robust.Server.GameObjects; using Robust.Server.Maps; +using Robust.Shared.Map; using Robust.Shared.Prototypes; namespace Content.Server.GameTicking.Rules; @@ -11,9 +13,12 @@ namespace Content.Server.GameTicking.Rules; public sealed class LoadMapRuleSystem : GameRuleSystem { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly MapSystem _map = default!; [Dependency] private readonly MapLoaderSystem _mapLoader = default!; + [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly GridPreloaderSystem _gridPreloader = default!; public override void Initialize() { @@ -41,7 +46,9 @@ protected override void Added(EntityUid uid, LoadMapRuleComponent comp, GameRule if (comp.Map != null) return; - _map.CreateMap(out var mapId); + // grid preloading needs map to init after moving it + var mapUid = comp.PreloadedGrid != null ? _map.CreateMap(out var mapId, false) : _map.CreateMap(out mapId); + _metaData.SetEntityName(mapUid, $"LoadMapRule destination for rule {ToPrettyString(uid)}"); comp.Map = mapId; if (comp.GameMap != null) @@ -51,8 +58,29 @@ protected override void Added(EntityUid uid, LoadMapRuleComponent comp, GameRule } else if (comp.MapPath != null) { - if (_mapLoader.TryLoad(comp.Map.Value, comp.MapPath.Value.ToString(), out var roots, new MapLoadOptions { LoadMap = true })) - comp.MapGrids.AddRange(roots); + if (!_mapLoader.TryLoad(comp.Map.Value, + comp.MapPath.Value.ToString(), + out var roots, + new MapLoadOptions { LoadMap = true })) + { + _mapManager.DeleteMap(mapId); + return; + } + + comp.MapGrids.AddRange(roots); + } + else if (comp.PreloadedGrid != null) + { + // TODO: If there are no preloaded grids left, any rule announcements will still go off! + if (!_gridPreloader.TryGetPreloadedGrid(comp.PreloadedGrid.Value, out var loadedShuttle)) + { + _mapManager.DeleteMap(mapId); + return; + } + + _transform.SetParent(loadedShuttle.Value, mapUid); + comp.MapGrids.Add(loadedShuttle.Value); + _map.InitializeMap(mapId); } else { diff --git a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs index ee3a025533a..cae99fee9fc 100644 --- a/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/MaxTimeRestartRuleSystem.cs @@ -34,6 +34,7 @@ protected override void Ended(EntityUid uid, MaxTimeRestartRuleComponent compone public void RestartTimer(MaxTimeRestartRuleComponent component) { + // TODO FULL GAME SAVE component.TimerCancel.Cancel(); component.TimerCancel = new CancellationTokenSource(); Timer.Spawn(component.RoundMaxTime, () => TimerFired(component), component.TimerCancel.Token); @@ -50,6 +51,7 @@ private void TimerFired(MaxTimeRestartRuleComponent component) _chatManager.DispatchServerAnnouncement(Loc.GetString("rule-restarting-in-seconds",("seconds", (int) component.RoundEndDelay.TotalSeconds))); + // TODO FULL GAME SAVE Timer.Spawn(component.RoundEndDelay, () => GameTicker.RestartRound()); } diff --git a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs index d06b9fb899c..3e61fda8744 100644 --- a/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/NukeopsRuleSystem.cs @@ -481,12 +481,10 @@ private void OnAntagSelectEntity(Entity ent, ref AntagSele ? _prefs.GetPreferences(args.Session.UserId).SelectedCharacter as HumanoidCharacterProfile : HumanoidCharacterProfile.RandomWithSpecies(); if (!_prototypeManager.TryIndex(profile?.Species ?? SharedHumanoidAppearanceSystem.DefaultSpecies, out SpeciesPrototype? species)) - { species = _prototypeManager.Index(SharedHumanoidAppearanceSystem.DefaultSpecies); - } args.Entity = Spawn(species.Prototype); - _humanoid.LoadProfile(args.Entity.Value, profile); + _humanoid.LoadProfile(args.Entity.Value, profile!); } private void OnAfterAntagEntSelected(Entity ent, ref AfterAntagEntitySelectedEvent args) diff --git a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs index 7e6901e6c48..577b0c30303 100644 --- a/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/RevolutionaryRuleSystem.cs @@ -28,6 +28,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Timing; using Content.Server.GameTicking.Components; +using Content.Shared.Cuffs.Components; namespace Content.Server.GameTicking.Rules; @@ -141,7 +142,6 @@ private void OnPostFlash(EntityUid uid, HeadRevolutionaryComponent comp, ref Aft _npcFaction.AddFaction(ev.Target, RevolutionaryNpcFaction); var revComp = EnsureComp(ev.Target); - _stun.TryParalyze(ev.Target, comp.StunTime, true); if (ev.User != null) { @@ -180,7 +180,7 @@ private bool CheckCommandLose() commandList.Add(id); } - return IsGroupDead(commandList, true); + return IsGroupDetainedOrDead(commandList, true, true); } private void OnHeadRevMobStateChanged(EntityUid uid, HeadRevolutionaryComponent comp, MobStateChangedEvent ev) @@ -204,7 +204,8 @@ private bool CheckRevsLose() } // If no Head Revs are alive all normal Revs will lose their Rev status and rejoin Nanotrasen - if (IsGroupDead(headRevList, false)) + // Cuffing Head Revs is not enough - they must be killed. + if (IsGroupDetainedOrDead(headRevList, false, false)) { var rev = AllEntityQuery(); while (rev.MoveNext(out var uid, out _, out var mc)) @@ -236,35 +237,43 @@ private bool CheckRevsLose() } /// - /// Will take a group of entities and check if they are all alive or dead + /// Will take a group of entities and check if these entities are alive, dead or cuffed. /// /// The list of the entities - /// Bool for if you want to check if someone is in space and consider them dead. (Won't check when emergency shuttle arrives just in case) + /// Bool for if you want to check if someone is in space and consider them missing in action. (Won't check when emergency shuttle arrives just in case) + /// Bool for if you don't want to count cuffed entities. /// - private bool IsGroupDead(List list, bool checkOffStation) + private bool IsGroupDetainedOrDead(List list, bool checkOffStation, bool countCuffed) { - var dead = 0; + var gone = 0; foreach (var entity in list) { - if (TryComp(entity, out var state)) + if (TryComp(entity, out var cuffed) && cuffed.CuffedHandCount > 0 && countCuffed) { - if (state.CurrentState == MobState.Dead || state.CurrentState == MobState.Invalid) + gone++; + } + else + { + if (TryComp(entity, out var state)) { - dead++; + if (state.CurrentState == MobState.Dead || state.CurrentState == MobState.Invalid) + { + gone++; + } + else if (checkOffStation && _stationSystem.GetOwningStation(entity) == null && !_emergencyShuttle.EmergencyShuttleArrived) + { + gone++; + } } - else if (checkOffStation && _stationSystem.GetOwningStation(entity) == null && !_emergencyShuttle.EmergencyShuttleArrived) + //If they don't have the MobStateComponent they might as well be dead. + else { - dead++; + gone++; } } - //If they don't have the MobStateComponent they might as well be dead. - else - { - dead++; - } } - return dead == list.Count || list.Count == 0; + return gone == list.Count || list.Count == 0; } private static readonly string[] Outcomes = diff --git a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs index aff49510d9f..3f0e42c5af0 100644 --- a/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/TraitorRuleSystem.cs @@ -76,6 +76,7 @@ public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool return false; var briefing = Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", component.Codewords))); + var issuer = _random.Pick(_prototypeManager.Index(component.ObjectiveIssuers).Values); if (TryComp(traitor, out var autoTraitorComponent)) { @@ -105,7 +106,7 @@ public bool MakeTraitor(EntityUid traitor, TraitorRuleComponent component, bool Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("-", code).Replace("sharp", "#")))); } - _antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code), null, component.GreetSoundNotification); + _antag.SendBriefing(traitor, GenerateBriefing(component.Codewords, code, issuer), null, component.GreetSoundNotification); component.TraitorMinds.Add(mindId); @@ -152,10 +153,10 @@ private void OnObjectivesTextPrepend(EntityUid uid, TraitorRuleComponent comp, r args.Text += "\n" + Loc.GetString("traitor-round-end-codewords", ("codewords", string.Join(", ", comp.Codewords))); } - private string GenerateBriefing(string[] codewords, Note[]? uplinkCode) + private string GenerateBriefing(string[] codewords, Note[]? uplinkCode, string? objectiveIssuer = null) { var sb = new StringBuilder(); - sb.AppendLine(Loc.GetString("traitor-role-greeting")); + sb.AppendLine(Loc.GetString("traitor-role-greeting", ("corporation", objectiveIssuer ?? Loc.GetString("objective-issuer-unknown")))); sb.AppendLine(Loc.GetString("traitor-role-codewords-short", ("codewords", string.Join(", ", codewords)))); if (uplinkCode != null) sb.AppendLine(Loc.GetString("traitor-role-uplink-code-short", ("code", string.Join("-", uplinkCode).Replace("sharp", "#")))); diff --git a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs index f62d0b79ffb..1361ab37338 100644 --- a/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs +++ b/Content.Server/GameTicking/Rules/ZombieRuleSystem.cs @@ -38,7 +38,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnZombifySelf); + SubscribeLocalEvent(OnZombifySelf); } protected override void AppendRoundEndText(EntityUid uid, ZombieRuleComponent component, GameRuleComponent gameRule, @@ -133,7 +133,7 @@ protected override void ActiveTick(EntityUid uid, ZombieRuleComponent component, component.NextRoundEndCheck = _timing.CurTime + component.EndCheckDelay; } - private void OnZombifySelf(EntityUid uid, PendingZombieComponent component, ZombifySelfActionEvent args) + private void OnZombifySelf(EntityUid uid, IncurableZombieComponent component, ZombifySelfActionEvent args) { _zombie.ZombifyEntity(uid); if (component.Action != null) diff --git a/Content.Server/Gateway/Systems/GatewaySystem.cs b/Content.Server/Gateway/Systems/GatewaySystem.cs index 7ebc751dd2d..6ed28d71a76 100644 --- a/Content.Server/Gateway/Systems/GatewaySystem.cs +++ b/Content.Server/Gateway/Systems/GatewaySystem.cs @@ -129,7 +129,7 @@ private void UpdateUserInterface(EntityUid uid, GatewayComponent comp, Transform unlockTime ); - _ui.TrySetUiState(uid, GatewayUiKey.Key, state); + _ui.SetUiState(uid, GatewayUiKey.Key, state); } private void UpdateAppearance(EntityUid uid) @@ -139,12 +139,14 @@ private void UpdateAppearance(EntityUid uid) private void OnOpenPortal(EntityUid uid, GatewayComponent comp, GatewayOpenPortalMessage args) { - if (args.Session.AttachedEntity == null || GetNetEntity(uid) == args.Destination || + if (GetNetEntity(uid) == args.Destination || !comp.Enabled || !comp.Interactable) + { return; + } // if the gateway has an access reader check it before allowing opening - var user = args.Session.AttachedEntity.Value; + var user = args.Actor; if (CheckAccess(user, uid, comp)) return; diff --git a/Content.Server/Geras/GerasComponent.cs b/Content.Server/Geras/GerasComponent.cs new file mode 100644 index 00000000000..eaf792502f4 --- /dev/null +++ b/Content.Server/Geras/GerasComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.Actions; +using Content.Shared.Polymorph; +using Robust.Shared.Prototypes; + +namespace Content.Server.Geras; + +/// +/// This component assigns the entity with a polymorph action. +/// +[RegisterComponent] +public sealed partial class GerasComponent : Component +{ + [DataField] public ProtoId GerasPolymorphId = "SlimeMorphGeras"; + + [DataField] public ProtoId GerasAction = "ActionMorphGeras"; + + [DataField] public EntityUid? GerasActionEntity; +} diff --git a/Content.Server/Geras/GerasSystem.cs b/Content.Server/Geras/GerasSystem.cs new file mode 100644 index 00000000000..e7999d64d87 --- /dev/null +++ b/Content.Server/Geras/GerasSystem.cs @@ -0,0 +1,52 @@ +using Content.Server.Polymorph.Systems; +using Content.Shared.Zombies; +using Content.Server.Actions; +using Content.Server.Popups; +using Content.Shared.Geras; +using Robust.Shared.Player; + +namespace Content.Server.Geras; + +/// +public sealed class GerasSystem : SharedGerasSystem +{ + [Dependency] private readonly PolymorphSystem _polymorphSystem = default!; + [Dependency] private readonly MetaDataSystem _metaDataSystem = default!; + [Dependency] private readonly ActionsSystem _actionsSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnMorphIntoGeras); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnZombification); + } + + private void OnZombification(EntityUid uid, GerasComponent component, EntityZombifiedEvent args) + { + _actionsSystem.RemoveAction(uid, component.GerasActionEntity); + } + + private void OnMapInit(EntityUid uid, GerasComponent component, MapInitEvent args) + { + // try to add geras action + _actionsSystem.AddAction(uid, ref component.GerasActionEntity, component.GerasAction); + } + + private void OnMorphIntoGeras(EntityUid uid, GerasComponent component, MorphIntoGeras args) + { + if (HasComp(uid)) + return; // i hate zomber. + + var ent = _polymorphSystem.PolymorphEntity(uid, component.GerasPolymorphId); + + if (!ent.HasValue) + return; + + _popupSystem.PopupEntity(Loc.GetString("geras-popup-morph-message-others", ("entity", ent.Value)), ent.Value, Filter.PvsExcept(ent.Value), true); + _popupSystem.PopupEntity(Loc.GetString("geras-popup-morph-message-user"), ent.Value, ent.Value); + + args.Handled = true; + } +} diff --git a/Content.Server/Ghost/GhostSystem.cs b/Content.Server/Ghost/GhostSystem.cs index c0e753c4c55..b1fb67cce7b 100644 --- a/Content.Server/Ghost/GhostSystem.cs +++ b/Content.Server/Ghost/GhostSystem.cs @@ -19,6 +19,7 @@ using Content.Shared.Storage.Components; using Robust.Server.GameObjects; using Robust.Server.Player; +using Robust.Shared.Map; using Robust.Shared.Physics.Components; using Robust.Shared.Physics.Systems; using Robust.Shared.Player; @@ -42,11 +43,19 @@ public sealed class GhostSystem : SharedGhostSystem [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly TransformSystem _transformSystem = default!; [Dependency] private readonly VisibilitySystem _visibilitySystem = default!; + [Dependency] private readonly MetaDataSystem _metaData = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + + private EntityQuery _ghostQuery; + private EntityQuery _physicsQuery; public override void Initialize() { base.Initialize(); + _ghostQuery = GetEntityQuery(); + _physicsQuery = GetEntityQuery(); + SubscribeLocalEvent(OnGhostStartup); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnGhostShutdown); @@ -62,12 +71,14 @@ public override void Initialize() SubscribeNetworkEvent(OnGhostWarpsRequest); SubscribeNetworkEvent(OnGhostReturnToBodyRequest); SubscribeNetworkEvent(OnGhostWarpToTargetRequest); + SubscribeNetworkEvent(OnGhostnadoRequest); SubscribeLocalEvent(OnActionPerform); SubscribeLocalEvent(OnGhostHearingAction); SubscribeLocalEvent(OnEntityStorageInsertAttempt); SubscribeLocalEvent(_ => MakeVisible(true)); + SubscribeLocalEvent(OnToggleGhostVisibilityToAll); } private void OnGhostHearingAction(EntityUid uid, GhostComponent component, ToggleGhostHearingActionEvent args) @@ -241,7 +252,7 @@ private void DeleteEntity(EntityUid uid) private void OnGhostReturnToBodyRequest(GhostReturnToBodyRequest msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not {Valid: true} attached - || !TryComp(attached, out GhostComponent? ghost) + || !_ghostQuery.TryComp(attached, out var ghost) || !ghost.CanReturnToBody || !TryComp(attached, out ActorComponent? actor)) { @@ -257,7 +268,7 @@ private void OnGhostReturnToBodyRequest(GhostReturnToBodyRequest msg, EntitySess private void OnGhostWarpsRequest(GhostWarpsRequestEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not {Valid: true} entity - || !HasComp(entity)) + || !_ghostQuery.HasComp(entity)) { Log.Warning($"User {args.SenderSession.Name} sent a {nameof(GhostWarpsRequestEvent)} without being a ghost."); return; @@ -270,7 +281,7 @@ private void OnGhostWarpsRequest(GhostWarpsRequestEvent msg, EntitySessionEventA private void OnGhostWarpToTargetRequest(GhostWarpToTargetRequestEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not {Valid: true} attached - || !TryComp(attached, out GhostComponent? _)) + || !_ghostQuery.HasComp(attached)) { Log.Warning($"User {args.SenderSession.Name} tried to warp to {msg.Target} without being a ghost."); return; @@ -284,17 +295,37 @@ private void OnGhostWarpToTargetRequest(GhostWarpToTargetRequestEvent msg, Entit return; } + WarpTo(attached, target); + } + + private void OnGhostnadoRequest(GhostnadoRequestEvent msg, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not {} uid + || !_ghostQuery.HasComp(uid)) + { + Log.Warning($"User {args.SenderSession.Name} tried to ghostnado without being a ghost."); + return; + } + + if (_followerSystem.GetMostFollowed() is not {} target) + return; + + WarpTo(uid, target); + } + + private void WarpTo(EntityUid uid, EntityUid target) + { if ((TryComp(target, out WarpPointComponent? warp) && warp.Follow) || HasComp(target)) { - _followerSystem.StartFollowingEntity(attached, target); + _followerSystem.StartFollowingEntity(uid, target); return; } - var xform = Transform(attached); - _transformSystem.SetCoordinates(attached, xform, Transform(target).Coordinates); - _transformSystem.AttachToGridOrMap(attached, xform); - if (TryComp(attached, out PhysicsComponent? physics)) - _physics.SetLinearVelocity(attached, Vector2.Zero, body: physics); + var xform = Transform(uid); + _transformSystem.SetCoordinates(uid, xform, Transform(target).Coordinates); + _transformSystem.AttachToGridOrMap(uid, xform); + if (_physicsQuery.TryComp(uid, out var physics)) + _physics.SetLinearVelocity(uid, Vector2.Zero, body: physics); } private IEnumerable GetLocationWarps() @@ -333,6 +364,15 @@ private void OnEntityStorageInsertAttempt(EntityUid uid, GhostComponent comp, re args.Cancelled = true; } + private void OnToggleGhostVisibilityToAll(ToggleGhostVisibilityToAllEvent ev) + { + if (ev.Handled) + return; + + ev.Handled = true; + MakeVisible(true); + } + /// /// When the round ends, make all players able to see ghosts. /// @@ -362,5 +402,59 @@ public bool DoGhostBooEvent(EntityUid target) return ghostBoo.Handled; } + + public EntityUid? SpawnGhost(Entity mind, EntityUid targetEntity, + bool canReturn = false) + { + _transformSystem.TryGetMapOrGridCoordinates(targetEntity, out var spawnPosition); + return SpawnGhost(mind, spawnPosition, canReturn); + } + + public EntityUid? SpawnGhost(Entity mind, EntityCoordinates? spawnPosition = null, + bool canReturn = false) + { + if (!Resolve(mind, ref mind.Comp)) + return null; + + // Test if the map is being deleted + var mapUid = spawnPosition?.GetMapUid(EntityManager); + if (mapUid == null || TerminatingOrDeleted(mapUid.Value)) + spawnPosition = null; + + spawnPosition ??= _ticker.GetObserverSpawnPoint(); + + if (!spawnPosition.Value.IsValid(EntityManager)) + { + Log.Warning($"No spawn valid ghost spawn position found for {mind.Comp.CharacterName}" + + " \"{ToPrettyString(mind)}\""); + _minds.TransferTo(mind.Owner, null, createGhost: false, mind: mind.Comp); + return null; + } + + var ghost = SpawnAtPosition(GameTicker.ObserverPrototypeName, spawnPosition.Value); + var ghostComponent = Comp(ghost); + + // Try setting the ghost entity name to either the character name or the player name. + // If all else fails, it'll default to the default entity prototype name, "observer". + // However, that should rarely happen. + if (!string.IsNullOrWhiteSpace(mind.Comp.CharacterName)) + _metaData.SetEntityName(ghost, mind.Comp.CharacterName); + else if (!string.IsNullOrWhiteSpace(mind.Comp.Session?.Name)) + _metaData.SetEntityName(ghost, mind.Comp.Session.Name); + + if (mind.Comp.TimeOfDeath.HasValue) + { + SetTimeOfDeath(ghost, mind.Comp.TimeOfDeath!.Value, ghostComponent); + } + + SetCanReturnToBody(ghostComponent, canReturn); + + if (canReturn) + _minds.Visit(mind.Owner, ghost, mind.Comp); + else + _minds.TransferTo(mind.Owner, ghost, mind: mind.Comp); + Log.Debug($"Spawned ghost \"{ToPrettyString(ghost)}\" for {mind.Comp.CharacterName}."); + return ghost; + } } } diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs index 997961ae675..35b8ad75564 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.Mind.Commands; +using Content.Server.Ghost.Roles.Raffles; +using Content.Server.Mind.Commands; using Content.Shared.Customization.Systems; using Content.Shared.Roles; @@ -88,5 +89,12 @@ public string RoleRules [ViewVariables(VVAccess.ReadWrite)] [DataField("reregister")] public bool ReregisterOnGhost { get; set; } = true; + + /// + /// If set, ghost role is raffled, otherwise it is first-come-first-serve. + /// + [DataField("raffle")] + [Access(typeof(GhostRoleSystem), Other = AccessPermissions.ReadWriteExecute)] // FIXME Friends + public GhostRoleRaffleConfig? RaffleConfig { get; set; } } } diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs index 4cdab6ce070..6c2a6986fc9 100644 --- a/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs +++ b/Content.Server/Ghost/Roles/Components/GhostRoleMobSpawnerComponent.cs @@ -1,5 +1,4 @@ using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Ghost.Roles.Components { @@ -10,17 +9,22 @@ namespace Content.Server.Ghost.Roles.Components [Access(typeof(GhostRoleSystem))] public sealed partial class GhostRoleMobSpawnerComponent : Component { - [ViewVariables(VVAccess.ReadWrite)] [DataField("deleteOnSpawn")] + [DataField] public bool DeleteOnSpawn = true; - [ViewVariables(VVAccess.ReadWrite)] [DataField("availableTakeovers")] + [DataField] public int AvailableTakeovers = 1; [ViewVariables] public int CurrentTakeovers = 0; - [ViewVariables(VVAccess.ReadWrite)] - [DataField("prototype", customTypeSerializer: typeof(PrototypeIdSerializer))] - public string? Prototype { get; private set; } + [DataField] + public EntProtoId? Prototype; + + /// + /// If this ghostrole spawner has multiple selectable ghostrole prototypes. + /// + [DataField] + public List SelectablePrototypes = []; } } diff --git a/Content.Server/Ghost/Roles/Components/GhostRoleRaffleComponent.cs b/Content.Server/Ghost/Roles/Components/GhostRoleRaffleComponent.cs new file mode 100644 index 00000000000..ac518685e9b --- /dev/null +++ b/Content.Server/Ghost/Roles/Components/GhostRoleRaffleComponent.cs @@ -0,0 +1,58 @@ +using Content.Server.Ghost.Roles.Raffles; +using Robust.Shared.Player; + +namespace Content.Server.Ghost.Roles.Components; + +/// +/// Indicates that a ghost role is currently being raffled, and stores data about the raffle in progress. +/// Raffles start when the first player joins a raffle. +/// +[RegisterComponent] +[Access(typeof(GhostRoleSystem))] +public sealed partial class GhostRoleRaffleComponent : Component +{ + /// + /// Identifier of the Ghost Role this raffle is for. + /// + [ViewVariables(VVAccess.ReadOnly)] + [DataField] + public uint Identifier { get; set; } + + /// + /// List of sessions that are currently in the raffle. + /// + [ViewVariables(VVAccess.ReadOnly)] + public HashSet CurrentMembers = []; + + /// + /// List of sessions that are currently or were previously in the raffle. + /// + [ViewVariables(VVAccess.ReadOnly)] + public HashSet AllMembers = []; + + /// + /// Time left in the raffle in seconds. This must be initialized to a positive value. + /// + [ViewVariables(VVAccess.ReadOnly)] + [DataField] + public TimeSpan Countdown = TimeSpan.MaxValue; + + /// + /// The cumulative time, i.e. how much time the raffle will take in total. Added to when the time is extended + /// by someone joining the raffle. + /// Must be set to the same value as on initialization. + /// + [ViewVariables(VVAccess.ReadOnly)] + [DataField("cumulativeTime")] + public TimeSpan CumulativeTime = TimeSpan.MaxValue; + + /// + [ViewVariables(VVAccess.ReadOnly)] + [DataField("joinExtendsDurationBy")] + public TimeSpan JoinExtendsDurationBy { get; set; } + + /// + [ViewVariables(VVAccess.ReadOnly)] + [DataField("maxDuration")] + public TimeSpan MaxDuration { get; set; } +} diff --git a/Content.Server/Ghost/Roles/GhostRoleSystem.cs b/Content.Server/Ghost/Roles/GhostRoleSystem.cs index f603416d00a..de719ed1570 100644 --- a/Content.Server/Ghost/Roles/GhostRoleSystem.cs +++ b/Content.Server/Ghost/Roles/GhostRoleSystem.cs @@ -1,7 +1,10 @@ +using System.Linq; using Content.Server.Administration.Logs; using Content.Server.EUI; using Content.Server.Ghost.Roles.Components; using Content.Server.Ghost.Roles.Events; +using Content.Server.Ghost.Roles.Raffles; +using Content.Shared.Ghost.Roles.Raffles; using Content.Server.Ghost.Roles.UI; using Content.Server.Mind.Commands; using Content.Shared.Administration; @@ -21,8 +24,14 @@ using Robust.Shared.Console; using Robust.Shared.Enums; using Robust.Shared.Player; +using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Shared.Timing; using Robust.Shared.Utility; +using Content.Server.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Prototypes; +using Robust.Shared.Collections; namespace Content.Server.Ghost.Roles { @@ -37,10 +46,16 @@ namespace Content.Server.Ghost.Roles [Dependency] private readonly TransformSystem _transform = default!; [Dependency] private readonly SharedMindSystem _mindSystem = default!; [Dependency] private readonly SharedRoleSystem _roleSystem = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; private uint _nextRoleIdentifier; private bool _needsUpdateGhostRoleCount = true; + private readonly Dictionary> _ghostRoles = new(); + private readonly Dictionary> _ghostRoleRaffles = new(); + private readonly Dictionary _openUis = new(); private readonly Dictionary _openMakeGhostRoleUis = new(); @@ -57,13 +72,16 @@ public override void Initialize() SubscribeLocalEvent(OnMindRemoved); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnRoleStartup); + SubscribeLocalEvent(OnRoleShutdown); SubscribeLocalEvent(OnPaused); SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnRaffleInit); + SubscribeLocalEvent(OnRaffleShutdown); SubscribeLocalEvent(OnSpawnerTakeRole); SubscribeLocalEvent(OnTakeoverTakeRole); - SubscribeLocalEvent(OnSpawnerTakeCharacter); // DeltaV - Character ghost roles, see Content.Server/DeltaV/Ghost/Roles/GhostRoleSystem.Character.cs + SubscribeLocalEvent>(OnVerb); + SubscribeLocalEvent(OnSpawnerTakeCharacter); _playerManager.PlayerStatusChanged += PlayerStatusChanged; } @@ -75,11 +93,11 @@ private void OnMobStateChanged(Entity component switch (args.NewMobState) { case MobState.Alive: - { - if (!ghostRole.Taken) - RegisterGhostRole((component, ghostRole)); - break; - } + { + if (!ghostRole.Taken) + RegisterGhostRole((component, ghostRole)); + break; + } case MobState.Critical: case MobState.Dead: UnregisterGhostRole((component, ghostRole)); @@ -101,11 +119,11 @@ private uint GetNextRoleIdentifier() public void OpenEui(ICommonSession session) { - if (session.AttachedEntity is not {Valid: true} attached || + if (session.AttachedEntity is not { Valid: true } attached || !EntityManager.HasComponent(attached)) return; - if(_openUis.ContainsKey(session)) + if (_openUis.ContainsKey(session)) CloseEui(session); var eui = _openUis[session] = new GhostRolesEui(); @@ -159,17 +177,118 @@ public void UpdateAllEui() public override void Update(float frameTime) { base.Update(frameTime); - if (_needsUpdateGhostRoleCount) + + UpdateGhostRoleCount(); + UpdateRaffles(frameTime); + } + + /// + /// Handles sending count update for the ghost role button in ghost UI, if ghost role count changed. + /// + private void UpdateGhostRoleCount() + { + if (!_needsUpdateGhostRoleCount) + return; + + _needsUpdateGhostRoleCount = false; + var response = new GhostUpdateGhostRoleCountEvent(GetGhostRoleCount()); + foreach (var player in _playerManager.Sessions) + { + RaiseNetworkEvent(response, player.Channel); + } + } + + /// + /// Handles ghost role raffle logic. + /// + private void UpdateRaffles(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var entityUid, out var raffle, out var meta)) { - _needsUpdateGhostRoleCount = false; - var response = new GhostUpdateGhostRoleCountEvent(GetGhostRolesInfo().Length); - foreach (var player in _playerManager.Sessions) + if (meta.EntityPaused) + continue; + + // if all participants leave/were removed from the raffle, the raffle is canceled. + if (raffle.CurrentMembers.Count == 0) { - RaiseNetworkEvent(response, player.Channel); + RemoveRaffleAndUpdateEui(entityUid, raffle); + continue; } + + raffle.Countdown = raffle.Countdown.Subtract(TimeSpan.FromSeconds(frameTime)); + if (raffle.Countdown.Ticks > 0) + continue; + + // the raffle is over! find someone to take over the ghost role + if (!TryComp(entityUid, out GhostRoleComponent? ghostRole)) + { + Log.Warning($"Ghost role raffle finished on {entityUid} but {nameof(GhostRoleComponent)} is missing"); + RemoveRaffleAndUpdateEui(entityUid, raffle); + continue; + } + + if (ghostRole.RaffleConfig is null) + { + Log.Warning($"Ghost role raffle finished on {entityUid} but RaffleConfig became null"); + RemoveRaffleAndUpdateEui(entityUid, raffle); + continue; + } + + var foundWinner = false; + var deciderPrototype = _prototype.Index(ghostRole.RaffleConfig.Decider); + + // use the ghost role's chosen winner picker to find a winner + deciderPrototype.Decider.PickWinner( + raffle.CurrentMembers.AsEnumerable(), + session => + { + var success = TryTakeover(session, raffle.Identifier); + foundWinner |= success; + return success; + } + ); + + if (!foundWinner) + { + Log.Warning($"Ghost role raffle for {entityUid} ({ghostRole.RoleName}) finished without " + + $"{ghostRole.RaffleConfig?.Decider} finding a winner"); + } + + // raffle over + RemoveRaffleAndUpdateEui(entityUid, raffle); } } + private bool TryTakeover(ICommonSession player, uint identifier) + { + // TODO: the following two checks are kind of redundant since they should already be removed + // from the raffle + // can't win if you are disconnected (although you shouldn't be a candidate anyway) + if (player.Status != SessionStatus.InGame) + return false; + + // can't win if you are no longer a ghost (e.g. if you returned to your body) + if (player.AttachedEntity == null || !HasComp(player.AttachedEntity)) + return false; + + if (Takeover(player, identifier)) + { + // takeover successful, we have a winner! remove the winner from other raffles they might be in + LeaveAllRaffles(player); + return true; + } + + return false; + } + + private void RemoveRaffleAndUpdateEui(EntityUid entityUid, GhostRoleRaffleComponent raffle) + { + _ghostRoleRaffles.Remove(raffle.Identifier); + RemComp(entityUid, raffle); + UpdateAllEui(); + } + private void PlayerStatusChanged(object? blah, SessionStatusEventArgs args) { if (args.NewStatus == SessionStatus.InGame) @@ -177,6 +296,11 @@ private void PlayerStatusChanged(object? blah, SessionStatusEventArgs args) var response = new GhostUpdateGhostRoleCountEvent(_ghostRoles.Count); RaiseNetworkEvent(response, args.Session.Channel); } + else + { + // people who disconnect are removed from ghost role raffles + LeaveAllRaffles(args.Session); + } } public void RegisterGhostRole(Entity role) @@ -195,24 +319,170 @@ public void UnregisterGhostRole(Entity role) return; _ghostRoles.Remove(comp.Identifier); + if (TryComp(role.Owner, out GhostRoleRaffleComponent? raffle)) + { + // if a raffle is still running, get rid of it + RemoveRaffleAndUpdateEui(role.Owner, raffle); + } + else + { + UpdateAllEui(); + } + } + + // probably fine to be init because it's never added during entity initialization, but much later + private void OnRaffleInit(Entity ent, ref ComponentInit args) + { + if (!TryComp(ent, out GhostRoleComponent? ghostRole)) + { + // can't have a raffle for a ghost role that doesn't exist + RemComp(ent); + return; + } + + var config = ghostRole.RaffleConfig; + if (config is null) + return; // should, realistically, never be reached but you never know + + var settings = config.SettingsOverride + ?? _prototype.Index(config.Settings).Settings; + + if (settings.MaxDuration < settings.InitialDuration) + { + Log.Error($"Ghost role on {ent} has invalid raffle settings (max duration shorter than initial)"); + ghostRole.RaffleConfig = null; // make it a non-raffle role so stuff isn't entirely broken + RemComp(ent); + return; + } + + var raffle = ent.Comp; + raffle.Identifier = ghostRole.Identifier; + raffle.Countdown = TimeSpan.FromSeconds(settings.InitialDuration); + raffle.CumulativeTime = TimeSpan.FromSeconds(settings.InitialDuration); + // we copy these settings into the component because they would be cumbersome to access otherwise + raffle.JoinExtendsDurationBy = TimeSpan.FromSeconds(settings.JoinExtendsDurationBy); + raffle.MaxDuration = TimeSpan.FromSeconds(settings.MaxDuration); + } + + private void OnRaffleShutdown(Entity ent, ref ComponentShutdown args) + { + _ghostRoleRaffles.Remove(ent.Comp.Identifier); + } + + /// + /// Joins the given player onto a ghost role raffle, or creates it if it doesn't exist. + /// + /// The player. + /// The ID that represents the ghost role or ghost role raffle. + /// (A raffle will have the same ID as the ghost role it's for.) + private void JoinRaffle(ICommonSession player, uint identifier) + { + if (!_ghostRoles.TryGetValue(identifier, out var roleEnt)) + return; + + // get raffle or create a new one if it doesn't exist + var raffle = _ghostRoleRaffles.TryGetValue(identifier, out var raffleEnt) + ? raffleEnt.Comp + : EnsureComp(roleEnt.Owner); + + _ghostRoleRaffles.TryAdd(identifier, (roleEnt.Owner, raffle)); + + if (!raffle.CurrentMembers.Add(player)) + { + Log.Warning($"{player.Name} tried to join raffle for ghost role {identifier} but they are already in the raffle"); + return; + } + + // if this is the first time the player joins this raffle, and the player wasn't the starter of the raffle: + // extend the countdown, but only if doing so will not make the raffle take longer than the maximum + // duration + if (raffle.AllMembers.Add(player) && raffle.AllMembers.Count > 1 + && raffle.CumulativeTime.Add(raffle.JoinExtendsDurationBy) <= raffle.MaxDuration) + { + raffle.Countdown += raffle.JoinExtendsDurationBy; + raffle.CumulativeTime += raffle.JoinExtendsDurationBy; + } + UpdateAllEui(); } - public void Takeover(ICommonSession player, uint identifier) + /// + /// Makes the given player leave the raffle corresponding to the given ID. + /// + public void LeaveRaffle(ICommonSession player, uint identifier) { - if (!_ghostRoles.TryGetValue(identifier, out var role)) + if (!_ghostRoleRaffles.TryGetValue(identifier, out var raffleEnt)) return; + if (raffleEnt.Comp.CurrentMembers.Remove(player)) + { + UpdateAllEui(); + } + else + { + Log.Warning($"{player.Name} tried to leave raffle for ghost role {identifier} but they are not in the raffle"); + } + + // (raffle ending because all players left is handled in update()) + } + + /// + /// Makes the given player leave all ghost role raffles. + /// + public void LeaveAllRaffles(ICommonSession player) + { + var shouldUpdateEui = false; + + foreach (var raffleEnt in _ghostRoleRaffles.Values) + { + shouldUpdateEui |= raffleEnt.Comp.CurrentMembers.Remove(player); + } + + if (shouldUpdateEui) + UpdateAllEui(); + } + + /// + /// Request a ghost role. If it's a raffled role starts or joins a raffle, otherwise the player immediately + /// takes over the ghost role if possible. + /// + /// The player. + /// ID of the ghost role. + public void Request(ICommonSession player, uint identifier) + { + if (!_ghostRoles.TryGetValue(identifier, out var roleEnt)) + return; + + if (roleEnt.Comp.RaffleConfig is not null) + { + JoinRaffle(player, identifier); + } + else + { + Takeover(player, identifier); + } + } + + /// + /// Attempts having the player take over the ghost role with the corresponding ID. Does not start a raffle. + /// + /// True if takeover was successful, otherwise false. + public bool Takeover(ICommonSession player, uint identifier) + { + if (!_ghostRoles.TryGetValue(identifier, out var role)) + return false; + var ev = new TakeGhostRoleEvent(player); RaiseLocalEvent(role, ref ev); if (!ev.TookRole) - return; + return false; if (player.AttachedEntity != null) _adminLogger.Add(LogType.GhostRoleTaken, LogImpact.Low, $"{player:player} took the {role.Comp.RoleName:roleName} ghost role {ToPrettyString(player.AttachedEntity.Value):entity}"); CloseEui(player); + return true; } public void Follow(ICommonSession player, uint identifier) @@ -241,7 +511,22 @@ public void GhostRoleInternalCreateMindAndTransfer(ICommonSession player, Entity _mindSystem.TransferTo(newMind, mob); } - public GhostRoleInfo[] GetGhostRolesInfo() + /// + /// Returns the number of available ghost roles. + /// + public int GetGhostRoleCount() + { + var metaQuery = GetEntityQuery(); + return _ghostRoles.Count(pair => metaQuery.GetComponent(pair.Value.Owner).EntityPaused == false); + } + + /// + /// Returns information about all available ghost roles. + /// + /// + /// If not null, the s will show if the given player is in a raffle. + /// + public GhostRoleInfo[] GetGhostRolesInfo(ICommonSession? player) { var roles = new List(); var metaQuery = GetEntityQuery(); @@ -251,7 +536,40 @@ public GhostRoleInfo[] GetGhostRolesInfo() if (metaQuery.GetComponent(uid).EntityPaused) continue; - roles.Add(new GhostRoleInfo {Identifier = id, Name = role.RoleName, Description = role.RoleDescription, Rules = role.RoleRules, Requirements = role.Requirements}); + + var kind = GhostRoleKind.FirstComeFirstServe; + GhostRoleRaffleComponent? raffle = null; + + if (role.RaffleConfig is not null) + { + kind = GhostRoleKind.RaffleReady; + + if (_ghostRoleRaffles.TryGetValue(id, out var raffleEnt)) + { + kind = GhostRoleKind.RaffleInProgress; + raffle = raffleEnt.Comp; + + if (player is not null && raffle.CurrentMembers.Contains(player)) + kind = GhostRoleKind.RaffleJoined; + } + } + + var rafflePlayerCount = (uint?) raffle?.CurrentMembers.Count ?? 0; + var raffleEndTime = raffle is not null + ? _timing.CurTime.Add(raffle.Countdown) + : TimeSpan.MinValue; + + roles.Add(new GhostRoleInfo + { + Identifier = id, + Name = role.RoleName, + Description = role.RoleDescription, + Rules = role.RoleRules, + Requirements = role.Requirements, + Kind = kind, + RafflePlayerCount = rafflePlayerCount, + RaffleEndTime = raffleEndTime + }); } return roles.ToArray(); @@ -266,6 +584,10 @@ private void OnPlayerAttached(PlayerAttachedEvent message) if (HasComp(message.Entity)) return; + // The player is not a ghost (anymore), so they should not be in any raffles. Remove them. + // This ensures player doesn't win a raffle after returning to their (revived) body and ends up being + // forced into a ghost role. + LeaveAllRaffles(message.Player); CloseEui(message.Player); } @@ -300,6 +622,7 @@ public void Reset(RoundRestartCleanupEvent ev) _openUis.Clear(); _ghostRoles.Clear(); + _ghostRoleRaffles.Clear(); _nextRoleIdentifier = 0; } @@ -325,12 +648,12 @@ private void OnMapInit(Entity ent, ref MapInitEvent args) RemCompDeferred(ent); } - private void OnStartup(Entity ent, ref ComponentStartup args) + private void OnRoleStartup(Entity ent, ref ComponentStartup args) { RegisterGhostRole(ent); } - private void OnShutdown(Entity role, ref ComponentShutdown args) + private void OnRoleShutdown(Entity role, ref ComponentShutdown args) { UnregisterGhostRole(role); } @@ -408,6 +731,63 @@ private void OnTakeoverTakeRole(EntityUid uid, GhostTakeoverAvailableComponent c args.TookRole = true; } + + private void OnVerb(EntityUid uid, GhostRoleMobSpawnerComponent component, GetVerbsEvent args) + { + var prototypes = component.SelectablePrototypes; + if (prototypes.Count < 1) + return; + + if (!args.CanAccess || !args.CanInteract || args.Hands == null) + return; + + var verbs = new ValueList(); + + foreach (var prototypeID in prototypes) + { + if (_prototype.TryIndex(prototypeID, out var prototype)) + { + var verb = CreateVerb(uid, component, args.User, prototype); + verbs.Add(verb); + } + } + + args.Verbs.UnionWith(verbs); + } + + private Verb CreateVerb(EntityUid uid, GhostRoleMobSpawnerComponent component, EntityUid userUid, GhostRolePrototype prototype) + { + var verbText = Loc.GetString(prototype.Name); + + return new Verb() + { + Text = verbText, + Disabled = component.Prototype == prototype.EntityPrototype, + Category = VerbCategory.SelectType, + Act = () => SetMode(uid, prototype, verbText, component, userUid) + }; + } + + public void SetMode(EntityUid uid, GhostRolePrototype prototype, string verbText, GhostRoleMobSpawnerComponent? component, EntityUid? userUid = null) + { + if (!Resolve(uid, ref component)) + return; + + var ghostrolecomp = EnsureComp(uid); + + component.Prototype = prototype.EntityPrototype; + ghostrolecomp.RoleName = verbText; + ghostrolecomp.RoleDescription = prototype.Description; + ghostrolecomp.RoleRules = prototype.Rules; + + // Dirty(ghostrolecomp); + + if (userUid != null) + { + var msg = Loc.GetString("ghostrole-spawner-select", ("mode", verbText)); + _popupSystem.PopupEntity(msg, uid, userUid.Value); + } + } } [AnyCommand] @@ -418,7 +798,7 @@ public sealed class GhostRoles : IConsoleCommand public string Help => $"{Command}"; public void Execute(IConsoleShell shell, string argStr, string[] args) { - if(shell.Player != null) + if (shell.Player != null) EntitySystem.Get().OpenEui(shell.Player); else shell.WriteLine("You can only open the ghost roles UI on a client."); diff --git a/Content.Server/Ghost/Roles/MakeRaffledGhostRoleCommand.cs b/Content.Server/Ghost/Roles/MakeRaffledGhostRoleCommand.cs new file mode 100644 index 00000000000..5f5eabdad40 --- /dev/null +++ b/Content.Server/Ghost/Roles/MakeRaffledGhostRoleCommand.cs @@ -0,0 +1,127 @@ +using System.Linq; +using Content.Server.Administration; +using Content.Server.Ghost.Roles.Components; +using Content.Server.Ghost.Roles.Raffles; +using Content.Shared.Administration; +using Content.Shared.Ghost.Roles.Raffles; +using Content.Shared.Mind.Components; +using Robust.Shared.Console; +using Robust.Shared.Prototypes; + +namespace Content.Server.Ghost.Roles +{ + [AdminCommand(AdminFlags.Admin)] + public sealed class MakeRaffledGhostRoleCommand : IConsoleCommand + { + [Dependency] private readonly IPrototypeManager _protoManager = default!; + [Dependency] private readonly IEntityManager _entManager = default!; + + public string Command => "makeghostroleraffled"; + public string Description => "Turns an entity into a raffled ghost role."; + public string Help => $"Usage: {Command} ( | ) []\n" + + $"Durations are in seconds."; + + public void Execute(IConsoleShell shell, string argStr, string[] args) + { + if (args.Length is < 4 or > 7) + { + shell.WriteLine($"Invalid amount of arguments.\n{Help}"); + return; + } + + if (!NetEntity.TryParse(args[0], out var uidNet) || !_entManager.TryGetEntity(uidNet, out var uid)) + { + shell.WriteLine($"{args[0]} is not a valid entity uid."); + return; + } + + if (!_entManager.TryGetComponent(uid, out MetaDataComponent? metaData)) + { + shell.WriteLine($"No entity found with uid {uid}"); + return; + } + + if (_entManager.TryGetComponent(uid, out MindContainerComponent? mind) && + mind.HasMind) + { + shell.WriteLine($"Entity {metaData.EntityName} with id {uid} already has a mind."); + return; + } + + if (_entManager.TryGetComponent(uid, out GhostRoleComponent? ghostRole)) + { + shell.WriteLine($"Entity {metaData.EntityName} with id {uid} already has a {nameof(GhostRoleComponent)}"); + return; + } + + if (_entManager.HasComponent(uid)) + { + shell.WriteLine($"Entity {metaData.EntityName} with id {uid} already has a {nameof(GhostTakeoverAvailableComponent)}"); + return; + } + + var name = args[1]; + var description = args[2]; + + // if the rules are specified then use those, otherwise use the default + var rules = args.Length switch + { + 5 => args[4], + 7 => args[6], + _ => Loc.GetString("ghost-role-component-default-rules"), + }; + + // is it an invocation with a prototype ID and optional rules? + var isProto = args.Length is 4 or 5; + GhostRoleRaffleSettings settings; + + if (isProto) + { + if (!_protoManager.TryIndex(args[4], out var proto)) + { + var validProtos = string.Join(", ", + _protoManager.EnumeratePrototypes().Select(p => p.ID) + ); + + shell.WriteLine($"{args[4]} is not a valid raffle settings prototype. Valid options: {validProtos}"); + return; + } + + settings = proto.Settings; + } + else + { + if (!uint.TryParse(args[3], out var initial) + || !uint.TryParse(args[4], out var extends) + || !uint.TryParse(args[5], out var max) + || initial == 0 || max == 0) + { + shell.WriteLine($"The raffle initial/extends/max settings must be positive numbers."); + return; + } + + if (initial > max) + { + shell.WriteLine("The initial duration must be smaller than or equal to the maximum duration."); + return; + } + + settings = new GhostRoleRaffleSettings() + { + InitialDuration = initial, + JoinExtendsDurationBy = extends, + MaxDuration = max + }; + } + + ghostRole = _entManager.AddComponent(uid.Value); + _entManager.AddComponent(uid.Value); + ghostRole.RoleName = name; + ghostRole.RoleDescription = description; + ghostRole.RoleRules = rules; + ghostRole.RaffleConfig = new GhostRoleRaffleConfig(settings); + + shell.WriteLine($"Made entity {metaData.EntityName} a raffled ghost role."); + } + } +} diff --git a/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleConfig.cs b/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleConfig.cs new file mode 100644 index 00000000000..052704df250 --- /dev/null +++ b/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleConfig.cs @@ -0,0 +1,35 @@ +using Content.Shared.Ghost.Roles.Raffles; +using Robust.Shared.Prototypes; + +namespace Content.Server.Ghost.Roles.Raffles; + +/// +/// Raffle configuration. +/// +[DataDefinition] +public sealed partial class GhostRoleRaffleConfig +{ + public GhostRoleRaffleConfig(GhostRoleRaffleSettings settings) + { + SettingsOverride = settings; + } + + /// + /// Specifies the raffle settings to use. + /// + [DataField("settings", required: true)] + public ProtoId Settings { get; set; } = "default"; + + /// + /// If not null, the settings from are ignored and these settings are used instead. + /// Intended for allowing admins to set custom raffle settings for admeme ghost roles. + /// + [ViewVariables(VVAccess.ReadOnly)] + public GhostRoleRaffleSettings? SettingsOverride { get; set; } + + /// + /// Sets which is used. + /// + [DataField("decider")] + public ProtoId Decider { get; set; } = "default"; +} diff --git a/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleDeciderPrototype.cs b/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleDeciderPrototype.cs new file mode 100644 index 00000000000..b2ebf6ca5fc --- /dev/null +++ b/Content.Server/Ghost/Roles/Raffles/GhostRoleRaffleDeciderPrototype.cs @@ -0,0 +1,20 @@ +using Robust.Shared.Prototypes; + +namespace Content.Server.Ghost.Roles.Raffles; + +/// +/// Allows getting a as prototype. +/// +[Prototype("ghostRoleRaffleDecider")] +public sealed class GhostRoleRaffleDeciderPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The instance that chooses the winner of a raffle. + /// + [DataField("decider", required: true)] + public IGhostRoleRaffleDecider Decider { get; private set; } = new RngGhostRoleRaffleDecider(); +} diff --git a/Content.Server/Ghost/Roles/Raffles/IGhostRoleRaffleDecider.cs b/Content.Server/Ghost/Roles/Raffles/IGhostRoleRaffleDecider.cs new file mode 100644 index 00000000000..bdd2bf046da --- /dev/null +++ b/Content.Server/Ghost/Roles/Raffles/IGhostRoleRaffleDecider.cs @@ -0,0 +1,28 @@ +using Robust.Shared.Player; + +namespace Content.Server.Ghost.Roles.Raffles; + +/// +/// Chooses a winner of a ghost role raffle. +/// +[ImplicitDataDefinitionForInheritors] +public partial interface IGhostRoleRaffleDecider +{ + /// + /// Chooses a winner of a ghost role raffle draw from the given pool of candidates. + /// + /// The players in the session at the time of drawing. + /// + /// Call this with the chosen winner as argument. + ///
  • If true is returned, your winner was able to take over the ghost role, and the drawing is complete. + /// Do not call again after true is returned.
  • + ///
  • If false is returned, your winner was not able to take over the ghost role, + /// and you must choose another winner, and call with the new winner as argument.
  • + ///
+ /// + /// If is not called, or only returns false, the raffle will end without a winner. + /// Do not call with the same player several times. + /// + void PickWinner(IEnumerable candidates, Func tryTakeover); +} + diff --git a/Content.Server/Ghost/Roles/Raffles/RngGhostRoleRaffleDecider.cs b/Content.Server/Ghost/Roles/Raffles/RngGhostRoleRaffleDecider.cs new file mode 100644 index 00000000000..b91d359935e --- /dev/null +++ b/Content.Server/Ghost/Roles/Raffles/RngGhostRoleRaffleDecider.cs @@ -0,0 +1,27 @@ +using System.Linq; +using JetBrains.Annotations; +using Robust.Shared.Player; +using Robust.Shared.Random; + +namespace Content.Server.Ghost.Roles.Raffles; + +/// +/// Chooses the winner of a ghost role raffle entirely randomly, without any weighting. +/// +[UsedImplicitly(ImplicitUseTargetFlags.WithMembers)] +public sealed partial class RngGhostRoleRaffleDecider : IGhostRoleRaffleDecider +{ + public void PickWinner(IEnumerable candidates, Func tryTakeover) + { + var random = IoCManager.Resolve(); + + var choices = candidates.ToList(); + random.Shuffle(choices); // shuffle the list so we can pick a lucky winner! + + foreach (var candidate in choices) + { + if (tryTakeover(candidate)) + return; + } + } +} diff --git a/Content.Server/Ghost/Roles/UI/GhostRolesEui.cs b/Content.Server/Ghost/Roles/UI/GhostRolesEui.cs index 627231db9e3..fc73fc3454d 100644 --- a/Content.Server/Ghost/Roles/UI/GhostRolesEui.cs +++ b/Content.Server/Ghost/Roles/UI/GhostRolesEui.cs @@ -6,9 +6,16 @@ namespace Content.Server.Ghost.Roles.UI { public sealed class GhostRolesEui : BaseEui { + [Dependency] private readonly GhostRoleSystem _ghostRoleSystem; + + public GhostRolesEui() + { + _ghostRoleSystem = IoCManager.Resolve().GetEntitySystem(); + } + public override GhostRolesEuiState GetNewState() { - return new(EntitySystem.Get().GetGhostRolesInfo()); + return new(_ghostRoleSystem.GetGhostRolesInfo(Player)); } public override void HandleMessage(EuiMessageBase msg) @@ -17,11 +24,14 @@ public override void HandleMessage(EuiMessageBase msg) switch (msg) { - case GhostRoleTakeoverRequestMessage req: - EntitySystem.Get().Takeover(Player, req.Identifier); + case RequestGhostRoleMessage req: + _ghostRoleSystem.Request(Player, req.Identifier); + break; + case FollowGhostRoleMessage req: + _ghostRoleSystem.Follow(Player, req.Identifier); break; - case GhostRoleFollowRequestMessage req: - EntitySystem.Get().Follow(Player, req.Identifier); + case LeaveGhostRoleRaffleMessage req: + _ghostRoleSystem.LeaveRaffle(Player, req.Identifier); break; } } diff --git a/Content.Server/Gravity/GravityGeneratorSystem.cs b/Content.Server/Gravity/GravityGeneratorSystem.cs index b1696e6a713..dc31c004c64 100644 --- a/Content.Server/Gravity/GravityGeneratorSystem.cs +++ b/Content.Server/Gravity/GravityGeneratorSystem.cs @@ -136,13 +136,13 @@ public override void Update(float frameTime) } private void SetSwitchedOn(EntityUid uid, GravityGeneratorComponent component, bool on, - ApcPowerReceiverComponent? powerReceiver = null, ICommonSession? session = null) + ApcPowerReceiverComponent? powerReceiver = null, EntityUid? user = null) { if (!Resolve(uid, ref powerReceiver)) return; - if (session is { AttachedEntity: { } }) - _adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{session:player} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}"); + if (user != null) + _adminLogger.Add(LogType.Action, on ? LogImpact.Medium : LogImpact.High, $"{ToPrettyString(user)} set ${ToPrettyString(uid):target} to {(on ? "on" : "off")}"); component.SwitchedOn = on; UpdatePowerState(component, powerReceiver); @@ -159,7 +159,7 @@ private static void UpdatePowerState( private void UpdateUI(Entity ent, float chargeRate) { var (_, component, powerReceiver) = ent; - if (!_uiSystem.IsUiOpen(ent, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key)) + if (!_uiSystem.IsUiOpen(ent.Owner, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key)) return; var chargeTarget = chargeRate < 0 ? 0 : component.MaxCharge; @@ -194,8 +194,8 @@ private void UpdateUI(Entity ent, ref ComponentInit private void OnInteractHand(EntityUid uid, GravityGeneratorComponent component, InteractHandEvent args) { - if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor)) - return; - ApcPowerReceiverComponent? powerReceiver = default!; if (!Resolve(uid, ref powerReceiver)) return; @@ -225,7 +222,7 @@ private void OnInteractHand(EntityUid uid, GravityGeneratorComponent component, if (!component.Intact || powerReceiver.PowerReceived < component.IdlePowerUse) return; - _uiSystem.TryOpen(uid, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key, actor.PlayerSession); + _uiSystem.OpenUi(uid, SharedGravityGeneratorComponent.GravityGeneratorUiKey.Key, args.User); component.NeedUIUpdate = true; } @@ -298,7 +295,7 @@ private void OnSwitchGenerator( GravityGeneratorComponent component, SharedGravityGeneratorComponent.SwitchGeneratorMessage args) { - SetSwitchedOn(uid, component, args.On, session:args.Session); + SetSwitchedOn(uid, component, args.On, user: args.Actor); } private void OnEmpPulse(EntityUid uid, GravityGeneratorComponent component, EmpPulseEvent args) diff --git a/Content.Server/GridPreloader/GridPreloaderComponent.cs b/Content.Server/GridPreloader/GridPreloaderComponent.cs new file mode 100644 index 00000000000..9ff31927d0b --- /dev/null +++ b/Content.Server/GridPreloader/GridPreloaderComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.GridPreloader.Prototypes; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.Server.GridPreloader; + +/// +/// Component storing data about preloaded grids and their location +/// Goes on the map entity +/// +[RegisterComponent, Access(typeof(GridPreloaderSystem))] +public sealed partial class GridPreloaderComponent : Component +{ + [DataField] + public Dictionary, List> PreloadedGrids = new(); +} diff --git a/Content.Server/GridPreloader/GridPreloaderSystem.cs b/Content.Server/GridPreloader/GridPreloaderSystem.cs new file mode 100644 index 00000000000..569fe54141c --- /dev/null +++ b/Content.Server/GridPreloader/GridPreloaderSystem.cs @@ -0,0 +1,147 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.CCVar; +using Content.Shared.GridPreloader.Prototypes; +using Content.Shared.GridPreloader.Systems; +using Robust.Server.GameObjects; +using Robust.Server.Maps; +using Robust.Shared.Configuration; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; +using System.Numerics; +using Content.Server.GameTicking; +using Content.Shared.GameTicking; +using JetBrains.Annotations; + +namespace Content.Server.GridPreloader; +public sealed class GridPreloaderSystem : SharedGridPreloaderSystem +{ + [Dependency] private readonly IConfigurationManager _cfg = default!; + [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly MapLoaderSystem _mapLoader = default!; + [Dependency] private readonly MetaDataSystem _meta = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRoundRestart); + SubscribeLocalEvent(OnPostGameMapLoad); + } + + private void OnRoundRestart(RoundRestartCleanupEvent ev) + { + var ent = GetPreloaderEntity(); + if (ent == null) + return; + + Del(ent.Value.Owner); + } + + private void OnPostGameMapLoad(PostGameMapLoad ev) + { + EnsurePreloadedGridMap(); + } + + private void EnsurePreloadedGridMap() + { + // Already have a preloader? + if (GetPreloaderEntity() != null) + return; + + if (!_cfg.GetCVar(CCVars.PreloadGrids)) + return; + + var mapUid = _map.CreateMap(out var mapId, false); + var preloader = EnsureComp(mapUid); + _meta.SetEntityName(mapUid, "GridPreloader Map"); + _map.SetPaused(mapId, true); + + var globalXOffset = 0f; + foreach (var proto in _prototype.EnumeratePrototypes()) + { + for (var i = 0; i < proto.Copies; i++) + { + var options = new MapLoadOptions + { + LoadMap = false, + }; + + if (!_mapLoader.TryLoad(mapId, proto.Path.ToString(), out var roots, options)) + continue; + + // only supports loading maps with one grid. + if (roots.Count != 1) + continue; + + var gridUid = roots[0]; + + // gets grid + also confirms that the root we loaded is actually a grid + if (!TryComp(gridUid, out var mapGrid)) + continue; + + if (!TryComp(gridUid, out var physics)) + continue; + + // Position Calculating + globalXOffset += mapGrid.LocalAABB.Width / 2; + + var coords = new Vector2(-physics.LocalCenter.X + globalXOffset, -physics.LocalCenter.Y); + _transform.SetCoordinates(gridUid, new EntityCoordinates(mapUid, coords)); + + globalXOffset += (mapGrid.LocalAABB.Width / 2) + 1; + + // Add to list + if (!preloader.PreloadedGrids.ContainsKey(proto.ID)) + preloader.PreloadedGrids[proto.ID] = new(); + preloader.PreloadedGrids[proto.ID].Add(gridUid); + } + } + } + + /// + /// Should be a singleton no matter station count, so we can assume 1 + /// (better support for singleton component in engine at some point i guess) + /// + /// + public Entity? GetPreloaderEntity() + { + var query = AllEntityQuery(); + while (query.MoveNext(out var uid, out var comp)) + { + return (uid, comp); + } + + return null; + } + + /// + /// An attempt to get a certain preloaded shuttle. If there are no more such shuttles left, returns null + /// + [PublicAPI] + public bool TryGetPreloadedGrid(ProtoId proto, [NotNullWhen(true)] out EntityUid? preloadedGrid, GridPreloaderComponent? preloader = null) + { + preloadedGrid = null; + + if (preloader == null) + { + preloader = GetPreloaderEntity(); + if (preloader == null) + return false; + } + + if (!preloader.PreloadedGrids.TryGetValue(proto, out var list) || list.Count <= 0) + return false; + + preloadedGrid = list[0]; + + list.RemoveAt(0); + if (list.Count == 0) + preloader.PreloadedGrids.Remove(proto); + + return true; + } +} diff --git a/Content.Server/Hands/Systems/HandsSystem.cs b/Content.Server/Hands/Systems/HandsSystem.cs index bd24ddab5d1..f0a2aee82fa 100644 --- a/Content.Server/Hands/Systems/HandsSystem.cs +++ b/Content.Server/Hands/Systems/HandsSystem.cs @@ -19,6 +19,7 @@ using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; +using Robust.Shared.Random; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -27,6 +28,7 @@ namespace Content.Server.Hands.Systems public sealed class HandsSystem : SharedHandsSystem { [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly StackSystem _stackSystem = default!; [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!; [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!; @@ -90,7 +92,8 @@ private void OnDisarmed(EntityUid uid, HandsComponent component, DisarmedEvent a if (TryComp(uid, out PullerComponent? puller) && TryComp(puller.Pulling, out PullableComponent? pullable)) _pullingSystem.TryStopPull(puller.Pulling.Value, pullable); - if (!_handsSystem.TryDrop(uid, component.ActiveHand!, null, checkActionBlocker: false)) + var offsetRandomCoordinates = _transformSystem.GetMoverCoordinates(args.Target).Offset(_random.NextVector2(1f, 1.5f)); + if (!ThrowHeldItem(args.Target, offsetRandomCoordinates)) return; args.Handled = true; // no shove/stun. diff --git a/Content.Server/HealthExaminable/HealthExaminableComponent.cs b/Content.Server/HealthExaminable/HealthExaminableComponent.cs deleted file mode 100644 index 04053aed70e..00000000000 --- a/Content.Server/HealthExaminable/HealthExaminableComponent.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Content.Shared.Damage.Prototypes; -using Content.Shared.FixedPoint; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; - -namespace Content.Server.HealthExaminable; - -[RegisterComponent, Access(typeof(HealthExaminableSystem))] -public sealed partial class HealthExaminableComponent : Component -{ - // - // The thresholds for determining the examine text for certain amounts of damage. - // These are calculated as a percentage of the entity's critical threshold. - // - public List Thresholds = new() - { FixedPoint2.New(0.10), FixedPoint2.New(0.25), FixedPoint2.New(0.50), FixedPoint2.New(0.75) }; - - [DataField("examinableTypes", required: true, customTypeSerializer:typeof(PrototypeIdHashSetSerializer))] - public HashSet ExaminableTypes = default!; - - /// - /// Health examine text is automatically generated through creating loc string IDs, in the form: - /// `health-examine-[prefix]-[type]-[threshold]` - /// This part determines the prefix. - /// - [DataField("locPrefix")] - public string LocPrefix = "carbon"; -} diff --git a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs index 05a8b062221..06225c9d57c 100644 --- a/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs +++ b/Content.Server/Humanoid/Systems/HumanoidAppearanceSystem.Modifier.cs @@ -32,8 +32,8 @@ private void OnVerbsRequest(EntityUid uid, HumanoidAppearanceComponent component Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Customization/reptilian_parts.rsi"), "tail_smooth"), Act = () => { - _uiSystem.TryOpen(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession); - _uiSystem.TrySetUiState( + _uiSystem.OpenUi(uid, HumanoidMarkingModifierKey.Key, actor.PlayerSession); + _uiSystem.SetUiState( uid, HumanoidMarkingModifierKey.Key, new HumanoidMarkingModifierState(component.MarkingSet, component.Species, @@ -48,8 +48,7 @@ private void OnVerbsRequest(EntityUid uid, HumanoidAppearanceComponent component private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent component, HumanoidMarkingModifierBaseLayersSetMessage message) { - if (message.Session is not { } player - || !_adminManager.HasAdminFlag(player, AdminFlags.Fun)) + if (!_adminManager.HasAdminFlag(message.Actor, AdminFlags.Fun)) { return; } @@ -67,7 +66,7 @@ private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent componen if (message.ResendState) { - _uiSystem.TrySetUiState( + _uiSystem.SetUiState( uid, HumanoidMarkingModifierKey.Key, new HumanoidMarkingModifierState(component.MarkingSet, component.Species, @@ -81,8 +80,7 @@ private void OnBaseLayersSet(EntityUid uid, HumanoidAppearanceComponent componen private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component, HumanoidMarkingModifierMarkingSetMessage message) { - if (message.Session is not { } player - || !_adminManager.HasAdminFlag(player, AdminFlags.Fun)) + if (!_adminManager.HasAdminFlag(message.Actor, AdminFlags.Fun)) { return; } @@ -92,7 +90,7 @@ private void OnMarkingsSet(EntityUid uid, HumanoidAppearanceComponent component, if (message.ResendState) { - _uiSystem.TrySetUiState( + _uiSystem.SetUiState( uid, HumanoidMarkingModifierKey.Key, new HumanoidMarkingModifierState(component.MarkingSet, component.Species, diff --git a/Content.Server/ImmovableRod/ImmovableRodSystem.cs b/Content.Server/ImmovableRod/ImmovableRodSystem.cs index 4553dda095a..f9873b0d6a9 100644 --- a/Content.Server/ImmovableRod/ImmovableRodSystem.cs +++ b/Content.Server/ImmovableRod/ImmovableRodSystem.cs @@ -60,18 +60,21 @@ private void OnMapInit(EntityUid uid, ImmovableRodComponent component, MapInitEv _physics.SetFriction(uid, phys, 0f); _physics.SetBodyStatus(uid, phys, BodyStatus.InAir); - if (!component.RandomizeVelocity) - return; - var xform = Transform(uid); - var vel = component.DirectionOverride.Degrees switch + var (worldPos, worldRot) = _transform.GetWorldPositionRotation(uid); + var vel = worldRot.ToWorldVec() * component.MaxSpeed; + + if (component.RandomizeVelocity) { - 0f => _random.NextVector2(component.MinSpeed, component.MaxSpeed), - _ => _transform.GetWorldRotation(uid).RotateVec(component.DirectionOverride.ToVec()) * _random.NextFloat(component.MinSpeed, component.MaxSpeed) - }; + vel = component.DirectionOverride.Degrees switch + { + 0f => _random.NextVector2(component.MinSpeed, component.MaxSpeed), + _ => worldRot.RotateVec(component.DirectionOverride.ToVec()) * _random.NextFloat(component.MinSpeed, component.MaxSpeed) + }; + } _physics.ApplyLinearImpulse(uid, vel, body: phys); - xform.LocalRotation = (vel - _transform.GetWorldPosition(uid)).ToWorldAngle() + MathHelper.PiOver2; + xform.LocalRotation = (vel - worldPos).ToWorldAngle() + MathHelper.PiOver2; } } diff --git a/Content.Server/Instruments/InstrumentComponent.cs b/Content.Server/Instruments/InstrumentComponent.cs index 1b7913386d2..db9dbb375bc 100644 --- a/Content.Server/Instruments/InstrumentComponent.cs +++ b/Content.Server/Instruments/InstrumentComponent.cs @@ -1,6 +1,7 @@ using Content.Server.UserInterface; using Content.Shared.Instruments; using Robust.Shared.Player; +using ActivatableUIComponent = Content.Shared.UserInterface.ActivatableUIComponent; namespace Content.Server.Instruments; @@ -16,9 +17,9 @@ public sealed partial class InstrumentComponent : SharedInstrumentComponent [ViewVariables] public uint LastSequencerTick = 0; // TODO Instruments: Make this ECS - public ICommonSession? InstrumentPlayer => + public EntityUid? InstrumentPlayer => _entMan.GetComponentOrNull(Owner)?.CurrentSingleUser - ?? _entMan.GetComponentOrNull(Owner)?.PlayerSession; + ?? _entMan.GetComponentOrNull(Owner)?.PlayerSession.AttachedEntity; } [RegisterComponent] diff --git a/Content.Server/Instruments/InstrumentSystem.cs b/Content.Server/Instruments/InstrumentSystem.cs index 8dd9644e3c5..f5a6713886d 100644 --- a/Content.Server/Instruments/InstrumentSystem.cs +++ b/Content.Server/Instruments/InstrumentSystem.cs @@ -111,7 +111,7 @@ private void OnMidiStart(InstrumentStartMidiEvent msg, EntitySessionEventArgs ar if (!TryComp(uid, out InstrumentComponent? instrument)) return; - if (args.SenderSession != instrument.InstrumentPlayer) + if (args.SenderSession.AttachedEntity != instrument.InstrumentPlayer) return; instrument.Playing = true; @@ -125,7 +125,7 @@ private void OnMidiStop(InstrumentStopMidiEvent msg, EntitySessionEventArgs args if (!TryComp(uid, out InstrumentComponent? instrument)) return; - if (args.SenderSession != instrument.InstrumentPlayer) + if (args.SenderSession.AttachedEntity != instrument.InstrumentPlayer) return; Clean(uid, instrument); @@ -142,7 +142,7 @@ private void OnMidiSetMaster(InstrumentSetMasterEvent msg, EntitySessionEventArg if (!TryComp(uid, out InstrumentComponent? instrument)) return; - if (args.SenderSession != instrument.InstrumentPlayer) + if (args.SenderSession.AttachedEntity != instrument.InstrumentPlayer) return; if (master != null) @@ -174,7 +174,7 @@ private void OnMidiSetFilteredChannel(InstrumentSetFilteredChannelEvent msg, Ent if (!TryComp(uid, out InstrumentComponent? instrument)) return; - if (args.SenderSession != instrument.InstrumentPlayer) + if (args.SenderSession.AttachedEntity != instrument.InstrumentPlayer) return; if (msg.Channel == RobustMidiEvent.PercussionChannel && !instrument.AllowPercussion) @@ -194,8 +194,7 @@ private void OnMidiSetFilteredChannel(InstrumentSetFilteredChannelEvent msg, Ent private void OnBoundUIClosed(EntityUid uid, InstrumentComponent component, BoundUIClosedEvent args) { if (HasComp(uid) - && _bui.TryGetUi(uid, args.UiKey, out var bui) - && bui.SubscribedSessions.Count == 0) + && !_bui.IsUiOpen(uid, args.UiKey)) { RemComp(uid); } @@ -232,7 +231,7 @@ private void OnBoundUIRequestBands(EntityUid uid, InstrumentComponent component, var instrumentQuery = EntityManager.GetEntityQuery(); if (!TryComp(uid, out InstrumentComponent? originInstrument) - || originInstrument.InstrumentPlayer?.AttachedEntity is not {} originPlayer) + || originInstrument.InstrumentPlayer is not {} originPlayer) return Array.Empty<(NetEntity, string)>(); // It's probably faster to get all possible active instruments than all entities in range @@ -247,7 +246,7 @@ private void OnBoundUIRequestBands(EntityUid uid, InstrumentComponent component, continue; // We want to use the instrument player's name. - if (instrument.InstrumentPlayer?.AttachedEntity is not {} playerUid) + if (instrument.InstrumentPlayer is not {} playerUid) continue; // Maybe a bit expensive but oh well GetBands is queued and has a timer anyway. @@ -298,7 +297,7 @@ private void OnMidiEventRx(InstrumentMidiEventEvent msg, EntitySessionEventArgs return; if (!instrument.Playing - || args.SenderSession != instrument.InstrumentPlayer + || args.SenderSession.AttachedEntity != instrument.InstrumentPlayer || instrument.InstrumentPlayer == null || args.SenderSession.AttachedEntity is not { } attached) { @@ -374,8 +373,7 @@ public override void Update(float frameTime) var entity = GetEntity(request.Entity); var nearby = GetBands(entity); - _bui.TrySendUiMessage(entity, request.UiKey, new InstrumentBandResponseBuiMessage(nearby), - request.Session); + _bui.ServerSendUiMessage(entity, request.UiKey, new InstrumentBandResponseBuiMessage(nearby), request.Actor); } _bandRequestQueue.Clear(); @@ -413,7 +411,7 @@ public override void Update(float frameTime) (instrument.BatchesDropped >= MaxMidiBatchesDropped || instrument.LaggedBatches >= MaxMidiLaggedBatches)) { - if (instrument.InstrumentPlayer?.AttachedEntity is {Valid: true} mob) + if (instrument.InstrumentPlayer is {Valid: true} mob) { _stuns.TryParalyze(mob, TimeSpan.FromSeconds(1), true); @@ -423,7 +421,7 @@ public override void Update(float frameTime) // Just in case Clean(uid); - _bui.TryCloseAll(uid, InstrumentUiKey.Key); + _bui.CloseUi(uid, InstrumentUiKey.Key); } instrument.Timer += frameTime; @@ -437,13 +435,12 @@ public override void Update(float frameTime) } } - public void ToggleInstrumentUi(EntityUid uid, ICommonSession session, InstrumentComponent? component = null) + public void ToggleInstrumentUi(EntityUid uid, EntityUid actor, InstrumentComponent? component = null) { if (!Resolve(uid, ref component)) return; - if (_bui.TryGetUi(uid, InstrumentUiKey.Key, out var bui)) - _bui.ToggleUi(bui, session); + _bui.TryToggleUi(uid, InstrumentUiKey.Key, actor); } public override bool ResolveInstrument(EntityUid uid, ref SharedInstrumentComponent? component) diff --git a/Content.Server/Interaction/InteractionSystem.cs b/Content.Server/Interaction/InteractionSystem.cs index 203781bcdaa..4eac7e9ef1d 100644 --- a/Content.Server/Interaction/InteractionSystem.cs +++ b/Content.Server/Interaction/InteractionSystem.cs @@ -16,13 +16,6 @@ public sealed partial class InteractionSystem : SharedInteractionSystem [Dependency] private readonly SharedContainerSystem _container = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(HandleUserInterfaceRangeCheck); - } - public override bool CanAccessViaStorage(EntityUid user, EntityUid target) { if (Deleted(target)) @@ -37,26 +30,8 @@ public override bool CanAccessViaStorage(EntityUid user, EntityUid target) if (storage.Container?.ID != container.ID) return false; - if (!TryComp(user, out ActorComponent? actor)) - return false; - // we don't check if the user can access the storage entity itself. This should be handed by the UI system. - return _uiSystem.SessionHasOpenUi(container.Owner, StorageComponent.StorageUiKey.Key, actor.PlayerSession); - } - - private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev) - { - if (ev.Player.AttachedEntity is not { } user || ev.Result == BoundUserInterfaceRangeResult.Fail) - return; - - if (InRangeUnobstructed(user, ev.Target, ev.UserInterface.InteractionRange)) - { - ev.Result = BoundUserInterfaceRangeResult.Pass; - } - else - { - ev.Result = BoundUserInterfaceRangeResult.Fail; - } + return _uiSystem.IsUiOpen(container.Owner, StorageComponent.StorageUiKey.Key, user); } } } diff --git a/Content.Server/Inventory/ServerInventorySystem.cs b/Content.Server/Inventory/ServerInventorySystem.cs index 29d39f37234..e3783753bbc 100644 --- a/Content.Server/Inventory/ServerInventorySystem.cs +++ b/Content.Server/Inventory/ServerInventorySystem.cs @@ -1,21 +1,15 @@ -using Content.Server.Storage.EntitySystems; using Content.Shared.Explosion; using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; -using Content.Shared.Storage; namespace Content.Server.Inventory { public sealed class ServerInventorySystem : InventorySystem { - [Dependency] private readonly StorageSystem _storageSystem = default!; - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnExploded); - SubscribeNetworkEvent(OnOpenSlotStorage); } private void OnExploded(Entity ent, ref BeforeExplodeEvent args) @@ -29,17 +23,6 @@ private void OnExploded(Entity ent, ref BeforeExplodeEvent a } } - private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev, EntitySessionEventArgs args) - { - if (args.SenderSession.AttachedEntity is not { Valid: true } uid) - return; - - if (TryGetSlotEntity(uid, ev.Slot, out var entityUid) && TryComp(entityUid, out var storageComponent)) - { - _storageSystem.OpenStorageUI(entityUid.Value, uid, storageComponent); - } - } - public void TransferEntityInventories(Entity source, Entity target) { if (!Resolve(source.Owner, ref source.Comp) || !Resolve(target.Owner, ref target.Comp)) diff --git a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs index 3de7051f54d..f9e1ae22416 100644 --- a/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs @@ -81,7 +81,7 @@ public override void Initialize() SubscribeLocalEvent(OnSignalReceived); - SubscribeLocalEvent((u, c, m) => Wzhzhzh(u, c, m.Session.AttachedEntity)); + SubscribeLocalEvent((u, c, m) => Wzhzhzh(u, c, m.Actor)); SubscribeLocalEvent(OnEjectMessage); SubscribeLocalEvent(OnEjectIndex); SubscribeLocalEvent(OnSelectTime); @@ -273,6 +273,9 @@ private void OnSolutionChange(Entity ent, ref SolutionContai private void OnContentUpdate(EntityUid uid, MicrowaveComponent component, ContainerModifiedMessage args) // For some reason ContainerModifiedMessage just can't be used at all with Entity. TODO: replace with Entity syntax once that's possible { + if (component.Storage != args.Container) + return; + UpdateUserInterfaceState(uid, component); } @@ -368,11 +371,7 @@ private void OnSignalReceived(Entity ent, ref SignalReceived public void UpdateUserInterfaceState(EntityUid uid, MicrowaveComponent component) { - var ui = _userInterface.GetUiOrNull(uid, MicrowaveUiKey.Key); - if (ui == null) - return; - - _userInterface.SetUiState(ui, new MicrowaveUpdateUserInterfaceState( + _userInterface.SetUiState(uid, MicrowaveUiKey.Key, new MicrowaveUpdateUserInterfaceState( GetNetEntityArray(component.Storage.ContainedEntities.ToArray()), HasComp(uid), component.CurrentCookTimeButtonIndex, diff --git a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs index aad33fea678..93a15f319d9 100644 --- a/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs +++ b/Content.Server/Kitchen/EntitySystems/ReagentGrinderSystem.cs @@ -130,7 +130,7 @@ public override void Update(float frameTime) _solutionContainersSystem.TryAddSolution(containerSoln.Value, solution); } - _userInterfaceSystem.TrySendUiMessage(uid, ReagentGrinderUiKey.Key, + _userInterfaceSystem.ServerSendUiMessage(uid, ReagentGrinderUiKey.Key, new ReagentGrinderWorkCompleteMessage()); UpdateUiState(uid); @@ -249,7 +249,7 @@ private void UpdateUiState(EntityUid uid) GetNetEntityArray(inputContainer.ContainedEntities.ToArray()), containerSolution?.Contents.ToArray() ); - _userInterfaceSystem.TrySetUiState(uid, ReagentGrinderUiKey.Key, state); + _userInterfaceSystem.SetUiState(uid, ReagentGrinderUiKey.Key, state); } private void OnStartMessage(Entity entity, ref ReagentGrinderStartMessage message) @@ -326,7 +326,7 @@ private void DoWork(EntityUid uid, ReagentGrinderComponent reagentGrinder, Grind reagentGrinder.AudioStream = _audioSystem.PlayPvs(sound, uid, AudioParams.Default.WithPitchScale(1 / reagentGrinder.WorkTimeMultiplier)).Value.Entity; //slightly higher pitched - _userInterfaceSystem.TrySendUiMessage(uid, ReagentGrinderUiKey.Key, + _userInterfaceSystem.ServerSendUiMessage(uid, ReagentGrinderUiKey.Key, new ReagentGrinderWorkStartedMessage(program)); } diff --git a/Content.Server/Labels/Label/Components/HandLabelerComponent.cs b/Content.Server/Labels/Label/Components/HandLabelerComponent.cs deleted file mode 100644 index 6c96cada9e7..00000000000 --- a/Content.Server/Labels/Label/Components/HandLabelerComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Shared.Whitelist; - -namespace Content.Server.Labels.Components -{ - [RegisterComponent] - public sealed partial class HandLabelerComponent : Component - { - [ViewVariables(VVAccess.ReadWrite)] - [DataField("assignedLabel")] - public string AssignedLabel { get; set; } = string.Empty; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxLabelChars")] - public int MaxLabelChars { get; set; } = 50; - - [DataField("whitelist")] - public EntityWhitelist Whitelist = new(); - } -} diff --git a/Content.Server/Labels/Label/HandLabelerSystem.cs b/Content.Server/Labels/Label/HandLabelerSystem.cs index dec7d697590..d52bf260460 100644 --- a/Content.Server/Labels/Label/HandLabelerSystem.cs +++ b/Content.Server/Labels/Label/HandLabelerSystem.cs @@ -1,123 +1,8 @@ -using Content.Server.Labels.Components; -using Content.Server.UserInterface; -using Content.Server.Popups; -using Content.Shared.Administration.Logs; -using Content.Shared.Database; -using Content.Shared.Interaction; -using Content.Shared.Labels; -using Content.Shared.Tag; -using Content.Shared.Verbs; -using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.Player; +using Content.Shared.Labels.EntitySystems; -namespace Content.Server.Labels -{ - /// - /// A hand labeler system that lets an object apply labels to objects with the . - /// - [UsedImplicitly] - public sealed class HandLabelerSystem : EntitySystem - { - [Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!; - [Dependency] private readonly PopupSystem _popupSystem = default!; - [Dependency] private readonly LabelSystem _labelSystem = default!; - [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; - - [ValidatePrototypeId] - private const string PreventTag = "PreventLabel"; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(AfterInteractOn); - SubscribeLocalEvent>(OnUtilityVerb); - // Bound UI subscriptions - SubscribeLocalEvent(OnHandLabelerLabelChanged); - } - - private void OnUtilityVerb(EntityUid uid, HandLabelerComponent handLabeler, GetVerbsEvent args) - { - if (args.Target is not { Valid: true } target || !handLabeler.Whitelist.IsValid(target) || !args.CanAccess - || _tagSystem.HasTag(target, PreventTag)) // DeltaV - Prevent labels on certain items - return; - - string labelerText = handLabeler.AssignedLabel == string.Empty ? Loc.GetString("hand-labeler-remove-label-text") : Loc.GetString("hand-labeler-add-label-text"); - - var verb = new UtilityVerb() - { - Act = () => - { - AddLabelTo(uid, handLabeler, target, out var result); - if (result != null) - _popupSystem.PopupEntity(result, args.User, args.User); - }, - Text = labelerText - }; - - args.Verbs.Add(verb); - } - - private void AfterInteractOn(EntityUid uid, HandLabelerComponent handLabeler, AfterInteractEvent args) - { - if (args.Target is not {Valid: true} target || !handLabeler.Whitelist.IsValid(target) || !args.CanReach - || _tagSystem.HasTag(target, PreventTag)) // DeltaV - Prevent labels on certain items - return; - - AddLabelTo(uid, handLabeler, target, out string? result); - if (result == null) - return; - _popupSystem.PopupEntity(result, args.User, args.User); +namespace Content.Server.Labels.Label; - // Log labeling - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.User):user} labeled {ToPrettyString(target):target} with {ToPrettyString(uid):labeler}"); - } - - private void AddLabelTo(EntityUid uid, HandLabelerComponent? handLabeler, EntityUid target, out string? result) - { - if (!Resolve(uid, ref handLabeler)) - { - result = null; - return; - } - - if (handLabeler.AssignedLabel == string.Empty) - { - _labelSystem.Label(target, null); - result = Loc.GetString("hand-labeler-successfully-removed"); - return; - } - - _labelSystem.Label(target, handLabeler.AssignedLabel); - result = Loc.GetString("hand-labeler-successfully-applied"); - } - - private void OnHandLabelerLabelChanged(EntityUid uid, HandLabelerComponent handLabeler, HandLabelerLabelChangedMessage args) - { - if (args.Session.AttachedEntity is not {Valid: true} player) - return; - - var label = args.Label.Trim(); - handLabeler.AssignedLabel = label.Substring(0, Math.Min(handLabeler.MaxLabelChars, label.Length)); - DirtyUI(uid, handLabeler); - - // Log label change - _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(player):user} set {ToPrettyString(uid):labeler} to apply label \"{handLabeler.AssignedLabel}\""); - - } - - private void DirtyUI(EntityUid uid, - HandLabelerComponent? handLabeler = null) - { - if (!Resolve(uid, ref handLabeler)) - return; +public sealed class HandLabelerSystem : SharedHandLabelerSystem +{ - _userInterfaceSystem.TrySetUiState(uid, HandLabelerUiKey.Key, - new HandLabelerBoundUserInterfaceState(handLabeler.AssignedLabel)); - } - } } diff --git a/Content.Server/Labels/Label/LabelSystem.cs b/Content.Server/Labels/Label/LabelSystem.cs index 52184fb58f2..9d235b488b8 100644 --- a/Content.Server/Labels/Label/LabelSystem.cs +++ b/Content.Server/Labels/Label/LabelSystem.cs @@ -54,7 +54,7 @@ private void OnLabelCompMapInit(EntityUid uid, LabelComponent component, MapInit /// intended label text (null to remove) /// label component for resolve /// metadata component for resolve - public void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null) + public override void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null) { if (!Resolve(uid, ref metadata)) return; diff --git a/Content.Server/Lathe/LatheSystem.cs b/Content.Server/Lathe/LatheSystem.cs index 06d1b463ec3..7448a9b84dd 100644 --- a/Content.Server/Lathe/LatheSystem.cs +++ b/Content.Server/Lathe/LatheSystem.cs @@ -8,11 +8,13 @@ using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.Stack; +using Content.Shared.Atmos; using Content.Shared.UserInterface; using Content.Shared.Database; using Content.Shared.Emag.Components; using Content.Shared.Lathe; using Content.Shared.Materials; +using Content.Shared.ReagentSpeed; using Content.Shared.Research.Components; using Content.Shared.Research.Prototypes; using JetBrains.Annotations; @@ -34,6 +36,7 @@ public sealed class LatheSystem : SharedLatheSystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly UserInterfaceSystem _uiSys = default!; [Dependency] private readonly MaterialStorageSystem _materialStorage = default!; + [Dependency] private readonly ReagentSpeedSystem _reagentSpeed = default!; [Dependency] private readonly StackSystem _stack = default!; [Dependency] private readonly TransformSystem _transform = default!; @@ -185,9 +188,11 @@ public bool TryStartProducing(EntityUid uid, LatheComponent? component = null) var recipe = component.Queue.First(); component.Queue.RemoveAt(0); + var time = _reagentSpeed.ApplySpeed(uid, recipe.CompleteTime); + var lathe = EnsureComp(uid); lathe.StartTime = _timing.CurTime; - lathe.ProductionLength = recipe.CompleteTime * component.TimeMultiplier; + lathe.ProductionLength = time * component.TimeMultiplier; component.CurrentRecipe = recipe; var ev = new LatheStartPrintingEvent(recipe); @@ -226,11 +231,10 @@ public void UpdateUserInterfaceState(EntityUid uid, LatheComponent? component = if (!Resolve(uid, ref component)) return; - var ui = _uiSys.GetUi(uid, LatheUiKey.Key); var producing = component.CurrentRecipe ?? component.Queue.FirstOrDefault(); var state = new LatheUpdateState(GetAvailableRecipes(uid, component), component.Queue, producing); - _uiSys.SetUiState(ui, state); + _uiSys.SetUiState(uid, LatheUiKey.Key, state); } private void OnGetRecipes(EntityUid uid, TechnologyDatabaseComponent component, LatheGetRecipesEvent args) @@ -337,10 +341,10 @@ private void OnLatheQueueRecipeMessage(EntityUid uid, LatheComponent component, else break; } - if (count > 0 && args.Session.AttachedEntity != null) + if (count > 0) { _adminLogger.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):player} queued {count} {recipe.Name} at {ToPrettyString(uid):lathe}"); + $"{ToPrettyString(args.Actor):player} queued {count} {recipe.Name} at {ToPrettyString(uid):lathe}"); } } TryStartProducing(uid, component); diff --git a/Content.Server/Light/Components/EmergencyLightComponent.cs b/Content.Server/Light/Components/EmergencyLightComponent.cs index 20de7f1c03b..b49a8c3868a 100644 --- a/Content.Server/Light/Components/EmergencyLightComponent.cs +++ b/Content.Server/Light/Components/EmergencyLightComponent.cs @@ -14,7 +14,7 @@ public sealed partial class EmergencyLightComponent : SharedEmergencyLightCompon /// /// Is this emergency light forced on for some reason and cannot be disabled through normal means - /// (i.e. delta alert level?) + /// (i.e. blue alert or higher?) /// public bool ForciblyEnabled = false; diff --git a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs index 3fa5237948c..f2c4c7dcc59 100644 --- a/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs +++ b/Content.Server/Light/EntitySystems/EmergencyLightSystem.cs @@ -31,9 +31,9 @@ public override void Initialize() SubscribeLocalEvent(OnEmergencyPower); } - private void OnEmergencyPower(EntityUid uid, EmergencyLightComponent component, ref PowerChangedEvent args) + private void OnEmergencyPower(Entity entity, ref PowerChangedEvent args) { - var meta = MetaData(uid); + var meta = MetaData(entity.Owner); // TODO: PowerChangedEvent shouldn't be issued for paused ents but this is the world we live in. if (meta.EntityLifeStage >= EntityLifeStage.Terminating || @@ -42,7 +42,7 @@ private void OnEmergencyPower(EntityUid uid, EmergencyLightComponent component, return; } - UpdateState(uid, component); + UpdateState(entity); } private void OnEmergencyExamine(EntityUid uid, EmergencyLightComponent component, ExaminedEvent args) @@ -111,13 +111,13 @@ private void OnAlertLevelChanged(AlertLevelChangedEvent ev) if (details.ForceEnableEmergencyLights && !light.ForciblyEnabled) { light.ForciblyEnabled = true; - TurnOn(uid, light); + TurnOn((uid, light)); } else if (!details.ForceEnableEmergencyLights && light.ForciblyEnabled) { // Previously forcibly enabled, and we went down an alert level. light.ForciblyEnabled = false; - UpdateState(uid, light); + UpdateState((uid, light)); } } } @@ -135,31 +135,31 @@ public override void Update(float frameTime) var query = EntityQueryEnumerator(); while (query.MoveNext(out var uid, out _, out var emergencyLight, out var battery)) { - Update(uid, emergencyLight, battery, frameTime); + Update((uid, emergencyLight), battery, frameTime); } } - private void Update(EntityUid uid, EmergencyLightComponent component, BatteryComponent battery, float frameTime) + private void Update(Entity entity, BatteryComponent battery, float frameTime) { - if (component.State == EmergencyLightState.On) + if (entity.Comp.State == EmergencyLightState.On) { - if (!_battery.TryUseCharge(uid, component.Wattage * frameTime, battery)) + if (!_battery.TryUseCharge(entity.Owner, entity.Comp.Wattage * frameTime, battery)) { - SetState(uid, component, EmergencyLightState.Empty); - TurnOff(uid, component); + SetState(entity.Owner, entity.Comp, EmergencyLightState.Empty); + TurnOff(entity); } } else { - _battery.SetCharge(uid, battery.CurrentCharge + component.ChargingWattage * frameTime * component.ChargingEfficiency, battery); + _battery.SetCharge(entity.Owner, battery.CurrentCharge + entity.Comp.ChargingWattage * frameTime * entity.Comp.ChargingEfficiency, battery); if (battery.IsFullyCharged) { - if (TryComp(uid, out var receiver)) + if (TryComp(entity.Owner, out var receiver)) { receiver.Load = 1; } - SetState(uid, component, EmergencyLightState.Full); + SetState(entity.Owner, entity.Comp, EmergencyLightState.Full); } } } @@ -167,35 +167,73 @@ private void Update(EntityUid uid, EmergencyLightComponent component, BatteryCom /// /// Updates the light's power drain, battery drain, sprite and actual light state. /// - public void UpdateState(EntityUid uid, EmergencyLightComponent component) + public void UpdateState(Entity entity) { - if (!TryComp(uid, out var receiver)) + if (!TryComp(entity.Owner, out var receiver)) return; - if (receiver.Powered && !component.ForciblyEnabled) + if (!TryComp(_station.GetOwningStation(entity.Owner), out var alerts)) + return; + + if (alerts.AlertLevels == null || !alerts.AlertLevels.Levels.TryGetValue(alerts.CurrentLevel, out var details)) { - receiver.Load = (int) Math.Abs(component.Wattage); - TurnOff(uid, component); - SetState(uid, component, EmergencyLightState.Charging); + TurnOff(entity, Color.Red); // if no alert, default to off red state + return; } - else + + if (receiver.Powered && !entity.Comp.ForciblyEnabled) // Green alert { - TurnOn(uid, component); - SetState(uid, component, EmergencyLightState.On); + receiver.Load = (int) Math.Abs(entity.Comp.Wattage); + TurnOff(entity, details.Color); + SetState(entity.Owner, entity.Comp, EmergencyLightState.Charging); + } + else if (!receiver.Powered) // If internal battery runs out it will end in off red state + { + TurnOn(entity, Color.Red); + SetState(entity.Owner, entity.Comp, EmergencyLightState.On); + } + else // Powered and enabled + { + TurnOn(entity, details.Color); + SetState(entity.Owner, entity.Comp, EmergencyLightState.On); } } - private void TurnOff(EntityUid uid, EmergencyLightComponent component) + private void TurnOff(Entity entity) { - _pointLight.SetEnabled(uid, false); - _appearance.SetData(uid, EmergencyLightVisuals.On, false); - _ambient.SetAmbience(uid, false); + _pointLight.SetEnabled(entity.Owner, false); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.On, false); + _ambient.SetAmbience(entity.Owner, false); } - private void TurnOn(EntityUid uid, EmergencyLightComponent component) + /// + /// Turn off emergency light and set color. + /// + private void TurnOff(Entity entity, Color color) + { + _pointLight.SetEnabled(entity.Owner, false); + _pointLight.SetColor(entity.Owner, color); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.Color, color); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.On, false); + _ambient.SetAmbience(entity.Owner, false); + } + + private void TurnOn(Entity entity) + { + _pointLight.SetEnabled(entity.Owner, true); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.On, true); + _ambient.SetAmbience(entity.Owner, true); + } + + /// + /// Turn on emergency light and set color. + /// + private void TurnOn(Entity entity, Color color) { - _pointLight.SetEnabled(uid, true); - _appearance.SetData(uid, EmergencyLightVisuals.On, true); - _ambient.SetAmbience(uid, true); + _pointLight.SetEnabled(entity.Owner, true); + _pointLight.SetColor(entity.Owner, color); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.Color, color); + _appearance.SetData(entity.Owner, EmergencyLightVisuals.On, true); + _ambient.SetAmbience(entity.Owner, true); } } diff --git a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs b/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs deleted file mode 100644 index a1ed71ee4cd..00000000000 --- a/Content.Server/Light/EntitySystems/UnpoweredFlashlightSystem.cs +++ /dev/null @@ -1,113 +0,0 @@ -using Content.Server.Light.Events; -using Content.Shared.Actions; -using Content.Shared.Decals; -using Content.Shared.Emag.Systems; -using Content.Shared.Light; -using Content.Shared.Light.Components; -using Content.Shared.Mind.Components; -using Content.Shared.Toggleable; -using Content.Shared.Verbs; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Utility; - -namespace Content.Server.Light.EntitySystems -{ - public sealed class UnpoweredFlashlightSystem : EntitySystem - { - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; - [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly SharedAudioSystem _audioSystem = default!; - [Dependency] private readonly SharedPointLightSystem _light = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent>(AddToggleLightVerbs); - SubscribeLocalEvent(OnGetActions); - SubscribeLocalEvent(OnToggleAction); - SubscribeLocalEvent(OnMindAdded); - SubscribeLocalEvent(OnGotEmagged); - SubscribeLocalEvent(OnMapInit); - } - - private void OnMapInit(EntityUid uid, UnpoweredFlashlightComponent component, MapInitEvent args) - { - _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); - Dirty(uid, component); - } - - private void OnToggleAction(EntityUid uid, UnpoweredFlashlightComponent component, ToggleActionEvent args) - { - if (args.Handled) - return; - - ToggleLight(uid, component); - - args.Handled = true; - } - - private void OnGetActions(EntityUid uid, UnpoweredFlashlightComponent component, GetItemActionsEvent args) - { - args.AddAction(ref component.ToggleActionEntity, component.ToggleAction); - } - - private void AddToggleLightVerbs(EntityUid uid, UnpoweredFlashlightComponent component, GetVerbsEvent args) - { - if (!args.CanAccess || !args.CanInteract) - return; - - ActivationVerb verb = new() - { - Text = Loc.GetString("toggle-flashlight-verb-get-data-text"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/light.svg.192dpi.png")), - Act = () => ToggleLight(uid, component), - Priority = -1 // For things like PDA's, Open-UI and other verbs that should be higher priority. - }; - - args.Verbs.Add(verb); - } - - private void OnMindAdded(EntityUid uid, UnpoweredFlashlightComponent component, MindAddedMessage args) - { - _actionsSystem.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction); - } - - private void OnGotEmagged(EntityUid uid, UnpoweredFlashlightComponent component, ref GotEmaggedEvent args) - { - if (!_light.TryGetLight(uid, out var light)) - return; - - if (_prototypeManager.TryIndex(component.EmaggedColorsPrototype, out var possibleColors)) - { - var pick = _random.Pick(possibleColors.Colors.Values); - _light.SetColor(uid, pick, light); - } - - args.Repeatable = true; - args.Handled = true; - } - - public void ToggleLight(EntityUid uid, UnpoweredFlashlightComponent flashlight) - { - if (!_light.TryGetLight(uid, out var light)) - return; - - flashlight.LightOn = !flashlight.LightOn; - _light.SetEnabled(uid, flashlight.LightOn, light); - - _appearance.SetData(uid, UnpoweredFlashlightVisuals.LightOn, flashlight.LightOn); - - _audioSystem.PlayPvs(flashlight.ToggleSound, uid); - - RaiseLocalEvent(uid, new LightToggleEvent(flashlight.LightOn), true); - _actionsSystem.SetToggled(flashlight.ToggleActionEntity, flashlight.LightOn); - } - } -} diff --git a/Content.Server/Light/Events/LightToggleEvent.cs b/Content.Server/Light/Events/LightToggleEvent.cs deleted file mode 100644 index c7e82ce7542..00000000000 --- a/Content.Server/Light/Events/LightToggleEvent.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace Content.Server.Light.Events -{ - public sealed class LightToggleEvent : EntityEventArgs - { - public bool IsOn; - - public LightToggleEvent(bool isOn) - { - IsOn = isOn; - } - } -} diff --git a/Content.Server/Lock/EntitySystems/ActivatableUIRequiresLockSystem.cs b/Content.Server/Lock/EntitySystems/ActivatableUIRequiresLockSystem.cs index dfe398ebafa..04f8e2eb54c 100644 --- a/Content.Server/Lock/EntitySystems/ActivatableUIRequiresLockSystem.cs +++ b/Content.Server/Lock/EntitySystems/ActivatableUIRequiresLockSystem.cs @@ -3,6 +3,7 @@ using Content.Shared.UserInterface; using Content.Shared.Lock; using Content.Server.UserInterface; +using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem; namespace Content.Server.Lock.EntitySystems; public sealed class ActivatableUIRequiresLockSystem : EntitySystem diff --git a/Content.Server/Magic/Components/SpellbookComponent.cs b/Content.Server/Magic/Components/SpellbookComponent.cs deleted file mode 100644 index ebc3c880436..00000000000 --- a/Content.Server/Magic/Components/SpellbookComponent.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; - -namespace Content.Server.Magic.Components; - -/// -/// Spellbooks for having an entity learn spells as long as they've read the book and it's in their hand. -/// -[RegisterComponent] -public sealed partial class SpellbookComponent : Component -{ - /// - /// List of spells that this book has. This is a combination of the WorldSpells, EntitySpells, and InstantSpells. - /// - [ViewVariables] - public readonly List Spells = new(); - - /// - /// The three fields below is just used for initialization. - /// - [DataField("spells", customTypeSerializer: typeof(PrototypeIdDictionarySerializer))] - [ViewVariables(VVAccess.ReadWrite)] - public Dictionary SpellActions = new(); - - [DataField("learnTime")] - [ViewVariables(VVAccess.ReadWrite)] - public float LearnTime = .75f; - - /// - /// If true, the spell action stays even after the book is removed - /// - [DataField("learnPermanently")] - [ViewVariables(VVAccess.ReadWrite)] - public bool LearnPermanently; -} diff --git a/Content.Server/Magic/MagicSystem.cs b/Content.Server/Magic/MagicSystem.cs index 18602c3de8b..c25aada3a07 100644 --- a/Content.Server/Magic/MagicSystem.cs +++ b/Content.Server/Magic/MagicSystem.cs @@ -1,409 +1,23 @@ -using System.Numerics; -using Content.Server.Body.Components; -using Content.Server.Body.Systems; using Content.Server.Chat.Systems; -using Content.Server.Doors.Systems; -using Content.Server.Magic.Components; -using Content.Server.Weapons.Ranged.Systems; -using Content.Shared.Actions; -using Content.Shared.Body.Components; using Content.Shared.Chat; -using Content.Shared.Coordinates.Helpers; -using Content.Shared.DoAfter; -using Content.Shared.Doors.Components; -using Content.Shared.Doors.Systems; -using Content.Shared.Interaction.Events; using Content.Shared.Magic; using Content.Shared.Magic.Events; -using Content.Shared.Maps; -using Content.Shared.Physics; -using Content.Shared.Storage; -using Robust.Server.GameObjects; -using Robust.Shared.Audio; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Map; -using Robust.Shared.Map.Components; -using Robust.Shared.Random; -using Robust.Shared.Serialization.Manager; -using Robust.Shared.Spawners; namespace Content.Server.Magic; -/// -/// Handles learning and using spells (actions) -/// -public sealed class MagicSystem : EntitySystem +public sealed class MagicSystem : SharedMagicSystem { - [Dependency] private readonly ISerializationManager _seriMan = default!; - [Dependency] private readonly IComponentFactory _compFact = default!; - [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly BodySystem _bodySystem = default!; - [Dependency] private readonly EntityLookupSystem _lookup = default!; - [Dependency] private readonly SharedDoorSystem _doorSystem = default!; - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; - [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; - [Dependency] private readonly GunSystem _gunSystem = default!; - [Dependency] private readonly PhysicsSystem _physics = default!; - [Dependency] private readonly SharedTransformSystem _transformSystem = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly ChatSystem _chat = default!; - [Dependency] private readonly ActionContainerSystem _actionContainer = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnInit); - SubscribeLocalEvent(OnUse); - SubscribeLocalEvent(OnDoAfter); - - SubscribeLocalEvent(OnInstantSpawn); - SubscribeLocalEvent(OnTeleportSpell); - SubscribeLocalEvent(OnKnockSpell); - SubscribeLocalEvent(OnSmiteSpell); - SubscribeLocalEvent(OnWorldSpawn); - SubscribeLocalEvent(OnProjectileSpell); - SubscribeLocalEvent(OnChangeComponentsSpell); - } - - private void OnDoAfter(EntityUid uid, SpellbookComponent component, DoAfterEvent args) - { - if (args.Handled || args.Cancelled) - return; - - args.Handled = true; - if (!component.LearnPermanently) - { - _actionsSystem.GrantActions(args.Args.User, component.Spells, uid); - return; - } - - foreach (var (id, charges) in component.SpellActions) - { - // TOOD store spells entity ids on some sort of innate magic user component or something like that. - EntityUid? actionId = null; - if (_actionsSystem.AddAction(args.Args.User, ref actionId, id)) - _actionsSystem.SetCharges(actionId, charges < 0 ? null : charges); - } - - component.SpellActions.Clear(); - } - - private void OnInit(EntityUid uid, SpellbookComponent component, MapInitEvent args) - { - if (component.LearnPermanently) - return; - - foreach (var (id, charges) in component.SpellActions) - { - var spell = _actionContainer.AddAction(uid, id); - if (spell == null) - continue; - - _actionsSystem.SetCharges(spell, charges < 0 ? null : charges); - component.Spells.Add(spell.Value); - } - } - - private void OnUse(EntityUid uid, SpellbookComponent component, UseInHandEvent args) - { - if (args.Handled) - return; - - AttemptLearn(uid, component, args); - - args.Handled = true; - } - - private void AttemptLearn(EntityUid uid, SpellbookComponent component, UseInHandEvent args) - { - var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, component.LearnTime, new SpellbookDoAfterEvent(), uid, target: uid) - { - BreakOnTargetMove = true, - BreakOnUserMove = true, - BreakOnDamage = true, - NeedHand = true //What, are you going to read with your eyes only?? - }; - - _doAfter.TryStartDoAfter(doAfterEventArgs); - } - - #region Spells - - /// - /// Handles the instant action (i.e. on the caster) attempting to spawn an entity. - /// - private void OnInstantSpawn(InstantSpawnSpellEvent args) - { - if (args.Handled) - return; - - var transform = Transform(args.Performer); - - foreach (var position in GetSpawnPositions(transform, args.Pos)) - { - var ent = Spawn(args.Prototype, position.SnapToGrid(EntityManager, _mapManager)); - - if (args.PreventCollideWithCaster) - { - var comp = EnsureComp(ent); - comp.Uid = args.Performer; - } - } - - Speak(args); - args.Handled = true; - } - - private void OnProjectileSpell(ProjectileSpellEvent ev) - { - if (ev.Handled) - return; - - ev.Handled = true; - Speak(ev); - - var xform = Transform(ev.Performer); - var userVelocity = _physics.GetMapLinearVelocity(ev.Performer); - - foreach (var pos in GetSpawnPositions(xform, ev.Pos)) - { - // If applicable, this ensures the projectile is parented to grid on spawn, instead of the map. - var mapPos = pos.ToMap(EntityManager, _transformSystem); - var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _) - ? pos.WithEntityId(gridUid, EntityManager) - : new(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position); - - var ent = Spawn(ev.Prototype, spawnCoords); - var direction = ev.Target.ToMapPos(EntityManager, _transformSystem) - - spawnCoords.ToMapPos(EntityManager, _transformSystem); - _gunSystem.ShootProjectile(ent, direction, userVelocity, ev.Performer, ev.Performer); - } - } - - private void OnChangeComponentsSpell(ChangeComponentsSpellEvent ev) - { - if (ev.Handled) - return; - ev.Handled = true; - Speak(ev); - - foreach (var toRemove in ev.ToRemove) - { - if (_compFact.TryGetRegistration(toRemove, out var registration)) - RemComp(ev.Target, registration.Type); - } - - foreach (var (name, data) in ev.ToAdd) - { - if (HasComp(ev.Target, data.Component.GetType())) - continue; - - var component = (Component) _compFact.GetComponent(name); - component.Owner = ev.Target; - var temp = (object) component; - _seriMan.CopyTo(data.Component, ref temp); - EntityManager.AddComponent(ev.Target, (Component) temp!); - } - } - - private List GetSpawnPositions(TransformComponent casterXform, MagicSpawnData data) - { - switch (data) - { - case TargetCasterPos: - return new List(1) {casterXform.Coordinates}; - case TargetInFront: - { - // This is shit but you get the idea. - var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized()); - - if (!TryComp(casterXform.GridUid, out var mapGrid)) - return new List(); - - if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) - return new List(); - - var tileIndex = tileReference.Value.GridIndices; - var coords = mapGrid.GridTileToLocal(tileIndex); - EntityCoordinates coordsPlus; - EntityCoordinates coordsMinus; - - var dir = casterXform.LocalRotation.GetCardinalDir(); - switch (dir) - { - case Direction.North: - case Direction.South: - { - coordsPlus = mapGrid.GridTileToLocal(tileIndex + (1, 0)); - coordsMinus = mapGrid.GridTileToLocal(tileIndex + (-1, 0)); - return new List(3) - { - coords, - coordsPlus, - coordsMinus, - }; - } - case Direction.East: - case Direction.West: - { - coordsPlus = mapGrid.GridTileToLocal(tileIndex + (0, 1)); - coordsMinus = mapGrid.GridTileToLocal(tileIndex + (0, -1)); - return new List(3) - { - coords, - coordsPlus, - coordsMinus, - }; - } - } - - return new List(); - } - default: - throw new ArgumentOutOfRangeException(); - } - } - - /// - /// Teleports the user to the clicked location - /// - /// - private void OnTeleportSpell(TeleportSpellEvent args) - { - if (args.Handled) - return; - - var transform = Transform(args.Performer); - - if (transform.MapID != args.Target.GetMapId(EntityManager)) return; - - _transformSystem.SetCoordinates(args.Performer, args.Target); - transform.AttachToGridOrMap(); - _audio.PlayPvs(args.BlinkSound, args.Performer, AudioParams.Default.WithVolume(args.BlinkVolume)); - Speak(args); - args.Handled = true; + SubscribeLocalEvent(OnSpellSpoken); } - /// - /// Opens all doors within range - /// - /// - private void OnKnockSpell(KnockSpellEvent args) + private void OnSpellSpoken(ref SpeakSpellEvent args) { - if (args.Handled) - return; - - args.Handled = true; - Speak(args); - - //Get the position of the player - var transform = Transform(args.Performer); - var coords = transform.Coordinates; - - _audio.PlayPvs(args.KnockSound, args.Performer, AudioParams.Default.WithVolume(args.KnockVolume)); - - //Look for doors and don't open them if they're already open. - foreach (var entity in _lookup.GetEntitiesInRange(coords, args.Range)) - { - if (TryComp(entity, out var bolts)) - _doorSystem.SetBoltsDown((entity, bolts), false); - - if (TryComp(entity, out var doorComp) && doorComp.State is not DoorState.Open) - _doorSystem.StartOpening(entity); - } - } - - private void OnSmiteSpell(SmiteSpellEvent ev) - { - if (ev.Handled) - return; - - ev.Handled = true; - Speak(ev); - - var direction = Transform(ev.Target).MapPosition.Position - Transform(ev.Performer).MapPosition.Position; - var impulseVector = direction * 10000; - - _physics.ApplyLinearImpulse(ev.Target, impulseVector); - - if (!TryComp(ev.Target, out var body)) - return; - - var ents = _bodySystem.GibBody(ev.Target, true, body); - - if (!ev.DeleteNonBrainParts) - return; - - foreach (var part in ents) - { - // just leaves a brain and clothes - if (HasComp(part) && !HasComp(part)) - { - QueueDel(part); - } - } - } - - /// - /// Spawns entity prototypes from a list within range of click. - /// - /// - /// It will offset mobs after the first mob based on the OffsetVector2 property supplied. - /// - /// The Spawn Spell Event args. - private void OnWorldSpawn(WorldSpawnSpellEvent args) - { - if (args.Handled) - return; - - var targetMapCoords = args.Target; - - SpawnSpellHelper(args.Contents, targetMapCoords, args.Lifetime, args.Offset); - Speak(args); - args.Handled = true; - } - - /// - /// Loops through a supplied list of entity prototypes and spawns them - /// - /// - /// If an offset of 0, 0 is supplied then the entities will all spawn on the same tile. - /// Any other offset will spawn entities starting from the source Map Coordinates and will increment the supplied - /// offset - /// - /// The list of Entities to spawn in - /// Map Coordinates where the entities will spawn - /// Check to see if the entities should self delete - /// A Vector2 offset that the entities will spawn in - private void SpawnSpellHelper(List entityEntries, EntityCoordinates entityCoords, float? lifetime, Vector2 offsetVector2) - { - var getProtos = EntitySpawnCollection.GetSpawns(entityEntries, _random); - - var offsetCoords = entityCoords; - foreach (var proto in getProtos) - { - // TODO: Share this code with instant because they're both doing similar things for positioning. - var entity = Spawn(proto, offsetCoords); - offsetCoords = offsetCoords.Offset(offsetVector2); - - if (lifetime != null) - { - var comp = EnsureComp(entity); - comp.Lifetime = lifetime.Value; - } - } - } - - #endregion - - private void Speak(BaseActionEvent args) - { - if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech)) - return; - - _chat.TrySendInGameICMessage(args.Performer, Loc.GetString(speak.Speech), - InGameICChatType.Speak, false); + _chat.TrySendInGameICMessage(args.Performer, Loc.GetString(args.Speech), InGameICChatType.Speak, false); } } diff --git a/Content.Server/MagicMirror/MagicMirrorSystem.cs b/Content.Server/MagicMirror/MagicMirrorSystem.cs index aef6e11d71c..6cbfc55cac0 100644 --- a/Content.Server/MagicMirror/MagicMirrorSystem.cs +++ b/Content.Server/MagicMirror/MagicMirrorSystem.cs @@ -16,13 +16,12 @@ namespace Content.Server.MagicMirror; /// /// Allows humanoids to change their appearance mid-round. /// -public sealed class MagicMirrorSystem : EntitySystem +public sealed class MagicMirrorSystem : SharedMagicMirrorSystem { [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly DoAfterSystem _doAfterSystem = default!; [Dependency] private readonly MarkingManager _markings = default!; [Dependency] private readonly HumanoidAppearanceSystem _humanoid = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; public override void Initialize() @@ -32,7 +31,7 @@ public override void Initialize() Subs.BuiEvents(MagicMirrorUiKey.Key, subs => { - subs.Event(OnUIClosed); + subs.Event(OnUiClosed); subs.Event(OnMagicMirrorSelect); subs.Event(OnTryMagicMirrorChangeColor); subs.Event(OnTryMagicMirrorAddSlot); @@ -45,16 +44,6 @@ public override void Initialize() SubscribeLocalEvent(OnChangeColorDoAfter); SubscribeLocalEvent(OnRemoveSlotDoAfter); SubscribeLocalEvent(OnAddSlotDoAfter); - - SubscribeLocalEvent(OnMirrorRangeCheck); - } - - private void OnMirrorRangeCheck(EntityUid uid, MagicMirrorComponent component, ref BoundUserInterfaceCheckRangeEvent args) - { - if (!Exists(component.Target) || !_interaction.InRangeUnobstructed(uid, component.Target.Value)) - { - args.Result = BoundUserInterfaceRangeResult.Fail; - } } private void OnMagicMirrorInteract(Entity mirror, ref AfterInteractEvent args) @@ -62,10 +51,7 @@ private void OnMagicMirrorInteract(Entity mirror, ref Afte if (!args.CanReach || args.Target == null) return; - if (!TryComp(args.User, out var actor)) - return; - - if (!_uiSystem.TryOpen(mirror.Owner, MagicMirrorUiKey.Key, actor.PlayerSession)) + if (!_uiSystem.TryOpenUi(mirror.Owner, MagicMirrorUiKey.Key, args.User)) return; UpdateInterface(mirror.Owner, args.Target.Value, mirror.Comp); @@ -79,7 +65,7 @@ private void OnOpenUIAttempt(EntityUid uid, MagicMirrorComponent mirror, Activat private void OnMagicMirrorSelect(EntityUid uid, MagicMirrorComponent component, MagicMirrorSelectMessage message) { - if (component.Target is not { } target || message.Session.AttachedEntity is not { } user) + if (component.Target is not { } target) return; _doAfterSystem.Cancel(component.DoAfter); @@ -92,7 +78,7 @@ private void OnMagicMirrorSelect(EntityUid uid, MagicMirrorComponent component, Marking = message.Marking, }; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.SelectSlotTime, doAfter, uid, target: target, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.SelectSlotTime, doAfter, uid, target: target, used: uid) { DistanceThreshold = SharedInteractionSystem.InteractionRange, BreakOnTargetMove = true, @@ -136,7 +122,7 @@ private void OnSelectSlotDoAfter(EntityUid uid, MagicMirrorComponent component, private void OnTryMagicMirrorChangeColor(EntityUid uid, MagicMirrorComponent component, MagicMirrorChangeColorMessage message) { - if (component.Target is not { } target || message.Session.AttachedEntity is not { } user) + if (component.Target is not { } target) return; _doAfterSystem.Cancel(component.DoAfter); @@ -149,7 +135,7 @@ private void OnTryMagicMirrorChangeColor(EntityUid uid, MagicMirrorComponent com Colors = message.Colors, }; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.ChangeSlotTime, doAfter, uid, target: target, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.ChangeSlotTime, doAfter, uid, target: target, used: uid) { BreakOnTargetMove = true, BreakOnDamage = true, @@ -191,7 +177,7 @@ private void OnChangeColorDoAfter(EntityUid uid, MagicMirrorComponent component, private void OnTryMagicMirrorRemoveSlot(EntityUid uid, MagicMirrorComponent component, MagicMirrorRemoveSlotMessage message) { - if (component.Target is not { } target || message.Session.AttachedEntity is not { } user) + if (component.Target is not { } target) return; _doAfterSystem.Cancel(component.DoAfter); @@ -203,7 +189,7 @@ private void OnTryMagicMirrorRemoveSlot(EntityUid uid, MagicMirrorComponent comp Slot = message.Slot, }; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, component.RemoveSlotTime, doAfter, uid, target: target, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.RemoveSlotTime, doAfter, uid, target: target, used: uid) { DistanceThreshold = SharedInteractionSystem.InteractionRange, BreakOnTargetMove = true, @@ -250,9 +236,6 @@ private void OnTryMagicMirrorAddSlot(EntityUid uid, MagicMirrorComponent compone if (component.Target == null) return; - if (message.Session.AttachedEntity == null) - return; - _doAfterSystem.Cancel(component.DoAfter); component.DoAfter = null; @@ -261,7 +244,7 @@ private void OnTryMagicMirrorAddSlot(EntityUid uid, MagicMirrorComponent compone Category = message.Category, }; - _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Session.AttachedEntity.Value, component.AddSlotTime, doAfter, uid, target: component.Target.Value, used: uid) + _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, message.Actor, component.AddSlotTime, doAfter, uid, target: component.Target.Value, used: uid) { BreakOnTargetMove = true, BreakOnDamage = true, @@ -324,12 +307,15 @@ private void UpdateInterface(EntityUid mirrorUid, EntityUid targetUid, MagicMirr facialHair, humanoid.MarkingSet.PointsLeft(MarkingCategories.FacialHair) + facialHair.Count); + // TODO: Component states component.Target = targetUid; - _uiSystem.TrySetUiState(mirrorUid, MagicMirrorUiKey.Key, state); + _uiSystem.SetUiState(mirrorUid, MagicMirrorUiKey.Key, state); + Dirty(mirrorUid, component); } - private void OnUIClosed(Entity ent, ref BoundUIClosedEvent args) + private void OnUiClosed(Entity ent, ref BoundUIClosedEvent args) { ent.Comp.Target = null; + Dirty(ent); } } diff --git a/Content.Server/Mapping/MappingCommand.cs b/Content.Server/Mapping/MappingCommand.cs index 08f3dcccf9f..46534f7059d 100644 --- a/Content.Server/Mapping/MappingCommand.cs +++ b/Content.Server/Mapping/MappingCommand.cs @@ -53,7 +53,7 @@ public void Execute(IConsoleShell shell, string argStr, string[] args) } #if DEBUG - shell.WriteError(Loc.GetString("cmd-mapping-warning")); + shell.WriteLine(Loc.GetString("cmd-mapping-warning")); #endif MapId mapId; diff --git a/Content.Server/MassMedia/Systems/NewsSystem.cs b/Content.Server/MassMedia/Systems/NewsSystem.cs index c313b0d4ccd..3246de5316c 100644 --- a/Content.Server/MassMedia/Systems/NewsSystem.cs +++ b/Content.Server/MassMedia/Systems/NewsSystem.cs @@ -92,15 +92,12 @@ private void OnWriteUiDeleteMessage(Entity ent, ref NewsWri if (msg.ArticleNum >= articles.Count) return; - if (msg.Session.AttachedEntity is not { } actor) - return; - var article = articles[msg.ArticleNum]; - if (CheckDeleteAccess(article, ent, actor)) + if (CheckDeleteAccess(article, ent, msg.Actor)) { _adminLogger.Add( LogType.Chat, LogImpact.Medium, - $"{ToPrettyString(actor):actor} deleted news article {article.Title} by {article.Author}: {article.Content}" + $"{ToPrettyString(msg.Actor):actor} deleted news article {article.Title} by {article.Author}: {article.Content}" ); articles.RemoveAt(msg.ArticleNum); @@ -138,11 +135,8 @@ private void OnWriteUiPublishMessage(Entity ent, ref NewsWr if (!TryGetArticles(ent, out var articles)) return; - if (msg.Session.AttachedEntity is not { } author) - return; - string? authorName = null; - if (_idCardSystem.TryFindIdCard(author, out var idCard)) + if (_idCardSystem.TryFindIdCard(msg.Actor, out var idCard)) authorName = idCard.Comp.FullName; var title = msg.Title.Trim(); @@ -161,7 +155,7 @@ private void OnWriteUiPublishMessage(Entity ent, ref NewsWr _adminLogger.Add( LogType.Chat, LogImpact.Medium, - $"{ToPrettyString(author):actor} created news article {article.Title} by {article.Author}: {article.Content}" + $"{ToPrettyString(msg.Actor):actor} created news article {article.Title} by {article.Author}: {article.Content}" ); articles.Add(article); @@ -245,14 +239,14 @@ private bool TryGetArticles(EntityUid uid, [NotNullWhen(true)] out List ent) { - if (!_ui.TryGetUi(ent, NewsWriterUiKey.Key, out var ui)) + if (!_ui.HasUi(ent, NewsWriterUiKey.Key)) return; if (!TryGetArticles(ent, out var articles)) return; var state = new NewsWriterBoundUserInterfaceState(articles.ToArray(), ent.Comp.PublishEnabled, ent.Comp.NextPublish); - _ui.SetUiState(ui, state); + _ui.SetUiState(ent.Owner, NewsWriterUiKey.Key, state); } private void UpdateReaderUi(Entity ent, EntityUid loaderUid) diff --git a/Content.Server/Mech/Components/MechAirComponent.cs b/Content.Server/Mech/Components/MechAirComponent.cs index c533b3d8343..d312e1b7399 100644 --- a/Content.Server/Mech/Components/MechAirComponent.cs +++ b/Content.Server/Mech/Components/MechAirComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos; +using Content.Shared.Atmos; namespace Content.Server.Mech.Components; diff --git a/Content.Server/Mech/Systems/MechSystem.cs b/Content.Server/Mech/Systems/MechSystem.cs index 976c3867a9c..36dce2c9bcc 100644 --- a/Content.Server/Mech/Systems/MechSystem.cs +++ b/Content.Server/Mech/Systems/MechSystem.cs @@ -306,15 +306,14 @@ public override void UpdateUserInterface(EntityUid uid, MechComponent? component { EquipmentStates = ev.States }; - var ui = _ui.GetUi(uid, MechUiKey.Key); - _ui.SetUiState(ui, state); + _ui.SetUiState(uid, MechUiKey.Key, state); } public override void BreakMech(EntityUid uid, MechComponent? component = null) { base.BreakMech(uid, component); - _ui.TryCloseAll(uid, MechUiKey.Key); + _ui.CloseUi(uid, MechUiKey.Key); _actionBlocker.UpdateCanMove(uid); } diff --git a/Content.Server/Medical/Components/CryoPodAirComponent.cs b/Content.Server/Medical/Components/CryoPodAirComponent.cs index baaa3bcda0e..72a10b391e7 100644 --- a/Content.Server/Medical/Components/CryoPodAirComponent.cs +++ b/Content.Server/Medical/Components/CryoPodAirComponent.cs @@ -11,5 +11,5 @@ public sealed partial class CryoPodAirComponent : Component ///
[ViewVariables(VVAccess.ReadWrite)] [DataField("gasMixture")] - public GasMixture Air { get; set; } = new(Atmospherics.OneAtmosphere); + public GasMixture Air { get; set; } = new GasMixture(1000f); } diff --git a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs index ff02b9cbdfe..a53df6dbae9 100644 --- a/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs +++ b/Content.Server/Medical/CrewMonitoring/CrewMonitoringConsoleSystem.cs @@ -58,7 +58,7 @@ private void UpdateUserInterface(EntityUid uid, CrewMonitoringConsoleComponent? if (!Resolve(uid, ref component)) return; - if (!_uiSystem.TryGetUi(uid, CrewMonitoringUIKey.Key, out var bui)) + if (!_uiSystem.IsUiOpen(uid, CrewMonitoringUIKey.Key)) return; // The grid must have a NavMapComponent to visualize the map in the UI @@ -69,6 +69,6 @@ private void UpdateUserInterface(EntityUid uid, CrewMonitoringConsoleComponent? // Update all sensors info var allSensors = component.ConnectedSensors.Values.ToList(); - _uiSystem.SetUiState(bui, new CrewMonitoringState(allSensors)); + _uiSystem.SetUiState(uid, CrewMonitoringUIKey.Key, new CrewMonitoringState(allSensors)); } } diff --git a/Content.Server/Medical/CryoPodSystem.cs b/Content.Server/Medical/CryoPodSystem.cs index bcacd2f5051..e693274fa3c 100644 --- a/Content.Server/Medical/CryoPodSystem.cs +++ b/Content.Server/Medical/CryoPodSystem.cs @@ -13,6 +13,7 @@ using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; using Content.Server.Temperature.Components; +using Content.Shared.Atmos; using Content.Shared.UserInterface; using Content.Shared.Chemistry; using Content.Shared.Chemistry.Components; @@ -194,7 +195,8 @@ private void OnActivateUI(Entity entity, ref AfterActivatableU healthAnalyzer.ScannedEntity = entity.Comp.BodyContainer.ContainedEntity; } - _userInterfaceSystem.TrySendUiMessage( + // TODO: This should be a state my dude + _userInterfaceSystem.ServerSendUiMessage( entity.Owner, HealthAnalyzerUiKey.Key, new HealthAnalyzerScannedUserMessage(GetNetEntity(entity.Comp.BodyContainer.ContainedEntity), @@ -247,7 +249,7 @@ private void OnPowerChanged(Entity entity, ref PowerChangedEve else { RemComp(entity); - _uiSystem.TryCloseAll(entity.Owner, HealthAnalyzerUiKey.Key); + _uiSystem.CloseUi(entity.Owner, HealthAnalyzerUiKey.Key); } UpdateAppearance(entity.Owner, entity.Comp); } @@ -277,10 +279,17 @@ private void OnGasAnalyzed(Entity entity, ref GasAnalyzerScanE if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir)) return; - args.GasMixtures ??= new Dictionary { { Name(entity.Owner), cryoPodAir.Air } }; + args.GasMixtures ??= new List<(string, GasMixture?)>(); + args.GasMixtures.Add((Name(entity.Owner), cryoPodAir.Air)); // If it's connected to a port, include the port side - if (_nodeContainer.TryGetNode(entity.Owner, entity.Comp.PortName, out PipeNode? port)) - args.GasMixtures.Add(entity.Comp.PortName, port.Air); + // multiply by volume fraction to make sure to send only the gas inside the analyzed pipe element, not the whole pipe system + if (_nodeContainer.TryGetNode(entity.Owner, entity.Comp.PortName, out PipeNode? port) && port.Air.Volume != 0f) + { + var portAirLocal = port.Air.Clone(); + portAirLocal.Multiply(port.Volume / port.Air.Volume); + portAirLocal.Volume = port.Volume; + args.GasMixtures.Add((entity.Comp.PortName, portAirLocal)); + } } private void OnEjected(Entity cryoPod, ref EntRemovedFromContainerMessage args) @@ -291,7 +300,7 @@ private void OnEjected(Entity cryoPod, ref EntRemovedFromConta } // if body is ejected - no need to display health-analyzer - _uiSystem.TryCloseAll(cryoPod.Owner, HealthAnalyzerUiKey.Key); + _uiSystem.CloseUi(cryoPod.Owner, HealthAnalyzerUiKey.Key); } #endregion diff --git a/Content.Server/Medical/HealthAnalyzerSystem.cs b/Content.Server/Medical/HealthAnalyzerSystem.cs index 489ba9ac81c..76616ac8017 100644 --- a/Content.Server/Medical/HealthAnalyzerSystem.cs +++ b/Content.Server/Medical/HealthAnalyzerSystem.cs @@ -129,10 +129,10 @@ private void OnDropped(Entity uid, ref DroppedEvent arg private void OpenUserInterface(EntityUid user, EntityUid analyzer) { - if (!TryComp(user, out var actor) || !_uiSystem.TryGetUi(analyzer, HealthAnalyzerUiKey.Key, out var ui)) + if (!_uiSystem.HasUi(analyzer, HealthAnalyzerUiKey.Key)) return; - _uiSystem.OpenUi(ui, actor.PlayerSession); + _uiSystem.OpenUi(analyzer, HealthAnalyzerUiKey.Key, user); } /// @@ -173,7 +173,7 @@ private void StopAnalyzingEntity(Entity healthAnalyzer, /// True makes the UI show ACTIVE, False makes the UI show INACTIVE public void UpdateScannedUser(EntityUid healthAnalyzer, EntityUid target, bool scanMode) { - if (!_uiSystem.TryGetUi(healthAnalyzer, HealthAnalyzerUiKey.Key, out var ui)) + if (!_uiSystem.HasUi(healthAnalyzer, HealthAnalyzerUiKey.Key)) return; if (!HasComp(target)) @@ -195,9 +195,7 @@ public void UpdateScannedUser(EntityUid healthAnalyzer, EntityUid target, bool s bleeding = bloodstream.BleedAmount > 0; } - - - _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage( + _uiSystem.ServerSendUiMessage(healthAnalyzer, HealthAnalyzerUiKey.Key, new HealthAnalyzerScannedUserMessage( GetNetEntity(target), bodyTemperature, bloodAmount, diff --git a/Content.Server/Medical/PenLightSystem.cs b/Content.Server/Medical/PenLightSystem.cs index 0e0f22684a7..29cb4888ebc 100644 --- a/Content.Server/Medical/PenLightSystem.cs +++ b/Content.Server/Medical/PenLightSystem.cs @@ -38,9 +38,9 @@ private void OnAfterInteract(EntityUid uid, PenLightComponent component, ref Aft { if (args.Handled || args.Target is not {} target - || target == null - || !args.CanReach - || !HasComp(target) + || target == null + || !args.CanReach + || !HasComp(target) || !_powerCell.HasDrawCharge(uid, user: args.User)) return; args.Handled = TryStartExam(uid, target, args.User, component); @@ -100,10 +100,10 @@ public bool TryStartExam(EntityUid uid, EntityUid target, EntityUid user, PenLig private void OpenUserInterface(EntityUid user, EntityUid penlight) { if (!TryComp(user, out var actor) - || !_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui)) + || !_uiSystem.TryGetOpenUi(penlight, PenLightUiKey.Key, out var ui)) return; - _uiSystem.OpenUi(ui, actor.PlayerSession); + _uiSystem.OpenUi(ui.Owner, ui.UiKey, actor.PlayerSession); } /// @@ -111,7 +111,7 @@ private void OpenUserInterface(EntityUid user, EntityUid penlight) /// private void Diagnose(EntityUid penlight, EntityUid target) { - if (!_uiSystem.TryGetUi(penlight, PenLightUiKey.Key, out var ui) + if (!_uiSystem.TryGetOpenUi(penlight, PenLightUiKey.Key, out var ui) || !HasComp(target) || !HasComp(target)) return; @@ -135,12 +135,16 @@ private void Diagnose(EntityUid penlight, EntityUid target) // Healthy var healthy = !(blind || drunk || eyeDamage || seeingRainbows); - _uiSystem.SendUiMessage(ui, new PenLightUserMessage(GetNetEntity(target), - blind, - drunk, - eyeDamage, - healthy, - seeingRainbows - )); + _uiSystem.ServerSendUiMessage( + ui.Owner, + ui.UiKey, + new PenLightUserMessage(GetNetEntity(target), + blind, + drunk, + eyeDamage, + healthy, + seeingRainbows + ) + ); } } diff --git a/Content.Server/Medical/Stethoscope/StethoscopeSystem.cs b/Content.Server/Medical/Stethoscope/StethoscopeSystem.cs index 9521c14f2e3..96bfc7c904c 100644 --- a/Content.Server/Medical/Stethoscope/StethoscopeSystem.cs +++ b/Content.Server/Medical/Stethoscope/StethoscopeSystem.cs @@ -3,11 +3,10 @@ using Content.Server.Medical.Stethoscope.Components; using Content.Server.Popups; using Content.Shared.Actions; -using Content.Shared.Clothing.Components; +using Content.Shared.Clothing; using Content.Shared.Damage; using Content.Shared.DoAfter; using Content.Shared.FixedPoint; -using Content.Shared.Inventory.Events; using Content.Shared.Medical; using Content.Shared.Medical.Stethoscope; using Content.Shared.Mobs.Components; @@ -26,8 +25,8 @@ public sealed class StethoscopeSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnEquipped); - SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent>(AddStethoscopeVerb); SubscribeLocalEvent(OnGetActions); SubscribeLocalEvent(OnStethoscopeAction); @@ -37,26 +36,20 @@ public override void Initialize() /// /// Add the component the verb event subs to if the equippee is wearing the stethoscope. /// - private void OnEquipped(EntityUid uid, StethoscopeComponent component, GotEquippedEvent args) + private void OnEquipped(EntityUid uid, StethoscopeComponent component, ref ClothingGotEquippedEvent args) { - if (!TryComp(uid, out var clothing)) - return; - // Is the clothing in its actual slot? - if (!clothing.Slots.HasFlag(args.SlotFlags)) - return; - component.IsActive = true; - var wearingComp = EnsureComp(args.Equipee); + var wearingComp = EnsureComp(args.Wearer); wearingComp.Stethoscope = uid; } - private void OnUnequipped(EntityUid uid, StethoscopeComponent component, GotUnequippedEvent args) + private void OnUnequipped(EntityUid uid, StethoscopeComponent component, ref ClothingGotUnequippedEvent args) { if (!component.IsActive) return; - RemComp(args.Equipee); + RemComp(args.Wearer); component.IsActive = false; } diff --git a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs index 0c4f1ec5463..0ec75790a41 100644 --- a/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs +++ b/Content.Server/Medical/SuitSensors/SuitSensorSystem.cs @@ -7,10 +7,10 @@ using Content.Server.Medical.CrewMonitoring; using Content.Server.Popups; using Content.Server.Station.Systems; +using Content.Shared.Clothing; using Content.Shared.Damage; using Content.Shared.DeviceNetwork; using Content.Shared.Examine; -using Content.Shared.Inventory.Events; using Content.Shared.Medical.SuitSensor; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; @@ -40,8 +40,8 @@ public override void Initialize() base.Initialize(); SubscribeLocalEvent(OnPlayerSpawn); SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnEquipped); - SubscribeLocalEvent(OnUnequipped); + SubscribeLocalEvent(OnEquipped); + SubscribeLocalEvent(OnUnequipped); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent>(OnVerb); SubscribeLocalEvent(OnInsert); @@ -165,19 +165,13 @@ private void OnMapInit(EntityUid uid, SuitSensorComponent component, MapInitEven } } - private void OnEquipped(EntityUid uid, SuitSensorComponent component, GotEquippedEvent args) + private void OnEquipped(EntityUid uid, SuitSensorComponent component, ref ClothingGotEquippedEvent args) { - if (args.Slot != component.ActivationSlot) - return; - - component.User = args.Equipee; + component.User = args.Wearer; } - private void OnUnequipped(EntityUid uid, SuitSensorComponent component, GotUnequippedEvent args) + private void OnUnequipped(EntityUid uid, SuitSensorComponent component, ref ClothingGotUnequippedEvent args) { - if (args.Slot != component.ActivationSlot) - return; - component.User = null; } diff --git a/Content.Server/Mind/MindSystem.cs b/Content.Server/Mind/MindSystem.cs index dc12836d904..4271d76b445 100644 --- a/Content.Server/Mind/MindSystem.cs +++ b/Content.Server/Mind/MindSystem.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Administration.Logs; using Content.Server.GameTicking; +using Content.Server.Ghost; using Content.Server.Mind.Commands; using Content.Shared.Database; using Content.Shared.Ghost; @@ -9,10 +10,8 @@ using Content.Shared.Players; using Robust.Server.GameStates; using Robust.Server.Player; -using Robust.Shared.Map.Components; using Robust.Shared.Network; using Robust.Shared.Player; -using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Server.Mind; @@ -22,8 +21,7 @@ public sealed class MindSystem : SharedMindSystem [Dependency] private readonly GameTicker _gameTicker = default!; [Dependency] private readonly IAdminLogManager _adminLogger = default!; [Dependency] private readonly IPlayerManager _players = default!; - [Dependency] private readonly MetaDataSystem _metaData = default!; - [Dependency] private readonly SharedGhostSystem _ghosts = default!; + [Dependency] private readonly GhostSystem _ghosts = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly PvsOverrideSystem _pvsOverride = default!; @@ -63,8 +61,8 @@ private void OnMindContainerTerminating(EntityUid uid, MindContainerComponent co && !Terminating(visiting)) { TransferTo(mindId, visiting, mind: mind); - if (TryComp(visiting, out GhostComponent? ghost)) - _ghosts.SetCanReturnToBody(ghost, false); + if (TryComp(visiting, out GhostComponent? ghostComp)) + _ghosts.SetCanReturnToBody(ghostComp, false); return; } @@ -74,40 +72,13 @@ private void OnMindContainerTerminating(EntityUid uid, MindContainerComponent co if (!component.GhostOnShutdown || mind.Session == null || _gameTicker.RunLevel == GameRunLevel.PreRoundLobby) return; - var xform = Transform(uid); - var gridId = xform.GridUid; - var spawnPosition = Transform(uid).Coordinates; - - // Use a regular timer here because the entity has probably been deleted. - Timer.Spawn(0, () => - { - // Make extra sure the round didn't end between spawning the timer and it being executed. - if (_gameTicker.RunLevel == GameRunLevel.PreRoundLobby) - return; - - // Async this so that we don't throw if the grid we're on is being deleted. - if (!HasComp(gridId)) - spawnPosition = _gameTicker.GetObserverSpawnPoint(); - - // TODO refactor observer spawning. - // please. - if (!spawnPosition.IsValid(EntityManager)) - { - // This should be an error, if it didn't cause tests to start erroring when they delete a player. - Log.Warning($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, and no applicable spawn location is available."); - TransferTo(mindId, null, createGhost: false, mind: mind); - return; - } - - var ghost = Spawn(GameTicker.ObserverPrototypeName, spawnPosition); - var ghostComponent = Comp(ghost); - _ghosts.SetCanReturnToBody(ghostComponent, false); - + var ghost = _ghosts.SpawnGhost((mindId, mind), uid); + if (ghost != null) // Log these to make sure they're not causing the GameTicker round restart bugs... Log.Debug($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, spawned \"{ToPrettyString(ghost)}\"."); - _metaData.SetEntityName(ghost, mind.CharacterName ?? string.Empty); - TransferTo(mindId, ghost, mind: mind); - }); + else + // This should be an error, if it didn't cause tests to start erroring when they delete a player. + Log.Warning($"Entity \"{ToPrettyString(uid)}\" for {mind.CharacterName} was deleted, and no applicable spawn location is available."); } public override bool TryGetMind(NetUserId user, [NotNullWhen(true)] out EntityUid? mindId, [NotNullWhen(true)] out MindComponent? mind) diff --git a/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs index fe3b844ae34..58647d88749 100644 --- a/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs +++ b/Content.Server/NPC/HTN/Preconditions/GunAmmoPrecondition.cs @@ -35,7 +35,7 @@ public override bool IsMet(NPCBlackboard blackboard) else percent = ammoEv.Count / (float) ammoEv.Capacity; - percent = Math.Clamp(percent, 0f, 1f); + percent = System.Math.Clamp(percent, 0f, 1f); if (MaxPercent < percent) return false; diff --git a/Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs new file mode 100644 index 00000000000..aa0ad98edec --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/InContainerPrecondition.cs @@ -0,0 +1,27 @@ +using Robust.Server.Containers; + +namespace Content.Server.NPC.HTN.Preconditions; + +/// +/// Checks if the owner in container or not +/// +public sealed partial class InContainerPrecondition : HTNPrecondition +{ + private ContainerSystem _container = default!; + + [ViewVariables(VVAccess.ReadWrite)] [DataField("isInContainer")] public bool IsInContainer = true; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _container = sysManager.GetEntitySystem(); + } + + public override bool IsMet(NPCBlackboard blackboard) + { + var owner = blackboard.GetValue(NPCBlackboard.Owner); + + return IsInContainer && _container.IsEntityInContainer(owner) || + !IsInContainer && !_container.IsEntityInContainer(owner); + } +} diff --git a/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs new file mode 100644 index 00000000000..c12663901c7 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/KeyNotExistsPrecondition.cs @@ -0,0 +1,12 @@ +namespace Content.Server.NPC.HTN.Preconditions; + +public sealed partial class KeyNotExistsPrecondition : HTNPrecondition +{ + [DataField(required: true)] + public string Key = string.Empty; + + public override bool IsMet(NPCBlackboard blackboard) + { + return !blackboard.ContainsKey(Key); + } +} diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs new file mode 100644 index 00000000000..8c7920e8be5 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyBoolEqualsPrecondition.cs @@ -0,0 +1,23 @@ +namespace Content.Server.NPC.HTN.Preconditions.Math; + +/// +/// Checks for the presence of data in the blackboard and makes a comparison with the specified boolean +/// +public sealed partial class KeyBoolEqualsPrecondition : HTNPrecondition +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField(required: true)] + public string Key = string.Empty; + + [DataField(required: true)] + public bool Value; + + public override bool IsMet(NPCBlackboard blackboard) + { + if (!blackboard.TryGetValue(Key, out var value, _entManager)) + return false; + + return Value == value; + } +} diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs new file mode 100644 index 00000000000..802fdaf2b9c --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatEqualsPrecondition.cs @@ -0,0 +1,18 @@ +namespace Content.Server.NPC.HTN.Preconditions.Math; + +public sealed partial class KeyFloatEqualsPrecondition : HTNPrecondition +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField(required: true)] + public string Key = string.Empty; + + [DataField(required: true)] + public float Value; + + public override bool IsMet(NPCBlackboard blackboard) + { + return blackboard.TryGetValue(Key, out var value, _entManager) && + MathHelper.CloseTo(value, value); + } +} diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs new file mode 100644 index 00000000000..3a9ac366980 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatGreaterPrecondition.cs @@ -0,0 +1,17 @@ +namespace Content.Server.NPC.HTN.Preconditions.Math; + +public sealed partial class KeyFloatGreaterPrecondition : HTNPrecondition +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField(required: true)] + public string Key = string.Empty; + + [DataField(required: true)] + public float Value; + + public override bool IsMet(NPCBlackboard blackboard) + { + return blackboard.TryGetValue(Key, out var value, _entManager) && value > Value; + } +} diff --git a/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs new file mode 100644 index 00000000000..5cd51d7a7c5 --- /dev/null +++ b/Content.Server/NPC/HTN/Preconditions/Math/KeyFloatLessPrecondition.cs @@ -0,0 +1,17 @@ +namespace Content.Server.NPC.HTN.Preconditions.Math; + +public sealed partial class KeyFloatLessPrecondition : HTNPrecondition +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField(required: true)] + public string Key = string.Empty; + + [DataField(required: true)] + public float Value; + + public override bool IsMet(NPCBlackboard blackboard) + { + return blackboard.TryGetValue(Key, out var value, _entManager) && value < Value; + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs new file mode 100644 index 00000000000..667d0b8ec40 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/ContainerOperator.cs @@ -0,0 +1,40 @@ +using Robust.Server.Containers; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; + +public sealed partial class ContainerOperator : HTNOperator +{ + [Dependency] private readonly IEntityManager _entManager = default!; + private ContainerSystem _container = default!; + private EntityQuery _transformQuery; + + [DataField("shutdownState")] + public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished; + + [DataField("targetKey", required: true)] + public string TargetKey = default!; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _container = sysManager.GetEntitySystem(); + _transformQuery = _entManager.GetEntityQuery(); + } + + public override void Startup(NPCBlackboard blackboard) + { + base.Startup(blackboard); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + + if (!_container.TryGetOuterContainer(owner, _transformQuery.GetComponent(owner), out var outerContainer) && outerContainer == null) + return; + + var target = outerContainer.Owner; + blackboard.SetValue(TargetKey, target); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + return HTNOperatorStatus.Finished; + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs new file mode 100644 index 00000000000..a794e1e3140 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/EscapeOperator.cs @@ -0,0 +1,140 @@ +using System.Threading; +using System.Threading.Tasks; +using Content.Server.NPC.Components; +using Content.Server.Storage.EntitySystems; +using Content.Shared.CombatMode; +using Robust.Server.Containers; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat.Melee; + +public sealed partial class EscapeOperator : HTNOperator, IHtnConditionalShutdown +{ + [Dependency] private readonly IEntityManager _entManager = default!; + private ContainerSystem _container = default!; + private EntityStorageSystem _entityStorage = default!; + + [DataField("shutdownState")] + public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished; + + [DataField("targetKey", required: true)] + public string TargetKey = default!; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _container = sysManager.GetEntitySystem(); + _entityStorage = sysManager.GetEntitySystem(); + } + + public override void Startup(NPCBlackboard blackboard) + { + base.Startup(blackboard); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + var target = blackboard.GetValue(TargetKey); + + if (_entityStorage.TryOpenStorage(owner, target)) + { + TaskShutdown(blackboard, HTNOperatorStatus.Finished); + return; + } + + var melee = _entManager.EnsureComponent(owner); + melee.MissChance = blackboard.GetValueOrDefault(NPCBlackboard.MeleeMissChance, _entManager); + melee.Target = target; + } + + public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, + CancellationToken cancelToken) + { + var owner = blackboard.GetValue(NPCBlackboard.Owner); + if (!blackboard.TryGetValue(TargetKey, out var target, _entManager)) + { + return (false, null); + } + + if (!_container.IsEntityInContainer(owner)) + { + return (false, null); + } + + if (_entityStorage.TryOpenStorage(owner, target)) + { + return (false, null); + } + + return (true, null); + } + + public void ConditionalShutdown(NPCBlackboard blackboard) + { + var owner = blackboard.GetValue(NPCBlackboard.Owner); + _entManager.System().SetInCombatMode(owner, false); + _entManager.RemoveComponent(owner); + blackboard.Remove(TargetKey); + } + + public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status) + { + base.TaskShutdown(blackboard, status); + + ConditionalShutdown(blackboard); + } + + public override void PlanShutdown(NPCBlackboard blackboard) + { + base.PlanShutdown(blackboard); + + ConditionalShutdown(blackboard); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + base.Update(blackboard, frameTime); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + HTNOperatorStatus status; + + if (_entManager.TryGetComponent(owner, out var combat) && + blackboard.TryGetValue(TargetKey, out var target, _entManager)) + { + combat.Target = target; + + // Success + if (!_container.IsEntityInContainer(owner)) + { + status = HTNOperatorStatus.Finished; + } + else + { + if (_entityStorage.TryOpenStorage(owner, target)) + { + status = HTNOperatorStatus.Finished; + } + else + { + switch (combat.Status) + { + case CombatStatus.TargetOutOfRange: + case CombatStatus.Normal: + status = HTNOperatorStatus.Continuing; + break; + default: + status = HTNOperatorStatus.Failed; + break; + } + } + } + } + else + { + status = HTNOperatorStatus.Failed; + } + + // Mark it as finished to continue the plan. + if (status == HTNOperatorStatus.Continuing && ShutdownState == HTNPlanState.PlanFinished) + { + status = HTNOperatorStatus.Finished; + } + + return status; + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs new file mode 100644 index 00000000000..54f422fe67d --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnPullOperator.cs @@ -0,0 +1,35 @@ +using Content.Shared.Movement.Pulling.Components; +using Content.Shared.Movement.Pulling.Systems; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; + +public sealed partial class UnPullOperator : HTNOperator +{ + [Dependency] private readonly IEntityManager _entManager = default!; + private PullingSystem _pulling = default!; + + private EntityQuery _pullableQuery; + + [DataField("shutdownState")] + public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _pulling = sysManager.GetEntitySystem(); + _pullableQuery = _entManager.GetEntityQuery(); + } + + public override void Startup(NPCBlackboard blackboard) + { + base.Startup(blackboard); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + + _pulling.TryStopPull(owner, _pullableQuery.GetComponent(owner), owner); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + return HTNOperatorStatus.Finished; + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs new file mode 100644 index 00000000000..207665d786f --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Combat/UnbuckleOperator.cs @@ -0,0 +1,34 @@ +using Content.Server.Buckle.Systems; +using Content.Shared.Buckle.Components; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Combat; + +public sealed partial class UnbuckleOperator : HTNOperator +{ + [Dependency] private readonly IEntityManager _entManager = default!; + private BuckleSystem _buckle = default!; + + [DataField("shutdownState")] + public HTNPlanState ShutdownState { get; private set; } = HTNPlanState.TaskFinished; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _buckle = sysManager.GetEntitySystem(); + } + + public override void Startup(NPCBlackboard blackboard) + { + base.Startup(blackboard); + var owner = blackboard.GetValue(NPCBlackboard.Owner); + if (!_entManager.TryGetComponent(owner, out var buckle) || !buckle.Buckled) + return; + + _buckle.TryUnbuckle(owner, owner, true, buckle); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + return HTNOperatorStatus.Finished; + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs new file mode 100644 index 00000000000..00404517c9e --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/AddFloatOperator.cs @@ -0,0 +1,33 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math; + +/// +/// Gets the key, and adds the value to that float +/// +public sealed partial class AddFloatOperator : HTNOperator +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + [DataField(required: true)] + public string TargetKey = string.Empty; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Amount; + + public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, + CancellationToken cancelToken) + { + if (!blackboard.TryGetValue(TargetKey, out var value, _entManager)) + return (false, null); + + return ( + true, + new Dictionary + { + { TargetKey, value + Amount } + } + ); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs new file mode 100644 index 00000000000..a40b96798d4 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetBoolOperator.cs @@ -0,0 +1,28 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math; + +/// +/// Just sets a blackboard key to a bool +/// +public sealed partial class SetBoolOperator : HTNOperator +{ + [DataField(required: true)] + public string TargetKey = string.Empty; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool Value; + + public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, + CancellationToken cancelToken) + { + return ( + true, + new Dictionary + { + { TargetKey, Value } + } + ); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs new file mode 100644 index 00000000000..76842b431f7 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetFloatOperator.cs @@ -0,0 +1,28 @@ +using System.Threading; +using System.Threading.Tasks; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math; + +/// +/// Just sets a blackboard key to a float +/// +public sealed partial class SetFloatOperator : HTNOperator +{ + [DataField(required: true)] + public string TargetKey = string.Empty; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float Amount; + + public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, + CancellationToken cancelToken) + { + return ( + true, + new Dictionary + { + { TargetKey, Amount } + } + ); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs new file mode 100644 index 00000000000..999756f1f74 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/Math/SetRandomFloatOperator.cs @@ -0,0 +1,34 @@ +using System.Threading; +using System.Threading.Tasks; +using Robust.Shared.Random; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Math; + +/// +/// Sets a random float from MinAmount to MaxAmount to blackboard +/// +public sealed partial class SetRandomFloatOperator : HTNOperator +{ + [Dependency] private readonly IRobustRandom _random = default!; + + [DataField(required: true)] + public string TargetKey = string.Empty; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float MaxAmount = 1f; + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public float MinAmount = 0f; + + public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, + CancellationToken cancelToken) + { + return ( + true, + new Dictionary + { + { TargetKey, _random.NextFloat(MinAmount, MaxAmount) } + } + ); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs new file mode 100644 index 00000000000..57cc2e91e44 --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/PlaySoundOperator.cs @@ -0,0 +1,28 @@ +using Robust.Server.Audio; +using Robust.Shared.Audio; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; + +public sealed partial class PlaySoundOperator : HTNOperator +{ + private AudioSystem _audio = default!; + + [DataField(required: true)] + public SoundSpecifier? Sound; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + + _audio = IoCManager.Resolve().GetEntitySystem(); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + var uid = blackboard.GetValue(NPCBlackboard.Owner); + + _audio.PlayPvs(Sound, uid); + + return base.Update(blackboard, frameTime); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs new file mode 100644 index 00000000000..3422c77249a --- /dev/null +++ b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SayKeyOperator.cs @@ -0,0 +1,37 @@ +using Content.Server.Chat.Systems; +using Content.Shared.Chat; + +namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; + +public sealed partial class SayKeyOperator : HTNOperator +{ + [Dependency] private readonly IEntityManager _entManager = default!; + + private ChatSystem _chat = default!; + + [DataField(required: true)] + public string Key = string.Empty; + + /// + /// Whether to hide message from chat window and logs. + /// + [DataField] + public bool Hidden; + + public override void Initialize(IEntitySystemManager sysManager) + { + base.Initialize(sysManager); + _chat = IoCManager.Resolve().GetEntitySystem(); + } + + public override HTNOperatorStatus Update(NPCBlackboard blackboard, float frameTime) + { + if (!blackboard.TryGetValue(Key, out var value, _entManager)) + return HTNOperatorStatus.Failed; + + var speaker = blackboard.GetValue(NPCBlackboard.Owner); + _chat.TrySendInGameICMessage(speaker, value.ToString() ?? "Oh no...", InGameICChatType.Speak, hideChat: Hidden, hideLog: Hidden); + + return base.Update(blackboard, frameTime); + } +} diff --git a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs b/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs deleted file mode 100644 index 7a460592cb4..00000000000 --- a/Content.Server/NPC/HTN/PrimitiveTasks/Operators/SetFloatOperator.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System.Threading; -using System.Threading.Tasks; - -namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators; - -/// -/// Just sets a blackboard key to a float -/// -public sealed partial class SetFloatOperator : HTNOperator -{ - [DataField("targetKey", required: true)] public string TargetKey = string.Empty; - - [ViewVariables(VVAccess.ReadWrite), DataField("amount")] - public float Amount; - - public override async Task<(bool Valid, Dictionary? Effects)> Plan(NPCBlackboard blackboard, - CancellationToken cancelToken) - { - return (true, new Dictionary() - { - {TargetKey, Amount}, - }); - } -} diff --git a/Content.Server/NPC/Systems/NPCSystem.cs b/Content.Server/NPC/Systems/NPCSystem.cs index 8abe0f7f54c..24c038a3e7f 100644 --- a/Content.Server/NPC/Systems/NPCSystem.cs +++ b/Content.Server/NPC/Systems/NPCSystem.cs @@ -2,6 +2,8 @@ using Content.Server.NPC.Components; using Content.Server.NPC.HTN; using Content.Shared.CCVar; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; using Content.Shared.Mobs; using Content.Shared.Mobs.Systems; using Content.Shared.NPC; @@ -48,6 +50,10 @@ public void OnPlayerNPCDetach(EntityUid uid, HTNComponent component, PlayerDetac if (_mobState.IsIncapacitated(uid) || TerminatingOrDeleted(uid)) return; + // This NPC has an attached mind, so it should not wake up. + if (TryComp(uid, out var mindContainer) && mindContainer.HasMind) + return; + WakeNPC(uid, component); } diff --git a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs index d84a7287751..2c0f6c63e3e 100644 --- a/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs +++ b/Content.Server/Ninja/Systems/NinjaGlovesSystem.cs @@ -1,8 +1,9 @@ using Content.Server.Communications; using Content.Server.Mind; using Content.Server.Ninja.Events; -using Content.Server.Objectives.Components; +using Content.Server.Objectives.Systems; using Content.Shared.Communications; +using Content.Shared.CriminalRecords.Components; using Content.Shared.Ninja.Components; using Content.Shared.Ninja.Systems; using Content.Shared.Research.Components; @@ -16,6 +17,7 @@ namespace Content.Server.Ninja.Systems; public sealed class NinjaGlovesSystem : SharedNinjaGlovesSystem { [Dependency] private readonly EmagProviderSystem _emagProvider = default!; + [Dependency] private readonly CodeConditionSystem _codeCondition = default!; [Dependency] private readonly CommsHackerSystem _commsHacker = default!; [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly SharedStunProviderSystem _stunProvider = default!; @@ -88,12 +90,16 @@ private void EnableGloves(EntityUid uid, NinjaGlovesComponent comp, EntityUid us EnsureComp(user); // prevent calling in multiple threats by toggling gloves after - if (_mind.TryGetObjectiveComp(user, out var obj) && !obj.CalledInThreat) + if (!_codeCondition.IsCompleted(user, ninja.TerrorObjective)) { var hacker = EnsureComp(user); var rule = _ninja.NinjaRule(user); if (rule != null) _commsHacker.SetThreats(user, rule.Threats, hacker); } + if (!_codeCondition.IsCompleted(user, ninja.MassArrestObjective)) + { + EnsureComp(user); + } } } diff --git a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs index 835ac7ad6cd..1dfaf4f3393 100644 --- a/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs +++ b/Content.Server/Ninja/Systems/SpaceNinjaSystem.cs @@ -1,12 +1,15 @@ using Content.Server.Communications; using Content.Server.Chat.Managers; +using Content.Server.CriminalRecords.Systems; using Content.Server.GameTicking.Rules.Components; +using Content.Server.GenericAntag; +using Content.Server.Objectives.Components; +using Content.Server.Objectives.Systems; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; using Content.Server.PowerCell; using Content.Server.Research.Systems; using Content.Server.Roles; -using Content.Server.GenericAntag; using Content.Shared.Alert; using Content.Shared.Clothing.EntitySystems; using Content.Shared.Doors.Components; @@ -19,7 +22,6 @@ using Robust.Shared.Audio; using Robust.Shared.Player; using System.Diagnostics.CodeAnalysis; -using Content.Server.Objectives.Components; using Robust.Shared.Audio.Systems; namespace Content.Server.Ninja.Systems; @@ -28,7 +30,6 @@ namespace Content.Server.Ninja.Systems; // engi -> saboteur // medi -> idk reskin it // other -> assault -// TODO: when criminal records is merged, hack it to set everyone to arrest /// /// Main ninja system that handles ninja setup, provides helper methods for the rest of the code to use. @@ -37,6 +38,7 @@ public sealed class SpaceNinjaSystem : SharedSpaceNinjaSystem { [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly BatterySystem _battery = default!; + [Dependency] private readonly CodeConditionSystem _codeCondition = default!; [Dependency] private readonly IChatManager _chatMan = default!; [Dependency] private readonly PowerCellSystem _powerCell = default!; [Dependency] private readonly RoleSystem _role = default!; @@ -52,6 +54,7 @@ public override void Initialize() SubscribeLocalEvent(OnDoorjack); SubscribeLocalEvent(OnResearchStolen); SubscribeLocalEvent(OnThreatCalledIn); + SubscribeLocalEvent(OnCriminalRecordsHacked); } public override void Update(float frameTime) @@ -216,11 +219,21 @@ private void OnResearchStolen(EntityUid uid, SpaceNinjaComponent comp, ref Resea Popup.PopupEntity(str, uid, uid, PopupType.Medium); } - private void OnThreatCalledIn(EntityUid uid, SpaceNinjaComponent comp, ref ThreatCalledInEvent args) + private void OnThreatCalledIn(Entity ent, ref ThreatCalledInEvent args) { - if (_mind.TryGetObjectiveComp(uid, out var obj)) - { - obj.CalledInThreat = true; - } + _codeCondition.SetCompleted(ent.Owner, ent.Comp.TerrorObjective); + } + + private void OnCriminalRecordsHacked(Entity ent, ref CriminalRecordsHackedEvent args) + { + _codeCondition.SetCompleted(ent.Owner, ent.Comp.MassArrestObjective); + } + + /// + /// Called by when it detonates. + /// + public void DetonatedSpiderCharge(Entity ent) + { + _codeCondition.SetCompleted(ent.Owner, ent.Comp.SpiderChargeObjective); } } diff --git a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs index 948d715f0a7..64c958d6f1a 100644 --- a/Content.Server/Ninja/Systems/SpiderChargeSystem.cs +++ b/Content.Server/Ninja/Systems/SpiderChargeSystem.cs @@ -19,6 +19,7 @@ public sealed class SpiderChargeSystem : EntitySystem [Dependency] private readonly MindSystem _mind = default!; [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly SpaceNinjaSystem _ninja = default!; public override void Initialize() { @@ -76,10 +77,10 @@ private void OnStuck(EntityUid uid, SpiderChargeComponent comp, EntityStuckEvent /// private void OnExplode(EntityUid uid, SpiderChargeComponent comp, TriggerEvent args) { - if (comp.Planter == null || !_mind.TryGetObjectiveComp(comp.Planter.Value, out var obj)) + if (!TryComp(comp.Planter, out var ninja)) return; // assumes the target was destroyed, that the charge wasn't moved somehow - obj.Detonated = true; + _ninja.DetonatedSpiderCharge((comp.Planter.Value, ninja)); } } diff --git a/Content.Server/Nuke/NukeCodePaperSystem.cs b/Content.Server/Nuke/NukeCodePaperSystem.cs index 36268d5648d..cedae696825 100644 --- a/Content.Server/Nuke/NukeCodePaperSystem.cs +++ b/Content.Server/Nuke/NukeCodePaperSystem.cs @@ -1,6 +1,7 @@ using System.Diagnostics.CodeAnalysis; using Content.Server.Chat.Systems; using Content.Server.Fax; +using Content.Shared.Fax.Components; using Content.Server.Paper; using Content.Server.Station.Components; using Content.Server.Station.Systems; @@ -66,6 +67,7 @@ public bool SendNukeCodes(EntityUid station) paperContent, Loc.GetString("nuke-codes-fax-paper-name"), null, + null, "paper_stamp-centcom", new List { diff --git a/Content.Server/Nuke/NukeSystem.cs b/Content.Server/Nuke/NukeSystem.cs index 5a7219fdf15..2f62f9d6743 100644 --- a/Content.Server/Nuke/NukeSystem.cs +++ b/Content.Server/Nuke/NukeSystem.cs @@ -189,7 +189,7 @@ private async void OnAnchorButtonPressed(EntityUid uid, NukeComponent component, continue; var msg = Loc.GetString("nuke-component-cant-anchor-floor"); - _popups.PopupEntity(msg, uid, args.Session, PopupType.MediumCaution); + _popups.PopupEntity(msg, uid, args.Actor, PopupType.MediumCaution); return; } @@ -245,10 +245,7 @@ private void OnArmButtonPressed(EntityUid uid, NukeComponent component, NukeArme else { - if (args.Session.AttachedEntity is not { } user) - return; - - DisarmBombDoafter(uid, user, component); + DisarmBombDoafter(uid, args.Actor, component); } } @@ -368,8 +365,7 @@ private void UpdateUserInterface(EntityUid uid, NukeComponent? component = null) if (!Resolve(uid, ref component)) return; - var ui = _ui.GetUiOrNull(uid, NukeUiKey.Key); - if (ui == null) + if (!_ui.HasUi(uid, NukeUiKey.Key)) return; var anchored = Transform(uid).Anchored; @@ -390,7 +386,7 @@ private void UpdateUserInterface(EntityUid uid, NukeComponent? component = null) CooldownTime = (int) component.CooldownTime }; - _ui.SetUiState(ui, state); + _ui.SetUiState(uid, NukeUiKey.Key, state); } private void PlayNukeKeypadSound(EntityUid uid, int number, NukeComponent? component = null) diff --git a/Content.Server/NukeOps/WarDeclaratorSystem.cs b/Content.Server/NukeOps/WarDeclaratorSystem.cs index dee0c10c40e..04f0b069f12 100644 --- a/Content.Server/NukeOps/WarDeclaratorSystem.cs +++ b/Content.Server/NukeOps/WarDeclaratorSystem.cs @@ -58,9 +58,6 @@ private void OnAttemptOpenUI(Entity ent, ref Activatable private void OnActivated(Entity ent, ref WarDeclaratorActivateMessage args) { - if (args.Session.AttachedEntity is not {} playerEntity) - return; - var ev = new WarDeclaredEvent(ent.Comp.CurrentStatus, ent); RaiseLocalEvent(ref ev); @@ -78,7 +75,7 @@ private void OnActivated(Entity ent, ref WarDeclaratorAc { var title = Loc.GetString(ent.Comp.SenderTitle); _announcer.SendAnnouncement("war", Filter.Broadcast(), ent.Comp.Message, title, ent.Comp.Color); - _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(playerEntity):player} has declared war with this text: {ent.Comp.Message}"); + _adminLogger.Add(LogType.Chat, LogImpact.Low, $"{ToPrettyString(args.Actor):player} has declared war with this text: {ent.Comp.Message}"); } UpdateUI(ent, ev.Status); @@ -86,8 +83,8 @@ private void OnActivated(Entity ent, ref WarDeclaratorAc private void UpdateUI(Entity ent, WarConditionStatus? status = null) { - _userInterfaceSystem.TrySetUiState( - ent, + _userInterfaceSystem.SetUiState( + ent.Owner, WarDeclaratorUiKey.Key, new WarDeclaratorBoundUserInterfaceState(status, ent.Comp.DisableAt, ent.Comp.ShuttleDisabledTime)); } diff --git a/Content.Server/Nutrition/Components/DrinkComponent.cs b/Content.Server/Nutrition/Components/DrinkComponent.cs deleted file mode 100644 index 20d47cda88c..00000000000 --- a/Content.Server/Nutrition/Components/DrinkComponent.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Server.Nutrition.EntitySystems; -using Content.Shared.FixedPoint; -using Robust.Shared.Audio; - -namespace Content.Server.Nutrition.Components; - -[RegisterComponent, Access(typeof(DrinkSystem))] -public sealed partial class DrinkComponent : Component -{ - [DataField, ViewVariables(VVAccess.ReadWrite)] - public string Solution = "drink"; - - [DataField] - public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/drink.ogg"); - - [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 TransferAmount = FixedPoint2.New(5); - - /// - /// How long it takes to drink this yourself. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float Delay = 1; - - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool Examinable = true; - - /// - /// If true, trying to drink when empty will not handle the event. - /// This means other systems such as equipping on use can run. - /// Example usecase is the bucket. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool IgnoreEmpty; - - /// - /// This is how many seconds it takes to force feed someone this drink. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float ForceFeedDelay = 3; -} diff --git a/Content.Server/Nutrition/Components/PressurizedDrinkComponent.cs b/Content.Server/Nutrition/Components/PressurizedDrinkComponent.cs deleted file mode 100644 index aafb3bc1065..00000000000 --- a/Content.Server/Nutrition/Components/PressurizedDrinkComponent.cs +++ /dev/null @@ -1,27 +0,0 @@ -using Content.Server.Nutrition.EntitySystems; -using Robust.Shared.Audio; - -namespace Content.Server.Nutrition.Components; - -/// -/// Lets a drink burst open when thrown while closed. -/// Requires and to work. -/// -[RegisterComponent, Access(typeof(DrinkSystem))] -public sealed partial class PressurizedDrinkComponent : Component -{ - /// - /// Chance for the drink to burst when thrown while closed. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public float BurstChance = 0.25f; - - /// - /// Sound played when the drink bursts. - /// - [DataField] - public SoundSpecifier BurstSound = new SoundPathSpecifier("/Audio/Effects/flash_bang.ogg") - { - Params = AudioParams.Default.WithVolume(-4) - }; -} diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index 2249926baab..cd05adc7948 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -5,7 +5,6 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.Forensics; using Content.Server.Inventory; -using Content.Server.Nutrition.Components; using Content.Server.Popups; using Content.Server.Traits.Assorted.Components; using Content.Shared.Administration.Logs; @@ -18,7 +17,6 @@ using Content.Shared.Chemistry.Reagent; using Content.Shared.Database; using Content.Shared.DoAfter; -using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; @@ -27,25 +25,22 @@ using Content.Shared.Nutrition; using Content.Shared.Nutrition.Components; using Content.Shared.Nutrition.EntitySystems; -using Content.Shared.Throwing; using Content.Shared.Verbs; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Configuration; using Robust.Shared.Player; using Robust.Shared.Prototypes; -using Robust.Shared.Random; using Robust.Shared.Utility; namespace Content.Server.Nutrition.EntitySystems; -public sealed class DrinkSystem : EntitySystem +public sealed class DrinkSystem : SharedDrinkSystem { [Dependency] private readonly BodySystem _body = default!; [Dependency] private readonly FlavorProfileSystem _flavorProfile = default!; [Dependency] private readonly FoodSystem _food = default!; [Dependency] private readonly IPrototypeManager _proto = default!; - [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly MobStateSystem _mobState = default!; [Dependency] private readonly OpenableSystem _openable = default!; @@ -70,33 +65,10 @@ public override void Initialize() SubscribeLocalEvent(OnDrinkInit); // run before inventory so for bucket it always tries to drink before equipping (when empty) // run after openable so its always open -> drink - SubscribeLocalEvent(OnUse, before: new[] { typeof(ServerInventorySystem) }, after: new[] { typeof(OpenableSystem) }); + SubscribeLocalEvent(OnUse, before: [typeof(ServerInventorySystem)], after: [typeof(OpenableSystem)]); SubscribeLocalEvent(AfterInteract); SubscribeLocalEvent>(AddDrinkVerb); - // put drink amount after opened - SubscribeLocalEvent(OnExamined, after: new[] { typeof(OpenableSystem) }); SubscribeLocalEvent(OnDoAfter); - - SubscribeLocalEvent(OnPressurizedDrinkLand); - } - - private FixedPoint2 DrinkVolume(EntityUid uid, DrinkComponent? component = null) - { - if (!Resolve(uid, ref component)) - return FixedPoint2.Zero; - - if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol)) - return FixedPoint2.Zero; - - return sol.Volume; - } - - public bool IsEmpty(EntityUid uid, DrinkComponent? component = null) - { - if (!Resolve(uid, ref component)) - return true; - - return DrinkVolume(uid, component) <= 0; } /// @@ -133,38 +105,6 @@ public float TotalHydration(EntityUid uid, DrinkComponent? comp = null) return total; } - private void OnExamined(Entity entity, ref ExaminedEvent args) - { - TryComp(entity, out var openable); - if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable) - return; - - var empty = IsEmpty(entity, entity.Comp); - if (empty) - { - args.PushMarkup(Loc.GetString("drink-component-on-examine-is-empty")); - return; - } - - if (HasComp(entity)) - { - //provide exact measurement for beakers - args.PushText(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp)))); - } - else - { - //general approximation - var remainingString = (int) _solutionContainer.PercentFull(entity) switch - { - 100 => "drink-component-on-examine-is-full", - > 66 => "drink-component-on-examine-is-mostly-full", - > 33 => HalfEmptyOrHalfFull(args), - _ => "drink-component-on-examine-is-mostly-empty", - }; - args.PushMarkup(Loc.GetString(remainingString)); - } - } - private void AfterInteract(Entity entity, ref AfterInteractEvent args) { if (args.Handled || args.Target == null || !args.CanReach) @@ -181,25 +121,6 @@ private void OnUse(Entity entity, ref UseInHandEvent args) args.Handled = TryDrink(args.User, args.User, entity.Comp, entity); } - private void OnPressurizedDrinkLand(Entity entity, ref LandEvent args) - { - if (!TryComp(entity, out var drink) || !TryComp(entity, out var openable)) - return; - - if (!openable.Opened && - _random.Prob(entity.Comp.BurstChance) && - _solutionContainer.TryGetSolution(entity.Owner, drink.Solution, out var soln, out var interactions)) - { - // using SetOpen instead of TryOpen to not play 2 sounds - _openable.SetOpen(entity, true, openable); - - var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume); - _puddle.TrySpillAt(entity, solution, out _); - - _audio.PlayPvs(entity.Comp.BurstSound, entity); - } - } - private void OnDrinkInit(Entity entity, ref ComponentInit args) { if (TryComp(entity, out var existingDrainable)) @@ -442,16 +363,4 @@ private void AddDrinkVerb(Entity entity, ref GetVerbsEvent(args.Examiner, out var examiner) && examiner.EntityName.Length > 0 - && string.Compare(examiner.EntityName.Substring(0, 1), "m", StringComparison.InvariantCultureIgnoreCase) > 0) - remainingString = "drink-component-on-examine-is-half-empty"; - - return remainingString; - } } diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs index fe0d1d0c168..d5bff967b3c 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.Vape.cs @@ -13,6 +13,7 @@ using Content.Shared.Interaction; using Content.Shared.Nutrition; using System.Threading; +using Content.Shared.Atmos; /// /// System for vapes diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Storage.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Storage.cs index 8858286dbf6..a9a07c287b4 100644 --- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Storage.cs +++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Storage.cs @@ -80,14 +80,13 @@ private void OnInteractUsing(EntityUid uid, DeepFryerComponent component, Intera private void OnInsertItem(EntityUid uid, DeepFryerComponent component, DeepFryerInsertItemMessage args) { - var user = args.Session.AttachedEntity; + var user = EntityManager.GetEntity(args.Entity); - if (user == null || - !TryComp(user, out var handsComponent) || + if (!TryComp(user, out var handsComponent) || handsComponent.ActiveHandEntity == null) return; if (handsComponent.ActiveHandEntity != null) - TryInsertItem(uid, component, user.Value, handsComponent.ActiveHandEntity.Value); + TryInsertItem(uid, component, user, handsComponent.ActiveHandEntity.Value); } } diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs index 80c38f4630e..dc182c1edfa 100644 --- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs +++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs @@ -128,8 +128,7 @@ private void UpdateUserInterface(EntityUid uid, DeepFryerComponent component) component.FryingOilThreshold, EntityManager.GetNetEntityArray(component.Storage.ContainedEntities.ToArray())); - if (!_uiSystem.TrySetUiState(uid, DeepFryerUiKey.Key, state)) - _sawmill.Warning($"{ToPrettyString(uid)} was unable to set UI state."); + _uiSystem.SetUiState(new Entity(uid, null), DeepFryerUiKey.Key, state); } /// @@ -525,15 +524,12 @@ private void OnRemoveItem(EntityUid uid, DeepFryerComponent component, DeepFryer if (!_containerSystem.Remove(removedItem, component.Storage)) return; - var user = args.Session.AttachedEntity; + var user = EntityManager.GetEntity(args.Entity); - if (user != null) - { - _handsSystem.TryPickupAnyHand(user.Value, removedItem); + _handsSystem.TryPickupAnyHand(user, removedItem); - _adminLogManager.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(user.Value)} took {ToPrettyString(args.Item)} out of {ToPrettyString(uid)}."); - } + _adminLogManager.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(user)} took {ToPrettyString(args.Item)} out of {ToPrettyString(uid)}."); _audioSystem.PlayPvs(component.SoundRemoveItem, uid, AudioParamsInsertRemove); @@ -581,17 +577,16 @@ private bool TryGetActiveHandSolutionContainer( private void OnScoopVat(EntityUid uid, DeepFryerComponent component, DeepFryerScoopVatMessage args) { - var user = args.Session.AttachedEntity; + var user = EntityManager.GetEntity(args.Entity); - if (user == null || - !TryGetActiveHandSolutionContainer(uid, user.Value, out var heldItem, out var heldSolution, + if (!TryGetActiveHandSolutionContainer(uid, user, out var heldItem, out var heldSolution, out var transferAmount)) return; if (!_solutionContainerSystem.TryGetSolution(component.Owner, component.Solution.Name, out var solution)) return; - _solutionTransferSystem.Transfer(user.Value, + _solutionTransferSystem.Transfer(user, uid, solution.Value, heldItem.Value, @@ -603,10 +598,9 @@ private void OnScoopVat(EntityUid uid, DeepFryerComponent component, DeepFryerSc private void OnClearSlagStart(EntityUid uid, DeepFryerComponent component, DeepFryerClearSlagMessage args) { - var user = args.Session.AttachedEntity; + var user = EntityManager.GetEntity(args.Entity); - if (user == null || - !TryGetActiveHandSolutionContainer(uid, user.Value, out var heldItem, out var heldSolution, + if (!TryGetActiveHandSolutionContainer(uid, user, out var heldItem, out var heldSolution, out var transferAmount)) return; @@ -616,7 +610,7 @@ private void OnClearSlagStart(EntityUid uid, DeepFryerComponent component, DeepF _popupSystem.PopupEntity( Loc.GetString("deep-fryer-oil-no-slag"), uid, - user.Value); + user); return; } @@ -626,7 +620,7 @@ private void OnClearSlagStart(EntityUid uid, DeepFryerComponent component, DeepF var ev = new ClearSlagDoAfterEvent(heldSolution.Value.Comp.Solution, transferAmount); //JJ Comment - not sure I have DoAfterArgs configured correctly. - var doAfterArgs = new DoAfterArgs(EntityManager, user.Value, delay, ev, uid, uid, heldItem) + var doAfterArgs = new DoAfterArgs(EntityManager, user, delay, ev, uid, uid, heldItem) { BreakOnDamage = true, BreakOnTargetMove = true, @@ -645,13 +639,10 @@ private void OnRemoveAllItems(EntityUid uid, DeepFryerComponent component, DeepF _containerSystem.EmptyContainer(component.Storage); - var user = args.Session.AttachedEntity; + var user = EntityManager.GetEntity(args.Entity); - if (user != null) - { - _adminLogManager.Add(LogType.Action, LogImpact.Low, - $"{ToPrettyString(user.Value)} removed all items from {ToPrettyString(uid)}."); - } + _adminLogManager.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(user)} removed all items from {ToPrettyString(uid)}."); _audioSystem.PlayPvs(component.SoundRemoveItem, uid, AudioParamsInsertRemove); diff --git a/Content.Server/Nyanotrasen/ReverseEngineering/ReverseEngineeringSystem.cs b/Content.Server/Nyanotrasen/ReverseEngineering/ReverseEngineeringSystem.cs index 85fa160d8ee..f4e5a1c4198 100644 --- a/Content.Server/Nyanotrasen/ReverseEngineering/ReverseEngineeringSystem.cs +++ b/Content.Server/Nyanotrasen/ReverseEngineering/ReverseEngineeringSystem.cs @@ -187,7 +187,7 @@ private void UpdateUserInterface(EntityUid uid, ReverseEngineeringMachineCompone if (!Resolve(uid, ref component)) return; - if (!_ui.TryGetUi(uid, ReverseEngineeringMachineUiKey.Key, out var bui)) + if (!_ui.TryGetOpenUi(uid, ReverseEngineeringMachineUiKey.Key, out var bui)) return; EntityUid? item = component.CurrentItem; @@ -202,7 +202,7 @@ private void UpdateUserInterface(EntityUid uid, ReverseEngineeringMachineCompone var state = new ReverseEngineeringMachineScanUpdateState(netItem, canScan, component.CachedMessage, scanning, component.SafetyOn, component.AutoScan, component.Progress, remaining, component.AnalysisDuration); - _ui.SetUiState(bui, state); + _ui.SetUiState(bui.Owner, bui.UiKey, state); } private ReverseEngineeringTickResult Roll(ReverseEngineeringMachineComponent component, out int actualRoll) diff --git a/Content.Server/Objectives/Components/CodeConditionSystem.cs b/Content.Server/Objectives/Components/CodeConditionSystem.cs new file mode 100644 index 00000000000..581098c3f7e --- /dev/null +++ b/Content.Server/Objectives/Components/CodeConditionSystem.cs @@ -0,0 +1,17 @@ +using Content.Server.Objectives.Systems; + +namespace Content.Server.Objectives.Components; + +/// +/// An objective that is set to complete by code in another system. +/// Use to check and set this. +/// +[RegisterComponent, Access(typeof(CodeConditionSystem))] +public sealed partial class CodeConditionComponent : Component +{ + /// + /// Whether the objective is complete or not. + /// + [DataField] + public bool Completed; +} diff --git a/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs b/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs index 368c9f27ed4..9983b35969f 100644 --- a/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs +++ b/Content.Server/Objectives/Components/SpiderChargeConditionComponent.cs @@ -9,9 +9,6 @@ namespace Content.Server.Objectives.Components; [RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SpiderChargeSystem), typeof(SpaceNinjaSystem))] public sealed partial class SpiderChargeConditionComponent : Component { - [DataField, ViewVariables(VVAccess.ReadWrite)] - public bool Detonated; - /// /// Warp point that the spider charge has to target /// diff --git a/Content.Server/Objectives/Components/TerminatorTargetOverrideComponent.cs b/Content.Server/Objectives/Components/TerminatorTargetOverrideComponent.cs deleted file mode 100644 index c66ff55f054..00000000000 --- a/Content.Server/Objectives/Components/TerminatorTargetOverrideComponent.cs +++ /dev/null @@ -1,12 +0,0 @@ -using Content.Server.Objectives.Systems; - -namespace Content.Server.Objectives.Components; - -/// -/// Sets this objective's target to the exterminator's target override, if it has one. -/// If not it will be random. -/// -[RegisterComponent, Access(typeof(TerminatorTargetOverrideSystem))] -public sealed partial class TerminatorTargetOverrideComponent : Component -{ -} diff --git a/Content.Server/Objectives/Components/TerrorConditionComponent.cs b/Content.Server/Objectives/Components/TerrorConditionComponent.cs deleted file mode 100644 index acd3218ad4d..00000000000 --- a/Content.Server/Objectives/Components/TerrorConditionComponent.cs +++ /dev/null @@ -1,17 +0,0 @@ -using Content.Server.Objectives.Systems; -using Content.Shared.Ninja.Systems; - -namespace Content.Server.Objectives.Components; - -/// -/// Requires that the player is a ninja and has called in a threat. -/// -[RegisterComponent, Access(typeof(NinjaConditionsSystem), typeof(SharedSpaceNinjaSystem))] -public sealed partial class TerrorConditionComponent : Component -{ - /// - /// Whether the comms console has been hacked - /// - [DataField("calledInThreat"), ViewVariables(VVAccess.ReadWrite)] - public bool CalledInThreat; -} diff --git a/Content.Server/Objectives/Systems/CodeConditionSystem.cs b/Content.Server/Objectives/Systems/CodeConditionSystem.cs new file mode 100644 index 00000000000..7ba312f4bb9 --- /dev/null +++ b/Content.Server/Objectives/Systems/CodeConditionSystem.cs @@ -0,0 +1,76 @@ +using Content.Server.Objectives.Components; +using Content.Shared.Objectives.Components; +using Content.Shared.Mind; +using Content.Shared.Mind.Components; + +namespace Content.Server.Objectives.Systems; + +/// +/// Handles progress and provides API for systems to use. +/// +public sealed class CodeConditionSystem : EntitySystem +{ + [Dependency] private readonly SharedMindSystem _mind = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnGetProgress); + } + + private void OnGetProgress(Entity ent, ref ObjectiveGetProgressEvent args) + { + args.Progress = ent.Comp.Completed ? 1f : 0f; + } + + /// + /// Returns whether an objective is completed. + /// + public bool IsCompleted(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return false; + + return ent.Comp.Completed; + } + + /// + /// Returns true if a mob's objective with a certain prototype is completed. + /// + public bool IsCompleted(Entity mob, string prototype) + { + if (_mind.GetMind(mob, mob.Comp) is not {} mindId) + return false; + + if (!_mind.TryFindObjective(mindId, prototype, out var obj)) + return false; + + return IsCompleted(obj.Value); + } + + /// + /// Sets an objective's completed field. + /// + public void SetCompleted(Entity ent, bool completed = true) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + ent.Comp.Completed = completed; + } + + /// + /// Sets a mob's objective to complete. + /// + public void SetCompleted(Entity mob, string prototype, bool completed = true) + { + if (_mind.GetMind(mob, mob.Comp) is not {} mindId) + return; + + if (!_mind.TryFindObjective(mindId, prototype, out var obj)) + return; + + SetCompleted(obj.Value, completed); + } +} diff --git a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs index 888a365a5dd..47c54b937a0 100644 --- a/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs +++ b/Content.Server/Objectives/Systems/NinjaConditionsSystem.cs @@ -23,11 +23,8 @@ public override void Initialize() SubscribeLocalEvent(OnSpiderChargeRequirementCheck); SubscribeLocalEvent(OnSpiderChargeAfterAssign); - SubscribeLocalEvent(OnSpiderChargeGetProgress); SubscribeLocalEvent(OnStealResearchGetProgress); - - SubscribeLocalEvent(OnTerrorGetProgress); } // doorjack @@ -88,11 +85,6 @@ private void OnSpiderChargeAfterAssign(EntityUid uid, SpiderChargeConditionCompo _metaData.SetEntityName(uid, title, args.Meta); } - private void OnSpiderChargeGetProgress(EntityUid uid, SpiderChargeConditionComponent comp, ref ObjectiveGetProgressEvent args) - { - args.Progress = comp.Detonated ? 1f : 0f; - } - // steal research private void OnStealResearchGetProgress(EntityUid uid, StealResearchConditionComponent comp, ref ObjectiveGetProgressEvent args) @@ -108,9 +100,4 @@ private float StealResearchProgress(StealResearchConditionComponent comp, int ta return MathF.Min(comp.DownloadedNodes.Count / (float) target, 1f); } - - private void OnTerrorGetProgress(EntityUid uid, TerrorConditionComponent comp, ref ObjectiveGetProgressEvent args) - { - args.Progress = comp.CalledInThreat ? 1f : 0f; - } } diff --git a/Content.Server/Objectives/Systems/TerminatorTargetOverrideSystem.cs b/Content.Server/Objectives/Systems/TerminatorTargetOverrideSystem.cs deleted file mode 100644 index 0a81c2810ed..00000000000 --- a/Content.Server/Objectives/Systems/TerminatorTargetOverrideSystem.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Server.Objectives.Components; -using Content.Server.Terminator.Components; -using Content.Shared.Mind; -using Content.Shared.Objectives.Components; - -namespace Content.Server.Objectives.Systems; - -/// -/// Handles copying the exterminator's target override to this objective. -/// -public sealed class TerminatorTargetOverrideSystem : EntitySystem -{ - [Dependency] private readonly TargetObjectiveSystem _target = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnAssigned); - } - - private void OnAssigned(EntityUid uid, TerminatorTargetOverrideComponent comp, ref ObjectiveAssignedEvent args) - { - if (args.Mind.OwnedEntity == null) - { - args.Cancelled = true; - return; - } - - var user = args.Mind.OwnedEntity.Value; - if (!TryComp(user, out var terminator)) - { - args.Cancelled = true; - return; - } - - // this exterminator has a target override so set its objective target accordingly - if (terminator.Target != null) - _target.SetTarget(uid, terminator.Target.Value); - } -} diff --git a/Content.Server/PAI/PAISystem.cs b/Content.Server/PAI/PAISystem.cs index e9505b5e6fd..091afb15576 100644 --- a/Content.Server/PAI/PAISystem.cs +++ b/Content.Server/PAI/PAISystem.cs @@ -102,13 +102,15 @@ public void PAITurningOff(EntityUid uid) { // Close the instrument interface if it was open // before closing - if (HasComp(uid) && TryComp(uid, out var actor)) + if (HasComp(uid)) { - _instrumentSystem.ToggleInstrumentUi(uid, actor.PlayerSession); + _instrumentSystem.ToggleInstrumentUi(uid, uid); } // Stop instrument - if (TryComp(uid, out var instrument)) _instrumentSystem.Clean(uid, instrument); + if (TryComp(uid, out var instrument)) + _instrumentSystem.Clean(uid, instrument); + if (TryComp(uid, out var metadata)) { var proto = metadata.EntityPrototype; diff --git a/Content.Server/PDA/PdaSystem.cs b/Content.Server/PDA/PdaSystem.cs index a3436071969..d4934ee24e5 100644 --- a/Content.Server/PDA/PdaSystem.cs +++ b/Content.Server/PDA/PdaSystem.cs @@ -4,7 +4,6 @@ using Content.Server.DeviceNetwork.Components; using Content.Server.Instruments; using Content.Server.Light.EntitySystems; -using Content.Server.Light.Events; using Content.Server.PDA.Ringer; using Content.Server.Station.Systems; using Content.Server.Store.Components; @@ -12,7 +11,9 @@ using Content.Shared.Access.Components; using Content.Shared.CartridgeLoader; using Content.Shared.Chat; +using Content.Shared.Light; using Content.Shared.Light.Components; +using Content.Shared.Light.EntitySystems; using Content.Shared.PDA; using Robust.Server.Containers; using Robust.Server.GameObjects; @@ -41,6 +42,7 @@ public override void Initialize() SubscribeLocalEvent(OnLightToggle); // UI Events: + SubscribeLocalEvent(OnPdaOpen); SubscribeLocalEvent(OnUiMessage); SubscribeLocalEvent(OnUiMessage); SubscribeLocalEvent(OnUiMessage); @@ -145,7 +147,7 @@ public void UpdatePdaUi(EntityUid uid, PdaComponent? pda = null) if (!Resolve(uid, ref pda, false)) return; - if (!_ui.TryGetUi(uid, PdaUiKey.Key, out var ui)) + if (!_ui.HasUi(uid, PdaUiKey.Key)) return; var address = GetDeviceNetAddress(uid); @@ -182,7 +184,15 @@ public void UpdatePdaUi(EntityUid uid, PdaComponent? pda = null) hasInstrument, address); - _ui.SetUiState(ui, state); + _ui.SetUiState(uid, PdaUiKey.Key, state); + } + + private void OnPdaOpen(Entity ent, ref BoundUIOpenedEvent args) + { + if (!PdaUiKey.Key.Equals(args.UiKey)) + return; + + UpdatePdaUi(ent.Owner, ent.Comp); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaRequestUpdateInterfaceMessage msg) @@ -198,8 +208,9 @@ private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaToggleFlashlightMes if (!PdaUiKey.Key.Equals(msg.UiKey)) return; - if (TryComp(uid, out var flashlight)) - _unpoweredFlashlight.ToggleLight(uid, flashlight); + // TODO PREDICTION + // When moving this to shared, fill in the user field + _unpoweredFlashlight.TryToggleLight(uid, user: null); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowRingtoneMessage msg) @@ -208,7 +219,7 @@ private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowRingtoneMessage return; if (HasComp(uid)) - _ringer.ToggleRingerUI(uid, msg.Session); + _ringer.ToggleRingerUI(uid, msg.Actor); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowMusicMessage msg) @@ -217,7 +228,7 @@ private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowMusicMessage ms return; if (TryComp(uid, out var instrument)) - _instrument.ToggleInstrumentUi(uid, msg.Session, instrument); + _instrument.ToggleInstrumentUi(uid, msg.Actor, instrument); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowUplinkMessage msg) @@ -227,7 +238,7 @@ private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaShowUplinkMessage m // check if its locked again to prevent malicious clients opening locked uplinks if (TryComp(uid, out var store) && IsUnlocked(uid)) - _store.ToggleUi(msg.Session.AttachedEntity!.Value, uid, store); + _store.ToggleUi(msg.Actor, uid, store); } private void OnUiMessage(EntityUid uid, PdaComponent pda, PdaLockUplinkMessage msg) diff --git a/Content.Server/PDA/Ringer/RingerSystem.cs b/Content.Server/PDA/Ringer/RingerSystem.cs index f95725873ae..a10544d6966 100644 --- a/Content.Server/PDA/Ringer/RingerSystem.cs +++ b/Content.Server/PDA/Ringer/RingerSystem.cs @@ -81,7 +81,10 @@ private void UpdateRingerUserInterfaceDriver(EntityUid uid, RingerComponent ring private void OnSetRingtone(EntityUid uid, RingerComponent ringer, RingerSetRingtoneMessage args) { - ref var lastSetAt = ref CollectionsMarshal.GetValueRefOrAddDefault(_lastSetRingtoneAt, args.Session.UserId, out var exists); + if (!TryComp(args.Actor, out ActorComponent? actorComp)) + return; + + ref var lastSetAt = ref CollectionsMarshal.GetValueRefOrAddDefault(_lastSetRingtoneAt, actorComp.PlayerSession.UserId, out var exists); // Delay on the client is 0.333, 0.25 is still enough and gives some leeway in case of small time differences if (exists && lastSetAt > _gameTiming.CurTime - TimeSpan.FromMilliseconds(250)) @@ -111,7 +114,7 @@ private void OnSetUplinkRingtone(EntityUid uid, RingerUplinkComponent uplink, re // can't keep store open after locking it if (!uplink.Unlocked) - _ui.TryCloseAll(uid, StoreUiKey.Key); + _ui.CloseUi(uid, StoreUiKey.Key); // no saving the code to prevent meta click set on sus guys pda -> wewlad args.Handled = true; @@ -130,7 +133,7 @@ public void LockUplink(EntityUid uid, RingerUplinkComponent? uplink) return; uplink.Unlocked = false; - _ui.TryCloseAll(uid, StoreUiKey.Key); + _ui.CloseUi(uid, StoreUiKey.Key); } public void RandomizeRingtone(EntityUid uid, RingerComponent ringer, MapInitEvent args) @@ -181,14 +184,12 @@ private bool UpdateRingerRingtone(EntityUid uid, RingerComponent ringer, Note[] private void UpdateRingerUserInterface(EntityUid uid, RingerComponent ringer, bool isPlaying) { - if (_ui.TryGetUi(uid, RingerUiKey.Key, out var bui)) - _ui.SetUiState(bui, new RingerUpdateState(isPlaying, ringer.Ringtone)); + _ui.SetUiState(uid, RingerUiKey.Key, new RingerUpdateState(isPlaying, ringer.Ringtone)); } - public bool ToggleRingerUI(EntityUid uid, ICommonSession session) + public bool ToggleRingerUI(EntityUid uid, EntityUid actor) { - if (_ui.TryGetUi(uid, RingerUiKey.Key, out var bui)) - _ui.ToggleUi(bui, session); + _ui.TryToggleUi(uid, RingerUiKey.Key, actor); return true; } diff --git a/Content.Server/Paper/PaperComponent.cs b/Content.Server/Paper/PaperComponent.cs index 556a197fd4c..6c96b67acb4 100644 --- a/Content.Server/Paper/PaperComponent.cs +++ b/Content.Server/Paper/PaperComponent.cs @@ -3,7 +3,7 @@ namespace Content.Server.Paper; -[NetworkedComponent, RegisterComponent] +[RegisterComponent] public sealed partial class PaperComponent : SharedPaperComponent { public PaperAction Mode; diff --git a/Content.Server/Paper/PaperSystem.cs b/Content.Server/Paper/PaperSystem.cs index 27c94313b21..d9202341d55 100644 --- a/Content.Server/Paper/PaperSystem.cs +++ b/Content.Server/Paper/PaperSystem.cs @@ -67,11 +67,7 @@ private void OnInit(EntityUid uid, PaperComponent paperComp, ComponentInit args) private void BeforeUIOpen(EntityUid uid, PaperComponent paperComp, BeforeActivatableUIOpenEvent args) { paperComp.Mode = PaperAction.Read; - - if (!TryComp(args.User, out var actor)) - return; - - UpdateUserInterface(uid, paperComp, actor.PlayerSession); + UpdateUserInterface(uid, paperComp); } private void OnExamined(EntityUid uid, PaperComponent paperComp, ExaminedEvent args) @@ -108,12 +104,10 @@ private void OnInteractUsing(EntityUid uid, PaperComponent paperComp, InteractUs { var writeEvent = new PaperWriteEvent(uid, args.User); RaiseLocalEvent(args.Used, ref writeEvent); - if (!TryComp(args.User, out var actor)) - return; paperComp.Mode = PaperAction.Write; - _uiSystem.TryOpen(uid, PaperUiKey.Key, actor.PlayerSession); - UpdateUserInterface(uid, paperComp, actor.PlayerSession); + _uiSystem.OpenUi(uid, PaperUiKey.Key, args.User); + UpdateUserInterface(uid, paperComp); args.Handled = true; return; } @@ -157,9 +151,8 @@ private void OnInputTextMessage(EntityUid uid, PaperComponent paperComp, PaperIn if (TryComp(uid, out var meta)) _metaSystem.SetEntityDescription(uid, "", meta); - if (args.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Chat, LogImpact.Low, - $"{ToPrettyString(args.Session.AttachedEntity.Value):player} has written on {ToPrettyString(uid):entity} the following text: {args.Text}"); + _adminLogger.Add(LogType.Chat, LogImpact.Low, + $"{ToPrettyString(args.Actor):player} has written on {ToPrettyString(uid):entity} the following text: {args.Text}"); _audio.PlayPvs(paperComp.Sound, uid); } @@ -213,13 +206,12 @@ public void SetContent(EntityUid uid, string content, PaperComponent? paperComp _appearance.SetData(uid, PaperVisuals.Status, status, appearance); } - public void UpdateUserInterface(EntityUid uid, PaperComponent? paperComp = null, ICommonSession? session = null) + public void UpdateUserInterface(EntityUid uid, PaperComponent? paperComp = null) { if (!Resolve(uid, ref paperComp)) return; - if (_uiSystem.TryGetUi(uid, PaperUiKey.Key, out var bui)) - _uiSystem.SetUiState(bui, new PaperBoundUserInterfaceState(paperComp.Content, paperComp.StampedBy, paperComp.Mode), session); + _uiSystem.SetUiState(uid, PaperUiKey.Key, new PaperBoundUserInterfaceState(paperComp.Content, paperComp.StampedBy, paperComp.Mode)); } } diff --git a/Content.Server/Parallax/BiomeSystem.cs b/Content.Server/Parallax/BiomeSystem.cs index 83cf9b9cb2d..0543518dcc9 100644 --- a/Content.Server/Parallax/BiomeSystem.cs +++ b/Content.Server/Parallax/BiomeSystem.cs @@ -973,7 +973,7 @@ private void UnloadChunk(BiomeComponent component, EntityUid gridUid, MapGridCom /// /// Creates a simple planet setup for a map. /// - public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, int? seed = null, MetaDataComponent? metadata = null) + public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, int? seed = null, MetaDataComponent? metadata = null, Color? mapLight = null) { if (!Resolve(mapUid, ref metadata)) return; @@ -998,7 +998,7 @@ public void EnsurePlanet(EntityUid mapUid, BiomeTemplatePrototype biomeTemplate, // Lava: #A34931 var light = EnsureComp(mapUid); - light.AmbientLightColor = Color.FromHex("#D8B059"); + light.AmbientLightColor = mapLight ?? Color.FromHex("#D8B059"); Dirty(mapUid, light, metadata); var moles = new float[Atmospherics.AdjustedNumberOfGases]; diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs index 5d373652a97..f3cff9f2e72 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.ControlBox.cs @@ -67,7 +67,7 @@ public void Fire(EntityUid uid, TimeSpan curTime, ParticleAcceleratorControlBoxC FireEmitter(comp.StarboardEmitter!.Value, strength); } - public void SwitchOn(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SwitchOn(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; @@ -77,7 +77,7 @@ public void SwitchOn(EntityUid uid, ICommonSession? user = null, ParticleAcceler if (comp.Enabled || !comp.CanBeEnabled) return; - if (user?.AttachedEntity is { } player) + if (user is { } player) _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} has turned {ToPrettyString(uid)} on"); comp.Enabled = true; @@ -90,14 +90,14 @@ public void SwitchOn(EntityUid uid, ICommonSession? user = null, ParticleAcceler UpdateUI(uid, comp); } - public void SwitchOff(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SwitchOff(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; if (!comp.Enabled) return; - if (user?.AttachedEntity is { } player) + if (user is { } player) _adminLogger.Add(LogType.Action, LogImpact.Low, $"{ToPrettyString(player):player} has turned {ToPrettyString(uid)} off"); comp.Enabled = false; @@ -138,7 +138,7 @@ public void PowerOff(EntityUid uid, ParticleAcceleratorControlBoxComponent? comp UpdateUI(uid, comp); } - public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? comp = null) + public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? comp = null) { if (!Resolve(uid, ref comp)) return; @@ -154,7 +154,7 @@ public void SetStrength(EntityUid uid, ParticleAcceleratorPowerState strength, I if (strength == comp.SelectedStrength) return; - if (user?.AttachedEntity is { } player) + if (user is { } player) { var impact = strength switch { @@ -235,7 +235,8 @@ private void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? com { if (!Resolve(uid, ref comp)) return; - if (!_uiSystem.TryGetUi(uid, ParticleAcceleratorControlBoxUiKey.Key, out var bui)) + + if (!_uiSystem.HasUi(uid, ParticleAcceleratorControlBoxUiKey.Key)) return; var draw = 0f; @@ -247,7 +248,7 @@ private void UpdateUI(EntityUid uid, ParticleAcceleratorControlBoxComponent? com receive = powerConsumer.ReceivedPower; } - _uiSystem.SetUiState(bui, new ParticleAcceleratorUIState( + _uiSystem.SetUiState(uid, ParticleAcceleratorControlBoxUiKey.Key, new ParticleAcceleratorUIState( comp.Assembled, comp.Enabled, comp.SelectedStrength, @@ -346,7 +347,7 @@ private void OnControlBoxPowerChange(EntityUid uid, ParticleAcceleratorControlBo UpdateAppearance(uid, comp); if (!args.Powered) - _uiSystem.TryCloseAll(uid, ParticleAcceleratorControlBoxUiKey.Key); + _uiSystem.CloseUi(uid, ParticleAcceleratorControlBoxUiKey.Key); } private void OnUISetEnableMessage(EntityUid uid, ParticleAcceleratorControlBoxComponent comp, ParticleAcceleratorSetEnableMessage msg) @@ -361,10 +362,10 @@ private void OnUISetEnableMessage(EntityUid uid, ParticleAcceleratorControlBoxCo if (msg.Enabled) { if (comp.Assembled) - SwitchOn(uid, msg.Session, comp); + SwitchOn(uid, msg.Actor, comp); } else - SwitchOff(uid, msg.Session, comp); + SwitchOff(uid, msg.Actor, comp); UpdateUI(uid, comp); } @@ -378,7 +379,7 @@ private void OnUISetPowerMessage(EntityUid uid, ParticleAcceleratorControlBoxCom if (TryComp(uid, out var apcPower) && !apcPower.Powered) return; - SetStrength(uid, msg.State, msg.Session, comp); + SetStrength(uid, msg.State, msg.Actor, comp); UpdateUI(uid, comp); } @@ -392,7 +393,7 @@ private void OnUIRescanMessage(EntityUid uid, ParticleAcceleratorControlBoxCompo if (TryComp(uid, out var apcPower) && !apcPower.Powered) return; - RescanParts(uid, msg.Session, comp); + RescanParts(uid, msg.Actor, comp); UpdateUI(uid, comp); } diff --git a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs index bdbc7b3f5bc..99bb0d5cbda 100644 --- a/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs +++ b/Content.Server/ParticleAccelerator/EntitySystems/ParticleAcceleratorSystem.Parts.cs @@ -18,7 +18,7 @@ private void InitializePartSystem() SubscribeLocalEvent(BodyTypeChanged); } - public void RescanParts(EntityUid uid, ICommonSession? user = null, ParticleAcceleratorControlBoxComponent? controller = null) + public void RescanParts(EntityUid uid, EntityUid? user = null, ParticleAcceleratorControlBoxComponent? controller = null) { if (!Resolve(uid, ref controller)) return; diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs index 0cbd47c233a..0645944a2ac 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorLimiterWireAction.cs @@ -48,8 +48,7 @@ public override bool Mend(EntityUid user, Wire wire, ParticleAcceleratorControlB // Yes, it's a feature that mending this wire WON'T WORK if the strength wire is also cut. // Since that blocks SetStrength(). var paSystem = EntityManager.System(); - var userSession = EntityManager.TryGetComponent(user, out var actor) ? actor.PlayerSession : null; - paSystem.SetStrength(wire.Owner, controller.MaxStrength, userSession, controller); + paSystem.SetStrength(wire.Owner, controller.MaxStrength, user, controller); return true; } diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs index 65fa76ee413..1650960bd31 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorStrengthWireAction.cs @@ -33,7 +33,6 @@ public override bool Mend(EntityUid user, Wire wire, ParticleAcceleratorControlB public override void Pulse(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller) { var paSystem = EntityManager.System(); - var userSession = EntityManager.TryGetComponent(user, out var actor) ? actor.PlayerSession : null; - paSystem.SetStrength(wire.Owner, (ParticleAcceleratorPowerState) ((int) controller.SelectedStrength + 1), userSession, controller); + paSystem.SetStrength(wire.Owner, (ParticleAcceleratorPowerState) ((int) controller.SelectedStrength + 1), user, controller); } } diff --git a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs index c43403edd41..40a15d2bc50 100644 --- a/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs +++ b/Content.Server/ParticleAccelerator/Wires/ParticleAcceleratorToggleWireAction.cs @@ -23,10 +23,9 @@ public sealed partial class ParticleAcceleratorPowerWireAction : ComponentWireAc public override bool Cut(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller) { var paSystem = EntityManager.System(); - var userSession = EntityManager.TryGetComponent(user, out var actor) ? actor.PlayerSession : null; controller.CanBeEnabled = false; - paSystem.SwitchOff(wire.Owner, userSession, controller); + paSystem.SwitchOff(wire.Owner, user, controller); return true; } @@ -39,11 +38,10 @@ public override bool Mend(EntityUid user, Wire wire, ParticleAcceleratorControlB public override void Pulse(EntityUid user, Wire wire, ParticleAcceleratorControlBoxComponent controller) { var paSystem = EntityManager.System(); - var userSession = EntityManager.TryGetComponent(user, out var actor) ? actor.PlayerSession : null; if (controller.Enabled) - paSystem.SwitchOff(wire.Owner, userSession, controller); + paSystem.SwitchOff(wire.Owner, user, controller); else if (controller.Assembled) - paSystem.SwitchOn(wire.Owner, userSession, controller); + paSystem.SwitchOn(wire.Owner, user, controller); } } diff --git a/Content.Server/Pinpointer/NavMapSystem.cs b/Content.Server/Pinpointer/NavMapSystem.cs index aee8b901910..5881daa0689 100644 --- a/Content.Server/Pinpointer/NavMapSystem.cs +++ b/Content.Server/Pinpointer/NavMapSystem.cs @@ -1,61 +1,65 @@ -using System.Diagnostics.CodeAnalysis; using Content.Server.Administration.Logs; +using Content.Server.Atmos.Components; +using Content.Server.Atmos.EntitySystems; using Content.Server.Station.Systems; using Content.Server.Warps; using Content.Shared.Database; using Content.Shared.Examine; using Content.Shared.Localizations; +using Content.Shared.Maps; using Content.Shared.Pinpointer; -using Content.Shared.Tag; using JetBrains.Annotations; -using Robust.Server.GameObjects; -using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Physics; -using Robust.Shared.Physics.Components; +using Robust.Shared.Timing; +using System.Diagnostics.CodeAnalysis; namespace Content.Server.Pinpointer; /// /// Handles data to be used for in-grid map displays. /// -public sealed class NavMapSystem : SharedNavMapSystem +public sealed partial class NavMapSystem : SharedNavMapSystem { [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; - [Dependency] private readonly TagSystem _tags = default!; - [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly IMapManager _mapManager = default!; - [Dependency] private readonly TransformSystem _transform = default!; - - private EntityQuery _physicsQuery; - private EntityQuery _tagQuery; + [Dependency] private readonly IGameTiming _gameTiming = default!; + [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; public const float CloseDistance = 15f; public const float FarDistance = 30f; + private EntityQuery _airtightQuery; + private EntityQuery _gridQuery; + private EntityQuery _navQuery; + public override void Initialize() { base.Initialize(); - _physicsQuery = GetEntityQuery(); - _tagQuery = GetEntityQuery(); + var categories = Enum.GetNames(typeof(NavMapChunkType)).Length - 1; // -1 due to "Invalid" entry. + if (Categories != categories) + throw new Exception($"{nameof(Categories)} must be equal to the number of chunk types"); + + _airtightQuery = GetEntityQuery(); + _gridQuery = GetEntityQuery(); + _navQuery = GetEntityQuery(); - SubscribeLocalEvent(OnAnchorChange); - SubscribeLocalEvent(OnReAnchor); + // Initialization events SubscribeLocalEvent(OnStationInit); - SubscribeLocalEvent(OnNavMapStartup); - SubscribeLocalEvent(OnGetState); + + // Grid change events SubscribeLocalEvent(OnNavMapSplit); + SubscribeLocalEvent(OnTileChanged); + + SubscribeLocalEvent(OnAirtightChange); + // Beacon events SubscribeLocalEvent(OnNavMapBeaconMapInit); - SubscribeLocalEvent(OnNavMapBeaconStartup); SubscribeLocalEvent(OnNavMapBeaconAnchor); - - SubscribeLocalEvent(OnNavMapDoorStartup); - SubscribeLocalEvent(OnNavMapDoorAnchor); - SubscribeLocalEvent(OnConfigureMessage); SubscribeLocalEvent(OnConfigurableMapInit); SubscribeLocalEvent(OnConfigurableExamined); @@ -67,64 +71,137 @@ private void OnStationInit(StationGridAddedEvent ev) RefreshGrid(comp, Comp(ev.GridId)); } - private void OnNavMapBeaconMapInit(EntityUid uid, NavMapBeaconComponent component, MapInitEvent args) + #region: Grid change event handling + + private void OnNavMapSplit(ref GridSplitEvent args) { - if (component.DefaultText == null || component.Text != null) + if (!_navQuery.TryComp(args.Grid, out var comp)) return; - component.Text = Loc.GetString(component.DefaultText); - Dirty(uid, component); - RefreshNavGrid(uid); + foreach (var grid in args.NewGrids) + { + var newComp = EnsureComp(grid); + RefreshGrid(comp, newComp); + } + + RefreshGrid(comp, _gridQuery.GetComponent(args.Grid)); } - private void OnNavMapBeaconStartup(EntityUid uid, NavMapBeaconComponent component, ComponentStartup args) + private NavMapChunk EnsureChunk(NavMapComponent component, Vector2i origin) { - RefreshNavGrid(uid); + if (!component.Chunks.TryGetValue(origin, out var chunk)) + { + chunk = new(origin); + component.Chunks[origin] = chunk; + } + + return chunk; } - private void OnNavMapBeaconAnchor(EntityUid uid, NavMapBeaconComponent component, ref AnchorStateChangedEvent args) + private void OnTileChanged(ref TileChangedEvent ev) { - UpdateBeaconEnabledVisuals((uid, component)); - RefreshNavGrid(uid); + if (!ev.EmptyChanged || !_navQuery.TryComp(ev.NewTile.GridUid, out var navMap)) + return; + + var tile = ev.NewTile.GridIndices; + var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize); + + var chunk = EnsureChunk(navMap, chunkOrigin); + + // This could be easily replaced in the future to accommodate diagonal tiles + var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize); + ref var tileData = ref chunk.TileData[GetTileIndex(relative)]; + + if (ev.NewTile.IsSpace(_tileDefManager)) + { + tileData = 0; + if (PruneEmpty((ev.NewTile.GridUid, navMap), chunk)) + return; + } + else + { + tileData = FloorMask; + } + + DirtyChunk((ev.NewTile.GridUid, navMap), chunk); } - private void OnNavMapDoorStartup(Entity ent, ref ComponentStartup args) + private void DirtyChunk(Entity entity, NavMapChunk chunk) { - RefreshNavGrid(ent); + if (chunk.LastUpdate == _gameTiming.CurTick) + return; + + chunk.LastUpdate = _gameTiming.CurTick; + Dirty(entity); } - private void OnNavMapDoorAnchor(Entity ent, ref AnchorStateChangedEvent args) + private void OnAirtightChange(ref AirtightChanged args) { - RefreshNavGrid(ent); + if (args.AirBlockedChanged) + return; + + var gridUid = args.Position.Grid; + + if (!_navQuery.TryComp(gridUid, out var navMap) || + !_gridQuery.TryComp(gridUid, out var mapGrid)) + { + return; + } + + var chunkOrigin = SharedMapSystem.GetChunkIndices(args.Position.Tile, ChunkSize); + var (newValue, chunk) = RefreshTileEntityContents(gridUid, navMap, mapGrid, chunkOrigin, args.Position.Tile, setFloor: false); + + if (newValue == 0 && PruneEmpty((gridUid, navMap), chunk)) + return; + + DirtyChunk((gridUid, navMap), chunk); } - private void OnConfigureMessage(Entity ent, ref NavMapBeaconConfigureBuiMessage args) + #endregion + + #region: Beacon event handling + + private void OnNavMapBeaconMapInit(EntityUid uid, NavMapBeaconComponent component, MapInitEvent args) { - if (args.Session.AttachedEntity is not { } user) + if (component.DefaultText == null || component.Text != null) return; - if (!TryComp(ent, out var navMap)) + component.Text = Loc.GetString(component.DefaultText); + Dirty(uid, component); + + UpdateNavMapBeaconData(uid, component); + } + + private void OnNavMapBeaconAnchor(EntityUid uid, NavMapBeaconComponent component, ref AnchorStateChangedEvent args) + { + UpdateBeaconEnabledVisuals((uid, component)); + UpdateNavMapBeaconData(uid, component); + } + + private void OnConfigureMessage(Entity ent, ref NavMapBeaconConfigureBuiMessage args) + { + if (!TryComp(ent, out var beacon)) return; - if (navMap.Text == args.Text && - navMap.Color == args.Color && - navMap.Enabled == args.Enabled) + if (beacon.Text == args.Text && + beacon.Color == args.Color && + beacon.Enabled == args.Enabled) return; _adminLog.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(user):player} configured NavMapBeacon \'{ToPrettyString(ent):entity}\' with text \'{args.Text}\', color {args.Color.ToHexNoAlpha()}, and {(args.Enabled ? "enabled" : "disabled")} it."); + $"{ToPrettyString(args.Actor):player} configured NavMapBeacon \'{ToPrettyString(ent):entity}\' with text \'{args.Text}\', color {args.Color.ToHexNoAlpha()}, and {(args.Enabled ? "enabled" : "disabled")} it."); if (TryComp(ent, out var warpPoint)) { warpPoint.Location = args.Text; } - navMap.Text = args.Text; - navMap.Color = args.Color; - navMap.Enabled = args.Enabled; - UpdateBeaconEnabledVisuals((ent, navMap)); - Dirty(ent, navMap); - RefreshNavGrid(ent); + beacon.Text = args.Text; + beacon.Color = args.Color; + beacon.Enabled = args.Enabled; + + UpdateBeaconEnabledVisuals((ent, beacon)); + UpdateNavMapBeaconData(ent, beacon); } private void OnConfigurableMapInit(Entity ent, ref MapInitEvent args) @@ -134,9 +211,7 @@ private void OnConfigurableMapInit(Entity ent // We set this on mapinit just in case the text was edited via VV or something. if (TryComp(ent, out var warpPoint)) - { warpPoint.Location = navMap.Text; - } UpdateBeaconEnabledVisuals((ent, navMap)); } @@ -152,231 +227,117 @@ private void OnConfigurableExamined(Entity en ("label", navMap.Text ?? string.Empty))); } - private void UpdateBeaconEnabledVisuals(Entity ent) - { - _appearance.SetData(ent, NavMapBeaconVisuals.Enabled, ent.Comp.Enabled && Transform(ent).Anchored); - } - - /// - /// Refreshes the grid for the corresponding beacon. - /// - /// - private void RefreshNavGrid(EntityUid uid) - { - var xform = Transform(uid); - - if (!TryComp(xform.GridUid, out var navMap)) - return; + #endregion - Dirty(xform.GridUid.Value, navMap); - } + #region: Grid functions - private bool CanBeacon(EntityUid uid, TransformComponent? xform = null) - { - if (!Resolve(uid, ref xform)) - return false; - - return xform.GridUid != null && xform.Anchored; - } - - private void OnNavMapStartup(EntityUid uid, NavMapComponent component, ComponentStartup args) - { - if (!TryComp(uid, out var grid)) - return; - - RefreshGrid(component, grid); - } - - private void OnNavMapSplit(ref GridSplitEvent args) - { - if (!TryComp(args.Grid, out NavMapComponent? comp)) - return; - - var gridQuery = GetEntityQuery(); - - foreach (var grid in args.NewGrids) - { - var newComp = EnsureComp(grid); - RefreshGrid(newComp, gridQuery.GetComponent(grid)); - } - - RefreshGrid(comp, gridQuery.GetComponent(args.Grid)); - } - - private void RefreshGrid(NavMapComponent component, MapGridComponent grid) + private void RefreshGrid(NavMapComponent component, MapGridComponent mapGrid) { + // Clear stale data component.Chunks.Clear(); + component.Beacons.Clear(); - var tiles = grid.GetAllTilesEnumerator(); + // Loop over all tiles + var tileRefs = _mapSystem.GetAllTiles(mapGrid.Owner, mapGrid); - while (tiles.MoveNext(out var tile)) + foreach (var tileRef in tileRefs) { - var chunkOrigin = SharedMapSystem.GetChunkIndices(tile.Value.GridIndices, ChunkSize); + var tile = tileRef.GridIndices; + var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize); - if (!component.Chunks.TryGetValue(chunkOrigin, out var chunk)) - { - chunk = new NavMapChunk(chunkOrigin); - component.Chunks[chunkOrigin] = chunk; - } - - RefreshTile(grid, component, chunk, tile.Value.GridIndices); + var chunk = EnsureChunk(component, chunkOrigin); + chunk.LastUpdate = _gameTiming.CurTick; + RefreshTileEntityContents(mapGrid.Owner, component, mapGrid, chunkOrigin, tile, setFloor: true); } + + Dirty(mapGrid.Owner, component); } - private void OnGetState(EntityUid uid, NavMapComponent component, ref ComponentGetState args) + private (int NewVal, NavMapChunk Chunk) RefreshTileEntityContents(EntityUid uid, + NavMapComponent component, + MapGridComponent mapGrid, + Vector2i chunkOrigin, + Vector2i tile, + bool setFloor) { - if (!TryComp(uid, out var mapGrid)) - return; - - var data = new Dictionary(component.Chunks.Count); - foreach (var (index, chunk) in component.Chunks) - { - data.Add(index, chunk.TileData); - } + var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize); + var chunk = EnsureChunk(component, chunkOrigin); + ref var tileData = ref chunk.TileData[GetTileIndex(relative)]; - var beaconQuery = AllEntityQuery(); - var beacons = new List(); + // Clear all data except for floor bits + if (setFloor) + tileData = FloorMask; + else + tileData &= FloorMask; - while (beaconQuery.MoveNext(out var beaconUid, out var beacon, out var xform)) + var enumerator = _mapSystem.GetAnchoredEntitiesEnumerator(uid, mapGrid, tile); + while (enumerator.MoveNext(out var ent)) { - if (!beacon.Enabled || xform.GridUid != uid || !CanBeacon(beaconUid, xform)) + if (!_airtightQuery.TryComp(ent, out var airtight)) continue; - // TODO: Make warp points use metadata name instead. - string? name = beacon.Text; - - if (string.IsNullOrEmpty(name)) - { - if (TryComp(beaconUid, out var warpPoint) && warpPoint.Location != null) - { - name = warpPoint.Location; - } - else - { - name = MetaData(beaconUid).EntityName; - } - } - - beacons.Add(new NavMapBeacon(beacon.Color, name, xform.LocalPosition)); + var category = GetEntityType(ent.Value); + if (category == NavMapChunkType.Invalid) + continue; + + var directions = (int)airtight.AirBlockedDirection; + tileData |= directions << (int) category; } - var airlockQuery = EntityQueryEnumerator(); - var airlocks = new List(); - while (airlockQuery.MoveNext(out _, out _, out var xform)) - { - if (xform.GridUid != uid || !xform.Anchored) - continue; + // Remove walls that intersect with doors (unless they can both physically fit on the same tile) + // TODO NAVMAP why can this even happen? + // Is this for blast-doors or something? - var pos = _map.TileIndicesFor(uid, mapGrid, xform.Coordinates); - var enumerator = _map.GetAnchoredEntitiesEnumerator(uid, mapGrid, pos); - - var wallPresent = false; - while (enumerator.MoveNext(out var ent)) - { - if (!_physicsQuery.TryGetComponent(ent, out var body) || - !body.CanCollide || - !body.Hard || - body.BodyType != BodyType.Static || - !_tags.HasTag(ent.Value, "Wall", _tagQuery) && - !_tags.HasTag(ent.Value, "Window", _tagQuery)) - { - continue; - } - - wallPresent = true; - break; - } - - if (wallPresent) - continue; + // Shift airlock bits over to the wall bits + var shiftedAirlockBits = (tileData & AirlockMask) >> ((int) NavMapChunkType.Airlock - (int) NavMapChunkType.Wall); - airlocks.Add(new NavMapAirlock(xform.LocalPosition)); - } + // And then mask door bits + tileData &= ~shiftedAirlockBits; - // TODO: Diffs - args.State = new NavMapComponentState() - { - TileData = data, - Beacons = beacons, - Airlocks = airlocks - }; + return (tileData, chunk); } - private void OnReAnchor(ref ReAnchorEvent ev) + private bool PruneEmpty(Entity entity, NavMapChunk chunk) { - if (TryComp(ev.OldGrid, out var oldGrid) && - TryComp(ev.OldGrid, out var navMap)) + foreach (var val in chunk.TileData) { - var chunkOrigin = SharedMapSystem.GetChunkIndices(ev.TilePos, ChunkSize); - - if (navMap.Chunks.TryGetValue(chunkOrigin, out var chunk)) - { - RefreshTile(oldGrid, navMap, chunk, ev.TilePos); - } + // TODO NAVMAP SIMD + if (val != 0) + return false; } - HandleAnchor(ev.Xform); + entity.Comp.Chunks.Remove(chunk.Origin); + Dirty(entity); + return true; } - private void OnAnchorChange(ref AnchorStateChangedEvent ev) - { - HandleAnchor(ev.Transform); - } + #endregion - private void HandleAnchor(TransformComponent xform) + #region: Beacon functions + + private void UpdateNavMapBeaconData(EntityUid uid, NavMapBeaconComponent component, TransformComponent? xform = null) { - if (!TryComp(xform.GridUid, out var navMap) || - !TryComp(xform.GridUid, out var grid)) + if (!Resolve(uid, ref xform) + || xform.GridUid == null + || !_navQuery.TryComp(xform.GridUid, out var navMap)) return; - var tile = grid.LocalToTile(xform.Coordinates); - var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize); + var meta = MetaData(uid); + var changed = navMap.Beacons.Remove(meta.NetEntity); - if (!navMap.Chunks.TryGetValue(chunkOrigin, out var chunk)) + if (TryCreateNavMapBeaconData(uid, component, xform, meta, out var beaconData)) { - chunk = new NavMapChunk(chunkOrigin); - navMap.Chunks[chunkOrigin] = chunk; + navMap.Beacons.Add(meta.NetEntity, beaconData.Value); + changed = true; } - RefreshTile(grid, navMap, chunk, tile); + if (changed) + Dirty(xform.GridUid.Value, navMap); } - private void RefreshTile(MapGridComponent grid, NavMapComponent component, NavMapChunk chunk, Vector2i tile) + private void UpdateBeaconEnabledVisuals(Entity ent) { - var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize); - var existing = chunk.TileData; - var flag = GetFlag(relative); - - chunk.TileData &= ~flag; - - var enumerator = grid.GetAnchoredEntitiesEnumerator(tile); - // TODO: Use something to get convex poly. - - while (enumerator.MoveNext(out var ent)) - { - if (!_physicsQuery.TryGetComponent(ent, out var body) || - !body.CanCollide || - !body.Hard || - body.BodyType != BodyType.Static || - !_tags.HasTag(ent.Value, "Wall", _tagQuery) && - !_tags.HasTag(ent.Value, "Window", _tagQuery)) - { - continue; - } - - chunk.TileData |= flag; - break; - } - - if (chunk.TileData == 0) - { - component.Chunks.Remove(chunk.Origin); - } - - if (existing == chunk.TileData) - return; - - Dirty(component); + _appearance.SetData(ent, NavMapBeaconVisuals.Enabled, ent.Comp.Enabled && Transform(ent).Anchored); } /// @@ -389,9 +350,6 @@ public void SetBeaconEnabled(EntityUid uid, bool enabled, NavMapBeaconComponent? comp.Enabled = enabled; UpdateBeaconEnabledVisuals((uid, comp)); - Dirty(uid, comp); - - RefreshNavGrid(uid); } /// @@ -419,7 +377,7 @@ public bool TryGetNearestBeacon(Entity ent, if (!Resolve(ent, ref ent.Comp)) return false; - return TryGetNearestBeacon(_transform.GetMapCoordinates(ent, ent.Comp), out beacon, out beaconCoords); + return TryGetNearestBeacon(_transformSystem.GetMapCoordinates(ent, ent.Comp), out beacon, out beaconCoords); } /// @@ -446,7 +404,7 @@ public bool TryGetNearestBeacon(MapCoordinates coordinates, if (coordinates.MapId != xform.MapID) continue; - var coords = _transform.GetWorldPosition(xform); + var coords = _transformSystem.GetWorldPosition(xform); var distanceSquared = (coordinates.Position - coords).LengthSquared(); if (!float.IsInfinity(minDistance) && distanceSquared >= minDistance) continue; @@ -465,7 +423,7 @@ public string GetNearestBeaconString(Entity ent) if (!Resolve(ent, ref ent.Comp)) return Loc.GetString("nav-beacon-pos-no-beacons"); - return GetNearestBeaconString(_transform.GetMapCoordinates(ent, ent.Comp)); + return GetNearestBeaconString(_transformSystem.GetMapCoordinates(ent, ent.Comp)); } public string GetNearestBeaconString(MapCoordinates coordinates) @@ -494,11 +452,13 @@ public string GetNearestBeaconString(MapCoordinates coordinates) ? Loc.GetString("nav-beacon-pos-format-direction-mod-far") : string.Empty; - // we can null suppress the text being null because TRyGetNearestVisibleStationBeacon always gives us a beacon with not-null text. + // we can null suppress the text being null because TryGetNearestVisibleStationBeacon always gives us a beacon with not-null text. return Loc.GetString("nav-beacon-pos-format-direction", ("modifier", modifier), ("direction", ContentLocalizationManager.FormatDirection(adjustedDir).ToLowerInvariant()), ("color", beacon.Value.Comp.Color), ("marker", beacon.Value.Comp.Text!)); } + + #endregion } diff --git a/Content.Server/Pinpointer/StationMapSystem.cs b/Content.Server/Pinpointer/StationMapSystem.cs index c9db560fef0..b0b3141fb0e 100644 --- a/Content.Server/Pinpointer/StationMapSystem.cs +++ b/Content.Server/Pinpointer/StationMapSystem.cs @@ -24,29 +24,23 @@ public override void Initialize() private void OnStationMapClosed(EntityUid uid, StationMapComponent component, BoundUIClosedEvent args) { - if (!Equals(args.UiKey, StationMapUiKey.Key) || args.Session.AttachedEntity == null) + if (!Equals(args.UiKey, StationMapUiKey.Key)) return; - RemCompDeferred(args.Session.AttachedEntity.Value); + RemCompDeferred(args.Actor); } private void OnUserParentChanged(EntityUid uid, StationMapUserComponent component, ref EntParentChangedMessage args) { - if (TryComp(uid, out var actor)) - { - _ui.TryClose(component.Map, StationMapUiKey.Key, actor.PlayerSession); - } + _ui.CloseUi(component.Map, StationMapUiKey.Key, uid); } private void OnStationMapOpened(EntityUid uid, StationMapComponent component, BoundUIOpenedEvent args) { - if (args.Session.AttachedEntity == null) - return; - if (!_cell.TryUseActivatableCharge(uid)) return; - var comp = EnsureComp(args.Session.AttachedEntity.Value); + var comp = EnsureComp(args.Actor); comp.Map = uid; } } diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs index 02d57803154..943b4cf7868 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingManager.cs @@ -317,7 +317,7 @@ public async Task LoadData(ICommonSession session, CancellationToken cancel) var data = new PlayTimeData(); _playTimeData.Add(session, data); - var playTimes = await _db.GetPlayTimes(session.UserId); + var playTimes = await _db.GetPlayTimes(session.UserId, cancel); cancel.ThrowIfCancellationRequested(); foreach (var timer in playTimes) diff --git a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs index de532351985..14eefbd6b87 100644 --- a/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs +++ b/Content.Server/Players/PlayTimeTracking/PlayTimeTrackingSystem.cs @@ -1,4 +1,6 @@ using System.Linq; +using Content.Server.Administration; +using Content.Server.Administration.Managers; using Content.Server.Afk; using Content.Server.Afk.Events; using Content.Server.GameTicking; @@ -34,6 +36,7 @@ public sealed class PlayTimeTrackingSystem : EntitySystem [Dependency] private readonly IConfigurationManager _cfg = default!; [Dependency] private readonly MindSystem _minds = default!; [Dependency] private readonly PlayTimeTrackingManager _tracking = default!; + [Dependency] private readonly IAdminManager _adminManager = default!; [Dependency] private readonly CharacterRequirementsSystem _characterRequirements = default!; [Dependency] private readonly IServerPreferencesManager _prefs = default!; [Dependency] private readonly IConfigurationManager _config = default!; @@ -54,6 +57,7 @@ public override void Initialize() SubscribeLocalEvent(OnUnAFK); SubscribeLocalEvent(OnMobStateChanged); SubscribeLocalEvent(OnPlayerJoinedLobby); + _adminManager.OnPermsChanged += AdminPermsChanged; } public override void Shutdown() @@ -61,6 +65,7 @@ public override void Shutdown() base.Shutdown(); _tracking.CalcTrackers -= CalcTrackers; + _adminManager.OnPermsChanged -= AdminPermsChanged; } private void CalcTrackers(ICommonSession player, HashSet trackers) @@ -68,6 +73,13 @@ private void CalcTrackers(ICommonSession player, HashSet trackers) if (_afk.IsAfk(player)) return; + if (_adminManager.IsAdmin(player)) + { + trackers.Add(PlayTimeTrackingShared.TrackerAdmin); + trackers.Add(PlayTimeTrackingShared.TrackerOverall); + return; + } + if (!IsPlayerAlive(player)) return; @@ -138,6 +150,11 @@ private void OnAFK(ref AFKEvent ev) _tracking.QueueRefreshTrackers(ev.Session); } + private void AdminPermsChanged(AdminPermsChangedEventArgs admin) + { + _tracking.QueueRefreshTrackers(admin.Player); + } + private void OnPlayerAttached(PlayerAttachedEvent ev) { _tracking.QueueRefreshTrackers(ev.Player); diff --git a/Content.Server/Polymorph/Systems/ChameleonProjectorSystem.cs b/Content.Server/Polymorph/Systems/ChameleonProjectorSystem.cs new file mode 100644 index 00000000000..1586973a21e --- /dev/null +++ b/Content.Server/Polymorph/Systems/ChameleonProjectorSystem.cs @@ -0,0 +1,99 @@ +using Content.Server.Polymorph.Components; +using Content.Shared.Actions; +using Content.Shared.Construction.Components; +using Content.Shared.Hands; +using Content.Shared.Mobs; +using Content.Shared.Mobs.Components; +using Content.Shared.Mobs.Systems; +using Content.Shared.Polymorph; +using Content.Shared.Polymorph.Components; +using Content.Shared.Polymorph.Systems; +using Content.Shared.StatusIcon.Components; +using Robust.Shared.Physics.Components; + +namespace Content.Server.Polymorph.Systems; + +public sealed class ChameleonProjectorSystem : SharedChameleonProjectorSystem +{ + [Dependency] private readonly MetaDataSystem _meta = default!; + [Dependency] private readonly MobThresholdSystem _mobThreshold = default!; + [Dependency] private readonly PolymorphSystem _polymorph = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedTransformSystem _xform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnEquippedHand); + SubscribeLocalEvent(OnToggleNoRot); + SubscribeLocalEvent(OnToggleAnchored); + } + + private void OnEquippedHand(Entity ent, ref GotEquippedHandEvent args) + { + if (!TryComp(ent, out var poly)) + return; + + _polymorph.Revert((ent, poly)); + args.Handled = true; + } + + public override void Disguise(ChameleonProjectorComponent proj, EntityUid user, EntityUid entity) + { + if (_polymorph.PolymorphEntity(user, proj.Polymorph) is not {} disguise) + return; + + // make disguise look real (for simple things at least) + var meta = MetaData(entity); + _meta.SetEntityName(disguise, meta.EntityName); + _meta.SetEntityDescription(disguise, meta.EntityDescription); + + var comp = EnsureComp(disguise); + comp.SourceEntity = entity; + comp.SourceProto = Prototype(entity)?.ID; + Dirty(disguise, comp); + + // no sechud trolling + RemComp(disguise); + + _appearance.CopyData(entity, disguise); + + var mass = CompOrNull(entity)?.Mass ?? 0f; + + // let the disguise die when its taken enough damage, which then transfers to the player + // health is proportional to mass, and capped to not be insane + if (TryComp(disguise, out var thresholds)) + { + // if the player is of flesh and blood, cap max health to theirs + // so that when reverting damage scales 1:1 and not round removing + var playerMax = _mobThreshold.GetThresholdForState(user, MobState.Dead).Float(); + var max = playerMax == 0f ? proj.MaxHealth : Math.Max(proj.MaxHealth, playerMax); + + var health = Math.Clamp(mass, proj.MinHealth, proj.MaxHealth); + _mobThreshold.SetMobStateThreshold(disguise, health, MobState.Critical, thresholds); + _mobThreshold.SetMobStateThreshold(disguise, max, MobState.Dead, thresholds); + } + + // add actions for controlling transform aspects + _actions.AddAction(disguise, proj.NoRotAction); + _actions.AddAction(disguise, proj.AnchorAction); + } + + private void OnToggleNoRot(Entity ent, ref DisguiseToggleNoRotEvent args) + { + var xform = Transform(ent); + xform.NoLocalRotation = !xform.NoLocalRotation; + } + + private void OnToggleAnchored(Entity ent, ref DisguiseToggleAnchoredEvent args) + { + var uid = ent.Owner; + var xform = Transform(uid); + if (xform.Anchored) + _xform.Unanchor(uid, xform); + else + _xform.AnchorEntity((uid, xform)); + } +} diff --git a/Content.Server/Polymorph/Systems/PolymorphSystem.cs b/Content.Server/Polymorph/Systems/PolymorphSystem.cs index 8cae15d70df..e6ba1d02afd 100644 --- a/Content.Server/Polymorph/Systems/PolymorphSystem.cs +++ b/Content.Server/Polymorph/Systems/PolymorphSystem.cs @@ -199,7 +199,7 @@ private void OnDestruction(Entity ent, ref Destructi var targetTransformComp = Transform(uid); - var child = Spawn(configuration.Entity, targetTransformComp.Coordinates); + var child = Spawn(configuration.Entity, _transform.GetMapCoordinates(uid, targetTransformComp), rotation: _transform.GetWorldRotation(uid)); MakeSentientCommand.MakeSentient(child, EntityManager); diff --git a/Content.Server/Popups/PopupSystem.cs b/Content.Server/Popups/PopupSystem.cs index d1163a2be1b..4aa3d39224c 100644 --- a/Content.Server/Popups/PopupSystem.cs +++ b/Content.Server/Popups/PopupSystem.cs @@ -88,11 +88,19 @@ public override void PopupEntity(string? message, EntityUid uid, EntityUid recip RaiseNetworkEvent(new PopupEntityEvent(message, type, GetNetEntity(uid)), actor.PlayerSession); } + public override void PopupClient(string? message, EntityUid? recipient, PopupType type = PopupType.Small) + { + } + public override void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small) { // do nothing duh its for client only } + public override void PopupClient(string? message, EntityCoordinates coordinates, EntityUid? recipient, PopupType type = PopupType.Small) + { + } + public override void PopupEntity(string? message, EntityUid uid, ICommonSession recipient, PopupType type = PopupType.Small) { if (message == null) diff --git a/Content.Server/Power/Components/ActivatableUIRequiresPowerComponent.cs b/Content.Server/Power/Components/ActivatableUIRequiresPowerComponent.cs deleted file mode 100644 index c387457adba..00000000000 --- a/Content.Server/Power/Components/ActivatableUIRequiresPowerComponent.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Content.Server.Power.Components -{ - [RegisterComponent] - public sealed partial class ActivatableUIRequiresPowerComponent : Component - { - } -} - diff --git a/Content.Server/Power/Components/ChargerComponent.cs b/Content.Server/Power/Components/ChargerComponent.cs index af4498f01ba..e45ded071cf 100644 --- a/Content.Server/Power/Components/ChargerComponent.cs +++ b/Content.Server/Power/Components/ChargerComponent.cs @@ -1,5 +1,10 @@ using Content.Shared.Power; using Content.Shared.Whitelist; +using Content.Shared.Power; +using Content.Shared.Whitelist; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization.Manager.Attributes; +using Robust.Shared.ViewVariables; namespace Content.Server.Power.Components { @@ -26,5 +31,12 @@ public sealed partial class ChargerComponent : Component /// [DataField("whitelist")] public EntityWhitelist? Whitelist; + + /// + /// Indicates whether the charger is portable and thus subject to EMP effects + /// and bypasses checks for transform, anchored, and ApcPowerReceiverComponent. + /// + [DataField] + public bool Portable = false; } } diff --git a/Content.Server/Power/Components/SiliconEmitSoundOnDrainedComponent.cs b/Content.Server/Power/Components/SiliconEmitSoundOnDrainedComponent.cs index 5740d7822d0..481311d9681 100644 --- a/Content.Server/Power/Components/SiliconEmitSoundOnDrainedComponent.cs +++ b/Content.Server/Power/Components/SiliconEmitSoundOnDrainedComponent.cs @@ -1,4 +1,6 @@ using Robust.Shared.Audio; +using Content.Server.Sound.Components; +using Content.Shared.Sound.Components; namespace Content.Server.Silicon; diff --git a/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs b/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs index 561b0e71f09..72843a65b84 100644 --- a/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs +++ b/Content.Server/Power/EntitySystems/ActivatableUIRequiresPowerSystem.cs @@ -4,11 +4,12 @@ using JetBrains.Annotations; using Content.Shared.Wires; using Content.Server.UserInterface; +using Content.Shared.Power.Components; +using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem; namespace Content.Server.Power.EntitySystems; -[UsedImplicitly] -internal sealed class ActivatableUIRequiresPowerSystem : EntitySystem +public sealed class ActivatableUIRequiresPowerSystem : EntitySystem { [Dependency] private readonly ActivatableUISystem _activatableUI = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; diff --git a/Content.Server/Power/EntitySystems/ApcSystem.cs b/Content.Server/Power/EntitySystems/ApcSystem.cs index f345c9e88ea..a449f3555ac 100644 --- a/Content.Server/Power/EntitySystems/ApcSystem.cs +++ b/Content.Server/Power/EntitySystems/ApcSystem.cs @@ -68,11 +68,8 @@ private void OnApcInit(EntityUid uid, ApcComponent component, MapInitEvent args) //Update the HasAccess var for UI to read private void OnBoundUiOpen(EntityUid uid, ApcComponent component, BoundUIOpenedEvent args) { - if (args.Session.AttachedEntity == null) - return; - // TODO: this should be per-player not stored on the apc - component.HasAccess = _accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid); + component.HasAccess = _accessReader.IsAllowed(args.Actor, uid); UpdateApcState(uid, component); } @@ -83,21 +80,18 @@ private void OnToggleMainBreaker(EntityUid uid, ApcComponent component, ApcToggl if (attemptEv.Cancelled) { _popup.PopupCursor(Loc.GetString("apc-component-on-toggle-cancel"), - args.Session, PopupType.Medium); + args.Actor, PopupType.Medium); return; } - if (args.Session.AttachedEntity == null) - return; - - if (_accessReader.IsAllowed(args.Session.AttachedEntity.Value, uid)) + if (_accessReader.IsAllowed(args.Actor, uid)) { ApcToggleBreaker(uid, component); } else { _popup.PopupCursor(Loc.GetString("apc-component-insufficient-access"), - args.Session, PopupType.Medium); + args.Actor, PopupType.Medium); } } @@ -160,7 +154,7 @@ public void UpdateUIState(EntityUid uid, (int) MathF.Ceiling(battery.CurrentSupply), apc.LastExternalState, battery.CurrentStorage / battery.Capacity); - _ui.TrySetUiState(uid, ApcUiKey.Key, state, ui: ui); + _ui.SetUiState((uid, ui), ApcUiKey.Key, state); } private ApcChargeState CalcChargeState(EntityUid uid, PowerState.Battery battery) diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs index db16dfa008e..1ff13a24f2c 100644 --- a/Content.Server/Power/EntitySystems/ChargerSystem.cs +++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs @@ -1,8 +1,10 @@ using Content.Server.Power.Components; +using Content.Server.Emp; using Content.Server.PowerCell; using Content.Shared.Examine; using Content.Shared.Power; using Content.Shared.PowerCell.Components; +using Content.Shared.Emp; using JetBrains.Annotations; using Robust.Shared.Containers; using System.Diagnostics.CodeAnalysis; @@ -28,6 +30,8 @@ public override void Initialize() SubscribeLocalEvent(OnInsertAttempt); SubscribeLocalEvent(OnEntityStorageInsertAttempt); SubscribeLocalEvent(OnChargerExamine); + + SubscribeLocalEvent(OnEmpPulse); } private void OnStartup(EntityUid uid, ChargerComponent component, ComponentStartup args) @@ -158,18 +162,27 @@ private void UpdateStatus(EntityUid uid, ChargerComponent component) } } + private void OnEmpPulse(EntityUid uid, ChargerComponent component, ref EmpPulseEvent args) + { + args.Affected = true; + args.Disabled = true; + } + private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component) { - if (!TryComp(uid, out TransformComponent? transformComponent)) - return CellChargerStatus.Off; + if (!component.Portable) + { + if (!TryComp(uid, out TransformComponent? transformComponent) || !transformComponent.Anchored) + return CellChargerStatus.Off; + } - if (!transformComponent.Anchored) + if (!TryComp(uid, out ApcPowerReceiverComponent? apcPowerReceiverComponent)) return CellChargerStatus.Off; - if (!TryComp(uid, out ApcPowerReceiverComponent? apcPowerReceiverComponent)) + if (!component.Portable && !apcPowerReceiverComponent.Powered) return CellChargerStatus.Off; - if (!apcPowerReceiverComponent.Powered) + if (HasComp(uid)) return CellChargerStatus.Off; if (!_container.TryGetContainer(uid, component.SlotId, out var container)) @@ -186,7 +199,7 @@ private CellChargerStatus GetStatus(EntityUid uid, ChargerComponent component) return CellChargerStatus.Charging; } - + private void TransferPower(EntityUid uid, EntityUid targetEntity, ChargerComponent component, float frameTime) { if (!TryComp(uid, out ApcPowerReceiverComponent? receiverComponent)) diff --git a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs index 0e20f007d71..42c84b7f43b 100644 --- a/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs +++ b/Content.Server/Power/EntitySystems/PowerMonitoringConsoleSystem.cs @@ -1,7 +1,5 @@ -using Content.Server.GameTicking.Rules.Components; using Content.Server.NodeContainer; using Content.Server.NodeContainer.EntitySystems; -using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; using Content.Server.Power.Nodes; @@ -13,10 +11,8 @@ using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Map.Components; -using Robust.Shared.Player; using Robust.Shared.Utility; using System.Linq; -using System.Diagnostics.CodeAnalysis; using Content.Server.GameTicking.Components; namespace Content.Server.Power.EntitySystems; @@ -163,7 +159,7 @@ public void OnCableAnchorStateChanged(EntityUid uid, CableComponent component, C allChunks = new(); var tile = _sharedMapSystem.LocalToTile(xform.GridUid.Value, grid, xform.Coordinates); - var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, SharedNavMapSystem.ChunkSize); + var chunkOrigin = SharedMapSystem.GetChunkIndices(tile, ChunkSize); if (!allChunks.TryGetValue(chunkOrigin, out var chunk)) { @@ -171,8 +167,8 @@ public void OnCableAnchorStateChanged(EntityUid uid, CableComponent component, C allChunks[chunkOrigin] = chunk; } - var relative = SharedMapSystem.GetChunkRelative(tile, SharedNavMapSystem.ChunkSize); - var flag = SharedNavMapSystem.GetFlag(relative); + var relative = SharedMapSystem.GetChunkRelative(tile, ChunkSize); + var flag = GetFlag(relative); if (args.Anchored) chunk.PowerCableData[(int) component.CableType] |= flag; @@ -286,20 +282,17 @@ public override void Update(float frameTime) var query = AllEntityQuery(); while (query.MoveNext(out var ent, out var console)) { - if (!_userInterfaceSystem.TryGetUi(ent, PowerMonitoringConsoleUiKey.Key, out var bui)) + if (!_userInterfaceSystem.IsUiOpen(ent, PowerMonitoringConsoleUiKey.Key)) continue; - foreach (var session in bui.SubscribedSessions) - UpdateUIState(ent, console, session); + UpdateUIState(ent, console); + } } } - public void UpdateUIState(EntityUid uid, PowerMonitoringConsoleComponent component, ICommonSession session) + private void UpdateUIState(EntityUid uid, PowerMonitoringConsoleComponent component) { - if (!_userInterfaceSystem.TryGetUi(uid, PowerMonitoringConsoleUiKey.Key, out var bui)) - return; - var consoleXform = Transform(uid); if (consoleXform?.GridUid == null) @@ -422,15 +415,15 @@ public void UpdateUIState(EntityUid uid, PowerMonitoringConsoleComponent compone } // Set the UI state - _userInterfaceSystem.SetUiState(bui, + _userInterfaceSystem.SetUiState(uid, + PowerMonitoringConsoleUiKey.Key, new PowerMonitoringConsoleBoundInterfaceState (totalSources, totalBatteryUsage, totalLoads, allEntries.ToArray(), sourcesForFocus.ToArray(), - loadsForFocus.ToArray()), - session); + loadsForFocus.ToArray())); } private double GetPrimaryPowerValues(EntityUid uid, PowerMonitoringDeviceComponent device, out double powerSupplied, out double powerUsage, out double batteryUsage) @@ -887,7 +880,7 @@ private Dictionary RefreshPowerCableGrid(EntityUid gr continue; var tile = _sharedMapSystem.GetTileRef(gridUid, grid, entXform.Coordinates); - var chunkOrigin = SharedMapSystem.GetChunkIndices(tile.GridIndices, SharedNavMapSystem.ChunkSize); + var chunkOrigin = SharedMapSystem.GetChunkIndices(tile.GridIndices, ChunkSize); if (!allChunks.TryGetValue(chunkOrigin, out var chunk)) { @@ -895,8 +888,8 @@ private Dictionary RefreshPowerCableGrid(EntityUid gr allChunks[chunkOrigin] = chunk; } - var relative = SharedMapSystem.GetChunkRelative(tile.GridIndices, SharedNavMapSystem.ChunkSize); - var flag = SharedNavMapSystem.GetFlag(relative); + var relative = SharedMapSystem.GetChunkRelative(tile.GridIndices, ChunkSize); + var flag = GetFlag(relative); chunk.PowerCableData[(int) cable.CableType] |= flag; } @@ -913,7 +906,7 @@ private void UpdateFocusNetwork(EntityUid uid, PowerMonitoringCableNetworksCompo var xform = Transform(ent); var tile = _sharedMapSystem.GetTileRef(gridUid, grid, xform.Coordinates); var gridIndices = tile.GridIndices; - var chunkOrigin = SharedMapSystem.GetChunkIndices(gridIndices, SharedNavMapSystem.ChunkSize); + var chunkOrigin = SharedMapSystem.GetChunkIndices(gridIndices, ChunkSize); if (!component.FocusChunks.TryGetValue(chunkOrigin, out var chunk)) { @@ -921,8 +914,8 @@ private void UpdateFocusNetwork(EntityUid uid, PowerMonitoringCableNetworksCompo component.FocusChunks[chunkOrigin] = chunk; } - var relative = SharedMapSystem.GetChunkRelative(gridIndices, SharedNavMapSystem.ChunkSize); - var flag = SharedNavMapSystem.GetFlag(relative); + var relative = SharedMapSystem.GetChunkRelative(gridIndices, ChunkSize); + var flag = GetFlag(relative); if (TryComp(ent, out var cable)) chunk.PowerCableData[(int) cable.CableType] |= flag; diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs index 3510a3da45d..540bd6c4832 100644 --- a/Content.Server/Power/Generation/Teg/TegSystem.cs +++ b/Content.Server/Power/Generation/Teg/TegSystem.cs @@ -7,6 +7,7 @@ using Content.Server.NodeContainer; using Content.Server.NodeContainer.Nodes; using Content.Server.Power.Components; +using Content.Shared.Atmos; using Content.Shared.DeviceNetwork; using Content.Shared.Examine; using Content.Shared.Power.Generation.Teg; diff --git a/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs b/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs index cd85e67221c..359c31d75bb 100644 --- a/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs +++ b/Content.Server/Power/Generator/GeneratorExhaustGasSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos; using Content.Server.Atmos.EntitySystems; +using Content.Shared.Atmos; using Content.Shared.Power.Generator; namespace Content.Server.Power.Generator; diff --git a/Content.Server/Power/Generator/GeneratorSignalControlComponent.cs b/Content.Server/Power/Generator/GeneratorSignalControlComponent.cs index f16a09eae37..19ae0bd6876 100644 --- a/Content.Server/Power/Generator/GeneratorSignalControlComponent.cs +++ b/Content.Server/Power/Generator/GeneratorSignalControlComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.DeviceLinking; +using Content.Shared.Power.Generator; using Robust.Shared.Prototypes; namespace Content.Server.Power.Generator; diff --git a/Content.Server/Power/Generator/PortableGeneratorSystem.cs b/Content.Server/Power/Generator/PortableGeneratorSystem.cs index e7dfa351789..e2996a54d71 100644 --- a/Content.Server/Power/Generator/PortableGeneratorSystem.cs +++ b/Content.Server/Power/Generator/PortableGeneratorSystem.cs @@ -48,30 +48,21 @@ public override void Initialize() private void GeneratorSwitchOutputMessage(EntityUid uid, PortableGeneratorComponent component, PortableGeneratorSwitchOutputMessage args) { - if (args.Session.AttachedEntity == null) - return; - var fuelGenerator = Comp(uid); if (fuelGenerator.On) return; - _switchable.Cycle(uid, args.Session.AttachedEntity.Value); + _switchable.Cycle(uid, args.Actor); } private void GeneratorStopMessage(EntityUid uid, PortableGeneratorComponent component, PortableGeneratorStopMessage args) { - if (args.Session.AttachedEntity == null) - return; - - StopGenerator(uid, component, args.Session.AttachedEntity.Value); + StopGenerator(uid, component, args.Actor); } private void GeneratorStartMessage(EntityUid uid, PortableGeneratorComponent component, PortableGeneratorStartMessage args) { - if (args.Session.AttachedEntity == null) - return; - - StartGenerator(uid, component, args.Session.AttachedEntity.Value); + StartGenerator(uid, component, args.Actor); } private void StartGenerator(EntityUid uid, PortableGeneratorComponent component, EntityUid user) @@ -234,7 +225,7 @@ private void UpdateUI( if (powerSupplier.Net is { IsConnectedNetwork: true } net) networkStats = (net.NetworkNode.LastCombinedLoad, net.NetworkNode.LastCombinedSupply); - _uiSystem.TrySetUiState( + _uiSystem.SetUiState( uid, GeneratorComponentUiKey.Key, new PortableGeneratorComponentBuiState(fuelComp, fuel, clogged, networkStats)); diff --git a/Content.Server/PowerCell/PowerCellSystem.cs b/Content.Server/PowerCell/PowerCellSystem.cs index d4c1faa4c9d..f45a01b2e1b 100644 --- a/Content.Server/PowerCell/PowerCellSystem.cs +++ b/Content.Server/PowerCell/PowerCellSystem.cs @@ -11,6 +11,7 @@ using Content.Server.UserInterface; using Content.Shared.Containers.ItemSlots; using Content.Shared.Popups; +using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem; namespace Content.Server.PowerCell; diff --git a/Content.Server/Prayer/PrayerSystem.cs b/Content.Server/Prayer/PrayerSystem.cs index f5051741c03..c8ef368dadf 100644 --- a/Content.Server/Prayer/PrayerSystem.cs +++ b/Content.Server/Prayer/PrayerSystem.cs @@ -39,7 +39,7 @@ private void AddPrayVerb(EntityUid uid, PrayableComponent comp, GetVerbsEvent(curPrefs.Characters) { @@ -192,23 +194,32 @@ public async Task LoadData(ICommonSession session, CancellationToken cancel) async Task LoadPrefs() { - var prefs = await GetOrCreatePreferencesAsync(session.UserId); + var prefs = await GetOrCreatePreferencesAsync(session.UserId, cancel); prefsData.Prefs = prefs; - prefsData.PrefsLoaded = true; - - var msg = new MsgPreferencesAndSettings - { - Preferences = prefs, - Settings = new GameSettings - { - MaxCharacterSlots = MaxCharacterSlots - } - }; - _netManager.ServerSendMessage(msg, session.Channel); } } } + public void FinishLoad(ICommonSession session) + { + // This is a separate step from the actual database load. + // Sanitizing preferences requires play time info due to loadouts. + // And play time info is loaded concurrently from the DB with preferences. + var prefsData = _cachedPlayerPrefs[session.UserId]; + DebugTools.Assert(prefsData.Prefs != null); + prefsData.Prefs = SanitizePreferences(session, prefsData.Prefs, _dependencies); + + prefsData.PrefsLoaded = true; + + var msg = new MsgPreferencesAndSettings(); + msg.Preferences = prefsData.Prefs; + msg.Settings = new GameSettings + { + MaxCharacterSlots = MaxCharacterSlots + }; + _netManager.ServerSendMessage(msg, session.Channel); + } + public void OnClientDisconnected(ICommonSession session) { _cachedPlayerPrefs.Remove(session.UserId); @@ -267,18 +278,15 @@ public PlayerPreferences GetPreferences(NetUserId userId) return null; } - private async Task GetOrCreatePreferencesAsync(NetUserId userId) + private async Task GetOrCreatePreferencesAsync(NetUserId userId, CancellationToken cancel) { - var prefs = await _db.GetPlayerPreferencesAsync(userId); + var prefs = await _db.GetPlayerPreferencesAsync(userId, cancel); if (prefs is null) { - return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random()); + return await _db.InitPrefsAsync(userId, HumanoidCharacterProfile.Random(), cancel); } - var session = _playerManager.GetSessionById(userId); - var collection = IoCManager.Instance!; - - return SanitizePreferences(session, prefs, collection); + return prefs; } private PlayerPreferences SanitizePreferences(ICommonSession session, PlayerPreferences prefs, diff --git a/Content.Server/Radio/Components/RadioJammerComponent.cs b/Content.Server/Radio/Components/RadioJammerComponent.cs deleted file mode 100644 index 93504ef9573..00000000000 --- a/Content.Server/Radio/Components/RadioJammerComponent.cs +++ /dev/null @@ -1,20 +0,0 @@ -using Content.Server.Radio.EntitySystems; - -namespace Content.Server.Radio.Components; - -/// -/// When activated () prevents from sending messages in range -/// -[RegisterComponent] -[Access(typeof(JammerSystem))] -public sealed partial class RadioJammerComponent : Component -{ - [DataField("range"), ViewVariables(VVAccess.ReadWrite)] - public float Range = 8f; - - /// - /// Power usage per second when enabled - /// - [DataField("wattage"), ViewVariables(VVAccess.ReadWrite)] - public float Wattage = 2f; -} diff --git a/Content.Server/Radio/EntitySystems/JammerSystem.cs b/Content.Server/Radio/EntitySystems/JammerSystem.cs index bba8c4766e6..6e0689390e1 100644 --- a/Content.Server/Radio/EntitySystems/JammerSystem.cs +++ b/Content.Server/Radio/EntitySystems/JammerSystem.cs @@ -1,27 +1,22 @@ using Content.Server.DeviceNetwork.Components; -using Content.Server.DeviceNetwork.Systems; -using Content.Server.Medical.CrewMonitoring; using Content.Server.Medical.SuitSensors; -using Content.Server.Popups; using Content.Server.Power.EntitySystems; using Content.Server.PowerCell; using Content.Server.Radio.Components; -using Content.Server.Station.Systems; using Content.Shared.DeviceNetwork.Components; using Content.Shared.Examine; using Content.Shared.Interaction; using Content.Shared.PowerCell.Components; +using Content.Shared.RadioJammer; +using Content.Shared.Radio.EntitySystems; namespace Content.Server.Radio.EntitySystems; -public sealed class JammerSystem : EntitySystem +public sealed class JammerSystem : SharedJammerSystem { [Dependency] private readonly PowerCellSystem _powerCell = default!; [Dependency] private readonly BatterySystem _battery = default!; - [Dependency] private readonly PopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; - [Dependency] private readonly StationSystem _stationSystem = default!; - [Dependency] private readonly SingletonDeviceNetServerSystem _singletonServerSystem = default!; public override void Initialize() { @@ -37,14 +32,37 @@ public override void Initialize() public override void Update(float frameTime) { var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var _, out var jam)) { - if (_powerCell.TryGetBatteryFromSlot(uid, out var batteryUid, out var battery) && - !_battery.TryUseCharge(batteryUid.Value, jam.Wattage * frameTime, battery)) + + if (_powerCell.TryGetBatteryFromSlot(uid, out var batteryUid, out var battery)) { - RemComp(uid); - RemComp(uid); + if (!_battery.TryUseCharge(batteryUid.Value, GetCurrentWattage(jam) * frameTime, battery)) + { + ChangeLEDState(false, uid); + RemComp(uid); + RemComp(uid); + } + else + { + var percentCharged = battery.CurrentCharge / battery.MaxCharge; + if (percentCharged > .50) + { + ChangeChargeLevel(RadioJammerChargeLevel.High, uid); + } + else if (percentCharged < .15) + { + ChangeChargeLevel(RadioJammerChargeLevel.Low, uid); + } + else + { + ChangeChargeLevel(RadioJammerChargeLevel.Medium, uid); + } + } + } + } } @@ -52,40 +70,49 @@ private void OnActivate(EntityUid uid, RadioJammerComponent comp, ActivateInWorl { var activated = !HasComp(uid) && _powerCell.TryGetBatteryFromSlot(uid, out var battery) && - battery.CurrentCharge > comp.Wattage; + battery.CurrentCharge > GetCurrentWattage(comp); if (activated) { + ChangeLEDState(true, uid); EnsureComp(uid); EnsureComp(uid, out var jammingComp); - jammingComp.Range = comp.Range; + jammingComp.Range = GetCurrentRange(comp); jammingComp.JammableNetworks.Add(DeviceNetworkComponent.DeviceNetIdDefaults.Wireless.ToString()); Dirty(uid, jammingComp); } else { - RemComp(uid); - RemComp(uid); + ChangeLEDState(false, uid); + RemCompDeferred(uid); + RemCompDeferred(uid); } var state = Loc.GetString(activated ? "radio-jammer-component-on-state" : "radio-jammer-component-off-state"); var message = Loc.GetString("radio-jammer-component-on-use", ("state", state)); - _popup.PopupEntity(message, args.User, args.User); + Popup.PopupEntity(message, args.User, args.User); args.Handled = true; } private void OnPowerCellChanged(EntityUid uid, ActiveRadioJammerComponent comp, PowerCellChangedEvent args) { if (args.Ejected) - RemComp(uid); + { + ChangeLEDState(false, uid); + RemCompDeferred(uid); + } } private void OnExamine(EntityUid uid, RadioJammerComponent comp, ExaminedEvent args) { if (args.IsInDetailsRange) { - var msg = HasComp(uid) + var powerIndicator = HasComp(uid) ? Loc.GetString("radio-jammer-component-examine-on-state") : Loc.GetString("radio-jammer-component-examine-off-state"); - args.PushMarkup(msg); + args.PushMarkup(powerIndicator); + + var powerLevel = Loc.GetString(comp.Settings[comp.SelectedPowerLevel].Name); + var switchIndicator = Loc.GetString("radio-jammer-component-switch-setting", ("powerLevel", powerLevel)); + args.PushMarkup(switchIndicator); } } @@ -112,7 +139,7 @@ private bool ShouldCancelSend(EntityUid sourceUid) while (query.MoveNext(out _, out _, out var jam, out var transform)) { - if (source.InRange(EntityManager, _transform, transform.Coordinates, jam.Range)) + if (source.InRange(EntityManager, _transform, transform.Coordinates, GetCurrentRange(jam))) { return true; } diff --git a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs index fc3f69a3ba2..ddf2a41b573 100644 --- a/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioDeviceSystem.cs @@ -203,6 +203,9 @@ private void OnAttemptListen(EntityUid uid, RadioMicrophoneComponent component, private void OnReceiveRadio(EntityUid uid, RadioSpeakerComponent component, ref RadioReceiveEvent args) { + if (uid == args.RadioSource) + return; + var nameEv = new TransformSpeakerNameEvent(args.MessageSource, Name(args.MessageSource)); RaiseLocalEvent(args.MessageSource, nameEv); @@ -221,25 +224,25 @@ private void OnBeforeIntercomUiOpen(EntityUid uid, IntercomComponent component, private void OnToggleIntercomMic(EntityUid uid, IntercomComponent component, ToggleIntercomMicMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { } user) + if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) return; - SetMicrophoneEnabled(uid, user, args.Enabled, true); + SetMicrophoneEnabled(uid, args.Actor, args.Enabled, true); UpdateIntercomUi(uid, component); } private void OnToggleIntercomSpeaker(EntityUid uid, IntercomComponent component, ToggleIntercomSpeakerMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { } user) + if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) return; - SetSpeakerEnabled(uid, user, args.Enabled, true); + SetSpeakerEnabled(uid, args.Actor, args.Enabled, true); UpdateIntercomUi(uid, component); } private void OnSelectIntercomChannel(EntityUid uid, IntercomComponent component, SelectIntercomChannelMessage args) { - if (component.RequiresPower && !this.IsPowered(uid, EntityManager) || args.Session.AttachedEntity is not { }) + if (component.RequiresPower && !this.IsPowered(uid, EntityManager)) return; if (!_protoMan.TryIndex(args.Channel, out _) || !component.SupportedChannels.Contains(args.Channel)) @@ -262,6 +265,6 @@ private void UpdateIntercomUi(EntityUid uid, IntercomComponent component) var availableChannels = component.SupportedChannels; var selectedChannel = micComp?.BroadcastChannel ?? SharedChatSystem.CommonChannel; var state = new IntercomBoundUIState(micEnabled, speakerEnabled, availableChannels, selectedChannel); - _ui.TrySetUiState(uid, IntercomUiKey.Key, state); + _ui.SetUiState(uid, IntercomUiKey.Key, state); } } diff --git a/Content.Server/Radio/EntitySystems/RadioSystem.cs b/Content.Server/Radio/EntitySystems/RadioSystem.cs index 5fce6f770a2..28e6bfc1081 100644 --- a/Content.Server/Radio/EntitySystems/RadioSystem.cs +++ b/Content.Server/Radio/EntitySystems/RadioSystem.cs @@ -126,7 +126,7 @@ public void SendRadioMessage(EntityUid messageSource, string message, RadioChann var obfuscatedWrapped = WrapRadioMessage(messageSource, channel, name, obfuscated, language); var notUdsMsg = new ChatMessage(ChatChannel.Radio, obfuscated, obfuscatedWrapped, NetEntity.Invalid, null); - var ev = new RadioReceiveEvent(messageSource, channel, msg, notUdsMsg, language); + var ev = new RadioReceiveEvent(messageSource, channel, msg, notUdsMsg, language, radioSource); var sendAttemptEv = new RadioSendAttemptEvent(channel, radioSource); RaiseLocalEvent(ref sendAttemptEv); diff --git a/Content.Server/Radio/RadioEvent.cs b/Content.Server/Radio/RadioEvent.cs index 35220d1d757..1198f7c1339 100644 --- a/Content.Server/Radio/RadioEvent.cs +++ b/Content.Server/Radio/RadioEvent.cs @@ -10,12 +10,12 @@ namespace Content.Server.Radio; /// [ByRefEvent] public readonly record struct RadioReceiveEvent( - // Einstein-Engines - languages mechanic EntityUid MessageSource, RadioChannelPrototype Channel, ChatMessage OriginalChatMsg, ChatMessage LanguageObfuscatedChatMsg, - LanguagePrototype Language + LanguagePrototype Language, + EntityUid RadioSource ); /// diff --git a/Content.Server/RandomMetadata/RandomMetadataSystem.cs b/Content.Server/RandomMetadata/RandomMetadataSystem.cs index 0c254c52ac0..abab5e5fc38 100644 --- a/Content.Server/RandomMetadata/RandomMetadataSystem.cs +++ b/Content.Server/RandomMetadata/RandomMetadataSystem.cs @@ -47,9 +47,13 @@ public string GetRandomFromSegments(List segments, string? separator) var outputSegments = new List(); foreach (var segment in segments) { - if (_prototype.TryIndex(segment, out var proto)) - outputSegments.Add(_random.Pick(proto.Values)); - else if (Loc.TryGetString(segment, out var localizedSegment)) + if (_prototype.TryIndex(segment, out var proto)) { + var random = _random.Pick(proto.Values); + if (Loc.TryGetString(random, out var localizedSegment)) + outputSegments.Add(localizedSegment); + else + outputSegments.Add(random); + } else if (Loc.TryGetString(segment, out var localizedSegment)) outputSegments.Add(localizedSegment); else outputSegments.Add(segment); diff --git a/Content.Server/Repairable/RepairableComponent.cs b/Content.Server/Repairable/RepairableComponent.cs index c436386110c..bab70f66b56 100644 --- a/Content.Server/Repairable/RepairableComponent.cs +++ b/Content.Server/Repairable/RepairableComponent.cs @@ -1,5 +1,6 @@ using Content.Shared.Damage; using Content.Shared.Tools; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Server.Repairable @@ -14,28 +15,28 @@ public sealed partial class RepairableComponent : Component /// If this data-field is specified, it will change damage by this amount instead of setting all damage to 0. /// in order to heal/repair the damage values have to be negative. /// - [ViewVariables(VVAccess.ReadWrite)] [DataField("damage")] + [DataField] public DamageSpecifier? Damage; - [ViewVariables(VVAccess.ReadWrite)] [DataField("fuelCost")] + [DataField] public int FuelCost = 5; - [ViewVariables(VVAccess.ReadWrite)] [DataField("qualityNeeded", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string QualityNeeded = "Welding"; + [DataField] + public ProtoId QualityNeeded = "Welding"; - [ViewVariables(VVAccess.ReadWrite)] [DataField("doAfterDelay")] + [DataField] public int DoAfterDelay = 1; /// /// A multiplier that will be applied to the above if an entity is repairing themselves. /// - [ViewVariables(VVAccess.ReadWrite)] [DataField("selfRepairPenalty")] + [DataField] public float SelfRepairPenalty = 3f; /// /// Whether or not an entity is allowed to repair itself. /// - [DataField("allowSelfRepair")] + [DataField] public bool AllowSelfRepair = true; } } diff --git a/Content.Server/Repairable/RepairableSystem.cs b/Content.Server/Repairable/RepairableSystem.cs index 5bd580756da..ec24cd81975 100644 --- a/Content.Server/Repairable/RepairableSystem.cs +++ b/Content.Server/Repairable/RepairableSystem.cs @@ -4,7 +4,6 @@ using Content.Shared.Interaction; using Content.Shared.Popups; using Content.Shared.Repairable; -using Content.Shared.Tools; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; namespace Content.Server.Repairable @@ -70,7 +69,7 @@ public async void Repair(EntityUid uid, RepairableComponent component, InteractU } // Run the repairing doafter - args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, delay, component.QualityNeeded, new RepairFinishedEvent()); + args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, delay, component.QualityNeeded, new RepairFinishedEvent(), component.FuelCost); } } } diff --git a/Content.Server/Research/Systems/ResearchSystem.Client.cs b/Content.Server/Research/Systems/ResearchSystem.Client.cs index 6bd5300d8fe..f8fdba55b76 100644 --- a/Content.Server/Research/Systems/ResearchSystem.Client.cs +++ b/Content.Server/Research/Systems/ResearchSystem.Client.cs @@ -45,7 +45,7 @@ private void OnConsoleSelect(EntityUid uid, ResearchClientComponent component, C if (!this.IsPowered(uid, EntityManager)) return; - _uiSystem.TryToggleUi(uid, ResearchClientUiKey.Key, args.Session); + _uiSystem.TryToggleUi(uid, ResearchClientUiKey.Key, args.Actor); } #endregion @@ -88,7 +88,7 @@ private void UpdateClientInterface(EntityUid uid, ResearchClientComponent? compo var state = new ResearchClientBoundInterfaceState(names.Length, names, GetServerIds(), serverComponent?.Id ?? -1); - _uiSystem.TrySetUiState(uid, ResearchClientUiKey.Key, state); + _uiSystem.SetUiState(uid, ResearchClientUiKey.Key, state); } /// diff --git a/Content.Server/Research/Systems/ResearchSystem.Console.cs b/Content.Server/Research/Systems/ResearchSystem.Console.cs index 9f95fd25176..5358ddefcdf 100644 --- a/Content.Server/Research/Systems/ResearchSystem.Console.cs +++ b/Content.Server/Research/Systems/ResearchSystem.Console.cs @@ -20,8 +20,7 @@ private void InitializeConsole() private void OnConsoleUnlock(EntityUid uid, ResearchConsoleComponent component, ConsoleUnlockTechnologyMessage args) { - if (args.Session.AttachedEntity is not { } ent) - return; + var act = args.Actor; if (!this.IsPowered(uid, EntityManager)) return; @@ -29,13 +28,13 @@ private void OnConsoleUnlock(EntityUid uid, ResearchConsoleComponent component, if (!PrototypeManager.TryIndex(args.Id, out var technologyPrototype)) return; - if (TryComp(uid, out var access) && !_accessReader.IsAllowed(ent, uid, access)) + if (TryComp(uid, out var access) && !_accessReader.IsAllowed(act, uid, access)) { - _popup.PopupEntity(Loc.GetString("research-console-no-access-popup"), ent); + _popup.PopupEntity(Loc.GetString("research-console-no-access-popup"), act); return; } - if (!UnlockTechnology(uid, args.Id, ent)) + if (!UnlockTechnology(uid, args.Id, act)) return; var message = Loc.GetString("research-console-unlock-technology-radio-broadcast", @@ -68,7 +67,7 @@ private void UpdateConsoleInterface(EntityUid uid, ResearchConsoleComponent? com state = new ResearchConsoleBoundInterfaceState(default); } - _uiSystem.TrySetUiState(uid, ResearchConsoleUiKey.Key, state); + _uiSystem.SetUiState(uid, ResearchConsoleUiKey.Key, state); } private void OnPointsChanged(EntityUid uid, ResearchConsoleComponent component, ref ResearchServerPointsChangedEvent args) diff --git a/Content.Server/Research/TechnologyDisk/Systems/DiskConsoleSystem.cs b/Content.Server/Research/TechnologyDisk/Systems/DiskConsoleSystem.cs index 2064abd8ebf..67002475228 100644 --- a/Content.Server/Research/TechnologyDisk/Systems/DiskConsoleSystem.cs +++ b/Content.Server/Research/TechnologyDisk/Systems/DiskConsoleSystem.cs @@ -91,7 +91,7 @@ public void UpdateUserInterface(EntityUid uid, DiskConsoleComponent? component = totalPoints >= component.PricePerDisk; var state = new DiskConsoleBoundUserInterfaceState(totalPoints, component.PricePerDisk, canPrint); - _ui.TrySetUiState(uid, DiskConsoleUiKey.Key, state); + _ui.SetUiState(uid, DiskConsoleUiKey.Key, state); } private void OnShutdown(EntityUid uid, DiskConsolePrintingComponent component, ComponentShutdown args) diff --git a/Content.Server/Resist/CanEscapeInventoryComponent.cs b/Content.Server/Resist/CanEscapeInventoryComponent.cs index 978e03d95f9..2b4045143a4 100644 --- a/Content.Server/Resist/CanEscapeInventoryComponent.cs +++ b/Content.Server/Resist/CanEscapeInventoryComponent.cs @@ -6,9 +6,9 @@ namespace Content.Server.Resist; public sealed partial class CanEscapeInventoryComponent : Component { /// - /// Base doafter length for uncontested breakouts. + /// Base doafter length for uncontested breakouts. /// - [DataField("baseResistTime")] + [DataField] public float BaseResistTime = 5f; public bool IsEscaping => DoAfter != null; diff --git a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs index cd64f043a08..5d7c7514b84 100644 --- a/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs +++ b/Content.Server/Revenant/EntitySystems/RevenantSystem.Abilities.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Numerics; using Content.Server.Revenant.Components; +using Content.Shared.Physics; using Content.Shared.DoAfter; using Content.Shared.Emag.Systems; using Content.Shared.FixedPoint; @@ -135,6 +136,12 @@ private void BeginHarvestDoAfter(EntityUid uid, EntityUid target, RevenantCompon return; } + if(_physics.GetEntitiesIntersectingBody(uid, (int) CollisionGroup.Impassable).Count > 0) + { + _popup.PopupEntity(Loc.GetString("revenant-in-solid"), uid, uid); + return; + } + var doAfter = new DoAfterArgs(EntityManager, uid, revenant.HarvestDebuffs.X, new HarvestEvent(), uid, target: target) { DistanceThreshold = 2, @@ -238,7 +245,7 @@ private void OnDefileAction(EntityUid uid, RevenantComponent component, Revenant { //hardcoded damage specifiers til i die. var dspec = new DamageSpecifier(); - dspec.DamageDict.Add("Structural", 15); + dspec.DamageDict.Add("Structural", 60); _damage.TryChangeDamage(ent, dspec, origin: uid); } diff --git a/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs new file mode 100644 index 00000000000..916694fdd86 --- /dev/null +++ b/Content.Server/Robotics/Systems/RoboticsConsoleSystem.cs @@ -0,0 +1,146 @@ +using Content.Server.Administration.Logs; +using Content.Server.DeviceNetwork; +using Content.Server.DeviceNetwork.Systems; +using Content.Server.Radio.EntitySystems; +using Content.Shared.Lock; +using Content.Shared.Database; +using Content.Shared.DeviceNetwork; +using Content.Shared.Robotics; +using Content.Shared.Robotics.Components; +using Content.Shared.Robotics.Systems; +using Robust.Server.GameObjects; +using Robust.Shared.Timing; +using System.Diagnostics.CodeAnalysis; + +namespace Content.Server.Research.Systems; + +/// +/// Handles UI and state receiving for the robotics control console. +/// BorgTransponderComponent broadcasts state from the station's borgs to consoles. +/// +public sealed class RoboticsConsoleSystem : SharedRoboticsConsoleSystem +{ + [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!; + [Dependency] private readonly IAdminLogManager _adminLogger = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly LockSystem _lock = default!; + [Dependency] private readonly RadioSystem _radio = default!; + [Dependency] private readonly UserInterfaceSystem _ui = default!; + + // almost never timing out more than 1 per tick so initialize with that capacity + private List _removing = new(1); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPacketReceived); + Subs.BuiEvents(RoboticsConsoleUiKey.Key, subs => + { + subs.Event(OnOpened); + subs.Event(OnDisable); + subs.Event(OnDestroy); + // TODO: camera stuff + }); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var now = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + // remove cyborgs that havent pinged in a while + _removing.Clear(); + foreach (var (address, data) in comp.Cyborgs) + { + if (now >= data.Timeout) + _removing.Add(address); + } + + // needed to prevent modifying while iterating it + foreach (var address in _removing) + { + comp.Cyborgs.Remove(address); + } + + if (_removing.Count > 0) + UpdateUserInterface((uid, comp)); + } + } + + private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + return; + if (command != DeviceNetworkConstants.CmdUpdatedState) + return; + + if (!payload.TryGetValue(RoboticsConsoleConstants.NET_CYBORG_DATA, out CyborgControlData? data)) + return; + + var real = data.Value; + real.Timeout = _timing.CurTime + ent.Comp.Timeout; + ent.Comp.Cyborgs[args.SenderAddress] = real; + + UpdateUserInterface(ent); + } + + private void OnOpened(Entity ent, ref BoundUIOpenedEvent args) + { + UpdateUserInterface(ent); + } + + private void OnDisable(Entity ent, ref RoboticsConsoleDisableMessage args) + { + if (_lock.IsLocked(ent.Owner)) + return; + + if (!ent.Comp.Cyborgs.TryGetValue(args.Address, out var data)) + return; + + var payload = new NetworkPayload() + { + [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DISABLE_COMMAND + }; + + _deviceNetwork.QueuePacket(ent, args.Address, payload); + _adminLogger.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):user} disabled borg {data.Name} with address {args.Address}"); + } + + private void OnDestroy(Entity ent, ref RoboticsConsoleDestroyMessage args) + { + if (_lock.IsLocked(ent.Owner)) + return; + + var now = _timing.CurTime; + if (now < ent.Comp.NextDestroy) + return; + + if (!ent.Comp.Cyborgs.Remove(args.Address, out var data)) + return; + + var payload = new NetworkPayload() + { + [DeviceNetworkConstants.Command] = RoboticsConsoleConstants.NET_DESTROY_COMMAND + }; + + _deviceNetwork.QueuePacket(ent, args.Address, payload); + + var message = Loc.GetString(ent.Comp.DestroyMessage, ("name", data.Name)); + _radio.SendRadioMessage(ent, message, ent.Comp.RadioChannel, ent); + _adminLogger.Add(LogType.Action, LogImpact.Extreme, $"{ToPrettyString(args.Actor):user} destroyed borg {data.Name} with address {args.Address}"); + + ent.Comp.NextDestroy = now + ent.Comp.DestroyCooldown; + Dirty(ent, ent.Comp); + } + + private void UpdateUserInterface(Entity ent) + { + var state = new RoboticsConsoleState(ent.Comp.Cyborgs); + _ui.SetUiState(ent.Owner, RoboticsConsoleUiKey.Key, state); + } +} diff --git a/Content.Server/Roles/RoleSystem.cs b/Content.Server/Roles/RoleSystem.cs index f7a51773573..c53fa1cf9eb 100644 --- a/Content.Server/Roles/RoleSystem.cs +++ b/Content.Server/Roles/RoleSystem.cs @@ -15,7 +15,6 @@ public override void Initialize() SubscribeAntagEvents(); SubscribeAntagEvents(); SubscribeAntagEvents(); - SubscribeAntagEvents(); SubscribeAntagEvents(); SubscribeAntagEvents(); SubscribeAntagEvents(); diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index d79fe2d2cca..0866b975c2b 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -147,11 +147,15 @@ public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = tr public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") { - if (_gameTicker.RunLevel != GameRunLevel.InRound) return; + if (_gameTicker.RunLevel != GameRunLevel.InRound) + return; - if (checkCooldown && _cooldownTokenSource != null) return; + if (checkCooldown && _cooldownTokenSource != null) + return; + + if (_countdownTokenSource != null) + return; - if (_countdownTokenSource != null) return; _countdownTokenSource = new(); if (requester != null) @@ -191,6 +195,8 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, LastCountdownStart = _gameTiming.CurTime; ExpectedCountdownEnd = _gameTiming.CurTime + countdownTime; + + // TODO full game saves Timer.Spawn(countdownTime, _shuttle.CallEmergencyShuttle, _countdownTokenSource.Token); ActivateCooldown(); @@ -343,6 +349,8 @@ private void ActivateCooldown() { _cooldownTokenSource?.Cancel(); _cooldownTokenSource = new(); + + // TODO full game saves Timer.Spawn(DefaultCooldownDuration, () => { _cooldownTokenSource.Cancel(); diff --git a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs index 6a58c209cfa..ff3c8176fd0 100644 --- a/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs +++ b/Content.Server/Salvage/Expeditions/SalvageExpeditionComponent.cs @@ -40,14 +40,21 @@ public sealed partial class SalvageExpeditionComponent : SharedSalvageExpedition /// /// Countdown audio stream. /// + [DataField, AutoNetworkedField] public EntityUid? Stream = null; /// /// Sound that plays when the mission end is imminent. /// - [ViewVariables(VVAccess.ReadWrite), DataField("sound")] - public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Misc/tension_session.ogg") + [ViewVariables(VVAccess.ReadWrite), DataField] + public SoundSpecifier Sound = new SoundCollectionSpecifier("ExpeditionEnd") { Params = AudioParams.Default.WithVolume(-5), }; + + /// + /// Song selected on MapInit so we can predict the audio countdown properly. + /// + [DataField] + public SoundPathSpecifier SelectedSong; } diff --git a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs index 61636bea7c9..d0314184767 100644 --- a/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs +++ b/Content.Server/Salvage/SalvageSystem.ExpeditionConsole.cs @@ -56,7 +56,7 @@ private void UpdateConsoles(Entity component) if (station != component.Owner) continue; - _ui.TrySetUiState(uid, SalvageConsoleUiKey.Expedition, state, ui: uiComp); + _ui.SetUiState((uid, uiComp), SalvageConsoleUiKey.Expedition, state); } } @@ -74,6 +74,6 @@ private void UpdateConsole(Entity component) state = new SalvageExpeditionConsoleState(TimeSpan.Zero, false, true, 0, new List()); } - _ui.TrySetUiState(component, SalvageConsoleUiKey.Expedition, state); + _ui.SetUiState(component.Owner, SalvageConsoleUiKey.Expedition, state); } } diff --git a/Content.Server/Salvage/SalvageSystem.Expeditions.cs b/Content.Server/Salvage/SalvageSystem.Expeditions.cs index 4d5d569dabd..923880169d5 100644 --- a/Content.Server/Salvage/SalvageSystem.Expeditions.cs +++ b/Content.Server/Salvage/SalvageSystem.Expeditions.cs @@ -4,7 +4,9 @@ using Content.Server.Salvage.Expeditions.Structure; using Content.Shared.CCVar; using Content.Shared.Examine; +using Content.Shared.Random.Helpers; using Content.Shared.Salvage.Expeditions; +using Robust.Shared.Audio; using Robust.Shared.CPUJob.JobQueues; using Robust.Shared.CPUJob.JobQueues.Queues; using Robust.Shared.GameStates; @@ -32,6 +34,7 @@ private void InitializeExpeditions() SubscribeLocalEvent(OnSalvageConsoleParent); SubscribeLocalEvent(OnSalvageClaimMessage); + SubscribeLocalEvent(OnExpeditionMapInit); SubscribeLocalEvent(OnExpeditionShutdown); SubscribeLocalEvent(OnExpeditionGetState); @@ -64,6 +67,12 @@ private void SetCooldownChange(float obj) _cooldown = obj; } + private void OnExpeditionMapInit(EntityUid uid, SalvageExpeditionComponent component, MapInitEvent args) + { + var selectedFile = _audio.GetSound(component.Sound); + component.SelectedSong = new SoundPathSpecifier(selectedFile, component.Sound.Params); + } + private void OnExpeditionShutdown(EntityUid uid, SalvageExpeditionComponent component, ComponentShutdown args) { component.Stream = _audio.Stop(component.Stream); diff --git a/Content.Server/Salvage/SalvageSystem.Magnet.cs b/Content.Server/Salvage/SalvageSystem.Magnet.cs index e4711a58763..4b7291298b2 100644 --- a/Content.Server/Salvage/SalvageSystem.Magnet.cs +++ b/Content.Server/Salvage/SalvageSystem.Magnet.cs @@ -35,11 +35,6 @@ private void InitializeMagnet() private void OnMagnetClaim(EntityUid uid, SalvageMagnetComponent component, ref MagnetClaimOfferEvent args) { - var player = args.Session.AttachedEntity; - - if (player is null) - return; - var station = _station.GetOwningStation(uid); if (!TryComp(station, out SalvageMagnetDataComponent? dataComp) || @@ -177,12 +172,12 @@ private void CreateMagnetOffers(Entity data) // Fuck with the seed to mix wrecks and asteroids. seed = (int) (seed / 10f) * 10; - + if (i >= data.Comp.OfferCount / 2) { seed++; } - + data.Comp.Offered.Add(seed); } @@ -216,7 +211,7 @@ private void UpdateMagnetUI(Entity entity, TransformComp if (!TryComp(station, out SalvageMagnetDataComponent? dataComp)) return; - _ui.TrySetUiState(entity, SalvageMagnetUiKey.Key, + _ui.SetUiState(entity.Owner, SalvageMagnetUiKey.Key, new SalvageMagnetBoundUserInterfaceState(dataComp.Offered) { Cooldown = dataComp.OfferCooldown, @@ -238,7 +233,7 @@ private void UpdateMagnetUIs(Entity data) if (station != data.Owner) continue; - _ui.TrySetUiState(magnetUid, SalvageMagnetUiKey.Key, + _ui.SetUiState(magnetUid, SalvageMagnetUiKey.Key, new SalvageMagnetBoundUserInterfaceState(data.Comp.Offered) { Cooldown = data.Comp.OfferCooldown, diff --git a/Content.Server/Salvage/SalvageSystem.Runner.cs b/Content.Server/Salvage/SalvageSystem.Runner.cs index 8a1498cbe96..23607e2bdc5 100644 --- a/Content.Server/Salvage/SalvageSystem.Runner.cs +++ b/Content.Server/Salvage/SalvageSystem.Runner.cs @@ -1,9 +1,7 @@ using System.Numerics; using Content.Server.Salvage.Expeditions; -using Content.Server.Salvage.Expeditions.Structure; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; -using Content.Server.Shuttles.Systems; using Content.Server.Station.Components; using Content.Shared.Chat; using Content.Shared.Humanoid; @@ -13,7 +11,6 @@ using Content.Shared.Shuttles.Components; using Robust.Shared.Map.Components; using Robust.Shared.Player; -using Robust.Shared.Utility; namespace Content.Server.Salvage; @@ -144,6 +141,7 @@ private void UpdateRunner() while (query.MoveNext(out var uid, out var comp)) { var remaining = comp.EndTime - _timing.CurTime; + var audioLength = _audio.GetAudioLength(comp.SelectedSong.Path.ToString()); if (comp.Stage < ExpeditionStage.FinalCountdown && remaining < TimeSpan.FromSeconds(45)) { @@ -151,13 +149,14 @@ private void UpdateRunner() Dirty(uid, comp); Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-seconds", ("duration", TimeSpan.FromSeconds(45).Seconds))); } - else if (comp.Stage < ExpeditionStage.MusicCountdown && remaining < TimeSpan.FromMinutes(2)) + else if (comp.Stream == null && remaining < audioLength) { - // TODO: Some way to play audio attached to a map for players. - comp.Stream = _audio.PlayGlobal(comp.Sound, Filter.BroadcastMap(Comp(uid).MapId), true).Value.Entity; + var audio = _audio.PlayPvs(comp.Sound, uid).Value; + comp.Stream = audio.Entity; + _audio.SetMapAudio(audio); comp.Stage = ExpeditionStage.MusicCountdown; Dirty(uid, comp); - Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(2).Minutes))); + Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", audioLength.Minutes))); } else if (comp.Stage < ExpeditionStage.Countdown && remaining < TimeSpan.FromMinutes(4)) { @@ -166,16 +165,16 @@ private void UpdateRunner() Announce(uid, Loc.GetString("salvage-expedition-announcement-countdown-minutes", ("duration", TimeSpan.FromMinutes(5).Minutes))); } // Auto-FTL out any shuttles - else if (remaining < TimeSpan.FromSeconds(ShuttleSystem.DefaultStartupTime) + TimeSpan.FromSeconds(0.5)) + else if (remaining < TimeSpan.FromSeconds(_shuttle.DefaultStartupTime) + TimeSpan.FromSeconds(0.5)) { var ftlTime = (float) remaining.TotalSeconds; - if (remaining < TimeSpan.FromSeconds(ShuttleSystem.DefaultStartupTime)) + if (remaining < TimeSpan.FromSeconds(_shuttle.DefaultStartupTime)) { ftlTime = MathF.Max(0, (float) remaining.TotalSeconds - 0.5f); } - ftlTime = MathF.Min(ftlTime, ShuttleSystem.DefaultStartupTime); + ftlTime = MathF.Min(ftlTime, _shuttle.DefaultStartupTime); var shuttleQuery = AllEntityQuery(); if (TryComp(comp.Station, out var data)) diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs index 63b4d9daef9..b5a954f166d 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleComponent.cs @@ -27,7 +27,7 @@ public sealed partial class SensorMonitoringConsoleComponent : Component public TimeSpan RetentionTime = TimeSpan.FromMinutes(1); // UI update tracking stuff. - public HashSet InitialUIStateSent = new(); + public HashSet InitialUIStateSent = new(); public TimeSpan LastUIUpdate; public ValueList RemovedSensors; diff --git a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs index 26c6b178313..dec3e6c36ea 100644 --- a/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs +++ b/Content.Server/SensorMonitoring/SensorMonitoringConsoleSystem.UI.cs @@ -18,27 +18,26 @@ private void InitUI() private void UpdateConsoleUI(EntityUid uid, SensorMonitoringConsoleComponent comp) { - if (!_userInterface.TryGetUi(uid, SensorMonitoringConsoleUiKey.Key, out var ui)) - return; - - if (ui.SubscribedSessions.Count == 0) + if (!_userInterface.IsUiOpen(uid, SensorMonitoringConsoleUiKey.Key)) + { return; + } ConsoleUIState? fullState = null; SensorMonitoringIncrementalUpdate? incrementalUpdate = null; - foreach (var session in ui.SubscribedSessions) + foreach (var actorUid in _userInterface.GetActors(uid, SensorMonitoringConsoleUiKey.Key)) { - if (comp.InitialUIStateSent.Contains(session)) + if (comp.InitialUIStateSent.Contains(actorUid)) { incrementalUpdate ??= CalculateIncrementalUpdate(); - _userInterface.TrySendUiMessage(ui, incrementalUpdate, session); + _userInterface.ServerSendUiMessage(uid, SensorMonitoringConsoleUiKey.Key, incrementalUpdate, actorUid); } else { fullState ??= CalculateFullState(); - _userInterface.SetUiState(ui, fullState, session); - comp.InitialUIStateSent.Add(session); + _userInterface.SetUiState(uid, SensorMonitoringConsoleUiKey.Key, fullState); + comp.InitialUIStateSent.Add(actorUid); } } @@ -131,9 +130,6 @@ private static void ConsoleUIClosed( if (!args.UiKey.Equals(SensorMonitoringConsoleUiKey.Key)) return; - if (args.Session is not { } player) - return; - - component.InitialUIStateSent.Remove(player); + component.InitialUIStateSent.Remove(args.Actor); } } diff --git a/Content.Server/Shuttles/Components/DockingSignalControlComponent.cs b/Content.Server/Shuttles/Components/DockingSignalControlComponent.cs new file mode 100644 index 00000000000..43612650802 --- /dev/null +++ b/Content.Server/Shuttles/Components/DockingSignalControlComponent.cs @@ -0,0 +1,14 @@ +using Content.Shared.DeviceLinking; +using Robust.Shared.Prototypes; + +namespace Content.Server.Shuttles.Components; + +[RegisterComponent] +public sealed partial class DockingSignalControlComponent : Component +{ + /// + /// Output port that is high while docked. + /// + [DataField] + public ProtoId DockStatusSignalPort = "DockStatus"; +} diff --git a/Content.Server/Shuttles/Components/FTLComponent.cs b/Content.Server/Shuttles/Components/FTLComponent.cs index ab40875e29a..c9b84064234 100644 --- a/Content.Server/Shuttles/Components/FTLComponent.cs +++ b/Content.Server/Shuttles/Components/FTLComponent.cs @@ -14,6 +14,8 @@ namespace Content.Server.Shuttles.Components; [RegisterComponent] public sealed partial class FTLComponent : Component { + // TODO Full game save / add datafields + [ViewVariables] public FTLState State = FTLState.Available; @@ -23,6 +25,7 @@ public sealed partial class FTLComponent : Component [ViewVariables(VVAccess.ReadWrite)] public float StartupTime = 0f; + // Because of sphagetti, actual travel time is Math.Max(TravelTime, DefaultArrivalTime) [ViewVariables(VVAccess.ReadWrite)] public float TravelTime = 0f; diff --git a/Content.Server/Shuttles/Components/StationEmergencyShuttleComponent.cs b/Content.Server/Shuttles/Components/StationEmergencyShuttleComponent.cs index bdfdcb273aa..58d23ee4326 100644 --- a/Content.Server/Shuttles/Components/StationEmergencyShuttleComponent.cs +++ b/Content.Server/Shuttles/Components/StationEmergencyShuttleComponent.cs @@ -13,7 +13,7 @@ public sealed partial class StationEmergencyShuttleComponent : Component /// /// The emergency shuttle assigned to this station. /// - [ViewVariables, Access(typeof(ShuttleSystem), typeof(EmergencyShuttleSystem), Friend = AccessPermissions.ReadWrite)] + [DataField, Access(typeof(ShuttleSystem), typeof(EmergencyShuttleSystem), Friend = AccessPermissions.ReadWrite)] public EntityUid? EmergencyShuttle; /// diff --git a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs index ae742cf1f9e..23f7e10a3e3 100644 --- a/Content.Server/Shuttles/Systems/ArrivalsSystem.cs +++ b/Content.Server/Shuttles/Systems/ArrivalsSystem.cs @@ -1,15 +1,16 @@ using System.Linq; using Content.Server.Administration; +using Content.Server.DeviceNetwork.Components; +using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking; using Content.Server.GameTicking.Events; using Content.Server.Parallax; -using Content.Server.DeviceNetwork.Components; -using Content.Server.DeviceNetwork.Systems; using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Spawners.Components; using Content.Server.Station.Components; +using Content.Server.Station.Events; using Content.Server.Station.Systems; using Content.Shared.Administration; using Content.Shared.CCVar; @@ -77,7 +78,7 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnArrivalsStartup); + SubscribeLocalEvent(OnStationPostInit); SubscribeLocalEvent(OnShuttleStartup); SubscribeLocalEvent(OnShuttleTag); @@ -187,7 +188,7 @@ private void OnArrivalsFTL(EntityUid shuttleUid, ArrivalsShuttleComponent compon if (TryComp(shuttleUid, out var netComp)) { TryComp(shuttleUid, out var ftlComp); - var ftlTime = TimeSpan.FromSeconds(ftlComp?.TravelTime ?? ShuttleSystem.DefaultTravelTime); + var ftlTime = TimeSpan.FromSeconds(ftlComp?.TravelTime ?? _shuttles.DefaultTravelTime); var payload = new NetworkPayload { @@ -253,7 +254,7 @@ private void OnArrivalsFTL(EntityUid shuttleUid, ArrivalsShuttleComponent compon private void OnArrivalsDocked(EntityUid uid, ArrivalsShuttleComponent component, ref FTLCompletedEvent args) { - TimeSpan dockTime = component.NextTransfer - _timing.CurTime + TimeSpan.FromSeconds(ShuttleSystem.DefaultStartupTime); + var dockTime = component.NextTransfer - _timing.CurTime + TimeSpan.FromSeconds(_shuttles.DefaultStartupTime); if (TryComp(uid, out var netComp)) { @@ -419,7 +420,7 @@ public override void Update(float frameTime) if (comp.NextTransfer > curTime || !TryComp(comp.Station, out var data)) continue; - var tripTime = ShuttleSystem.DefaultTravelTime + ShuttleSystem.DefaultStartupTime; + var tripTime = _shuttles.DefaultTravelTime + _shuttles.DefaultStartupTime; // Go back to arrivals source if (xform.MapUid != arrivalsXform.MapUid) @@ -530,7 +531,7 @@ private void SetArrivals(bool obj) } } - private void OnArrivalsStartup(EntityUid uid, StationArrivalsComponent component, ComponentStartup args) + private void OnStationPostInit(EntityUid uid, StationArrivalsComponent component, ref StationPostInitEvent args) { if (!Enabled) return; diff --git a/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs b/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs new file mode 100644 index 00000000000..34cade7f1c1 --- /dev/null +++ b/Content.Server/Shuttles/Systems/DockingSignalControlSystem.cs @@ -0,0 +1,28 @@ +using Content.Server.DeviceLinking.Systems; +using Content.Server.Shuttles.Components; +using Content.Server.Shuttles.Events; + +namespace Content.Server.Shuttles.Systems; + +public sealed class DockingSignalControlSystem : EntitySystem +{ + [Dependency] private readonly DeviceLinkSystem _deviceLinkSystem = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnDocked); + SubscribeLocalEvent(OnUndocked); + } + + private void OnDocked(Entity ent, ref DockEvent args) + { + _deviceLinkSystem.SendSignal(ent, ent.Comp.DockStatusSignalPort, signal: true); + } + + private void OnUndocked(Entity ent, ref UndockEvent args) + { + _deviceLinkSystem.SendSignal(ent, ent.Comp.DockStatusSignalPort, signal: false); + } +} diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs index 3f6eafb454c..6c040e7a0ec 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.Console.cs @@ -1,10 +1,8 @@ using System.Threading; -using Content.Server.DeviceNetwork; using Content.Server.DeviceNetwork.Components; using Content.Server.Screens.Components; using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; -using Content.Shared.UserInterface; using Content.Shared.Access; using Content.Shared.CCVar; using Content.Shared.Database; @@ -13,12 +11,15 @@ using Content.Shared.Shuttles.BUIStates; using Content.Shared.Shuttles.Events; using Content.Shared.Shuttles.Systems; +using Content.Shared.UserInterface; using Robust.Shared.Map; using Robust.Shared.Player; using Timer = Robust.Shared.Timing.Timer; namespace Content.Server.Shuttles.Systems; +// TODO full game saves +// Move state data into the emergency shuttle component public sealed partial class EmergencyShuttleSystem { /* @@ -55,7 +56,7 @@ public sealed partial class EmergencyShuttleSystem /// /// How long it will take for the emergency shuttle to arrive at CentComm. /// - public float TransitTime { get; private set; } + public float TransitTime; /// /// @@ -129,9 +130,17 @@ private void OnEmergencyStartup(EntityUid uid, EmergencyShuttleConsoleComponent private void UpdateEmergencyConsole(float frameTime) { // Add some buffer time so eshuttle always first. - var minTime = -(TransitTime - (ShuttleSystem.DefaultStartupTime + ShuttleSystem.DefaultTravelTime + 1f)); + var minTime = -(TransitTime - (_shuttle.DefaultStartupTime + _shuttle.DefaultTravelTime + 1f)); // TODO: I know this is shit but I already just cleaned up a billion things. + + // This is very cursed spaghetti code. I don't even know what the fuck this is doing or why it exists. + // But I think it needs to be less than or equal to zero or the shuttle might never leave??? + // TODO Shuttle AAAAAAAAAAAAAAAAAAAAAAAAA + // Clean this up, just have a single timer with some state system. + // I.e., dont infer state from the current interval that the accumulator is in??? + minTime = Math.Min(0, minTime); // ???? + if (_consoleAccumulator < minTime) { return; @@ -147,7 +156,7 @@ private void UpdateEmergencyConsole(float frameTime) } // Imminent departure - if (!_launchedShuttles && _consoleAccumulator <= ShuttleSystem.DefaultStartupTime) + if (!_launchedShuttles && _consoleAccumulator <= _shuttle.DefaultStartupTime) { _launchedShuttles = true; @@ -241,19 +250,18 @@ private void UpdateEmergencyConsole(float frameTime) private void OnEmergencyRepealAll(EntityUid uid, EmergencyShuttleConsoleComponent component, EmergencyShuttleRepealAllMessage args) { - var player = args.Session.AttachedEntity; - if (player == null) return; + var player = args.Actor; - if (!_reader.FindAccessTags(player.Value).Contains(EmergencyRepealAllAccess)) + if (!_reader.FindAccessTags(player).Contains(EmergencyRepealAllAccess)) { - _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), player.Value, PopupType.Medium); + _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), player, PopupType.Medium); return; } if (component.AuthorizedEntities.Count == 0) return; - _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL ALL by {args.Session:user}"); + _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL ALL by {args.Actor:user}"); _announcer.SendAnnouncement( _announcer.GetAnnouncementId("ShuttleAuthRevoked"), Filter.Broadcast(), @@ -267,13 +275,11 @@ private void OnEmergencyRepealAll(EntityUid uid, EmergencyShuttleConsoleComponen private void OnEmergencyRepeal(EntityUid uid, EmergencyShuttleConsoleComponent component, EmergencyShuttleRepealMessage args) { - var player = args.Session.AttachedEntity; - if (player == null) - return; + var player = args.Actor; - if (!_idSystem.TryFindIdCard(player.Value, out var idCard) || !_reader.IsAllowed(idCard, uid)) + if (!_idSystem.TryFindIdCard(player, out var idCard) || !_reader.IsAllowed(idCard, uid)) { - _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), player.Value, PopupType.Medium); + _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), player, PopupType.Medium); return; } @@ -281,7 +287,7 @@ private void OnEmergencyRepeal(EntityUid uid, EmergencyShuttleConsoleComponent c if (!component.AuthorizedEntities.Remove(MetaData(idCard).EntityName)) return; - _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL by {args.Session:user}"); + _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch REPEAL by {args.Actor:user}"); var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count; _announcer.SendAnnouncement( _announcer.GetAnnouncementId("ShuttleAuthRevoked"), @@ -296,13 +302,11 @@ private void OnEmergencyRepeal(EntityUid uid, EmergencyShuttleConsoleComponent c private void OnEmergencyAuthorize(EntityUid uid, EmergencyShuttleConsoleComponent component, EmergencyShuttleAuthorizeMessage args) { - var player = args.Session.AttachedEntity; - if (player == null) - return; + var player = args.Actor; - if (!_idSystem.TryFindIdCard(player.Value, out var idCard) || !_reader.IsAllowed(idCard, uid)) + if (!_idSystem.TryFindIdCard(player, out var idCard) || !_reader.IsAllowed(idCard, uid)) { - _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), args.Session, PopupType.Medium); + _popup.PopupCursor(Loc.GetString("emergency-shuttle-console-denied"), args.Actor, PopupType.Medium); return; } @@ -310,7 +314,7 @@ private void OnEmergencyAuthorize(EntityUid uid, EmergencyShuttleConsoleComponen if (!component.AuthorizedEntities.Add(MetaData(idCard).EntityName)) return; - _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch AUTH by {args.Session:user}"); + _logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle early launch AUTH by {args.Actor:user}"); var remaining = component.AuthorizationsRequired - component.AuthorizedEntities.Count; if (remaining > 0) @@ -362,9 +366,10 @@ private void UpdateConsoleState(EntityUid uid, EmergencyShuttleConsoleComponent auths.Add(auth); } - if (_uiSystem.TryGetUi(uid, EmergencyConsoleUiKey.Key, out var bui)) + if (_uiSystem.HasUi(uid, EmergencyConsoleUiKey.Key)) _uiSystem.SetUiState( - bui, + uid, + EmergencyConsoleUiKey.Key, new EmergencyConsoleBoundUserInterfaceState() { EarlyLaunchTime = EarlyLaunchAuthorized ? _timing.CurTime + TimeSpan.FromSeconds(_consoleAccumulator) : null, diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 2df0bc148cc..90be263ae2e 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -15,6 +15,7 @@ using Content.Server.Shuttles.Components; using Content.Server.Shuttles.Events; using Content.Server.Station.Components; +using Content.Server.Station.Events; using Content.Server.Station.Systems; using Content.Shared.Access.Systems; using Content.Shared.CCVar; @@ -84,9 +85,9 @@ public override void Initialize() SubscribeLocalEvent(OnRoundStart); SubscribeLocalEvent(OnRoundCleanup); - SubscribeLocalEvent(OnStationStartup); + SubscribeLocalEvent(OnStationStartup); SubscribeLocalEvent(OnCentcommShutdown); - SubscribeLocalEvent(OnCentcommInit); + SubscribeLocalEvent(OnStationInit); SubscribeLocalEvent(OnEmergencyFTL); SubscribeLocalEvent(OnEmergencyFTLComplete); @@ -201,10 +202,9 @@ private void OnShuttleRequestPosition(EmergencyShuttleRequestPositionMessage msg /// private void OnEmergencyFTL(EntityUid uid, EmergencyShuttleComponent component, ref FTLStartedEvent args) { - TimeSpan ftlTime = TimeSpan.FromSeconds + var ftlTime = TimeSpan.FromSeconds ( - TryComp(uid, out var ftlComp) ? - ftlComp.TravelTime : ShuttleSystem.DefaultTravelTime + TryComp(uid, out var ftlComp) ? ftlComp.TravelTime : _shuttle.DefaultTravelTime ); if (TryComp(uid, out var netComp)) @@ -260,10 +260,13 @@ private void OnEmergencyFTLComplete(EntityUid uid, EmergencyShuttleComponent com /// public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleComponent? stationShuttle = null) { - if (!Resolve(stationUid, ref stationShuttle) || - !TryComp(stationShuttle.EmergencyShuttle, out var xform) || + if (!Resolve(stationUid, ref stationShuttle)) + return; + + if (!TryComp(stationShuttle.EmergencyShuttle, out var xform) || !TryComp(stationShuttle.EmergencyShuttle, out var shuttle)) { + Log.Error($"Attempted to call an emergency shuttle for an uninitialized station? Station: {ToPrettyString(stationUid)}. Shuttle: {ToPrettyString(stationShuttle.EmergencyShuttle)}"); return; } @@ -329,8 +332,10 @@ public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleCo } } - private void OnCentcommInit(EntityUid uid, StationCentcommComponent component, ComponentInit args) + private void OnStationInit(EntityUid uid, StationCentcommComponent component, MapInitEvent args) { + // This is handled on map-init, so that centcomm has finished initializing by the time the StationPostInitEvent + // gets raised if (!_emergencyShuttleEnabled) return; @@ -341,12 +346,12 @@ private void OnCentcommInit(EntityUid uid, StationCentcommComponent component, C return; } - AddCentcomm(component); + AddCentcomm(uid, component); } - private void OnStationStartup(EntityUid uid, StationEmergencyShuttleComponent component, ComponentStartup args) + private void OnStationStartup(Entity ent, ref StationPostInitEvent args) { - AddEmergencyShuttle(uid, component); + AddEmergencyShuttle((ent, ent)); } /// @@ -383,19 +388,22 @@ private void SetupEmergencyShuttle() var centcommQuery = AllEntityQuery(); - while (centcommQuery.MoveNext(out var centcomm)) + while (centcommQuery.MoveNext(out var uid, out var centcomm)) { - AddCentcomm(centcomm); + AddCentcomm(uid, centcomm); } var query = AllEntityQuery(); while (query.MoveNext(out var uid, out var comp)) - AddEmergencyShuttle(uid, comp); + { + AddEmergencyShuttle((uid, comp)); + } } - private void AddCentcomm(StationCentcommComponent component) + private void AddCentcomm(EntityUid station, StationCentcommComponent component) { + DebugTools.Assert(LifeStage(station)>= EntityLifeStage.MapInitialized); if (component.MapEntity != null || component.Entity != null) { Log.Warning("Attempted to re-add an existing centcomm map."); @@ -411,12 +419,13 @@ private void AddCentcomm(StationCentcommComponent component) if (!Exists(otherComp.MapEntity) || !Exists(otherComp.Entity)) { - Log.Error($"Disconvered invalid centcomm component?"); + Log.Error($"Discovered invalid centcomm component?"); ClearCentcomm(otherComp); continue; } component.MapEntity = otherComp.MapEntity; + component.Entity = otherComp.Entity; component.ShuttleIndex = otherComp.ShuttleIndex; return; } @@ -460,6 +469,7 @@ private void AddCentcomm(StationCentcommComponent component) component.MapEntity = map; component.Entity = grid; _shuttle.TryAddFTLDestination(mapId, false, out _); + Log.Info($"Created centcomm grid {ToPrettyString(grid)} on map {ToPrettyString(map)} for station {ToPrettyString(station)}"); } public HashSet GetCentcommMaps() @@ -476,49 +486,67 @@ public HashSet GetCentcommMaps() return maps; } - private void AddEmergencyShuttle(EntityUid uid, StationEmergencyShuttleComponent component) + private void AddEmergencyShuttle(Entity ent) { - if (!_emergencyShuttleEnabled - || component.EmergencyShuttle != null || - !TryComp(uid, out var centcomm) - || !TryComp(centcomm.MapEntity, out MapComponent? map)) + if (!Resolve(ent.Owner, ref ent.Comp1, ref ent.Comp2)) + return; + + if (!_emergencyShuttleEnabled) + return; + + if (ent.Comp1.EmergencyShuttle != null ) + { + if (Exists(ent.Comp1.EmergencyShuttle)) + { + Log.Error($"Attempted to add an emergency shuttle to {ToPrettyString(ent)}, despite a shuttle already existing?"); + return; + } + + Log.Error($"Encountered deleted emergency shuttle during initialization of {ToPrettyString(ent)}"); + ent.Comp1.EmergencyShuttle = null; + } + + if (!TryComp(ent.Comp2.MapEntity, out MapComponent? map)) { + Log.Error($"Failed to add emergency shuttle - centcomm has not been initialized? {ToPrettyString(ent)}"); return; } // Load escape shuttle - var shuttlePath = component.EmergencyShuttlePath; + var shuttlePath = ent.Comp1.EmergencyShuttlePath; var shuttle = _map.LoadGrid(map.MapId, shuttlePath.ToString(), new MapLoadOptions() { // Should be far enough... right? I'm too lazy to bounds check CentCom rn. - Offset = new Vector2(500f + centcomm.ShuttleIndex, 0f), + Offset = new Vector2(500f + ent.Comp2.ShuttleIndex, 0f), // fun fact: if you just fucking yeet centcomm into nullspace anytime you try to spawn the shuttle, then any distance is far enough. so lets not do that LoadMap = false, }); if (shuttle == null) { - Log.Error($"Unable to spawn emergency shuttle {shuttlePath} for {ToPrettyString(uid)}"); + Log.Error($"Unable to spawn emergency shuttle {shuttlePath} for {ToPrettyString(ent)}"); return; } - centcomm.ShuttleIndex += Comp(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; + ent.Comp2.ShuttleIndex += Comp(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer; // Update indices for all centcomm comps pointing to same map var query = AllEntityQuery(); while (query.MoveNext(out var comp)) { - if (comp == centcomm || comp.MapEntity != centcomm.MapEntity) + if (comp == ent.Comp2 || comp.MapEntity != ent.Comp2.MapEntity) continue; - comp.ShuttleIndex = centcomm.ShuttleIndex; + comp.ShuttleIndex = ent.Comp2.ShuttleIndex; } - component.EmergencyShuttle = shuttle; + ent.Comp1.EmergencyShuttle = shuttle; EnsureComp(shuttle.Value); EnsureComp(shuttle.Value); EnsureComp(shuttle.Value); + + Log.Info($"Added emergency shuttle {ToPrettyString(shuttle)} for station {ToPrettyString(ent)} and centcomm {ToPrettyString(ent.Comp2.Entity)}"); } /// diff --git a/Content.Server/Shuttles/Systems/RadarConsoleSystem.cs b/Content.Server/Shuttles/Systems/RadarConsoleSystem.cs index b7f08b4b349..1de20a87348 100644 --- a/Content.Server/Shuttles/Systems/RadarConsoleSystem.cs +++ b/Content.Server/Shuttles/Systems/RadarConsoleSystem.cs @@ -39,7 +39,7 @@ protected override void UpdateState(EntityUid uid, RadarConsoleComponent compone angle = Angle.Zero; } - if (_uiSystem.TryGetUi(uid, RadarConsoleUiKey.Key, out var bui)) + if (_uiSystem.HasUi(uid, RadarConsoleUiKey.Key)) { NavInterfaceState state; var docks = _console.GetAllDocks(); @@ -53,7 +53,7 @@ protected override void UpdateState(EntityUid uid, RadarConsoleComponent compone state = _console.GetNavState(uid, docks); } - _uiSystem.SetUiState(bui, new NavBoundUserInterfaceState(state)); + _uiSystem.SetUiState(uid, RadarConsoleUiKey.Key, new NavBoundUserInterfaceState(state)); } } } diff --git a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs index fac74e34c58..6f24208c3a6 100644 --- a/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleConsoleSystem.cs @@ -136,13 +136,12 @@ public void RefreshShuttleConsoles() /// private void OnConsoleUIClose(EntityUid uid, ShuttleConsoleComponent component, BoundUIClosedEvent args) { - if ((ShuttleConsoleUiKey) args.UiKey != ShuttleConsoleUiKey.Key || - args.Session.AttachedEntity is not { } user) + if ((ShuttleConsoleUiKey) args.UiKey != ShuttleConsoleUiKey.Key) { return; } - RemovePilot(user); + RemovePilot(args.Actor); } private void OnConsoleUIOpenAttempt(EntityUid uid, ShuttleConsoleComponent component, @@ -265,9 +264,9 @@ private void UpdateState(EntityUid consoleUid, ref DockingInterfaceState? dockSt new List()); } - if (_ui.TryGetUi(consoleUid, ShuttleConsoleUiKey.Key, out var bui)) + if (_ui.HasUi(consoleUid, ShuttleConsoleUiKey.Key)) { - _ui.SetUiState(bui, new ShuttleBoundUserInterfaceState(navState, mapState, dockState)); + _ui.SetUiState(consoleUid, ShuttleConsoleUiKey.Key, new ShuttleBoundUserInterfaceState(navState, mapState, dockState)); } } diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs index 51288691039..11cc16e0cd0 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.FasterThanLight.cs @@ -6,6 +6,8 @@ using Content.Server.Station.Events; using Content.Shared.Body.Components; using Content.Shared.Buckle.Components; +using Content.Shared.CCVar; +using Content.Shared.Database; using Content.Shared.Ghost; using Content.Shared.Maps; using Content.Shared.Parallax; @@ -33,14 +35,6 @@ public sealed partial class ShuttleSystem * This is a way to move a shuttle from one location to another, via an intermediate map for fanciness. */ - public const float DefaultStartupTime = 5.5f; - public const float DefaultTravelTime = 20f; - public const float DefaultArrivalTime = 5f; - private const float FTLCooldown = 10f; - public const float FTLMassLimit = 300f; - - // I'm too lazy to make CVars. - private readonly SoundSpecifier _startupSound = new SoundPathSpecifier("/Audio/Effects/Shuttle/hyperspace_begin.ogg") { Params = AudioParams.Default.WithVolume(-5f), @@ -51,7 +45,12 @@ public sealed partial class ShuttleSystem Params = AudioParams.Default.WithVolume(-5f), }; - private readonly TimeSpan _hyperspaceKnockdownTime = TimeSpan.FromSeconds(5); + public float DefaultStartupTime; + public float DefaultTravelTime; + public float DefaultArrivalTime; + private float FTLCooldown; + public float FTLMassLimit; + private TimeSpan _hyperspaceKnockdownTime = TimeSpan.FromSeconds(5); /// /// Left-side of the station we're allowed to use @@ -89,6 +88,13 @@ private void InitializeFTL() _physicsQuery = GetEntityQuery(); _statusQuery = GetEntityQuery(); _xformQuery = GetEntityQuery(); + + _cfg.OnValueChanged(CCVars.FTLStartupTime, time => DefaultStartupTime = time, true); + _cfg.OnValueChanged(CCVars.FTLTravelTime, time => DefaultTravelTime = time, true); + _cfg.OnValueChanged(CCVars.FTLArrivalTime, time => DefaultArrivalTime = time, true); + _cfg.OnValueChanged(CCVars.FTLCooldown, time => FTLCooldown = time, true); + _cfg.OnValueChanged(CCVars.FTLMassLimit, time => FTLMassLimit = time, true); + _cfg.OnValueChanged(CCVars.HyperspaceKnockdownTime, time => _hyperspaceKnockdownTime = TimeSpan.FromSeconds(time), true); } private void OnStationPostInit(ref StationPostInitEvent ev) @@ -210,7 +216,9 @@ public bool CanFTL(EntityUid shuttleUid, [NotNullWhen(false)] out string? reason return false; } - if (TryComp(shuttleUid, out PhysicsComponent? shuttlePhysics) && shuttlePhysics.Mass > FTLMassLimit) + if (FTLMassLimit > 0 && + TryComp(shuttleUid, out PhysicsComponent? shuttlePhysics) && + shuttlePhysics.Mass > FTLMassLimit) { reason = Loc.GetString("shuttle-console-mass"); return false; @@ -243,15 +251,18 @@ public void FTLToCoordinates( ShuttleComponent component, EntityCoordinates coordinates, Angle angle, - float startupTime = DefaultStartupTime, - float hyperspaceTime = DefaultTravelTime, + float? startupTime = null, + float? hyperspaceTime = null, string? priorityTag = null) { if (!TrySetupFTL(shuttleUid, component, out var hyperspace)) return; - hyperspace.StartupTime = startupTime; - hyperspace.TravelTime = hyperspaceTime; + startupTime ??= DefaultStartupTime; + hyperspaceTime ??= DefaultTravelTime; + + hyperspace.StartupTime = startupTime.Value; + hyperspace.TravelTime = hyperspaceTime.Value; hyperspace.StateTime = StartEndTime.FromStartDuration( _gameTiming.CurTime, TimeSpan.FromSeconds(hyperspace.StartupTime)); @@ -275,16 +286,19 @@ public void FTLToDock( EntityUid shuttleUid, ShuttleComponent component, EntityUid target, - float startupTime = DefaultStartupTime, - float hyperspaceTime = DefaultTravelTime, + float? startupTime = null, + float? hyperspaceTime = null, string? priorityTag = null) { if (!TrySetupFTL(shuttleUid, component, out var hyperspace)) return; + startupTime ??= DefaultStartupTime; + hyperspaceTime ??= DefaultTravelTime; + var config = _dockSystem.GetDockingConfig(shuttleUid, target, priorityTag); - hyperspace.StartupTime = startupTime; - hyperspace.TravelTime = hyperspaceTime; + hyperspace.StartupTime = startupTime.Value; + hyperspace.TravelTime = hyperspaceTime.Value; hyperspace.StateTime = StartEndTime.FromStartDuration( _gameTiming.CurTime, TimeSpan.FromSeconds(hyperspace.StartupTime)); @@ -863,6 +877,8 @@ private void Smimsh(EntityUid uid, FixturesComponent? manager = null, MapGridCom if (_bodyQuery.TryGetComponent(ent, out var mob)) { + _logger.Add(LogType.Gib, LogImpact.Extreme, $"{ToPrettyString(ent):player} got gibbed by the shuttle" + + $" {ToPrettyString(uid)} arriving from FTL at {xform.Coordinates:coordinates}"); var gibs = _bobby.GibBody(ent, body: mob); _immuneEnts.UnionWith(gibs); continue; diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.IFF.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.IFF.cs index bf265da2e64..ce79466b589 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.IFF.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.IFF.cs @@ -57,7 +57,7 @@ private void OnIFFConsoleAnchor(EntityUid uid, IFFConsoleComponent component, re !TryComp(uid, out var xform) || !TryComp(xform.GridUid, out var iff)) { - _uiSystem.TrySetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() + _uiSystem.SetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() { AllowedFlags = component.AllowedFlags, Flags = IFFFlags.None, @@ -65,7 +65,7 @@ private void OnIFFConsoleAnchor(EntityUid uid, IFFConsoleComponent component, re } else { - _uiSystem.TrySetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() + _uiSystem.SetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() { AllowedFlags = component.AllowedFlags, Flags = iff.Flags, @@ -83,7 +83,7 @@ protected override void UpdateIFFInterfaces(EntityUid gridUid, IFFComponent comp if (xform.GridUid != gridUid) continue; - _uiSystem.TrySetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() + _uiSystem.SetUiState(uid, IFFConsoleUiKey.Key, new IFFConsoleBoundUserInterfaceState() { AllowedFlags = comp.AllowedFlags, Flags = component.Flags, diff --git a/Content.Server/Shuttles/Systems/ShuttleSystem.cs b/Content.Server/Shuttles/Systems/ShuttleSystem.cs index 6dc25e8d766..6fe2324d51e 100644 --- a/Content.Server/Shuttles/Systems/ShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/ShuttleSystem.cs @@ -1,3 +1,4 @@ +using Content.Server.Administration.Logs; using Content.Server.Body.Systems; using Content.Server.Doors.Systems; using Content.Server.Parallax; @@ -48,6 +49,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem [Dependency] private readonly ThrowingSystem _throwing = default!; [Dependency] private readonly ThrusterSystem _thruster = default!; [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly IAdminLogManager _logger = default!; public const float TileMassMultiplier = 0.5f; diff --git a/Content.Server/Shuttles/Systems/ThrusterSystem.cs b/Content.Server/Shuttles/Systems/ThrusterSystem.cs index ee131d7857a..46715dd2916 100644 --- a/Content.Server/Shuttles/Systems/ThrusterSystem.cs +++ b/Content.Server/Shuttles/Systems/ThrusterSystem.cs @@ -268,11 +268,6 @@ public void EnableThruster(EntityUid uid, ThrusterComponent component, Transform return; } - if (TryComp(uid, out var apcPower)) - { - apcPower.NeedsPower = true; - } - component.IsOn = true; if (!EntityManager.TryGetComponent(xform.GridUid, out ShuttleComponent? shuttleComponent)) @@ -375,11 +370,6 @@ public void DisableThruster(EntityUid uid, ThrusterComponent component, EntityUi if (!EntityManager.TryGetComponent(gridId, out ShuttleComponent? shuttleComponent)) return; - if (TryComp(uid, out var apcPower)) - { - apcPower.NeedsPower = false; - } - // Logger.DebugS("thruster", $"Disabled thruster {uid}"); switch (component.Type) diff --git a/Content.Server/Silicon/WeldingHealable/WeldingHealableSystem.cs b/Content.Server/Silicon/WeldingHealable/WeldingHealableSystem.cs index e0783db0c8b..df7ac7ac0fd 100644 --- a/Content.Server/Silicon/WeldingHealable/WeldingHealableSystem.cs +++ b/Content.Server/Silicon/WeldingHealable/WeldingHealableSystem.cs @@ -1,11 +1,12 @@ using Content.Server.Silicon.WeldingHealing; -using Content.Server.Tools.Components; +using Content.Shared.Chemistry.Components; using Content.Shared.Silicon.WeldingHealing; using Content.Shared.Chemistry.Components.SolutionManager; using Content.Shared.Chemistry.EntitySystems; using Content.Shared.Damage; using Content.Shared.Interaction; using Content.Shared.Popups; +using Content.Shared.Tools.Components; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; namespace Content.Server.Silicon.WeldingHealable; @@ -32,13 +33,15 @@ private void OnRepairFinished(EntityUid uid, WeldingHealableComponent healableCo || !component.DamageContainers.Contains(damageable.DamageContainerID) || !HasDamage(damageable, component) || !TryComp(args.Used, out var welder) - || !TryComp(args.Used, out var solutionContainer) - || !_solutionContainer.ResolveSolution(((EntityUid) args.Used, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution)) + || !TryComp(args.Used, out var solutionContainer)) return; _damageableSystem.TryChangeDamage(uid, component.Damage, true, false, origin: args.User); - _solutionContainer.RemoveReagent(welder.FuelSolution.Value, welder.FuelReagent, component.FuelCost); + Entity? sol = new(); + if (!_solutionContainer.ResolveSolution(((EntityUid) args.Used, solutionContainer), welder.FuelSolutionName, ref sol, out _)) + return; + _solutionContainer.RemoveReagent(sol.Value, welder.FuelReagent, component.FuelCost); var str = Loc.GetString("comp-repairable-repair", ("target", uid), diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs new file mode 100644 index 00000000000..1c10cbe667e --- /dev/null +++ b/Content.Server/Silicons/Borgs/BorgSystem.Transponder.cs @@ -0,0 +1,107 @@ +using Content.Shared.DeviceNetwork; +using Content.Shared.Emag.Components; +using Content.Shared.Popups; +using Content.Shared.Robotics; +using Content.Shared.Silicons.Borgs.Components; +using Content.Server.DeviceNetwork; +using Content.Server.DeviceNetwork.Components; +using Content.Server.DeviceNetwork.Systems; +using Content.Server.Explosion.Components; + +namespace Content.Server.Silicons.Borgs; + +/// +public sealed partial class BorgSystem +{ + private void InitializeTransponder() + { + SubscribeLocalEvent(OnPacketReceived); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var now = _timing.CurTime; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp, out var chassis, out var device, out var meta)) + { + if (now < comp.NextBroadcast) + continue; + + var charge = 0f; + if (_powerCell.TryGetBatteryFromSlot(uid, out var battery)) + charge = battery.CurrentCharge / battery.MaxCharge; + + var data = new CyborgControlData( + comp.Sprite, + comp.Name, + meta.EntityName, + charge, + chassis.ModuleCount, + chassis.BrainEntity != null); + + var payload = new NetworkPayload() + { + [DeviceNetworkConstants.Command] = DeviceNetworkConstants.CmdUpdatedState, + [RoboticsConsoleConstants.NET_CYBORG_DATA] = data + }; + _deviceNetwork.QueuePacket(uid, null, payload, device: device); + + comp.NextBroadcast = now + comp.BroadcastDelay; + } + } + + private void OnPacketReceived(Entity ent, ref DeviceNetworkPacketEvent args) + { + var payload = args.Data; + if (!payload.TryGetValue(DeviceNetworkConstants.Command, out string? command)) + return; + + if (command == RoboticsConsoleConstants.NET_DISABLE_COMMAND) + Disable(ent); + else if (command == RoboticsConsoleConstants.NET_DESTROY_COMMAND) + Destroy(ent.Owner); + } + + private void Disable(Entity ent) + { + if (!Resolve(ent, ref ent.Comp2) || ent.Comp2.BrainEntity is not {} brain) + return; + + // this won't exactly be stealthy but if you are malf its better than actually disabling you + if (CheckEmagged(ent, "disabled")) + return; + + var message = Loc.GetString(ent.Comp1.DisabledPopup, ("name", Name(ent))); + Popup.PopupEntity(message, ent); + _container.Remove(brain, ent.Comp2.BrainContainer); + } + + private void Destroy(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + // this is stealthy until someone realises you havent exploded + if (CheckEmagged(ent, "destroyed")) + { + // prevent reappearing on the console a few seconds later + RemComp(ent); + return; + } + + _explosion.TriggerExplosive(ent, ent.Comp, delete: false); + } + + private bool CheckEmagged(EntityUid uid, string name) + { + if (HasComp(uid)) + { + Popup.PopupEntity(Loc.GetString($"borg-transponder-emagged-{name}-popup"), uid, uid, PopupType.LargeCaution); + return true; + } + + return false; + } +} diff --git a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs index 3dcdd78affa..d0e9f80e364 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.Ui.cs @@ -28,20 +28,19 @@ private void OnBeforeBorgUiOpen(EntityUid uid, BorgChassisComponent component, B private void OnEjectBrainBuiMessage(EntityUid uid, BorgChassisComponent component, BorgEjectBrainBuiMessage args) { - if (args.Session.AttachedEntity is not { } attachedEntity || component.BrainEntity is not { } brain) + if (component.BrainEntity is not { } brain) return; _adminLog.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(attachedEntity):player} removed brain {ToPrettyString(brain)} from borg {ToPrettyString(uid)}"); + $"{ToPrettyString(args.Actor):player} removed brain {ToPrettyString(brain)} from borg {ToPrettyString(uid)}"); _container.Remove(brain, component.BrainContainer); - _hands.TryPickupAnyHand(attachedEntity, brain); + _hands.TryPickupAnyHand(args.Actor, brain); UpdateUI(uid, component); } private void OnEjectBatteryBuiMessage(EntityUid uid, BorgChassisComponent component, BorgEjectBatteryBuiMessage args) { - if (args.Session.AttachedEntity is not { } attachedEntity || - !TryComp(uid, out var slotComp) || + if (!TryComp(uid, out var slotComp) || !Container.TryGetContainer(uid, slotComp.CellSlotId, out var container) || !container.ContainedEntities.Any()) { @@ -49,14 +48,11 @@ private void OnEjectBatteryBuiMessage(EntityUid uid, BorgChassisComponent compon } var ents = Container.EmptyContainer(container); - _hands.TryPickupAnyHand(attachedEntity, ents.First()); + _hands.TryPickupAnyHand(args.Actor, ents.First()); } private void OnSetNameBuiMessage(EntityUid uid, BorgChassisComponent component, BorgSetNameBuiMessage args) { - if (args.Session.AttachedEntity is not { } attachedEntity) - return; - if (args.Name.Length > HumanoidCharacterProfile.MaxNameLength || args.Name.Length == 0 || string.IsNullOrWhiteSpace(args.Name) || @@ -75,24 +71,21 @@ private void OnSetNameBuiMessage(EntityUid uid, BorgChassisComponent component, if (metaData.EntityName.Equals(name, StringComparison.InvariantCulture)) return; - _adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(attachedEntity):player} set borg \"{ToPrettyString(uid)}\"'s name to: {name}"); + _adminLog.Add(LogType.Action, LogImpact.High, $"{ToPrettyString(args.Actor):player} set borg \"{ToPrettyString(uid)}\"'s name to: {name}"); _metaData.SetEntityName(uid, name, metaData); } private void OnRemoveModuleBuiMessage(EntityUid uid, BorgChassisComponent component, BorgRemoveModuleBuiMessage args) { - if (args.Session.AttachedEntity is not { } attachedEntity) - return; - var module = GetEntity(args.Module); if (!component.ModuleContainer.Contains(module)) return; _adminLog.Add(LogType.Action, LogImpact.Medium, - $"{ToPrettyString(attachedEntity):player} removed module {ToPrettyString(module)} from borg {ToPrettyString(uid)}"); + $"{ToPrettyString(args.Actor):player} removed module {ToPrettyString(module)} from borg {ToPrettyString(uid)}"); _container.Remove(module, component.ModuleContainer); - _hands.TryPickupAnyHand(attachedEntity, module); + _hands.TryPickupAnyHand(args.Actor, module); UpdateUI(uid, component); } @@ -111,6 +104,6 @@ public void UpdateUI(EntityUid uid, BorgChassisComponent? component = null) } var state = new BorgBuiState(chargePercent, hasBattery); - _ui.TrySetUiState(uid, BorgUiKey.Key, state); + _ui.SetUiState(uid, BorgUiKey.Key, state); } } diff --git a/Content.Server/Silicons/Borgs/BorgSystem.cs b/Content.Server/Silicons/Borgs/BorgSystem.cs index 869c2797047..75f25a3a922 100644 --- a/Content.Server/Silicons/Borgs/BorgSystem.cs +++ b/Content.Server/Silicons/Borgs/BorgSystem.cs @@ -1,6 +1,8 @@ using Content.Server.Actions; using Content.Server.Administration.Logs; using Content.Server.Administration.Managers; +using Content.Server.DeviceNetwork.Systems; +using Content.Server.Explosion.EntitySystems; using Content.Server.Hands.Systems; using Content.Server.PowerCell; using Content.Shared.UserInterface; @@ -26,6 +28,7 @@ using Robust.Shared.Containers; using Robust.Shared.Player; using Robust.Shared.Random; +using Robust.Shared.Timing; namespace Content.Server.Silicons.Borgs; @@ -34,10 +37,13 @@ public sealed partial class BorgSystem : SharedBorgSystem { [Dependency] private readonly IAdminLogManager _adminLog = default!; [Dependency] private readonly IBanManager _banManager = default!; + [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SharedAccessSystem _access = default!; [Dependency] private readonly ActionsSystem _actions = default!; [Dependency] private readonly AlertsSystem _alerts = default!; + [Dependency] private readonly DeviceNetworkSystem _deviceNetwork = default!; + [Dependency] private readonly ExplosionSystem _explosion = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; [Dependency] private readonly HandsSystem _hands = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; @@ -73,6 +79,7 @@ public override void Initialize() InitializeModules(); InitializeMMI(); InitializeUI(); + InitializeTransponder(); } private void OnMapInit(EntityUid uid, BorgChassisComponent component, MapInitEvent args) diff --git a/Content.Server/Silicons/Laws/SiliconLawSystem.cs b/Content.Server/Silicons/Laws/SiliconLawSystem.cs index 010682bc0d3..bc7a7b35c27 100644 --- a/Content.Server/Silicons/Laws/SiliconLawSystem.cs +++ b/Content.Server/Silicons/Laws/SiliconLawSystem.cs @@ -55,7 +55,6 @@ public override void Initialize() SubscribeLocalEvent(OnEmagLawsAdded); SubscribeLocalEvent(OnEmagMindAdded); SubscribeLocalEvent(OnEmagMindRemoved); - SubscribeLocalEvent(OnExamined); } private void OnComponentShutdown(EntityUid uid, SiliconLawBoundComponent component, ComponentShutdown args) @@ -93,10 +92,10 @@ private void OnToggleLawsScreen(EntityUid uid, SiliconLawBoundComponent componen private void OnBoundUIOpened(EntityUid uid, SiliconLawBoundComponent component, BoundUIOpenedEvent args) { _entityManager.TryGetComponent(uid, out var intrinsicRadio); - HashSet? radioChannels = intrinsicRadio?.Channels; + var radioChannels = intrinsicRadio?.Channels; var state = new SiliconLawBuiState(GetLaws(uid).Laws, radioChannels); - _userInterface.TrySetUiState(args.Entity, SiliconLawsUiKey.Key, state, args.Session); + _userInterface.SetUiState(args.Entity, SiliconLawsUiKey.Key, state); } private void OnPlayerSpawnComplete(EntityUid uid, SiliconLawBoundComponent component, PlayerSpawnCompleteEvent args) @@ -155,17 +154,6 @@ private void OnEmagLawsAdded(EntityUid uid, SiliconLawProviderComponent componen }); } - private void OnExamined(EntityUid uid, EmagSiliconLawComponent component, ExaminedEvent args) - { - if (!args.IsInDetailsRange || !HasComp(uid)) - return; - - if (component.RequireOpenPanel && TryComp(uid, out var panel) && !panel.Open) - return; - - args.PushMarkup(Loc.GetString("laws-compromised-examine")); - } - protected override void OnGotEmagged(EntityUid uid, EmagSiliconLawComponent component, ref GotEmaggedEvent args) { if (component.RequireOpenPanel && TryComp(uid, out var panel) && !panel.Open) diff --git a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs index b26ab301c64..9107ff2e32e 100644 --- a/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/RadiationCollectorSystem.cs @@ -151,7 +151,8 @@ private void OnAnalyzed(EntityUid uid, RadiationCollectorComponent component, Ga if (!TryGetLoadedGasTank(uid, out var gasTankComponent)) return; - args.GasMixtures = new Dictionary { { Name(uid), gasTankComponent.Air } }; + args.GasMixtures ??= new List<(string, GasMixture?)>(); + args.GasMixtures.Add((Name(uid), gasTankComponent.Air)); } public void ToggleCollector(EntityUid uid, EntityUid? user = null, RadiationCollectorComponent? component = null) diff --git a/Content.Server/Solar/EntitySystems/PowerSolarControlConsoleSystem.cs b/Content.Server/Solar/EntitySystems/PowerSolarControlConsoleSystem.cs index 179cadcfbcb..dd3f0c00543 100644 --- a/Content.Server/Solar/EntitySystems/PowerSolarControlConsoleSystem.cs +++ b/Content.Server/Solar/EntitySystems/PowerSolarControlConsoleSystem.cs @@ -35,13 +35,13 @@ public override void Update(float frameTime) _updateTimer -= 1; var state = new SolarControlConsoleBoundInterfaceState(_powerSolarSystem.TargetPanelRotation, _powerSolarSystem.TargetPanelVelocity, _powerSolarSystem.TotalPanelPower, _powerSolarSystem.TowardsSun); var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var _, out var uiComp)) + while (query.MoveNext(out var uid, out _, out var uiComp)) { - _uiSystem.TrySetUiState(uid, SolarControlConsoleUiKey.Key, state, ui: uiComp); + _uiSystem.SetUiState((uid, uiComp), SolarControlConsoleUiKey.Key, state); } } } - + private void OnUIMessage(EntityUid uid, SolarControlConsoleComponent component, SolarControlConsoleAdjustMessage msg) { if (double.IsFinite(msg.Rotation)) diff --git a/Content.Server/Speech/Components/PirateAccentComponent.cs b/Content.Server/Speech/Components/PirateAccentComponent.cs index 0559d9854b8..b5b292775dc 100644 --- a/Content.Server/Speech/Components/PirateAccentComponent.cs +++ b/Content.Server/Speech/Components/PirateAccentComponent.cs @@ -15,6 +15,7 @@ public sealed partial class PirateAccentComponent : Component { "accent-pirate-prefix-1", "accent-pirate-prefix-2", - "accent-pirate-prefix-3" + "accent-pirate-prefix-3", + "accent-pirate-prefix-4", }; } diff --git a/Content.Server/Speech/Components/ReplacementAccentComponent.cs b/Content.Server/Speech/Components/ReplacementAccentComponent.cs index ac4e9fbafef..e7f57b80d04 100644 --- a/Content.Server/Speech/Components/ReplacementAccentComponent.cs +++ b/Content.Server/Speech/Components/ReplacementAccentComponent.cs @@ -32,5 +32,11 @@ public sealed partial class ReplacementAccentComponent : Component { [DataField("accent", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] public string Accent = default!; + + /// + /// Allows you to substitute words, not always, but with some chance + /// + [DataField] + public float ReplacementChance = 1f; } } diff --git a/Content.Server/Speech/EmotesMenuSystem.cs b/Content.Server/Speech/EmotesMenuSystem.cs new file mode 100644 index 00000000000..a69b5a65e43 --- /dev/null +++ b/Content.Server/Speech/EmotesMenuSystem.cs @@ -0,0 +1,30 @@ +using Content.Server.Chat.Systems; +using Content.Shared.Chat; +using Robust.Shared.Prototypes; + +namespace Content.Server.Speech; + +public sealed partial class EmotesMenuSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly ChatSystem _chat = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeAllEvent(OnPlayEmote); + } + + private void OnPlayEmote(PlayEmoteMessage msg, EntitySessionEventArgs args) + { + var player = args.SenderSession.AttachedEntity; + if (!player.HasValue) + return; + + if (!_prototypeManager.TryIndex(msg.ProtoId, out var proto) || proto.ChatTriggers.Count == 0) + return; + + _chat.TryEmoteWithChat(player.Value, msg.ProtoId); + } +} diff --git a/Content.Server/Speech/EntitySystems/AddAccentClothingSystem.cs b/Content.Server/Speech/EntitySystems/AddAccentClothingSystem.cs index 1f707c2249c..897cd061f42 100644 --- a/Content.Server/Speech/EntitySystems/AddAccentClothingSystem.cs +++ b/Content.Server/Speech/EntitySystems/AddAccentClothingSystem.cs @@ -1,6 +1,5 @@ using Content.Server.Speech.Components; -using Content.Shared.Clothing.Components; -using Content.Shared.Inventory.Events; +using Content.Shared.Clothing; namespace Content.Server.Speech.EntitySystems; @@ -11,29 +10,20 @@ public sealed class AddAccentClothingSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); } - private void OnGotEquipped(EntityUid uid, AddAccentClothingComponent component, GotEquippedEvent args) + private void OnGotEquipped(EntityUid uid, AddAccentClothingComponent component, ref ClothingGotEquippedEvent args) { - if (!TryComp(uid, out ClothingComponent? clothing)) - return; - - // check if entity was actually used as clothing - // not just taken in pockets or something - var isCorrectSlot = clothing.Slots.HasFlag(args.SlotFlags); - if (!isCorrectSlot) - return; - // does the user already has this accent? var componentType = _componentFactory.GetRegistration(component.Accent).Type; - if (HasComp(args.Equipee, componentType)) + if (HasComp(args.Wearer, componentType)) return; // add accent to the user var accentComponent = (Component) _componentFactory.GetComponent(componentType); - AddComp(args.Equipee, accentComponent); + AddComp(args.Wearer, accentComponent); // snowflake case for replacement accent if (accentComponent is ReplacementAccentComponent rep) @@ -42,16 +32,16 @@ private void OnGotEquipped(EntityUid uid, AddAccentClothingComponent component, component.IsActive = true; } - private void OnGotUnequipped(EntityUid uid, AddAccentClothingComponent component, GotUnequippedEvent args) + private void OnGotUnequipped(EntityUid uid, AddAccentClothingComponent component, ref ClothingGotUnequippedEvent args) { if (!component.IsActive) return; // try to remove accent var componentType = _componentFactory.GetRegistration(component.Accent).Type; - if (EntityManager.HasComponent(args.Equipee, componentType)) + if (EntityManager.HasComponent(args.Wearer, componentType)) { - EntityManager.RemoveComponent(args.Equipee, componentType); + EntityManager.RemoveComponent(args.Wearer, componentType); } component.IsActive = false; diff --git a/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs b/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs index 56372887325..f6d259c1153 100644 --- a/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/FrenchAccentSystem.cs @@ -10,6 +10,10 @@ public sealed class FrenchAccentSystem : EntitySystem { [Dependency] private readonly ReplacementAccentSystem _replacement = default!; + private static readonly Regex RegexTh = new(@"th", RegexOptions.IgnoreCase); + private static readonly Regex RegexStartH = new(@"(? DirectReplacements = new() - { - { "let me", "lemme" }, - { "should", "oughta" }, - { "the", "da" }, - { "them", "dem" }, - { "attack", "whack" }, - { "kill", "whack" }, - { "murder", "whack" }, - { "dead", "sleepin' with da fishies"}, - { "hey", "ey'o" }, - { "hi", "ey'o"}, - { "hello", "ey'o"}, - { "rules", "roolz" }, - { "you", "yous" }, - { "have to", "gotta" }, - { "going to", "boutta" }, - { "about to", "boutta" }, - { "here", "'ere" } - }; - public override void Initialize() { base.Initialize(); @@ -49,20 +36,30 @@ public string Accentuate(string message, MobsterAccentComponent component) // thinking -> thinkin' // king -> king - msg = Regex.Replace(msg, @"(?<=\w\w)ing(?!\w)", "in'", RegexOptions.IgnoreCase); + //Uses captures groups to make sure the captialization of IN is kept + msg = RegexIng.Replace(msg, "$1'"); // or -> uh and ar -> ah in the middle of words (fuhget, tahget) - msg = Regex.Replace(msg, @"(?<=\w)or(?=\w)", "uh", RegexOptions.IgnoreCase); - msg = Regex.Replace(msg, @"(?<=\w)ar(?=\w)", "ah", RegexOptions.IgnoreCase); + msg = RegexLowerOr.Replace(msg, "uh"); + msg = RegexUpperOr.Replace(msg, "UH"); + msg = RegexLowerAr.Replace(msg, "ah"); + msg = RegexUpperAr.Replace(msg, "AH"); // Prefix if (_random.Prob(0.15f)) { + //Checks if the first word of the sentence is all caps + //So the prefix can be allcapped and to not resanitize the captial + var firstWordAllCaps = !RegexFirstWord.Match(msg).Value.Any(char.IsLower); var pick = _random.Next(1, 2); // Reverse sanitize capital - msg = msg[0].ToString().ToLower() + msg.Remove(0, 1); - msg = Loc.GetString($"accent-mobster-prefix-{pick}") + " " + msg; + var prefix = Loc.GetString($"accent-mobster-prefix-{pick}"); + if (!firstWordAllCaps) + msg = msg[0].ToString().ToLower() + msg.Remove(0, 1); + else + prefix = prefix.ToUpper(); + msg = prefix + " " + msg; } // Sanitize capital again, in case we substituted a word that should be capitalized @@ -71,16 +68,23 @@ public string Accentuate(string message, MobsterAccentComponent component) // Suffixes if (_random.Prob(0.4f)) { + //Checks if the last word of the sentence is all caps + //So the suffix can be allcapped + var lastWordAllCaps = !RegexLastWord.Match(msg).Value.Any(char.IsLower); + var suffix = ""; if (component.IsBoss) { var pick = _random.Next(1, 4); - msg += Loc.GetString($"accent-mobster-suffix-boss-{pick}"); + suffix = Loc.GetString($"accent-mobster-suffix-boss-{pick}"); } else { var pick = _random.Next(1, 3); - msg += Loc.GetString($"accent-mobster-suffix-minion-{pick}"); + suffix = Loc.GetString($"accent-mobster-suffix-minion-{pick}"); } + if (lastWordAllCaps) + suffix = suffix.ToUpper(); + msg += suffix; } return msg; diff --git a/Content.Server/Speech/EntitySystems/MothAccentSystem.cs b/Content.Server/Speech/EntitySystems/MothAccentSystem.cs index 3de4651b4af..84b79d4ce98 100644 --- a/Content.Server/Speech/EntitySystems/MothAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/MothAccentSystem.cs @@ -5,6 +5,9 @@ namespace Content.Server.Speech.EntitySystems; public sealed class MothAccentSystem : EntitySystem { + private static readonly Regex RegexLowerBuzz = new Regex("z{1,3}"); + private static readonly Regex RegexUpperBuzz = new Regex("Z{1,3}"); + public override void Initialize() { base.Initialize(); @@ -16,10 +19,10 @@ private void OnAccent(EntityUid uid, MothAccentComponent component, AccentGetEve var message = args.Message; // buzzz - message = Regex.Replace(message, "z{1,3}", "zzz"); + message = RegexLowerBuzz.Replace(message, "zzz"); // buZZZ - message = Regex.Replace(message, "Z{1,3}", "ZZZ"); - + message = RegexUpperBuzz.Replace(message, "ZZZ"); + args.Message = message; } } diff --git a/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs b/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs index 10437c235d6..ae8fe522b9b 100644 --- a/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/ParrotAccentSystem.cs @@ -7,6 +7,8 @@ namespace Content.Server.Speech.EntitySystems; public sealed partial class ParrotAccentSystem : EntitySystem { + private static readonly Regex WordCleanupRegex = new Regex("[^A-Za-z0-9 -]"); + [Dependency] private readonly IRobustRandom _random = default!; public override void Initialize() @@ -27,7 +29,7 @@ public string Accentuate(Entity entity, string message) if (_random.Prob(entity.Comp.LongestWordRepeatChance)) { // Don't count non-alphanumeric characters as parts of words - var cleaned = Regex.Replace(message, "[^A-Za-z0-9 -]", string.Empty); + var cleaned = WordCleanupRegex.Replace(message, string.Empty); // Split on whitespace and favor words towards the end of the message var words = cleaned.Split(null).Reverse(); // Find longest word diff --git a/Content.Server/Speech/EntitySystems/PirateAccentSystem.cs b/Content.Server/Speech/EntitySystems/PirateAccentSystem.cs index f1d64ede101..84298cbf01a 100644 --- a/Content.Server/Speech/EntitySystems/PirateAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/PirateAccentSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Server.Speech.Components; using Robust.Shared.Random; using System.Text.RegularExpressions; @@ -6,6 +7,8 @@ namespace Content.Server.Speech.EntitySystems; public sealed class PirateAccentSystem : EntitySystem { + private static readonly Regex FirstWordAllCapsRegex = new(@"^(\S+)"); + [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly ReplacementAccentSystem _replacement = default!; @@ -19,17 +22,22 @@ public override void Initialize() // converts left word when typed into the right word. For example typing you becomes ye. public string Accentuate(string message, PirateAccentComponent component) { - var msg = message; - - msg = _replacement.ApplyReplacements(msg, "pirate"); + var msg = _replacement.ApplyReplacements(message, "pirate"); if (!_random.Prob(component.YarrChance)) return msg; + //Checks if the first word of the sentence is all caps + //So the prefix can be allcapped and to not resanitize the captial + var firstWordAllCaps = !FirstWordAllCapsRegex.Match(msg).Value.Any(char.IsLower); var pick = _random.Pick(component.PirateWords); + var pirateWord = Loc.GetString(pick); // Reverse sanitize capital - msg = msg[0].ToString().ToLower() + msg.Remove(0, 1); - msg = Loc.GetString(pick) + " " + msg; + if (!firstWordAllCaps) + msg = msg[0].ToString().ToLower() + msg.Remove(0, 1); + else + pirateWord = pirateWord.ToUpper(); + msg = pirateWord + " " + msg; return msg; } diff --git a/Content.Server/Speech/EntitySystems/ReplacementAccentSystem.cs b/Content.Server/Speech/EntitySystems/ReplacementAccentSystem.cs index 36fa7e07ad5..da198bcc12b 100644 --- a/Content.Server/Speech/EntitySystems/ReplacementAccentSystem.cs +++ b/Content.Server/Speech/EntitySystems/ReplacementAccentSystem.cs @@ -24,6 +24,9 @@ public override void Initialize() private void OnAccent(EntityUid uid, ReplacementAccentComponent component, AccentGetEvent args) { + if (!_random.Prob(component.ReplacementChance)) + return; + args.Message = ApplyReplacements(args.Message, component.Accent); } @@ -46,6 +49,12 @@ public string ApplyReplacements(string message, string accent) if (prototype.WordReplacements == null) return message; + // Prohibition of repeated word replacements. + // All replaced words placed in the final message are placed here as dashes (___) with the same length. + // The regex search goes through this buffer message, from which the already replaced words are crossed out, + // ensuring that the replaced words cannot be replaced again. + var maskMessage = message; + foreach (var (first, replace) in prototype.WordReplacements) { var f = _loc.GetString(first); @@ -53,10 +62,10 @@ public string ApplyReplacements(string message, string accent) // this is kind of slow but its not that bad // essentially: go over all matches, try to match capitalization where possible, then replace // rather than using regex.replace - for (int i = Regex.Count(message, $@"(? 0; i--) + for (int i = Regex.Count(maskMessage, $@"(? 0; i--) { // fetch the match again as the character indices may have changed - Match match = Regex.Match(message, $@"(? +/// Runs EnsurePlanet against the largest grid on Mapinit. +/// +[RegisterComponent, Access(typeof(StationBiomeSystem))] +public sealed partial class StationBiomeComponent : Component +{ + [DataField(required: true)] + public ProtoId Biome = "Grasslands"; + + // If null, its random + [DataField] + public int? Seed = null; + + [DataField] + public Color MapLightColor = Color.Black; +} diff --git a/Content.Server/Station/Events/StationPostInitEvent.cs b/Content.Server/Station/Events/StationPostInitEvent.cs index 4f7927cee52..54b8eeeb312 100644 --- a/Content.Server/Station/Events/StationPostInitEvent.cs +++ b/Content.Server/Station/Events/StationPostInitEvent.cs @@ -4,6 +4,8 @@ namespace Content.Server.Station.Events; /// /// Raised directed on a station after it has been initialized, as well as broadcast. +/// This gets raised after the entity has been map-initialized, and the station's centcomm map/entity (if any) has been +/// set up. /// [ByRefEvent] public readonly record struct StationPostInitEvent(Entity Station); diff --git a/Content.Server/Station/Systems/StationBiomeSystem.cs b/Content.Server/Station/Systems/StationBiomeSystem.cs new file mode 100644 index 00000000000..8c80806ccf5 --- /dev/null +++ b/Content.Server/Station/Systems/StationBiomeSystem.cs @@ -0,0 +1,35 @@ +using Content.Server.Parallax; +using Content.Server.Station.Components; +using Content.Server.Station.Events; +using Content.Server.Station.Systems; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; + +namespace Content.Server.Station.Systems; +public sealed partial class StationBiomeSystem : EntitySystem +{ + [Dependency] private readonly BiomeSystem _biome = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly StationSystem _station = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnStationPostInit); + } + + private void OnStationPostInit(Entity map, ref StationPostInitEvent args) + { + if (!TryComp(map, out StationDataComponent? dataComp)) + return; + + var station = _station.GetLargestGrid(dataComp); + if (station == null) return; + + var mapId = Transform(station.Value).MapID; + var mapUid = _mapManager.GetMapEntityId(mapId); + + _biome.EnsurePlanet(mapUid, _proto.Index(map.Comp.Biome), map.Comp.Seed, mapLight: map.Comp.MapLightColor); + } +} diff --git a/Content.Server/Station/Systems/StationSpawningSystem.cs b/Content.Server/Station/Systems/StationSpawningSystem.cs index 92f16de5c73..85be5f740d5 100644 --- a/Content.Server/Station/Systems/StationSpawningSystem.cs +++ b/Content.Server/Station/Systems/StationSpawningSystem.cs @@ -58,6 +58,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem /// public override void Initialize() { + base.Initialize(); Subs.CVar(_configurationManager, CCVars.ICRandomCharacters, e => _randomizeCharacters = e, true); _spawnerCallbacks = new Dictionary>() @@ -173,12 +174,15 @@ public EntityUid SpawnPlayerMob( if (prototype?.StartingGear != null) { var startingGear = _prototypeManager.Index(prototype.StartingGear); - EquipStartingGear(entity.Value, startingGear); + EquipStartingGear(entity.Value, startingGear, raiseEvent: false); if (profile != null) EquipIdCard(entity.Value, profile.Name, prototype, station); _internalEncryption.TryInsertEncryptionKey(entity.Value, startingGear, EntityManager); } + var gearEquippedEv = new StartingGearEquippedEvent(entity.Value); + RaiseLocalEvent(entity.Value, ref gearEquippedEv, true); + if (profile != null) { _humanoidSystem.LoadProfile(entity.Value, profile); diff --git a/Content.Server/Station/Systems/StationSystem.cs b/Content.Server/Station/Systems/StationSystem.cs index 408b3ebc555..2fa2671b196 100644 --- a/Content.Server/Station/Systems/StationSystem.cs +++ b/Content.Server/Station/Systems/StationSystem.cs @@ -112,26 +112,12 @@ private void OnPostGameMapLoad(PostGameMapLoad ev) { var dict = new Dictionary>(); - void AddGrid(string station, EntityUid grid) - { - if (dict.ContainsKey(station)) - { - dict[station].Add(grid); - } - else - { - dict[station] = new List {grid}; - } - } - // Iterate over all BecomesStation foreach (var grid in ev.Grids) { // We still setup the grid - if (!TryComp(grid, out var becomesStation)) - continue; - - AddGrid(becomesStation.Id, grid); + if (TryComp(grid, out var becomesStation)) + dict.GetOrNew(becomesStation.Id).Add(grid); } if (!dict.Any()) @@ -294,8 +280,6 @@ public EntityUid InitializeNewStation(StationConfig stationConfig, IEnumerable + /// Alert level to set the station to when the event starts. + /// + [DataField] + public string AlertLevel = "blue"; +} diff --git a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs index 282ee5b612a..9771e02e038 100644 --- a/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs +++ b/Content.Server/StationEvents/Components/RampingStationEventSchedulerComponent.cs @@ -24,6 +24,7 @@ public sealed partial class RampingStationEventSchedulerComponent : Component /// /// The number by which average expected shift length is multiplied. Higher values lead to slower chaos growth. /// + [DataField] public float ShiftLengthModifier = 1f; // Everything below is overridden in the RampingStationEventSchedulerSystem based on CVars diff --git a/Content.Server/StationEvents/Components/StationEventComponent.cs b/Content.Server/StationEvents/Components/StationEventComponent.cs index 980034aa7b7..54af1a59d99 100644 --- a/Content.Server/StationEvents/Components/StationEventComponent.cs +++ b/Content.Server/StationEvents/Components/StationEventComponent.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Audio; +using Robust.Shared.Audio; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.StationEvents.Components; @@ -15,43 +15,43 @@ public sealed partial class StationEventComponent : Component public const float WeightHigh = 15.0f; public const float WeightVeryHigh = 20.0f; - [DataField("weight")] + [DataField] public float Weight = WeightNormal; - [DataField("startAnnouncement")] + [DataField] public bool StartAnnouncement; - [DataField("endAnnouncement")] + [DataField] public bool EndAnnouncement; /// /// In minutes, when is the first round time this event can start /// - [DataField("earliestStart")] + [DataField] public int EarliestStart = 5; /// /// In minutes, the amount of time before the same event can occur again /// - [DataField("reoccurrenceDelay")] + [DataField] public int ReoccurrenceDelay = 30; /// /// How long after being added does the event start /// - [DataField("startDelay")] + [DataField] public TimeSpan StartDelay = TimeSpan.Zero; /// /// How long the event lasts. /// - [DataField("duration")] + [DataField] public TimeSpan? Duration = TimeSpan.FromSeconds(1); /// /// The max amount of time the event lasts. /// - [DataField("maxDuration")] + [DataField] public TimeSpan? MaxDuration; /// @@ -60,13 +60,13 @@ public sealed partial class StationEventComponent : Component /// /// To avoid running deadly events with low-pop /// - [DataField("minimumPlayers")] + [DataField] public int MinimumPlayers; /// /// How many times this even can occur in a single round /// - [DataField("maxOccurrences")] + [DataField] public int? MaxOccurrences; /// diff --git a/Content.Server/StationEvents/EventManagerSystem.cs b/Content.Server/StationEvents/EventManagerSystem.cs index 2d8606e9293..9c0005d06db 100644 --- a/Content.Server/StationEvents/EventManagerSystem.cs +++ b/Content.Server/StationEvents/EventManagerSystem.cs @@ -1,4 +1,5 @@ using System.Linq; +using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Server.StationEvents.Components; using Content.Shared.CCVar; @@ -16,6 +17,7 @@ public sealed class EventManagerSystem : EntitySystem [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IChatManager _chat = default!; [Dependency] public readonly GameTicker GameTicker = default!; [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; //Nyano - Summary: pulls in the glimmer system. @@ -45,6 +47,7 @@ public string RunRandomEvent() var ent = GameTicker.AddGameRule(randomEvent); var str = Loc.GetString("station-event-system-run-event",("eventName", ToPrettyString(ent))); + _chat.SendAdminAlert(str); Log.Info(str); return str; } diff --git a/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs b/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs new file mode 100644 index 00000000000..a78a542d3b3 --- /dev/null +++ b/Content.Server/StationEvents/Events/AlertLevelInterceptionRule.cs @@ -0,0 +1,23 @@ +using Content.Server.GameTicking.Components; +using Content.Server.StationEvents.Components; +using Content.Server.AlertLevel; + +namespace Content.Server.StationEvents.Events; + +public sealed class AlertLevelInterceptionRule : StationEventSystem +{ + [Dependency] private readonly AlertLevelSystem _alertLevelSystem = default!; + + protected override void Started(EntityUid uid, AlertLevelInterceptionRuleComponent component, GameRuleComponent gameRule, + GameRuleStartedEvent args) + { + base.Started(uid, component, gameRule, args); + + if (!TryGetRandomStation(out var chosenStation)) + return; + if (_alertLevelSystem.GetLevel(chosenStation.Value) != "green") + return; + + _alertLevelSystem.SetLevel(chosenStation.Value, component.AlertLevel, true, true, true); + } +} \ No newline at end of file diff --git a/Content.Server/StationEvents/Events/CargoGiftsRule.cs b/Content.Server/StationEvents/Events/CargoGiftsRule.cs index 62f01f58fe6..550f799b27e 100644 --- a/Content.Server/StationEvents/Events/CargoGiftsRule.cs +++ b/Content.Server/StationEvents/Events/CargoGiftsRule.cs @@ -1,4 +1,4 @@ -using System.Linq; +using System.Linq; using Content.Server.Cargo.Components; using Content.Server.Cargo.Systems; using Content.Server.GameTicking; @@ -74,13 +74,14 @@ protected override void ActiveTick(EntityUid uid, CargoGiftsRuleComponent compon if (!_cargoSystem.AddAndApproveOrder( station!.Value, product.Product, + product.Name, product.Cost, qty, Loc.GetString(component.Sender), Loc.GetString(component.Description), Loc.GetString(component.Dest), cargoDb, - stationData! + (station.Value, stationData) )) { break; diff --git a/Content.Server/StationEvents/Events/StationEventSystem.cs b/Content.Server/StationEvents/Events/StationEventSystem.cs index 257babd0d2c..040ebad2260 100644 --- a/Content.Server/StationEvents/Events/StationEventSystem.cs +++ b/Content.Server/StationEvents/Events/StationEventSystem.cs @@ -1,3 +1,4 @@ +using System.Linq; using Content.Server.Administration.Logs; using Content.Server.Chat.Systems; using Content.Server.GameTicking.Components; @@ -46,6 +47,7 @@ protected override void Added(EntityUid uid, T component, GameRuleComponent game if (!TryComp(uid, out var stationEvent)) return; + AdminLogManager.Add(LogType.EventAnnounced, $"Event added / announced: {ToPrettyString(uid)}"); stationEvent.StartTime = Timing.CurTime + stationEvent.StartDelay; diff --git a/Content.Server/StationGoal/StationGoalPaperSystem.cs b/Content.Server/StationGoal/StationGoalPaperSystem.cs index 6a059c37a3d..8442f9b4aac 100644 --- a/Content.Server/StationGoal/StationGoalPaperSystem.cs +++ b/Content.Server/StationGoal/StationGoalPaperSystem.cs @@ -9,6 +9,7 @@ using Robust.Shared.Prototypes; using Robust.Shared.Random; using Content.Shared.Dataset; +using Content.Shared.Fax.Components; namespace Content.Server.StationGoal; diff --git a/Content.Server/StationGoal/StationGoalPrototype.cs b/Content.Server/StationGoal/StationGoalPrototype.cs index 733759a37df..c49d49e939e 100644 --- a/Content.Server/StationGoal/StationGoalPrototype.cs +++ b/Content.Server/StationGoal/StationGoalPrototype.cs @@ -3,7 +3,7 @@ namespace Content.Server.StationGoal { [Serializable, Prototype("stationGoal")] - public sealed class StationGoalPrototype : IPrototype + public sealed partial class StationGoalPrototype : IPrototype { [IdDataFieldAttribute] public string ID { get; } = default!; diff --git a/Content.Server/StationRecords/Systems/GeneralStationRecordConsoleSystem.cs b/Content.Server/StationRecords/Systems/GeneralStationRecordConsoleSystem.cs index 721eff6f2cf..a5202285d99 100644 --- a/Content.Server/StationRecords/Systems/GeneralStationRecordConsoleSystem.cs +++ b/Content.Server/StationRecords/Systems/GeneralStationRecordConsoleSystem.cs @@ -57,7 +57,7 @@ private void UpdateUserInterface(Entity en if (!TryComp(owningStation, out var stationRecords)) { - _ui.TrySetUiState(uid, GeneralStationRecordConsoleKey.Key, new GeneralStationRecordConsoleState()); + _ui.SetUiState(uid, GeneralStationRecordConsoleKey.Key, new GeneralStationRecordConsoleState()); return; } @@ -66,7 +66,7 @@ private void UpdateUserInterface(Entity en switch (listing.Count) { case 0: - _ui.TrySetUiState(uid, GeneralStationRecordConsoleKey.Key, new GeneralStationRecordConsoleState()); + _ui.SetUiState(uid, GeneralStationRecordConsoleKey.Key, new GeneralStationRecordConsoleState()); return; case 1: console.ActiveKey = listing.Keys.First(); @@ -80,6 +80,6 @@ private void UpdateUserInterface(Entity en _stationRecords.TryGetRecord(key, out var record, stationRecords); GeneralStationRecordConsoleState newState = new(id, record, listing, console.Filter); - _ui.TrySetUiState(uid, GeneralStationRecordConsoleKey.Key, newState); + _ui.SetUiState(uid, GeneralStationRecordConsoleKey.Key, newState); } } diff --git a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs index 67f50d7a4e1..58c4c876c50 100644 --- a/Content.Server/StationRecords/Systems/StationRecordsSystem.cs +++ b/Content.Server/StationRecords/Systems/StationRecordsSystem.cs @@ -211,7 +211,7 @@ public bool TryGetRecord(StationRecordKey key, [NotNullWhen(true)] out T? ent /// public uint? GetRecordByName(EntityUid station, string name, StationRecordsComponent? records = null) { - if (!Resolve(station, ref records)) + if (!Resolve(station, ref records, false)) return null; foreach (var (id, record) in GetRecordsOfType(station, records)) diff --git a/Content.Server/Storage/Components/EntityStorageComponent.cs b/Content.Server/Storage/Components/EntityStorageComponent.cs index 40fdb1b3261..3fba89b64ab 100644 --- a/Content.Server/Storage/Components/EntityStorageComponent.cs +++ b/Content.Server/Storage/Components/EntityStorageComponent.cs @@ -1,4 +1,5 @@ using Content.Server.Atmos; +using Content.Shared.Atmos; using Content.Shared.Storage.Components; using Robust.Shared.GameStates; diff --git a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs index c49bfdec931..4c533ede3ad 100644 --- a/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs +++ b/Content.Server/Storage/EntitySystems/SpawnItemsOnUseSystem.cs @@ -82,7 +82,9 @@ private void OnUseInHand(EntityUid uid, SpawnItemsOnUseComponent component, UseI if (component.Sound != null) { - _audio.PlayPvs(component.Sound, uid); + // The entity is often deleted, so play the sound at its position rather than parenting + var coordinates = Transform(uid).Coordinates; + _audio.PlayPvs(component.Sound, coordinates); } component.Uses--; diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs b/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs index 10278cc8051..768491f9876 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.Fill.cs @@ -65,12 +65,23 @@ private void FillStorage(Entity entity var sortedItems = items .OrderByDescending(x => ItemSystem.GetItemShape(x.Comp).GetArea()); + ClearCantFillReasons(); foreach (var ent in sortedItems) { if (Insert(uid, ent, out _, out var reason, storageComp: storage, playSound: false)) continue; + if (CantFillReasons.Count > 0) + { + var reasons = string.Join(", ", CantFillReasons.Select(s => Loc.GetString(s))); + if (reason == null) + reason = reasons; + else + reason += $", {reasons}"; + } + Log.Error($"Tried to StorageFill {ToPrettyString(ent)} inside {ToPrettyString(uid)} but can't. reason: {reason}"); + ClearCantFillReasons(); Del(ent); } } diff --git a/Content.Server/Storage/EntitySystems/StorageSystem.cs b/Content.Server/Storage/EntitySystems/StorageSystem.cs index 0f5efda74de..4b5dd7290c0 100644 --- a/Content.Server/Storage/EntitySystems/StorageSystem.cs +++ b/Content.Server/Storage/EntitySystems/StorageSystem.cs @@ -3,17 +3,12 @@ using Content.Shared.Explosion; using Content.Shared.Ghost; using Content.Shared.Hands; -using Content.Shared.Input; -using Content.Shared.Inventory; using Content.Shared.Lock; using Content.Shared.Storage; using Content.Shared.Storage.Components; using Content.Shared.Storage.EntitySystems; -using Content.Shared.Timing; using Content.Shared.Verbs; using Robust.Server.GameObjects; -using Robust.Shared.Audio.Systems; -using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -23,95 +18,14 @@ namespace Content.Server.Storage.EntitySystems; public sealed partial class StorageSystem : SharedStorageSystem { - [Dependency] private readonly IAdminManager _admin = default!; [Dependency] private readonly IPrototypeManager _prototype = default!; - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly UseDelaySystem _useDelay = default!; public override void Initialize() { base.Initialize(); - SubscribeLocalEvent>(AddUiVerb); - Subs.BuiEvents(StorageComponent.StorageUiKey.Key, subs => - { - subs.Event(OnBoundUIClosed); - }); SubscribeLocalEvent(OnExploded); SubscribeLocalEvent(OnStorageFillMapInit); - - CommandBinds.Builder - .Bind(ContentKeyFunctions.OpenBackpack, InputCmdHandler.FromDelegate(HandleOpenBackpack)) - .Bind(ContentKeyFunctions.OpenBelt, InputCmdHandler.FromDelegate(HandleOpenBelt)) - .Register(); - } - - private void AddUiVerb(EntityUid uid, StorageComponent component, GetVerbsEvent args) - { - var silent = false; - if (!args.CanAccess || !args.CanInteract || TryComp(uid, out var lockComponent) && lockComponent.Locked) - { - // we allow admins to open the storage anyways - if (!_admin.HasAdminFlag(args.User, AdminFlags.Admin)) - return; - - silent = true; - } - - silent |= HasComp(args.User); - - // Get the session for the user - if (!TryComp(args.User, out var actor)) - return; - - // Does this player currently have the storage UI open? - var uiOpen = _uiSystem.SessionHasOpenUi(uid, StorageComponent.StorageUiKey.Key, actor.PlayerSession); - - ActivationVerb verb = new() - { - Act = () => - { - if (uiOpen) - { - _uiSystem.TryClose(uid, StorageComponent.StorageUiKey.Key, actor.PlayerSession); - } - else - { - OpenStorageUI(uid, args.User, component, silent); - } - } - }; - if (uiOpen) - { - verb.Text = Loc.GetString("verb-common-close-ui"); - verb.Icon = new SpriteSpecifier.Texture( - new("/Textures/Interface/VerbIcons/close.svg.192dpi.png")); - } - else - { - verb.Text = Loc.GetString("verb-common-open-ui"); - verb.Icon = new SpriteSpecifier.Texture( - new("/Textures/Interface/VerbIcons/open.svg.192dpi.png")); - } - args.Verbs.Add(verb); - } - - private void OnBoundUIClosed(EntityUid uid, StorageComponent storageComp, BoundUIClosedEvent args) - { - if (TryComp(args.Session.AttachedEntity, out var actor) && actor?.PlayerSession != null) - CloseNestedInterfaces(uid, actor.PlayerSession, storageComp); - - // If UI is closed for everyone - if (!_uiSystem.IsUiOpen(uid, args.UiKey)) - { - storageComp.IsUiOpen = false; - UpdateAppearance((uid, storageComp, null)); - - if (storageComp.StorageCloseSound is not null) - Audio.PlayEntity(storageComp.StorageCloseSound, Filter.Pvs(uid, entityManager: EntityManager), uid, true, storageComp.StorageCloseSound.Params); - } } private void OnExploded(Entity ent, ref BeforeExplodeEvent args) @@ -119,34 +33,6 @@ private void OnExploded(Entity ent, ref BeforeExplodeEvent arg args.Contents.AddRange(ent.Comp.Container.ContainedEntities); } - /// - /// Opens the storage UI for an entity - /// - /// The entity to open the UI for - public override void OpenStorageUI(EntityUid uid, EntityUid entity, StorageComponent? storageComp = null, bool silent = false) - { - if (!Resolve(uid, ref storageComp, false) || !TryComp(entity, out ActorComponent? player)) - return; - - // prevent spamming bag open / honkerton honk sound - silent |= TryComp(uid, out var useDelay) && _useDelay.IsDelayed((uid, useDelay)); - if (!silent) - { - if (!storageComp.IsUiOpen) - _audio.PlayPvs(storageComp.StorageOpenSound, uid); - if (useDelay != null) - _useDelay.TryResetDelay((uid, useDelay)); - } - - Log.Debug($"Storage (UID {uid}) \"used\" by player session (UID {player.PlayerSession.AttachedEntity})."); - - var bui = _uiSystem.GetUiOrNull(uid, StorageComponent.StorageUiKey.Key); - if (bui == null) - return; - _uiSystem.OpenUi(bui, player.PlayerSession); - _uiSystem.SendUiMessage(bui, new StorageModifyWindowMessage()); - } - /// public override void PlayPickupAnimation(EntityUid uid, EntityCoordinates initialCoordinates, EntityCoordinates finalCoordinates, Angle initialRotation, EntityUid? user = null) @@ -154,57 +40,4 @@ public override void PlayPickupAnimation(EntityUid uid, EntityCoordinates initia var filter = Filter.Pvs(uid).RemoveWhereAttachedEntity(e => e == user); RaiseNetworkEvent(new PickupAnimationEvent(GetNetEntity(uid), GetNetCoordinates(initialCoordinates), GetNetCoordinates(finalCoordinates), initialRotation), filter); } - - /// - /// If the user has nested-UIs open (e.g., PDA UI open when pda is in a backpack), close them. - /// - /// - public void CloseNestedInterfaces(EntityUid uid, ICommonSession session, StorageComponent? storageComp = null) - { - if (!Resolve(uid, ref storageComp)) - return; - - // for each containing thing - // if it has a storage comp - // ensure unsubscribe from session - // if it has a ui component - // close ui - foreach (var entity in storageComp.Container.ContainedEntities) - { - if (!TryComp(entity, out UserInterfaceComponent? ui)) - continue; - - foreach (var bui in ui.Interfaces.Values) - { - _uiSystem.TryClose(entity, bui.UiKey, session, ui); - } - } - } - - private void HandleOpenBackpack(ICommonSession? session) - { - HandleOpenSlotUI(session, "back"); - } - - private void HandleOpenBelt(ICommonSession? session) - { - HandleOpenSlotUI(session, "belt"); - } - - private void HandleOpenSlotUI(ICommonSession? session, string slot) - { - if (session is not { } playerSession) - return; - - if (playerSession.AttachedEntity is not {Valid: true} playerEnt || !Exists(playerEnt)) - return; - - if (!_inventory.TryGetSlotEntity(playerEnt, slot, out var storageEnt)) - return; - - if (!ActionBlocker.CanInteract(playerEnt, storageEnt)) - return; - - OpenStorageUI(storageEnt.Value, playerEnt); - } } diff --git a/Content.Server/Store/Systems/StoreSystem.Refund.cs b/Content.Server/Store/Systems/StoreSystem.Refund.cs index d59ee75e3ea..5a8be4be2bb 100644 --- a/Content.Server/Store/Systems/StoreSystem.Refund.cs +++ b/Content.Server/Store/Systems/StoreSystem.Refund.cs @@ -1,4 +1,4 @@ -using Content.Server.Store.Components; +using Content.Server.Store.Components; using Robust.Shared.Containers; namespace Content.Server.Store.Systems; diff --git a/Content.Server/Store/Systems/StoreSystem.Ui.cs b/Content.Server/Store/Systems/StoreSystem.Ui.cs index 7187a704768..0d2f3af91b3 100644 --- a/Content.Server/Store/Systems/StoreSystem.Ui.cs +++ b/Content.Server/Store/Systems/StoreSystem.Ui.cs @@ -73,7 +73,7 @@ public void CloseUi(EntityUid uid, StoreComponent? component = null) if (!Resolve(uid, ref component)) return; - _ui.TryCloseAll(uid, StoreUiKey.Key); + _ui.CloseUi(uid, StoreUiKey.Key); } /// @@ -83,12 +83,13 @@ public void CloseUi(EntityUid uid, StoreComponent? component = null) /// The store entity itself /// The store component being refreshed. /// - public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null, PlayerBoundUserInterface? ui = null) + public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent? component = null) { if (!Resolve(store, ref component)) return; - if (ui == null && !_ui.TryGetUi(store, StoreUiKey.Key, out ui)) + // TODO: Why is the state not being set unless this? + if (!_ui.HasUi(store, StoreUiKey.Key)) return; //this is the person who will be passed into logic for all listing filtering. @@ -113,12 +114,12 @@ public void UpdateUserInterface(EntityUid? user, EntityUid store, StoreComponent // only tell operatives to lock their uplink if it can be locked var showFooter = HasComp(store); var state = new StoreUpdateState(component.LastAvailableListings, allCurrency, showFooter, component.RefundAllowed); - _ui.SetUiState(ui, state); + _ui.SetUiState(store, StoreUiKey.Key, state); } private void OnRequestUpdate(EntityUid uid, StoreComponent component, StoreRequestUpdateInterfaceMessage args) { - UpdateUserInterface(args.Session.AttachedEntity, GetEntity(args.Entity), component); + UpdateUserInterface(args.Actor, GetEntity(args.Entity), component); } private void BeforeActivatableUiOpen(EntityUid uid, StoreComponent component, BeforeActivatableUIOpenEvent args) @@ -139,8 +140,7 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi return; } - if (msg.Session.AttachedEntity is not { Valid: true } buyer) - return; + var buyer = msg.Actor; //verify that we can actually buy this listing and it wasn't added if (!ListingHasCategory(listing, component.Categories)) @@ -215,11 +215,11 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi { HandleRefundComp(uid, component, actionId.Value); - if (listing.ProductUpgradeID != null) + if (listing.ProductUpgradeId != null) { foreach (var upgradeListing in component.Listings) { - if (upgradeListing.ID == listing.ProductUpgradeID) + if (upgradeListing.ID == listing.ProductUpgradeId) { upgradeListing.ProductActionEntity = actionId.Value; break; @@ -229,7 +229,7 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi } } - if (listing is { ProductUpgradeID: not null, ProductActionEntity: not null }) + if (listing is { ProductUpgradeId: not null, ProductActionEntity: not null }) { if (listing.ProductActionEntity != null) { @@ -263,7 +263,7 @@ private void OnBuyRequest(EntityUid uid, StoreComponent component, StoreBuyListi $"{ToPrettyString(buyer):player} purchased listing \"{ListingLocalisationHelpers.GetLocalisedNameOrEntityName(listing, _prototypeManager)}\" from {ToPrettyString(uid)}"); listing.PurchaseAmount++; //track how many times something has been purchased - _audio.PlayEntity(component.BuySuccessSound, msg.Session, uid); //cha-ching! + _audio.PlayEntity(component.BuySuccessSound, msg.Actor, uid); //cha-ching! if (listing.SaleLimit != 0 && listing.DiscountValue > 0 && listing.PurchaseAmount >= listing.SaleLimit) { @@ -295,8 +295,7 @@ private void OnRequestWithdraw(EntityUid uid, StoreComponent component, StoreReq if (proto.Cash == null || !proto.CanWithdraw) return; - if (msg.Session.AttachedEntity is not { Valid: true } buyer) - return; + var buyer = msg.Actor; FixedPoint2 amountRemaining = msg.Amount; var coordinates = Transform(buyer).Coordinates; @@ -319,7 +318,7 @@ private void OnRequestRefund(EntityUid uid, StoreComponent component, StoreReque { // TODO: Remove guardian/holopara - if (args.Session.AttachedEntity is not { Valid: true } buyer) + if (args.Actor is not { Valid: true } buyer) return; if (!IsOnStartingMap(uid, component)) diff --git a/Content.Server/Store/Systems/StoreSystem.cs b/Content.Server/Store/Systems/StoreSystem.cs index a86dffef633..978d98ac0cf 100644 --- a/Content.Server/Store/Systems/StoreSystem.cs +++ b/Content.Server/Store/Systems/StoreSystem.cs @@ -102,7 +102,7 @@ private void OnAfterInteract(EntityUid uid, CurrencyComponent component, AfterIn if (args.Handled) { var msg = Loc.GetString("store-currency-inserted", ("used", args.Used), ("target", args.Target)); - _popup.PopupEntity(msg, args.Target.Value); + _popup.PopupEntity(msg, args.Target.Value, args.User); QueueDel(args.Used); } } @@ -203,11 +203,8 @@ public void InitializeFromPreset(StorePresetPrototype preset, EntityUid uid, Sto _storeDiscount.ApplyDiscounts(component.Listings, preset); - var ui = _ui.GetUiOrNull(uid, StoreUiKey.Key); - if (ui != null) - { - _ui.SetUiState(ui, new StoreInitializeState(preset.StoreName)); - } + if (_ui.HasUi(uid, StoreUiKey.Key)) + _ui.SetUiState(uid, StoreUiKey.Key, new StoreInitializeState(preset.StoreName)); } } diff --git a/Content.Server/Strip/StrippableSystem.cs b/Content.Server/Strip/StrippableSystem.cs index d9f084252ae..73f2ce17a66 100644 --- a/Content.Server/Strip/StrippableSystem.cs +++ b/Content.Server/Strip/StrippableSystem.cs @@ -112,17 +112,15 @@ public override void StartOpeningStripper(EntityUid user, Entity(user, out var mode) && mode.IsInCombatMode && !openInCombat) return; - if (TryComp(user, out var actor) && HasComp(user)) + if (HasComp(user)) { - if (_userInterfaceSystem.SessionHasOpenUi(strippable, StrippingUiKey.Key, actor.PlayerSession)) - return; - _userInterfaceSystem.TryOpen(strippable, StrippingUiKey.Key, actor.PlayerSession); + _userInterfaceSystem.OpenUi(strippable.Owner, StrippingUiKey.Key, user); } } private void OnStripButtonPressed(Entity strippable, ref StrippingSlotButtonPressed args) { - if (args.Session.AttachedEntity is not { Valid: true } user || + if (args.Actor is not { Valid: true } user || !TryComp(user, out var userHands)) return; @@ -174,7 +172,7 @@ private void StripHand( private void OnStripEnsnareMessage(EntityUid uid, EnsnareableComponent component, StrippingEnsnareButtonPressed args) { - if (args.Session.AttachedEntity is not { Valid: true } user) + if (args.Actor is not { Valid: true } user) return; foreach (var entity in component.Container.ContainedEntities) diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs index f258fbe89cf..ca0f59cd14d 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraMonitorSystem.cs @@ -90,7 +90,7 @@ private void OnComponentStartup(EntityUid uid, SurveillanceCameraMonitorComponen private void OnSubnetRequest(EntityUid uid, SurveillanceCameraMonitorComponent component, SurveillanceCameraMonitorSubnetRequestMessage args) { - if (args.Session.AttachedEntity != null) + if (args.Actor != null) { SetActiveSubnet(uid, args.Subnet, component); } @@ -208,13 +208,9 @@ private void OnSurveillanceCameraDeactivate(EntityUid uid, SurveillanceCameraMon private void OnBoundUiClose(EntityUid uid, SurveillanceCameraMonitorComponent component, BoundUIClosedEvent args) { - if (args.Session.AttachedEntity == null) - { - return; - } - - RemoveViewer(uid, args.Session.AttachedEntity.Value, component); + RemoveViewer(uid, args.Actor, component); } + #endregion private void SendHeartbeat(EntityUid uid, SurveillanceCameraMonitorComponent? monitor = null) @@ -487,6 +483,6 @@ private void UpdateUserInterface(EntityUid uid, SurveillanceCameraMonitorCompone } var state = new SurveillanceCameraMonitorUiState(GetNetEntity(monitor.ActiveCamera), monitor.KnownSubnets.Keys.ToHashSet(), monitor.ActiveCameraAddress, monitor.ActiveSubnet, monitor.KnownCameras); - _userInterface.TrySetUiState(uid, SurveillanceCameraMonitorUiKey.Key, state); + _userInterface.SetUiState(uid, SurveillanceCameraMonitorUiKey.Key, state); } } diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs index ac417230267..d0c2cd78d32 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraRouterSystem.cs @@ -134,14 +134,14 @@ private void OnSetNetwork(EntityUid uid, SurveillanceCameraRouterComponent compo UpdateSetupInterface(uid, component); } - private void OpenSetupInterface(EntityUid uid, EntityUid player, SurveillanceCameraRouterComponent? camera = null, ActorComponent? actor = null) + private void OpenSetupInterface(EntityUid uid, EntityUid player, SurveillanceCameraRouterComponent? camera = null) { - if (!Resolve(uid, ref camera) || !Resolve(player, ref actor)) + if (!Resolve(uid, ref camera)) return; - if (!_userInterface.TryGetUi(uid, SurveillanceCameraSetupUiKey.Router, out var bui)) + + if (!_userInterface.TryOpenUi(uid, SurveillanceCameraSetupUiKey.Router, player)) return; - _userInterface.OpenUi(bui, actor.PlayerSession); UpdateSetupInterface(uid, camera); } @@ -154,13 +154,13 @@ private void UpdateSetupInterface(EntityUid uid, SurveillanceCameraRouterCompone if (router.AvailableNetworks.Count == 0 || router.SubnetFrequencyId != null) { - _userInterface.TryCloseAll(uid, SurveillanceCameraSetupUiKey.Router); + _userInterface.CloseUi(uid, SurveillanceCameraSetupUiKey.Router); return; } var state = new SurveillanceCameraSetupBoundUiState(router.SubnetName, deviceNet.ReceiveFrequency ?? 0, router.AvailableNetworks, true, router.SubnetFrequencyId != null); - _userInterface.TrySetUiState(uid, SurveillanceCameraSetupUiKey.Router, state); + _userInterface.SetUiState(uid, SurveillanceCameraSetupUiKey.Router, state); } private void SendHeartbeat(EntityUid uid, string origin, string destination, diff --git a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs index ec3d33157ab..accaa75d1c3 100644 --- a/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs +++ b/Content.Server/SurveillanceCamera/Systems/SurveillanceCameraSystem.cs @@ -192,14 +192,14 @@ private void OnSetNetwork(EntityUid uid, SurveillanceCameraComponent component, UpdateSetupInterface(uid, component); } - private void OpenSetupInterface(EntityUid uid, EntityUid player, SurveillanceCameraComponent? camera = null, ActorComponent? actor = null) + private void OpenSetupInterface(EntityUid uid, EntityUid player, SurveillanceCameraComponent? camera = null) { - if (!Resolve(uid, ref camera) || !Resolve(player, ref actor)) + if (!Resolve(uid, ref camera)) return; - if (!_userInterface.TryGetUi(uid, SurveillanceCameraSetupUiKey.Camera, out var bui)) + + if (!_userInterface.TryOpenUi(uid, SurveillanceCameraSetupUiKey.Camera, player)) return; - _userInterface.OpenUi(bui, actor.PlayerSession); UpdateSetupInterface(uid, camera); } @@ -212,7 +212,7 @@ private void UpdateSetupInterface(EntityUid uid, SurveillanceCameraComponent? ca if (camera.NameSet && camera.NetworkSet) { - _userInterface.TryCloseAll(uid, SurveillanceCameraSetupUiKey.Camera); + _userInterface.CloseUi(uid, SurveillanceCameraSetupUiKey.Camera); return; } @@ -224,14 +224,14 @@ private void UpdateSetupInterface(EntityUid uid, SurveillanceCameraComponent? ca } else if (!camera.NetworkSet) { - _userInterface.TryCloseAll(uid, SurveillanceCameraSetupUiKey.Camera); + _userInterface.CloseUi(uid, SurveillanceCameraSetupUiKey.Camera); return; } } var state = new SurveillanceCameraSetupBoundUiState(camera.CameraId, deviceNet.ReceiveFrequency ?? 0, camera.AvailableNetworks, camera.NameSet, camera.NetworkSet); - _userInterface.TrySetUiState(uid, SurveillanceCameraSetupUiKey.Camera, state); + _userInterface.SetUiState(uid, SurveillanceCameraSetupUiKey.Camera, state); } // If the camera deactivates for any reason, it must have all viewers removed, diff --git a/Content.Server/Terminator/Components/TerminatorComponent.cs b/Content.Server/Terminator/Components/TerminatorComponent.cs deleted file mode 100644 index 9427f95eeda..00000000000 --- a/Content.Server/Terminator/Components/TerminatorComponent.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Content.Server.Terminator.Systems; -using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; - -namespace Content.Server.Terminator.Components; - -/// -/// Main terminator component, handles the target, if any, and objectives. -/// -[RegisterComponent, Access(typeof(TerminatorSystem))] -public sealed partial class TerminatorComponent : Component -{ - /// - /// Used to force the terminate objective's target. - /// If null it will be a random person. - /// - [DataField("target")] - public EntityUid? Target; -} diff --git a/Content.Server/Terminator/Components/TerminatorTargetComponent.cs b/Content.Server/Terminator/Components/TerminatorTargetComponent.cs deleted file mode 100644 index 786cbd1167b..00000000000 --- a/Content.Server/Terminator/Components/TerminatorTargetComponent.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Content.Server.Terminator.Systems; - -namespace Content.Server.Terminator.Components; - -/// -/// Sets after the ghost role spawns. -/// -[RegisterComponent, Access(typeof(TerminatorSystem))] -public sealed partial class TerminatorTargetComponent : Component -{ - /// - /// The target to set after the ghost role spawns. - /// - [DataField("target")] - public EntityUid? Target; -} diff --git a/Content.Server/Terminator/Systems/TerminatorSystem.cs b/Content.Server/Terminator/Systems/TerminatorSystem.cs deleted file mode 100644 index 837778d3c41..00000000000 --- a/Content.Server/Terminator/Systems/TerminatorSystem.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Content.Server.Body.Components; -using Content.Server.GenericAntag; -using Content.Server.Ghost.Roles.Events; -using Content.Server.Roles; -using Content.Server.Terminator.Components; -using Content.Shared.Roles; -using Robust.Shared.Map; - -namespace Content.Server.Terminator.Systems; - -public sealed class TerminatorSystem : EntitySystem -{ - [Dependency] private readonly SharedRoleSystem _role = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnSpawned); - SubscribeLocalEvent(OnCreated); - } - - private void OnMapInit(EntityUid uid, TerminatorComponent comp, MapInitEvent args) - { - // cyborg doesn't need to breathe - //RemComp(uid); // DeltaV - paradox anomaly does actually need to breathe - } - - private void OnSpawned(EntityUid uid, TerminatorComponent comp, GhostRoleSpawnerUsedEvent args) - { - if (!TryComp(args.Spawner, out var target)) - return; - - comp.Target = target.Target; - } - - private void OnCreated(EntityUid uid, TerminatorComponent comp, ref GenericAntagCreatedEvent args) - { - var mindId = args.MindId; - var mind = args.Mind; - - _role.MindAddRole(mindId, new RoleBriefingComponent - { - Briefing = Loc.GetString("terminator-role-briefing") - }, mind); - _role.MindAddRole(mindId, new TerminatorRoleComponent(), mind); - } - - /// - /// DeltaV - used for paradox anomaly. - /// - public void SetTarget(Entity ent, EntityUid mindId) - { - ent.Comp ??= EnsureComp(ent); - ent.Comp.Target = mindId; - } - - /// - /// Create a spawner at a position and return it. - /// - /// Coordinates to create the spawner at - /// Optional target mind to force the terminator to target - public EntityUid CreateSpawner(EntityCoordinates coords, EntityUid? target) - { - var uid = Spawn("SpawnPointGhostTerminator", coords); - if (target != null) - { - var comp = EnsureComp(uid); - comp.Target = target; - } - - return uid; - } -} diff --git a/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs b/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs index 99185653288..133876bd751 100644 --- a/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs +++ b/Content.Server/Thief/Systems/ThiefUndeterminedBackpackSystem.cs @@ -79,6 +79,6 @@ private void UpdateUI(EntityUid uid, ThiefUndeterminedBackpackComponent? compone data.Add(i, info); } - _ui.TrySetUiState(uid, ThiefBackpackUIKey.Key, new ThiefBackpackBoundUserInterfaceState(data, MaxSelectedSets)); + _ui.SetUiState(uid, ThiefBackpackUIKey.Key, new ThiefBackpackBoundUserInterfaceState(data, MaxSelectedSets)); } } diff --git a/Content.Server/Tips/TipsSystem.cs b/Content.Server/Tips/TipsSystem.cs index cc45a3a1d5e..168f11de8f8 100644 --- a/Content.Server/Tips/TipsSystem.cs +++ b/Content.Server/Tips/TipsSystem.cs @@ -1,9 +1,13 @@ -using Content.Server.Chat.Managers; +using Content.Server.Chat.Managers; using Content.Server.GameTicking; using Content.Shared.CCVar; using Content.Shared.Chat; using Content.Shared.Dataset; +using Content.Shared.Tips; +using Robust.Server.GameObjects; +using Robust.Server.Player; using Robust.Shared.Configuration; +using Robust.Shared.Console; using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; @@ -22,11 +26,14 @@ public sealed class TipsSystem : EntitySystem [Dependency] private readonly IGameTiming _timing = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly GameTicker _ticker = default!; + [Dependency] private readonly IConsoleHost _conHost = default!; + [Dependency] private readonly IPlayerManager _playerManager = default!; private bool _tipsEnabled; private float _tipTimeOutOfRound; private float _tipTimeInRound; private string _tipsDataset = ""; + private float _tipTippyChance; [ViewVariables(VVAccess.ReadWrite)] private TimeSpan _nextTipTime = TimeSpan.Zero; @@ -40,10 +47,100 @@ public override void Initialize() Subs.CVar(_cfg, CCVars.TipFrequencyInRound, SetInRound, true); Subs.CVar(_cfg, CCVars.TipsEnabled, SetEnabled, true); Subs.CVar(_cfg, CCVars.TipsDataset, SetDataset, true); + Subs.CVar(_cfg, CCVars.TipsTippyChance, SetTippyChance, true); RecalculateNextTipTime(); + _conHost.RegisterCommand("tippy", Loc.GetString("cmd-tippy-desc"), Loc.GetString("cmd-tippy-help"), SendTippy, SendTippyHelper); + _conHost.RegisterCommand("tip", Loc.GetString("cmd-tip-desc"), "tip", SendTip); } + private CompletionResult SendTippyHelper(IConsoleShell shell, string[] args) + { + return args.Length switch + { + 1 => CompletionResult.FromHintOptions(CompletionHelper.SessionNames(), Loc.GetString("cmd-tippy-auto-1")), + 2 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-2")), + 3 => CompletionResult.FromHintOptions(CompletionHelper.PrototypeIDs(), Loc.GetString("cmd-tippy-auto-3")), + 4 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-4")), + 5 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-5")), + 6 => CompletionResult.FromHint(Loc.GetString("cmd-tippy-auto-6")), + _ => CompletionResult.Empty + }; + } + + private void SendTip(IConsoleShell shell, string argstr, string[] args) + { + AnnounceRandomTip(); + RecalculateNextTipTime(); + } + + private void SendTippy(IConsoleShell shell, string argstr, string[] args) + { + if (args.Length < 2) + { + shell.WriteLine(Loc.GetString("cmd-tippy-help")); + return; + } + + ActorComponent? actor = null; + if (args[0] != "all") + { + ICommonSession? session; + if (args.Length > 0) + { + // Get player entity + if (!_playerManager.TryGetSessionByUsername(args[0], out session)) + { + shell.WriteLine(Loc.GetString("cmd-tippy-error-no-user")); + return; + } + } + else + { + session = shell.Player; + } + + if (session?.AttachedEntity is not { } user) + { + shell.WriteLine(Loc.GetString("cmd-tippy-error-no-user")); + return; + } + + if (!TryComp(user, out actor)) + { + shell.WriteError(Loc.GetString("cmd-tippy-error-no-user")); + return; + } + } + + var ev = new TippyEvent(args[1]); + + if (args.Length > 2) + { + ev.Proto = args[2]; + if (!_prototype.HasIndex(args[2])) + { + shell.WriteError(Loc.GetString("cmd-tippy-error-no-prototype", ("proto", args[2]))); + return; + } + } + + if (args.Length > 3) + ev.SpeakTime = float.Parse(args[3]); + + if (args.Length > 4) + ev.SlideTime = float.Parse(args[4]); + + if (args.Length > 5) + ev.WaddleInterval = float.Parse(args[5]); + + if (actor != null) + RaiseNetworkEvent(ev, actor.PlayerSession); + else + RaiseNetworkEvent(ev); + } + + public override void Update(float frameTime) { base.Update(frameTime); @@ -81,6 +178,11 @@ private void SetDataset(string value) _tipsDataset = value; } + private void SetTippyChance(float value) + { + _tipTippyChance = value; + } + private void AnnounceRandomTip() { if (!_prototype.TryIndex(_tipsDataset, out var tips)) @@ -89,8 +191,16 @@ private void AnnounceRandomTip() var tip = _random.Pick(tips.Values); var msg = Loc.GetString("tips-system-chat-message-wrap", ("tip", tip)); - _chat.ChatMessageToManyFiltered(Filter.Broadcast(), ChatChannel.OOC, tip, msg, + if (_random.Prob(_tipTippyChance)) + { + var ev = new TippyEvent(msg); + ev.SpeakTime = 1 + tip.Length * 0.05f; + RaiseNetworkEvent(ev); + } else + { + _chat.ChatMessageToManyFiltered(Filter.Broadcast(), ChatChannel.OOC, tip, msg, EntityUid.Invalid, false, false, Color.MediumPurple); + } } private void RecalculateNextTipTime() diff --git a/Content.Server/Tools/Components/WelderComponent.cs b/Content.Server/Tools/Components/WelderComponent.cs deleted file mode 100644 index b0db2c58e88..00000000000 --- a/Content.Server/Tools/Components/WelderComponent.cs +++ /dev/null @@ -1,56 +0,0 @@ -using Content.Shared.Chemistry.Components; -using Content.Shared.Chemistry.Reagent; -using Content.Shared.FixedPoint; -using Content.Shared.Tools.Components; -using Robust.Shared.Audio; -using Robust.Shared.Prototypes; - -namespace Content.Server.Tools.Components -{ - [RegisterComponent] - public sealed partial class WelderComponent : SharedWelderComponent - { - /// - /// Name of . - /// - [DataField("fuelSolution"), ViewVariables(VVAccess.ReadWrite)] - public string FuelSolutionName = "Welder"; - - /// - /// Solution on the entity that contains the fuel. - /// - [DataField("fuelSolutionRef")] - public Entity? FuelSolution = null; - - /// - /// Reagent that will be used as fuel for welding. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public ProtoId FuelReagent = "WeldingFuel"; - - /// - /// Fuel consumption per second while the welder is active. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 FuelConsumption = FixedPoint2.New(2.0f); - - /// - /// A fuel amount to be consumed when the welder goes from being unlit to being lit. - /// - [DataField, ViewVariables(VVAccess.ReadWrite)] - public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f); - - /// - /// Sound played when refilling the welder. - /// - [DataField] - public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); - - /// - /// Whether the item is safe to refill while lit without exploding the tank. - /// - [DataField] - public bool TankSafe = false; //I have no idea what I'm doing - - } -} diff --git a/Content.Server/Tools/ToolSystem.Welder.cs b/Content.Server/Tools/ToolSystem.Welder.cs deleted file mode 100644 index 727526b3989..00000000000 --- a/Content.Server/Tools/ToolSystem.Welder.cs +++ /dev/null @@ -1,211 +0,0 @@ -using Content.Server.Chemistry.Components; -using Content.Server.IgnitionSource; -using Content.Server.Tools.Components; -using Content.Shared.Chemistry.Components.SolutionManager; -using Content.Shared.Database; -using Content.Shared.DoAfter; -using Content.Shared.Examine; -using Content.Shared.FixedPoint; -using Content.Shared.Interaction; -using Content.Shared.Item.ItemToggle; -using Content.Shared.Tools.Components; -using Robust.Shared.GameStates; -using System.Linq; -using Content.Shared.Item.ItemToggle.Components; - -namespace Content.Server.Tools -{ - public sealed partial class ToolSystem - { - [Dependency] private readonly SharedItemToggleSystem _itemToggle = default!; - [Dependency] private readonly IgnitionSourceSystem _ignitionSource = default!; - private readonly HashSet _activeWelders = new(); - - private const float WelderUpdateTimer = 1f; - private float _welderTimer; - - public void InitializeWelders() - { - SubscribeLocalEvent(OnWelderExamine); - SubscribeLocalEvent(OnWelderAfterInteract); - SubscribeLocalEvent>(OnWelderToolUseAttempt); - SubscribeLocalEvent(OnWelderShutdown); - SubscribeLocalEvent(OnWelderGetState); - SubscribeLocalEvent(OnToggle); - SubscribeLocalEvent(OnActivateAttempt); - } - - public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null) - { - if (!Resolve(uid, ref welder, ref solutionContainer) - || !_solutionContainer.ResolveSolution((uid, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var fuelSolution)) - return (FixedPoint2.Zero, FixedPoint2.Zero); - - return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume); - } - - private void OnToggle(Entity entity, ref ItemToggledEvent args) - { - if (args.Activated) - TurnOn(entity, args.User); - else - TurnOff(entity, args.User); - } - - private void OnActivateAttempt(Entity entity, ref ItemToggleActivateAttemptEvent args) - { - if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var solution)) - { - args.Cancelled = true; - args.Popup = Loc.GetString("welder-component-no-fuel-message"); - return; - } - - var fuel = solution.GetTotalPrototypeQuantity(entity.Comp.FuelReagent); - if (fuel == FixedPoint2.Zero || fuel < entity.Comp.FuelLitCost) - { - args.Popup = Loc.GetString("welder-component-no-fuel-message"); - args.Cancelled = true; - } - } - - public void TurnOn(Entity entity, EntityUid? user) - { - if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution)) - return; - - _solutionContainer.RemoveReagent(entity.Comp.FuelSolution.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost); - AdminLogger.Add(LogType.InteractActivate, LogImpact.Low, - $"{ToPrettyString(user):user} toggled {ToPrettyString(entity.Owner):welder} on"); - - var xform = Transform(entity); - if (xform.GridUid is { } gridUid) - { - var position = _transformSystem.GetGridOrMapTilePosition(entity.Owner, xform); - _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, entity.Owner, true); - } - - _activeWelders.Add(entity); - } - - public void TurnOff(Entity entity, EntityUid? user) - { - AdminLogger.Add(LogType.InteractActivate, LogImpact.Low, - $"{ToPrettyString(user):user} toggled {ToPrettyString(entity.Owner):welder} off"); - _activeWelders.Remove(entity); - } - - private void OnWelderExamine(Entity entity, ref ExaminedEvent args) - { - using (args.PushGroup(nameof(WelderComponent))) - { - if (_itemToggle.IsActivated(entity.Owner)) - { - args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message")); - } - else - { - args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-not-lit-message")); - } - - if (args.IsInDetailsRange) - { - var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp); - - args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message", - ("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"), - ("fuelLeft", fuel), - ("fuelCapacity", capacity), - ("status", string.Empty))); // Lit status is handled above - } - } - } - - private void OnWelderAfterInteract(Entity entity, ref AfterInteractEvent args) - { - if (args.Handled) - return; - - if (args.Target is not { Valid: true } target || !args.CanReach) - return; - - if (TryComp(target, out ReagentTankComponent? tank) - && tank.TankType == ReagentTankType.Fuel - && _solutionContainer.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) - && _solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var welderSolution)) - { - var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume); - if (trans > 0) - { - var drained = _solutionContainer.Drain(target, targetSoln.Value, trans); - _solutionContainer.TryAddSolution(entity.Comp.FuelSolution.Value, drained); - _audio.PlayPvs(entity.Comp.WelderRefill, entity); - _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), entity, args.User); - } - else if (welderSolution.AvailableVolume <= 0) - { - _popup.PopupEntity(Loc.GetString("welder-component-already-full"), entity, args.User); - } - else - { - _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), entity, args.User); - } - - args.Handled = true; - } - } - - private void OnWelderToolUseAttempt(Entity entity, ref DoAfterAttemptEvent args) - { - var user = args.DoAfter.Args.User; - - if (!_itemToggle.IsActivated(entity.Owner)) - { - _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), entity, user); - args.Cancel(); - } - } - - private void OnWelderShutdown(Entity entity, ref ComponentShutdown args) - { - _activeWelders.Remove(entity); - } - - private void OnWelderGetState(Entity entity, ref ComponentGetState args) - { - var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp); - args.State = new WelderComponentState(capacity.Float(), fuel.Float()); - } - - private void UpdateWelders(float frameTime) - { - _welderTimer += frameTime; - - if (_welderTimer < WelderUpdateTimer) - return; - - // TODO Serialization. _activeWelders is not serialized. - // Need to use some "active" component, and EntityQuery over that. - // Probably best to generalize it to a "ToggleableFuelDrain" component. - foreach (var tool in _activeWelders.ToArray()) - { - if (!TryComp(tool, out WelderComponent? welder) - || !TryComp(tool, out SolutionContainerManagerComponent? solutionContainer)) - continue; - - if (!_solutionContainer.ResolveSolution((tool, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var solution)) - continue; - - _solutionContainer.RemoveReagent(welder.FuelSolution.Value, welder.FuelReagent, welder.FuelConsumption * _welderTimer); - - if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) - { - _itemToggle.Toggle(tool, predicted: false); - } - - Dirty(tool, welder); - } - _welderTimer -= WelderUpdateTimer; - } - } -} diff --git a/Content.Server/Tools/ToolSystem.cs b/Content.Server/Tools/ToolSystem.cs index 7bae1778923..7738a6398fa 100644 --- a/Content.Server/Tools/ToolSystem.cs +++ b/Content.Server/Tools/ToolSystem.cs @@ -1,40 +1,63 @@ using Content.Server.Atmos.EntitySystems; -using Content.Server.Chemistry.Containers.EntitySystems; -using Content.Server.Popups; -using Content.Server.Tools.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.FixedPoint; +using Content.Shared.Tools.Components; using Robust.Server.GameObjects; -using Robust.Shared.Audio.Systems; using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem; -namespace Content.Server.Tools +namespace Content.Server.Tools; + +public sealed class ToolSystem : SharedToolSystem { - // TODO move tool system to shared, and make it a friend of Tool Component. - public sealed partial class ToolSystem : SharedToolSystem - { - [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; - [Dependency] private readonly PopupSystem _popup = default!; - [Dependency] private readonly SharedAudioSystem _audio = default!; - [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!; - [Dependency] private readonly TransformSystem _transformSystem = default!; + [Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!; + [Dependency] private readonly TransformSystem _transformSystem = default!; - public override void Initialize() + public override void TurnOn(Entity entity, EntityUid? user) + { + base.TurnOn(entity, user); + var xform = Transform(entity); + if (xform.GridUid is { } gridUid) { - base.Initialize(); - - InitializeWelders(); + var position = _transformSystem.GetGridOrMapTilePosition(entity.Owner, xform); + _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, entity.Owner, true); } + } - public override void Update(float frameTime) - { - base.Update(frameTime); + public override void Update(float frameTime) + { + base.Update(frameTime); - UpdateWelders(frameTime); - } + UpdateWelders(frameTime); + } - protected override bool IsWelder(EntityUid uid) + //todo move to shared once you can remove reagents from shared without it freaking out. + private void UpdateWelders(float frameTime) + { + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var welder, out var solutionContainer)) { - return HasComp(uid); + if (!welder.Enabled) + continue; + + welder.WelderTimer += frameTime; + + if (welder.WelderTimer < welder.WelderUpdateTimer) + continue; + + if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution)) + continue; + + SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderTimer); + + if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero) + { + ItemToggle.Toggle(uid, predicted: false); + } + + Dirty(uid, welder); + welder.WelderTimer -= welder.WelderUpdateTimer; } } } + diff --git a/Content.Server/Traits/Assorted/SingerSystem.cs b/Content.Server/Traits/Assorted/SingerSystem.cs index 7b560957b6e..78a4101a65f 100644 --- a/Content.Server/Traits/Assorted/SingerSystem.cs +++ b/Content.Server/Traits/Assorted/SingerSystem.cs @@ -65,9 +65,7 @@ private void OnEquip(GotEquippedEvent args) if (TryComp(args.Equipment, out var accent) && accent.ReplacementPrototype == "mumble" && args.Slot == "mask") - { CloseMidiUi(args.Equipee); - } } private void OnMobStateChangedEvent(EntityUid uid, SharedInstrumentComponent component, MobStateChangedEvent args) @@ -154,8 +152,6 @@ public override void CloseMidiUi(EntityUid uid) { if (HasComp(uid) && TryComp(uid, out var actor)) - { - _instrument.ToggleInstrumentUi(uid, actor.PlayerSession); - } + _instrument.ToggleInstrumentUi(uid, actor.PlayerSession.AttachedEntity ?? EntityUid.Invalid); } } diff --git a/Content.Server/UserInterface/ActivatableUIComponent.cs b/Content.Server/UserInterface/ActivatableUIComponent.cs deleted file mode 100644 index cc0e5008e47..00000000000 --- a/Content.Server/UserInterface/ActivatableUIComponent.cs +++ /dev/null @@ -1,75 +0,0 @@ -using Content.Shared.Whitelist; -using Robust.Server.GameObjects; -using Robust.Server.Player; -using Robust.Shared.Player; -using Robust.Shared.Serialization.TypeSerializers.Implementations; - -namespace Content.Server.UserInterface -{ - [RegisterComponent] - public sealed partial class ActivatableUIComponent : Component - { - [DataField(required: true, customTypeSerializer:typeof(EnumSerializer))] - public Enum? Key { get; set; } - - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool InHandsOnly { get; set; } = false; - - [DataField] - public bool SingleUser { get; set; } = false; - - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool AdminOnly { get; set; } = false; - - [DataField] - public LocId VerbText = "ui-verb-toggle-open"; - - /// - /// Whether you need a hand to operate this UI. The hand does not need to be free, you just need to have one. - /// - /// - /// This should probably be true for most machines & computers, but there will still be UIs that represent a - /// more generic interaction / configuration that might not require hands. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool RequireHands = true; - - /// - /// Entities that are required to open this UI. - /// - [DataField("allowedItems")] - [ViewVariables(VVAccess.ReadWrite)] - public EntityWhitelist? AllowedItems = null; - - /// - /// Whether you can activate this ui with activateinhand or not - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool RightClickOnly; - - /// - /// Whether spectators (non-admin ghosts) should be allowed to view this UI. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool AllowSpectator = true; - - /// - /// Whether the UI should close when the item is deselected due to a hand swap or drop - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField] - public bool CloseOnHandDeselect = true; - - /// - /// The client channel currently using the object, or null if there's none/not single user. - /// NOTE: DO NOT DIRECTLY SET, USE ActivatableUISystem.SetCurrentSingleUser - /// - [ViewVariables] - public ICommonSession? CurrentSingleUser; - } -} diff --git a/Content.Server/UserInterface/ActivatableUIRequiresPowerCellComponent.cs b/Content.Server/UserInterface/ActivatableUIRequiresPowerCellComponent.cs deleted file mode 100644 index fdc56f89a05..00000000000 --- a/Content.Server/UserInterface/ActivatableUIRequiresPowerCellComponent.cs +++ /dev/null @@ -1,14 +0,0 @@ -using Content.Server.PowerCell; -using Content.Shared.PowerCell; -using Content.Shared.UserInterface; - -namespace Content.Server.UserInterface; - -/// -/// Specifies that the attached entity requires power. -/// -[RegisterComponent] -public sealed partial class ActivatableUIRequiresPowerCellComponent : Component -{ - -} diff --git a/Content.Server/UserInterface/ActivatableUISystem.Power.cs b/Content.Server/UserInterface/ActivatableUISystem.Power.cs deleted file mode 100644 index d4dcc91d46e..00000000000 --- a/Content.Server/UserInterface/ActivatableUISystem.Power.cs +++ /dev/null @@ -1,81 +0,0 @@ -using Content.Server.PowerCell; -using Content.Shared.PowerCell; -using Content.Shared.UserInterface; -using Robust.Shared.Containers; - -namespace Content.Server.UserInterface; - -public sealed partial class ActivatableUISystem -{ - [Dependency] private readonly PowerCellSystem _cell = default!; - - private void InitializePower() - { - SubscribeLocalEvent(OnBatteryOpenAttempt); - SubscribeLocalEvent(OnBatteryOpened); - SubscribeLocalEvent(OnBatteryClosed); - - SubscribeLocalEvent(OnPowerCellRemoved); - } - - private void OnPowerCellRemoved(EntityUid uid, PowerCellDrawComponent component, EntRemovedFromContainerMessage args) - { - _cell.SetPowerCellDrawEnabled(uid, false); - - if (HasComp(uid) && - TryComp(uid, out var activatable) && - activatable.Key != null) - { - _uiSystem.TryCloseAll(uid, activatable.Key); - } - } - - private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args) - { - var activatable = Comp(uid); - - if (!args.UiKey.Equals(activatable.Key)) - return; - - _cell.SetPowerCellDrawEnabled(uid, true); - } - - private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args) - { - var activatable = Comp(uid); - - if (!args.UiKey.Equals(activatable.Key)) - return; - - // Stop drawing power if this was the last person with the UI open. - if (!_uiSystem.IsUiOpen(uid, activatable.Key)) - _cell.SetPowerCellDrawEnabled(uid, false); - } - - /// - /// Call if you want to check if the UI should close due to a recent battery usage. - /// - public void CheckUsage(EntityUid uid, ActivatableUIComponent? active = null, ActivatableUIRequiresPowerCellComponent? component = null, PowerCellDrawComponent? draw = null) - { - if (!Resolve(uid, ref component, ref draw, ref active, false) || active.Key == null) - return; - - if (_cell.HasCharge(uid, draw.UseRate)) - return; - - _uiSystem.TryCloseAll(uid, active.Key); - } - - private void OnBatteryOpenAttempt(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, ActivatableUIOpenAttemptEvent args) - { - if (!TryComp(uid, out var draw)) - return; - - // Check if we have the appropriate drawrate / userate to even open it. - if (args.Cancelled || !_cell.HasCharge(uid, MathF.Max(draw.DrawRate, draw.UseRate), user: args.User)) - { - args.Cancel(); - return; - } - } -} diff --git a/Content.Server/UserInterface/ActivatableUISystem.cs b/Content.Server/UserInterface/ActivatableUISystem.cs deleted file mode 100644 index 5f2314df90b..00000000000 --- a/Content.Server/UserInterface/ActivatableUISystem.cs +++ /dev/null @@ -1,235 +0,0 @@ -using Content.Server.Administration.Managers; -using Content.Shared.ActionBlocker; -using Content.Shared.Ghost; -using Content.Shared.Hands; -using Content.Shared.Hands.Components; -using Content.Shared.Interaction; -using Content.Shared.Interaction.Events; -using Content.Shared.Popups; -using Content.Shared.UserInterface; -using Content.Shared.Verbs; -using Robust.Server.GameObjects; -using Robust.Shared.Player; - -namespace Content.Server.UserInterface; - -public sealed partial class ActivatableUISystem : EntitySystem -{ - [Dependency] private readonly IAdminManager _adminManager = default!; - [Dependency] private readonly ActionBlockerSystem _blockerSystem = default!; - [Dependency] private readonly UserInterfaceSystem _uiSystem = default!; - [Dependency] private readonly SharedPopupSystem _popupSystem = default!; - - public override void Initialize() - { - base.Initialize(); - - SubscribeLocalEvent(OnActivate); - SubscribeLocalEvent(OnUseInHand); - SubscribeLocalEvent(OnInteractUsing); - SubscribeLocalEvent(OnHandDeselected); - SubscribeLocalEvent((uid, aui, _) => CloseAll(uid, aui)); - // *THIS IS A BLATANT WORKAROUND!* RATIONALE: Microwaves need it - SubscribeLocalEvent(OnParentChanged); - SubscribeLocalEvent(OnUIClose); - SubscribeLocalEvent(OnBoundInterfaceInteractAttempt); - - SubscribeLocalEvent>(AddOpenUiVerb); - - SubscribeLocalEvent(OnActionPerform); - - InitializePower(); - } - - private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev) - { - if (!TryComp(ev.Target, out ActivatableUIComponent? comp)) - return; - - if (!comp.RequireHands) - return; - - if (!TryComp(ev.Sender.AttachedEntity, out HandsComponent? hands) || hands.Hands.Count == 0) - ev.Cancel(); - } - - private void OnActionPerform(EntityUid uid, UserInterfaceComponent component, OpenUiActionEvent args) - { - if (args.Handled || args.Key == null) - return; - - if (!TryComp(args.Performer, out ActorComponent? actor)) - return; - - args.Handled = _uiSystem.TryToggleUi(uid, args.Key, actor.PlayerSession); - } - - private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent args) - { - if (!args.CanAccess) - return; - - if (component.RequireHands && args.Hands == null) - return; - - if (component.InHandsOnly && args.Using != uid) - return; - - if (!args.CanInteract && (!component.AllowSpectator || !HasComp(args.User))) - return; - - ActivationVerb verb = new(); - verb.Act = () => InteractUI(args.User, uid, component); - verb.Text = Loc.GetString(component.VerbText); - // TODO VERBS add "open UI" icon? - args.Verbs.Add(verb); - } - - private void OnActivate(EntityUid uid, ActivatableUIComponent component, ActivateInWorldEvent args) - { - if (args.Handled) - return; - - if (component.InHandsOnly) - return; - - if (component.AllowedItems != null) - return; - - args.Handled = InteractUI(args.User, uid, component); - } - - private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args) - { - if (args.Handled) - return; - - if (component.RightClickOnly) - return; - - if (component.AllowedItems != null) - return; - - args.Handled = InteractUI(args.User, uid, component); - } - - private void OnInteractUsing(EntityUid uid, ActivatableUIComponent component, InteractUsingEvent args) - { - if (args.Handled) return; - if (component.AllowedItems == null) return; - if (!component.AllowedItems.IsValid(args.Used, EntityManager)) return; - args.Handled = InteractUI(args.User, uid, component); - } - - private void OnParentChanged(EntityUid uid, ActivatableUIComponent aui, ref EntParentChangedMessage args) - { - CloseAll(uid, aui); - } - - private void OnUIClose(EntityUid uid, ActivatableUIComponent component, BoundUIClosedEvent args) - { - if (args.Session != component.CurrentSingleUser) - return; - - if (!Equals(args.UiKey, component.Key)) - return; - - SetCurrentSingleUser(uid, null, component); - } - - private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUIComponent aui) - { - if (!TryComp(user, out ActorComponent? actor)) - return false; - - if (aui.Key == null) - return false; - - if (!_uiSystem.TryGetUi(uiEntity, aui.Key, out var ui)) - return false; - - if (ui.SubscribedSessions.Contains(actor.PlayerSession)) - { - _uiSystem.CloseUi(ui, actor.PlayerSession); - return true; - } - - if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp(user))) - return false; - - if (aui.RequireHands && !HasComp(user)) - return false; - - if (aui.AdminOnly && !_adminManager.IsAdmin(actor.PlayerSession)) - return false; - - if (aui.SingleUser && (aui.CurrentSingleUser != null) && (actor.PlayerSession != aui.CurrentSingleUser)) - { - string message = Loc.GetString("machine-already-in-use", ("machine", uiEntity)); - _popupSystem.PopupEntity(message, uiEntity, user); - - // If we get here, supposedly, the object is in use. - // Check with BUI that it's ACTUALLY in use just in case. - // Since this could brick the object if it goes wrong. - if (ui.SubscribedSessions.Count != 0) - return false; - } - - // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this. - // This is so that stuff can require further conditions (like power). - var oae = new ActivatableUIOpenAttemptEvent(user); - var uae = new UserOpenActivatableUIAttemptEvent(user, uiEntity); - RaiseLocalEvent(user, uae); - RaiseLocalEvent(uiEntity, oae); - if (oae.Cancelled || uae.Cancelled) - return false; - - // Give the UI an opportunity to prepare itself if it needs to do anything - // before opening - var bae = new BeforeActivatableUIOpenEvent(user); - RaiseLocalEvent(uiEntity, bae); - - SetCurrentSingleUser(uiEntity, actor.PlayerSession, aui); - _uiSystem.OpenUi(ui, actor.PlayerSession); - - //Let the component know a user opened it so it can do whatever it needs to do - var aae = new AfterActivatableUIOpenEvent(user, actor.PlayerSession); - RaiseLocalEvent(uiEntity, aae); - - return true; - } - - public void SetCurrentSingleUser(EntityUid uid, ICommonSession? v, ActivatableUIComponent? aui = null) - { - if (!Resolve(uid, ref aui)) - return; - if (!aui.SingleUser) - return; - - aui.CurrentSingleUser = v; - - RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent()); - } - - public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null) - { - if (!Resolve(uid, ref aui, false)) - return; - - if (aui.Key == null || !_uiSystem.TryGetUi(uid, aui.Key, out var ui)) - return; - - _uiSystem.CloseAll(ui); - } - - private void OnHandDeselected(EntityUid uid, ActivatableUIComponent? aui, HandDeselectedEvent args) - { - if (!Resolve(uid, ref aui, false)) - return; - - if (!aui.CloseOnHandDeselect) - return; - - CloseAll(uid, aui); - } -} diff --git a/Content.Server/UserInterface/IntrinsicUIComponent.cs b/Content.Server/UserInterface/IntrinsicUIComponent.cs index 4d3c7ffba97..83936edc8c4 100644 --- a/Content.Server/UserInterface/IntrinsicUIComponent.cs +++ b/Content.Server/UserInterface/IntrinsicUIComponent.cs @@ -9,18 +9,12 @@ public sealed partial class IntrinsicUIComponent : Component /// /// List of UIs and their actions that this entity has. /// - [DataField("uis", required: true)] public List UIs = new(); + [DataField("uis", required: true)] public Dictionary UIs = new(); } [DataDefinition] -public partial class IntrinsicUIEntry +public sealed partial class IntrinsicUIEntry { - /// - /// The BUI key that this intrinsic UI should open. - /// - [DataField("key", required: true)] - public Enum? Key { get; private set; } - [DataField("toggleAction", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] public string? ToggleAction; diff --git a/Content.Server/UserInterface/IntrinsicUISystem.cs b/Content.Server/UserInterface/IntrinsicUISystem.cs index fa725e524a0..0f7261865dc 100644 --- a/Content.Server/UserInterface/IntrinsicUISystem.cs +++ b/Content.Server/UserInterface/IntrinsicUISystem.cs @@ -18,50 +18,31 @@ public override void Initialize() private void OnActionToggle(EntityUid uid, IntrinsicUIComponent component, ToggleIntrinsicUIEvent args) { + if (args.Key == null) + return; + args.Handled = InteractUI(uid, args.Key, component); } private void InitActions(EntityUid uid, IntrinsicUIComponent component, MapInitEvent args) { - foreach (var entry in component.UIs) + foreach (var entry in component.UIs.Values) { _actionsSystem.AddAction(uid, ref entry.ToggleActionEntity, entry.ToggleAction); } } - public bool InteractUI(EntityUid uid, Enum? key, IntrinsicUIComponent? iui = null, ActorComponent? actor = null) + public bool InteractUI(EntityUid uid, Enum key, IntrinsicUIComponent? iui = null, ActorComponent? actor = null) { if (!Resolve(uid, ref iui, ref actor)) return false; - if (key is null) - { - Log.Error($"Entity {ToPrettyString(uid)} has an invalid intrinsic UI."); - } - - var ui = GetUIOrNull(uid, key, iui); - - if (ui is null) - { - Log.Error($"Couldn't get UI {key} on {ToPrettyString(uid)}"); - return false; - } - var attempt = new IntrinsicUIOpenAttemptEvent(uid, key); RaiseLocalEvent(uid, attempt); if (attempt.Cancelled) return false; - _uiSystem.ToggleUi(ui, actor.PlayerSession); - return true; - } - - private PlayerBoundUserInterface? GetUIOrNull(EntityUid uid, Enum? key, IntrinsicUIComponent? component = null) - { - if (!Resolve(uid, ref component)) - return null; - - return key is null ? null : _uiSystem.GetUiOrNull(uid, key); + return _uiSystem.TryToggleUi(uid, key, actor.PlayerSession); } } diff --git a/Content.Server/Vampire/BloodSuckerSystem.cs b/Content.Server/Vampire/BloodSuckerSystem.cs index a63334a8943..81d28543189 100644 --- a/Content.Server/Vampire/BloodSuckerSystem.cs +++ b/Content.Server/Vampire/BloodSuckerSystem.cs @@ -11,9 +11,9 @@ using Content.Server.Body.Systems; using Content.Shared.Chemistry.EntitySystems; using Content.Server.Popups; -using Content.Server.HealthExaminable; using Content.Server.DoAfter; using Content.Server.Nutrition.Components; +using Content.Shared.HealthExaminable; using Robust.Shared.Prototypes; using Robust.Shared.Audio.Systems; using Robust.Shared.Utility; diff --git a/Content.Server/VendingMachines/VendingMachineSystem.cs b/Content.Server/VendingMachines/VendingMachineSystem.cs index 36fa69313e3..60be1ad6f1b 100644 --- a/Content.Server/VendingMachines/VendingMachineSystem.cs +++ b/Content.Server/VendingMachines/VendingMachineSystem.cs @@ -114,7 +114,7 @@ private void UpdateVendingMachineInterfaceState(EntityUid uid, VendingMachineCom { var state = new VendingMachineInterfaceState(GetAllInventory(uid, component)); - _userInterfaceSystem.TrySetUiState(uid, VendingMachineUiKey.Key, state); + _userInterfaceSystem.SetUiState(uid, VendingMachineUiKey.Key, state); } private void OnInventoryEjectMessage(EntityUid uid, VendingMachineComponent component, VendingMachineEjectMessage args) @@ -122,7 +122,7 @@ private void OnInventoryEjectMessage(EntityUid uid, VendingMachineComponent comp if (!this.IsPowered(uid, EntityManager)) return; - if (args.Session.AttachedEntity is not { Valid: true } entity || Deleted(entity)) + if (args.Actor is not { Valid: true } entity || Deleted(entity)) return; AuthorizedVend(uid, entity, args.Type, args.ID, component); diff --git a/Content.Server/VoiceMask/VoiceMaskSystem.Equip.cs b/Content.Server/VoiceMask/VoiceMaskSystem.Equip.cs index bd0c40f26a1..b97c47ceefc 100644 --- a/Content.Server/VoiceMask/VoiceMaskSystem.Equip.cs +++ b/Content.Server/VoiceMask/VoiceMaskSystem.Equip.cs @@ -1,6 +1,6 @@ using Content.Server.Actions; +using Content.Shared.Clothing; using Content.Shared.Inventory; -using Content.Shared.Inventory.Events; namespace Content.Server.VoiceMask; @@ -12,13 +12,9 @@ public sealed partial class VoiceMaskSystem private const string MaskSlot = "mask"; - private void OnEquip(EntityUid uid, VoiceMaskerComponent component, GotEquippedEvent args) + private void OnEquip(EntityUid uid, VoiceMaskerComponent component, ClothingGotEquippedEvent args) { - var user = args.Equipee; - // have to be wearing the mask to use it, duh. - if (!_inventory.TryGetSlotEntity(user, MaskSlot, out var maskEntity) || maskEntity != uid) - return; - + var user = args.Wearer; var comp = EnsureComp(user); comp.VoiceName = component.LastSetName; comp.SpeechVerb = component.LastSpeechVerb; @@ -26,9 +22,9 @@ private void OnEquip(EntityUid uid, VoiceMaskerComponent component, GotEquippedE _actions.AddAction(user, ref component.ActionEntity, component.Action, uid); } - private void OnUnequip(EntityUid uid, VoiceMaskerComponent compnent, GotUnequippedEvent args) + private void OnUnequip(EntityUid uid, VoiceMaskerComponent compnent, ClothingGotUnequippedEvent args) { - RemComp(args.Equipee); + RemComp(args.Wearer); } private VoiceMaskerComponent? TryGetMask(EntityUid user) diff --git a/Content.Server/VoiceMask/VoiceMaskSystem.cs b/Content.Server/VoiceMask/VoiceMaskSystem.cs index 19ed156a0b4..d925092083b 100644 --- a/Content.Server/VoiceMask/VoiceMaskSystem.cs +++ b/Content.Server/VoiceMask/VoiceMaskSystem.cs @@ -3,7 +3,6 @@ using Content.Server.Popups; using Content.Shared.Clothing; using Content.Shared.Database; -using Content.Shared.Inventory.Events; using Content.Shared.Popups; using Content.Shared.Preferences; using Content.Shared.Speech; @@ -27,8 +26,8 @@ public override void Initialize() SubscribeLocalEvent(OnChangeName); SubscribeLocalEvent(OnChangeVerb); SubscribeLocalEvent(OnMaskToggled); - SubscribeLocalEvent(OnEquip); - SubscribeLocalEvent(OnUnequip); + SubscribeLocalEvent(OnEquip); + SubscribeLocalEvent(OnUnequip); SubscribeLocalEvent(OnSetName); // SubscribeLocalEvent>(GetVerbs); } @@ -42,17 +41,14 @@ private void OnChangeName(EntityUid uid, VoiceMaskComponent component, VoiceMask { if (message.Name.Length > HumanoidCharacterProfile.MaxNameLength || message.Name.Length <= 0) { - _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-failure"), uid, message.Session, PopupType.SmallCaution); + _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-failure"), uid, message.Actor, PopupType.SmallCaution); return; } component.VoiceName = message.Name; - if (message.Session.AttachedEntity != null) - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(message.Session.AttachedEntity.Value):player} set voice of {ToPrettyString(uid):mask}: {component.VoiceName}"); - else - _adminLogger.Add(LogType.Action, LogImpact.Medium, $"Voice of {ToPrettyString(uid):mask} set: {component.VoiceName}"); + _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(message.Actor):player} set voice of {ToPrettyString(uid):mask}: {component.VoiceName}"); - _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), uid, message.Session); + _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), uid, message.Actor); TrySetLastKnownName(uid, message.Name); @@ -67,7 +63,7 @@ private void OnChangeVerb(Entity ent, ref VoiceMaskChangeVer ent.Comp.SpeechVerb = msg.Verb; // verb is only important to metagamers so no need to log as opposed to name - _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), ent, msg.Session); + _popupSystem.PopupEntity(Loc.GetString("voice-mask-popup-success"), ent, msg.Actor); TrySetLastSpeechVerb(ent, msg.Verb); @@ -95,27 +91,21 @@ private void OnMaskToggled(Entity ent, ref WearerMaskToggled ent.Comp.Enabled = !args.IsToggled; } - private void OpenUI(EntityUid player, ActorComponent? actor = null) + private void OpenUI(EntityUid player) { - // Delta-V: `logMissing: false` because of syrinx. - if (!Resolve(player, ref actor, logMissing: false)) - return; - if (!_uiSystem.TryGetUi(player, VoiceMaskUIKey.Key, out var bui)) + if (!_uiSystem.IsUiOpen(player, VoiceMaskUIKey.Key)) return; - _uiSystem.OpenUi(bui, actor.PlayerSession); + _uiSystem.OpenUi(player, VoiceMaskUIKey.Key, player); UpdateUI(player); } private void UpdateUI(EntityUid owner, VoiceMaskComponent? component = null) { - // Delta-V: `logMissing: false` because of syrinx if (!Resolve(owner, ref component, logMissing: false)) - { return; - } - if (_uiSystem.TryGetUi(owner, VoiceMaskUIKey.Key, out var bui)) - _uiSystem.SetUiState(bui, new VoiceMaskBuiState(component.VoiceName, component.SpeechVerb)); + if (_uiSystem.HasUi(owner, VoiceMaskUIKey.Key)) + _uiSystem.SetUiState(owner, VoiceMaskUIKey.Key, new VoiceMaskBuiState(component.VoiceName, component.SpeechVerb)); } } diff --git a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs index fbc46f59179..53993e4b35f 100644 --- a/Content.Server/Weapons/Ranged/Systems/GunSystem.cs +++ b/Content.Server/Weapons/Ranged/Systems/GunSystem.cs @@ -107,7 +107,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? // Update shot based on the recoil toMap = fromMap.Position + angle.ToVec() * mapDirection.Length(); mapDirection = toMap - fromMap.Position; - var gunVelocity = Physics.GetMapLinearVelocity(gunUid); + var gunVelocity = Physics.GetMapLinearVelocity(fromEnt); // I must be high because this was getting tripped even when true. // DebugTools.Assert(direction != Vector2.Zero); @@ -156,7 +156,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? }); SetCartridgeSpent(ent.Value, cartridge, true); - MuzzleFlash(gunUid, cartridge, user); + MuzzleFlash(gunUid, cartridge, mapDirection.ToAngle(), user); Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user); if (cartridge.DeleteOnSpawn) @@ -177,7 +177,7 @@ public override void Shoot(EntityUid gunUid, GunComponent gun, List<(EntityUid? // Ammo shoots itself case AmmoComponent newAmmo: shotProjectiles.Add(ent!.Value); - MuzzleFlash(gunUid, newAmmo, user); + MuzzleFlash(gunUid, newAmmo, mapDirection.ToAngle(), user); Audio.PlayPredicted(gun.SoundGunshotModified, gunUid, user); ShootOrThrow(ent.Value, mapDirection, gunVelocity, gun, gunUid, user); break; @@ -336,9 +336,9 @@ private Angle GetRecoilAngle(TimeSpan curTime, GunComponent component, Angle dir protected override void Popup(string message, EntityUid? uid, EntityUid? user) { } - protected override void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null) + protected override void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null) { - var filter = Filter.Pvs(uid, entityManager: EntityManager); + var filter = Filter.Pvs(gunUid, entityManager: EntityManager); if (TryComp(user, out var actor)) filter.RemovePlayer(actor.PlayerSession); diff --git a/Content.Server/Wires/WiresSystem.cs b/Content.Server/Wires/WiresSystem.cs index 0f9ee8b0f75..54ed1995006 100644 --- a/Content.Server/Wires/WiresSystem.cs +++ b/Content.Server/Wires/WiresSystem.cs @@ -17,6 +17,7 @@ using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; +using ActivatableUISystem = Content.Shared.UserInterface.ActivatableUISystem; namespace Content.Server.Wires; @@ -393,11 +394,11 @@ private void OnWiresPowered(EntityUid uid, WiresComponent component, ref PowerCh private void OnWiresActionMessage(EntityUid uid, WiresComponent component, WiresActionMessage args) { - if (args.Session.AttachedEntity == null) + if (args.Actor == null) { return; } - var player = (EntityUid) args.Session.AttachedEntity; + var player = (EntityUid) args.Actor; if (!EntityManager.TryGetComponent(player, out HandsComponent? handsComponent)) { @@ -458,7 +459,7 @@ private void OnInteractUsing(EntityUid uid, WiresComponent component, InteractUs { if (TryComp(args.User, out ActorComponent? actor)) { - _uiSystem.TryOpen(uid, WiresUiKey.Key, actor.PlayerSession); + _uiSystem.OpenUi(uid, WiresUiKey.Key, actor.PlayerSession); args.Handled = true; } } @@ -468,7 +469,8 @@ private void OnPanelChanged(Entity ent, ref PanelChangedEvent ar { if (args.Open) return; - _uiSystem.TryCloseAll(ent, WiresUiKey.Key); + + _uiSystem.CloseUi(ent.Owner, WiresUiKey.Key); } private void OnAttemptOpenActivatableUI(EntityUid uid, ActivatableUIRequiresPanelComponent component, ActivatableUIOpenAttemptEvent args) @@ -574,18 +576,17 @@ private void UpdateUserInterface(EntityUid uid, WiresComponent? wires = null, Us statuses.Sort((a, b) => a.position.CompareTo(b.position)); - _uiSystem.TrySetUiState(uid, WiresUiKey.Key, new WiresBoundUserInterfaceState( + _uiSystem.SetUiState((uid, ui), WiresUiKey.Key, new WiresBoundUserInterfaceState( clientList.ToArray(), statuses.Select(p => new StatusEntry(p.key, p.value)).ToArray(), Loc.GetString(wires.BoardName), wires.SerialNumber, - wires.WireSeed), ui: ui); + wires.WireSeed)); } public void OpenUserInterface(EntityUid uid, ICommonSession player) { - if (_uiSystem.TryGetUi(uid, WiresUiKey.Key, out var ui)) - _uiSystem.OpenUi(ui, player); + _uiSystem.OpenUi(uid, WiresUiKey.Key, player); } /// @@ -629,7 +630,7 @@ public void SetWiresPanelSecurity(EntityUid uid, WiresPanelSecurityComponent com if (!args.WiresAccessible) { - _uiSystem.TryCloseAll(uid, WiresUiKey.Key); + _uiSystem.CloseUi(uid, WiresUiKey.Key); } } diff --git a/Content.Server/Worldgen/Prototypes/NoiseChannelPrototype.cs b/Content.Server/Worldgen/Prototypes/NoiseChannelPrototype.cs index 67da4c4df18..02ca383d300 100644 --- a/Content.Server/Worldgen/Prototypes/NoiseChannelPrototype.cs +++ b/Content.Server/Worldgen/Prototypes/NoiseChannelPrototype.cs @@ -80,7 +80,7 @@ public class NoiseChannelConfig } [Prototype("noiseChannel")] -public sealed class NoiseChannelPrototype : NoiseChannelConfig, IPrototype, IInheritingPrototype +public sealed partial class NoiseChannelPrototype : NoiseChannelConfig, IPrototype, IInheritingPrototype { /// [ParentDataField(typeof(AbstractPrototypeIdArraySerializer))] diff --git a/Content.Server/Xenoarchaeology/Equipment/Components/TraversalDistorterComponent.cs b/Content.Server/Xenoarchaeology/Equipment/Components/TraversalDistorterComponent.cs index d6a39fe4f40..1461021e3d3 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Components/TraversalDistorterComponent.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Components/TraversalDistorterComponent.cs @@ -23,7 +23,7 @@ public sealed partial class TraversalDistorterComponent : Component public float PartRatingBiasChance = 1.1f; [ViewVariables(VVAccess.ReadWrite)] - public BiasDirection BiasDirection = BiasDirection.In; + public BiasDirection BiasDirection = BiasDirection.Up; public TimeSpan NextActivation = default!; public TimeSpan ActivationDelay = TimeSpan.FromSeconds(1); @@ -31,6 +31,6 @@ public sealed partial class TraversalDistorterComponent : Component public enum BiasDirection : byte { - In, //down the tree, towards depth 0 - Out //up the tree, away from depth 0 + Up, //Towards depth 0 + Down, //Away from depth 0 } diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs index 27caebef808..72d99460fe2 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/ArtifactAnalyzerSystem.cs @@ -41,7 +41,8 @@ public sealed class ArtifactAnalyzerSystem : EntitySystem [Dependency] private readonly PaperSystem _paper = default!; [Dependency] private readonly ResearchSystem _research = default!; [Dependency] private readonly MetaDataSystem _metaSystem = default!; - [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; //Nyano - Summary: pulls in the glimmer system. + [Dependency] private readonly TraversalDistorterSystem _traversalDistorter = default!; + [Dependency] private readonly GlimmerSystem _glimmerSystem = default!; /// public override void Initialize() @@ -63,6 +64,7 @@ public override void Initialize() SubscribeLocalEvent(OnScanButton); SubscribeLocalEvent(OnPrintButton); SubscribeLocalEvent(OnExtractButton); + SubscribeLocalEvent(OnBiasButton); SubscribeLocalEvent((e, c, _) => UpdateUserInterface(e, c), after: new[] { typeof(ResearchSystem) }); @@ -194,6 +196,7 @@ private void UpdateUserInterface(EntityUid uid, AnalysisConsoleComponent? compon var canScan = false; var canPrint = false; var points = 0; + if (TryComp(component.AnalyzerEntity, out var analyzer)) { artifact = analyzer.LastAnalyzedArtifact; @@ -207,18 +210,22 @@ private void UpdateUserInterface(EntityUid uid, AnalysisConsoleComponent? compon if (GetArtifactForAnalysis(component.AnalyzerEntity, placer) is { } current) points = _artifact.GetResearchPointValue(current); } + var analyzerConnected = component.AnalyzerEntity != null; var serverConnected = TryComp(uid, out var client) && client.ConnectedToServer; var scanning = TryComp(component.AnalyzerEntity, out var active); var paused = active != null ? active.AnalysisPaused : false; + var biasDirection = BiasDirection.Up; - var state = new AnalysisConsoleScanUpdateState(GetNetEntity(artifact), analyzerConnected, serverConnected, - canScan, canPrint, msg, scanning, paused, active?.StartTime, active?.AccumulatedRunTime, totalTime, points); + if (TryComp(component.AnalyzerEntity, out var trav)) + biasDirection = trav.BiasDirection; - var bui = _ui.GetUi(uid, ArtifactAnalzyerUiKey.Key); - _ui.SetUiState(bui, state); + var state = new AnalysisConsoleUpdateState(GetNetEntity(artifact), analyzerConnected, serverConnected, + canScan, canPrint, msg, scanning, paused, active?.StartTime, active?.AccumulatedRunTime, totalTime, points, biasDirection == BiasDirection.Down); + + _ui.SetUiState(uid, ArtifactAnalzyerUiKey.Key, state); } /// @@ -229,7 +236,7 @@ private void UpdateUserInterface(EntityUid uid, AnalysisConsoleComponent? compon /// private void OnServerSelectionMessage(EntityUid uid, AnalysisConsoleComponent component, AnalysisConsoleServerSelectionMessage args) { - _ui.TryOpen(uid, ResearchClientUiKey.Key, args.Session); + _ui.OpenUi(uid, ResearchClientUiKey.Key, args.Actor); } /// @@ -382,6 +389,20 @@ private void OnExtractButton(EntityUid uid, AnalysisConsoleComponent component, UpdateUserInterface(uid, component); } + private void OnBiasButton(EntityUid uid, AnalysisConsoleComponent component, AnalysisConsoleBiasButtonPressedMessage args) + { + if (component.AnalyzerEntity == null) + return; + + if (!TryComp(component.AnalyzerEntity, out var trav)) + return; + + if (!_traversalDistorter.SetState(component.AnalyzerEntity.Value, trav, args.IsDown)) + return; + + UpdateUserInterface(uid, component); + } + /// /// Cancels scans if the artifact changes nodes (is activated) during the scan. /// @@ -505,4 +526,3 @@ private void OnPowerChanged(EntityUid uid, ActiveArtifactAnalyzerComponent activ } } } - diff --git a/Content.Server/Xenoarchaeology/Equipment/Systems/TraversalDistorterSystem.cs b/Content.Server/Xenoarchaeology/Equipment/Systems/TraversalDistorterSystem.cs index bb662925a92..1bcffd3a7ba 100644 --- a/Content.Server/Xenoarchaeology/Equipment/Systems/TraversalDistorterSystem.cs +++ b/Content.Server/Xenoarchaeology/Equipment/Systems/TraversalDistorterSystem.cs @@ -20,8 +20,6 @@ public sealed class TraversalDistorterSystem : EntitySystem public override void Initialize() { SubscribeLocalEvent(OnInit); - - SubscribeLocalEvent(OnInteract); SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnRefreshParts); SubscribeLocalEvent(OnUpgradeExamine); @@ -35,30 +33,25 @@ private void OnInit(EntityUid uid, TraversalDistorterComponent component, MapIni component.NextActivation = _timing.CurTime; } - private void OnInteract(EntityUid uid, TraversalDistorterComponent component, ActivateInWorldEvent args) + /// + /// Switches the state of the traversal distorter between up and down. + /// + /// The distorter's entity + /// The component on the entity + /// If the distorter changed state + public bool SetState(EntityUid uid, TraversalDistorterComponent component, bool isDown) { - if (args.Handled || !this.IsPowered(uid, EntityManager)) - return; + if (!this.IsPowered(uid, EntityManager)) + return false; + if (_timing.CurTime < component.NextActivation) - return; - args.Handled = true; + return false; + component.NextActivation = _timing.CurTime + component.ActivationDelay; - component.BiasDirection = component.BiasDirection == BiasDirection.In - ? BiasDirection.Out - : BiasDirection.In; + component.BiasDirection = isDown ? BiasDirection.Down : BiasDirection.Up; - var toPopup = string.Empty; - switch (component.BiasDirection) - { - case BiasDirection.In: - toPopup = Loc.GetString("traversal-distorter-set-in"); - break; - case BiasDirection.Out: - toPopup = Loc.GetString("traversal-distorter-set-out"); - break; - } - _popup.PopupEntity(toPopup, uid); + return true; } private void OnExamine(EntityUid uid, TraversalDistorterComponent component, ExaminedEvent args) @@ -66,11 +59,11 @@ private void OnExamine(EntityUid uid, TraversalDistorterComponent component, Exa string examine = string.Empty; switch (component.BiasDirection) { - case BiasDirection.In: - examine = Loc.GetString("traversal-distorter-desc-in"); + case BiasDirection.Up: + examine = Loc.GetString("traversal-distorter-desc-up"); break; - case BiasDirection.Out: - examine = Loc.GetString("traversal-distorter-desc-out"); + case BiasDirection.Down: + examine = Loc.GetString("traversal-distorter-desc-down"); break; } args.PushMarkup(examine); diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs index 647f31a8953..895bb0217b3 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.Nodes.cs @@ -19,26 +19,46 @@ public sealed partial class ArtifactSystem /// /// /// - /// The amount of nodes it has. - private void GenerateArtifactNodeTree(EntityUid artifact, ref List allNodes, int nodeAmount) + /// The amount of nodes it has. + private void GenerateArtifactNodeTree(EntityUid artifact, List allNodes, int nodesToCreate) { - if (nodeAmount < 1) + if (nodesToCreate < 1) { - Log.Error($"nodeAmount {nodeAmount} is less than 1. Aborting artifact tree generation."); + Log.Error($"nodesToCreate {nodesToCreate} is less than 1. Aborting artifact tree generation."); return; } _usedNodeIds.Clear(); + var uninitializedNodes = new List { new(){ Id = GetValidNodeId() } }; + var createdNodes = 1; - var rootNode = new ArtifactNode + while (uninitializedNodes.Count > 0) { - Id = GetValidNodeId() - }; - var uninitializedNodes = new List { rootNode }; - while (uninitializedNodes.Any()) - { - GenerateNode(artifact, ref uninitializedNodes, ref allNodes, nodeAmount); + var node = uninitializedNodes[0]; + uninitializedNodes.Remove(node); + + node.Trigger = GetRandomTrigger(artifact, ref node); + node.Effect = GetRandomEffect(artifact, ref node); + + var maxChildren = _random.Next(1, MaxEdgesPerNode - 1); + + for (var i = 0; i < maxChildren; i++) + { + if (nodesToCreate <= createdNodes) + { + break; + } + + var child = new ArtifactNode {Id = GetValidNodeId(), Depth = node.Depth + 1}; + node.Edges.Add(child.Id); + child.Edges.Add(node.Id); + + uninitializedNodes.Add(child); + createdNodes++; + } + + allNodes.Add(node); } } @@ -51,44 +71,8 @@ private int GetValidNodeId() } _usedNodeIds.Add(id); - return id; - } - /// - /// Generate an individual node on the tree. - /// - private void GenerateNode(EntityUid artifact, ref List uninitializedNodes, ref List allNodes, int targetNodeAmount) - { - if (!uninitializedNodes.Any()) - return; - - var node = uninitializedNodes.First(); - uninitializedNodes.Remove(node); - - //Generate the connected nodes - var maxEdges = Math.Max(1, targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1); - maxEdges = Math.Min(maxEdges, MaxEdgesPerNode); - var minEdges = Math.Clamp(targetNodeAmount - allNodes.Count - uninitializedNodes.Count - 1, 0, 1); - - var edgeAmount = _random.Next(minEdges, maxEdges); - - for (var i = 0; i < edgeAmount; i++) - { - var neighbor = new ArtifactNode - { - Depth = node.Depth + 1, - Id = GetValidNodeId() - }; - node.Edges.Add(neighbor.Id); - neighbor.Edges.Add(node.Id); - - uninitializedNodes.Add(neighbor); - } - - node.Trigger = GetRandomTrigger(artifact, ref node); - node.Effect = GetRandomEffect(artifact, ref node); - - allNodes.Add(node); + return id; } //yeah these two functions are near duplicates but i don't @@ -159,6 +143,7 @@ private int GetRandomTargetDepth(Dictionary weights) return key; } } + return _random.Pick(weights.Keys); //shouldn't happen } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs index a7948aa7ff9..f1700759772 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/ArtifactSystem.cs @@ -129,7 +129,7 @@ public void RandomizeArtifact(EntityUid uid, ArtifactComponent component) { var nodeAmount = _random.Next(component.NodesMin, component.NodesMax); - GenerateArtifactNodeTree(uid, ref component.NodeTree, nodeAmount); + GenerateArtifactNodeTree(uid, component.NodeTree, nodeAmount); var firstNode = GetRootNode(component.NodeTree); EnterNode(uid, ref firstNode, component); } @@ -184,13 +184,14 @@ public void ForceActivateArtifact(EntityUid uid, EntityUid? user = null, Artifac var currentNode = GetNodeFromId(component.CurrentNodeId.Value, component); currentNode.Triggered = true; - if (currentNode.Edges.Any()) - { - var newNode = GetNewNode(uid, component); - if (newNode == null) - return; - EnterNode(uid, ref newNode, component); - } + if (currentNode.Edges.Count == 0) + return; + + var newNode = GetNewNode(uid, component); + if (newNode == null) + return; + + EnterNode(uid, ref newNode, component); } private ArtifactNode? GetNewNode(EntityUid uid, ArtifactComponent component) @@ -211,15 +212,15 @@ public void ForceActivateArtifact(EntityUid uid, EntityUid? user = null, Artifac { switch (trav.BiasDirection) { - case BiasDirection.In: - var foo = allNodes.Where(x => GetNodeFromId(x, component).Depth < currentNode.Depth).ToHashSet(); - if (foo.Any()) - allNodes = foo; + case BiasDirection.Up: + var upNodes = allNodes.Where(x => GetNodeFromId(x, component).Depth < currentNode.Depth).ToHashSet(); + if (upNodes.Count != 0) + allNodes = upNodes; break; - case BiasDirection.Out: - var bar = allNodes.Where(x => GetNodeFromId(x, component).Depth > currentNode.Depth).ToHashSet(); - if (bar.Any()) - allNodes = bar; + case BiasDirection.Down: + var downNodes = allNodes.Where(x => GetNodeFromId(x, component).Depth > currentNode.Depth).ToHashSet(); + if (downNodes.Count != 0) + allNodes = downNodes; break; } } @@ -227,12 +228,14 @@ public void ForceActivateArtifact(EntityUid uid, EntityUid? user = null, Artifac var undiscoveredNodes = allNodes.Where(x => !GetNodeFromId(x, component).Discovered).ToList(); Log.Debug($"Undiscovered nodes: {string.Join(", ", undiscoveredNodes)}"); var newNode = _random.Pick(allNodes); - if (undiscoveredNodes.Any() && _random.Prob(0.75f)) + + if (undiscoveredNodes.Count != 0 && _random.Prob(0.75f)) { newNode = _random.Pick(undiscoveredNodes); } Log.Debug($"Going to node {newNode}"); + return GetNodeFromId(newNode, component); } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs index e24d31a1135..dc054d23182 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/GasArtifactSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Atmos; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs index e2d21723550..e44ee6baa12 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/PortalArtifactSystem.cs @@ -35,8 +35,7 @@ private void OnActivate(Entity artifact, ref ArtifactAc var secondPortal = Spawn(artifact.Comp.PortalProto, _transform.GetMapCoordinates(target)); //Manual position swapping, because the portal that opens doesn't trigger a collision, and doesn't teleport targets the first time. - _transform.SetCoordinates(artifact, Transform(secondPortal).Coordinates); - _transform.SetCoordinates(target, Transform(firstPortal).Coordinates); + _transform.SwapPositions(target, secondPortal); _link.TryLink(firstPortal, secondPortal, true); } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ShuffleArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ShuffleArtifactSystem.cs index b977cb038c9..c39627818a1 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ShuffleArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/ShuffleArtifactSystem.cs @@ -22,7 +22,6 @@ private void OnActivated(EntityUid uid, ShuffleArtifactComponent component, Arti { var mobState = GetEntityQuery(); - List allCoords = new(); List> toShuffle = new(); foreach (var ent in _lookup.GetEntitiesInRange(uid, component.Radius, LookupFlags.Dynamic | LookupFlags.Sundries)) @@ -33,13 +32,15 @@ private void OnActivated(EntityUid uid, ShuffleArtifactComponent component, Arti var xform = Transform(ent); toShuffle.Add((ent, xform)); - allCoords.Add(xform.Coordinates); } - foreach (var xform in toShuffle) + _random.Shuffle(toShuffle); + + while (toShuffle.Count > 1) { - var xformUid = xform.Owner; - _xform.SetCoordinates(xformUid, xform, _random.PickAndTake(allCoords)); + var ent1 = _random.PickAndTake(toShuffle); + var ent2 = _random.PickAndTake(toShuffle); + _xform.SwapPositions((ent1, ent1), (ent2, ent2)); } } } diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs index f314d4a4fb2..e62ce36b5b9 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Effects/Systems/TemperatureArtifactSystem.cs @@ -2,6 +2,7 @@ using Content.Server.Atmos.EntitySystems; using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components; using Content.Server.Xenoarchaeology.XenoArtifacts.Events; +using Content.Shared.Atmos; using Robust.Server.GameObjects; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems; diff --git a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactExamineTriggerSystem.cs b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactExamineTriggerSystem.cs index cbade1682e5..b7afbcfc8b4 100644 --- a/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactExamineTriggerSystem.cs +++ b/Content.Server/Xenoarchaeology/XenoArtifacts/Triggers/Systems/ArtifactExamineTriggerSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components; using Content.Shared.Examine; +using Content.Shared.Ghost; namespace Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Systems; @@ -15,6 +16,10 @@ public override void Initialize() private void OnExamine(EntityUid uid, ArtifactExamineTriggerComponent component, ExaminedEvent args) { + // Prevent ghosts from activating this trigger unless they have CanGhostInteract + if (TryComp(args.Examiner, out var ghost) && !ghost.CanGhostInteract) + return; + _artifact.TryActivateArtifact(uid); } } diff --git a/Content.Server/Zombies/IncurableZombieComponent.cs b/Content.Server/Zombies/IncurableZombieComponent.cs index 26958656909..375b814b51d 100644 --- a/Content.Server/Zombies/IncurableZombieComponent.cs +++ b/Content.Server/Zombies/IncurableZombieComponent.cs @@ -1,10 +1,16 @@ -namespace Content.Server.Zombies; +using Robust.Shared.Prototypes; + +namespace Content.Server.Zombies; /// -/// This is used for a zombie that cannot be cured by any methods. +/// This is used for a zombie that cannot be cured by any methods. Gives a succumb to zombie infection action. /// [RegisterComponent] public sealed partial class IncurableZombieComponent : Component { + [DataField] + public EntProtoId ZombifySelfActionPrototype = "ActionTurnUndead"; + [DataField] + public EntityUid? Action; } diff --git a/Content.Server/Zombies/PendingZombieComponent.cs b/Content.Server/Zombies/PendingZombieComponent.cs index 1bb0ef28720..811d3f96440 100644 --- a/Content.Server/Zombies/PendingZombieComponent.cs +++ b/Content.Server/Zombies/PendingZombieComponent.cs @@ -1,5 +1,4 @@ using Content.Shared.Damage; -using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; namespace Content.Server.Zombies; @@ -17,7 +16,7 @@ public sealed partial class PendingZombieComponent : Component { DamageDict = new () { - { "Poison", 0.3 }, + { "Poison", 0.2 }, } }; @@ -48,9 +47,6 @@ public sealed partial class PendingZombieComponent : Component [DataField] public TimeSpan MaxInitialInfectedGrace = TimeSpan.FromMinutes(15f); - [DataField] - public EntProtoId ZombifySelfActionPrototype = "ActionTurnUndead"; - /// /// The chance each second that a warning will be shown. /// @@ -66,6 +62,4 @@ public sealed partial class PendingZombieComponent : Component "zombie-infection-warning", "zombie-infection-underway" }; - - [DataField] public EntityUid? Action; } diff --git a/Content.Server/Zombies/ZombieSystem.Transform.cs b/Content.Server/Zombies/ZombieSystem.Transform.cs index 5b38e6f766f..a906652765c 100644 --- a/Content.Server/Zombies/ZombieSystem.Transform.cs +++ b/Content.Server/Zombies/ZombieSystem.Transform.cs @@ -80,7 +80,7 @@ private void OnDamageChanged(EntityUid uid, ZombifyOnDeathComponent component, M /// the entity being zombified /// /// - /// ALRIGHT BIG BOY. YOU'VE COME TO THE LAYER OF THE BEAST. THIS IS YOUR WARNING. + /// ALRIGHT BIG BOYS, GIRLS AND ANYONE ELSE. YOU'VE COME TO THE LAYER OF THE BEAST. THIS IS YOUR WARNING. /// This function is the god function for zombie stuff, and it is cursed. I have /// attempted to label everything thouroughly for your sanity. I have attempted to /// rewrite this, but this is how it shall lie eternal. Turn back now. @@ -236,6 +236,11 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) _identity.QueueIdentityUpdate(target); + var htn = EnsureComp(target); + htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" }; + htn.Blackboard.SetValue(NPCBlackboard.Owner, target); + _npc.SleepNPC(target, htn); + //He's gotta have a mind var hasMind = _mind.TryGetMind(target, out var mindId, out _); if (hasMind && _mind.TryGetSession(mindId, out var session)) @@ -251,9 +256,6 @@ public void ZombifyEntity(EntityUid target, MobStateComponent? mobState = null) } else { - var htn = EnsureComp(target); - htn.RootTask = new HTNCompoundTask() { Task = "SimpleHostileCompound" }; - htn.Blackboard.SetValue(NPCBlackboard.Owner, target); _npc.WakeNPC(target, htn); } diff --git a/Content.Server/Zombies/ZombieSystem.cs b/Content.Server/Zombies/ZombieSystem.cs index 09c8fa26db6..552fd2781c0 100644 --- a/Content.Server/Zombies/ZombieSystem.cs +++ b/Content.Server/Zombies/ZombieSystem.cs @@ -64,9 +64,16 @@ public override void Initialize() SubscribeLocalEvent(OnPendingMapInit); + SubscribeLocalEvent(OnPendingMapInit); + SubscribeLocalEvent(OnDamageChanged); } + private void OnPendingMapInit(EntityUid uid, IncurableZombieComponent component, MapInitEvent args) + { + _actions.AddAction(uid, ref component.Action, component.ZombifySelfActionPrototype); + } + private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, MapInitEvent args) { if (_mobState.IsDead(uid)) @@ -77,7 +84,6 @@ private void OnPendingMapInit(EntityUid uid, PendingZombieComponent component, M component.NextTick = _timing.CurTime + TimeSpan.FromSeconds(1f); component.GracePeriod = _random.Next(component.MinInitialInfectedGrace, component.MaxInitialInfectedGrace); - _actions.AddAction(uid, ref component.Action, component.ZombifySelfActionPrototype); } public override void Update(float frameTime) diff --git a/Content.Shared/Access/Components/IdCardComponent.cs b/Content.Shared/Access/Components/IdCardComponent.cs index 26e83c5586e..39d5d9d27f3 100644 --- a/Content.Shared/Access/Components/IdCardComponent.cs +++ b/Content.Shared/Access/Components/IdCardComponent.cs @@ -40,4 +40,10 @@ public sealed partial class IdCardComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public bool BypassLogging; + + [DataField] + public LocId NameLocId = "access-id-card-component-owner-name-job-title-text"; + + [DataField] + public LocId FullNameLocId = "access-id-card-component-owner-full-name-job-title-text"; } diff --git a/Content.Shared/Access/Components/IdExaminableComponent.cs b/Content.Shared/Access/Components/IdExaminableComponent.cs new file mode 100644 index 00000000000..87d3e03a14f --- /dev/null +++ b/Content.Shared/Access/Components/IdExaminableComponent.cs @@ -0,0 +1,6 @@ +using Content.Shared.Access.Systems; + +namespace Content.Shared.Access.Components; + +[RegisterComponent, Access(typeof(IdExaminableSystem))] +public sealed partial class IdExaminableComponent : Component; diff --git a/Content.Shared/Access/SharedAgentIDCardSystem.cs b/Content.Shared/Access/SharedAgentIDCardSystem.cs index ef6690cc356..d027a3937f5 100644 --- a/Content.Shared/Access/SharedAgentIDCardSystem.cs +++ b/Content.Shared/Access/SharedAgentIDCardSystem.cs @@ -26,12 +26,14 @@ public sealed class AgentIDCardBoundUserInterfaceState : BoundUserInterfaceState public readonly HashSet Icons; public string CurrentName { get; } public string CurrentJob { get; } + public string CurrentJobIconId { get; } - public AgentIDCardBoundUserInterfaceState(string currentName, string currentJob, HashSet icons) + public AgentIDCardBoundUserInterfaceState(string currentName, string currentJob, string currentJobIconId, HashSet icons) { Icons = icons; CurrentName = currentName; CurrentJob = currentJob; + CurrentJobIconId = currentJobIconId; } } @@ -60,11 +62,11 @@ public AgentIDCardJobChangedMessage(string job) [Serializable, NetSerializable] public sealed class AgentIDCardJobIconChangedMessage : BoundUserInterfaceMessage { - public string JobIcon { get; } + public string JobIconId { get; } - public AgentIDCardJobIconChangedMessage(string jobIcon) + public AgentIDCardJobIconChangedMessage(string jobIconId) { - JobIcon = jobIcon; + JobIconId = jobIconId; } } } diff --git a/Content.Shared/Access/Systems/AccessReaderSystem.cs b/Content.Shared/Access/Systems/AccessReaderSystem.cs index 89c08e0a4e7..3670e24bd32 100644 --- a/Content.Shared/Access/Systems/AccessReaderSystem.cs +++ b/Content.Shared/Access/Systems/AccessReaderSystem.cs @@ -153,7 +153,7 @@ public bool IsAllowed( return IsAllowedInternal(access, stationKeys, reader); if (!_containerSystem.TryGetContainer(target, reader.ContainerAccessProvider, out var container)) - return false; + return Paused(target); // when mapping, containers with electronics arent spawned foreach (var entity in container.ContainedEntities) { diff --git a/Content.Server/Access/Systems/IdExaminableSystem.cs b/Content.Shared/Access/Systems/IdExaminableSystem.cs similarity index 85% rename from Content.Server/Access/Systems/IdExaminableSystem.cs rename to Content.Shared/Access/Systems/IdExaminableSystem.cs index c2231605e4a..333272e27ac 100644 --- a/Content.Server/Access/Systems/IdExaminableSystem.cs +++ b/Content.Shared/Access/Systems/IdExaminableSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Access.Components; using Content.Shared.Access.Components; using Content.Shared.Examine; using Content.Shared.Inventory; @@ -6,7 +5,7 @@ using Content.Shared.Verbs; using Robust.Shared.Utility; -namespace Content.Server.Access.Systems; +namespace Content.Shared.Access.Systems; public sealed class IdExaminableSystem : EntitySystem { @@ -22,7 +21,7 @@ public override void Initialize() private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, GetVerbsEvent args) { var detailsRange = _examineSystem.IsInDetailsRange(args.User, uid); - var info = GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id"); + var info = GetMessage(uid); var verb = new ExamineVerb() { @@ -41,7 +40,12 @@ private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, G args.Verbs.Add(verb); } - private string? GetInfo(EntityUid uid) + public string GetMessage(EntityUid uid) + { + return GetInfo(uid) ?? Loc.GetString("id-examinable-component-verb-no-id"); + } + + public string? GetInfo(EntityUid uid) { if (_inventorySystem.TryGetSlotEntity(uid, "id", out var idUid)) { @@ -65,9 +69,9 @@ private string GetNameAndJob(IdCardComponent id) var jobSuffix = string.IsNullOrWhiteSpace(id.JobTitle) ? string.Empty : $" ({id.JobTitle})"; var val = string.IsNullOrWhiteSpace(id.FullName) - ? Loc.GetString("access-id-card-component-owner-name-job-title-text", + ? Loc.GetString(id.NameLocId, ("jobSuffix", jobSuffix)) - : Loc.GetString("access-id-card-component-owner-full-name-job-title-text", + : Loc.GetString(id.FullNameLocId, ("fullName", id.FullName), ("jobSuffix", jobSuffix)); diff --git a/Content.Shared/Access/Systems/SharedIdCardSystem.cs b/Content.Shared/Access/Systems/SharedIdCardSystem.cs index 842e7e7e6ac..bfde70f5041 100644 --- a/Content.Shared/Access/Systems/SharedIdCardSystem.cs +++ b/Content.Shared/Access/Systems/SharedIdCardSystem.cs @@ -1,13 +1,32 @@ using Content.Shared.Access.Components; +using Content.Shared.Administration.Logs; +using Content.Shared.Database; using Content.Shared.Hands.Components; using Content.Shared.Inventory; using Content.Shared.PDA; +using Content.Shared.Roles; +using Content.Shared.StatusIcon; +using Robust.Shared.Prototypes; namespace Content.Shared.Access.Systems; public abstract class SharedIdCardSystem : EntitySystem { + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly MetaDataSystem _metaSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, IdCardComponent id, MapInitEvent args) + { + UpdateEntityName(uid, id); + } /// /// Attempt to find an ID card on an entity. This will look in the entity itself, in the entity's hands, and @@ -56,4 +75,143 @@ public bool TryGetIdCard(EntityUid uid, out Entity idCard) idCard = default; return false; } + + /// + /// Attempts to change the job title of a card. + /// Returns true/false. + /// + /// + /// If provided with a player's EntityUid to the player parameter, adds the change to the admin logs. + /// + public bool TryChangeJobTitle(EntityUid uid, string? jobTitle, IdCardComponent? id = null, EntityUid? player = null) + { + if (!Resolve(uid, ref id)) + return false; + + if (!string.IsNullOrWhiteSpace(jobTitle)) + { + jobTitle = jobTitle.Trim(); + + if (jobTitle.Length > IdCardConsoleComponent.MaxJobTitleLength) + jobTitle = jobTitle[..IdCardConsoleComponent.MaxJobTitleLength]; + } + else + { + jobTitle = null; + } + + if (id.JobTitle == jobTitle) + return true; + id.JobTitle = jobTitle; + Dirty(uid, id); + UpdateEntityName(uid, id); + + if (player != null) + { + _adminLogger.Add(LogType.Identity, LogImpact.Low, + $"{ToPrettyString(player.Value):player} has changed the job title of {ToPrettyString(uid):entity} to {jobTitle} "); + } + return true; + } + + public bool TryChangeJobIcon(EntityUid uid, StatusIconPrototype jobIcon, IdCardComponent? id = null, EntityUid? player = null) + { + if (!Resolve(uid, ref id)) + { + return false; + } + + if (id.JobIcon == jobIcon.ID) + { + return true; + } + + id.JobIcon = jobIcon.ID; + Dirty(uid, id); + + if (player != null) + { + _adminLogger.Add(LogType.Identity, LogImpact.Low, + $"{ToPrettyString(player.Value):player} has changed the job icon of {ToPrettyString(uid):entity} to {jobIcon} "); + } + + return true; + } + + public bool TryChangeJobDepartment(EntityUid uid, JobPrototype job, IdCardComponent? id = null) + { + if (!Resolve(uid, ref id)) + return false; + + id.JobDepartments.Clear(); + foreach (var department in _prototypeManager.EnumeratePrototypes()) + { + if (department.Roles.Contains(job.ID)) + id.JobDepartments.Add("department-" + department.ID); + } + + Dirty(uid, id); + + return true; + } + + /// + /// Attempts to change the full name of a card. + /// Returns true/false. + /// + /// + /// If provided with a player's EntityUid to the player parameter, adds the change to the admin logs. + /// + public bool TryChangeFullName(EntityUid uid, string? fullName, IdCardComponent? id = null, EntityUid? player = null) + { + if (!Resolve(uid, ref id)) + return false; + + if (!string.IsNullOrWhiteSpace(fullName)) + { + fullName = fullName.Trim(); + if (fullName.Length > IdCardConsoleComponent.MaxFullNameLength) + fullName = fullName[..IdCardConsoleComponent.MaxFullNameLength]; + } + else + { + fullName = null; + } + + if (id.FullName == fullName) + return true; + id.FullName = fullName; + Dirty(uid, id); + UpdateEntityName(uid, id); + + if (player != null) + { + _adminLogger.Add(LogType.Identity, LogImpact.Low, + $"{ToPrettyString(player.Value):player} has changed the name of {ToPrettyString(uid):entity} to {fullName} "); + } + return true; + } + + /// + /// Changes the name of the id's owner. + /// + /// + /// If either or is empty, it's replaced by placeholders. + /// If both are empty, the original entity's name is restored. + /// + private void UpdateEntityName(EntityUid uid, IdCardComponent? id = null) + { + if (!Resolve(uid, ref id)) + return; + + var jobSuffix = string.IsNullOrWhiteSpace(id.JobTitle) ? string.Empty : $" ({id.JobTitle})"; + + var val = string.IsNullOrWhiteSpace(id.FullName) + ? Loc.GetString(id.NameLocId, + ("jobSuffix", jobSuffix)) + : Loc.GetString(id.FullNameLocId, + ("fullName", id.FullName), + ("jobSuffix", jobSuffix)); + _metaSystem.SetEntityName(uid, val); + } } diff --git a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs index f5ed2df227c..47b3997806d 100644 --- a/Content.Shared/ActionBlocker/ActionBlockerSystem.cs +++ b/Content.Shared/ActionBlocker/ActionBlockerSystem.cs @@ -169,8 +169,16 @@ public bool CanEmote(EntityUid uid) public bool CanAttack(EntityUid uid, EntityUid? target = null, Entity? weapon = null, bool disarm = false) { + // If target is in a container can we attack + if (target != null && _container.IsEntityInContainer(target.Value)) + { + return false; + } + _container.TryGetOuterContainer(uid, Transform(uid), out var outerContainer); - if (target != null && target != outerContainer?.Owner && _container.IsEntityInContainer(uid)) + + // If we're in a container can we attack the target. + if (target != null && target != outerContainer?.Owner && _container.IsEntityInContainer(uid)) { var containerEv = new CanAttackFromContainerEvent(uid, target); RaiseLocalEvent(uid, containerEv); diff --git a/Content.Shared/Actions/ActionEvents.cs b/Content.Shared/Actions/ActionEvents.cs index 72a566b8c88..6cc50bc21b4 100644 --- a/Content.Shared/Actions/ActionEvents.cs +++ b/Content.Shared/Actions/ActionEvents.cs @@ -68,9 +68,10 @@ public void AddAction(ref EntityUid? actionId, string prototypeId) AddAction(ref actionId, prototypeId, Provider); } - public void AddAction(EntityUid actionId) + public void AddAction(EntityUid? actionId) { - Actions.Add(actionId); + if (actionId != null) + Actions.Add(actionId.Value); } } @@ -154,4 +155,9 @@ public abstract partial class BaseActionEvent : HandledEntityEventArgs /// The user performing the action. /// public EntityUid Performer; + + /// + /// The action the event belongs to. + /// + public EntityUid Action; } diff --git a/Content.Shared/Actions/BaseActionComponent.cs b/Content.Shared/Actions/BaseActionComponent.cs index 6d9242acc1d..57c145a0ecf 100644 --- a/Content.Shared/Actions/BaseActionComponent.cs +++ b/Content.Shared/Actions/BaseActionComponent.cs @@ -1,5 +1,4 @@ -using Content.Shared.Mobs; -using Robust.Shared.Audio; +using Robust.Shared.Audio; using Robust.Shared.Serialization; using Robust.Shared.Utility; @@ -25,6 +24,11 @@ public abstract partial class BaseActionComponent : Component /// [DataField("iconOn")] public SpriteSpecifier? IconOn; + /// + /// For toggle actions only, background to show when toggled on. + /// + [DataField] public SpriteSpecifier? BackgroundOn; + /// /// If not null, this color will modulate the action icon color. /// diff --git a/Content.Shared/Actions/Events/ActionPerformedEvent.cs b/Content.Shared/Actions/Events/ActionPerformedEvent.cs new file mode 100644 index 00000000000..530d7c93355 --- /dev/null +++ b/Content.Shared/Actions/Events/ActionPerformedEvent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Actions.Events; + +/// +/// Raised on the action entity when it is used and . +/// +/// The entity that performed this action. +[ByRefEvent] +public readonly record struct ActionPerformedEvent(EntityUid Performer); diff --git a/Content.Shared/Actions/Events/ValidateActionEntityTargetEvent.cs b/Content.Shared/Actions/Events/ValidateActionEntityTargetEvent.cs new file mode 100644 index 00000000000..9f22e7973a4 --- /dev/null +++ b/Content.Shared/Actions/Events/ValidateActionEntityTargetEvent.cs @@ -0,0 +1,4 @@ +namespace Content.Shared.Actions.Events; + +[ByRefEvent] +public record struct ValidateActionEntityTargetEvent(EntityUid User, EntityUid Target, bool Cancelled = false); diff --git a/Content.Shared/Actions/Events/ValidateActionWorldTargetEvent.cs b/Content.Shared/Actions/Events/ValidateActionWorldTargetEvent.cs new file mode 100644 index 00000000000..43e398aad4a --- /dev/null +++ b/Content.Shared/Actions/Events/ValidateActionWorldTargetEvent.cs @@ -0,0 +1,6 @@ +using Robust.Shared.Map; + +namespace Content.Shared.Actions.Events; + +[ByRefEvent] +public record struct ValidateActionWorldTargetEvent(EntityUid User, EntityCoordinates Target, bool Cancelled = false); diff --git a/Content.Shared/Actions/SharedActionsSystem.cs b/Content.Shared/Actions/SharedActionsSystem.cs index 35d962b0e4e..0a4755bf105 100644 --- a/Content.Shared/Actions/SharedActionsSystem.cs +++ b/Content.Shared/Actions/SharedActionsSystem.cs @@ -8,14 +8,13 @@ using Content.Shared.Interaction; using Content.Shared.Inventory.Events; using Content.Shared.Mind; -using Content.Shared.Mobs.Components; +using Content.Shared.Rejuvenate; using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; using Robust.Shared.Map; using Robust.Shared.Timing; using Robust.Shared.Utility; -using Content.Shared.Rejuvenate; namespace Content.Shared.Actions; @@ -145,9 +144,6 @@ public bool ResolveActionData( public void SetCooldown(EntityUid? actionId, TimeSpan start, TimeSpan end) { - if (actionId == null) - return; - if (!TryGetActionData(actionId, out var action)) return; @@ -163,9 +159,6 @@ public void SetCooldown(EntityUid? actionId, TimeSpan cooldown) public void ClearCooldown(EntityUid? actionId) { - if (actionId == null) - return; - if (!TryGetActionData(actionId, out var action)) return; @@ -176,6 +169,27 @@ public void ClearCooldown(EntityUid? actionId) Dirty(actionId.Value, action); } + /// + /// Sets the cooldown for this action only if it is bigger than the one it already has. + /// + public void SetIfBiggerCooldown(EntityUid? actionId, TimeSpan? cooldown) + { + if (cooldown == null || + cooldown.Value <= TimeSpan.Zero || + !TryGetActionData(actionId, out var action)) + { + return; + } + + var start = GameTiming.CurTime; + var end = start + cooldown; + if (action.Cooldown?.End > end) + return; + + action.Cooldown = (start, end.Value); + Dirty(actionId.Value, action); + } + public void StartUseDelay(EntityUid? actionId) { if (actionId == null) @@ -389,7 +403,7 @@ private void OnActionRequest(RequestPerformActionEvent ev, EntitySessionEventArg var targetWorldPos = _transformSystem.GetWorldPosition(entityTarget); _rotateToFaceSystem.TryFaceCoordinates(user, targetWorldPos); - if (!ValidateEntityTarget(user, entityTarget, entityAction)) + if (!ValidateEntityTarget(user, entityTarget, (actionEnt, entityAction))) return; _adminLogger.Add(LogType.Action, @@ -413,7 +427,7 @@ private void OnActionRequest(RequestPerformActionEvent ev, EntitySessionEventArg var entityCoordinatesTarget = GetCoordinates(netCoordinatesTarget); _rotateToFaceSystem.TryFaceCoordinates(user, entityCoordinatesTarget.ToMapPos(EntityManager, _transformSystem)); - if (!ValidateWorldTarget(user, entityCoordinatesTarget, worldAction)) + if (!ValidateWorldTarget(user, entityCoordinatesTarget, (actionEnt, worldAction))) return; _adminLogger.Add(LogType.Action, @@ -439,13 +453,26 @@ private void OnActionRequest(RequestPerformActionEvent ev, EntitySessionEventArg } if (performEvent != null) + { performEvent.Performer = user; + performEvent.Action = actionEnt; + } // All checks passed. Perform the action! PerformAction(user, component, actionEnt, action, performEvent, curTime); } - public bool ValidateEntityTarget(EntityUid user, EntityUid target, EntityTargetActionComponent action) + public bool ValidateEntityTarget(EntityUid user, EntityUid target, Entity actionEnt) + { + if (!ValidateEntityTargetBase(user, target, actionEnt)) + return false; + + var ev = new ValidateActionEntityTargetEvent(user, target); + RaiseLocalEvent(actionEnt, ref ev); + return !ev.Cancelled; + } + + private bool ValidateEntityTargetBase(EntityUid user, EntityUid target, EntityTargetActionComponent action) { if (!target.IsValid() || Deleted(target)) return false; @@ -487,7 +514,17 @@ public bool ValidateEntityTarget(EntityUid user, EntityUid target, EntityTargetA return _interactionSystem.CanAccessViaStorage(user, target); } - public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, WorldTargetActionComponent action) + public bool ValidateWorldTarget(EntityUid user, EntityCoordinates coords, Entity action) + { + if (!ValidateWorldTargetBase(user, coords, action)) + return false; + + var ev = new ValidateActionWorldTargetEvent(user, coords); + RaiseLocalEvent(action, ref ev); + return !ev.Cancelled; + } + + private bool ValidateWorldTargetBase(EntityUid user, EntityCoordinates coords, WorldTargetActionComponent action) { if (action.CheckCanInteract && !_actionBlockerSystem.CanInteract(user, null)) return false; @@ -535,13 +572,12 @@ public void PerformAction(EntityUid performer, ActionsComponent? component, Enti handled = actionEvent.Handled; } - _audio.PlayPredicted(action.Sound, performer,predicted ? performer : null); - handled |= action.Sound != null; - if (!handled) return; // no interaction occurred. - // reduce charges, start cooldown, and mark as dirty (if required). + // play sound, reduce charges, start cooldown, and mark as dirty (if required). + + _audio.PlayPredicted(action.Sound, performer,predicted ? performer : null); var dirty = toggledBefore == action.Toggled; @@ -564,6 +600,9 @@ public void PerformAction(EntityUid performer, ActionsComponent? component, Enti if (dirty && component != null) Dirty(performer, component); + + var ev = new ActionPerformedEvent(performer); + RaiseLocalEvent(actionId, ref ev); } #endregion diff --git a/Content.Shared/Administration/AdminFlags.cs b/Content.Shared/Administration/AdminFlags.cs index 9842e638c2c..71a08a70dbf 100644 --- a/Content.Shared/Administration/AdminFlags.cs +++ b/Content.Shared/Administration/AdminFlags.cs @@ -100,6 +100,16 @@ public enum AdminFlags : uint /// Stealth = 1 << 16, + /// + /// Allows you to use Admin chat + /// + Adminchat = 1 << 17, + + /// + /// Permits the visibility of Pii in game and on SS14 Admin + /// + Pii = 1 << 18, + /// /// DeltaV - The ability to whitelist people. Either this permission or +BAN is required for remove. /// diff --git a/Content.Shared/Administration/Components/SharedHeadstandComponent.cs b/Content.Shared/Administration/Components/SharedHeadstandComponent.cs index ebc23c7b053..96a4dfc2ddd 100644 --- a/Content.Shared/Administration/Components/SharedHeadstandComponent.cs +++ b/Content.Shared/Administration/Components/SharedHeadstandComponent.cs @@ -1,6 +1,9 @@ -namespace Content.Shared.Administration.Components; +using Robust.Shared.GameStates; + +namespace Content.Shared.Administration.Components; /// /// Flips the target's sprite on it's head, so they do a headstand. /// +[NetworkedComponent] public abstract partial class SharedHeadstandComponent : Component { } diff --git a/Content.Shared/Administration/Components/SharedKillSignComponent.cs b/Content.Shared/Administration/Components/SharedKillSignComponent.cs index 2e6d54ca884..9a95454f721 100644 --- a/Content.Shared/Administration/Components/SharedKillSignComponent.cs +++ b/Content.Shared/Administration/Components/SharedKillSignComponent.cs @@ -1,5 +1,8 @@ -namespace Content.Shared.Administration.Components; +using Robust.Shared.GameStates; +namespace Content.Shared.Administration.Components; + +[NetworkedComponent] public abstract partial class SharedKillSignComponent : Component { diff --git a/Content.Shared/Alert/AlertType.cs b/Content.Shared/Alert/AlertType.cs index 1130e25b66d..0808114b9d5 100644 --- a/Content.Shared/Alert/AlertType.cs +++ b/Content.Shared/Alert/AlertType.cs @@ -71,6 +71,7 @@ public enum AlertType : byte BorgCrit, BorgDead, Offer, + Deflecting, } } diff --git a/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs b/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs index 42db148df9c..1cb9ba085f6 100644 --- a/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs +++ b/Content.Shared/Announcements/Prototypes/AnnouncerPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Announcements.Prototypes; /// Defines an announcer and their announcement file paths /// [Prototype("announcer")] -public sealed class AnnouncerPrototype : IPrototype +public sealed partial class AnnouncerPrototype : IPrototype { [IdDataField] public string ID { get; } = default!; diff --git a/Content.Shared/Armor/AllowSuitStorageComponent.cs b/Content.Shared/Armor/AllowSuitStorageComponent.cs new file mode 100644 index 00000000000..aa7bce1c873 --- /dev/null +++ b/Content.Shared/Armor/AllowSuitStorageComponent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Armor; + +/// +/// Used on outerclothing to allow use of suit storage +/// +[RegisterComponent] +public sealed partial class AllowSuitStorageComponent : Component +{ + +} diff --git a/Content.Shared/Atmos/AtmosDirection.cs b/Content.Shared/Atmos/AtmosDirection.cs index 09ba521aa96..a8155ef88d7 100644 --- a/Content.Shared/Atmos/AtmosDirection.cs +++ b/Content.Shared/Atmos/AtmosDirection.cs @@ -104,15 +104,14 @@ public static Angle ToAngle(this AtmosDirection direction) { return direction switch { - AtmosDirection.East => Angle.FromDegrees(90), - AtmosDirection.North => Angle.FromDegrees(180), - AtmosDirection.West => Angle.FromDegrees(270), - AtmosDirection.South => Angle.FromDegrees(0), - - AtmosDirection.NorthEast => Angle.FromDegrees(135), - AtmosDirection.NorthWest => Angle.FromDegrees(205), - AtmosDirection.SouthWest => Angle.FromDegrees(315), - AtmosDirection.SouthEast => Angle.FromDegrees(45), + AtmosDirection.South => Angle.Zero, + AtmosDirection.East => new Angle(MathHelper.PiOver2), + AtmosDirection.North => new Angle(Math.PI), + AtmosDirection.West => new Angle(-MathHelper.PiOver2), + AtmosDirection.NorthEast => new Angle(Math.PI*3/4), + AtmosDirection.NorthWest => new Angle(-Math.PI*3/4), + AtmosDirection.SouthWest => new Angle(-MathHelper.PiOver4), + AtmosDirection.SouthEast => new Angle(MathHelper.PiOver4), _ => throw new ArgumentOutOfRangeException(nameof(direction), $"It was {direction}."), }; diff --git a/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs b/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs index 51ae8cc7406..dec9516c013 100644 --- a/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs +++ b/Content.Shared/Atmos/Components/GasAnalyzerComponent.cs @@ -56,13 +56,15 @@ public struct GasMixEntry /// Name of the tab in the UI /// public readonly string Name; + public readonly float Volume; public readonly float Pressure; public readonly float Temperature; public readonly GasEntry[]? Gases; - public GasMixEntry(string name, float pressure, float temperature, GasEntry[]? gases = null) + public GasMixEntry(string name, float volume, float pressure, float temperature, GasEntry[]? gases = null) { Name = name; + Volume = volume; Pressure = pressure; Temperature = temperature; Gases = gases; diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Shared/Atmos/GasMixture.cs similarity index 98% rename from Content.Server/Atmos/GasMixture.cs rename to Content.Shared/Atmos/GasMixture.cs index 3d73a4d0b16..a676ed67204 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Shared/Atmos/GasMixture.cs @@ -1,13 +1,12 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Runtime.CompilerServices; -using Content.Server.Atmos.Reactions; -using Content.Shared.Atmos; using Content.Shared.Atmos.EntitySystems; +using Content.Shared.Atmos.Reactions; using Robust.Shared.Serialization; using Robust.Shared.Utility; -namespace Content.Server.Atmos +namespace Content.Shared.Atmos { /// /// A general-purpose, variable volume gas mixture. diff --git a/Content.Shared/Atmos/GasMixtureStringRepresentation.cs b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs new file mode 100644 index 00000000000..942b2bdc672 --- /dev/null +++ b/Content.Shared/Atmos/GasMixtureStringRepresentation.cs @@ -0,0 +1,16 @@ +namespace Content.Shared.Atmos; + +public readonly record struct GasMixtureStringRepresentation(float TotalMoles, float Temperature, float Pressure, Dictionary MolesPerGas) : IFormattable +{ + public override string ToString() + { + return $"{Temperature}K {Pressure} kPa"; + } + + public string ToString(string? format, IFormatProvider? formatProvider) + { + return ToString(); + } + + public static implicit operator string(GasMixtureStringRepresentation rep) => rep.ToString(); +} diff --git a/Content.Shared/Atmos/GetFireProtectionEvent.cs b/Content.Shared/Atmos/GetFireProtectionEvent.cs new file mode 100644 index 00000000000..e243295449a --- /dev/null +++ b/Content.Shared/Atmos/GetFireProtectionEvent.cs @@ -0,0 +1,33 @@ +using Content.Shared.Inventory; + +namespace Content.Shared.Atmos; + +/// +/// Raised on a burning entity to check its fire protection. +/// Damage taken is multiplied by the final amount, but not temperature. +/// TemperatureProtection is needed for that. +/// +[ByRefEvent] +public sealed class GetFireProtectionEvent : EntityEventArgs, IInventoryRelayEvent +{ + public SlotFlags TargetSlots { get; } = ~SlotFlags.POCKET; + + /// + /// What to multiply the fire damage by. + /// If this is 0 then it's ignored + /// + public float Multiplier; + + public GetFireProtectionEvent() + { + Multiplier = 1f; + } + + /// + /// Reduce fire damage taken by a percentage. + /// + public void Reduce(float by) + { + Multiplier -= by; + } +} diff --git a/Content.Shared/Atmos/Reactions/GasReactionEnums.cs b/Content.Shared/Atmos/Reactions/GasReactionEnums.cs new file mode 100644 index 00000000000..73b8998d409 --- /dev/null +++ b/Content.Shared/Atmos/Reactions/GasReactionEnums.cs @@ -0,0 +1,14 @@ +namespace Content.Shared.Atmos.Reactions; + +[Flags] +public enum ReactionResult : byte +{ + NoReaction = 0, + Reacting = 1, + StopReactions = 2, +} + +public enum GasReaction : byte +{ + Fire = 0, +} diff --git a/Content.Shared/Audio/Jukebox/JukeboxPrototype.cs b/Content.Shared/Audio/Jukebox/JukeboxPrototype.cs index 256f22f2a6e..ad690ef4973 100644 --- a/Content.Shared/Audio/Jukebox/JukeboxPrototype.cs +++ b/Content.Shared/Audio/Jukebox/JukeboxPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Audio.Jukebox; /// Soundtrack that's visible on the jukebox list. /// [Prototype] -public sealed class JukeboxPrototype : IPrototype +public sealed partial class JukeboxPrototype : IPrototype { [IdDataField] public string ID { get; } = string.Empty; diff --git a/Content.Shared/Body/Prototypes/MetabolismGroupPrototype.cs b/Content.Shared/Body/Prototypes/MetabolismGroupPrototype.cs index 162b5f2d6c2..82f4e70ce0c 100644 --- a/Content.Shared/Body/Prototypes/MetabolismGroupPrototype.cs +++ b/Content.Shared/Body/Prototypes/MetabolismGroupPrototype.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; namespace Content.Shared.Body.Prototypes { @@ -7,5 +7,11 @@ public sealed partial class MetabolismGroupPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; + + [DataField("name", required: true)] + private LocId Name { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string LocalizedName => Loc.GetString(Name); } } diff --git a/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs b/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs index c840983ca0c..5273ac722b2 100644 --- a/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs +++ b/Content.Shared/Body/Prototypes/MetabolizerTypePrototype.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; namespace Content.Shared.Body.Prototypes { @@ -9,6 +9,9 @@ public sealed partial class MetabolizerTypePrototype : IPrototype public string ID { get; private set; } = default!; [DataField("name", required: true)] - public string Name { get; private set; } = default!; + private LocId Name { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string LocalizedName => Loc.GetString(Name); } } diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 1b3bef5e333..5609eb73929 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1,6 +1,8 @@ +using Content.Shared.Maps; using Content.Shared.Supermatter.Components; using Robust.Shared; using Robust.Shared.Configuration; +using Robust.Shared.Physics.Components; namespace Content.Shared.CCVar { @@ -214,7 +216,7 @@ public static readonly CVarDef // 20 Minutes - which constitutes a minimum /// Controls the maximum number of character slots a player is allowed to have. /// public static readonly CVarDef - GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 10, CVar.ARCHIVE | CVar.SERVERONLY); + GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 30, CVar.ARCHIVE | CVar.SERVERONLY); /// /// Controls the game map prototype to load. SS14 stores these prototypes in Prototypes/Maps. @@ -583,6 +585,12 @@ public static readonly CVarDef public static readonly CVarDef LoginTipsDataset = CVarDef.Create("tips.login_dataset", "Tips"); + /// + /// The chance for Tippy to replace a normal tip message. + /// + public static readonly CVarDef TipsTippyChance = + CVarDef.Create("tips.tippy_chance", 0.01f); + /* * Console */ @@ -771,7 +779,6 @@ public static readonly CVarDef public static readonly CVarDef OfferModeIndicatorsPointShow = CVarDef.Create("hud.offer_mode_indicators_point_show", true, CVar.ARCHIVE | CVar.CLIENTONLY); - public static readonly CVarDef LoocAboveHeadShow = CVarDef.Create("hud.show_looc_above_head", true, CVar.ARCHIVE | CVar.CLIENTONLY); @@ -860,19 +867,43 @@ public static readonly CVarDef /// Default severity for role bans /// public static readonly CVarDef RoleBanDefaultSeverity = - CVarDef.Create("admin.role_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER); + CVarDef.Create("admin.role_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); /// /// Default severity for department bans /// public static readonly CVarDef DepartmentBanDefaultSeverity = - CVarDef.Create("admin.department_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER); + CVarDef.Create("admin.department_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); /// /// Default severity for server bans /// public static readonly CVarDef ServerBanDefaultSeverity = - CVarDef.Create("admin.server_ban_default_severity", "High", CVar.ARCHIVE | CVar.SERVER); + CVarDef.Create("admin.server_ban_default_severity", "High", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); + + /// + /// Whether a server ban will ban the player's ip by default. + /// + public static readonly CVarDef ServerBanIpBanDefault = + CVarDef.Create("admin.server_ban_ip_ban_default", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); + + /// + /// Whether a server ban will ban the player's hardware id by default. + /// + public static readonly CVarDef ServerBanHwidBanDefault = + CVarDef.Create("admin.server_ban_hwid_ban_default", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); + + /// + /// Whether to use details from last connection for ip/hwid in the BanPanel. + /// + public static readonly CVarDef ServerBanUseLastDetails = + CVarDef.Create("admin.server_ban_use_last_details", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); + + /// + /// Whether to erase a player's chat messages and their entity from the game when banned. + /// + public static readonly CVarDef ServerBanErasePlayer = + CVarDef.Create("admin.server_ban_erase_player", false, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED); /// /// Minimum explosion intensity to create an admin alert message. -1 to disable the alert. @@ -1017,6 +1048,13 @@ public static readonly CVarDef public static readonly CVarDef ExplosionSingleTickAreaLimit = CVarDef.Create("explosion.single_tick_area_limit", 400, CVar.SERVERONLY); + /// + /// Whether or not explosions are allowed to create tiles that have + /// set to true. + /// + public static readonly CVarDef ExplosionCanCreateVacuum = + CVarDef.Create("explosion.can_create_vacuum", true, CVar.SERVERONLY); + /* * Radiation */ @@ -1525,6 +1563,49 @@ public static readonly CVarDef public static readonly CVarDef GridFill = CVarDef.Create("shuttle.grid_fill", true, CVar.SERVERONLY); + /// + /// Whether to automatically preloading grids by GridPreloaderSystem + /// + public static readonly CVarDef PreloadGrids = + CVarDef.Create("shuttle.preload_grids", true, CVar.SERVERONLY); + + /// + /// How long the warmup time before FTL start should be. + /// + public static readonly CVarDef FTLStartupTime = + CVarDef.Create("shuttle.startup_time", 5.5f, CVar.SERVERONLY); + + /// + /// How long a shuttle spends in FTL. + /// + public static readonly CVarDef FTLTravelTime = + CVarDef.Create("shuttle.travel_time", 20f, CVar.SERVERONLY); + + /// + /// How long the final stage of FTL before arrival should be. + /// + public static readonly CVarDef FTLArrivalTime = + CVarDef.Create("shuttle.arrival_time", 5f, CVar.SERVERONLY); + + /// + /// How much time needs to pass before a shuttle can FTL again. + /// + public static readonly CVarDef FTLCooldown = + CVarDef.Create("shuttle.cooldown", 10f, CVar.SERVERONLY); + + /// + /// The maximum a grid can have before it becomes unable to FTL. + /// Any value equal to or less than zero will disable this check. + /// + public static readonly CVarDef FTLMassLimit = + CVarDef.Create("shuttle.mass_limit", 300f, CVar.SERVERONLY); + + /// + /// How long to knock down entities for if they aren't buckled when FTL starts and stops. + /// + public static readonly CVarDef HyperspaceKnockdownTime = + CVarDef.Create("shuttle.hyperspace_knockdown_time", 5f, CVar.SERVERONLY); + /* * Emergency */ @@ -1549,6 +1630,7 @@ public static readonly CVarDef /// /// The minimum time for the emergency shuttle to arrive at centcomm. + /// Actual minimum travel time cannot be less than /// public static readonly CVarDef EmergencyShuttleMinTransitTime = CVarDef.Create("shuttle.emergency_transit_time_min", 90f, CVar.SERVERONLY); @@ -1704,6 +1786,9 @@ public static readonly CVarDef public static readonly CVarDef ViewportWidth = CVarDef.Create("viewport.width", 21, CVar.CLIENTONLY | CVar.ARCHIVE); + public static readonly CVarDef ViewportVerticalFit = + CVarDef.Create("viewport.vertical_fit", true, CVar.CLIENTONLY | CVar.ARCHIVE); + /* * FOV */ @@ -2229,6 +2314,10 @@ public static readonly CVarDef public static readonly CVarDef GatewayGeneratorEnabled = CVarDef.Create("gateway.generator_enabled", true); + // Clippy! + public static readonly CVarDef TippyEntity = + CVarDef.Create("tippy.entity", "Tippy", CVar.SERVER | CVar.REPLICATED); + /* * DEBUG */ diff --git a/Content.Shared/Cargo/CargoOrderData.cs b/Content.Shared/Cargo/CargoOrderData.cs index a6d5fb0a18a..ce05d922362 100644 --- a/Content.Shared/Cargo/CargoOrderData.cs +++ b/Content.Shared/Cargo/CargoOrderData.cs @@ -1,48 +1,62 @@ using Robust.Shared.Serialization; -using Content.Shared.Access.Components; using System.Text; namespace Content.Shared.Cargo { - [NetSerializable, Serializable] - public sealed class CargoOrderData + [DataDefinition, NetSerializable, Serializable] + public sealed partial class CargoOrderData { /// /// Price when the order was added. /// + [DataField] public int Price; /// /// A unique (arbitrary) ID which identifies this order. /// - public readonly int OrderId; + [DataField] + public int OrderId { get; private set; } /// /// Prototype Id for the item to be created /// - public readonly string ProductId; + [DataField] + public string ProductId { get; private set; } + + /// + /// Prototype Name + /// + [DataField] + public string ProductName { get; private set; } /// /// The number of items in the order. Not readonly, as it might change /// due to caps on the amount of orders that can be placed. /// + [DataField] public int OrderQuantity; /// /// How many instances of this order that we've already dispatched /// + [DataField] public int NumDispatched = 0; - public readonly string Requester; + [DataField] + public string Requester { get; private set; } // public String RequesterRank; // TODO Figure out how to get Character ID card data // public int RequesterId; - public readonly string Reason; + [DataField] + public string Reason { get; private set; } public bool Approved => Approver is not null; + [DataField] public string? Approver; - public CargoOrderData(int orderId, string productId, int price, int amount, string requester, string reason) + public CargoOrderData(int orderId, string productId, string productName, int price, int amount, string requester, string reason) { OrderId = orderId; ProductId = productId; + ProductName = productName; Price = price; OrderQuantity = amount; Requester = requester; diff --git a/Content.Shared/Cargo/Components/CargoOrderConsoleComponent.cs b/Content.Shared/Cargo/Components/CargoOrderConsoleComponent.cs index a7d1f531754..873e9bb7b9d 100644 --- a/Content.Shared/Cargo/Components/CargoOrderConsoleComponent.cs +++ b/Content.Shared/Cargo/Components/CargoOrderConsoleComponent.cs @@ -1,6 +1,8 @@ using Content.Shared.Cargo.Prototypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; +using Content.Shared.Radio; +using Robust.Shared.Prototypes; namespace Content.Shared.Cargo.Components; @@ -21,5 +23,11 @@ public sealed partial class CargoOrderConsoleComponent : Component /// [DataField, ViewVariables(VVAccess.ReadWrite)] public List AllowedGroups = new() { "market" }; + + /// + /// Radio channel on which order approval announcements are transmitted + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ProtoId AnnouncementChannel = "Supply"; } diff --git a/Content.Shared/Cargo/Components/CashComponent.cs b/Content.Shared/Cargo/Components/CashComponent.cs index 10a47ff803a..89af094e04a 100644 --- a/Content.Shared/Cargo/Components/CashComponent.cs +++ b/Content.Shared/Cargo/Components/CashComponent.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Cargo.Components; /// -/// Can be inserted into a to increase the station's bank account. +/// Can be inserted into a to increase the station's bank account. /// [RegisterComponent, NetworkedComponent] public sealed partial class CashComponent : Component diff --git a/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs b/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs index 7c8a3625227..e69e83d6352 100644 --- a/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs +++ b/Content.Shared/Cargo/Components/SharedCargoTelepadComponent.cs @@ -13,6 +13,9 @@ namespace Content.Shared.Cargo.Components; [RegisterComponent, NetworkedComponent, Access(typeof(SharedCargoSystem))] public sealed partial class CargoTelepadComponent : Component { + [DataField] + public List CurrentOrders = new(); + /// /// The base amount of time it takes to teleport from the telepad /// diff --git a/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs b/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs index 1d0ca8abdb4..af2f6613d63 100644 --- a/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs +++ b/Content.Shared/Cargo/Prototypes/CargoProductPrototype.cs @@ -1,4 +1,4 @@ -using Robust.Shared.Prototypes; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array; using Robust.Shared.Utility; diff --git a/Content.Shared/Chat/EmotesEvents.cs b/Content.Shared/Chat/EmotesEvents.cs new file mode 100644 index 00000000000..4479f8b2ab9 --- /dev/null +++ b/Content.Shared/Chat/EmotesEvents.cs @@ -0,0 +1,11 @@ +using Content.Shared.Chat.Prototypes; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chat; + +[Serializable, NetSerializable] +public sealed class PlayEmoteMessage(ProtoId protoId) : EntityEventArgs +{ + public readonly ProtoId ProtoId = protoId; +} diff --git a/Content.Shared/Chat/Prototypes/EmotePrototype.cs b/Content.Shared/Chat/Prototypes/EmotePrototype.cs index 08f209d28d3..7ee958ee6a7 100644 --- a/Content.Shared/Chat/Prototypes/EmotePrototype.cs +++ b/Content.Shared/Chat/Prototypes/EmotePrototype.cs @@ -1,11 +1,13 @@ +using Content.Shared.Whitelist; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Chat.Prototypes; /// /// IC emotes (scream, smile, clapping, etc). -/// Entities can activate emotes by chat input or code. +/// Entities can activate emotes by chat input, radial or code. /// [Prototype("emote")] public sealed partial class EmotePrototype : IPrototype @@ -13,18 +15,50 @@ public sealed partial class EmotePrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; + /// + /// Localization string for the emote name. Displayed in the radial UI. + /// + [DataField(required: true)] + public string Name = default!; + + /// + /// Determines if emote available to all by default + /// check comes after this setting + /// can ignore this setting + /// + [DataField] + public bool Available = true; + /// /// Different emote categories may be handled by different systems. /// Also may be used for filtering. /// - [DataField("category")] + [DataField] public EmoteCategory Category = EmoteCategory.General; + /// + /// An icon used to visually represent the emote in radial UI. + /// + [DataField] + public SpriteSpecifier Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/Actions/scream.png")); + + /// + /// Determines conditions to this emote be available to use + /// + [DataField] + public EntityWhitelist? Whitelist; + + /// + /// Determines conditions to this emote be unavailable to use + /// + [DataField] + public EntityWhitelist? Blacklist; + /// /// Collection of words that will be sent to chat if emote activates. /// Will be picked randomly from list. /// - [DataField("chatMessages")] + [DataField] public List ChatMessages = new(); /// @@ -32,7 +66,7 @@ public sealed partial class EmotePrototype : IPrototype /// When typed into players chat they will activate emote event. /// All words should be unique across all emote prototypes. /// - [DataField("chatTriggers")] + [DataField] public HashSet ChatTriggers = new(); } diff --git a/Content.Shared/Chat/Prototypes/EmoteSoundsPrototype.cs b/Content.Shared/Chat/Prototypes/EmoteSoundsPrototype.cs index c9a78e7d6d7..2b7064c1e90 100644 --- a/Content.Shared/Chat/Prototypes/EmoteSoundsPrototype.cs +++ b/Content.Shared/Chat/Prototypes/EmoteSoundsPrototype.cs @@ -1,5 +1,6 @@ using Robust.Shared.Audio; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; namespace Content.Shared.Chat.Prototypes; @@ -8,8 +9,8 @@ namespace Content.Shared.Chat.Prototypes; /// Sounds collection for each . /// Different entities may use different sounds collections. /// -[Prototype("emoteSounds")] -public sealed partial class EmoteSoundsPrototype : IPrototype +[Prototype("emoteSounds"), Serializable, NetSerializable] +public sealed class EmoteSoundsPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; diff --git a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs index 41ed4b1b2ba..81ebcfb1088 100644 --- a/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs +++ b/Content.Shared/Chat/TypingIndicator/SharedTypingIndicatorSystem.cs @@ -1,5 +1,4 @@ -using Content.Shared.Clothing.Components; -using Content.Shared.Inventory.Events; +using Content.Shared.Clothing; namespace Content.Shared.Chat.TypingIndicator; @@ -17,25 +16,21 @@ public abstract class SharedTypingIndicatorSystem : EntitySystem public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); } - private void OnGotEquipped(EntityUid uid, TypingIndicatorClothingComponent component, GotEquippedEvent args) + private void OnGotEquipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotEquippedEvent args) { - if (!TryComp(uid, out var clothing) || - !TryComp(args.Equipee, out var indicator)) + if (!TryComp(args.Wearer, out var indicator)) return; - var isCorrectSlot = clothing.Slots.HasFlag(args.SlotFlags); - if (!isCorrectSlot) return; - indicator.Prototype = component.Prototype; } - private void OnGotUnequipped(EntityUid uid, TypingIndicatorClothingComponent component, GotUnequippedEvent args) + private void OnGotUnequipped(EntityUid uid, TypingIndicatorClothingComponent component, ClothingGotUnequippedEvent args) { - if (!TryComp(args.Equipee, out var indicator)) + if (!TryComp(args.Wearer, out var indicator)) return; indicator.Prototype = SharedTypingIndicatorSystem.InitialIndicatorId; diff --git a/Content.Shared/Chat/V2/Repository/Types.cs b/Content.Shared/Chat/V2/Repository/Types.cs new file mode 100644 index 00000000000..59acb849d46 --- /dev/null +++ b/Content.Shared/Chat/V2/Repository/Types.cs @@ -0,0 +1,60 @@ +using System.Linq; +using System.Runtime.InteropServices; +using Robust.Shared.Network; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chat.V2.Repository; + +/// +/// The record associated with a specific chat event. +/// +public struct ChatRecord(string userName, NetUserId userId, IChatEvent storedEvent, string entityName) +{ + public string UserName = userName; + public NetUserId UserId = userId; + public string EntityName = entityName; + public IChatEvent StoredEvent = storedEvent; +} + +/// +/// Notifies that a chat message has been created. +/// +/// +[Serializable, NetSerializable] +public sealed class MessageCreatedEvent(IChatEvent ev) : EntityEventArgs +{ + public IChatEvent Event = ev; +} + +/// +/// Notifies that a chat message has been changed. +/// +/// +/// +[Serializable, NetSerializable] +public sealed class MessagePatchedEvent(uint id, string newMessage) : EntityEventArgs +{ + public uint MessageId = id; + public string NewMessage = newMessage; +} + +/// +/// Notifies that a chat message has been deleted. +/// +/// +[Serializable, NetSerializable] +public sealed class MessageDeletedEvent(uint id) : EntityEventArgs +{ + public uint MessageId = id; +} + +/// +/// Notifies that a player's messages have been nuked. +/// +/// +[Serializable, NetSerializable] +public sealed class MessagesNukedEvent(List set) : EntityEventArgs +{ + public uint[] MessageIds = CollectionsMarshal.AsSpan(set).ToArray(); +} + diff --git a/Content.Shared/Chat/V2/Types.cs b/Content.Shared/Chat/V2/Types.cs new file mode 100644 index 00000000000..50e5a53ab50 --- /dev/null +++ b/Content.Shared/Chat/V2/Types.cs @@ -0,0 +1,94 @@ +namespace Content.Shared.Chat.V2; + +/// +/// The types of messages that can be sent, validated and processed via user input that are covered by Chat V2. +/// +public enum MessageType : byte +{ + #region Player-sendable types + + /// + /// Chat for announcements like CentCom telling you to stop sending them memes. + /// + Announcement, + /// + /// Chat that ghosts use to complain about being gibbed. + /// + DeadChat, + /// + /// Chat that mimes use to evade their vow. + /// + Emote, + /// + /// Chat that players use to make lame jokes to people nearby. + /// + Local, + /// + /// Chat that players use to complain about shitsec/admins/antags/balance/etc. + /// + Looc, + /// + /// Chat that players use to say "HELP MAINT", or plead to call the shuttle because a beaker spilled. + /// + /// This does not tell you what radio channel has been chatted on! + Radio, + /// + /// Chat that is used exclusively by syndie tots to collaborate on whatever tots do. + /// + Whisper, + + #endregion + + #region Non-player-sendable types + + /// + /// Chat that is sent to exactly one player; almost exclusively used for admemes and prayer responses. + /// + Subtle, + /// + /// Chat that is sent by automata, like when a vending machine thanks you for your unwise purchases. + /// + Background, + + #endregion +} + +/// +/// Defines a chat event that can be stored in a chat repository. +/// +public interface IChatEvent +{ + /// + /// The sender of the chat message. + /// + public EntityUid Sender + { + get; + } + + /// + /// The ID of the message. This is overwritten when saved into a repository. + /// + public uint Id + { + get; + set; + } + + /// + /// The sent message. + /// + public string Message + { + get; + set; + } + + /// + /// The type of sent message. + /// + public MessageType Type + { + get; + } +} diff --git a/Content.Shared/Chemistry/Components/InjectorComponent.cs b/Content.Shared/Chemistry/Components/InjectorComponent.cs index 437c5e327d2..c583ee66640 100644 --- a/Content.Shared/Chemistry/Components/InjectorComponent.cs +++ b/Content.Shared/Chemistry/Components/InjectorComponent.cs @@ -24,7 +24,8 @@ public sealed partial class InjectorDoAfterEvent : SimpleDoAfterEvent [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class InjectorComponent : Component { - public const string SolutionName = "injector"; + [DataField] + public string SolutionName = "injector"; /// /// Whether or not the injector is able to draw from containers or if it's a single use diff --git a/Content.Shared/Chemistry/Components/MixableSolutionComponent.cs b/Content.Shared/Chemistry/Components/MixableSolutionComponent.cs new file mode 100644 index 00000000000..2b1c140aa69 --- /dev/null +++ b/Content.Shared/Chemistry/Components/MixableSolutionComponent.cs @@ -0,0 +1,13 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Chemistry.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class MixableSolutionComponent : Component +{ + /// + /// Solution name which can be mixed with methods such as blessing + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public string Solution = "default"; +} diff --git a/Content.Shared/Chemistry/Components/ReagentTankComponent.cs b/Content.Shared/Chemistry/Components/ReagentTankComponent.cs new file mode 100644 index 00000000000..3aa1756cf9c --- /dev/null +++ b/Content.Shared/Chemistry/Components/ReagentTankComponent.cs @@ -0,0 +1,22 @@ +using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Chemistry.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ReagentTankComponent : Component +{ + [DataField, ViewVariables(VVAccess.ReadWrite)] + public FixedPoint2 TransferAmount { get; set; } = FixedPoint2.New(10); + + [DataField, ViewVariables(VVAccess.ReadWrite)] + public ReagentTankType TankType { get; set; } = ReagentTankType.Unspecified; +} + +[Serializable, NetSerializable] +public enum ReagentTankType : byte +{ + Unspecified, + Fuel +} diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index 1c24c860dd0..f16cf4a80fa 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -6,6 +6,7 @@ using Robust.Shared.Utility; using System.Collections; using System.Linq; +using Content.Shared.Chemistry.Components.SolutionManager; namespace Content.Shared.Chemistry.Components { @@ -48,13 +49,6 @@ public sealed partial class Solution : IEnumerable, ISerializat [DataField("canReact")] public bool CanReact { get; set; } = true; - /// - /// If reactions can occur via mixing. - /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("canMix")] - public bool CanMix { get; set; } = false; - /// /// Volume needed to fill this container. /// diff --git a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs index 44bfb583dd8..36ca791290a 100644 --- a/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/RehydratableSystem.cs @@ -34,7 +34,7 @@ private void OnSolutionChange(Entity ent, ref SolutionCon private void Expand(Entity ent) { if (_net.IsClient) - return; // no + return; var (uid, comp) = ent; diff --git a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs index 6c43c1d5f06..1620344652c 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedInjectorSystem.cs @@ -113,7 +113,7 @@ private void Toggle(Entity injector, EntityUid user) if (injector.Comp.InjectOnly) return; - if (!SolutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var solEnt, out var solution)) + if (!SolutionContainers.TryGetSolution(injector.Owner, injector.Comp.SolutionName, out var solEnt, out var solution)) return; string msg; diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs index 0d4912a504b..ce0cfab0021 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.Capabilities.cs @@ -78,31 +78,15 @@ public bool TryGetFitsInDispenser(Entity container, [NotNullWhen(true)] out Entity? solution) + public bool TryGetMixableSolution(Entity entity, [NotNullWhen(true)] out Entity? soln, [NotNullWhen(true)] out Solution? solution) { - var getMixableSolutionAttempt = new GetMixableSolutionAttemptEvent(container); - RaiseLocalEvent(container, ref getMixableSolutionAttempt); - if (getMixableSolutionAttempt.MixedSolution != null) - { - solution = getMixableSolutionAttempt.MixedSolution; - return true; - } - - if (!Resolve(container, ref container.Comp, false)) + if (!Resolve(entity, ref entity.Comp1, logMissing: false)) { - solution = default!; + (soln, solution) = (default!, null); return false; } - var tryGetSolution = EnumerateSolutions(container).FirstOrNull(x => x.Solution.Comp.Solution.CanMix); - if (tryGetSolution.HasValue) - { - solution = tryGetSolution.Value.Solution; - return true; - } - - solution = default!; - return false; + return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution); } #endregion Solution Accessors diff --git a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs index e74c1463804..fdb2f550f96 100644 --- a/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SharedSolutionContainerSystem.cs @@ -11,10 +11,13 @@ using Robust.Shared.Utility; using System.Diagnostics.CodeAnalysis; using System.Linq; +using System.Numerics; using System.Runtime.CompilerServices; using System.Text; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; +using Robust.Shared.Map; +using Robust.Shared.Network; using Dependency = Robust.Shared.IoC.DependencyAttribute; namespace Content.Shared.Chemistry.EntitySystems; @@ -58,6 +61,7 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem [Dependency] protected readonly SharedHandsSystem Hands = default!; [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!; [Dependency] protected readonly MetaDataSystem MetaData = default!; + [Dependency] protected readonly INetManager NetManager = default!; public override void Initialize() { @@ -66,13 +70,18 @@ public override void Initialize() InitializeRelays(); SubscribeLocalEvent(OnComponentInit); - SubscribeLocalEvent(OnComponentStartup); - SubscribeLocalEvent(OnComponentShutdown); - - SubscribeLocalEvent(OnComponentInit); - + SubscribeLocalEvent(OnSolutionStartup); + SubscribeLocalEvent(OnSolutionShutdown); + SubscribeLocalEvent(OnContainerManagerInit); SubscribeLocalEvent(OnExamineSolution); SubscribeLocalEvent>(OnSolutionExaminableVerb); + SubscribeLocalEvent(OnMapInit); + + if (NetManager.IsServer) + { + SubscribeLocalEvent(OnContainerManagerShutdown); + SubscribeLocalEvent(OnContainedSolutionShutdown); + } } @@ -121,8 +130,14 @@ public bool ResolveSolution(Entity container /// The name of the solution entity to fetch. /// Returns the solution entity that was fetched. /// Returns the solution state of the solution entity that was fetched. + /// /// Should we print an error if the solution specified by name is missing /// - public bool TryGetSolution(Entity container, string? name, [NotNullWhen(true)] out Entity? entity, [NotNullWhen(true)] out Solution? solution) + public bool TryGetSolution( + Entity container, + string? name, + [NotNullWhen(true)] out Entity? entity, + [NotNullWhen(true)] out Solution? solution, + bool errorOnMissing = false) { if (!TryGetSolution(container, name, out entity)) { @@ -135,7 +150,11 @@ public bool TryGetSolution(Entity container, } /// - public bool TryGetSolution(Entity container, string? name, [NotNullWhen(true)] out Entity? entity) + public bool TryGetSolution( + Entity container, + string? name, + [NotNullWhen(true)] out Entity? entity, + bool errorOnMissing = false) { if (TryComp(container, out BlockSolutionAccessComponent? blocker)) { @@ -155,12 +174,18 @@ solutionSlot.ContainedEntity is { } containedSolution else { entity = null; + if (!errorOnMissing) + return false; + Log.Error($"{ToPrettyString(container)} does not have a solution with ID: {name}"); return false; } if (!TryComp(uid, out SolutionComponent? comp)) { entity = null; + if (!errorOnMissing) + return false; + Log.Error($"{ToPrettyString(container)} does not have a solution with ID: {name}"); return false; } @@ -171,13 +196,18 @@ solutionSlot.ContainedEntity is { } containedSolution /// /// Version of TryGetSolution that doesn't take or return an entity. /// Used for prototypes and with old code parity. - public bool TryGetSolution(SolutionContainerManagerComponent container, string name, [NotNullWhen(true)] out Solution? solution) + public bool TryGetSolution(SolutionContainerManagerComponent container, + string name, + [NotNullWhen(true)] out Solution? solution, + bool errorOnMissing = false) { solution = null; - if (container.Solutions == null) + if (container.Solutions != null) + return container.Solutions.TryGetValue(name, out solution); + if (!errorOnMissing) return false; - - return container.Solutions.TryGetValue(name, out solution); + Log.Error($"{container} does not have a solution with ID: {name}"); + return false; } public IEnumerable<(string? Name, Entity Solution)> EnumerateSolutions(Entity container, bool includeSelf = true) @@ -703,17 +733,17 @@ private void OnComponentInit(Entity entity, ref ComponentInit entity.Comp.Solution.ValidateSolution(); } - private void OnComponentStartup(Entity entity, ref ComponentStartup args) + private void OnSolutionStartup(Entity entity, ref ComponentStartup args) { UpdateChemicals(entity); } - private void OnComponentShutdown(Entity entity, ref ComponentShutdown args) + private void OnSolutionShutdown(Entity entity, ref ComponentShutdown args) { RemoveAllSolution(entity); } - private void OnComponentInit(Entity entity, ref ComponentInit args) + private void OnContainerManagerInit(Entity entity, ref ComponentInit args) { if (entity.Comp.Containers is not { Count: > 0 } containers) return; @@ -733,7 +763,7 @@ private void OnExamineSolution(Entity entity, ref E return; } - if (!CanSeeHiddenSolution(entity,args.Examiner)) + if (!CanSeeHiddenSolution(entity, args.Examiner)) return; var primaryReagent = solution.GetPrimaryReagentId(); @@ -832,7 +862,7 @@ private void OnSolutionExaminableVerb(Entity entity return; } - if (!CanSeeHiddenSolution(entity,args.User)) + if (!CanSeeHiddenSolution(entity, args.User)) return; var target = args.Target; @@ -881,6 +911,9 @@ private FormattedMessage GetSolutionExamine(Solution solution) , ("amount", quantity))); } + msg.PushNewline(); + msg.AddMarkup(Loc.GetString("scannable-solution-temperature", ("temperature", Math.Round(solution.Temperature)))); + return msg; } @@ -901,5 +934,273 @@ private bool CanSeeHiddenSolution(Entity entity, En return true; } + private void OnMapInit(Entity entity, ref MapInitEvent args) + { + EnsureAllSolutions(entity); + } + + private void OnContainerManagerShutdown(Entity entity, ref ComponentShutdown args) + { + foreach (var name in entity.Comp.Containers) + { + if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer)) + ContainerSystem.ShutdownContainer(solutionContainer); + } + entity.Comp.Containers.Clear(); + } + + private void OnContainedSolutionShutdown(Entity entity, ref ComponentShutdown args) + { + if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container)) + { + container.Containers.Remove(entity.Comp.ContainerName); + Dirty(entity.Comp.Container, container); + } + + if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer)) + ContainerSystem.ShutdownContainer(solutionContainer); + } + #endregion Event Handlers + + public bool EnsureSolution( + Entity entity, + string name, + [NotNullWhen(true)]out Solution? solution, + FixedPoint2 maxVol = default) + { + return EnsureSolution(entity, name, maxVol, null, out _, out solution); + } + + public bool EnsureSolution( + Entity entity, + string name, + out bool existed, + [NotNullWhen(true)]out Solution? solution, + FixedPoint2 maxVol = default) + { + return EnsureSolution(entity, name, maxVol, null, out existed, out solution); + } + + public bool EnsureSolution( + Entity entity, + string name, + FixedPoint2 maxVol, + Solution? prototype, + out bool existed, + [NotNullWhen(true)] out Solution? solution) + { + solution = null; + existed = false; + + var (uid, meta) = entity; + if (!Resolve(uid, ref meta)) + throw new InvalidOperationException("Attempted to ensure solution on invalid entity."); + var manager = EnsureComp(uid); + if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized) + { + EnsureSolutionEntity((uid, manager), name, out existed, + out var solEnt, maxVol, prototype); + solution = solEnt!.Value.Comp.Solution; + return true; + } + solution = EnsureSolutionPrototype((uid, manager), name, maxVol, prototype, out existed); + return true; + } + + public void EnsureAllSolutions(Entity entity) + { + if (NetManager.IsClient) + return; + + if (entity.Comp.Solutions is not { } prototypes) + return; + + foreach (var (name, prototype) in prototypes) + { + EnsureSolutionEntity((entity.Owner, entity.Comp), name, out _, out _, prototype.MaxVolume, prototype); + } + + entity.Comp.Solutions = null; + Dirty(entity); + } + + public bool EnsureSolutionEntity( + Entity entity, + string name, + [NotNullWhen(true)] out Entity? solutionEntity, + FixedPoint2 maxVol = default) => + EnsureSolutionEntity(entity, name, out _, out solutionEntity, maxVol); + + public bool EnsureSolutionEntity( + Entity entity, + string name, + out bool existed, + [NotNullWhen(true)] out Entity? solutionEntity, + FixedPoint2 maxVol = default, + Solution? prototype = null + ) + { + existed = true; + solutionEntity = null; + + var (uid, container) = entity; + + var solutionSlot = ContainerSystem.EnsureContainer(uid, $"solution@{name}", out existed); + if (!Resolve(uid, ref container, logMissing: false)) + { + existed = false; + container = AddComp(uid); + container.Containers.Add(name); + if (NetManager.IsClient) + return false; + } + else if (!existed) + { + container.Containers.Add(name); + Dirty(uid, container); + } + + var needsInit = false; + SolutionComponent solutionComp; + if (solutionSlot.ContainedEntity is not { } solutionId) + { + if (NetManager.IsClient) + return false; + prototype ??= new() { MaxVolume = maxVol }; + prototype.Name = name; + (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, maxVol, prototype); + existed = false; + needsInit = true; + Dirty(uid, container); + } + else + { + solutionComp = Comp(solutionId); + DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name); + DebugTools.Assert(solutionComp.Solution.Name == name); + + var solution = solutionComp.Solution; + solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol); + + // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions. + // We want the reagents from the prototype to exist even if something else already created the solution. + if (prototype is { Volume.Value: > 0 }) + solution.AddSolution(prototype, PrototypeManager); + + Dirty(solutionId, solutionComp); + } + + if (needsInit) + EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID); + solutionEntity = (solutionId, solutionComp); + return true; + } + + private Solution EnsureSolutionPrototype(Entity entity, string name, FixedPoint2 maxVol, Solution? prototype, out bool existed) + { + existed = true; + + var (uid, container) = entity; + if (!Resolve(uid, ref container, logMissing: false)) + { + container = AddComp(uid); + existed = false; + } + + if (container.Solutions is null) + container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity); + + if (!container.Solutions.TryGetValue(name, out var solution)) + { + solution = prototype ?? new() { Name = name, MaxVolume = maxVol }; + container.Solutions.Add(name, solution); + existed = false; + } + else + solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, maxVol); + + Dirty(uid, container); + return solution; + } + + private Entity SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 maxVol, Solution prototype) + { + var coords = new EntityCoordinates(container.Owner, Vector2.Zero); + var uid = EntityManager.CreateEntityUninitialized(null, coords, null); + + var solution = new SolutionComponent() { Solution = prototype }; + AddComp(uid, solution); + + var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name }; + AddComp(uid, relation); + + MetaData.SetEntityName(uid, $"solution - {name}"); + ContainerSystem.Insert(uid, container, force: true); + + return (uid, solution, relation); + } + + public void AdjustDissolvedReagent( + Entity dissolvedSolution, + FixedPoint2 volume, + ReagentId reagent, + float concentrationChange) + { + if (concentrationChange == 0) + return; + var dissolvedSol = dissolvedSolution.Comp.Solution; + var amtChange = + GetReagentQuantityFromConcentration(dissolvedSolution, volume, MathF.Abs(concentrationChange)); + if (concentrationChange > 0) + { + dissolvedSol.AddReagent(reagent, amtChange); + } + else + { + dissolvedSol.RemoveReagent(reagent,amtChange); + } + UpdateChemicals(dissolvedSolution); + } + + public FixedPoint2 GetReagentQuantityFromConcentration(Entity dissolvedSolution, + FixedPoint2 volume,float concentration) + { + var dissolvedSol = dissolvedSolution.Comp.Solution; + if (volume == 0 + || dissolvedSol.Volume == 0) + return 0; + return concentration * volume; + } + + public float GetReagentConcentration(Entity dissolvedSolution, + FixedPoint2 volume, ReagentId dissolvedReagent) + { + var dissolvedSol = dissolvedSolution.Comp.Solution; + if (volume == 0 + || dissolvedSol.Volume == 0 + || !dissolvedSol.TryGetReagentQuantity(dissolvedReagent, out var dissolvedVol)) + return 0; + return (float)dissolvedVol / volume.Float(); + } + + public FixedPoint2 ClampReagentAmountByConcentration( + Entity dissolvedSolution, + FixedPoint2 volume, + ReagentId dissolvedReagent, + FixedPoint2 dissolvedReagentAmount, + float maxConcentration = 1f) + { + var dissolvedSol = dissolvedSolution.Comp.Solution; + if (volume == 0 + || dissolvedSol.Volume == 0 + || !dissolvedSol.TryGetReagentQuantity(dissolvedReagent, out var dissolvedVol)) + return 0; + volume *= maxConcentration; + dissolvedVol += dissolvedReagentAmount; + var overflow = volume - dissolvedVol; + if (overflow < 0) + dissolvedReagentAmount += overflow; + return dissolvedReagentAmount; + } } diff --git a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs index 34a64d0edbd..3bea79d3451 100644 --- a/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs +++ b/Content.Shared/Chemistry/EntitySystems/SolutionTransferSystem.cs @@ -42,7 +42,7 @@ private void OnTransferAmountSetValueMessage(Entity e var newTransferAmount = FixedPoint2.Clamp(message.Value, ent.Comp.MinimumTransferAmount, ent.Comp.MaximumTransferAmount); ent.Comp.TransferAmount = newTransferAmount; - if (message.Session.AttachedEntity is { Valid: true } user) + if (message.Actor is { Valid: true } user) _popup.PopupClient(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), ent, user); } @@ -53,10 +53,9 @@ private void AddSetTransferVerbs(Entity ent, ref GetV if (!args.CanAccess || !args.CanInteract || !comp.CanChangeTransferAmount || args.Hands == null) return; - if (!TryComp(args.User, out var actor)) - return; - // Custom transfer verb + var @event = args; + args.Verbs.Add(new AlternativeVerb() { Text = Loc.GetString("comp-solution-transfer-verb-custom-amount"), @@ -64,8 +63,7 @@ private void AddSetTransferVerbs(Entity ent, ref GetV // TODO: remove server check when bui prediction is a thing Act = () => { - if (_net.IsServer) - _ui.TryOpen(uid, TransferAmountUiKey.Key, actor.PlayerSession); + _ui.OpenUi(uid, TransferAmountUiKey.Key, @event.User); }, Priority = 1 }); diff --git a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs index ede73c49690..118f2240610 100644 --- a/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs +++ b/Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs @@ -25,6 +25,3 @@ public sealed partial class ReactionMixerComponent : Component public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false); public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer); - -[ByRefEvent] -public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Entity? MixedSolution = null); diff --git a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs index 5d6d9d21208..df1b1aa20b4 100644 --- a/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs +++ b/Content.Shared/Chemistry/Reagent/ReagentPrototype.cs @@ -104,6 +104,13 @@ public sealed partial class ReagentPrototype : IPrototype, IInheritingPrototype [DataField] public bool Slippery; + /// + /// How easily this reagent becomes fizzy when aggitated. + /// 0 - completely flat, 1 - fizzes up when nudged. + /// + [DataField] + public float Fizziness; + /// /// How much reagent slows entities down if it's part of a puddle. /// 0 - no slowdown; 1 - can't move. diff --git a/Content.Shared/Chemistry/SharedReagentDispenser.cs b/Content.Shared/Chemistry/SharedReagentDispenser.cs index 2b9c318c58d..5de3f6cae35 100644 --- a/Content.Shared/Chemistry/SharedReagentDispenser.cs +++ b/Content.Shared/Chemistry/SharedReagentDispenser.cs @@ -20,6 +20,46 @@ public ReagentDispenserSetDispenseAmountMessage(ReagentDispenserDispenseAmount a { ReagentDispenserDispenseAmount = amount; } + + /// + /// Create a new instance from interpreting a String as an integer, + /// throwing an exception if it is unable to parse. + /// + public ReagentDispenserSetDispenseAmountMessage(String s) + { + switch (s) + { + case "1": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U1; + break; + case "5": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U5; + break; + case "10": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U10; + break; + case "15": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U15; + break; + case "20": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U20; + break; + case "25": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U25; + break; + case "30": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U30; + break; + case "50": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U50; + break; + case "100": + ReagentDispenserDispenseAmount = ReagentDispenserDispenseAmount.U100; + break; + default: + throw new Exception($"Cannot convert the string `{s}` into a valid ReagentDispenser DispenseAmount"); + } + } } [Serializable, NetSerializable] @@ -52,20 +92,30 @@ public enum ReagentDispenserDispenseAmount U100 = 100, } + [Serializable, NetSerializable] + public sealed class ReagentInventoryItem(string storageSlotId, string reagentLabel, string storedAmount, Color reagentColor) + { + public string StorageSlotId = storageSlotId; + public string ReagentLabel = reagentLabel; + public string StoredAmount = storedAmount; + public Color ReagentColor = reagentColor; + } + [Serializable, NetSerializable] public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState { public readonly ContainerInfo? OutputContainer; public readonly NetEntity? OutputContainerEntity; + /// /// A list of the reagents which this dispenser can dispense. /// - public readonly List>> Inventory; + public readonly List Inventory; public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount; - public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List>> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount) + public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List inventory, ReagentDispenserDispenseAmount selectedDispenseAmount) { OutputContainer = outputContainer; OutputContainerEntity = outputContainerEntity; diff --git a/Content.Shared/Climbing/Systems/BonkSystem.cs b/Content.Shared/Climbing/Systems/BonkSystem.cs index 08ca63368a8..c7c89a3b7fa 100644 --- a/Content.Shared/Climbing/Systems/BonkSystem.cs +++ b/Content.Shared/Climbing/Systems/BonkSystem.cs @@ -108,17 +108,16 @@ private bool TryStartBonk(EntityUid uid, EntityUid user, EntityUid climber, Bonk { BreakOnTargetMove = true, BreakOnUserMove = true, - BreakOnDamage = true + BreakOnDamage = true, + DuplicateCondition = DuplicateConditions.SameTool | DuplicateConditions.SameTarget }; - _doAfter.TryStartDoAfter(doAfterArgs); - - return true; + return _doAfter.TryStartDoAfter(doAfterArgs); } - private void OnAttemptClimb(EntityUid uid, BonkableComponent component, AttemptClimbEvent args) + private void OnAttemptClimb(EntityUid uid, BonkableComponent component, ref AttemptClimbEvent args) { - if (args.Cancelled || !HasComp(args.Climber) || !HasComp(args.User)) + if (args.Cancelled) return; if (TryStartBonk(uid, args.User, args.Climber, component)) diff --git a/Content.Shared/Climbing/Systems/ClimbSystem.cs b/Content.Shared/Climbing/Systems/ClimbSystem.cs index 521f5ace99d..e3c494e955b 100644 --- a/Content.Shared/Climbing/Systems/ClimbSystem.cs +++ b/Content.Shared/Climbing/Systems/ClimbSystem.cs @@ -228,7 +228,8 @@ public bool TryClimb( { BreakOnTargetMove = true, BreakOnUserMove = true, - BreakOnDamage = true + BreakOnDamage = true, + DuplicateCondition = DuplicateConditions.SameTool | DuplicateConditions.SameTarget }; _audio.PlayPredicted(comp.StartClimbSound, climbable, user); diff --git a/Content.Shared/Clothing/ClothingEvents.cs b/Content.Shared/Clothing/ClothingEvents.cs index 1dcce2402ae..83afea45973 100644 --- a/Content.Shared/Clothing/ClothingEvents.cs +++ b/Content.Shared/Clothing/ClothingEvents.cs @@ -1,5 +1,6 @@ using Content.Shared.Actions; +using Content.Shared.Clothing.Components; namespace Content.Shared.Clothing; @@ -71,3 +72,31 @@ public sealed partial class ToggleMaskEvent : InstantActionEvent { } /// [ByRefEvent] public readonly record struct WearerMaskToggledEvent(bool IsToggled); + +/// +/// Raised on the clothing entity when it is equipped to a valid slot, +/// as determined by . +/// +[ByRefEvent] +public readonly record struct ClothingGotEquippedEvent(EntityUid Wearer, ClothingComponent Clothing); + +/// +/// Raised on the clothing entity when it is unequipped from a valid slot, +/// as determined by . +/// +[ByRefEvent] +public readonly record struct ClothingGotUnequippedEvent(EntityUid Wearer, ClothingComponent Clothing); + +/// +/// Raised on an entity when they equip a clothing item to a valid slot, +/// as determined by . +/// +[ByRefEvent] +public readonly record struct ClothingDidEquippedEvent(Entity Clothing); + +/// +/// Raised on an entity when they unequip a clothing item from a valid slot, +/// as determined by . +/// +[ByRefEvent] +public readonly record struct ClothingDidUnequippedEvent(Entity Clothing); diff --git a/Content.Shared/Clothing/Components/ClothingComponent.cs b/Content.Shared/Clothing/Components/ClothingComponent.cs index 0f4c7f68bfc..6d7226e767d 100644 --- a/Content.Shared/Clothing/Components/ClothingComponent.cs +++ b/Content.Shared/Clothing/Components/ClothingComponent.cs @@ -66,6 +66,9 @@ public sealed partial class ClothingComponent : Component [DataField("unisexMask")] public ClothingMask UnisexMask = ClothingMask.UniformFull; + /// + /// Name of the inventory slot the clothing is in. + /// public string? InSlot; [DataField, ViewVariables(VVAccess.ReadWrite)] diff --git a/Content.Shared/Clothing/Components/FireProtectionComponent.cs b/Content.Shared/Clothing/Components/FireProtectionComponent.cs new file mode 100644 index 00000000000..cafa6e5359e --- /dev/null +++ b/Content.Shared/Clothing/Components/FireProtectionComponent.cs @@ -0,0 +1,17 @@ +using Content.Shared.Clothing.EntitySystems; + +namespace Content.Shared.Clothing.Components; + +/// +/// Makes this clothing reduce fire damage when worn. +/// +[RegisterComponent, Access(typeof(FireProtectionSystem))] +public sealed partial class FireProtectionComponent : Component +{ + /// + /// Percentage to reduce fire damage by, subtracted not multiplicative. + /// 0.25 means 25% less fire damage. + /// + [DataField(required: true)] + public float Reduction; +} diff --git a/Content.Shared/Clothing/Components/HideLayerClothingComponent.cs b/Content.Shared/Clothing/Components/HideLayerClothingComponent.cs new file mode 100644 index 00000000000..ac3d9b97896 --- /dev/null +++ b/Content.Shared/Clothing/Components/HideLayerClothingComponent.cs @@ -0,0 +1,24 @@ +using Content.Shared.Humanoid; +using Robust.Shared.GameStates; + +namespace Content.Shared.Clothing.Components; + +/// +/// This is used for a clothing item that hides an appearance layer. +/// The entity's HumanoidAppearance component must have the corresponding hideLayerOnEquip value. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class HideLayerClothingComponent : Component +{ + /// + /// The appearance layer to hide. + /// + [DataField] + public HashSet Slots = new(); + + /// + /// If true, the layer will only hide when the item is in a toggled state (e.g. masks) + /// + [DataField] + public bool HideOnToggle = false; +} diff --git a/Content.Shared/Clothing/Components/LoadoutComponent.cs b/Content.Shared/Clothing/Components/LoadoutComponent.cs index a3c6efe2a0b..612286e6e69 100644 --- a/Content.Shared/Clothing/Components/LoadoutComponent.cs +++ b/Content.Shared/Clothing/Components/LoadoutComponent.cs @@ -1,16 +1,15 @@ using Content.Shared.Roles; using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; +using Robust.Shared.Prototypes; namespace Content.Shared.Clothing.Components; [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class LoadoutComponent : Component { - /// /// A list of starting gears, of which one will be given. /// All elements are weighted the same in the list. - /// - [DataField("prototypes", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer)), AutoNetworkedField] - public List? Prototypes; + [DataField("prototypes")] + [AutoNetworkedField] + public List>? StartingGear; } diff --git a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs index b407b867f74..9e3f917e96f 100644 --- a/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/ClothingSystem.cs @@ -6,31 +6,18 @@ using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Content.Shared.Item; -using Content.Shared.Tag; -using Robust.Shared.GameStates; -using System.Linq; using Robust.Shared.Containers; +using Robust.Shared.GameStates; namespace Content.Shared.Clothing.EntitySystems; public abstract class ClothingSystem : EntitySystem { [Dependency] private readonly SharedItemSystem _itemSys = default!; + [Dependency] private readonly SharedContainerSystem _containerSys = default!; [Dependency] private readonly SharedHumanoidAppearanceSystem _humanoidSystem = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; [Dependency] private readonly InventorySystem _invSystem = default!; [Dependency] private readonly SharedHandsSystem _handsSystem = default!; - [Dependency] private readonly SharedContainerSystem _containerSys = default!; - - [ValidatePrototypeId] - private const string HairTag = "HidesHair"; - - [ValidatePrototypeId] - private const string NoseTag = "HidesNose"; - - [ValidatePrototypeId] - - private const string BeardTag = "HidesBeard"; public override void Initialize() { @@ -101,61 +88,71 @@ private void QuickEquip( } } - private void ToggleVisualLayer(EntityUid equipee, HumanoidVisualLayers layer, string tag) + private void ToggleVisualLayers(EntityUid equipee, HashSet layers, HashSet appearanceLayers) { - InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee, SlotFlags.HEAD ^ SlotFlags.MASK); - bool shouldLayerShow = true; - - while (enumerator.NextItem(out EntityUid item)) + foreach (HumanoidVisualLayers layer in layers) { - if (_tagSystem.HasTag(item, tag)) + if (!appearanceLayers.Contains(layer)) + break; + + InventorySystem.InventorySlotEnumerator enumerator = _invSystem.GetSlotEnumerator(equipee); + + bool shouldLayerShow = true; + while (enumerator.NextItem(out EntityUid item)) { - if (tag == NoseTag || tag == BeardTag) // Special check for NoseTag or BeardTag, due to masks being toggleable + if (TryComp(item, out HideLayerClothingComponent? comp)) { - if (TryComp(item, out MaskComponent? mask) && TryComp(item, out ClothingComponent? clothing)) + if (comp.Slots.Contains(layer)) { - if (clothing.EquippedPrefix != mask.EquippedPrefix) + //Checks for mask toggling. TODO: Make a generic system for this + if (comp.HideOnToggle && TryComp(item, out MaskComponent? mask) && TryComp(item, out ClothingComponent? clothing)) + { + if (clothing.EquippedPrefix != mask.EquippedPrefix) + { + shouldLayerShow = false; + break; + } + } + else { shouldLayerShow = false; break; } } - else - { - shouldLayerShow = false; - break; - } - } - else - { - shouldLayerShow = false; - break; } } + _humanoidSystem.SetLayerVisibility(equipee, layer, shouldLayerShow); } - _humanoidSystem.SetLayerVisibility(equipee, layer, shouldLayerShow); } protected virtual void OnGotEquipped(EntityUid uid, ClothingComponent component, GotEquippedEvent args) { component.InSlot = args.Slot; - if ((new string[] { "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, HairTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Hair, HairTag); - if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, NoseTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Snout, NoseTag); - if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, BeardTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.FacialHair, BeardTag); + CheckEquipmentForLayerHide(args.Equipment, args.Equipee); + + if ((component.Slots & args.SlotFlags) != SlotFlags.NONE) + { + var gotEquippedEvent = new ClothingGotEquippedEvent(args.Equipee, component); + RaiseLocalEvent(uid, ref gotEquippedEvent); + + var didEquippedEvent = new ClothingDidEquippedEvent((uid, component)); + RaiseLocalEvent(args.Equipee, ref didEquippedEvent); + } } protected virtual void OnGotUnequipped(EntityUid uid, ClothingComponent component, GotUnequippedEvent args) { + if ((component.Slots & args.SlotFlags) != SlotFlags.NONE) + { + var gotUnequippedEvent = new ClothingGotUnequippedEvent(args.Equipee, component); + RaiseLocalEvent(uid, ref gotUnequippedEvent); + + var didUnequippedEvent = new ClothingDidUnequippedEvent((uid, component)); + RaiseLocalEvent(args.Equipee, ref didUnequippedEvent); + } + component.InSlot = null; - if ((new string[] { "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, HairTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Hair, HairTag); - if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, NoseTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.Snout, NoseTag); - if ((new string[] { "mask", "head" }).Contains(args.Slot) && _tagSystem.HasTag(args.Equipment, BeardTag)) - ToggleVisualLayer(args.Equipee, HumanoidVisualLayers.FacialHair, BeardTag); + CheckEquipmentForLayerHide(args.Equipment, args.Equipee); } private void OnGetState(EntityUid uid, ClothingComponent component, ref ComponentGetState args) @@ -166,15 +163,20 @@ private void OnGetState(EntityUid uid, ClothingComponent component, ref Componen private void OnHandleState(EntityUid uid, ClothingComponent component, ref ComponentHandleState args) { if (args.Current is ClothingComponentState state) + { SetEquippedPrefix(uid, state.EquippedPrefix, component); + if (component.InSlot != null && _containerSys.TryGetContainingContainer(uid, out var container)) + { + CheckEquipmentForLayerHide(uid, container.Owner); + } + } } private void OnMaskToggled(Entity ent, ref ItemMaskToggledEvent args) { //TODO: sprites for 'pulled down' state. defaults to invisible due to no sprite with this prefix SetEquippedPrefix(ent, args.IsToggled ? args.equippedPrefix : null, ent); - ToggleVisualLayer(args.Wearer, HumanoidVisualLayers.Snout, NoseTag); - ToggleVisualLayer(args.Wearer, HumanoidVisualLayers.FacialHair, BeardTag); + CheckEquipmentForLayerHide(ent.Owner, args.Wearer); } private void OnPickedUp(Entity ent, ref GettingPickedUpAttemptEvent args) @@ -205,6 +207,12 @@ private void OnUnequipDoAfter(Entity ent, ref ClothingUnequip _handsSystem.TryPickup(args.User, ent); } + private void CheckEquipmentForLayerHide(EntityUid equipment, EntityUid equipee) + { + if (TryComp(equipment, out HideLayerClothingComponent? clothesComp) && TryComp(equipee, out HumanoidAppearanceComponent? appearanceComp)) + ToggleVisualLayers(equipee, clothesComp.Slots, appearanceComp.HideLayersOnEquip); + } + #region Public API public void SetEquippedPrefix(EntityUid uid, string? prefix, ClothingComponent? clothing = null) diff --git a/Content.Shared/Clothing/EntitySystems/FireProtectionSystem.cs b/Content.Shared/Clothing/EntitySystems/FireProtectionSystem.cs new file mode 100644 index 00000000000..6f80bc05882 --- /dev/null +++ b/Content.Shared/Clothing/EntitySystems/FireProtectionSystem.cs @@ -0,0 +1,23 @@ +using Content.Shared.Atmos; +using Content.Shared.Clothing.Components; +using Content.Shared.Inventory; + +namespace Content.Shared.Clothing.EntitySystems; + +/// +/// Handles reducing fire damage when wearing clothing with . +/// +public sealed class FireProtectionSystem : EntitySystem +{ + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetProtection); + } + + private void OnGetProtection(Entity ent, ref InventoryRelayedEvent args) + { + args.Args.Reduce(ent.Comp.Reduction); + } +} diff --git a/Content.Shared/Clothing/EntitySystems/MaskSystem.cs b/Content.Shared/Clothing/EntitySystems/MaskSystem.cs index aab2a172dc1..2a4383279a5 100644 --- a/Content.Shared/Clothing/EntitySystems/MaskSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/MaskSystem.cs @@ -42,12 +42,10 @@ private void OnToggleMask(Entity ent, ref ToggleMaskEvent args) return; mask.IsToggled ^= true; - _actionSystem.SetToggled(mask.ToggleActionEntity, mask.IsToggled); - if (mask.IsToggled) - _popupSystem.PopupEntity(Loc.GetString("action-mask-pull-down-popup-message", ("mask", uid)), args.Performer, args.Performer); - else - _popupSystem.PopupEntity(Loc.GetString("action-mask-pull-up-popup-message", ("mask", uid)), args.Performer, args.Performer); + var dir = mask.IsToggled ? "down" : "up"; + var msg = $"action-mask-pull-{dir}-popup-message"; + _popupSystem.PopupClient(Loc.GetString(msg, ("mask", uid)), args.Performer, args.Performer); ToggleMaskComponents(uid, mask, args.Performer, mask.EquippedPrefix); } @@ -55,18 +53,22 @@ private void OnToggleMask(Entity ent, ref ToggleMaskEvent args) // set to untoggled when unequipped, so it isn't left in a 'pulled down' state private void OnGotUnequipped(EntityUid uid, MaskComponent mask, GotUnequippedEvent args) { - if (mask.ToggleActionEntity == null) + if (!mask.IsToggled) return; mask.IsToggled = false; - Dirty(uid, mask); - _actionSystem.SetToggled(mask.ToggleActionEntity, mask.IsToggled); - ToggleMaskComponents(uid, mask, args.Equipee, mask.EquippedPrefix, true); } + /// + /// Called after setting IsToggled, raises events and dirties. + /// private void ToggleMaskComponents(EntityUid uid, MaskComponent mask, EntityUid wearer, string? equippedPrefix = null, bool isEquip = false) { + Dirty(uid, mask); + if (mask.ToggleActionEntity is {} action) + _actionSystem.SetToggled(action, mask.IsToggled); + var maskEv = new ItemMaskToggledEvent(wearer, equippedPrefix, mask.IsToggled, isEquip); RaiseLocalEvent(uid, ref maskEv); diff --git a/Content.Shared/Clothing/EntitySystems/SkatesSystem.cs b/Content.Shared/Clothing/EntitySystems/SkatesSystem.cs index 7d748a67a45..bbb640bd986 100644 --- a/Content.Shared/Clothing/EntitySystems/SkatesSystem.cs +++ b/Content.Shared/Clothing/EntitySystems/SkatesSystem.cs @@ -17,34 +17,28 @@ public override void Initialize() { base.Initialize(); - SubscribeLocalEvent(OnGotEquipped); - SubscribeLocalEvent(OnGotUnequipped); + SubscribeLocalEvent(OnGotEquipped); + SubscribeLocalEvent(OnGotUnequipped); } /// /// When item is unequipped from the shoe slot, friction, aceleration and collide on impact return to default settings. /// - public void OnGotUnequipped(EntityUid uid, SkatesComponent component, GotUnequippedEvent args) + public void OnGotUnequipped(EntityUid uid, SkatesComponent component, ClothingGotUnequippedEvent args) { - if (!TryComp(args.Equipee, out MovementSpeedModifierComponent? speedModifier)) + if (!TryComp(args.Wearer, out MovementSpeedModifierComponent? speedModifier)) return; - if (args.Slot == "shoes") - { - _move.ChangeFriction(args.Equipee, MovementSpeedModifierComponent.DefaultFriction, MovementSpeedModifierComponent.DefaultFrictionNoInput, MovementSpeedModifierComponent.DefaultAcceleration, speedModifier); - _impact.ChangeCollide(args.Equipee, component.DefaultMinimumSpeed, component.DefaultStunSeconds, component.DefaultDamageCooldown, component.DefaultSpeedDamage); - } + _move.ChangeFriction(args.Wearer, MovementSpeedModifierComponent.DefaultFriction, MovementSpeedModifierComponent.DefaultFrictionNoInput, MovementSpeedModifierComponent.DefaultAcceleration, speedModifier); + _impact.ChangeCollide(args.Wearer, component.DefaultMinimumSpeed, component.DefaultStunSeconds, component.DefaultDamageCooldown, component.DefaultSpeedDamage); } /// /// When item is equipped into the shoe slot, friction, acceleration and collide on impact are adjusted. /// - private void OnGotEquipped(EntityUid uid, SkatesComponent component, GotEquippedEvent args) + private void OnGotEquipped(EntityUid uid, SkatesComponent component, ClothingGotEquippedEvent args) { - if (args.Slot == "shoes") - { - _move.ChangeFriction(args.Equipee, component.Friction, component.FrictionNoInput, component.Acceleration); - _impact.ChangeCollide(args.Equipee, component.MinimumSpeed, component.StunSeconds, component.DamageCooldown, component.SpeedDamage); - } + _move.ChangeFriction(args.Wearer, component.Friction, component.FrictionNoInput, component.Acceleration); + _impact.ChangeCollide(args.Wearer, component.MinimumSpeed, component.StunSeconds, component.DamageCooldown, component.SpeedDamage); } } diff --git a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutCategoryPrototype.cs b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutCategoryPrototype.cs index 26567d0c13b..2d008e437d1 100644 --- a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutCategoryPrototype.cs +++ b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutCategoryPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.Clothing.Loadouts.Prototypes; /// A prototype defining a valid category for s to go into. /// [Prototype] -public sealed class LoadoutCategoryPrototype : IPrototype +public sealed partial class LoadoutCategoryPrototype : IPrototype { [IdDataField] public string ID { get; } = default!; diff --git a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs index 74cfa1d4e86..19c2bf59f1f 100644 --- a/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs +++ b/Content.Shared/Clothing/Loadouts/Prototypes/LoadoutPrototype.cs @@ -8,7 +8,7 @@ namespace Content.Shared.Clothing.Loadouts.Prototypes; [Prototype] -public sealed class LoadoutPrototype : IPrototype +public sealed partial class LoadoutPrototype : IPrototype { /// /// Formatted like "Loadout[Department/ShortHeadName][CommonClothingSlot][SimplifiedClothingId]", example: "LoadoutScienceOuterLabcoatSeniorResearcher" diff --git a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs index 5a2f1b2da90..0be25aaa8b4 100644 --- a/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs +++ b/Content.Shared/Clothing/Loadouts/Systems/LoadoutSystem.cs @@ -31,10 +31,7 @@ public override void Initialize() private void OnMapInit(EntityUid uid, LoadoutComponent component, MapInitEvent args) { - if (component.Prototypes == null) - return; - - var proto = _prototype.Index(_random.Pick(component.Prototypes)); + var proto = _prototype.Index(_random.Pick(component.StartingGear?? new())); _station.EquipStartingGear(uid, proto); } diff --git a/Content.Shared/Containers/ContainerFillComponent.cs b/Content.Shared/Containers/ContainerFillComponent.cs index 8c63cbc66af..7ce5fa88502 100644 --- a/Content.Shared/Containers/ContainerFillComponent.cs +++ b/Content.Shared/Containers/ContainerFillComponent.cs @@ -1,4 +1,5 @@ using Content.Shared.Storage; +using Content.Shared.Storage.Components; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.Manager; using Robust.Shared.Serialization.Markdown.Mapping; diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index c7932ef8f75..cb6b2a747bc 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -633,9 +633,9 @@ private void HandleButtonPressed(EntityUid uid, ItemSlotsComponent component, It return; if (args.TryEject && slot.HasItem) - TryEjectToHands(uid, slot, args.Session.AttachedEntity, false); - else if (args.TryInsert && !slot.HasItem && args.Session.AttachedEntity is EntityUid user) - TryInsertFromHand(uid, slot, user); + TryEjectToHands(uid, slot, args.Actor, true); + else if (args.TryInsert && !slot.HasItem) + TryInsertFromHand(uid, slot, args.Actor); } #endregion diff --git a/Content.Shared/Content.Shared.csproj b/Content.Shared/Content.Shared.csproj index 9752bfcfe2d..4cca399b28b 100644 --- a/Content.Shared/Content.Shared.csproj +++ b/Content.Shared/Content.Shared.csproj @@ -23,9 +23,6 @@ false - - - diff --git a/Content.Shared/CriminalRecords/Components/CriminalRecordsHackerComponent.cs b/Content.Shared/CriminalRecords/Components/CriminalRecordsHackerComponent.cs new file mode 100644 index 00000000000..189a387a5de --- /dev/null +++ b/Content.Shared/CriminalRecords/Components/CriminalRecordsHackerComponent.cs @@ -0,0 +1,31 @@ +using Content.Shared.CriminalRecords.Systems; +using Content.Shared.Dataset; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.CriminalRecords.Components; + +/// +/// Lets the user hack a criminal records console, once. +/// Everyone is set to wanted with a randomly picked reason. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedCriminalRecordsHackerSystem))] +public sealed partial class CriminalRecordsHackerComponent : Component +{ + /// + /// How long the doafter is for hacking it. + /// + public TimeSpan Delay = TimeSpan.FromSeconds(20); + + /// + /// Dataset of random reasons to use. + /// + [DataField] + public ProtoId Reasons = "CriminalRecordsWantedReasonPlaceholders"; + + /// + /// Announcement made after the console is hacked. + /// + [DataField] + public LocId Announcement = "ninja-criminal-records-hack-announcement"; +} diff --git a/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsHackerSystem.cs b/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsHackerSystem.cs new file mode 100644 index 00000000000..a626db19e5f --- /dev/null +++ b/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsHackerSystem.cs @@ -0,0 +1,50 @@ +using Content.Shared.CriminalRecords.Components; +using Content.Shared.DoAfter; +using Content.Shared.Interaction; +using Content.Shared.Ninja.Systems; +using Robust.Shared.Serialization; + +namespace Content.Shared.CriminalRecords.Systems; + +public abstract class SharedCriminalRecordsHackerSystem : EntitySystem +{ + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedNinjaGlovesSystem _gloves = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnBeforeInteractHand); + } + + private void OnBeforeInteractHand(Entity ent, ref BeforeInteractHandEvent args) + { + // TODO: generic event + if (args.Handled || !_gloves.AbilityCheck(ent, args, out var target)) + return; + + if (!HasComp(target)) + return; + + var doAfterArgs = new DoAfterArgs(EntityManager, ent, ent.Comp.Delay, new CriminalRecordsHackDoAfterEvent(), target: target, used: ent, eventTarget: ent) + { + BreakOnDamage = true, + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnWeightlessMove = true, + MovementThreshold = 0.5f, + }; + + _doAfter.TryStartDoAfter(doAfterArgs); + args.Handled = true; + } +} + +/// +/// Raised on the user when the doafter completes. +/// +[Serializable, NetSerializable] +public sealed partial class CriminalRecordsHackDoAfterEvent : SimpleDoAfterEvent +{ +} diff --git a/Content.Shared/Damage/Prototypes/DamageGroupPrototype.cs b/Content.Shared/Damage/Prototypes/DamageGroupPrototype.cs index 807f143708c..bb5aea3a38c 100644 --- a/Content.Shared/Damage/Prototypes/DamageGroupPrototype.cs +++ b/Content.Shared/Damage/Prototypes/DamageGroupPrototype.cs @@ -17,6 +17,12 @@ public sealed partial class DamageGroupPrototype : IPrototype { [IdDataField] public string ID { get; } = default!; + [DataField(required: true)] + private LocId Name { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string LocalizedName => Loc.GetString(Name); + [DataField("damageTypes", required: true, customTypeSerializer: typeof(PrototypeIdListSerializer))] public List DamageTypes { get; private set; } = default!; } diff --git a/Content.Shared/Damage/Prototypes/DamageModifierSetPrototype.cs b/Content.Shared/Damage/Prototypes/DamageModifierSetPrototype.cs index 99e13ee2842..a50856b0448 100644 --- a/Content.Shared/Damage/Prototypes/DamageModifierSetPrototype.cs +++ b/Content.Shared/Damage/Prototypes/DamageModifierSetPrototype.cs @@ -10,7 +10,7 @@ namespace Content.Shared.Damage.Prototypes /// just want normal data to be deserialized. /// [Prototype("damageModifierSet")] - public sealed class DamageModifierSetPrototype : DamageModifierSet, IPrototype + public sealed partial class DamageModifierSetPrototype : DamageModifierSet, IPrototype { [ViewVariables] [IdDataField] diff --git a/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs b/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs index cde7a8617f5..a1ae23ef676 100644 --- a/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs +++ b/Content.Shared/Damage/Prototypes/DamageTypePrototype.cs @@ -11,6 +11,12 @@ public sealed partial class DamageTypePrototype : IPrototype [IdDataField] public string ID { get; private set; } = default!; + [DataField(required: true)] + private LocId Name { get; set; } + + [ViewVariables(VVAccess.ReadOnly)] + public string LocalizedName => Loc.GetString(Name); + /// /// The price for each 1% damage reduction in armors /// diff --git a/Content.Shared/Damage/Systems/DamageExamineSystem.cs b/Content.Shared/Damage/Systems/DamageExamineSystem.cs index 8273719110b..fd1f191334f 100644 --- a/Content.Shared/Damage/Systems/DamageExamineSystem.cs +++ b/Content.Shared/Damage/Systems/DamageExamineSystem.cs @@ -1,8 +1,10 @@ using Content.Shared.Damage.Components; using Content.Shared.Damage.Events; +using Content.Shared.Damage.Prototypes; using Content.Shared.Examine; using Content.Shared.FixedPoint; using Content.Shared.Verbs; +using Robust.Shared.Prototypes; using Robust.Shared.Utility; namespace Content.Shared.Damage.Systems; @@ -10,6 +12,7 @@ namespace Content.Shared.Damage.Systems; public sealed class DamageExamineSystem : EntitySystem { [Dependency] private readonly ExamineSystemShared _examine = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; public override void Initialize() { @@ -66,7 +69,7 @@ private FormattedMessage GetDamageExamine(DamageSpecifier damageSpecifier, strin if (damage.Value != FixedPoint2.Zero) { msg.PushNewline(); - msg.AddMarkup(Loc.GetString("damage-value", ("type", damage.Key), ("amount", damage.Value))); + msg.AddMarkup(Loc.GetString("damage-value", ("type", _prototype.Index(damage.Key).LocalizedName), ("amount", damage.Value))); } } diff --git a/Content.Shared/DeviceLinking/DevicePortPrototype.cs b/Content.Shared/DeviceLinking/DevicePortPrototype.cs index c0a419ee653..e3421dda9db 100644 --- a/Content.Shared/DeviceLinking/DevicePortPrototype.cs +++ b/Content.Shared/DeviceLinking/DevicePortPrototype.cs @@ -29,13 +29,13 @@ public abstract class DevicePortPrototype [Prototype("sinkPort")] [Serializable, NetSerializable] -public sealed class SinkPortPrototype : DevicePortPrototype, IPrototype +public sealed partial class SinkPortPrototype : DevicePortPrototype, IPrototype { } [Prototype("sourcePort")] [Serializable, NetSerializable] -public sealed class SourcePortPrototype : DevicePortPrototype, IPrototype +public sealed partial class SourcePortPrototype : DevicePortPrototype, IPrototype { /// /// This is a set of sink ports that this source port will attempt to link to when using the diff --git a/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs b/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs index 4aa9db199dc..53928f83a98 100644 --- a/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs +++ b/Content.Shared/DeviceNetwork/Systems/SharedNetworkConfiguratorSystem.cs @@ -1,10 +1,23 @@ using Content.Shared.Actions; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.UserInterface; using Robust.Shared.Serialization; namespace Content.Shared.DeviceNetwork.Systems; public abstract class SharedNetworkConfiguratorSystem : EntitySystem { + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnUiOpenAttempt); + } + + private void OnUiOpenAttempt(EntityUid uid, NetworkConfiguratorComponent configurator, ActivatableUIOpenAttemptEvent args) + { + if (configurator.LinkModeActive) + args.Cancel(); + } } public sealed partial class ClearAllOverlaysEvent : InstantActionEvent diff --git a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs index 4948cb6640e..36dd14f9b22 100644 --- a/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs +++ b/Content.Shared/Disposal/Components/SharedDisposalUnitComponent.cs @@ -36,13 +36,6 @@ public abstract partial class SharedDisposalUnitComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("soundInsert")] public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Effects/trashbag1.ogg"); - /// - /// Sound played when an item is thrown and misses the disposal unit. - /// - [ViewVariables(VVAccess.ReadWrite), DataField("soundMiss")] - public SoundSpecifier? MissSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg"); - - /// /// State for this disposals unit. /// diff --git a/Content.Shared/DoAfter/DoAfterEvent.cs b/Content.Shared/DoAfter/DoAfterEvent.cs index c01505f9b25..bc9abdab87b 100644 --- a/Content.Shared/DoAfter/DoAfterEvent.cs +++ b/Content.Shared/DoAfter/DoAfterEvent.cs @@ -73,7 +73,7 @@ public sealed partial class DoAfterAttemptEvent : CancellableEntityEvent public readonly DoAfter DoAfter; /// - /// The event that the DoAfter will raise after sucesfully finishing. Given that this event has the data + /// The event that the DoAfter will raise after successfully finishing. Given that this event has the data /// required to perform the interaction, it should also contain the data required to validate/attempt the /// interaction. /// diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs index abd8888f583..24b38417596 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.Update.cs @@ -101,6 +101,7 @@ private bool TryAttemptEvent(DoAfter doAfter) doAfter.AttemptEvent = _factory.CreateInstance(evType, new object[] { doAfter, args.Event }); } + args.Event.DoAfter = doAfter; if (args.EventTarget != null) RaiseLocalEvent(args.EventTarget.Value, doAfter.AttemptEvent, args.Broadcast); else diff --git a/Content.Shared/DoAfter/SharedDoAfterSystem.cs b/Content.Shared/DoAfter/SharedDoAfterSystem.cs index 3b0ba58f55a..81c8c4f3823 100644 --- a/Content.Shared/DoAfter/SharedDoAfterSystem.cs +++ b/Content.Shared/DoAfter/SharedDoAfterSystem.cs @@ -247,8 +247,9 @@ public bool TryStartDoAfter(DoAfterArgs args, [NotNullWhen(true)] out DoAfterId? if (args.AttemptFrequency == AttemptFrequency.StartAndEnd && !TryAttemptEvent(doAfter)) return false; - if (args.Delay <= TimeSpan.Zero || - _tag.HasTag(args.User, "InstantDoAfters")) + // TODO DO AFTER + // Why does this tag exist? Just make this a bool on the component? + if (args.Delay <= TimeSpan.Zero || _tag.HasTag(args.User, "InstantDoAfters")) { RaiseDoAfterEvents(doAfter, comp); // We don't store instant do-afters. This is just a lazy way of hiding them from client-side visuals. diff --git a/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs b/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs index 53d58f1d80f..dbb1f6f2c4d 100644 --- a/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs +++ b/Content.Shared/Extinguisher/SharedFireExtinguisherComponent.cs @@ -1,8 +1,10 @@ using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Serialization; namespace Content.Shared.Extinguisher; +[NetworkedComponent] public abstract partial class SharedFireExtinguisherComponent : Component { [DataField("refillSound")] public SoundSpecifier RefillSound = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); diff --git a/Content.Shared/Eye/Blinding/Components/BlindableComponent.cs b/Content.Shared/Eye/Blinding/Components/BlindableComponent.cs index 4379d309bc4..c2e73bd6b89 100644 --- a/Content.Shared/Eye/Blinding/Components/BlindableComponent.cs +++ b/Content.Shared/Eye/Blinding/Components/BlindableComponent.cs @@ -24,7 +24,11 @@ public sealed partial class BlindableComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("EyeDamage"), AutoNetworkedField] public int EyeDamage = 0; - public const int MaxDamage = 9; + [ViewVariables(VVAccess.ReadOnly), DataField] + public int MaxDamage = 9; + + [ViewVariables(VVAccess.ReadOnly), DataField] + public int MinDamage = 0; /// /// Used to ensure that this doesn't break with sandbox or admin tools. diff --git a/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs b/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs index 5f24ff20188..24eed3adcf5 100644 --- a/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/BlindableSystem.cs @@ -37,7 +37,7 @@ public void UpdateIsBlind(Entity blindable) var old = blindable.Comp.IsBlind; // Don't bother raising an event if the eye is too damaged. - if (blindable.Comp.EyeDamage >= BlindableComponent.MaxDamage) + if (blindable.Comp.EyeDamage >= blindable.Comp.MaxDamage) { blindable.Comp.IsBlind = true; } @@ -62,13 +62,31 @@ public void AdjustEyeDamage(Entity blindable, int amount) return; blindable.Comp.EyeDamage += amount; - blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, 0, BlindableComponent.MaxDamage); + UpdateEyeDamage(blindable, true); + } + private void UpdateEyeDamage(Entity blindable, bool isDamageChanged) + { + if (!Resolve(blindable, ref blindable.Comp, false)) + return; + + var previousDamage = blindable.Comp.EyeDamage; + blindable.Comp.EyeDamage = Math.Clamp(blindable.Comp.EyeDamage, blindable.Comp.MinDamage, blindable.Comp.MaxDamage); Dirty(blindable); - UpdateIsBlind(blindable); + if (!isDamageChanged && previousDamage == blindable.Comp.EyeDamage) + return; + UpdateIsBlind(blindable); var ev = new EyeDamageChangedEvent(blindable.Comp.EyeDamage); RaiseLocalEvent(blindable.Owner, ref ev); } + public void SetMinDamage(Entity blindable, int amount) + { + if (!Resolve(blindable, ref blindable.Comp, false)) + return; + + blindable.Comp.MinDamage = amount; + UpdateEyeDamage(blindable, false); + } } /// diff --git a/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs b/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs index 5326af9636e..9a4afaec3a9 100644 --- a/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs +++ b/Content.Shared/Eye/Blinding/Systems/EyeClosingSystem.cs @@ -1,4 +1,3 @@ - using Content.Shared.Actions; using Content.Shared.Eye.Blinding.Components; using Robust.Shared.Audio.Systems; @@ -124,7 +123,7 @@ public void UpdateEyesClosable(Entity blindable) if (_entityManager.TryGetComponent(blindable, out var eyelids) && !eyelids.NaturallyCreated) return; - if (ev.Blur < BlurryVisionComponent.MaxMagnitude || ev.Blur >= BlindableComponent.MaxDamage) + if (ev.Blur < BlurryVisionComponent.MaxMagnitude || ev.Blur >= blindable.Comp.MaxDamage) { RemCompDeferred(blindable); return; diff --git a/Content.Server/Fax/FaxMachineComponent.cs b/Content.Shared/Fax/Components/FaxMachineComponent.cs similarity index 80% rename from Content.Server/Fax/FaxMachineComponent.cs rename to Content.Shared/Fax/Components/FaxMachineComponent.cs index a189bdc05ac..5599befa31b 100644 --- a/Content.Server/Fax/FaxMachineComponent.cs +++ b/Content.Shared/Fax/Components/FaxMachineComponent.cs @@ -1,12 +1,13 @@ using Content.Shared.Containers.ItemSlots; using Content.Shared.Paper; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Fax; +namespace Content.Shared.Fax.Components; -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class FaxMachineComponent : Component { /// @@ -16,6 +17,13 @@ public sealed partial class FaxMachineComponent : Component [DataField("name")] public string FaxName { get; set; } = "Unknown"; + /// + /// Sprite to use when inserting an object. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] + public string InsertingState = "inserting"; + /// /// Device address of fax in network to which data will be send /// @@ -26,7 +34,7 @@ public sealed partial class FaxMachineComponent : Component /// /// Contains the item to be sent, assumes it's paper... /// - [DataField("paperSlot", required: true)] + [DataField(required: true)] public ItemSlot PaperSlot = new(); /// @@ -34,21 +42,21 @@ public sealed partial class FaxMachineComponent : Component /// This will make it visible to others on the network /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("responsePings")] + [DataField] public bool ResponsePings { get; set; } = true; /// /// Should admins be notified on message receive /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("notifyAdmins")] + [DataField] public bool NotifyAdmins { get; set; } = false; /// /// Should that fax receive nuke codes send by admins. Probably should be captain fax only /// [ViewVariables(VVAccess.ReadWrite)] - [DataField("receiveNukeCodes")] + [DataField] public bool ReceiveNukeCodes { get; set; } = false; /// @@ -60,19 +68,19 @@ public sealed partial class FaxMachineComponent : Component /// /// Sound to play when fax has been emagged /// - [DataField("emagSound")] + [DataField] public SoundSpecifier EmagSound = new SoundCollectionSpecifier("sparks"); /// /// Sound to play when fax printing new message /// - [DataField("printSound")] + [DataField] public SoundSpecifier PrintSound = new SoundPathSpecifier("/Audio/Machines/printer.ogg"); /// /// Sound to play when fax successfully send message /// - [DataField("sendSound")] + [DataField] public SoundSpecifier SendSound = new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg"); /// @@ -85,27 +93,27 @@ public sealed partial class FaxMachineComponent : Component /// Print queue of the incoming message /// [ViewVariables] - [DataField("printingQueue")] + [DataField] public Queue PrintingQueue { get; private set; } = new(); /// /// Message sending timeout /// [ViewVariables] - [DataField("sendTimeoutRemaining")] + [DataField] public float SendTimeoutRemaining; /// /// Message sending timeout /// [ViewVariables] - [DataField("sendTimeout")] + [DataField] public float SendTimeout = 5f; /// /// Remaining time of inserting animation /// - [DataField("insertingTimeRemaining")] + [DataField] public float InsertingTimeRemaining; /// @@ -117,7 +125,7 @@ public sealed partial class FaxMachineComponent : Component /// /// Remaining time of printing animation /// - [DataField("printingTimeRemaining")] + [DataField] public float PrintingTimeRemaining; /// @@ -130,13 +138,16 @@ public sealed partial class FaxMachineComponent : Component [DataDefinition] public sealed partial class FaxPrintout { - [DataField("name", required: true)] + [DataField(required: true)] public string Name { get; private set; } = default!; - [DataField("content", required: true)] + [DataField] + public string? Label { get; private set; } + + [DataField(required: true)] public string Content { get; private set; } = default!; - [DataField("prototypeId", customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] + [DataField(customTypeSerializer: typeof(PrototypeIdSerializer), required: true)] public string PrototypeId { get; private set; } = default!; [DataField("stampState")] @@ -149,10 +160,11 @@ private FaxPrintout() { } - public FaxPrintout(string content, string name, string? prototypeId = null, string? stampState = null, List? stampedBy = null) + public FaxPrintout(string content, string name, string? label = null, string? prototypeId = null, string? stampState = null, List? stampedBy = null) { Content = content; Name = name; + Label = label; PrototypeId = prototypeId ?? ""; StampState = stampState; StampedBy = stampedBy ?? new List(); diff --git a/Content.Shared/Fax/Components/FaxableObjectComponent.cs b/Content.Shared/Fax/Components/FaxableObjectComponent.cs new file mode 100644 index 00000000000..57b6e610a32 --- /dev/null +++ b/Content.Shared/Fax/Components/FaxableObjectComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Fax.Components; +/// +/// Entity with this component can be faxed. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FaxableObjectComponent : Component +{ + /// + /// Sprite to use when inserting an object. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField, AutoNetworkedField] + public string InsertingState = "inserting"; +} diff --git a/Content.Shared/Fax/Components/FaxecuteComponent.cs b/Content.Shared/Fax/Components/FaxecuteComponent.cs new file mode 100644 index 00000000000..9c9bd030203 --- /dev/null +++ b/Content.Shared/Fax/Components/FaxecuteComponent.cs @@ -0,0 +1,19 @@ +using Content.Shared.Damage; +using Robust.Shared.GameStates; + +namespace Content.Shared.Fax.Components; + +/// +/// A fax component which stores a damage specifier for attempting to fax a mob. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class FaxecuteComponent : Component +{ + + /// + /// Type of damage dealt when entity is faxecuted. + /// + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier Damage = new(); +} + diff --git a/Content.Shared/Fax/DamageOnFaxecuteEvent.cs b/Content.Shared/Fax/DamageOnFaxecuteEvent.cs new file mode 100644 index 00000000000..b36f55ab5d2 --- /dev/null +++ b/Content.Shared/Fax/DamageOnFaxecuteEvent.cs @@ -0,0 +1,9 @@ + +namespace Content.Shared.Fax.Components; + +/// +/// Event for killing any mob within the fax machine. +/// +/// System for handling execution of a mob within fax when copy or send attempt is made. +/// +public sealed class FaxecuteSystem : EntitySystem +{ + [Dependency] private readonly DamageableSystem _damageable = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + + public override void Initialize() + { + base.Initialize(); + } + + public void Faxecute(EntityUid uid, FaxMachineComponent component, DamageOnFaxecuteEvent? args = null) + { + var sendEntity = component.PaperSlot.Item; + if (sendEntity == null) + return; + + if (!TryComp(uid, out var faxecute)) + return; + + var damageSpec = faxecute.Damage; + _damageable.TryChangeDamage(sendEntity, damageSpec); + _popupSystem.PopupEntity(Loc.GetString("fax-machine-popup-error", ("target", uid)), uid, PopupType.LargeCaution); + return; + + } +} diff --git a/Content.Shared/Flash/Components/FlashComponent.cs b/Content.Shared/Flash/Components/FlashComponent.cs index a26e32cb70f..a9098bc85a9 100644 --- a/Content.Shared/Flash/Components/FlashComponent.cs +++ b/Content.Shared/Flash/Components/FlashComponent.cs @@ -12,6 +12,13 @@ public sealed partial class FlashComponent : Component [ViewVariables(VVAccess.ReadWrite)] public int FlashDuration { get; set; } = 5000; + /// + /// How long a target is stunned when a melee flash is used. + /// If null, melee flashes will not stun at all + /// + [DataField] + public TimeSpan? MeleeStunDuration = TimeSpan.FromSeconds(1.5); + [DataField("range")] [ViewVariables(VVAccess.ReadWrite)] public float Range { get; set; } = 7f; @@ -32,5 +39,8 @@ public sealed partial class FlashComponent : Component }; public bool Flashing; + + [DataField] + public float Probability = 1f; } } diff --git a/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs b/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs index d1270e9db74..7658ca0ae5a 100644 --- a/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs +++ b/Content.Shared/Flash/Components/FlashOnTriggerComponent.cs @@ -9,4 +9,5 @@ public sealed partial class FlashOnTriggerComponent : Component { [DataField] public float Range = 1.0f; [DataField] public float Duration = 8.0f; + [DataField] public float Probability = 1.0f; } diff --git a/Content.Shared/Follower/FollowerSystem.cs b/Content.Shared/Follower/FollowerSystem.cs index fc7cccf9bd6..6c02b130762 100644 --- a/Content.Shared/Follower/FollowerSystem.cs +++ b/Content.Shared/Follower/FollowerSystem.cs @@ -247,6 +247,27 @@ public void StopAllFollowers(EntityUid uid, StopFollowingEntity(player, uid, followed); } } + + /// + /// Get the most followed entity. + /// + public EntityUid? GetMostFollowed() + { + EntityUid? picked = null; + int most = 0; + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var comp)) + { + var count = comp.Following.Count; + if (count > most) + { + picked = uid; + most = count; + } + } + + return picked; + } } public abstract class FollowEvent : EntityEventArgs diff --git a/Content.Shared/Geras/SharedGerasSystem.cs b/Content.Shared/Geras/SharedGerasSystem.cs new file mode 100644 index 00000000000..8c998371b64 --- /dev/null +++ b/Content.Shared/Geras/SharedGerasSystem.cs @@ -0,0 +1,16 @@ +using Content.Shared.Actions; + +namespace Content.Shared.Geras; + +/// +/// Geras is the god of old age, and A geras is the small morph of a slime. This system allows the slimes to have the morphing action. +/// +public abstract class SharedGerasSystem : EntitySystem +{ + +} + +public sealed partial class MorphIntoGeras : InstantActionEvent +{ + +} diff --git a/Content.Shared/Ghost/GhostComponent.cs b/Content.Shared/Ghost/GhostComponent.cs index f7717e8d232..96e9b717b90 100644 --- a/Content.Shared/Ghost/GhostComponent.cs +++ b/Content.Shared/Ghost/GhostComponent.cs @@ -101,4 +101,6 @@ public sealed partial class ToggleLightingActionEvent : InstantActionEvent { } public sealed partial class ToggleGhostHearingActionEvent : InstantActionEvent { } +public sealed partial class ToggleGhostVisibilityToAllEvent : InstantActionEvent { } + public sealed partial class BooActionEvent : InstantActionEvent { } diff --git a/Content.Shared/Ghost/Roles/GhostRolePrototype.cs b/Content.Shared/Ghost/Roles/GhostRolePrototype.cs new file mode 100644 index 00000000000..43d64322504 --- /dev/null +++ b/Content.Shared/Ghost/Roles/GhostRolePrototype.cs @@ -0,0 +1,38 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Ghost.Roles; + +/// +/// For selectable ghostrole prototypes in ghostrole spawners. +/// +[Prototype] +public sealed partial class GhostRolePrototype : IPrototype +{ + [ViewVariables] + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The name of the ghostrole. + /// + [DataField] + public string Name { get; set; } = default!; + + /// + /// The description of the ghostrole. + /// + [DataField] + public string Description { get; set; } = default!; + + /// + /// The entity prototype of the ghostrole + /// + [DataField] + public string EntityPrototype = default!; + + /// + /// Rules of the ghostrole + /// + [DataField] + public string Rules = default!; +} \ No newline at end of file diff --git a/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs b/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs index 74af1e89ecc..4dd6bfa433d 100644 --- a/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs +++ b/Content.Shared/Ghost/Roles/GhostRolesEuiMessages.cs @@ -13,6 +13,20 @@ public struct GhostRoleInfo public string Description { get; set; } public string Rules { get; set; } public List? Requirements { get; set; } + + /// + public GhostRoleKind Kind { get; set; } + + /// + /// if is , specifies how many players are currently + /// in the raffle for this role. + /// + public uint RafflePlayerCount { get; set; } + + /// + /// if is , specifies when raffle finishes. + /// + public TimeSpan RaffleEndTime { get; set; } } [NetSerializable, Serializable] @@ -27,24 +41,62 @@ public GhostRolesEuiState(GhostRoleInfo[] ghostRoles) } [NetSerializable, Serializable] - public sealed class GhostRoleTakeoverRequestMessage : EuiMessageBase + public sealed class RequestGhostRoleMessage : EuiMessageBase { public uint Identifier { get; } - public GhostRoleTakeoverRequestMessage(uint identifier) + public RequestGhostRoleMessage(uint identifier) { Identifier = identifier; } } [NetSerializable, Serializable] - public sealed class GhostRoleFollowRequestMessage : EuiMessageBase + public sealed class FollowGhostRoleMessage : EuiMessageBase { public uint Identifier { get; } - public GhostRoleFollowRequestMessage(uint identifier) + public FollowGhostRoleMessage(uint identifier) { Identifier = identifier; } } + + [NetSerializable, Serializable] + public sealed class LeaveGhostRoleRaffleMessage : EuiMessageBase + { + public uint Identifier { get; } + + public LeaveGhostRoleRaffleMessage(uint identifier) + { + Identifier = identifier; + } + } + + /// + /// Determines whether a ghost role is a raffle role, and if it is, whether it's running. + /// + [NetSerializable, Serializable] + public enum GhostRoleKind + { + /// + /// Role is not a raffle role and can be taken immediately. + /// + FirstComeFirstServe, + + /// + /// Role is a raffle role, but raffle hasn't started yet. + /// + RaffleReady, + + /// + /// Role is raffle role and currently being raffled, but player hasn't joined raffle. + /// + RaffleInProgress, + + /// + /// Role is raffle role and currently being raffled, and player joined raffle. + /// + RaffleJoined + } } diff --git a/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettings.cs b/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettings.cs new file mode 100644 index 00000000000..a7aa757b72a --- /dev/null +++ b/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettings.cs @@ -0,0 +1,30 @@ +namespace Content.Server.Ghost.Roles.Raffles; + +/// +/// Defines settings for a ghost role raffle. +/// +[DataDefinition] +public sealed partial class GhostRoleRaffleSettings +{ + /// + /// The initial duration of a raffle in seconds. This is the countdown timer's value when the raffle starts. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + public uint InitialDuration { get; set; } + + /// + /// When the raffle is joined by a player, the countdown timer is extended by this value in seconds. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + public uint JoinExtendsDurationBy { get; set; } + + /// + /// The maximum duration in seconds for the ghost role raffle. A raffle cannot run for longer than this + /// duration, even if extended by joiners. Must be greater than or equal to . + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] + public uint MaxDuration { get; set; } +} diff --git a/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettingsPrototype.cs b/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettingsPrototype.cs new file mode 100644 index 00000000000..f1447a0e096 --- /dev/null +++ b/Content.Shared/Ghost/Roles/Raffles/GhostRoleRaffleSettingsPrototype.cs @@ -0,0 +1,22 @@ +using Content.Server.Ghost.Roles.Raffles; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Ghost.Roles.Raffles; + +/// +/// Allows specifying the settings for a ghost role raffle as a prototype. +/// +[Prototype("ghostRoleRaffleSettings")] +public sealed class GhostRoleRaffleSettingsPrototype : IPrototype +{ + /// + [IdDataField] + public string ID { get; private set; } = default!; + + /// + /// The settings for a ghost role raffle. + /// + /// + [DataField(required: true)] + public GhostRoleRaffleSettings Settings { get; private set; } = new(); +} diff --git a/Content.Shared/Ghost/SharedGhostSystem.cs b/Content.Shared/Ghost/SharedGhostSystem.cs index 24da2f144f8..2cb3a1e1d63 100644 --- a/Content.Shared/Ghost/SharedGhostSystem.cs +++ b/Content.Shared/Ghost/SharedGhostSystem.cs @@ -127,6 +127,12 @@ public GhostWarpToTargetRequestEvent(NetEntity target) } } + /// + /// A client to server request for their ghost to be warped to the most followed entity. + /// + [Serializable, NetSerializable] + public sealed class GhostnadoRequestEvent : EntityEventArgs; + /// /// A client to server request for their ghost to return to body /// diff --git a/Content.Shared/GridPreloader/Prototypes/PreloadedGridPrototype.cs b/Content.Shared/GridPreloader/Prototypes/PreloadedGridPrototype.cs new file mode 100644 index 00000000000..89da9dfb8f7 --- /dev/null +++ b/Content.Shared/GridPreloader/Prototypes/PreloadedGridPrototype.cs @@ -0,0 +1,21 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Shared.GridPreloader.Prototypes; + +/// +/// Creating this prototype will automatically load the grid at the specified path at the beginning of the round, +/// and allow the GridPreloader system to load them in the middle of the round. This is needed for optimization, +/// because loading grids in the middle of a round causes the server to lag. +/// +[Prototype("preloadedGrid")] +public sealed partial class PreloadedGridPrototype : IPrototype +{ + [IdDataField] public string ID { get; } = string.Empty; + + [DataField(required: true)] + public ResPath Path; + + [DataField] + public int Copies = 1; +} diff --git a/Content.Shared/GridPreloader/Systems/SharedGridPreloaderSystem.cs b/Content.Shared/GridPreloader/Systems/SharedGridPreloaderSystem.cs new file mode 100644 index 00000000000..04c994adf2c --- /dev/null +++ b/Content.Shared/GridPreloader/Systems/SharedGridPreloaderSystem.cs @@ -0,0 +1,4 @@ +namespace Content.Shared.GridPreloader.Systems; +public abstract class SharedGridPreloaderSystem : EntitySystem +{ +} diff --git a/Content.Shared/Hands/Components/HandsComponent.cs b/Content.Shared/Hands/Components/HandsComponent.cs index f1f25a69f7a..919d55f294a 100644 --- a/Content.Shared/Hands/Components/HandsComponent.cs +++ b/Content.Shared/Hands/Components/HandsComponent.cs @@ -126,9 +126,43 @@ public HandsComponentState(HandsComponent handComp) /// /// What side of the body this hand is on. /// +/// +/// public enum HandLocation : byte { Left, Middle, Right } + +/// +/// What side of the UI a hand is on. +/// +/// +/// +public enum HandUILocation : byte +{ + Left, + Right +} + +/// +/// Helper functions for working with . +/// +public static class HandLocationExt +{ + /// + /// Convert a into the appropriate . + /// This maps "middle" hands to . + /// + public static HandUILocation GetUILocation(this HandLocation location) + { + return location switch + { + HandLocation.Left => HandUILocation.Left, + HandLocation.Middle => HandUILocation.Right, + HandLocation.Right => HandUILocation.Right, + _ => throw new ArgumentOutOfRangeException(nameof(location), location, null) + }; + } +} diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs index 32339eb03ac..6d4d332479f 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.Interactions.cs @@ -8,6 +8,7 @@ using Robust.Shared.Input.Binding; using Robust.Shared.Map; using Robust.Shared.Player; +using Robust.Shared.Utility; namespace Content.Shared.Hands.EntitySystems; @@ -181,27 +182,21 @@ public bool TryMoveHeldEntityToActiveHand(EntityUid uid, string handName, bool c } //TODO: Actually shows all items/clothing/etc. - private void HandleExamined(EntityUid uid, HandsComponent handsComp, ExaminedEvent args) + private void HandleExamined(EntityUid examinedUid, HandsComponent handsComp, ExaminedEvent args) { - var held = EnumerateHeld(uid, handsComp) - .Where(x => !HasComp(x)).ToList(); + var heldItemNames = EnumerateHeld(examinedUid, handsComp) + .Where(entity => !HasComp(entity)) + .Select(item => FormattedMessage.EscapeText(Identity.Name(item, EntityManager))) + .Select(itemName => Loc.GetString("comp-hands-examine-wrapper", ("item", itemName))) + .ToList(); + + var locKey = heldItemNames.Count != 0 ? "comp-hands-examine" : "comp-hands-examine-empty"; + var locUser = ("user", Identity.Entity(examinedUid, EntityManager)); + var locItems = ("items", ContentLocalizationManager.FormatList(heldItemNames)); using (args.PushGroup(nameof(HandsComponent))) { - if (!held.Any()) - { - args.PushText(Loc.GetString("comp-hands-examine-empty", - ("user", Identity.Entity(uid, EntityManager)))); - return; - } - - var heldList = ContentLocalizationManager.FormatList(held - .Select(x => Loc.GetString("comp-hands-examine-wrapper", - ("item", Identity.Entity(x, EntityManager)))).ToList()); - - args.PushMarkup(Loc.GetString("comp-hands-examine", - ("user", Identity.Entity(uid, EntityManager)), - ("items", heldList))); + args.PushMarkup(Loc.GetString(locKey, locUser, locItems)); } } } diff --git a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs index b72a7c4eb3c..fd732009e9a 100644 --- a/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs +++ b/Content.Shared/Hands/EntitySystems/SharedHandsSystem.cs @@ -87,7 +87,6 @@ public virtual void RemoveHand(EntityUid uid, string handName, HandsComponent? h /// /// /// - public void RemoveHands(EntityUid uid, HandsComponent? handsComp = null) { if (!Resolve(uid, ref handsComp)) @@ -137,6 +136,43 @@ public bool TryGetEmptyHand(EntityUid uid, [NotNullWhen(true)] out Hand? emptyHa return false; } + public bool TryGetActiveHand(Entity entity, [NotNullWhen(true)] out Hand? hand) + { + if (!Resolve(entity, ref entity.Comp, false)) + { + hand = null; + return false; + } + + hand = entity.Comp.ActiveHand; + return hand != null; + } + + public bool TryGetActiveItem(Entity entity, [NotNullWhen(true)] out EntityUid? item) + { + if (!TryGetActiveHand(entity, out var hand)) + { + item = null; + return false; + } + + item = hand.HeldEntity; + return item != null; + } + + public Hand? GetActiveHand(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return null; + + return entity.Comp.ActiveHand; + } + + public EntityUid? GetActiveItem(Entity entity) + { + return GetActiveHand(entity)?.HeldEntity; + } + /// /// Enumerate over hands, starting with the currently active hand. /// @@ -227,9 +263,17 @@ public bool SetActiveHand(EntityUid uid, Hand? hand, HandsComponent? handComp = return true; } - public bool IsHolding(EntityUid uid, EntityUid? entity, [NotNullWhen(true)] out Hand? inHand, HandsComponent? handsComp = null) + public bool IsHolding(Entity entity, [NotNullWhen(true)] EntityUid? item) + { + return IsHolding(entity, item, out _, entity); + } + + public bool IsHolding(EntityUid uid, [NotNullWhen(true)] EntityUid? entity, [NotNullWhen(true)] out Hand? inHand, HandsComponent? handsComp = null) { inHand = null; + if (entity == null) + return false; + if (!Resolve(uid, ref handsComp, false)) return false; diff --git a/Content.Shared/HealthExaminable/HealthExaminableComponent.cs b/Content.Shared/HealthExaminable/HealthExaminableComponent.cs new file mode 100644 index 00000000000..88a79782a55 --- /dev/null +++ b/Content.Shared/HealthExaminable/HealthExaminableComponent.cs @@ -0,0 +1,27 @@ +using Content.Shared.Damage.Prototypes; +using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; + +namespace Content.Shared.HealthExaminable; + +[RegisterComponent, Access(typeof(HealthExaminableSystem))] +public sealed partial class HealthExaminableComponent : Component +{ + // + // The thresholds for determining the examine text for certain amounts of damage. + // These are calculated as a percentage of the entity's critical threshold. + // + public List Thresholds = new() + { FixedPoint2.New(0.10), FixedPoint2.New(0.25), FixedPoint2.New(0.50), FixedPoint2.New(0.75) }; + + [DataField(required: true)] + public HashSet> ExaminableTypes = default!; + + /// + /// Health examine text is automatically generated through creating loc string IDs, in the form: + /// `health-examine-[prefix]-[type]-[threshold]` + /// This part determines the prefix. + /// + [DataField] + public string LocPrefix = "carbon"; +} diff --git a/Content.Server/HealthExaminable/HealthExaminableSystem.cs b/Content.Shared/HealthExaminable/HealthExaminableSystem.cs similarity index 96% rename from Content.Server/HealthExaminable/HealthExaminableSystem.cs rename to Content.Shared/HealthExaminable/HealthExaminableSystem.cs index 89291726fbe..39addfc9410 100644 --- a/Content.Server/HealthExaminable/HealthExaminableSystem.cs +++ b/Content.Shared/HealthExaminable/HealthExaminableSystem.cs @@ -1,4 +1,3 @@ -using Content.Server.Traits.Assorted; using Content.Shared.Damage; using Content.Shared.Examine; using Content.Shared.FixedPoint; @@ -8,8 +7,9 @@ using Content.Shared.Verbs; using Robust.Shared.Utility; using System.Linq; +using Content.Shared.Traits.Assorted.Components; -namespace Content.Server.HealthExaminable; +namespace Content.Shared.HealthExaminable; public sealed class HealthExaminableSystem : EntitySystem { @@ -53,7 +53,7 @@ private void OnGetExamineVerbs(EntityUid uid, HealthExaminableComponent componen args.Verbs.Add(verb); } - private FormattedMessage CreateMarkup(EntityUid uid, HealthExaminableComponent component, DamageableComponent damage) + public FormattedMessage CreateMarkup(EntityUid uid, HealthExaminableComponent component, DamageableComponent damage) { var msg = new FormattedMessage(); @@ -92,20 +92,14 @@ private FormattedMessage CreateMarkup(EntityUid uid, HealthExaminableComponent c continue; if (!first) - { msg.PushNewline(); - } else - { first = false; - } msg.AddMarkup(chosenLocStr); } if (msg.IsEmpty) - { msg.AddMarkup(Loc.GetString($"health-examinable-{component.LocPrefix}-none")); - } // Anything else want to add on to this? RaiseLocalEvent(uid, new HealthBeingExaminedEvent(msg, false), true); diff --git a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs index c9292337d7d..8e0af4c6f06 100644 --- a/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs +++ b/Content.Shared/Humanoid/HumanoidAppearanceComponent.cs @@ -85,6 +85,12 @@ public sealed partial class HumanoidAppearanceComponent : Component [ViewVariables(VVAccess.ReadOnly)] public Color? CachedFacialHairColor; + /// + /// Which layers of this humanoid that should be hidden on equipping a corresponding item.. + /// + [DataField] + public HashSet HideLayersOnEquip = [HumanoidVisualLayers.Hair]; + /// /// DeltaV - let paradox anomaly be cloned /// diff --git a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs index f1f7de5c11a..fc44ed5e3b9 100644 --- a/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Humanoid/HumanoidCharacterAppearance.cs @@ -5,262 +5,286 @@ using Robust.Shared.Random; using Robust.Shared.Serialization; -namespace Content.Shared.Humanoid +namespace Content.Shared.Humanoid; + +[DataDefinition] +[Serializable, NetSerializable] +public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance, IEquatable { - [DataDefinition] - [Serializable, NetSerializable] - public sealed partial class HumanoidCharacterAppearance : ICharacterAppearance - { - public HumanoidCharacterAppearance(string hairStyleId, - Color hairColor, - string facialHairStyleId, - Color facialHairColor, - Color eyeColor, - Color skinColor, - List markings) - { - HairStyleId = hairStyleId; - HairColor = ClampColor(hairColor); - FacialHairStyleId = facialHairStyleId; - FacialHairColor = ClampColor(facialHairColor); - EyeColor = ClampColor(eyeColor); - SkinColor = ClampColor(skinColor); - Markings = markings; - } + [DataField("hair")] + public string HairStyleId { get; set; } = HairStyles.DefaultHairStyle; - [DataField("hair")] - public string HairStyleId { get; private set; } + [DataField] + public Color HairColor { get; set; } = Color.Black; - [DataField("hairColor")] - public Color HairColor { get; private set; } + [DataField("facialHair")] + public string FacialHairStyleId { get; set; } = HairStyles.DefaultFacialHairStyle; - [DataField("facialHair")] - public string FacialHairStyleId { get; private set; } + [DataField] + public Color FacialHairColor { get; set; } = Color.Black; - [DataField("facialHairColor")] - public Color FacialHairColor { get; private set; } + [DataField] + public Color EyeColor { get; private set; } - [DataField("eyeColor")] - public Color EyeColor { get; private set; } + [DataField] + public Color SkinColor { get; private set; } - [DataField("skinColor")] - public Color SkinColor { get; private set; } + [DataField] + public List Markings { get; private set; } = new(); - [DataField("markings")] - public List Markings { get; private set; } + public HumanoidCharacterAppearance(string hairStyleId, + Color hairColor, + string facialHairStyleId, + Color facialHairColor, + Color eyeColor, + Color skinColor, + List markings) + { + HairStyleId = hairStyleId; + HairColor = ClampColor(hairColor); + FacialHairStyleId = facialHairStyleId; + FacialHairColor = ClampColor(facialHairColor); + EyeColor = ClampColor(eyeColor); + SkinColor = ClampColor(skinColor); + Markings = markings; + } - public HumanoidCharacterAppearance WithHairStyleName(string newName) - { - return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); - } + public HumanoidCharacterAppearance(HumanoidCharacterAppearance other) + : this( + other.HairStyleId, + other.HairColor, + other.FacialHairStyleId, + other.FacialHairColor, + other.EyeColor, + other.SkinColor, + new(other.Markings)) + { - public HumanoidCharacterAppearance WithHairColor(Color newColor) - { - return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); - } + } - public HumanoidCharacterAppearance WithFacialHairStyleName(string newName) - { - return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings); - } + public HumanoidCharacterAppearance WithHairStyleName(string newName) + { + return new(newName, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); + } - public HumanoidCharacterAppearance WithFacialHairColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings); - } + public HumanoidCharacterAppearance WithHairColor(Color newColor) + { + return new(HairStyleId, newColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, Markings); + } - public HumanoidCharacterAppearance WithEyeColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings); - } + public HumanoidCharacterAppearance WithFacialHairStyleName(string newName) + { + return new(HairStyleId, HairColor, newName, FacialHairColor, EyeColor, SkinColor, Markings); + } - public HumanoidCharacterAppearance WithSkinColor(Color newColor) - { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings); - } + public HumanoidCharacterAppearance WithFacialHairColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, newColor, EyeColor, SkinColor, Markings); + } - public HumanoidCharacterAppearance WithMarkings(List newMarkings) + public HumanoidCharacterAppearance WithEyeColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, newColor, SkinColor, Markings); + } + + public HumanoidCharacterAppearance WithSkinColor(Color newColor) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, newColor, Markings); + } + + public HumanoidCharacterAppearance WithMarkings(List newMarkings) + { + return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings); + } + + public static HumanoidCharacterAppearance DefaultWithSpecies(string species) + { + var speciesPrototype = IoCManager.Resolve().Index(species); + var skinColor = speciesPrototype.SkinColoration switch { - return new(HairStyleId, HairColor, FacialHairStyleId, FacialHairColor, EyeColor, SkinColor, newMarkings); - } + HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone), + HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone, + HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone), + HumanoidSkinColor.VoxFeathers => Humanoid.SkinColor.ClosestVoxColor(speciesPrototype.DefaultSkinTone), + HumanoidSkinColor.TintedHuesSkin => Humanoid.SkinColor.TintedHuesSkin(speciesPrototype.DefaultSkinTone, speciesPrototype.DefaultSkinTone), + _ => Humanoid.SkinColor.ValidHumanSkinTone, + }; - public HumanoidCharacterAppearance() : this( + return new( HairStyles.DefaultHairStyle, Color.Black, HairStyles.DefaultFacialHairStyle, Color.Black, Color.Black, - Humanoid.SkinColor.ValidHumanSkinTone, + skinColor, new () - ) - { - } - - public static HumanoidCharacterAppearance DefaultWithSpecies(string species) - { - var speciesPrototype = IoCManager.Resolve().Index(species); - var skinColor = speciesPrototype.SkinColoration switch - { - HumanoidSkinColor.HumanToned => Humanoid.SkinColor.HumanSkinTone(speciesPrototype.DefaultHumanSkinTone), - HumanoidSkinColor.Hues => speciesPrototype.DefaultSkinTone, - HumanoidSkinColor.TintedHues => Humanoid.SkinColor.TintedHues(speciesPrototype.DefaultSkinTone), - // DeltaV - Blended tint for moths - HumanoidSkinColor.TintedHuesSkin => Humanoid.SkinColor.TintedHuesSkin(speciesPrototype.DefaultSkinTone, speciesPrototype.DefaultSkinTone), - _ => Humanoid.SkinColor.ValidHumanSkinTone - }; - - return new( - HairStyles.DefaultHairStyle, - Color.Black, - HairStyles.DefaultFacialHairStyle, - Color.Black, - Color.Black, - skinColor, - new () - ); - } - - private static IReadOnlyList RealisticEyeColors = new List - { - Color.Brown, - Color.Gray, - Color.Azure, - Color.SteelBlue, - Color.Black - }; + ); + } - public static HumanoidCharacterAppearance Random(string species, Sex sex) - { - var random = IoCManager.Resolve(); - var markingManager = IoCManager.Resolve(); - var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList(); - var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList(); + private static IReadOnlyList RealisticEyeColors = new List + { + Color.Brown, + Color.Gray, + Color.Azure, + Color.SteelBlue, + Color.Black + }; + + public static HumanoidCharacterAppearance Random(string species, Sex sex) + { + var random = IoCManager.Resolve(); + var markingManager = IoCManager.Resolve(); + var hairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.Hair, species).Keys.ToList(); + var facialHairStyles = markingManager.MarkingsByCategoryAndSpecies(MarkingCategories.FacialHair, species).Keys.ToList(); - var newHairStyle = hairStyles.Count > 0 - ? random.Pick(hairStyles) - : HairStyles.DefaultHairStyle; + var newHairStyle = hairStyles.Count > 0 + ? random.Pick(hairStyles) + : HairStyles.DefaultHairStyle; - var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female - ? HairStyles.DefaultFacialHairStyle - : random.Pick(facialHairStyles); + var newFacialHairStyle = facialHairStyles.Count == 0 || sex == Sex.Female + ? HairStyles.DefaultFacialHairStyle + : random.Pick(facialHairStyles); - var newHairColor = random.Pick(HairStyles.RealisticHairColors); - newHairColor = newHairColor - .WithRed(RandomizeColor(newHairColor.R)) - .WithGreen(RandomizeColor(newHairColor.G)) - .WithBlue(RandomizeColor(newHairColor.B)); + var newHairColor = random.Pick(HairStyles.RealisticHairColors); + newHairColor = newHairColor + .WithRed(RandomizeColor(newHairColor.R)) + .WithGreen(RandomizeColor(newHairColor.G)) + .WithBlue(RandomizeColor(newHairColor.B)); - // TODO: Add random markings + // TODO: Add random markings - var newEyeColor = random.Pick(RealisticEyeColors); + var newEyeColor = random.Pick(RealisticEyeColors); - var skinType = IoCManager.Resolve().Index(species).SkinColoration; + var skinType = IoCManager.Resolve().Index(species).SkinColoration; var skinTone = IoCManager.Resolve().Index(species).DefaultSkinTone; // DeltaV, required for tone blending - var newSkinColor = Humanoid.SkinColor.ValidHumanSkinTone; - switch (skinType) - { - case HumanoidSkinColor.HumanToned: - var tone = random.Next(0, 100); - newSkinColor = Humanoid.SkinColor.HumanSkinTone(tone); - break; - case HumanoidSkinColor.Hues: - case HumanoidSkinColor.TintedHues: - var rbyte = random.NextByte(); - var gbyte = random.NextByte(); - var bbyte = random.NextByte(); - newSkinColor = new Color(rbyte, gbyte, bbyte); - break; - case HumanoidSkinColor.TintedHuesSkin: // DeltaV, tone blending - rbyte = random.NextByte(); - gbyte = random.NextByte(); - bbyte = random.NextByte(); - newSkinColor = new Color(rbyte, gbyte, bbyte); - break; - } - - if (skinType == HumanoidSkinColor.TintedHues) - { + var newSkinColor = new Color(random.NextFloat(1), random.NextFloat(1), random.NextFloat(1), 1); + switch (skinType) + { + case HumanoidSkinColor.HumanToned: + var tone = Math.Round(Humanoid.SkinColor.HumanSkinToneFromColor(newSkinColor)); + newSkinColor = Humanoid.SkinColor.HumanSkinTone((int)tone); + break; + case HumanoidSkinColor.Hues: + break; + case HumanoidSkinColor.TintedHues: newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(newSkinColor); - } - - if (skinType == HumanoidSkinColor.TintedHuesSkin) // DeltaV, tone blending - { + break; + case HumanoidSkinColor.TintedHuesSkin: newSkinColor = Humanoid.SkinColor.ValidTintedHuesSkinTone(skinTone, newSkinColor); - } + break; + case HumanoidSkinColor.VoxFeathers: + newSkinColor = Humanoid.SkinColor.ProportionalVoxColor(newSkinColor); + break; + } - return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ()); + return new HumanoidCharacterAppearance(newHairStyle, newHairColor, newFacialHairStyle, newHairColor, newEyeColor, newSkinColor, new ()); - float RandomizeColor(float channel) - { - return MathHelper.Clamp01(channel + random.Next(-25, 25) / 100f); - } + float RandomizeColor(float channel) + { + return MathHelper.Clamp01(channel + random.Next(-25, 25) / 100f); } + } + + public static Color ClampColor(Color color) + { + return new(color.RByte, color.GByte, color.BByte); + } + + public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex) + { + var hairStyleId = appearance.HairStyleId; + var facialHairStyleId = appearance.FacialHairStyleId; + + var hairColor = ClampColor(appearance.HairColor); + var facialHairColor = ClampColor(appearance.FacialHairColor); + var eyeColor = ClampColor(appearance.EyeColor); - public static Color ClampColor(Color color) + var proto = IoCManager.Resolve(); + var markingManager = IoCManager.Resolve(); + + if (!markingManager.MarkingsByCategory(MarkingCategories.Hair).ContainsKey(hairStyleId)) { - return new(color.RByte, color.GByte, color.BByte); + hairStyleId = HairStyles.DefaultHairStyle; } - public static HumanoidCharacterAppearance EnsureValid(HumanoidCharacterAppearance appearance, string species, Sex sex) + if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId)) { - var hairStyleId = appearance.HairStyleId; - var facialHairStyleId = appearance.FacialHairStyleId; - - var hairColor = ClampColor(appearance.HairColor); - var facialHairColor = ClampColor(appearance.FacialHairColor); - var eyeColor = ClampColor(appearance.EyeColor); + facialHairStyleId = HairStyles.DefaultFacialHairStyle; + } - var proto = IoCManager.Resolve(); - var markingManager = IoCManager.Resolve(); + var markingSet = new MarkingSet(); + var skinColor = appearance.SkinColor; + if (proto.TryIndex(species, out SpeciesPrototype? speciesProto)) + { + markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto); + markingSet.EnsureValid(markingManager); - if (!markingManager.MarkingsByCategory(MarkingCategories.Hair).ContainsKey(hairStyleId)) + if (!Humanoid.SkinColor.VerifySkinColor(speciesProto.SkinColoration, skinColor)) { - hairStyleId = HairStyles.DefaultHairStyle; + skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor); } - if (!markingManager.MarkingsByCategory(MarkingCategories.FacialHair).ContainsKey(facialHairStyleId)) - { - facialHairStyleId = HairStyles.DefaultFacialHairStyle; - } + markingSet.EnsureSpecies(species, skinColor, markingManager); + markingSet.EnsureSexes(sex, markingManager); + } - var markingSet = new MarkingSet(); - var skinColor = appearance.SkinColor; - if (proto.TryIndex(species, out SpeciesPrototype? speciesProto)) - { - markingSet = new MarkingSet(appearance.Markings, speciesProto.MarkingPoints, markingManager, proto); - markingSet.EnsureValid(markingManager); + return new HumanoidCharacterAppearance( + hairStyleId, + hairColor, + facialHairStyleId, + facialHairColor, + eyeColor, + skinColor, + markingSet.GetForwardEnumerator().ToList()); + } - if (!Humanoid.SkinColor.VerifySkinColor(speciesProto.SkinColoration, skinColor)) - { - skinColor = Humanoid.SkinColor.ValidSkinTone(speciesProto.SkinColoration, skinColor); - } + public bool MemberwiseEquals(ICharacterAppearance maybeOther) + { + return + maybeOther is HumanoidCharacterAppearance other + && HairStyleId == other.HairStyleId + && HairColor.Equals(other.HairColor) + && FacialHairStyleId == other.FacialHairStyleId + && FacialHairColor.Equals(other.FacialHairColor) + && EyeColor.Equals(other.EyeColor) + && SkinColor.Equals(other.SkinColor) + && Markings.SequenceEqual(other.Markings); + } - markingSet.EnsureSpecies(species, skinColor, markingManager); - markingSet.EnsureSexes(sex, markingManager); - } + public bool Equals(HumanoidCharacterAppearance? other) + { + if (ReferenceEquals(null, other)) + return false; + if (ReferenceEquals(this, other)) + return true; + return HairStyleId == other.HairStyleId + && HairColor.Equals(other.HairColor) + && FacialHairStyleId == other.FacialHairStyleId + && FacialHairColor.Equals(other.FacialHairColor) + && EyeColor.Equals(other.EyeColor) + && SkinColor.Equals(other.SkinColor) + && Markings.SequenceEqual(other.Markings); + } - return new HumanoidCharacterAppearance( - hairStyleId, - hairColor, - facialHairStyleId, - facialHairColor, - eyeColor, - skinColor, - markingSet.GetForwardEnumerator().ToList()); - } + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) + || obj is HumanoidCharacterAppearance other + && Equals(other); + } - public bool MemberwiseEquals(ICharacterAppearance maybeOther) - { - if (maybeOther is not HumanoidCharacterAppearance other) return false; - if (HairStyleId != other.HairStyleId) return false; - if (!HairColor.Equals(other.HairColor)) return false; - if (FacialHairStyleId != other.FacialHairStyleId) return false; - if (!FacialHairColor.Equals(other.FacialHairColor)) return false; - if (!EyeColor.Equals(other.EyeColor)) return false; - if (!SkinColor.Equals(other.SkinColor)) return false; - if (!Markings.SequenceEqual(other.Markings)) return false; - return true; - } + public override int GetHashCode() + { + return HashCode.Combine( + HairStyleId, + HairColor, + FacialHairStyleId, + FacialHairColor, + EyeColor, + SkinColor, + Markings); } + + public HumanoidCharacterAppearance Clone() => new(this); } diff --git a/Content.Shared/Humanoid/HumanoidProfileExport.cs b/Content.Shared/Humanoid/HumanoidProfileExport.cs new file mode 100644 index 00000000000..4f020cce19a --- /dev/null +++ b/Content.Shared/Humanoid/HumanoidProfileExport.cs @@ -0,0 +1,17 @@ +using Content.Shared.Preferences; + +namespace Content.Shared.Humanoid; + +/// Holds all of the data for importing / exporting character profiles. +[DataDefinition] +public sealed partial class HumanoidProfileExport +{ + [DataField] + public string ForkId; + + [DataField] + public int Version = 1; + + [DataField(required: true)] + public HumanoidCharacterProfile Profile = default!; +} diff --git a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs index ce49f80af3b..81546678307 100644 --- a/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs +++ b/Content.Shared/Humanoid/SharedHumanoidAppearanceSystem.cs @@ -1,3 +1,4 @@ +using System.IO; using System.Linq; using System.Numerics; using Content.Shared.Decals; @@ -7,9 +8,17 @@ using Content.Shared.IdentityManagement; using Content.Shared.Preferences; using Content.Shared.HeightAdjust; +using Microsoft.Extensions.Configuration; +using Robust.Shared; +using Robust.Shared.Configuration; using Robust.Shared.GameObjects.Components.Localization; using Robust.Shared.Network; +using Robust.Shared.Player; using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Serialization.Markdown; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; namespace Content.Shared.Humanoid; @@ -24,9 +33,11 @@ namespace Content.Shared.Humanoid; /// public abstract class SharedHumanoidAppearanceSystem : EntitySystem { + [Dependency] private readonly IConfigurationManager _cfgManager = default!; [Dependency] private readonly INetManager _netManager = default!; [Dependency] private readonly IPrototypeManager _proto = default!; [Dependency] private readonly MarkingManager _markingManager = default!; + [Dependency] private readonly ISerializationManager _serManager = default!; [Dependency] private readonly HeightAdjustSystem _heightAdjust = default!; [ValidatePrototypeId] @@ -40,12 +51,39 @@ public override void Initialize() SubscribeLocalEvent(OnExamined); } + public DataNode ToDataNode(HumanoidCharacterProfile profile) + { + var export = new HumanoidProfileExport + { + ForkId = _cfgManager.GetCVar(CVars.BuildForkId), + Profile = profile, + }; + + var dataNode = _serManager.WriteValue(export, alwaysWrite: true, notNullableOverride: true); + return dataNode; + } + + public HumanoidCharacterProfile FromStream(Stream stream, ICommonSession session) + { + using var reader = new StreamReader(stream, EncodingHelpers.UTF8); + var yamlStream = new YamlStream(); + yamlStream.Load(reader); + + var root = yamlStream.Documents[0].RootNode; + var export = _serManager.Read(root.ToDataNode(), notNullableOverride: true); + + // Add custom handling here for forks / version numbers if you care + + var profile = export.Profile; + var collection = IoCManager.Instance; + profile.EnsureValid(session, collection!); + return profile; + } + private void OnInit(EntityUid uid, HumanoidAppearanceComponent humanoid, ComponentInit args) { if (string.IsNullOrEmpty(humanoid.Species) || _netManager.IsClient && !IsClientSide(uid)) - { return; - } if (string.IsNullOrEmpty(humanoid.Initial) || !_proto.TryIndex(humanoid.Initial, out HumanoidProfilePrototype? startingSet)) @@ -56,9 +94,7 @@ private void OnInit(EntityUid uid, HumanoidAppearanceComponent humanoid, Compone // Do this first, because profiles currently do not support custom base layers foreach (var (layer, info) in startingSet.CustomBaseLayers) - { humanoid.CustomBaseLayers.Add(layer, info); - } LoadProfile(uid, startingSet.Profile, humanoid); } @@ -110,9 +146,7 @@ public void SetLayersVisibility(EntityUid uid, IEnumerable var dirty = false; foreach (var layer in layers) - { SetLayerVisibility(uid, humanoid, layer, visible, permanent, ref dirty); - } if (dirty) Dirty(humanoid); @@ -153,9 +187,7 @@ protected virtual void SetLayerVisibility( public void SetSpecies(EntityUid uid, string species, bool sync = true, HumanoidAppearanceComponent? humanoid = null) { if (!Resolve(uid, ref humanoid) || !_proto.TryIndex(species, out var prototype)) - { return; - } humanoid.Species = species; humanoid.MarkingSet.EnsureSpecies(species, humanoid.SkinColor, _markingManager); @@ -181,14 +213,10 @@ public virtual void SetSkinColor(EntityUid uid, Color skinColor, bool sync = tru return; if (!_proto.TryIndex(humanoid.Species, out var species)) - { return; - } if (verify && !SkinColor.VerifySkinColor(species.SkinColoration, skinColor)) - { skinColor = SkinColor.ValidSkinTone(species.SkinColoration, skinColor); - } humanoid.SkinColor = skinColor; @@ -259,9 +287,7 @@ public void SetSex(EntityUid uid, Sex sex, bool sync = true, HumanoidAppearanceC RaiseLocalEvent(uid, new SexChangedEvent(oldSex, sex)); if (sync) - { Dirty(humanoid); - } } /// @@ -328,15 +354,10 @@ public void SetScale(EntityUid uid, Vector2 scale, bool sync = true, HumanoidApp /// The mob's entity UID. /// The character profile to load. /// Humanoid component of the entity - public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile? profile, HumanoidAppearanceComponent? humanoid = null) + public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile profile, HumanoidAppearanceComponent? humanoid = null) { - if (profile == null) - return; - if (!Resolve(uid, ref humanoid)) - { return; - } SetSpecies(uid, profile.Species, false, humanoid); SetSex(uid, profile.Sex, false, humanoid); @@ -353,13 +374,9 @@ public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile? profile if (_markingManager.TryGetMarking(marking, out var prototype)) { if (!prototype.ForcedColoring) - { AddMarking(uid, marking.MarkingId, marking.MarkingColors, false); - } else - { markingFColored.Add(marking, prototype); - } } } @@ -372,15 +389,11 @@ public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile? profile if (_markingManager.Markings.TryGetValue(profile.Appearance.HairStyleId, out var hairPrototype) && _markingManager.CanBeApplied(profile.Species, profile.Sex, hairPrototype, _proto)) - { AddMarking(uid, profile.Appearance.HairStyleId, hairColor, false); - } if (_markingManager.Markings.TryGetValue(profile.Appearance.FacialHairStyleId, out var facialHairPrototype) && _markingManager.CanBeApplied(profile.Species, profile.Sex, facialHairPrototype, _proto)) - { AddMarking(uid, profile.Appearance.FacialHairStyleId, facialHairColor, false); - } humanoid.MarkingSet.EnsureSpecies(profile.Species, profile.Appearance.SkinColor, _markingManager, _proto); @@ -400,9 +413,7 @@ public virtual void LoadProfile(EntityUid uid, HumanoidCharacterProfile? profile humanoid.Gender = profile.Gender; if (TryComp(uid, out var grammar)) - { grammar.Gender = profile.Gender; - } humanoid.Age = profile.Age; @@ -426,9 +437,7 @@ public void AddMarking(EntityUid uid, string marking, Color? color = null, bool { if (!Resolve(uid, ref humanoid) || !_markingManager.Markings.TryGetValue(marking, out var prototype)) - { return; - } var markingObject = prototype.AsMarking(); markingObject.Forced = forced; @@ -449,9 +458,7 @@ public void AddMarking(EntityUid uid, string marking, Color? color = null, bool private void EnsureDefaultMarkings(EntityUid uid, HumanoidAppearanceComponent? humanoid) { if (!Resolve(uid, ref humanoid)) - { return; - } humanoid.MarkingSet.EnsureDefault(humanoid.SkinColor, humanoid.EyeColor, _markingManager); } @@ -468,9 +475,7 @@ public void AddMarking(EntityUid uid, string marking, IReadOnlyList color { if (!Resolve(uid, ref humanoid) || !_markingManager.Markings.TryGetValue(marking, out var prototype)) - { return; - } var markingObject = new Marking(marking, colors); markingObject.Forced = forced; @@ -486,9 +491,7 @@ public void AddMarking(EntityUid uid, string marking, IReadOnlyList color public string GetSpeciesRepresentation(string speciesId) { if (_proto.TryIndex(speciesId, out var species)) - { return Loc.GetString(species.Name); - } Log.Error("Tried to get representation of unknown species: {speciesId}"); return Loc.GetString("humanoid-appearance-component-unknown-species"); @@ -503,14 +506,10 @@ public string GetAgeRepresentation(string species, int age) } if (age < speciesPrototype.YoungAge) - { return Loc.GetString("identity-age-young"); - } if (age < speciesPrototype.OldAge) - { return Loc.GetString("identity-age-middle-aged"); - } return Loc.GetString("identity-age-old"); } diff --git a/Content.Shared/Humanoid/SkinColor.cs b/Content.Shared/Humanoid/SkinColor.cs index dcc5c2d7645..64ad82ac982 100644 --- a/Content.Shared/Humanoid/SkinColor.cs +++ b/Content.Shared/Humanoid/SkinColor.cs @@ -1,3 +1,6 @@ +using System.Security.Cryptography; +using Microsoft.VisualBasic.CompilerServices; + namespace Content.Shared.Humanoid; public static class SkinColor @@ -7,6 +10,13 @@ public static class SkinColor public const float MinHuesLightness = 0.175f; + public const float MinFeathersHue = 29f / 360; + public const float MaxFeathersHue = 174f / 360; + public const float MinFeathersSaturation = 20f / 100; + public const float MaxFeathersSaturation = 88f / 100; + public const float MinFeathersValue = 36f / 100; + public const float MaxFeathersValue = 55f / 100; + public static Color ValidHumanSkinTone => Color.FromHsv(new Vector4(0.07f, 0.2f, 1f, 1f)); /// @@ -159,6 +169,60 @@ public static bool VerifyTintedHues(Color color) return Color.ToHsl(color).Y <= MaxTintedHuesSaturation && Color.ToHsl(color).Z >= MinTintedHuesLightness; } + /// + /// Converts a Color proportionally to the allowed vox color range. + /// Will NOT preserve the specific input color even if it is within the allowed vox color range. + /// + /// Color to convert + /// Vox feather coloration + public static Color ProportionalVoxColor(Color color) + { + var newColor = Color.ToHsv(color); + + newColor.X = newColor.X * (MaxFeathersHue - MinFeathersHue) + MinFeathersHue; + newColor.Y = newColor.Y * (MaxFeathersSaturation - MinFeathersSaturation) + MinFeathersSaturation; + newColor.Z = newColor.Z * (MaxFeathersValue - MinFeathersValue) + MinFeathersValue; + + return Color.FromHsv(newColor); + } + + // /// + // /// Ensures the input Color is within the allowed vox color range. + // /// + // /// Color to convert + // /// The same Color if it was within the allowed range, or the closest matching Color otherwise + public static Color ClosestVoxColor(Color color) + { + var hsv = Color.ToHsv(color); + + hsv.X = Math.Clamp(hsv.X, MinFeathersHue, MaxFeathersHue); + hsv.Y = Math.Clamp(hsv.Y, MinFeathersSaturation, MaxFeathersSaturation); + hsv.Z = Math.Clamp(hsv.Z, MinFeathersValue, MaxFeathersValue); + + return Color.FromHsv(hsv); + } + + /// + /// Verify if this color is a valid vox feather coloration, or not. + /// + /// The color to verify + /// True if valid, false otherwise + public static bool VerifyVoxFeathers(Color color) + { + var colorHsv = Color.ToHsv(color); + + if (colorHsv.X < MinFeathersHue || colorHsv.X > MaxFeathersHue) + return false; + + if (colorHsv.Y < MinFeathersSaturation || colorHsv.Y > MaxFeathersSaturation) + return false; + + if (colorHsv.Z < MinFeathersValue || colorHsv.Z > MaxFeathersValue) + return false; + + return true; + } + /// /// This takes in a color, and returns a color guaranteed to be above MinHuesLightness /// @@ -189,6 +253,7 @@ public static bool VerifySkinColor(HumanoidSkinColor type, Color color) HumanoidSkinColor.TintedHues => VerifyTintedHues(color), HumanoidSkinColor.TintedHuesSkin => true, // DeltaV - Tone blending HumanoidSkinColor.Hues => VerifyHues(color), + HumanoidSkinColor.VoxFeathers => VerifyVoxFeathers(color), _ => false, }; } @@ -201,6 +266,7 @@ public static Color ValidSkinTone(HumanoidSkinColor type, Color color) HumanoidSkinColor.TintedHues => ValidTintedHuesSkinTone(color), HumanoidSkinColor.TintedHuesSkin => ValidTintedHuesSkinTone(color), // DeltaV - Tone blending HumanoidSkinColor.Hues => MakeHueValid(color), + HumanoidSkinColor.VoxFeathers => ClosestVoxColor(color), _ => color }; } @@ -210,6 +276,7 @@ public enum HumanoidSkinColor : byte { HumanToned, Hues, + VoxFeathers, // Vox feathers are limited to a specific color range TintedHues, //This gives a color tint to a humanoid's skin (10% saturation with full hue range). TintedHuesSkin, // DeltaV - Default TintedHues assumes the texture will have the proper skin color, but moths dont } diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs index f85983282c7..9f1370115da 100644 --- a/Content.Shared/Input/ContentKeyFunctions.cs +++ b/Content.Shared/Input/ContentKeyFunctions.cs @@ -25,6 +25,7 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction CycleChatChannelBackward = "CycleChatChannelBackward"; public static readonly BoundKeyFunction EscapeContext = "EscapeContext"; public static readonly BoundKeyFunction OpenCharacterMenu = "OpenCharacterMenu"; + public static readonly BoundKeyFunction OpenEmotesMenu = "OpenEmotesMenu"; public static readonly BoundKeyFunction OpenLanguageMenu = "OpenLanguageMenu"; public static readonly BoundKeyFunction OpenCraftingMenu = "OpenCraftingMenu"; public static readonly BoundKeyFunction OpenGuidebook = "OpenGuidebook"; @@ -43,6 +44,7 @@ public static class ContentKeyFunctions public static readonly BoundKeyFunction MovePulledObject = "MovePulledObject"; public static readonly BoundKeyFunction ReleasePulledObject = "ReleasePulledObject"; public static readonly BoundKeyFunction MouseMiddle = "MouseMiddle"; + public static readonly BoundKeyFunction ToggleRoundEndSummaryWindow = "ToggleRoundEndSummaryWindow"; public static readonly BoundKeyFunction OpenEntitySpawnWindow = "OpenEntitySpawnWindow"; public static readonly BoundKeyFunction OpenSandboxWindow = "OpenSandboxWindow"; public static readonly BoundKeyFunction OpenTileSpawnWindow = "OpenTileSpawnWindow"; diff --git a/Content.Shared/Interaction/Components/ClumsyComponent.cs b/Content.Shared/Interaction/Components/ClumsyComponent.cs index 5b72fc224c8..824696c8385 100644 --- a/Content.Shared/Interaction/Components/ClumsyComponent.cs +++ b/Content.Shared/Interaction/Components/ClumsyComponent.cs @@ -1,22 +1,24 @@ using Content.Shared.Damage; using Robust.Shared.Audio; +using Robust.Shared.GameStates; -namespace Content.Shared.Interaction.Components +namespace Content.Shared.Interaction.Components; + +/// +/// A simple clumsy tag-component. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ClumsyComponent : Component { /// - /// A simple clumsy tag-component. + /// Damage dealt to a clumsy character when they try to fire a gun. /// - [RegisterComponent] - public sealed partial class ClumsyComponent : Component - { - [DataField("clumsyDamage", required: true)] - [ViewVariables(VVAccess.ReadWrite)] - public DamageSpecifier ClumsyDamage = default!; + [DataField(required: true), AutoNetworkedField] + public DamageSpecifier ClumsyDamage = default!; - /// - /// Sound to play when clumsy interactions fail - /// - [DataField("clumsySound")] - public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg"); - } + /// + /// Sound to play when clumsy interactions fail. + /// + [DataField] + public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg"); } diff --git a/Content.Shared/Interaction/SharedInteractionSystem.cs b/Content.Shared/Interaction/SharedInteractionSystem.cs index 8d49ce31f0a..1f421d0e6f7 100644 --- a/Content.Shared/Interaction/SharedInteractionSystem.cs +++ b/Content.Shared/Interaction/SharedInteractionSystem.cs @@ -76,8 +76,11 @@ public abstract partial class SharedInteractionSystem : EntitySystem public override void Initialize() { + SubscribeLocalEvent(HandleUserInterfaceRangeCheck); SubscribeLocalEvent(OnBoundInterfaceInteractAttempt); + SubscribeAllEvent(HandleInteractInventorySlotEvent); + SubscribeLocalEvent(OnRemoveAttempt); SubscribeLocalEvent(OnUnequip); SubscribeLocalEvent(OnUnequipHand); @@ -108,7 +111,9 @@ public override void Shutdown() /// private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev) { - if (ev.Sender.AttachedEntity is not { } user || !_actionBlockerSystem.CanInteract(user, ev.Target)) + var user = ev.Actor; + + if (!_actionBlockerSystem.CanInteract(user, ev.Target)) { ev.Cancel(); return; @@ -973,8 +978,8 @@ public bool InteractionActivate( return false; DoContactInteraction(user, used, activateMsg); - if (delayComponent != null) - _useDelay.TryResetDelay((used, delayComponent)); + // Still need to call this even without checkUseDelay in case this gets relayed from Activate. + _useDelay.TryResetDelay(used, component: delayComponent); if (!activateMsg.WasLogged) _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(user):user} activated {ToPrettyString(used):used}"); return true; @@ -1145,6 +1150,21 @@ public void DoContactInteraction(EntityUid uidA, EntityUid? uidB, HandledEntityE RaiseLocalEvent(uidA, new ContactInteractionEvent(uidB.Value)); RaiseLocalEvent(uidB.Value, new ContactInteractionEvent(uidA)); } + + private void HandleUserInterfaceRangeCheck(ref BoundUserInterfaceCheckRangeEvent ev) + { + if (ev.Result == BoundUserInterfaceRangeResult.Fail) + return; + + if (InRangeUnobstructed(ev.Actor, ev.Target, ev.Data.InteractionRange)) + { + ev.Result = BoundUserInterfaceRangeResult.Pass; + } + else + { + ev.Result = BoundUserInterfaceRangeResult.Fail; + } + } } /// diff --git a/Content.Shared/Inventory/Events/UnequippedEvents.cs b/Content.Shared/Inventory/Events/UnequippedEvents.cs index ef607f071af..4e1764a7d2d 100644 --- a/Content.Shared/Inventory/Events/UnequippedEvents.cs +++ b/Content.Shared/Inventory/Events/UnequippedEvents.cs @@ -22,12 +22,18 @@ public abstract class UnequippedEventBase : EntityEventArgs /// public readonly string SlotGroup; + /// + /// Slotflags of the slot the entity just got unequipped from. + /// + public readonly SlotFlags SlotFlags; + public UnequippedEventBase(EntityUid equipee, EntityUid equipment, SlotDefinition slotDefinition) { Equipee = equipee; Equipment = equipment; Slot = slotDefinition.Name; SlotGroup = slotDefinition.SlotGroup; + SlotFlags = slotDefinition.SlotFlags; } } diff --git a/Content.Shared/Inventory/InventoryComponent.cs b/Content.Shared/Inventory/InventoryComponent.cs index 2a8710f0f28..02b3a5b2583 100644 --- a/Content.Shared/Inventory/InventoryComponent.cs +++ b/Content.Shared/Inventory/InventoryComponent.cs @@ -13,6 +13,18 @@ public sealed partial class InventoryComponent : Component [DataField("speciesId")] public string? SpeciesId { get; set; } + [DataField] public Dictionary Displacements = []; + public SlotDefinition[] Slots = Array.Empty(); public ContainerSlot[] Containers = Array.Empty(); + + [DataDefinition] + public sealed partial class SlotDisplacementData + { + [DataField(required: true)] + public PrototypeLayerData Layer = default!; + + [DataField] + public string? ShaderOverride = "DisplacedStencilDraw"; + } } diff --git a/Content.Shared/Inventory/InventorySystem.Equip.cs b/Content.Shared/Inventory/InventorySystem.Equip.cs index 7bdd17ee6fa..68308d2b884 100644 --- a/Content.Shared/Inventory/InventorySystem.Equip.cs +++ b/Content.Shared/Inventory/InventorySystem.Equip.cs @@ -1,4 +1,5 @@ using System.Diagnostics.CodeAnalysis; +using Content.Shared.Armor; using Content.Shared.Clothing.Components; using Content.Shared.DoAfter; using Content.Shared.Hands; @@ -114,7 +115,7 @@ private void OnUseSlot(UseSlotNetworkMessage ev, EntitySessionEventArgs eventArg if (!_handsSystem.CanDropHeld(actor, hands.ActiveHand!, checkActionBlocker: false)) return; - RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor), false); + RaiseLocalEvent(held.Value, new HandDeselectedEvent(actor)); TryEquip(actor, actor, held.Value, ev.Slot, predicted: true, inventory: inventory, force: true, checkDoafter:true); } @@ -244,8 +245,16 @@ public bool CanEquip(EntityUid actor, EntityUid target, EntityUid itemUid, strin return false; DebugTools.Assert(slotDefinition.Name == slot); - if (slotDefinition.DependsOn != null && !TryGetSlotEntity(target, slotDefinition.DependsOn, out _, inventory)) - return false; + if (slotDefinition.DependsOn != null) + { + if (!TryGetSlotEntity(target, slotDefinition.DependsOn, out EntityUid? slotEntity, inventory)) + return false; + + if (slotDefinition.DependsOnComponents is { } componentRegistry) + foreach (var (_, entry) in componentRegistry) + if (!HasComp(slotEntity, entry.Component.GetType())) + return false; + } var fittingInPocket = slotDefinition.SlotFlags.HasFlag(SlotFlags.POCKET) && item != null && @@ -302,7 +311,6 @@ public bool CanEquip(EntityUid actor, EntityUid target, EntityUid itemUid, strin reason = itemAttemptEvent.Reason ?? reason; return false; } - return true; } diff --git a/Content.Shared/Inventory/InventorySystem.Relay.cs b/Content.Shared/Inventory/InventorySystem.Relay.cs index 3308e881c52..b9d6a51f886 100644 --- a/Content.Shared/Inventory/InventorySystem.Relay.cs +++ b/Content.Shared/Inventory/InventorySystem.Relay.cs @@ -40,12 +40,14 @@ public void InitializeRelay() SubscribeLocalEvent(RelayInventoryEvent); // ComponentActivatedClientSystems - SubscribeLocalEvent>(RelayInventoryEvent); + SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); + SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(RelayInventoryEvent); + SubscribeLocalEvent>(RelayInventoryEvent); SubscribeLocalEvent>(OnGetEquipmentVerbs); } @@ -123,6 +125,11 @@ public InventoryRelayedEvent(TEvent args) } } +public interface IClothingSlots +{ + SlotFlags Slots { get; } +} + /// /// Events that should be relayed to inventory slots should implement this interface. /// diff --git a/Content.Shared/Inventory/InventorySystem.Slots.cs b/Content.Shared/Inventory/InventorySystem.Slots.cs index cbbee3a85bd..e0f2a695576 100644 --- a/Content.Shared/Inventory/InventorySystem.Slots.cs +++ b/Content.Shared/Inventory/InventorySystem.Slots.cs @@ -1,4 +1,6 @@ using System.Diagnostics.CodeAnalysis; +using Content.Shared.Inventory.Events; +using Content.Shared.Storage; using Robust.Shared.Containers; using Robust.Shared.Prototypes; using Robust.Shared.Utility; @@ -13,6 +15,7 @@ public partial class InventorySystem : EntitySystem private void InitializeSlots() { SubscribeLocalEvent(OnInit); + SubscribeNetworkEvent(OnOpenSlotStorage); _vvm.GetTypeHandler() .AddHandler(HandleViewVariablesSlots, ListViewVariablesSlots); @@ -24,6 +27,31 @@ private void ShutdownSlots() .RemoveHandler(HandleViewVariablesSlots, ListViewVariablesSlots); } + /// + /// Tries to find an entity in the specified slot with the specified component. + /// + public bool TryGetInventoryEntity(Entity entity, out EntityUid targetUid) + where T : IComponent, IClothingSlots + { + if (TryGetContainerSlotEnumerator(entity.Owner, out var containerSlotEnumerator)) + { + while (containerSlotEnumerator.NextItem(out var item, out var slot)) + { + if (!TryComp(item, out var required)) + continue; + + if ((((IClothingSlots) required).Slots & slot.SlotFlags) == 0x0) + continue; + + targetUid = item; + return true; + } + } + + targetUid = EntityUid.Invalid; + return false; + } + protected virtual void OnInit(EntityUid uid, InventoryComponent component, ComponentInit args) { if (!_prototypeManager.TryIndex(component.TemplateId, out InventoryTemplatePrototype? invTemplate)) @@ -40,6 +68,17 @@ protected virtual void OnInit(EntityUid uid, InventoryComponent component, Compo } } + private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev, EntitySessionEventArgs args) + { + if (args.SenderSession.AttachedEntity is not { Valid: true } uid) + return; + + if (TryGetSlotEntity(uid, ev.Slot, out var entityUid) && TryComp(entityUid, out var storageComponent)) + { + _storageSystem.OpenStorageUI(entityUid.Value, uid, storageComponent); + } + } + public bool TryGetSlotContainer(EntityUid uid, string slot, [NotNullWhen(true)] out ContainerSlot? containerSlot, [NotNullWhen(true)] out SlotDefinition? slotDefinition, InventoryComponent? inventory = null, ContainerManagerComponent? containerComp = null) { @@ -112,7 +151,6 @@ public bool TryGetSlots(EntityUid uid, [NotNullWhen(true)] out SlotDefinition[]? slotDefinitions = null; return false; } - slotDefinitions = inv.Slots; return true; } diff --git a/Content.Shared/Inventory/InventoryTemplatePrototype.cs b/Content.Shared/Inventory/InventoryTemplatePrototype.cs index 585f80d4ce9..a4d77767e37 100644 --- a/Content.Shared/Inventory/InventoryTemplatePrototype.cs +++ b/Content.Shared/Inventory/InventoryTemplatePrototype.cs @@ -17,6 +17,10 @@ public sealed partial class SlotDefinition { [DataField("name", required: true)] public string Name { get; private set; } = string.Empty; [DataField("slotTexture")] public string TextureName { get; private set; } = "pocket"; + /// + /// The texture displayed in a slot when it has an item inside of it. + /// + [DataField] public string FullTextureName { get; private set; } = "SlotBackground"; [DataField("slotFlags")] public SlotFlags SlotFlags { get; private set; } = SlotFlags.PREVENTEQUIP; [DataField("showInWindow")] public bool ShowInWindow { get; private set; } = true; [DataField("slotGroup")] public string SlotGroup { get; private set; } = "Default"; @@ -30,6 +34,8 @@ public sealed partial class SlotDefinition [DataField("dependsOn")] public string? DependsOn { get; private set; } + [DataField("dependsOnComponents")] public ComponentRegistry? DependsOnComponents { get; private set; } + [DataField("displayName", required: true)] public string DisplayName { get; private set; } = string.Empty; diff --git a/Content.Shared/Inventory/SlotFlags.cs b/Content.Shared/Inventory/SlotFlags.cs index 8d5e33e3486..90971d1670b 100644 --- a/Content.Shared/Inventory/SlotFlags.cs +++ b/Content.Shared/Inventory/SlotFlags.cs @@ -27,4 +27,6 @@ public enum SlotFlags FEET = 1 << 14, SUITSTORAGE = 1 << 15, All = ~NONE, + + WITHOUT_POCKET = All & ~POCKET } diff --git a/Content.Shared/Labels/Components/HandLabelerComponent.cs b/Content.Shared/Labels/Components/HandLabelerComponent.cs new file mode 100644 index 00000000000..8e2cb7b0675 --- /dev/null +++ b/Content.Shared/Labels/Components/HandLabelerComponent.cs @@ -0,0 +1,30 @@ +using Content.Shared.Labels.EntitySystems; +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared.Labels.Components; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedHandLabelerSystem))] +public sealed partial class HandLabelerComponent : Component +{ + [ViewVariables(VVAccess.ReadWrite), Access(Other = AccessPermissions.ReadWriteExecute)] + [DataField] + public string AssignedLabel = string.Empty; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public int MaxLabelChars = 50; + + [DataField] + public EntityWhitelist Whitelist = new(); +} + +[Serializable, NetSerializable] +public sealed class HandLabelerComponentState(string assignedLabel) : IComponentState +{ + public string AssignedLabel = assignedLabel; + + public int MaxLabelChars; +} diff --git a/Content.Shared/Labels/EntitySystems/SharedHandLabelerSystem.cs b/Content.Shared/Labels/EntitySystems/SharedHandLabelerSystem.cs new file mode 100644 index 00000000000..7dbeee3e770 --- /dev/null +++ b/Content.Shared/Labels/EntitySystems/SharedHandLabelerSystem.cs @@ -0,0 +1,129 @@ +using Content.Shared.Administration.Logs; +using Content.Shared.Database; +using Content.Shared.Interaction; +using Content.Shared.Labels.Components; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.GameStates; +using Robust.Shared.Network; + +namespace Content.Shared.Labels.EntitySystems; + +public abstract class SharedHandLabelerSystem : EntitySystem +{ + [Dependency] protected readonly SharedUserInterfaceSystem UserInterfaceSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedLabelSystem _labelSystem = default!; + [Dependency] private readonly ISharedAdminLogManager _adminLogger = default!; + [Dependency] private readonly INetManager _netManager = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(AfterInteractOn); + SubscribeLocalEvent>(OnUtilityVerb); + // Bound UI subscriptions + SubscribeLocalEvent(OnHandLabelerLabelChanged); + SubscribeLocalEvent(OnGetState); + SubscribeLocalEvent(OnHandleState); + } + + private void OnGetState(Entity ent, ref ComponentGetState args) + { + args.State = new HandLabelerComponentState(ent.Comp.AssignedLabel) + { + MaxLabelChars = ent.Comp.MaxLabelChars, + }; + } + + private void OnHandleState(Entity ent, ref ComponentHandleState args) + { + if (args.Current is not HandLabelerComponentState state) + return; + + ent.Comp.MaxLabelChars = state.MaxLabelChars; + + if (ent.Comp.AssignedLabel == state.AssignedLabel) + return; + + ent.Comp.AssignedLabel = state.AssignedLabel; + UpdateUI(ent); + } + + protected virtual void UpdateUI(Entity ent) + { + } + + private void AddLabelTo(EntityUid uid, HandLabelerComponent? handLabeler, EntityUid target, out string? result) + { + if (!Resolve(uid, ref handLabeler)) + { + result = null; + return; + } + + if (handLabeler.AssignedLabel == string.Empty) + { + if (_netManager.IsServer) + _labelSystem.Label(target, null); + result = Loc.GetString("hand-labeler-successfully-removed"); + return; + } + if (_netManager.IsServer) + _labelSystem.Label(target, handLabeler.AssignedLabel); + result = Loc.GetString("hand-labeler-successfully-applied"); + } + + private void OnUtilityVerb(EntityUid uid, HandLabelerComponent handLabeler, GetVerbsEvent args) + { + if (args.Target is not { Valid: true } target || !handLabeler.Whitelist.IsValid(target) || !args.CanAccess) + return; + + var labelerText = handLabeler.AssignedLabel == string.Empty ? Loc.GetString("hand-labeler-remove-label-text") : Loc.GetString("hand-labeler-add-label-text"); + + var verb = new UtilityVerb() + { + Act = () => + { + Labeling(uid, target, args.User, handLabeler); + }, + Text = labelerText + }; + + args.Verbs.Add(verb); + } + + private void AfterInteractOn(EntityUid uid, HandLabelerComponent handLabeler, AfterInteractEvent args) + { + if (args.Target is not { Valid: true } target || !handLabeler.Whitelist.IsValid(target) || !args.CanReach) + return; + + Labeling(uid, target, args.User, handLabeler); + } + + private void Labeling(EntityUid uid, EntityUid target, EntityUid User, HandLabelerComponent handLabeler) + { + AddLabelTo(uid, handLabeler, target, out var result); + if (result == null) + return; + + _popupSystem.PopupClient(result, User, User); + + // Log labeling + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(User):user} labeled {ToPrettyString(target):target} with {ToPrettyString(uid):labeler}"); + } + + private void OnHandLabelerLabelChanged(EntityUid uid, HandLabelerComponent handLabeler, HandLabelerLabelChangedMessage args) + { + var label = args.Label.Trim(); + handLabeler.AssignedLabel = label[..Math.Min(handLabeler.MaxLabelChars, label.Length)]; + UpdateUI((uid, handLabeler)); + Dirty(uid, handLabeler); + + // Log label change + _adminLogger.Add(LogType.Action, LogImpact.Low, + $"{ToPrettyString(args.Actor):user} set {ToPrettyString(uid):labeler} to apply label \"{handLabeler.AssignedLabel}\""); + } +} diff --git a/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs b/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs index a8239e7867b..1189bb46d04 100644 --- a/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs +++ b/Content.Shared/Labels/EntitySystems/SharedLabelSystem.cs @@ -13,6 +13,8 @@ public override void Initialize() SubscribeLocalEvent(OnExamine); } + public virtual void Label(EntityUid uid, string? text, MetaDataComponent? metadata = null, LabelComponent? label = null){} + private void OnExamine(EntityUid uid, LabelComponent? label, ExaminedEvent args) { if (!Resolve(uid, ref label)) diff --git a/Content.Shared/Labels/LabelEvents.cs b/Content.Shared/Labels/LabelEvents.cs index 9f00354af24..62e9c15c85e 100644 --- a/Content.Shared/Labels/LabelEvents.cs +++ b/Content.Shared/Labels/LabelEvents.cs @@ -1,47 +1,27 @@ using Robust.Shared.Serialization; -namespace Content.Shared.Labels -{ - /// - /// Key representing which is currently open. - /// Useful when there are multiple UI for an object. Here it's future-proofing only. - /// - [Serializable, NetSerializable] - public enum HandLabelerUiKey - { - Key, - } - - [Serializable, NetSerializable] - public enum PaperLabelVisuals : byte - { - Layer, - HasLabel, - LabelType - } +namespace Content.Shared.Labels; - /// - /// Represents a state that can be sent to the client - /// - [Serializable, NetSerializable] - public sealed class HandLabelerBoundUserInterfaceState : BoundUserInterfaceState - { - public string CurrentLabel { get; } - - public HandLabelerBoundUserInterfaceState(string currentLabel) - { - CurrentLabel = currentLabel; - } - } +/// +/// Key representing which is currently open. +/// Useful when there are multiple UI for an object. Here it's future-proofing only. +/// +[Serializable, NetSerializable] +public enum HandLabelerUiKey +{ + Key, +} - [Serializable, NetSerializable] - public sealed class HandLabelerLabelChangedMessage : BoundUserInterfaceMessage - { - public string Label { get; } +[Serializable, NetSerializable] +public enum PaperLabelVisuals : byte +{ + Layer, + HasLabel, + LabelType +} - public HandLabelerLabelChangedMessage(string label) - { - Label = label; - } - } +[Serializable, NetSerializable] +public sealed class HandLabelerLabelChangedMessage(string label) : BoundUserInterfaceMessage +{ + public string Label { get; } = label; } diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs index d40a7b40681..2137e4e838f 100644 --- a/Content.Shared/Language/LanguagePrototype.cs +++ b/Content.Shared/Language/LanguagePrototype.cs @@ -4,7 +4,7 @@ namespace Content.Shared.Language; [Prototype("language")] -public sealed class LanguagePrototype : IPrototype +public sealed partial class LanguagePrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; diff --git a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs index e40174ab783..001794880ac 100644 --- a/Content.Shared/Light/Components/SharedExpendableLightComponent.cs +++ b/Content.Shared/Light/Components/SharedExpendableLightComponent.cs @@ -7,7 +7,6 @@ namespace Content.Shared.Light.Components; [NetworkedComponent] public abstract partial class SharedExpendableLightComponent : Component { - public static readonly AudioParams LoopedSoundParams = new(0, 1, 62.5f, 1, 1, true, 0.3f); [ViewVariables(VVAccess.ReadOnly)] public ExpendableLightState CurrentState { get; set; } diff --git a/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs b/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs index 1b0701edd2c..2953a01ced8 100644 --- a/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs +++ b/Content.Shared/Light/Components/UnpoweredFlashlightComponent.cs @@ -2,7 +2,6 @@ using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Light.Components; @@ -17,7 +16,7 @@ public sealed partial class UnpoweredFlashlightComponent : Component public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/Items/flashlight_pda.ogg"); [DataField, AutoNetworkedField] - public bool LightOn = false; + public bool LightOn; [DataField] public EntProtoId ToggleAction = "ActionToggleLight"; diff --git a/Content.Shared/Light/EntitySystems/UnpoweredFlashlightSystem.cs b/Content.Shared/Light/EntitySystems/UnpoweredFlashlightSystem.cs new file mode 100644 index 00000000000..42e55bea55d --- /dev/null +++ b/Content.Shared/Light/EntitySystems/UnpoweredFlashlightSystem.cs @@ -0,0 +1,122 @@ +using Content.Shared.Actions; +using Content.Shared.Emag.Systems; +using Content.Shared.Light.Components; +using Content.Shared.Mind.Components; +using Content.Shared.Toggleable; +using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; +using Robust.Shared.Utility; + +namespace Content.Shared.Light.EntitySystems; + +public sealed class UnpoweredFlashlightSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audioSystem = default!; + [Dependency] private readonly SharedPointLightSystem _light = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(AddToggleLightVerbs); + SubscribeLocalEvent(OnGetActions); + SubscribeLocalEvent(OnToggleAction); + SubscribeLocalEvent(OnMindAdded); + SubscribeLocalEvent(OnGotEmagged); + SubscribeLocalEvent(OnMapInit); + } + + private void OnMapInit(EntityUid uid, UnpoweredFlashlightComponent component, MapInitEvent args) + { + _actionContainer.EnsureAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + Dirty(uid, component); + } + + private void OnToggleAction(EntityUid uid, UnpoweredFlashlightComponent component, ToggleActionEvent args) + { + if (args.Handled) + return; + + TryToggleLight((uid, component), args.Performer); + args.Handled = true; + } + + private void OnGetActions(EntityUid uid, UnpoweredFlashlightComponent component, GetItemActionsEvent args) + { + args.AddAction(component.ToggleActionEntity); + } + + private void AddToggleLightVerbs(EntityUid uid, UnpoweredFlashlightComponent component, GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + ActivationVerb verb = new() + { + Text = Loc.GetString("toggle-flashlight-verb-get-data-text"), + Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/light.svg.192dpi.png")), + Act = () => TryToggleLight((uid, component), args.User), + Priority = -1 // For things like PDA's, Open-UI and other verbs that should be higher priority. + }; + + args.Verbs.Add(verb); + } + + private void OnMindAdded(EntityUid uid, UnpoweredFlashlightComponent component, MindAddedMessage args) + { + _actionsSystem.AddAction(uid, ref component.ToggleActionEntity, component.ToggleAction); + } + + private void OnGotEmagged(EntityUid uid, UnpoweredFlashlightComponent component, ref GotEmaggedEvent args) + { + if (!_light.TryGetLight(uid, out var light)) + return; + + if (_prototypeManager.TryIndex(component.EmaggedColorsPrototype, out var possibleColors)) + { + var pick = _random.Pick(possibleColors.Colors.Values); + _light.SetColor(uid, pick, light); + } + + args.Repeatable = true; + args.Handled = true; + } + + public void TryToggleLight(Entity ent, EntityUid? user = null, bool quiet = false) + { + if (!Resolve(ent, ref ent.Comp, false)) + return; + + SetLight(ent, !ent.Comp.LightOn, user, quiet); + } + + public void SetLight(Entity ent, bool value, EntityUid? user = null, bool quiet = false) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + if (ent.Comp.LightOn == value) + return; + + if (!_light.TryGetLight(ent, out var light)) + return; + + Dirty(ent); + ent.Comp.LightOn = value; + _light.SetEnabled(ent, value, light); + _appearance.SetData(ent, UnpoweredFlashlightVisuals.LightOn, value); + + if (!quiet) + _audioSystem.PlayPredicted(ent.Comp.ToggleSound, ent, user); + + _actionsSystem.SetToggled(ent.Comp.ToggleActionEntity, value); + RaiseLocalEvent(ent, new LightToggleEvent(value)); + } +} diff --git a/Content.Shared/Light/LightToggleEvent.cs b/Content.Shared/Light/LightToggleEvent.cs new file mode 100644 index 00000000000..ac48c094195 --- /dev/null +++ b/Content.Shared/Light/LightToggleEvent.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.Light; + +public sealed class LightToggleEvent(bool isOn) : EntityEventArgs +{ + public bool IsOn = isOn; +} diff --git a/Content.Shared/Localizations/ContentLocalizationManager.cs b/Content.Shared/Localizations/ContentLocalizationManager.cs index 3c311f43821..7d40182f6cc 100644 --- a/Content.Shared/Localizations/ContentLocalizationManager.cs +++ b/Content.Shared/Localizations/ContentLocalizationManager.cs @@ -69,7 +69,7 @@ private ILocValue FormatNaturalPercent(LocArgs args) var maxDecimals = (int)Math.Floor(((LocValueNumber) args.Args[1]).Value); var formatter = (NumberFormatInfo)NumberFormatInfo.GetInstance(CultureInfo.GetCultureInfo(Culture)).Clone(); formatter.NumberDecimalDigits = maxDecimals; - return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd('.') + "%"); + return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd(char.Parse(formatter.NumberDecimalSeparator)) + "%"); } private ILocValue FormatNaturalFixed(LocArgs args) @@ -78,7 +78,7 @@ private ILocValue FormatNaturalFixed(LocArgs args) var maxDecimals = (int)Math.Floor(((LocValueNumber) args.Args[1]).Value); var formatter = (NumberFormatInfo)NumberFormatInfo.GetInstance(CultureInfo.GetCultureInfo(Culture)).Clone(); formatter.NumberDecimalDigits = maxDecimals; - return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd('.')); + return new LocValueString(string.Format(formatter, "{0:N}", number).TrimEnd('0').TrimEnd(char.Parse(formatter.NumberDecimalSeparator))); } private static readonly Regex PluralEsRule = new("^.*(s|sh|ch|x|z)$"); diff --git a/Content.Shared/Lock/LockComponent.cs b/Content.Shared/Lock/LockComponent.cs index 875451b5a14..e1d47365b7d 100644 --- a/Content.Shared/Lock/LockComponent.cs +++ b/Content.Shared/Lock/LockComponent.cs @@ -31,7 +31,6 @@ public sealed partial class LockComponent : Component [DataField, AutoNetworkedField] public bool UnlockOnClick = true; - /// /// The sound played when unlocked. /// diff --git a/Content.Shared/Lock/LockSystem.cs b/Content.Shared/Lock/LockSystem.cs index bd533663876..9296a354d2c 100644 --- a/Content.Shared/Lock/LockSystem.cs +++ b/Content.Shared/Lock/LockSystem.cs @@ -58,14 +58,14 @@ private void OnActivated(EntityUid uid, LockComponent lockComp, ActivateInWorldE return; // Only attempt an unlock by default on Activate - if (lockComp.Locked) + if (lockComp.Locked && lockComp.UnlockOnClick) { if (!lockComp.UnlockOnClick) return; TryUnlock(uid, args.User, lockComp); args.Handled = true; } - else if (lockComp.LockOnClick) + else if (!lockComp.Locked && lockComp.LockOnClick) { TryLock(uid, args.User, lockComp); args.Handled = true; @@ -203,6 +203,18 @@ public bool TryUnlock(EntityUid uid, EntityUid user, LockComponent? lockComp = n return true; } + /// + /// Returns true if the entity is locked. + /// Entities with no lock component are considered unlocked. + /// + public bool IsLocked(Entity ent) + { + if (!Resolve(ent, ref ent.Comp, false)) + return false; + + return ent.Comp.Locked; + } + /// /// Raises an event for other components to check whether or not /// the entity can be locked in its current state. diff --git a/Content.Shared/Magic/Components/MagicComponent.cs b/Content.Shared/Magic/Components/MagicComponent.cs new file mode 100644 index 00000000000..bcc11063b71 --- /dev/null +++ b/Content.Shared/Magic/Components/MagicComponent.cs @@ -0,0 +1,39 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Magic.Components; + +// TODO: Rename to MagicActionComponent or MagicRequirementsComponent +[RegisterComponent, NetworkedComponent, Access(typeof(SharedMagicSystem))] +public sealed partial class MagicComponent : Component +{ + // TODO: Split into different components? + // This could be the MagicRequirementsComp - which just is requirements for the spell + // Magic comp could be on the actual entities itself + // Could handle lifetime, ignore caster, etc? + // Magic caster comp would be on the caster, used for what I'm not sure + + // TODO: Do After here or in actions + + // TODO: Spell requirements + // A list of requirements to cast the spell + // Hands + // Any item in hand + // Spell takes up an inhand slot + // May be an action toggle or something + + // TODO: List requirements in action desc + /// + /// Does this spell require Wizard Robes & Hat? + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool RequiresClothes; + + /// + /// Does this spell require the user to speak? + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool RequiresSpeech; + + // TODO: FreeHand - should check if toggleable action + // Check which hand is free to toggle action in +} diff --git a/Content.Shared/Magic/Components/SpellbookComponent.cs b/Content.Shared/Magic/Components/SpellbookComponent.cs new file mode 100644 index 00000000000..f1b307c245d --- /dev/null +++ b/Content.Shared/Magic/Components/SpellbookComponent.cs @@ -0,0 +1,36 @@ +using Robust.Shared.Prototypes; + +namespace Content.Shared.Magic.Components; + +/// +/// Spellbooks can grant one or more spells to the user. If marked as it will teach +/// the performer the spells and wipe the book. +/// Default behavior requires the book to be held in hand +/// +[RegisterComponent, Access(typeof(SpellbookSystem))] +public sealed partial class SpellbookComponent : Component +{ + /// + /// List of spells that this book has. This is a combination of the WorldSpells, EntitySpells, and InstantSpells. + /// + [ViewVariables] + public readonly List Spells = new(); + + /// + /// The three fields below is just used for initialization. + /// + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public Dictionary SpellActions = new(); + + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public float LearnTime = .75f; + + /// + /// If true, the spell action stays even after the book is removed + /// + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public bool LearnPermanently; +} diff --git a/Content.Shared/Magic/Components/WizardClothesComponent.cs b/Content.Shared/Magic/Components/WizardClothesComponent.cs new file mode 100644 index 00000000000..063cf56c338 --- /dev/null +++ b/Content.Shared/Magic/Components/WizardClothesComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Magic.Components; + +/// +/// The checks this if a spell requires wizard clothes +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(SharedMagicSystem))] +public sealed partial class WizardClothesComponent : Component; diff --git a/Content.Shared/Magic/Events/BeforeCastSpellEvent.cs b/Content.Shared/Magic/Events/BeforeCastSpellEvent.cs new file mode 100644 index 00000000000..afb5c1f090d --- /dev/null +++ b/Content.Shared/Magic/Events/BeforeCastSpellEvent.cs @@ -0,0 +1,12 @@ +namespace Content.Shared.Magic.Events; + +[ByRefEvent] +public struct BeforeCastSpellEvent(EntityUid performer) +{ + /// + /// The Performer of the event, to check if they meet the requirements. + /// + public EntityUid Performer = performer; + + public bool Cancelled; +} diff --git a/Content.Shared/Magic/Events/ChargeSpellEvent.cs b/Content.Shared/Magic/Events/ChargeSpellEvent.cs new file mode 100644 index 00000000000..8898761ec2a --- /dev/null +++ b/Content.Shared/Magic/Events/ChargeSpellEvent.cs @@ -0,0 +1,18 @@ +using Content.Shared.Actions; + +namespace Content.Shared.Magic.Events; + +/// +/// Adds provided Charge to the held wand +/// +public sealed partial class ChargeSpellEvent : InstantActionEvent, ISpeakSpell +{ + [DataField(required: true)] + public int Charge; + + [DataField] + public string WandTag = "WizardWand"; + + [DataField] + public string? Speech { get; private set; } +} diff --git a/Content.Shared/Magic/Events/InstantSpawnSpellEvent.cs b/Content.Shared/Magic/Events/InstantSpawnSpellEvent.cs index ef8d6898623..1405b158271 100644 --- a/Content.Shared/Magic/Events/InstantSpawnSpellEvent.cs +++ b/Content.Shared/Magic/Events/InstantSpawnSpellEvent.cs @@ -1,6 +1,5 @@ using Content.Shared.Actions; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Magic.Events; @@ -9,17 +8,18 @@ public sealed partial class InstantSpawnSpellEvent : InstantActionEvent, ISpeakS /// /// What entity should be spawned. /// - [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Prototype = default!; + [DataField(required: true)] + public EntProtoId Prototype; - [DataField("preventCollide")] + [DataField] public bool PreventCollideWithCaster = true; - [DataField("speech")] + [DataField] public string? Speech { get; private set; } /// /// Gets the targeted spawn positons; may lead to multiple entities being spawned. /// - [DataField("posData")] public MagicSpawnData Pos = new TargetCasterPos(); + [DataField] + public MagicInstantSpawnData PosData = new TargetCasterPos(); } diff --git a/Content.Shared/Magic/Events/KnockSpellEvent.cs b/Content.Shared/Magic/Events/KnockSpellEvent.cs index a3b0be55759..24a1700d21f 100644 --- a/Content.Shared/Magic/Events/KnockSpellEvent.cs +++ b/Content.Shared/Magic/Events/KnockSpellEvent.cs @@ -1,5 +1,4 @@ using Content.Shared.Actions; -using Robust.Shared.Audio; namespace Content.Shared.Magic.Events; @@ -7,20 +6,12 @@ public sealed partial class KnockSpellEvent : InstantActionEvent, ISpeakSpell { /// /// The range this spell opens doors in - /// 4f is the default + /// 10f is the default + /// Should be able to open all doors/lockers in visible sight /// - [DataField("range")] - public float Range = 4f; + [DataField] + public float Range = 10f; - [DataField("knockSound")] - public SoundSpecifier KnockSound = new SoundPathSpecifier("/Audio/Magic/knock.ogg"); - - /// - /// Volume control for the spell. - /// - [DataField("knockVolume")] - public float KnockVolume = 5f; - - [DataField("speech")] + [DataField] public string? Speech { get; private set; } } diff --git a/Content.Shared/Magic/Events/ProjectileSpellEvent.cs b/Content.Shared/Magic/Events/ProjectileSpellEvent.cs index 44966257699..336ea03346b 100644 --- a/Content.Shared/Magic/Events/ProjectileSpellEvent.cs +++ b/Content.Shared/Magic/Events/ProjectileSpellEvent.cs @@ -1,6 +1,5 @@ using Content.Shared.Actions; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; namespace Content.Shared.Magic.Events; @@ -9,14 +8,9 @@ public sealed partial class ProjectileSpellEvent : WorldTargetActionEvent, ISpea /// /// What entity should be spawned. /// - [DataField("prototype", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string Prototype = default!; + [DataField(required: true)] + public EntProtoId Prototype; - /// - /// Gets the targeted spawn positions; may lead to multiple entities being spawned. - /// - [DataField("posData")] public MagicSpawnData Pos = new TargetCasterPos(); - - [DataField("speech")] + [DataField] public string? Speech { get; private set; } } diff --git a/Content.Shared/Magic/Events/SmiteSpellEvent.cs b/Content.Shared/Magic/Events/SmiteSpellEvent.cs index 08ec63c05e7..74ca116ad59 100644 --- a/Content.Shared/Magic/Events/SmiteSpellEvent.cs +++ b/Content.Shared/Magic/Events/SmiteSpellEvent.cs @@ -4,12 +4,13 @@ namespace Content.Shared.Magic.Events; public sealed partial class SmiteSpellEvent : EntityTargetActionEvent, ISpeakSpell { + // TODO: Make part of gib method /// - /// Should this smite delete all parts/mechanisms gibbed except for the brain? + /// Should this smite delete all parts/mechanisms gibbed except for the brain? /// - [DataField("deleteNonBrainParts")] + [DataField] public bool DeleteNonBrainParts = true; - [DataField("speech")] + [DataField] public string? Speech { get; private set; } } diff --git a/Content.Shared/Magic/Events/SpeakSpellEvent.cs b/Content.Shared/Magic/Events/SpeakSpellEvent.cs new file mode 100644 index 00000000000..1b3f7af63c3 --- /dev/null +++ b/Content.Shared/Magic/Events/SpeakSpellEvent.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Magic.Events; + +[ByRefEvent] +public readonly struct SpeakSpellEvent(EntityUid performer, string speech) +{ + public readonly EntityUid Performer = performer; + public readonly string Speech = speech; +} diff --git a/Content.Shared/Magic/Events/TeleportSpellEvent.cs b/Content.Shared/Magic/Events/TeleportSpellEvent.cs index b24f6ec72f7..525c1e51052 100644 --- a/Content.Shared/Magic/Events/TeleportSpellEvent.cs +++ b/Content.Shared/Magic/Events/TeleportSpellEvent.cs @@ -1,19 +1,19 @@ using Content.Shared.Actions; -using Robust.Shared.Audio; namespace Content.Shared.Magic.Events; +// TODO: Can probably just be an entity or something public sealed partial class TeleportSpellEvent : WorldTargetActionEvent, ISpeakSpell { - [DataField("blinkSound")] - public SoundSpecifier BlinkSound = new SoundPathSpecifier("/Audio/Magic/blink.ogg"); - - [DataField("speech")] + [DataField] public string? Speech { get; private set; } + // TODO: Move to magic component + // TODO: Maybe not since sound specifier is a thing + // Keep here to remind what the volume was set as /// /// Volume control for the spell. /// - [DataField("blinkVolume")] + [DataField] public float BlinkVolume = 5f; } diff --git a/Content.Shared/Magic/Events/WorldSpawnSpellEvent.cs b/Content.Shared/Magic/Events/WorldSpawnSpellEvent.cs index 4355cab8421..2f50c67b3e7 100644 --- a/Content.Shared/Magic/Events/WorldSpawnSpellEvent.cs +++ b/Content.Shared/Magic/Events/WorldSpawnSpellEvent.cs @@ -4,29 +4,31 @@ namespace Content.Shared.Magic.Events; +// TODO: This class needs combining with InstantSpawnSpellEvent + public sealed partial class WorldSpawnSpellEvent : WorldTargetActionEvent, ISpeakSpell { - // TODO:This class needs combining with InstantSpawnSpellEvent - /// /// The list of prototypes this spell will spawn /// - [DataField("prototypes")] - public List Contents = new(); + [DataField] + public List Prototypes = new(); // TODO: This offset is liable for deprecation. + // TODO: Target tile via code instead? /// /// The offset the prototypes will spawn in on relative to the one prior. /// Set to 0,0 to have them spawn on the same tile. /// - [DataField("offset")] + [DataField] public Vector2 Offset; /// /// Lifetime to set for the entities to self delete /// - [DataField("lifetime")] public float? Lifetime; + [DataField] + public float? Lifetime; - [DataField("speech")] + [DataField] public string? Speech { get; private set; } } diff --git a/Content.Shared/Magic/MagicInstantSpawnData.cs b/Content.Shared/Magic/MagicInstantSpawnData.cs new file mode 100644 index 00000000000..5dcc1453edc --- /dev/null +++ b/Content.Shared/Magic/MagicInstantSpawnData.cs @@ -0,0 +1,25 @@ +namespace Content.Shared.Magic; + +// TODO: If still needed, move to magic component +[ImplicitDataDefinitionForInheritors] +public abstract partial class MagicInstantSpawnData; + +/// +/// Spawns underneath caster. +/// +public sealed partial class TargetCasterPos : MagicInstantSpawnData; + +/// +/// Spawns 3 tiles wide in front of the caster. +/// +public sealed partial class TargetInFront : MagicInstantSpawnData +{ + [DataField] + public int Width = 3; +} + + +/// +/// Spawns 1 tile in front of caster +/// +public sealed partial class TargetInFrontSingle : MagicInstantSpawnData; diff --git a/Content.Shared/Magic/MagicSpawnData.cs b/Content.Shared/Magic/MagicSpawnData.cs deleted file mode 100644 index cd96d4ad76b..00000000000 --- a/Content.Shared/Magic/MagicSpawnData.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Content.Shared.Magic; - -[ImplicitDataDefinitionForInheritors] -public abstract partial class MagicSpawnData -{ - -} - -/// -/// Spawns 1 at the caster's feet. -/// -public sealed partial class TargetCasterPos : MagicSpawnData {} - -/// -/// Targets the 3 tiles in front of the caster. -/// -public sealed partial class TargetInFront : MagicSpawnData -{ - [DataField("width")] public int Width = 3; -} diff --git a/Content.Shared/Magic/SharedMagicSystem.cs b/Content.Shared/Magic/SharedMagicSystem.cs new file mode 100644 index 00000000000..cc7a297aa40 --- /dev/null +++ b/Content.Shared/Magic/SharedMagicSystem.cs @@ -0,0 +1,519 @@ +using System.Numerics; +using Content.Shared.Actions; +using Content.Shared.Body.Components; +using Content.Shared.Body.Systems; +using Content.Shared.Coordinates.Helpers; +using Content.Shared.Doors.Components; +using Content.Shared.Doors.Systems; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Inventory; +using Content.Shared.Lock; +using Content.Shared.Magic.Components; +using Content.Shared.Magic.Events; +using Content.Shared.Maps; +using Content.Shared.Physics; +using Content.Shared.Popups; +using Content.Shared.Speech.Muting; +using Content.Shared.Storage; +using Content.Shared.Tag; +using Content.Shared.Weapons.Ranged.Components; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.Map; +using Robust.Shared.Map.Components; +using Robust.Shared.Network; +using Robust.Shared.Physics.Systems; +using Robust.Shared.Random; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Spawners; + +namespace Content.Shared.Magic; + +/// +/// Handles learning and using spells (actions) +/// +public abstract class SharedMagicSystem : EntitySystem +{ + [Dependency] private readonly ISerializationManager _seriMan = default!; + [Dependency] private readonly IComponentFactory _compFact = default!; + [Dependency] private readonly IMapManager _mapManager = default!; + [Dependency] private readonly SharedMapSystem _mapSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly SharedGunSystem _gunSystem = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly SharedTransformSystem _transform = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly SharedBodySystem _body = default!; + [Dependency] private readonly EntityLookupSystem _lookup = default!; + [Dependency] private readonly SharedDoorSystem _door = default!; + [Dependency] private readonly InventorySystem _inventory = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly LockSystem _lock = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly TagSystem _tag = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnBeforeCastSpell); + + SubscribeLocalEvent(OnInstantSpawn); + SubscribeLocalEvent(OnTeleportSpell); + SubscribeLocalEvent(OnWorldSpawn); + SubscribeLocalEvent(OnProjectileSpell); + SubscribeLocalEvent(OnChangeComponentsSpell); + SubscribeLocalEvent(OnSmiteSpell); + SubscribeLocalEvent(OnKnockSpell); + SubscribeLocalEvent(OnChargeSpell); + + // Spell wishlist + // A wishlish of spells that I'd like to implement or planning on implementing in a future PR + + // TODO: InstantDoAfterSpell and WorldDoafterSpell + // Both would be an action that take in an event, that passes an event to trigger once the doafter is done + // This would be three events: + // 1 - Event that triggers from the action that starts the doafter + // 2 - The doafter event itself, which passes the event with it + // 3 - The event to trigger once the do-after finishes + + // TODO: Inanimate objects to life ECS + // AI sentience + + // TODO: Flesh2Stone + // Entity Target spell + // Synergy with Inanimate object to life (detects player and allows player to move around) + + // TODO: Lightning Spell + // Should just fire lightning, try to prevent arc back to caster + + // TODO: Magic Missile (homing projectile ecs) + // Instant action, target any player (except self) on screen + + // TODO: Random projectile ECS for magic-carp, wand of magic + + // TODO: Recall Spell + // mark any item in hand to recall + // ItemRecallComponent + // Event adds the component if it doesn't exist and the performer isn't stored in the comp + // 2nd firing of the event checks to see if the recall comp has this uid, and if it does it calls it + // if no free hands, summon at feet + // if item deleted, clear stored item + + // TODO: Jaunt (should be its own ECS) + // Instant action + // When clicked, disappear/reappear (goes to paused map) + // option to restrict to tiles + // option for requiring entry/exit (blood jaunt) + // speed option + + // TODO: Summon Events + // List of wizard events to add into the event pool that frequently activate + // floor is lava + // change places + // ECS that when triggered, will periodically trigger a random GameRule + // Would need a controller/controller entity? + + // TODO: Summon Guns + // Summon a random gun at peoples feet + // Get every alive player (not in cryo, not a simplemob) + // TODO: After Antag Rework - Rare chance of giving gun collector status to people + + // TODO: Summon Magic + // Summon a random magic wand at peoples feet + // Get every alive player (not in cryo, not a simplemob) + // TODO: After Antag Rework - Rare chance of giving magic collector status to people + + // TODO: Bottle of Blood + // Summons Slaughter Demon + // TODO: Slaughter Demon + // Also see Jaunt + + // TODO: Field Spells + // Should be able to specify a grid of tiles (3x3 for example) that it effects + // Timed despawn - so it doesn't last forever + // Ignore caster - for spells that shouldn't effect the caster (ie if timestop should effect the caster) + + // TODO: Touch toggle spell + // 1 - When toggled on, show in hand + // 2 - Block hand when toggled on + // - Require free hand + // 3 - use spell event when toggled & click + } + + private void OnBeforeCastSpell(Entity ent, ref BeforeCastSpellEvent args) + { + var comp = ent.Comp; + var hasReqs = true; + + if (comp.RequiresClothes) + { + var enumerator = _inventory.GetSlotEnumerator(args.Performer, SlotFlags.OUTERCLOTHING | SlotFlags.HEAD); + while (enumerator.MoveNext(out var containerSlot)) + { + if (containerSlot.ContainedEntity is { } item) + hasReqs = HasComp(item); + else + hasReqs = false; + + if (!hasReqs) + break; + } + } + + if (comp.RequiresSpeech && HasComp(args.Performer)) + hasReqs = false; + + if (hasReqs) + return; + + args.Cancelled = true; + _popup.PopupClient(Loc.GetString("spell-requirements-failed"), args.Performer, args.Performer); + + // TODO: Pre-cast do after, either here or in SharedActionsSystem + } + + private bool PassesSpellPrerequisites(EntityUid spell, EntityUid performer) + { + var ev = new BeforeCastSpellEvent(performer); + RaiseLocalEvent(spell, ref ev); + return !ev.Cancelled; + } + + #region Spells + #region Instant Spawn Spells + /// + /// Handles the instant action (i.e. on the caster) attempting to spawn an entity. + /// + private void OnInstantSpawn(InstantSpawnSpellEvent args) + { + if (args.Handled || !PassesSpellPrerequisites(args.Action, args.Performer)) + return; + + var transform = Transform(args.Performer); + + foreach (var position in GetInstantSpawnPositions(transform, args.PosData)) + { + SpawnSpellHelper(args.Prototype, position, args.Performer, preventCollide: args.PreventCollideWithCaster); + } + + Speak(args); + args.Handled = true; + } + + /// + /// Gets spawn positions listed on + /// + /// + private List GetInstantSpawnPositions(TransformComponent casterXform, MagicInstantSpawnData data) + { + switch (data) + { + case TargetCasterPos: + return new List(1) {casterXform.Coordinates}; + case TargetInFrontSingle: + { + var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized()); + + if (!TryComp(casterXform.GridUid, out var mapGrid)) + return new List(); + if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) + return new List(); + + var tileIndex = tileReference.Value.GridIndices; + return new List(1) { _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex) }; + } + case TargetInFront: + { + var directionPos = casterXform.Coordinates.Offset(casterXform.LocalRotation.ToWorldVec().Normalized()); + + if (!TryComp(casterXform.GridUid, out var mapGrid)) + return new List(); + + if (!directionPos.TryGetTileRef(out var tileReference, EntityManager, _mapManager)) + return new List(); + + var tileIndex = tileReference.Value.GridIndices; + var coords = _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex); + EntityCoordinates coordsPlus; + EntityCoordinates coordsMinus; + + var dir = casterXform.LocalRotation.GetCardinalDir(); + switch (dir) + { + case Direction.North: + case Direction.South: + { + coordsPlus = _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex + (1, 0)); + coordsMinus = _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex + (-1, 0)); + return new List(3) + { + coords, + coordsPlus, + coordsMinus, + }; + } + case Direction.East: + case Direction.West: + { + coordsPlus = _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex + (0, 1)); + coordsMinus = _mapSystem.GridTileToLocal(casterXform.GridUid.Value, mapGrid, tileIndex + (0, -1)); + return new List(3) + { + coords, + coordsPlus, + coordsMinus, + }; + } + } + + return new List(); + } + default: + throw new ArgumentOutOfRangeException(); + } + } + // End Instant Spawn Spells + #endregion + #region World Spawn Spells + /// + /// Spawns entities from a list within range of click. + /// + /// + /// It will offset entities after the first entity based on the OffsetVector2. + /// + /// The Spawn Spell Event args. + private void OnWorldSpawn(WorldSpawnSpellEvent args) + { + if (args.Handled || !PassesSpellPrerequisites(args.Action, args.Performer)) + return; + + var targetMapCoords = args.Target; + + WorldSpawnSpellHelper(args.Prototypes, targetMapCoords, args.Performer, args.Lifetime, args.Offset); + Speak(args); + args.Handled = true; + } + + /// + /// Loops through a supplied list of entity prototypes and spawns them + /// + /// + /// If an offset of 0, 0 is supplied then the entities will all spawn on the same tile. + /// Any other offset will spawn entities starting from the source Map Coordinates and will increment the supplied + /// offset + /// + /// The list of Entities to spawn in + /// Map Coordinates where the entities will spawn + /// Check to see if the entities should self delete + /// A Vector2 offset that the entities will spawn in + private void WorldSpawnSpellHelper(List entityEntries, EntityCoordinates entityCoords, EntityUid performer, float? lifetime, Vector2 offsetVector2) + { + var getProtos = EntitySpawnCollection.GetSpawns(entityEntries, _random); + + var offsetCoords = entityCoords; + foreach (var proto in getProtos) + { + SpawnSpellHelper(proto, offsetCoords, performer, lifetime); + offsetCoords = offsetCoords.Offset(offsetVector2); + } + } + // End World Spawn Spells + #endregion + #region Projectile Spells + private void OnProjectileSpell(ProjectileSpellEvent ev) + { + if (ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || !_net.IsServer) + return; + + ev.Handled = true; + Speak(ev); + + var xform = Transform(ev.Performer); + var fromCoords = xform.Coordinates; + var toCoords = ev.Target; + var userVelocity = _physics.GetMapLinearVelocity(ev.Performer); + + // If applicable, this ensures the projectile is parented to grid on spawn, instead of the map. + var fromMap = fromCoords.ToMap(EntityManager, _transform); + var spawnCoords = _mapManager.TryFindGridAt(fromMap, out var gridUid, out _) + ? fromCoords.WithEntityId(gridUid, EntityManager) + : new(_mapManager.GetMapEntityId(fromMap.MapId), fromMap.Position); + + var ent = Spawn(ev.Prototype, spawnCoords); + var direction = toCoords.ToMapPos(EntityManager, _transform) - + spawnCoords.ToMapPos(EntityManager, _transform); + _gunSystem.ShootProjectile(ent, direction, userVelocity, ev.Performer, ev.Performer); + } + // End Projectile Spells + #endregion + #region Change Component Spells + // staves.yml ActionRGB light + private void OnChangeComponentsSpell(ChangeComponentsSpellEvent ev) + { + if (ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer)) + return; + + ev.Handled = true; + Speak(ev); + + foreach (var toRemove in ev.ToRemove) + { + if (_compFact.TryGetRegistration(toRemove, out var registration)) + RemComp(ev.Target, registration.Type); + } + + foreach (var (name, data) in ev.ToAdd) + { + if (HasComp(ev.Target, data.Component.GetType())) + continue; + + var component = (Component) _compFact.GetComponent(name); + component.Owner = ev.Target; + var temp = (object) component; + _seriMan.CopyTo(data.Component, ref temp); + EntityManager.AddComponent(ev.Target, (Component) temp!); + } + } + // End Change Component Spells + #endregion + #region Teleport Spells + // TODO: Rename to teleport clicked spell? + /// + /// Teleports the user to the clicked location + /// + /// + private void OnTeleportSpell(TeleportSpellEvent args) + { + if (args.Handled || !PassesSpellPrerequisites(args.Action, args.Performer)) + return; + + var transform = Transform(args.Performer); + + if (transform.MapID != args.Target.GetMapId(EntityManager) || !_interaction.InRangeUnobstructed(args.Performer, args.Target, range: 1000F, collisionMask: CollisionGroup.Opaque, popup: true)) + return; + + _transform.SetCoordinates(args.Performer, args.Target); + _transform.AttachToGridOrMap(args.Performer, transform); + Speak(args); + args.Handled = true; + } + // End Teleport Spells + #endregion + #region Spell Helpers + private void SpawnSpellHelper(string? proto, EntityCoordinates position, EntityUid performer, float? lifetime = null, bool preventCollide = false) + { + if (!_net.IsServer) + return; + + var ent = Spawn(proto, position.SnapToGrid(EntityManager, _mapManager)); + + if (lifetime != null) + { + var comp = EnsureComp(ent); + comp.Lifetime = lifetime.Value; + } + + if (preventCollide) + { + var comp = EnsureComp(ent); + comp.Uid = performer; + } + } + // End Spell Helpers + #endregion + #region Smite Spells + private void OnSmiteSpell(SmiteSpellEvent ev) + { + if (ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer)) + return; + + ev.Handled = true; + Speak(ev); + + var direction = _transform.GetMapCoordinates(ev.Target, Transform(ev.Target)).Position - _transform.GetMapCoordinates(ev.Performer, Transform(ev.Performer)).Position; + var impulseVector = direction * 10000; + + _physics.ApplyLinearImpulse(ev.Target, impulseVector); + + if (!TryComp(ev.Target, out var body)) + return; + + _body.GibBody(ev.Target, true, body); + } + // End Smite Spells + #endregion + #region Knock Spells + /// + /// Opens all doors and locks within range + /// + /// + private void OnKnockSpell(KnockSpellEvent args) + { + if (args.Handled || !PassesSpellPrerequisites(args.Action, args.Performer)) + return; + + args.Handled = true; + Speak(args); + + var transform = Transform(args.Performer); + + // Look for doors and lockers, and don't open/unlock them if they're already opened/unlocked. + foreach (var target in _lookup.GetEntitiesInRange(_transform.GetMapCoordinates(args.Performer, transform), args.Range, flags: LookupFlags.Dynamic | LookupFlags.Static)) + { + if (!_interaction.InRangeUnobstructed(args.Performer, target, range: 0, collisionMask: CollisionGroup.Opaque)) + continue; + + if (TryComp(target, out var doorBoltComp) && doorBoltComp.BoltsDown) + _door.SetBoltsDown((target, doorBoltComp), false, predicted: true); + + if (TryComp(target, out var doorComp) && doorComp.State is not DoorState.Open) + _door.StartOpening(target); + + if (TryComp(target, out var lockComp) && lockComp.Locked) + _lock.Unlock(target, args.Performer, lockComp); + } + } + // End Knock Spells + #endregion + #region Charge Spells + // TODO: Future support to charge other items + private void OnChargeSpell(ChargeSpellEvent ev) + { + if (ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || !TryComp(ev.Performer, out var handsComp)) + return; + + EntityUid? wand = null; + foreach (var item in _hands.EnumerateHeld(ev.Performer, handsComp)) + { + if (!_tag.HasTag(item, ev.WandTag)) + continue; + + wand = item; + } + + ev.Handled = true; + Speak(ev); + + if (wand == null || !TryComp(wand, out var basicAmmoComp) || basicAmmoComp.Count == null) + return; + + _gunSystem.UpdateBasicEntityAmmoCount(wand.Value, basicAmmoComp.Count.Value + ev.Charge, basicAmmoComp); + } + // End Charge Spells + #endregion + // End Spells + #endregion + + // When any spell is cast it will raise this as an event, so then it can be played in server or something. At least until chat gets moved to shared + // TODO: Temp until chat is in shared + private void Speak(BaseActionEvent args) + { + if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech)) + return; + + var ev = new SpeakSpellEvent(args.Performer, speak.Speech); + RaiseLocalEvent(ref ev); + } +} diff --git a/Content.Shared/Magic/SpellbookSystem.cs b/Content.Shared/Magic/SpellbookSystem.cs new file mode 100644 index 00000000000..a7c82746249 --- /dev/null +++ b/Content.Shared/Magic/SpellbookSystem.cs @@ -0,0 +1,98 @@ +using Content.Shared.Actions; +using Content.Shared.DoAfter; +using Content.Shared.Interaction.Events; +using Content.Shared.Magic.Components; +using Content.Shared.Mind; +using Robust.Shared.Network; + +namespace Content.Shared.Magic; + +public sealed class SpellbookSystem : EntitySystem +{ + [Dependency] private readonly SharedMindSystem _mind = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly ActionContainerSystem _actionContainer = default!; + [Dependency] private readonly INetManager _netManager = default!; + + public override void Initialize() + { + SubscribeLocalEvent(OnInit, before: [typeof(SharedMagicSystem)]); + SubscribeLocalEvent(OnUse); + SubscribeLocalEvent(OnDoAfter); + } + + private void OnInit(Entity ent, ref MapInitEvent args) + { + foreach (var (id, charges) in ent.Comp.SpellActions) + { + var spell = _actionContainer.AddAction(ent, id); + if (spell == null) + continue; + + int? charge = charges; + if (_actions.GetCharges(spell) != null) + charge = _actions.GetCharges(spell); + + _actions.SetCharges(spell, charge < 0 ? null : charge); + ent.Comp.Spells.Add(spell.Value); + } + } + + private void OnUse(Entity ent, ref UseInHandEvent args) + { + if (args.Handled) + return; + + AttemptLearn(ent, args); + + args.Handled = true; + } + + private void OnDoAfter(Entity ent, ref T args) where T : DoAfterEvent // Sometimes i despise this language + { + if (args.Handled || args.Cancelled) + return; + + args.Handled = true; + + if (!ent.Comp.LearnPermanently) + { + _actions.GrantActions(args.Args.User, ent.Comp.Spells, ent); + return; + } + + if (_mind.TryGetMind(args.Args.User, out var mindId, out _)) + { + var mindActionContainerComp = EnsureComp(mindId); + + if (_netManager.IsServer) + _actionContainer.TransferAllActionsWithNewAttached(ent, mindId, args.Args.User, newContainer: mindActionContainerComp); + } + else + { + foreach (var (id, charges) in ent.Comp.SpellActions) + { + EntityUid? actionId = null; + if (_actions.AddAction(args.Args.User, ref actionId, id)) + _actions.SetCharges(actionId, charges < 0 ? null : charges); + } + } + + ent.Comp.SpellActions.Clear(); + } + + private void AttemptLearn(Entity ent, UseInHandEvent args) + { + var doAfterEventArgs = new DoAfterArgs(EntityManager, args.User, ent.Comp.LearnTime, new SpellbookDoAfterEvent(), ent, target: ent) + { + BreakOnTargetMove = true, + BreakOnUserMove = true, + BreakOnWeightlessMove = true, + BreakOnDamage = true, + NeedHand = true, // What, are you going to read with your eyes only?? + }; + + _doAfter.TryStartDoAfter(doAfterEventArgs); + } +} diff --git a/Content.Server/MagicMirror/MagicMirrorComponent.cs b/Content.Shared/MagicMirror/MagicMirrorComponent.cs similarity index 89% rename from Content.Server/MagicMirror/MagicMirrorComponent.cs rename to Content.Shared/MagicMirror/MagicMirrorComponent.cs index 624a381ca58..63575439052 100644 --- a/Content.Server/MagicMirror/MagicMirrorComponent.cs +++ b/Content.Shared/MagicMirror/MagicMirrorComponent.cs @@ -1,13 +1,13 @@ using Content.Shared.DoAfter; -using Content.Shared.Humanoid; using Robust.Shared.Audio; +using Robust.Shared.GameStates; -namespace Content.Server.MagicMirror; +namespace Content.Shared.MagicMirror; /// /// Allows humanoids to change their appearance mid-round. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] public sealed partial class MagicMirrorComponent : Component { [DataField] @@ -16,7 +16,7 @@ public sealed partial class MagicMirrorComponent : Component /// /// Magic mirror target, used for validating UI messages. /// - [DataField] + [DataField, AutoNetworkedField] public EntityUid? Target; /// diff --git a/Content.Shared/MagicMirror/SharedMagicMirrorSystem.cs b/Content.Shared/MagicMirror/SharedMagicMirrorSystem.cs index 0b22e024982..f9c941ffe39 100644 --- a/Content.Shared/MagicMirror/SharedMagicMirrorSystem.cs +++ b/Content.Shared/MagicMirror/SharedMagicMirrorSystem.cs @@ -1,10 +1,29 @@ using Content.Shared.DoAfter; using Content.Shared.Humanoid.Markings; -using Robust.Shared.Player; +using Content.Shared.Interaction; using Robust.Shared.Serialization; namespace Content.Shared.MagicMirror; +public abstract class SharedMagicMirrorSystem : EntitySystem +{ + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + + public override void Initialize() + { + base.Initialize(); + SubscribeLocalEvent(OnMirrorRangeCheck); + } + + private void OnMirrorRangeCheck(EntityUid uid, MagicMirrorComponent component, ref BoundUserInterfaceCheckRangeEvent args) + { + if (!Exists(component.Target) || !_interaction.InRangeUnobstructed(uid, component.Target.Value)) + { + args.Result = BoundUserInterfaceRangeResult.Fail; + } + } +} + [Serializable, NetSerializable] public enum MagicMirrorUiKey : byte { diff --git a/Content.Shared/Mind/SharedMindSystem.cs b/Content.Shared/Mind/SharedMindSystem.cs index 1898126d803..7887b8f9b22 100644 --- a/Content.Shared/Mind/SharedMindSystem.cs +++ b/Content.Shared/Mind/SharedMindSystem.cs @@ -383,6 +383,30 @@ public bool TryGetObjectiveComp(EntityUid mindId, [NotNullWhen(true)] out T? return false; } + /// + /// Tries to find an objective that has the same prototype as the argument. + /// + /// + /// Will not work for objectives that have no prototype, or duplicate objectives with the same prototype. + /// + public bool TryFindObjective(Entity mind, string prototype, [NotNullWhen(true)] out EntityUid? objective) + { + objective = null; + if (!Resolve(mind, ref mind.Comp)) + return false; + + foreach (var uid in mind.Comp.Objectives) + { + if (MetaData(uid).EntityPrototype?.ID == prototype) + { + objective = uid; + return true; + } + } + + return false; + } + public bool TryGetSession(EntityUid? mindId, [NotNullWhen(true)] out ICommonSession? session) { session = null; diff --git a/Content.Shared/Mobs/Components/MobStateComponent.cs b/Content.Shared/Mobs/Components/MobStateComponent.cs index a2ff349e133..7cff0779cbe 100644 --- a/Content.Shared/Mobs/Components/MobStateComponent.cs +++ b/Content.Shared/Mobs/Components/MobStateComponent.cs @@ -13,30 +13,21 @@ namespace Content.Shared.Mobs.Components /// [RegisterComponent] [NetworkedComponent] + [AutoGenerateComponentState] [Access(typeof(MobStateSystem), typeof(MobThresholdSystem))] public sealed partial class MobStateComponent : Component { //default mobstate is always the lowest state level - [ViewVariables] public MobState CurrentState { get; set; } = MobState.Alive; + [AutoNetworkedField, ViewVariables] + public MobState CurrentState { get; set; } = MobState.Alive; - [DataField("allowedStates")] public HashSet AllowedStates = new() + [DataField] + [AutoNetworkedField] + public HashSet AllowedStates = new() { MobState.Alive, MobState.Critical, MobState.Dead }; } - - [Serializable, NetSerializable] - public sealed class MobStateComponentState : ComponentState - { - public readonly MobState CurrentState; - public readonly HashSet AllowedStates; - - public MobStateComponentState(MobState currentState, HashSet allowedStates) - { - CurrentState = currentState; - AllowedStates = allowedStates; - } - } } diff --git a/Content.Shared/Mobs/Systems/MobStateSystem.cs b/Content.Shared/Mobs/Systems/MobStateSystem.cs index ff54c30aaf4..a3886dd42e1 100644 --- a/Content.Shared/Mobs/Systems/MobStateSystem.cs +++ b/Content.Shared/Mobs/Systems/MobStateSystem.cs @@ -25,8 +25,6 @@ public override void Initialize() _sawmill = _logManager.GetSawmill("MobState"); base.Initialize(); SubscribeEvents(); - SubscribeLocalEvent(OnGetComponentState); - SubscribeLocalEvent(OnHandleComponentState); } #region Public API @@ -100,24 +98,5 @@ public bool IsInvalidState(EntityUid target, MobStateComponent? component = null #region Private Implementation - private void OnHandleComponentState(EntityUid uid, MobStateComponent component, ref ComponentHandleState args) - { - if (args.Current is not MobStateComponentState state) - return; - - component.CurrentState = state.CurrentState; - - if (!component.AllowedStates.SetEquals(state.AllowedStates)) - { - component.AllowedStates.Clear(); - component.AllowedStates.UnionWith(state.AllowedStates); - } - } - - private void OnGetComponentState(EntityUid uid, MobStateComponent component, ref ComponentGetState args) - { - args.State = new MobStateComponentState(component.CurrentState, component.AllowedStates); - } - #endregion } diff --git a/Content.Shared/Mood/MoodCategoryPrototype.cs b/Content.Shared/Mood/MoodCategoryPrototype.cs index 13d5f8b7ea6..d5bcd707c82 100644 --- a/Content.Shared/Mood/MoodCategoryPrototype.cs +++ b/Content.Shared/Mood/MoodCategoryPrototype.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Mood; /// A prototype defining a category for moodlets, where only a single moodlet of a given category is permitted. /// [Prototype] -public sealed class MoodCategoryPrototype : IPrototype +public sealed partial class MoodCategoryPrototype : IPrototype { [IdDataField] public string ID { get; } = default!; diff --git a/Content.Shared/Mood/MoodEffectPrototype.cs b/Content.Shared/Mood/MoodEffectPrototype.cs index ab9bca01602..da9d178510f 100644 --- a/Content.Shared/Mood/MoodEffectPrototype.cs +++ b/Content.Shared/Mood/MoodEffectPrototype.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Mood; [Prototype] -public sealed class MoodEffectPrototype : IPrototype +public sealed partial class MoodEffectPrototype : IPrototype { /// /// The ID of the moodlet to use. diff --git a/Content.Shared/MouseRotator/MouseRotatorComponent.cs b/Content.Shared/MouseRotator/MouseRotatorComponent.cs index a35dfe0a288..2844b3cb8b5 100644 --- a/Content.Shared/MouseRotator/MouseRotatorComponent.cs +++ b/Content.Shared/MouseRotator/MouseRotatorComponent.cs @@ -30,8 +30,7 @@ public sealed partial class MouseRotatorComponent : Component public double RotationSpeed = float.MaxValue; /// - /// This one is important. If this is true, does not apply, and the system will - /// use instead. In this mode, the client will only send + /// This one is important. If this is true, does not apply. In this mode, the client will only send /// events when an entity should snap to a different cardinal direction, rather than for every angle change. /// /// This is useful for cases like humans, where what really matters is the visual sprite direction, as opposed to something @@ -50,13 +49,3 @@ public sealed class RequestMouseRotatorRotationEvent : EntityEventArgs { public Angle Rotation; } - -/// -/// Simpler version of for implementations -/// that only require snapping to 4-dir and not full angle rotation. -/// -[Serializable, NetSerializable] -public sealed class RequestMouseRotatorRotationSimpleEvent : EntityEventArgs -{ - public Direction Direction; -} diff --git a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs index c57d477bd2f..9663b3363d1 100644 --- a/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs +++ b/Content.Shared/MouseRotator/SharedMouseRotatorSystem.cs @@ -1,5 +1,4 @@ using Content.Shared.Interaction; -using Robust.Shared.Timing; namespace Content.Shared.MouseRotator; @@ -16,7 +15,6 @@ public override void Initialize() base.Initialize(); SubscribeAllEvent(OnRequestRotation); - SubscribeAllEvent(OnRequestSimpleRotation); } public override void Update(float frameTime) @@ -50,7 +48,7 @@ public override void Update(float frameTime) private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessionEventArgs args) { if (args.SenderSession.AttachedEntity is not { } ent - || !TryComp(ent, out var rotator) || rotator.Simple4DirMode) + || !TryComp(ent, out var rotator)) { Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting local rotation directly without a valid mouse rotator component attached!"); return; @@ -59,17 +57,4 @@ private void OnRequestRotation(RequestMouseRotatorRotationEvent msg, EntitySessi rotator.GoalRotation = msg.Rotation; Dirty(ent, rotator); } - - private void OnRequestSimpleRotation(RequestMouseRotatorRotationSimpleEvent ev, EntitySessionEventArgs args) - { - if (args.SenderSession.AttachedEntity is not { } ent - || !TryComp(ent, out var rotator) || !rotator.Simple4DirMode) - { - Log.Error($"User {args.SenderSession.Name} ({args.SenderSession.UserId}) tried setting 4-dir rotation directly without a valid mouse rotator component attached!"); - return; - } - - rotator.GoalRotation = ev.Direction.ToAngle(); - Dirty(ent, rotator); - } } diff --git a/Content.Shared/Movement/Components/MobMoverComponent.cs b/Content.Shared/Movement/Components/MobMoverComponent.cs index a77f415b938..7ad7961ed7e 100644 --- a/Content.Shared/Movement/Components/MobMoverComponent.cs +++ b/Content.Shared/Movement/Components/MobMoverComponent.cs @@ -14,6 +14,15 @@ public sealed partial class MobMoverComponent : Component [DataField] public float PushStrength = 600f; + [DataField, AutoNetworkedField] + public float StepSoundMoveDistanceRunning = 2; + + [DataField, AutoNetworkedField] + public float StepSoundMoveDistanceWalking = 1.5f; + + [DataField, AutoNetworkedField] + public float FootstepVariation; + [ViewVariables(VVAccess.ReadWrite)] public EntityCoordinates LastPosition { get; set; } diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs index 0470e10fe49..33dde399a51 100644 --- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs +++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs @@ -16,6 +16,7 @@ using Content.Shared.Movement.Systems; using Content.Shared.Projectiles; using Content.Shared.Pulling.Events; +using Content.Shared.Standing; using Content.Shared.Throwing; using Content.Shared.Verbs; using Robust.Shared.Containers; @@ -70,6 +71,7 @@ public override void Initialize() SubscribeLocalEvent(OnPullerUnpaused); SubscribeLocalEvent(OnVirtualItemDeleted); SubscribeLocalEvent(OnRefreshMovespeed); + SubscribeLocalEvent(OnDropHandItems); CommandBinds.Builder .Bind(ContentKeyFunctions.MovePulledObject, new PointerInputCmdHandler(OnRequestMovePulledObject)) @@ -159,6 +161,17 @@ private void OnPullerMoveInput(EntityUid uid, PullerComponent component, ref Mov component.NextPushStop = TimeSpan.Zero; } + private void OnDropHandItems(EntityUid uid, PullerComponent pullerComp, DropHandItemsEvent args) + { + if (pullerComp.Pulling == null || pullerComp.NeedsHands) + return; + + if (!TryComp(pullerComp.Pulling, out PullableComponent? pullableComp)) + return; + + TryStopPull(pullerComp.Pulling.Value, pullableComp, uid); + } + private void OnPullerContainerInsert(Entity ent, ref EntGotInsertedIntoContainerMessage args) { if (ent.Comp.Pulling == null) return; diff --git a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs index d72ce6e2a2d..1c097ce17bc 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.Input.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.Input.cs @@ -263,7 +263,7 @@ private void OnInputParentChange(EntityUid uid, InputMoverComponent component, r } var oldMapId = args.OldMapId; - var mapId = args.Transform.MapID; + var mapId = args.Transform.MapUid; // If we change maps then reset eye rotation entirely. if (oldMapId != mapId) diff --git a/Content.Shared/Movement/Systems/SharedMoverController.cs b/Content.Shared/Movement/Systems/SharedMoverController.cs index a3dc705ac17..00afa3a4fb8 100644 --- a/Content.Shared/Movement/Systems/SharedMoverController.cs +++ b/Content.Shared/Movement/Systems/SharedMoverController.cs @@ -64,11 +64,6 @@ public abstract partial class SharedMoverController : VirtualController protected EntityQuery CanMoveInAirQuery; protected EntityQuery NoRotateQuery; - private const float StepSoundMoveDistanceRunning = 2; - private const float StepSoundMoveDistanceWalking = 1.5f; - - private const float FootstepVariation = 0f; - /// /// /// @@ -274,7 +269,7 @@ protected void HandleMobMovement( var audioParams = sound.Params .WithVolume(volume) - .WithVariation(sound.Params.Variation ?? FootstepVariation); + .WithVariation(sound.Params.Variation ?? mobMover.FootstepVariation); // If we're a relay target then predict the sound for all relays. if (relayTarget != null) @@ -425,7 +420,9 @@ private bool TryGetSound( return false; var coordinates = xform.Coordinates; - var distanceNeeded = mover.Sprinting ? StepSoundMoveDistanceRunning : StepSoundMoveDistanceWalking; + var distanceNeeded = mover.Sprinting + ? mobMover.StepSoundMoveDistanceRunning + : mobMover.StepSoundMoveDistanceWalking; // Handle footsteps. if (!weightless) diff --git a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs index dff4b56aa4a..0f3bff265cb 100644 --- a/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs +++ b/Content.Shared/Ninja/Components/SpaceNinjaComponent.cs @@ -1,6 +1,6 @@ using Content.Shared.Ninja.Systems; using Robust.Shared.GameStates; -using Robust.Shared.Serialization; +using Robust.Shared.Prototypes; namespace Content.Shared.Ninja.Components; @@ -35,4 +35,22 @@ public sealed partial class SpaceNinjaComponent : Component /// [DataField("katana"), AutoNetworkedField] public EntityUid? Katana; + + /// + /// Objective to complete after calling in a threat. + /// + [DataField] + public EntProtoId TerrorObjective = "TerrorObjective"; + + /// + /// Objective to complete after setting everyone to arrest. + /// + [DataField] + public EntProtoId MassArrestObjective = "MassArrestObjective"; + + /// + /// Objective to complete after the spider charge detonates. + /// + [DataField] + public EntProtoId SpiderChargeObjective = "SpiderChargeObjective"; } diff --git a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs index f9e5d4a1f63..4853968b61f 100644 --- a/Content.Shared/Ninja/Systems/DashAbilitySystem.cs +++ b/Content.Shared/Ninja/Systems/DashAbilitySystem.cs @@ -4,8 +4,8 @@ using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; using Content.Shared.Ninja.Components; -using Content.Shared.Physics; using Content.Shared.Popups; +using Content.Shared.Examine; using Robust.Shared.Audio.Systems; using Robust.Shared.Timing; @@ -20,7 +20,7 @@ public sealed class DashAbilitySystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedChargesSystem _charges = default!; [Dependency] private readonly SharedHandsSystem _hands = default!; - [Dependency] private readonly SharedInteractionSystem _interaction = default!; + [Dependency] private readonly ExamineSystemShared _examine = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly ActionContainerSystem _actionContainer = default!; @@ -79,11 +79,10 @@ private void OnDash(EntityUid uid, DashAbilityComponent comp, DashEvent args) _popup.PopupClient(Loc.GetString("dash-ability-no-charges", ("item", uid)), user, user); return; } - - var origin = Transform(user).MapPosition; + var origin = _transform.GetMapCoordinates(user); var target = args.Target.ToMap(EntityManager, _transform); // prevent collision with the user duh - if (!_interaction.InRangeUnobstructed(origin, target, 0f, CollisionGroup.Opaque, uid => uid == user)) + if (!_examine.InRangeUnOccluded(origin, target, SharedInteractionSystem.MaxRaycastRange, null)) { // can only dash if the destination is visible on screen _popup.PopupClient(Loc.GetString("dash-ability-cant-see", ("item", uid)), user, user); diff --git a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs index 815464bf7a3..f61d0c6a908 100644 --- a/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs +++ b/Content.Shared/Ninja/Systems/SharedNinjaGlovesSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Actions; using Content.Shared.CombatMode; using Content.Shared.Communications; +using Content.Shared.CriminalRecords.Components; using Content.Shared.Examine; using Content.Shared.Hands.Components; using Content.Shared.Interaction; @@ -62,6 +63,7 @@ public void DisableGloves(EntityUid uid, NinjaGlovesComponent? comp = null) RemComp(user); RemComp(user); RemComp(user); + RemComp(user); } /// diff --git a/Content.Shared/Nutrition/Components/DrinkComponent.cs b/Content.Shared/Nutrition/Components/DrinkComponent.cs new file mode 100644 index 00000000000..17baaef5a37 --- /dev/null +++ b/Content.Shared/Nutrition/Components/DrinkComponent.cs @@ -0,0 +1,43 @@ +using Content.Shared.Nutrition.EntitySystems; +using Content.Shared.FixedPoint; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Nutrition.Components; + +[NetworkedComponent, AutoGenerateComponentState] +[RegisterComponent, Access(typeof(SharedDrinkSystem))] +public sealed partial class DrinkComponent : Component +{ + [DataField] + public string Solution = "drink"; + + [DataField, AutoNetworkedField] + public SoundSpecifier UseSound = new SoundPathSpecifier("/Audio/Items/drink.ogg"); + + [DataField, AutoNetworkedField] + public FixedPoint2 TransferAmount = FixedPoint2.New(5); + + /// + /// How long it takes to drink this yourself. + /// + [DataField, AutoNetworkedField] + public float Delay = 1; + + [DataField, AutoNetworkedField] + public bool Examinable = true; + + /// + /// If true, trying to drink when empty will not handle the event. + /// This means other systems such as equipping on use can run. + /// Example usecase is the bucket. + /// + [DataField] + public bool IgnoreEmpty; + + /// + /// This is how many seconds it takes to force feed someone this drink. + /// + [DataField, AutoNetworkedField] + public float ForceFeedDelay = 3; +} diff --git a/Content.Shared/Nutrition/Components/PressurizedSolutionComponent.cs b/Content.Shared/Nutrition/Components/PressurizedSolutionComponent.cs new file mode 100644 index 00000000000..7060f3bf799 --- /dev/null +++ b/Content.Shared/Nutrition/Components/PressurizedSolutionComponent.cs @@ -0,0 +1,106 @@ +using Content.Shared.Nutrition.EntitySystems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Nutrition.Components; + +/// +/// Represents a solution container that can hold the pressure from a solution that +/// gets fizzy when aggitated, and can spray the solution when opened or thrown. +/// Handles simulating the fizziness of the solution, responding to aggitating events, +/// and spraying the solution out when opening or throwing the entity. +/// +[NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +[RegisterComponent, Access(typeof(PressurizedSolutionSystem))] +public sealed partial class PressurizedSolutionComponent : Component +{ + /// + /// The name of the solution to use. + /// + [DataField] + public string Solution = "drink"; + + /// + /// The sound to play when the solution sprays out of the container. + /// + [DataField] + public SoundSpecifier SpraySound = new SoundPathSpecifier("/Audio/Items/soda_spray.ogg"); + + /// + /// The longest amount of time that the solution can remain fizzy after being aggitated. + /// Put another way, how long the solution will remain fizzy when aggitated the maximum amount. + /// Used to calculate the current fizziness level. + /// + [DataField] + public TimeSpan FizzinessMaxDuration = TimeSpan.FromSeconds(120); + + /// + /// The time at which the solution will be fully settled after being shaken. + /// + [DataField, AutoNetworkedField, AutoPausedField] + public TimeSpan FizzySettleTime; + + /// + /// How much to increase the solution's fizziness each time it's shaken. + /// This assumes the solution has maximum fizzability. + /// A value of 1 will maximize it with a single shake, and a value of + /// 0.5 will increase it by half with each shake. + /// + [DataField] + public float FizzinessAddedOnShake = 1.0f; + + /// + /// How much to increase the solution's fizziness when it lands after being thrown. + /// This assumes the solution has maximum fizzability. + /// + [DataField] + public float FizzinessAddedOnLand = 0.25f; + + /// + /// How much to modify the chance of spraying when the entity is opened. + /// Increasing this effectively increases the fizziness value when checking if it should spray. + /// + [DataField] + public float SprayChanceModOnOpened = -0.01f; // Just enough to prevent spraying at 0 fizziness + + /// + /// How much to modify the chance of spraying when the entity is shaken. + /// Increasing this effectively increases the fizziness value when checking if it should spray. + /// + [DataField] + public float SprayChanceModOnShake = -1; // No spraying when shaken by default + + /// + /// How much to modify the chance of spraying when the entity lands after being thrown. + /// Increasing this effectively increases the fizziness value when checking if it should spray. + /// + [DataField] + public float SprayChanceModOnLand = 0.25f; + + /// + /// Holds the current randomly-rolled threshold value for spraying. + /// If fizziness exceeds this value when the entity is opened, it will spray. + /// By rolling this value when the entity is aggitated, we can have randomization + /// while still having prediction! + /// + [DataField, AutoNetworkedField] + public float SprayFizzinessThresholdRoll; + + /// + /// Popup message shown to user when sprayed by the solution. + /// + [DataField] + public LocId SprayHolderMessageSelf = "pressurized-solution-spray-holder-self"; + + /// + /// Popup message shown to others when a user is sprayed by the solution. + /// + [DataField] + public LocId SprayHolderMessageOthers = "pressurized-solution-spray-holder-others"; + + /// + /// Popup message shown above the entity when the solution sprays without a target. + /// + [DataField] + public LocId SprayGroundMessage = "pressurized-solution-spray-ground"; +} diff --git a/Content.Shared/Nutrition/Components/ShakeableComponent.cs b/Content.Shared/Nutrition/Components/ShakeableComponent.cs new file mode 100644 index 00000000000..cc1c08a9b23 --- /dev/null +++ b/Content.Shared/Nutrition/Components/ShakeableComponent.cs @@ -0,0 +1,50 @@ +using Robust.Shared.Audio; +using Robust.Shared.GameStates; + +namespace Content.Shared.Nutrition.Components; + +/// +/// Adds a "Shake" verb to the entity's verb menu. +/// Handles checking the entity can be shaken, displaying popups when shaking, +/// and raising a ShakeEvent when a shake occurs. +/// Reacting to being shaken is left up to other components. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ShakeableComponent : Component +{ + /// + /// How long it takes to shake this item. + /// + [DataField] + public TimeSpan ShakeDuration = TimeSpan.FromSeconds(1f); + + /// + /// Does the entity need to be in the user's hand in order to be shaken? + /// + [DataField] + public bool RequireInHand; + + /// + /// Label to display in the verbs menu for this item's shake action. + /// + [DataField] + public LocId ShakeVerbText = "shakeable-verb"; + + /// + /// Text that will be displayed to the user when shaking this item. + /// + [DataField] + public LocId ShakePopupMessageSelf = "shakeable-popup-message-self"; + + /// + /// Text that will be displayed to other users when someone shakes this item. + /// + [DataField] + public LocId ShakePopupMessageOthers = "shakeable-popup-message-others"; + + /// + /// The sound that will be played when shaking this item. + /// + [DataField] + public SoundSpecifier ShakeSound = new SoundPathSpecifier("/Audio/Items/soda_shake.ogg"); +} diff --git a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs index 1bc2a945f31..e6d82553336 100644 --- a/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/HungerSystem.cs @@ -1,13 +1,17 @@ +using System.Diagnostics.CodeAnalysis; using Content.Shared.Alert; using Content.Shared.Damage; using Content.Shared.Mobs.Systems; using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Rejuvenate; +using Content.Shared.StatusIcon; +using Robust.Shared.Prototypes; using Content.Shared.Mood; using Robust.Shared.Network; using Robust.Shared.Random; using Robust.Shared.Timing; +using Robust.Shared.Utility; using Robust.Shared.Configuration; using Content.Shared.CCVar; @@ -16,6 +20,7 @@ namespace Content.Shared.Nutrition.EntitySystems; public sealed class HungerSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly DamageableSystem _damageable = default!; @@ -25,10 +30,27 @@ public sealed class HungerSystem : EntitySystem [Dependency] private readonly INetManager _net = default!; [Dependency] private readonly IConfigurationManager _config = default!; + [ValidatePrototypeId] + private const string HungerIconOverfedId = "HungerIconOverfed"; + + [ValidatePrototypeId] + private const string HungerIconPeckishId = "HungerIconPeckish"; + + [ValidatePrototypeId] + private const string HungerIconStarvingId = "HungerIconStarving"; + + private StatusIconPrototype? _hungerIconOverfed; + private StatusIconPrototype? _hungerIconPeckish; + private StatusIconPrototype? _hungerIconStarving; + public override void Initialize() { base.Initialize(); + DebugTools.Assert(_prototype.TryIndex(HungerIconOverfedId, out _hungerIconOverfed) && + _prototype.TryIndex(HungerIconPeckishId, out _hungerIconPeckish) && + _prototype.TryIndex(HungerIconStarvingId, out _hungerIconStarving)); + SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnShutdown); SubscribeLocalEvent(OnRefreshMovespeed); @@ -205,6 +227,27 @@ private bool GetMovementThreshold(HungerThreshold threshold) } } + public bool TryGetStatusIconPrototype(HungerComponent component, [NotNullWhen(true)] out StatusIconPrototype? prototype) + { + switch (component.CurrentThreshold) + { + case HungerThreshold.Overfed: + prototype = _hungerIconOverfed; + break; + case HungerThreshold.Peckish: + prototype = _hungerIconPeckish; + break; + case HungerThreshold.Starving: + prototype = _hungerIconStarving; + break; + default: + prototype = null; + break; + } + + return prototype != null; + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -221,4 +264,3 @@ public override void Update(float frameTime) } } } - diff --git a/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs b/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs index 0ad0877d222..2934ced8b4a 100644 --- a/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/OpenableSystem.cs @@ -16,9 +16,9 @@ namespace Content.Shared.Nutrition.EntitySystems; /// public sealed partial class OpenableSystem : EntitySystem { - [Dependency] protected readonly SharedAppearanceSystem Appearance = default!; - [Dependency] protected readonly SharedAudioSystem Audio = default!; - [Dependency] protected readonly SharedPopupSystem Popup = default!; + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; public override void Initialize() { @@ -31,6 +31,8 @@ public override void Initialize() SubscribeLocalEvent(HandleIfClosed); SubscribeLocalEvent>(AddOpenCloseVerbs); SubscribeLocalEvent(OnTransferAttempt); + SubscribeLocalEvent(OnAttemptShake); + SubscribeLocalEvent(OnAttemptAddFizziness); } private void OnInit(EntityUid uid, OpenableComponent comp, ComponentInit args) @@ -100,6 +102,20 @@ private void OnTransferAttempt(Entity ent, ref SolutionTransf } } + private void OnAttemptShake(Entity entity, ref AttemptShakeEvent args) + { + // Prevent shaking open containers + if (entity.Comp.Opened) + args.Cancelled = true; + } + + private void OnAttemptAddFizziness(Entity entity, ref AttemptAddFizzinessEvent args) + { + // Can't add fizziness to an open container + if (entity.Comp.Opened) + args.Cancelled = true; + } + /// /// Returns true if the entity either does not have OpenableComponent or it is opened. /// Drinks that don't have OpenableComponent are automatically open, so it returns true. @@ -126,7 +142,7 @@ public bool IsClosed(EntityUid uid, EntityUid? user = null, OpenableComponent? c return false; if (user != null) - Popup.PopupEntity(Loc.GetString(comp.ClosedPopup, ("owner", uid)), user.Value, user.Value); + _popup.PopupEntity(Loc.GetString(comp.ClosedPopup, ("owner", uid)), user.Value, user.Value); return true; } @@ -139,13 +155,13 @@ public void UpdateAppearance(EntityUid uid, OpenableComponent? comp = null, Appe if (!Resolve(uid, ref comp)) return; - Appearance.SetData(uid, OpenableVisuals.Opened, comp.Opened, appearance); + _appearance.SetData(uid, OpenableVisuals.Opened, comp.Opened, appearance); } /// /// Sets the opened field and updates open visuals. /// - public void SetOpen(EntityUid uid, bool opened = true, OpenableComponent? comp = null) + public void SetOpen(EntityUid uid, bool opened = true, OpenableComponent? comp = null, EntityUid? user = null) { if (!Resolve(uid, ref comp, false) || opened == comp.Opened) return; @@ -155,12 +171,12 @@ public void SetOpen(EntityUid uid, bool opened = true, OpenableComponent? comp = if (opened) { - var ev = new OpenableOpenedEvent(); + var ev = new OpenableOpenedEvent(user); RaiseLocalEvent(uid, ref ev); } else { - var ev = new OpenableClosedEvent(); + var ev = new OpenableClosedEvent(user); RaiseLocalEvent(uid, ref ev); } @@ -176,8 +192,8 @@ public bool TryOpen(EntityUid uid, OpenableComponent? comp = null, EntityUid? us if (!Resolve(uid, ref comp, false) || comp.Opened) return false; - SetOpen(uid, true, comp); - Audio.PlayPredicted(comp.Sound, uid, user); + SetOpen(uid, true, comp, user); + _audio.PlayPredicted(comp.Sound, uid, user); return true; } @@ -190,9 +206,9 @@ public bool TryClose(EntityUid uid, OpenableComponent? comp = null, EntityUid? u if (!Resolve(uid, ref comp, false) || !comp.Opened || !comp.Closeable) return false; - SetOpen(uid, false, comp); + SetOpen(uid, false, comp, user); if (comp.CloseSound != null) - Audio.PlayPredicted(comp.CloseSound, uid, user); + _audio.PlayPredicted(comp.CloseSound, uid, user); return true; } } @@ -201,10 +217,10 @@ public bool TryClose(EntityUid uid, OpenableComponent? comp = null, EntityUid? u /// Raised after an Openable is opened. /// [ByRefEvent] -public record struct OpenableOpenedEvent; +public record struct OpenableOpenedEvent(EntityUid? User = null); /// /// Raised after an Openable is closed. /// [ByRefEvent] -public record struct OpenableClosedEvent; +public record struct OpenableClosedEvent(EntityUid? User = null); diff --git a/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs new file mode 100644 index 00000000000..d63b8e7326c --- /dev/null +++ b/Content.Shared/Nutrition/EntitySystems/PressurizedSolutionSystem.cs @@ -0,0 +1,285 @@ +using Content.Shared.Chemistry.Reagent; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Nutrition.Components; +using Content.Shared.Throwing; +using Content.Shared.IdentityManagement; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Random; +using Robust.Shared.Timing; +using Robust.Shared.Prototypes; +using Robust.Shared.Network; +using Content.Shared.Fluids; +using Content.Shared.Popups; + +namespace Content.Shared.Nutrition.EntitySystems; + +public sealed partial class PressurizedSolutionSystem : EntitySystem +{ + [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; + [Dependency] private readonly OpenableSystem _openable = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedPuddleSystem _puddle = default!; + [Dependency] private readonly INetManager _net = default!; + [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShake); + SubscribeLocalEvent(OnOpened); + SubscribeLocalEvent(OnLand); + SubscribeLocalEvent(OnSolutionUpdate); + } + + /// + /// Helper method for checking if the solution's fizziness is high enough to spray. + /// is added to the actual fizziness for the comparison. + /// + private bool SprayCheck(Entity entity, float chanceMod = 0) + { + return Fizziness((entity, entity.Comp)) + chanceMod > entity.Comp.SprayFizzinessThresholdRoll; + } + + /// + /// Calculates how readily the contained solution becomes fizzy. + /// + private float SolutionFizzability(Entity entity) + { + if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out var _, out var solution)) + return 0; + + // An empty solution can't be fizzy + if (solution.Volume <= 0) + return 0; + + var totalFizzability = 0f; + + // Check each reagent in the solution + foreach (var reagent in solution.Contents) + { + if (_prototypeManager.TryIndex(reagent.Reagent.Prototype, out ReagentPrototype? reagentProto) && reagentProto != null) + { + // What portion of the solution is this reagent? + var proportion = (float) (reagent.Quantity / solution.Volume); + totalFizzability += reagentProto.Fizziness * proportion; + } + } + + return totalFizzability; + } + + /// + /// Increases the fizziness level of the solution by the given amount, + /// scaled by the solution's fizzability. + /// 0 will result in no change, and 1 will maximize fizziness. + /// Also rerolls the spray threshold. + /// + private void AddFizziness(Entity entity, float amount) + { + var fizzability = SolutionFizzability(entity); + + // Can't add fizziness if the solution isn't fizzy + if (fizzability <= 0) + return; + + // Make sure nothing is preventing fizziness from being added + var attemptEv = new AttemptAddFizzinessEvent(entity, amount); + RaiseLocalEvent(entity, ref attemptEv); + if (attemptEv.Cancelled) + return; + + // Scale added fizziness by the solution's fizzability + amount *= fizzability; + + // Convert fizziness to time + var duration = amount * entity.Comp.FizzinessMaxDuration; + + // Add to the existing settle time, if one exists. Otherwise, add to the current time + var start = entity.Comp.FizzySettleTime > _timing.CurTime ? entity.Comp.FizzySettleTime : _timing.CurTime; + var newTime = start + duration; + + // Cap the maximum fizziness + var maxEnd = _timing.CurTime + entity.Comp.FizzinessMaxDuration; + if (newTime > maxEnd) + newTime = maxEnd; + + entity.Comp.FizzySettleTime = newTime; + + // Roll a new fizziness threshold + RollSprayThreshold(entity); + } + + /// + /// Helper method. Performs a . If it passes, calls . If it fails, . + /// + private void SprayOrAddFizziness(Entity entity, float chanceMod = 0, float fizzinessToAdd = 0, EntityUid? user = null) + { + if (SprayCheck(entity, chanceMod)) + TrySpray((entity, entity.Comp), user); + else + AddFizziness(entity, fizzinessToAdd); + } + + /// + /// Randomly generates a new spray threshold. + /// This is the value used to compare fizziness against when doing . + /// Since RNG will give different results between client and server, this is run on the server + /// and synced to the client by marking the component dirty. + /// We roll this in advance, rather than during , so that the value (hopefully) + /// has time to get synced to the client, so we can try be accurate with prediction. + /// + private void RollSprayThreshold(Entity entity) + { + // Can't predict random, so we wait for the server to tell us + if (!_net.IsServer) + return; + + entity.Comp.SprayFizzinessThresholdRoll = _random.NextFloat(); + Dirty(entity, entity.Comp); + } + + #region Public API + + /// + /// Does the entity contain a solution capable of being fizzy? + /// + public bool CanSpray(Entity entity) + { + if (!Resolve(entity, ref entity.Comp, false)) + return false; + + return SolutionFizzability((entity, entity.Comp)) > 0; + } + + /// + /// Attempts to spray the solution onto the given entity, or the ground if none is given. + /// Fails if the solution isn't able to be sprayed. + /// + public bool TrySpray(Entity entity, EntityUid? target = null) + { + if (!Resolve(entity, ref entity.Comp)) + return false; + + if (!CanSpray(entity)) + return false; + + if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out var soln, out var interactions)) + return false; + + // If the container is openable, open it + _openable.SetOpen(entity, true); + + // Get the spray solution from the container + var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume); + + // Spray the solution onto the ground and anyone nearby + if (TryComp(entity, out var transform)) + _puddle.TrySplashSpillAt(entity, transform.Coordinates, solution, out _, sound: false); + + var drinkName = Identity.Entity(entity, EntityManager); + + if (target != null) + { + var victimName = Identity.Entity(target.Value, EntityManager); + + var selfMessage = Loc.GetString(entity.Comp.SprayHolderMessageSelf, ("victim", victimName), ("drink", drinkName)); + var othersMessage = Loc.GetString(entity.Comp.SprayHolderMessageOthers, ("victim", victimName), ("drink", drinkName)); + _popup.PopupPredicted(selfMessage, othersMessage, target.Value, target.Value); + } + else + { + // Show a popup to everyone in PVS range + if (_timing.IsFirstTimePredicted) + _popup.PopupEntity(Loc.GetString(entity.Comp.SprayGroundMessage, ("drink", drinkName)), entity); + } + + _audio.PlayPredicted(entity.Comp.SpraySound, entity, target); + + // We just used all our fizziness, so clear it + TryClearFizziness(entity); + + return true; + } + + /// + /// What is the current fizziness level of the solution, from 0 to 1? + /// + public double Fizziness(Entity entity) + { + // No component means no fizz + if (!Resolve(entity, ref entity.Comp, false)) + return 0; + + // No negative fizziness + if (entity.Comp.FizzySettleTime <= _timing.CurTime) + return 0; + + var currentDuration = entity.Comp.FizzySettleTime - _timing.CurTime; + return Easings.InOutCubic((float) Math.Min(currentDuration / entity.Comp.FizzinessMaxDuration, 1)); + } + + /// + /// Attempts to clear any fizziness in the solution. + /// + /// Rolls a new spray threshold. + public void TryClearFizziness(Entity entity) + { + if (!Resolve(entity, ref entity.Comp)) + return; + + entity.Comp.FizzySettleTime = TimeSpan.Zero; + + // Roll a new fizziness threshold + RollSprayThreshold((entity, entity.Comp)); + } + + #endregion + + #region Event Handlers + private void OnMapInit(Entity entity, ref MapInitEvent args) + { + RollSprayThreshold(entity); + } + + private void OnOpened(Entity entity, ref OpenableOpenedEvent args) + { + // Make sure the opener is actually holding the drink + var held = args.User != null && _hands.IsHolding(args.User.Value, entity, out _); + + SprayOrAddFizziness(entity, entity.Comp.SprayChanceModOnOpened, -1, held ? args.User : null); + } + + private void OnShake(Entity entity, ref ShakeEvent args) + { + SprayOrAddFizziness(entity, entity.Comp.SprayChanceModOnShake, entity.Comp.FizzinessAddedOnShake, args.Shaker); + } + + private void OnLand(Entity entity, ref LandEvent args) + { + SprayOrAddFizziness(entity, entity.Comp.SprayChanceModOnLand, entity.Comp.FizzinessAddedOnLand); + } + + private void OnSolutionUpdate(Entity entity, ref SolutionContainerChangedEvent args) + { + if (args.SolutionId != entity.Comp.Solution) + return; + + // If the solution is no longer capable of being fizzy, clear any built up fizziness + if (SolutionFizzability(entity) <= 0) + TryClearFizziness((entity, entity.Comp)); + } + + #endregion +} + +[ByRefEvent] +public record struct AttemptAddFizzinessEvent(Entity Entity, float Amount) +{ + public bool Cancelled; +} diff --git a/Content.Shared/Nutrition/EntitySystems/ShakeableSystem.cs b/Content.Shared/Nutrition/EntitySystems/ShakeableSystem.cs new file mode 100644 index 00000000000..39890aada93 --- /dev/null +++ b/Content.Shared/Nutrition/EntitySystems/ShakeableSystem.cs @@ -0,0 +1,155 @@ +using Content.Shared.DoAfter; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.IdentityManagement; +using Content.Shared.Nutrition.Components; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Serialization; + +namespace Content.Shared.Nutrition.EntitySystems; + +public sealed partial class ShakeableSystem : EntitySystem +{ + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly SharedAudioSystem _audio = default!; + [Dependency] private readonly SharedDoAfterSystem _doAfter = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(AddShakeVerb); + SubscribeLocalEvent(OnShakeDoAfter); + } + + private void AddShakeVerb(EntityUid uid, ShakeableComponent component, GetVerbsEvent args) + { + if (args.Hands == null || !args.CanAccess || !args.CanInteract) + return; + + if (!CanShake((uid, component), args.User)) + return; + + var shakeVerb = new Verb() + { + Text = Loc.GetString(component.ShakeVerbText), + Act = () => TryStartShake((args.Target, component), args.User) + }; + args.Verbs.Add(shakeVerb); + } + + private void OnShakeDoAfter(Entity entity, ref ShakeDoAfterEvent args) + { + if (args.Handled || args.Cancelled) + return; + + TryShake((entity, entity.Comp), args.User); + } + + /// + /// Attempts to start the doAfter to shake the entity. + /// Fails and returns false if the entity cannot be shaken for any reason. + /// If successful, displays popup messages, plays shake sound, and starts the doAfter. + /// + public bool TryStartShake(Entity entity, EntityUid user) + { + if (!Resolve(entity, ref entity.Comp)) + return false; + + if (!CanShake(entity, user)) + return false; + + var doAfterArgs = new DoAfterArgs(EntityManager, + user, + entity.Comp.ShakeDuration, + new ShakeDoAfterEvent(), + eventTarget: entity, + target: user, + used: entity) + { + NeedHand = true, + BreakOnDamage = true, + DistanceThreshold = 1, + MovementThreshold = 0.01f, + BreakOnHandChange = entity.Comp.RequireInHand, + }; + if (entity.Comp.RequireInHand) + doAfterArgs.BreakOnHandChange = true; + + if (!_doAfter.TryStartDoAfter(doAfterArgs)) + return false; + + var userName = Identity.Entity(user, EntityManager); + var shakeableName = Identity.Entity(entity, EntityManager); + + var selfMessage = Loc.GetString(entity.Comp.ShakePopupMessageSelf, ("user", userName), ("shakeable", shakeableName)); + var othersMessage = Loc.GetString(entity.Comp.ShakePopupMessageOthers, ("user", userName), ("shakeable", shakeableName)); + _popup.PopupPredicted(selfMessage, othersMessage, user, user); + + _audio.PlayPredicted(entity.Comp.ShakeSound, entity, user); + + return true; + } + + /// + /// Attempts to shake the entity, skipping the doAfter. + /// Fails and returns false if the entity cannot be shaken for any reason. + /// If successful, raises a ShakeEvent on the entity. + /// + public bool TryShake(Entity entity, EntityUid? user = null) + { + if (!Resolve(entity, ref entity.Comp)) + return false; + + if (!CanShake(entity, user)) + return false; + + var ev = new ShakeEvent(user); + RaiseLocalEvent(entity, ref ev); + + return true; + } + + + /// + /// Is it possible for the given user to shake the entity? + /// + public bool CanShake(Entity entity, EntityUid? user = null) + { + if (!Resolve(entity, ref entity.Comp, false)) + return false; + + // If required to be in hand, fail if the user is not holding this entity + if (user != null && entity.Comp.RequireInHand && !_hands.IsHolding(user.Value, entity, out _)) + return false; + + var attemptEv = new AttemptShakeEvent(); + RaiseLocalEvent(entity, ref attemptEv); + if (attemptEv.Cancelled) + return false; + return true; + } +} + +/// +/// Raised when a ShakeableComponent is shaken, after the doAfter completes. +/// +[ByRefEvent] +public record struct ShakeEvent(EntityUid? Shaker); + +/// +/// Raised when trying to shake a ShakeableComponent. If cancelled, the +/// entity will not be shaken. +/// +[ByRefEvent] +public record struct AttemptShakeEvent() +{ + public bool Cancelled; +} + +[Serializable, NetSerializable] +public sealed partial class ShakeDoAfterEvent : SimpleDoAfterEvent +{ +} diff --git a/Content.Shared/Nutrition/EntitySystems/SharedDrinkSystem.cs b/Content.Shared/Nutrition/EntitySystems/SharedDrinkSystem.cs new file mode 100644 index 00000000000..7cae3b92086 --- /dev/null +++ b/Content.Shared/Nutrition/EntitySystems/SharedDrinkSystem.cs @@ -0,0 +1,90 @@ +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Chemistry.EntitySystems; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Nutrition.Components; + +namespace Content.Shared.Nutrition.EntitySystems; + +public abstract partial class SharedDrinkSystem : EntitySystem +{ + [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!; + [Dependency] private readonly OpenableSystem _openable = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAttemptShake); + SubscribeLocalEvent(OnExamined); + } + + protected void OnAttemptShake(Entity entity, ref AttemptShakeEvent args) + { + if (IsEmpty(entity, entity.Comp)) + args.Cancelled = true; + } + + protected void OnExamined(Entity entity, ref ExaminedEvent args) + { + TryComp(entity, out var openable); + if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable) + return; + + var empty = IsEmpty(entity, entity.Comp); + if (empty) + { + args.PushMarkup(Loc.GetString("drink-component-on-examine-is-empty")); + return; + } + + if (HasComp(entity)) + { + //provide exact measurement for beakers + args.PushText(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp)))); + } + else + { + //general approximation + var remainingString = (int) _solutionContainer.PercentFull(entity) switch + { + 100 => "drink-component-on-examine-is-full", + > 66 => "drink-component-on-examine-is-mostly-full", + > 33 => HalfEmptyOrHalfFull(args), + _ => "drink-component-on-examine-is-mostly-empty", + }; + args.PushMarkup(Loc.GetString(remainingString)); + } + } + + protected FixedPoint2 DrinkVolume(EntityUid uid, DrinkComponent? component = null) + { + if (!Resolve(uid, ref component)) + return FixedPoint2.Zero; + + if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol)) + return FixedPoint2.Zero; + + return sol.Volume; + } + + protected bool IsEmpty(EntityUid uid, DrinkComponent? component = null) + { + if (!Resolve(uid, ref component)) + return true; + + return DrinkVolume(uid, component) <= 0; + } + + // some see half empty, and others see half full + private string HalfEmptyOrHalfFull(ExaminedEvent args) + { + string remainingString = "drink-component-on-examine-is-half-full"; + + if (TryComp(args.Examiner, out var examiner) && examiner.EntityName.Length > 0 + && string.Compare(examiner.EntityName.Substring(0, 1), "m", StringComparison.InvariantCultureIgnoreCase) > 0) + remainingString = "drink-component-on-examine-is-half-empty"; + + return remainingString; + } +} diff --git a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs index f1ddc9b2b5e..a068b19104c 100644 --- a/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs +++ b/Content.Shared/Nutrition/EntitySystems/ThirstSystem.cs @@ -3,9 +3,12 @@ using Content.Shared.Movement.Systems; using Content.Shared.Nutrition.Components; using Content.Shared.Rejuvenate; +using Content.Shared.StatusIcon; using JetBrains.Annotations; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Timing; +using Robust.Shared.Utility; using Content.Shared.Mood; using Robust.Shared.Configuration; using Content.Shared.CCVar; @@ -16,16 +19,34 @@ namespace Content.Shared.Nutrition.EntitySystems; public sealed class ThirstSystem : EntitySystem { [Dependency] private readonly IGameTiming _timing = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly AlertsSystem _alerts = default!; [Dependency] private readonly MovementSpeedModifierSystem _movement = default!; [Dependency] private readonly SharedJetpackSystem _jetpack = default!; [Dependency] private readonly IConfigurationManager _config = default!; + [ValidatePrototypeId] + private const string ThirstIconOverhydratedId = "ThirstIconOverhydrated"; + + [ValidatePrototypeId] + private const string ThirstIconThirstyId = "ThirstIconThirsty"; + + [ValidatePrototypeId] + private const string ThirstIconParchedId = "ThirstIconParched"; + + private StatusIconPrototype? _thirstIconOverhydrated = null; + private StatusIconPrototype? _thirstIconThirsty = null; + private StatusIconPrototype? _thirstIconParched = null; + public override void Initialize() { base.Initialize(); + DebugTools.Assert(_prototype.TryIndex(ThirstIconOverhydratedId, out _thirstIconOverhydrated) && + _prototype.TryIndex(ThirstIconThirstyId, out _thirstIconThirsty) && + _prototype.TryIndex(ThirstIconParchedId, out _thirstIconParched)); + SubscribeLocalEvent(OnRefreshMovespeed); SubscribeLocalEvent(OnMapInit); SubscribeLocalEvent(OnRejuvenate); @@ -112,6 +133,28 @@ private bool IsMovementThreshold(ThirstThreshold threshold) } } + public bool TryGetStatusIconPrototype(ThirstComponent component, out StatusIconPrototype? prototype) + { + switch (component.CurrentThirstThreshold) + { + case ThirstThreshold.OverHydrated: + prototype = _thirstIconOverhydrated; + return true; + + case ThirstThreshold.Thirsty: + prototype = _thirstIconThirsty; + return true; + + case ThirstThreshold.Parched: + prototype = _thirstIconParched; + return true; + + default: + prototype = null; + return false; + } + } + private void UpdateEffects(EntityUid uid, ThirstComponent component) { if (!_config.GetCVar(CCVars.MoodEnabled) diff --git a/Content.Shared/Nyanotrasen/Mail/MailDeliveryPoolPrototype.cs b/Content.Shared/Nyanotrasen/Mail/MailDeliveryPoolPrototype.cs index 544f489d28f..4de374a164c 100644 --- a/Content.Shared/Nyanotrasen/Mail/MailDeliveryPoolPrototype.cs +++ b/Content.Shared/Nyanotrasen/Mail/MailDeliveryPoolPrototype.cs @@ -6,7 +6,7 @@ namespace Content.Shared.Mail; /// Generic random weighting dataset to use. /// [Prototype("mailDeliveryPool")] -public sealed class MailDeliveryPoolPrototype : IPrototype +public sealed partial class MailDeliveryPoolPrototype : IPrototype { [IdDataFieldAttribute] public string ID { get; } = default!; diff --git a/Content.Shared/Objectives/ObjectiveInfo.cs b/Content.Shared/Objectives/ObjectiveInfo.cs index 689fe17e6c8..0b7e7a15f6e 100644 --- a/Content.Shared/Objectives/ObjectiveInfo.cs +++ b/Content.Shared/Objectives/ObjectiveInfo.cs @@ -1,3 +1,4 @@ +using Content.Shared.Objectives.Components; using Robust.Shared.Serialization; using Robust.Shared.Utility; diff --git a/Content.Shared/Overlays/ShowCriminalRecordIconsComponent.cs b/Content.Shared/Overlays/ShowCriminalRecordIconsComponent.cs new file mode 100644 index 00000000000..cb0759be3ee --- /dev/null +++ b/Content.Shared/Overlays/ShowCriminalRecordIconsComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Overlays; + +/// +/// This component allows you to see criminal record status of mobs. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ShowCriminalRecordIconsComponent : Component { } diff --git a/Content.Shared/Overlays/ShowHungerIconsComponent.cs b/Content.Shared/Overlays/ShowHungerIconsComponent.cs index bf1fb2dc19d..b3841bd80ff 100644 --- a/Content.Shared/Overlays/ShowHungerIconsComponent.cs +++ b/Content.Shared/Overlays/ShowHungerIconsComponent.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Overlays; /// -/// This component allows you to see the hungriness of mobs. +/// This component allows you to see the hungriness of mobs. /// [RegisterComponent, NetworkedComponent] public sealed partial class ShowHungerIconsComponent : Component { } diff --git a/Content.Shared/Overlays/ShowJobIconsComponent.cs b/Content.Shared/Overlays/ShowJobIconsComponent.cs new file mode 100644 index 00000000000..aae97395063 --- /dev/null +++ b/Content.Shared/Overlays/ShowJobIconsComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Overlays; + +/// +/// This component allows you to see job icons above mobs. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ShowJobIconsComponent : Component { } diff --git a/Content.Shared/Overlays/ShowMindShieldIconsComponent.cs b/Content.Shared/Overlays/ShowMindShieldIconsComponent.cs new file mode 100644 index 00000000000..624d5ab8efc --- /dev/null +++ b/Content.Shared/Overlays/ShowMindShieldIconsComponent.cs @@ -0,0 +1,9 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Overlays; + +/// +/// This component allows you to see mindshield icons above mobs. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ShowMindShieldIconsComponent : Component { } diff --git a/Content.Shared/Overlays/ShowSecurityIconsComponent.cs b/Content.Shared/Overlays/ShowSecurityIconsComponent.cs deleted file mode 100644 index ec268174d18..00000000000 --- a/Content.Shared/Overlays/ShowSecurityIconsComponent.cs +++ /dev/null @@ -1,9 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.Overlays; - -/// -/// This component allows you to see job icons above mobs. -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class ShowSecurityIconsComponent : Component { } diff --git a/Content.Shared/Overlays/ShowSyndicateIconsComponent.cs b/Content.Shared/Overlays/ShowSyndicateIconsComponent.cs index 74a67db694a..a63eae8e466 100644 --- a/Content.Shared/Overlays/ShowSyndicateIconsComponent.cs +++ b/Content.Shared/Overlays/ShowSyndicateIconsComponent.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Overlays; /// -/// +/// This component allows you to identify members of the Syndicate faction. /// [RegisterComponent, NetworkedComponent] public sealed partial class ShowSyndicateIconsComponent : Component {} diff --git a/Content.Shared/Overlays/ShowThirstIconsComponent.cs b/Content.Shared/Overlays/ShowThirstIconsComponent.cs index 905ab07fe23..1914034e9e3 100644 --- a/Content.Shared/Overlays/ShowThirstIconsComponent.cs +++ b/Content.Shared/Overlays/ShowThirstIconsComponent.cs @@ -3,7 +3,7 @@ namespace Content.Shared.Overlays; /// -/// This component allows you to see the thirstiness of mobs. +/// This component allows you to see the thirstiness of mobs. /// [RegisterComponent, NetworkedComponent] public sealed partial class ShowThirstIconsComponent : Component { } diff --git a/Content.Shared/Paper/SharedPaperComponent.cs b/Content.Shared/Paper/SharedPaperComponent.cs index dd87f9f907a..f65a599e539 100644 --- a/Content.Shared/Paper/SharedPaperComponent.cs +++ b/Content.Shared/Paper/SharedPaperComponent.cs @@ -1,8 +1,10 @@ using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Serialization; namespace Content.Shared.Paper; +[NetworkedComponent] public abstract partial class SharedPaperComponent : Component { /// diff --git a/Content.Shared/Payload/Components/PayloadTriggerComponent.cs b/Content.Shared/Payload/Components/PayloadTriggerComponent.cs index 6d3df41ac97..b064e91198c 100644 --- a/Content.Shared/Payload/Components/PayloadTriggerComponent.cs +++ b/Content.Shared/Payload/Components/PayloadTriggerComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Explosion.Components; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; diff --git a/Content.Shared/Physics/CollisionGroup.cs b/Content.Shared/Physics/CollisionGroup.cs index 1c10fefd5dc..775ccb7c446 100644 --- a/Content.Shared/Physics/CollisionGroup.cs +++ b/Content.Shared/Physics/CollisionGroup.cs @@ -48,6 +48,9 @@ public enum CollisionGroup MachineLayer = Opaque | MidImpassable | LowImpassable | BulletImpassable, ConveyorMask = Impassable | MidImpassable | LowImpassable | DoorPassable, + // Crates + CrateMask = Impassable | HighImpassable | LowImpassable, + // Tables that SmallMobs can go under TableMask = Impassable | MidImpassable, TableLayer = MidImpassable, diff --git a/Content.Shared/Pinpointer/NavMapComponent.cs b/Content.Shared/Pinpointer/NavMapComponent.cs index 8c9979ba25a..d77169d32ed 100644 --- a/Content.Shared/Pinpointer/NavMapComponent.cs +++ b/Content.Shared/Pinpointer/NavMapComponent.cs @@ -1,9 +1,13 @@ +using System.Linq; +using Content.Shared.Atmos; using Robust.Shared.GameStates; +using Robust.Shared.Serialization; +using Robust.Shared.Timing; namespace Content.Shared.Pinpointer; /// -/// Used to store grid poly data to be used for UIs. +/// Used to store grid data to be used for UIs. /// [RegisterComponent, NetworkedComponent] public sealed partial class NavMapComponent : Component @@ -12,25 +16,47 @@ public sealed partial class NavMapComponent : Component * Don't need DataFields as this can be reconstructed */ + /// + /// Bitmasks that represent chunked tiles. + /// [ViewVariables] - public readonly Dictionary Chunks = new(); + public Dictionary Chunks = new(); - [ViewVariables] public readonly List Beacons = new(); - - [ViewVariables] public readonly List Airlocks = new(); + /// + /// List of station beacons. + /// + [ViewVariables] + public Dictionary Beacons = new(); } -public sealed class NavMapChunk +[Serializable, NetSerializable] +public sealed class NavMapChunk(Vector2i origin) { - public readonly Vector2i Origin; + /// + /// The chunk origin + /// + [ViewVariables] + public readonly Vector2i Origin = origin; + + /// + /// Array containing the chunk's data. The + /// + [ViewVariables] + public int[] TileData = new int[SharedNavMapSystem.ArraySize]; /// - /// Bitmask for tiles, 1 for occupied and 0 for empty. + /// The last game tick that the chunk was updated /// - public int TileData; + [NonSerialized] + public GameTick LastUpdate; +} - public NavMapChunk(Vector2i origin) - { - Origin = origin; - } +public enum NavMapChunkType : byte +{ + // Values represent bit shift offsets when retrieving data in the tile array. + Invalid = byte.MaxValue, + Floor = 0, // I believe floors have directional information for diagonal tiles? + Wall = SharedNavMapSystem.Directions, + Airlock = 2 * SharedNavMapSystem.Directions, } + diff --git a/Content.Shared/Pinpointer/SharedNavMapSystem.cs b/Content.Shared/Pinpointer/SharedNavMapSystem.cs index 17f86ac7e68..0edcd5a4378 100644 --- a/Content.Shared/Pinpointer/SharedNavMapSystem.cs +++ b/Content.Shared/Pinpointer/SharedNavMapSystem.cs @@ -1,49 +1,194 @@ +using System.Diagnostics.CodeAnalysis; using System.Numerics; +using System.Runtime.CompilerServices; +using Content.Shared.Tag; +using Robust.Shared.GameStates; using Robust.Shared.Serialization; +using Robust.Shared.Timing; using Robust.Shared.Utility; namespace Content.Shared.Pinpointer; public abstract class SharedNavMapSystem : EntitySystem { - public const byte ChunkSize = 4; + public const int Categories = 3; + public const int Directions = 4; // Not directly tied to number of atmos directions - /// - /// Converts the chunk's tile into a bitflag for the slot. - /// - public static int GetFlag(Vector2i relativeTile) + public const int ChunkSize = 8; + public const int ArraySize = ChunkSize* ChunkSize; + + public const int AllDirMask = (1 << Directions) - 1; + public const int AirlockMask = AllDirMask << (int) NavMapChunkType.Airlock; + public const int WallMask = AllDirMask << (int) NavMapChunkType.Wall; + public const int FloorMask = AllDirMask << (int) NavMapChunkType.Floor; + + [Robust.Shared.IoC.Dependency] private readonly TagSystem _tagSystem = default!; + [Robust.Shared.IoC.Dependency] private readonly IGameTiming _gameTiming = default!; + + private readonly string[] _wallTags = ["Wall", "Window"]; + private EntityQuery _doorQuery; + + public override void Initialize() { - return 1 << (relativeTile.X * ChunkSize + relativeTile.Y); + base.Initialize(); + + // Data handling events + SubscribeLocalEvent(OnGetState); + _doorQuery = GetEntityQuery(); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetTileIndex(Vector2i relativeTile) + { + return relativeTile.X * ChunkSize + relativeTile.Y; } /// - /// Converts the chunk's tile into a bitflag for the slot. + /// Inverse of /// - public static Vector2i GetTile(int flag) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2i GetTileFromIndex(int index) + { + var x = index / ChunkSize; + var y = index % ChunkSize; + return new Vector2i(x, y); + } + + public NavMapChunkType GetEntityType(EntityUid uid) { - var value = Math.Log2(flag); - var x = (int) value / ChunkSize; - var y = (int) value % ChunkSize; - var result = new Vector2i(x, y); + if (_doorQuery.HasComp(uid)) + return NavMapChunkType.Airlock; - DebugTools.Assert(GetFlag(result) == flag); + if (_tagSystem.HasAnyTag(uid, _wallTags)) + return NavMapChunkType.Wall; - return new Vector2i(x, y); + return NavMapChunkType.Invalid; } - [Serializable, NetSerializable] - protected sealed class NavMapComponentState : ComponentState + protected bool TryCreateNavMapBeaconData(EntityUid uid, NavMapBeaconComponent component, TransformComponent xform, MetaDataComponent meta, [NotNullWhen(true)] out NavMapBeacon? beaconData) + { + beaconData = null; + + if (!component.Enabled || xform.GridUid == null || !xform.Anchored) + return false; + + var name = component.Text; + if (string.IsNullOrEmpty(name)) + name = meta.EntityName; + + beaconData = new NavMapBeacon(meta.NetEntity, component.Color, name, xform.LocalPosition); + + return true; + } + + #region: Event handling + + private void OnGetState(EntityUid uid, NavMapComponent component, ref ComponentGetState args) { - public Dictionary TileData = new(); + Dictionary chunks; + + // Should this be a full component state or a delta-state? + if (args.FromTick <= component.CreationTick) + { + // Full state + chunks = new(component.Chunks.Count); + foreach (var (origin, chunk) in component.Chunks) + { + chunks.Add(origin, chunk.TileData); + } - public List Beacons = new(); + args.State = new NavMapComponentState(chunks, component.Beacons); + return; + } - public List Airlocks = new(); + chunks = new(); + foreach (var (origin, chunk) in component.Chunks) + { + if (chunk.LastUpdate < args.FromTick) + continue; + + chunks.Add(origin, chunk.TileData); + } + + args.State = new NavMapComponentState(chunks, component.Beacons) + { + // TODO NAVMAP cache a single AllChunks hashset in the component. + // Or maybe just only send them if a chunk gets removed. + AllChunks = new(component.Chunks.Keys), + }; } + #endregion + + #region: System messages + [Serializable, NetSerializable] - public readonly record struct NavMapBeacon(Color Color, string Text, Vector2 Position); + protected sealed class NavMapComponentState( + Dictionary chunks, + Dictionary beacons) + : ComponentState, IComponentDeltaState + { + public Dictionary Chunks = chunks; + public Dictionary Beacons = beacons; + + // Required to infer deleted/missing chunks for delta states + public HashSet? AllChunks; + + public bool FullState => AllChunks == null; + + public void ApplyToFullState(IComponentState fullState) + { + DebugTools.Assert(!FullState); + var state = (NavMapComponentState) fullState; + DebugTools.Assert(state.FullState); + + foreach (var key in state.Chunks.Keys) + { + if (!AllChunks!.Contains(key)) + state.Chunks.Remove(key); + } + + foreach (var (index, data) in Chunks) + { + if (!state.Chunks.TryGetValue(index, out var stateValue)) + state.Chunks[index] = stateValue = new int[data.Length]; + + Array.Copy(data, stateValue, data.Length); + } + + state.Beacons.Clear(); + foreach (var (nuid, beacon) in Beacons) + { + state.Beacons.Add(nuid, beacon); + } + } + + public IComponentState CreateNewFullState(IComponentState fullState) + { + DebugTools.Assert(!FullState); + var state = (NavMapComponentState) fullState; + DebugTools.Assert(state.FullState); + + var chunks = new Dictionary(state.Chunks.Count); + foreach (var (index, data) in state.Chunks) + { + if (!AllChunks!.Contains(index)) + continue; + + var newData = chunks[index] = new int[ArraySize]; + + if (Chunks.TryGetValue(index, out var updatedData)) + Array.Copy(newData, updatedData, ArraySize); + else + Array.Copy(newData, data, ArraySize); + } + + return new NavMapComponentState(chunks, new(Beacons)); + } + } [Serializable, NetSerializable] - public readonly record struct NavMapAirlock(Vector2 Position); + public record struct NavMapBeacon(NetEntity NetEnt, Color Color, string Text, Vector2 Position); + + #endregion } diff --git a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs index e300524d876..ccaf9c17dd4 100644 --- a/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs +++ b/Content.Shared/Players/PlayTimeTracking/PlayTimeTrackingShared.cs @@ -1,9 +1,18 @@ -namespace Content.Shared.Players.PlayTimeTracking; +using Content.Shared.Dataset; + +namespace Content.Shared.Players.PlayTimeTracking; public static class PlayTimeTrackingShared { /// /// The prototype ID of the play time tracker that represents overall playtime, i.e. not tied to any one role. /// + [ValidatePrototypeId] public const string TrackerOverall = "Overall"; + + /// + /// The prototype ID of the play time tracker that represents admin time, when a player is in game as admin. + /// + [ValidatePrototypeId] + public const string TrackerAdmin = "Admin"; } diff --git a/Content.Shared/Polymorph/Components/ChameleonDisguiseComponent.cs b/Content.Shared/Polymorph/Components/ChameleonDisguiseComponent.cs new file mode 100644 index 00000000000..2b9fba7b391 --- /dev/null +++ b/Content.Shared/Polymorph/Components/ChameleonDisguiseComponent.cs @@ -0,0 +1,25 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Polymorph.Components; + +/// +/// Component added to disguise entities. +/// Used by client to copy over appearance from the disguise's source entity. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)] +public sealed partial class ChameleonDisguiseComponent : Component +{ + /// + /// The disguise source entity for copying the sprite. + /// + [DataField, AutoNetworkedField] + public EntityUid SourceEntity; + + /// + /// The source entity's prototype. + /// Used as a fallback if the source entity was deleted. + /// + [DataField, AutoNetworkedField] + public EntProtoId? SourceProto; +} diff --git a/Content.Shared/Polymorph/Components/ChameleonProjectorComponent.cs b/Content.Shared/Polymorph/Components/ChameleonProjectorComponent.cs new file mode 100644 index 00000000000..239b5236f27 --- /dev/null +++ b/Content.Shared/Polymorph/Components/ChameleonProjectorComponent.cs @@ -0,0 +1,68 @@ +using Content.Shared.Polymorph; +using Content.Shared.Polymorph.Systems; +using Content.Shared.Whitelist; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Polymorph.Components; + +/// +/// A chameleon projector polymorphs you into a clicked entity, then polymorphs back when clicked on or destroyed. +/// This creates a new dummy polymorph entity and copies the appearance over. +/// +[RegisterComponent, Access(typeof(SharedChameleonProjectorSystem))] +public sealed partial class ChameleonProjectorComponent : Component +{ + /// + /// If non-null, whitelist for valid entities to disguise as. + /// + [DataField(required: true)] + public EntityWhitelist? Whitelist; + + /// + /// If non-null, blacklist that prevents entities from being used even if they are in the whitelist. + /// + [DataField(required: true)] + public EntityWhitelist? Blacklist; + + /// + /// Polymorph configuration for the disguise entity. + /// + [DataField(required: true)] + public PolymorphConfiguration Polymorph = new(); + + /// + /// Action for disabling your disguise's rotation. + /// + [DataField] + public EntProtoId NoRotAction = "ActionDisguiseNoRot"; + + /// + /// Action for anchoring your disguise in place. + /// + [DataField] + public EntProtoId AnchorAction = "ActionDisguiseAnchor"; + + /// + /// Minimum health to give the disguise. + /// + [DataField] + public float MinHealth = 1f; + + /// + /// Maximum health to give the disguise, health scales with mass. + /// + [DataField] + public float MaxHealth = 100f; + + /// + /// Popup shown to the user when they try to disguise as an invalid entity. + /// + [DataField] + public LocId InvalidPopup = "chameleon-projector-invalid"; + + /// + /// Popup shown to the user when they disguise as a valid entity. + /// + [DataField] + public LocId SuccessPopup = "chameleon-projector-success"; +} diff --git a/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs b/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs new file mode 100644 index 00000000000..c1abfc526f5 --- /dev/null +++ b/Content.Shared/Polymorph/Systems/SharedChameleonProjectorSystem.cs @@ -0,0 +1,113 @@ +using Content.Shared.Actions; +using Content.Shared.Interaction; +using Content.Shared.Polymorph; +using Content.Shared.Polymorph.Components; +using Content.Shared.Popups; +using Robust.Shared.Serialization.Manager; +using Robust.Shared.Prototypes; +using System.Diagnostics.CodeAnalysis; + +namespace Content.Shared.Polymorph.Systems; + +/// +/// Handles whitelist/blacklist checking. +/// Actual polymorphing and deactivation is done serverside. +/// +public abstract class SharedChameleonProjectorSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _proto = default!; + [Dependency] private readonly ISerializationManager _serMan = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnInteract); + } + + private void OnInteract(Entity ent, ref AfterInteractEvent args) + { + if (!args.CanReach || args.Target is not {} target) + return; + + var user = args.User; + args.Handled = true; + + if (IsInvalid(ent.Comp, target)) + { + _popup.PopupClient(Loc.GetString(ent.Comp.InvalidPopup), target, user); + return; + } + + _popup.PopupClient(Loc.GetString(ent.Comp.SuccessPopup), target, user); + Disguise(ent.Comp, user, target); + } + + /// + /// Returns true if an entity cannot be used as a disguise. + /// + public bool IsInvalid(ChameleonProjectorComponent comp, EntityUid target) + { + return (comp.Whitelist?.IsValid(target, EntityManager) == false) + || (comp.Blacklist?.IsValid(target, EntityManager) == true); + } + + /// + /// On server, polymorphs the user into an entity and sets up the disguise. + /// + public virtual void Disguise(ChameleonProjectorComponent comp, EntityUid user, EntityUid entity) + { + } + + /// + /// Copy a component from the source entity/prototype to the disguise entity. + /// + /// + /// This would probably be a good thing to add to engine in the future. + /// + protected bool CopyComp(Entity ent) where T: Component, new() + { + if (!GetSrcComp(ent.Comp, out var src)) + return true; + + // remove then re-add to prevent a funny + RemComp(ent); + var dest = AddComp(ent); + _serMan.CopyTo(src, ref dest, notNullableOverride: true); + Dirty(ent, dest); + return false; + } + + /// + /// Try to get a single component from the source entity/prototype. + /// + private bool GetSrcComp(ChameleonDisguiseComponent comp, [NotNullWhen(true)] out T? src) where T: Component + { + src = null; + if (TryComp(comp.SourceEntity, out src)) + return true; + + if (comp.SourceProto is not {} protoId) + return false; + + if (!_proto.TryIndex(protoId, out var proto)) + return false; + + return proto.TryGetComponent(out src); + } +} + +/// +/// Action event for toggling transform NoRot on a disguise. +/// +public sealed partial class DisguiseToggleNoRotEvent : InstantActionEvent +{ +} + +/// +/// Action event for toggling transform Anchored on a disguise. +/// +public sealed partial class DisguiseToggleAnchoredEvent : InstantActionEvent +{ +} diff --git a/Content.Shared/Popups/SharedPopupSystem.cs b/Content.Shared/Popups/SharedPopupSystem.cs index 10e8ca9be11..38d2030cd5a 100644 --- a/Content.Shared/Popups/SharedPopupSystem.cs +++ b/Content.Shared/Popups/SharedPopupSystem.cs @@ -82,12 +82,24 @@ public abstract class SharedPopupSystem : EntitySystem /// public abstract void PopupEntity(string? message, EntityUid uid, Filter filter, bool recordReplay, PopupType type = PopupType.Small); + /// + /// Variant of that only runs on the client, outside of prediction. + /// Useful for shared code that is always ran by both sides to avoid duplicate popups. + /// + public abstract void PopupClient(string? message, EntityUid? recipient, PopupType type = PopupType.Small); + /// /// Variant of that only runs on the client, outside of prediction. /// Useful for shared code that is always ran by both sides to avoid duplicate popups. /// public abstract void PopupClient(string? message, EntityUid uid, EntityUid? recipient, PopupType type = PopupType.Small); + /// + /// Variant of that only runs on the client, outside of prediction. + /// Useful for shared code that is always ran by both sides to avoid duplicate popups. + /// + public abstract void PopupClient(string? message, EntityCoordinates coordinates, EntityUid? recipient, PopupType type = PopupType.Small); + /// /// Variant of for use with prediction. The local client will show /// the popup to the recipient, and the server will show it to every other player in PVS range. If recipient is null, the local client diff --git a/Content.Shared/Power/Components/ActivatableUIRequiresPowerComponent.cs b/Content.Shared/Power/Components/ActivatableUIRequiresPowerComponent.cs new file mode 100644 index 00000000000..af193c8dfc3 --- /dev/null +++ b/Content.Shared/Power/Components/ActivatableUIRequiresPowerComponent.cs @@ -0,0 +1,8 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared.Power.Components; + +[RegisterComponent, NetworkedComponent] +public sealed partial class ActivatableUIRequiresPowerComponent : Component +{ +} diff --git a/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs b/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs index dc4af23c239..749f0233aa8 100644 --- a/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs +++ b/Content.Shared/Power/SharedPowerMonitoringConsoleSystem.cs @@ -1,3 +1,4 @@ +using System.Runtime.CompilerServices; using JetBrains.Annotations; namespace Content.Shared.Power; @@ -5,4 +6,23 @@ namespace Content.Shared.Power; [UsedImplicitly] public abstract class SharedPowerMonitoringConsoleSystem : EntitySystem { + // Chunk size is limited as we require ChunkSize^2 <= 32 (number of bits in an int) + public const int ChunkSize = 5; + + /// + /// Converts the chunk's tile into a bitflag for the slot. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetFlag(Vector2i relativeTile) + { + return 1 << (relativeTile.X * ChunkSize + relativeTile.Y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2i GetTileFromIndex(int index) + { + var x = index / ChunkSize; + var y = index % ChunkSize; + return new Vector2i(x, y); + } } diff --git a/Content.Shared/Preferences/HumanoidCharacterProfile.cs b/Content.Shared/Preferences/HumanoidCharacterProfile.cs index a4e173d24e3..f7518a5eb54 100644 --- a/Content.Shared/Preferences/HumanoidCharacterProfile.cs +++ b/Content.Shared/Preferences/HumanoidCharacterProfile.cs @@ -15,690 +15,497 @@ using Robust.Shared.Serialization; using Robust.Shared.Utility; -namespace Content.Shared.Preferences -{ - /// - /// Character profile. Looks immutable, but uses non-immutable semantics internally for serialization/code sanity purposes. - /// - [DataDefinition] - [Serializable, NetSerializable] - public sealed partial class HumanoidCharacterProfile : ICharacterProfile - { - public const int MaxNameLength = 48; - public const int MaxDescLength = 1024; - - private readonly Dictionary _jobPriorities; - private readonly List _antagPreferences; - private readonly List _traitPreferences; - private readonly List _loadoutPreferences; - - private HumanoidCharacterProfile( - string name, - string flavortext, - string species, - float height, - float width, - int age, - Sex sex, - Gender gender, - HumanoidCharacterAppearance appearance, - ClothingPreference clothing, - BackpackPreference backpack, - SpawnPriorityPreference spawnPriority, - Dictionary jobPriorities, - PreferenceUnavailableMode preferenceUnavailable, - List antagPreferences, - List traitPreferences, - List loadoutPreferences) - { - Name = name; - FlavorText = flavortext; - Species = species; - Height = height; - Width = width; - Age = age; - Sex = sex; - Gender = gender; - Appearance = appearance; - Clothing = clothing; - Backpack = backpack; - SpawnPriority = spawnPriority; - _jobPriorities = jobPriorities; - PreferenceUnavailable = preferenceUnavailable; - _antagPreferences = antagPreferences; - _traitPreferences = traitPreferences; - _loadoutPreferences = loadoutPreferences; - } - - /// Copy constructor but with overridable references (to prevent useless copies) - private HumanoidCharacterProfile( - HumanoidCharacterProfile other, - Dictionary jobPriorities, - List antagPreferences, - List traitPreferences, - List loadoutPreferences) - : this(other.Name, other.FlavorText, other.Species, other.Height, other.Width, other.Age, other.Sex, other.Gender, other.Appearance, - other.Clothing, other.Backpack, other.SpawnPriority, jobPriorities, other.PreferenceUnavailable, - antagPreferences, traitPreferences, loadoutPreferences) - { - } +namespace Content.Shared.Preferences; - /// Copy constructor - private HumanoidCharacterProfile(HumanoidCharacterProfile other) - : this(other, new Dictionary(other.JobPriorities), - new List(other.AntagPreferences), new List(other.TraitPreferences), - new List(other.LoadoutPreferences)) - { - } - - public HumanoidCharacterProfile( - string name, - string flavortext, - string species, - float height, - float width, - int age, - Sex sex, - Gender gender, - HumanoidCharacterAppearance appearance, - ClothingPreference clothing, - BackpackPreference backpack, - SpawnPriorityPreference spawnPriority, - IReadOnlyDictionary jobPriorities, - PreferenceUnavailableMode preferenceUnavailable, - IReadOnlyList antagPreferences, - IReadOnlyList traitPreferences, - IReadOnlyList loadoutPreferences) - : this(name, flavortext, species, height, width, age, sex, gender, appearance, clothing, backpack, spawnPriority, - new Dictionary(jobPriorities), preferenceUnavailable, - new List(antagPreferences), new List(traitPreferences), - new List(loadoutPreferences)) - { - } - - /// - /// Get the default humanoid character profile, using internal constant values. - /// Defaults to for the species. - /// - /// - public HumanoidCharacterProfile() : this( - "John Doe", - "", - SharedHumanoidAppearanceSystem.DefaultSpecies, - 1f, - 1f, - 18, - Sex.Male, - Gender.Male, - new HumanoidCharacterAppearance(), - ClothingPreference.Jumpsuit, - BackpackPreference.Backpack, - SpawnPriorityPreference.None, - new Dictionary - { - {SharedGameTicker.FallbackOverflowJob, JobPriority.High} - }, - PreferenceUnavailableMode.SpawnAsOverflow, - new List(), - new List(), - new List()) - { - } +/// Character profile. Looks immutable, but uses non-immutable semantics internally for serialization/code sanity purposes +[DataDefinition] +[Serializable, NetSerializable] +public sealed partial class HumanoidCharacterProfile : ICharacterProfile +{ + private static readonly Regex RestrictedNameRegex = new("[^A-Z,a-z,0-9, -]"); + private static readonly Regex ICNameCaseRegex = new(@"^(?\w)|\b(?\w)(?=\w*$)"); - /// - /// Return a default character profile, based on species. - /// - /// The species to use in this default profile. The default species is . - /// Humanoid character profile with default settings. - public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) - { - return new( - "John Doe", - "", - species, - 1f, - 1f, - 18, - Sex.Male, - Gender.Male, - HumanoidCharacterAppearance.DefaultWithSpecies(species), - ClothingPreference.Jumpsuit, - BackpackPreference.Backpack, - SpawnPriorityPreference.None, - new Dictionary - { - {SharedGameTicker.FallbackOverflowJob, JobPriority.High} - }, - PreferenceUnavailableMode.SpawnAsOverflow, - new List(), - new List(), - new List()); - } + public const int MaxNameLength = 64; + public const int MaxDescLength = 1024; - // TODO: This should eventually not be a visual change only. - public static HumanoidCharacterProfile Random(HashSet? ignoredSpecies = null) + /// Job preferences for initial spawn + [DataField] + private Dictionary _jobPriorities = new() + { { - var prototypeManager = IoCManager.Resolve(); - var random = IoCManager.Resolve(); + SharedGameTicker.FallbackOverflowJob, JobPriority.High + }, + }; + + /// Antags we have opted in to + [DataField] + private HashSet _antagPreferences = new(); + + /// Enabled traits + [DataField] + private HashSet _traitPreferences = new(); + + /// + public HashSet LoadoutPreferences => _loadoutPreferences; + + [DataField] + private HashSet _loadoutPreferences = new(); + + [DataField] + public string Name { get; set; } = "John Doe"; + + /// Detailed text that can appear for the character if is enabled + [DataField] + public string FlavorText { get; set; } = string.Empty; + + /// Associated for this profile + [DataField] + public string Species { get; set; } = SharedHumanoidAppearanceSystem.DefaultSpecies; + + [DataField] + public float Height { get; private set; } + + [DataField] + public float Width { get; private set; } + + [DataField] + public int Age { get; set; } = 18; + + [DataField] + public Sex Sex { get; private set; } = Sex.Male; + + [DataField] + public Gender Gender { get; private set; } = Gender.Male; + + /// + public ICharacterAppearance CharacterAppearance => Appearance; + + /// Stores markings, eye colors, etc for the profile + [DataField] + public HumanoidCharacterAppearance Appearance { get; set; } = new(); + + [DataField] + public ClothingPreference Clothing { get; set; } + [DataField] + public BackpackPreference Backpack { get; set; } + + /// When spawning into a round what's the preferred spot to spawn + [DataField] + public SpawnPriorityPreference SpawnPriority { get; private set; } = SpawnPriorityPreference.None; + + /// + public IReadOnlyDictionary JobPriorities => _jobPriorities; + + /// + public IReadOnlySet AntagPreferences => _antagPreferences; + + /// + public IReadOnlySet TraitPreferences => _traitPreferences; + + /// If we're unable to get one of our preferred jobs do we spawn as a fallback job or do we stay in lobby + [DataField] + public PreferenceUnavailableMode PreferenceUnavailable { get; private set; } = + PreferenceUnavailableMode.SpawnAsOverflow; + + public HumanoidCharacterProfile( + string name, + string flavortext, + string species, + float height, + float width, + int age, + Sex sex, + Gender gender, + HumanoidCharacterAppearance appearance, + SpawnPriorityPreference spawnPriority, + Dictionary jobPriorities, + ClothingPreference clothing, + BackpackPreference backpack, + PreferenceUnavailableMode preferenceUnavailable, + HashSet antagPreferences, + HashSet traitPreferences, + HashSet loadoutPreferences) + { + Name = name; + FlavorText = flavortext; + Species = species; + Height = height; + Width = width; + Age = age; + Sex = sex; + Gender = gender; + Appearance = appearance; + SpawnPriority = spawnPriority; + _jobPriorities = jobPriorities; + Clothing = clothing; + Backpack = backpack; + PreferenceUnavailable = preferenceUnavailable; + _antagPreferences = antagPreferences; + _traitPreferences = traitPreferences; + _loadoutPreferences = loadoutPreferences; + } - var species = random.Pick(prototypeManager - .EnumeratePrototypes() - .Where(x => ignoredSpecies == null ? x.RoundStart : x.RoundStart && !ignoredSpecies.Contains(x.ID)) - .ToArray() - ).ID; + /// Copy constructor + public HumanoidCharacterProfile(HumanoidCharacterProfile other) + : this( + other.Name, + other.FlavorText, + other.Species, + other.Height, + other.Width, + other.Age, + other.Sex, + other.Gender, + other.Appearance.Clone(), + other.SpawnPriority, + new Dictionary(other.JobPriorities), + other.Clothing, + other.Backpack, + other.PreferenceUnavailable, + new HashSet(other.AntagPreferences), + new HashSet(other.TraitPreferences), + new HashSet(other.LoadoutPreferences)) + { + } - return RandomWithSpecies(species); - } + /// + /// Get the default humanoid character profile, using internal constant values. + /// Defaults to for the species. + /// + /// + public HumanoidCharacterProfile() + { + } - public static HumanoidCharacterProfile RandomWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) + /// + /// Return a default character profile, based on species. + /// + /// The species to use in this default profile. The default species is . + /// Humanoid character profile with default settings. + public static HumanoidCharacterProfile DefaultWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) + { + return new() { - var prototypeManager = IoCManager.Resolve(); - var random = IoCManager.Resolve(); - - var sex = Sex.Unsexed; - var age = 18; - var height = 1f; - var width = 1f; - if (prototypeManager.TryIndex(species, out var speciesPrototype)) - { - sex = random.Pick(speciesPrototype.Sexes); - age = random.Next(speciesPrototype.MinAge, speciesPrototype.OldAge); // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged - height = random.NextFloat(speciesPrototype.MinHeight, speciesPrototype.MaxHeight); - width = random.NextFloat(speciesPrototype.MinWidth, speciesPrototype.MaxWidth); - } - - var gender = Gender.Epicene; - - switch (sex) - { - case Sex.Male: - gender = Gender.Male; - break; - case Sex.Female: - gender = Gender.Female; - break; - } - - var name = GetName(species, gender); - - return new HumanoidCharacterProfile(name, "", species, height, width, age, sex, gender, - HumanoidCharacterAppearance.Random(species, sex), ClothingPreference.Jumpsuit, - BackpackPreference.Backpack, SpawnPriorityPreference.None, - new Dictionary - { - {SharedGameTicker.FallbackOverflowJob, JobPriority.High}, - }, PreferenceUnavailableMode.StayInLobby, new List(), new List(), new List()); - } - - public string Name { get; private set; } - public string FlavorText { get; private set; } - [DataField("species")] - public string Species { get; private set; } - - [DataField("height")] - public float Height { get; private set; } - - [DataField("width")] - public float Width { get; private set; } - - [DataField("age")] - public int Age { get; private set; } + Species = species, + }; + } - [DataField("sex")] - public Sex Sex { get; private set; } + // TODO: This should eventually not be a visual change only. + public static HumanoidCharacterProfile Random(HashSet? ignoredSpecies = null) + { + var prototypeManager = IoCManager.Resolve(); + var random = IoCManager.Resolve(); - [DataField("gender")] - public Gender Gender { get; private set; } + var species = random.Pick(prototypeManager + .EnumeratePrototypes() + .Where(x => ignoredSpecies == null ? x.RoundStart : x.RoundStart && !ignoredSpecies.Contains(x.ID)) + .ToArray() + ).ID; - public ICharacterAppearance CharacterAppearance => Appearance; + return RandomWithSpecies(species); + } - [DataField("appearance")] - public HumanoidCharacterAppearance Appearance { get; private set; } - public ClothingPreference Clothing { get; private set; } - public BackpackPreference Backpack { get; private set; } - public SpawnPriorityPreference SpawnPriority { get; private set; } - public IReadOnlyDictionary JobPriorities => _jobPriorities; - public IReadOnlyList AntagPreferences => _antagPreferences; - public IReadOnlyList TraitPreferences => _traitPreferences; - public IReadOnlyList LoadoutPreferences => _loadoutPreferences; - public PreferenceUnavailableMode PreferenceUnavailable { get; private set; } + public static HumanoidCharacterProfile RandomWithSpecies(string species = SharedHumanoidAppearanceSystem.DefaultSpecies) + { + var prototypeManager = IoCManager.Resolve(); + var random = IoCManager.Resolve(); - public HumanoidCharacterProfile WithName(string name) + var sex = Sex.Unsexed; + var age = 18; + if (prototypeManager.TryIndex(species, out var speciesPrototype)) { - return new(this) { Name = name }; + sex = random.Pick(speciesPrototype.Sexes); + age = random.Next(speciesPrototype.MinAge, speciesPrototype.OldAge); // people don't look and keep making 119 year old characters with zero rp, cap it at middle aged } - public HumanoidCharacterProfile WithFlavorText(string flavorText) - { - return new(this) { FlavorText = flavorText }; - } + var gender = Gender.Epicene; - public HumanoidCharacterProfile WithAge(int age) + switch (sex) { - return new(this) { Age = age }; + case Sex.Male: + gender = Gender.Male; + break; + case Sex.Female: + gender = Gender.Female; + break; } - public HumanoidCharacterProfile WithSex(Sex sex) - { - return new(this) { Sex = sex }; - } + var name = GetName(species, gender); - public HumanoidCharacterProfile WithGender(Gender gender) + return new HumanoidCharacterProfile() { - return new(this) { Gender = gender }; - } + Name = name, + Sex = sex, + Age = age, + Gender = gender, + Species = species, + Appearance = HumanoidCharacterAppearance.Random(species, sex), + }; + } - public HumanoidCharacterProfile WithSpecies(string species) - { - return new(this) { Species = species }; - } + public HumanoidCharacterProfile WithName(string name) => new(this) { Name = name }; + public HumanoidCharacterProfile WithFlavorText(string flavorText) => new(this) { FlavorText = flavorText }; + public HumanoidCharacterProfile WithAge(int age) => new(this) { Age = age }; + public HumanoidCharacterProfile WithSex(Sex sex) => new(this) { Sex = sex }; + public HumanoidCharacterProfile WithGender(Gender gender) => new(this) { Gender = gender }; + public HumanoidCharacterProfile WithSpecies(string species) => new(this) { Species = species }; + public HumanoidCharacterProfile WithHeight(float height) => new(this) { Height = height }; + public HumanoidCharacterProfile WithWidth(float width) => new(this) { Width = width }; + + public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance) => + new(this) { Appearance = appearance }; + public HumanoidCharacterProfile WithClothingPreference(ClothingPreference clothing) => + new(this) { Clothing = clothing }; + public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack) => + new(this) { Backpack = backpack }; + public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority) => + new(this) { SpawnPriority = spawnPriority }; + public HumanoidCharacterProfile WithJobPriorities(IEnumerable> jobPriorities) => + new(this) { _jobPriorities = new Dictionary(jobPriorities) }; + + public HumanoidCharacterProfile WithJobPriority(string jobId, JobPriority priority) + { + var dictionary = new Dictionary(_jobPriorities); + if (priority == JobPriority.Never) + dictionary.Remove(jobId); + else + dictionary[jobId] = priority; - public HumanoidCharacterProfile WithHeight(float height) - { - return new(this) { Height = height }; - } + return new(this) { _jobPriorities = dictionary }; + } - public HumanoidCharacterProfile WithWidth(float width) - { - return new(this) { Width = width }; - } + public HumanoidCharacterProfile WithPreferenceUnavailable(PreferenceUnavailableMode mode) => + new(this) { PreferenceUnavailable = mode }; + public HumanoidCharacterProfile WithAntagPreferences(IEnumerable antagPreferences) => + new(this) { _antagPreferences = new HashSet(antagPreferences) }; - public HumanoidCharacterProfile WithCharacterAppearance(HumanoidCharacterAppearance appearance) - { - return new(this) { Appearance = appearance }; - } + public HumanoidCharacterProfile WithAntagPreference(string antagId, bool pref) + { + var list = new HashSet(_antagPreferences); + if (pref) + list.Add(antagId); + else + list.Remove(antagId); - public HumanoidCharacterProfile WithClothingPreference(ClothingPreference clothing) - { - return new(this) { Clothing = clothing }; - } - public HumanoidCharacterProfile WithBackpackPreference(BackpackPreference backpack) - { - return new(this) { Backpack = backpack }; - } - public HumanoidCharacterProfile WithSpawnPriorityPreference(SpawnPriorityPreference spawnPriority) - { - return new(this) { SpawnPriority = spawnPriority }; - } - public HumanoidCharacterProfile WithJobPriorities(IEnumerable> jobPriorities) - { - return new(this, new Dictionary(jobPriorities), _antagPreferences, _traitPreferences, - _loadoutPreferences); - } + return new(this) { _antagPreferences = list }; + } - public HumanoidCharacterProfile WithJobPriority(string jobId, JobPriority priority) - { - var dictionary = new Dictionary(_jobPriorities); - if (priority == JobPriority.Never) - { - dictionary.Remove(jobId); - } - else - { - dictionary[jobId] = priority; - } - return new(this, dictionary, _antagPreferences, _traitPreferences, _loadoutPreferences); - } + public HumanoidCharacterProfile WithTraitPreference(string traitId, bool pref) + { + var list = new HashSet(_traitPreferences); - public HumanoidCharacterProfile WithPreferenceUnavailable(PreferenceUnavailableMode mode) - { - return new(this) { PreferenceUnavailable = mode }; - } + if (pref) + list.Add(traitId); + else + list.Remove(traitId); - public HumanoidCharacterProfile WithAntagPreferences(IEnumerable antagPreferences) - { - return new(this, _jobPriorities, new List(antagPreferences), _traitPreferences, - _loadoutPreferences); - } + return new(this) { _traitPreferences = list }; + } - public HumanoidCharacterProfile WithAntagPreference(string antagId, bool pref) - { - var list = new List(_antagPreferences); - if (pref) - { - if (!list.Contains(antagId)) - { - list.Add(antagId); - } - } - else - { - if (list.Contains(antagId)) - { - list.Remove(antagId); - } - } - return new(this, _jobPriorities, list, _traitPreferences, _loadoutPreferences); - } + public HumanoidCharacterProfile WithLoadoutPreference(string loadoutId, bool pref) + { + var list = new HashSet(_loadoutPreferences); - public HumanoidCharacterProfile WithTraitPreference(string traitId, bool pref) - { - var list = new List(_traitPreferences); + if (pref) + list.Add(loadoutId); + else + list.Remove(loadoutId); - // TODO: Maybe just refactor this to HashSet? Same with _antagPreferences - if (pref) - { - if (!list.Contains(traitId)) - { - list.Add(traitId); - } - } - else - { - if (list.Contains(traitId)) - { - list.Remove(traitId); - } - } - return new(this, _jobPriorities, _antagPreferences, list, _loadoutPreferences); - } + return new HumanoidCharacterProfile(this) { _loadoutPreferences = list }; + } - public HumanoidCharacterProfile WithLoadoutPreference(string loadoutId, bool pref) - { - var list = new List(_loadoutPreferences); + public string Summary => + Loc.GetString( + "humanoid-character-profile-summary", + ("name", Name), + ("gender", Gender.ToString().ToLowerInvariant()), + ("age", Age) + ); - if(pref) - { - if(!list.Contains(loadoutId)) - { - list.Add(loadoutId); - } - } - else - { - if(list.Contains(loadoutId)) - { - list.Remove(loadoutId); - } - } - return new(this, _jobPriorities, _antagPreferences, _traitPreferences, list); - } + public bool MemberwiseEquals(ICharacterProfile maybeOther) + { + return maybeOther is HumanoidCharacterProfile other + && Name == other.Name + && Age == other.Age + && Sex == other.Sex + && Gender == other.Gender + && Species == other.Species + && PreferenceUnavailable == other.PreferenceUnavailable + && SpawnPriority == other.SpawnPriority + && _jobPriorities.SequenceEqual(other._jobPriorities) + && _antagPreferences.SequenceEqual(other._antagPreferences) + && _traitPreferences.SequenceEqual(other._traitPreferences) + && LoadoutPreferences.SequenceEqual(other.LoadoutPreferences) + && Appearance.MemberwiseEquals(other.Appearance); + } - public string Summary => - Loc.GetString( - "humanoid-character-profile-summary", - ("name", Name), - ("gender", Gender.ToString().ToLowerInvariant()), - ("age", Age) - ); + public void EnsureValid(ICommonSession session, IDependencyCollection collection) + { + var configManager = collection.Resolve(); + var prototypeManager = collection.Resolve(); - public bool MemberwiseEquals(ICharacterProfile maybeOther) + if (!prototypeManager.TryIndex(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false) { - if (maybeOther is not HumanoidCharacterProfile other - || Name != other.Name - || Age != other.Age - || Height != other.Height - || Width != other.Width - || Sex != other.Sex - || Gender != other.Gender - || PreferenceUnavailable != other.PreferenceUnavailable - || Clothing != other.Clothing - || Backpack != other.Backpack - || SpawnPriority != other.SpawnPriority - || !_jobPriorities.SequenceEqual(other._jobPriorities) - || !_antagPreferences.SequenceEqual(other._antagPreferences) - || !_traitPreferences.SequenceEqual(other._traitPreferences) - || !_loadoutPreferences.SequenceEqual(other._loadoutPreferences)) - return false; - return Appearance.MemberwiseEquals(other.Appearance); + Species = SharedHumanoidAppearanceSystem.DefaultSpecies; + speciesPrototype = prototypeManager.Index(Species); } - public void EnsureValid(ICommonSession session, IDependencyCollection collection) + var sex = Sex switch { - var configManager = collection.Resolve(); - var prototypeManager = collection.Resolve(); + Sex.Male => Sex.Male, + Sex.Female => Sex.Female, + Sex.Unsexed => Sex.Unsexed, + _ => Sex.Male // Invalid enum values. + }; - if (!prototypeManager.TryIndex(Species, out var speciesPrototype) || speciesPrototype.RoundStart == false) - { - Species = SharedHumanoidAppearanceSystem.DefaultSpecies; - speciesPrototype = prototypeManager.Index(Species); - } + // ensure the species can be that sex and their age fits the founds + if (!speciesPrototype.Sexes.Contains(sex)) + sex = speciesPrototype.Sexes[0]; - var sex = Sex switch - { - Sex.Male => Sex.Male, - Sex.Female => Sex.Female, - Sex.Unsexed => Sex.Unsexed, - _ => Sex.Male // Invalid enum values. - }; + var age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); - // ensure the species can be that sex and their age fits the founds - if (!speciesPrototype.Sexes.Contains(sex)) - sex = speciesPrototype.Sexes[0]; + var gender = Gender switch + { + Gender.Epicene => Gender.Epicene, + Gender.Female => Gender.Female, + Gender.Male => Gender.Male, + Gender.Neuter => Gender.Neuter, + _ => Gender.Epicene // Invalid enum values. + }; - var age = Math.Clamp(Age, speciesPrototype.MinAge, speciesPrototype.MaxAge); + string name; + if (string.IsNullOrEmpty(Name)) + name = GetName(Species, gender); + else if (Name.Length > MaxNameLength) + name = Name[..MaxNameLength]; + else + name = Name; - var gender = Gender switch - { - Gender.Epicene => Gender.Epicene, - Gender.Female => Gender.Female, - Gender.Male => Gender.Male, - Gender.Neuter => Gender.Neuter, - _ => Gender.Epicene // Invalid enum values. - }; - - string name; - if (string.IsNullOrEmpty(Name)) - { - name = GetName(Species, gender); - } - else if (Name.Length > MaxNameLength) - { - name = Name[..MaxNameLength]; - } - else - { - name = Name; - } + name = name.Trim(); - name = name.Trim(); + if (configManager.GetCVar(CCVars.RestrictedNames)) + name = RestrictedNameRegex.Replace(name, string.Empty); - if (configManager.GetCVar(CCVars.RestrictedNames)) - { - name = Regex.Replace(name, @"[^\u0030-\u0039,\u0041-\u005A,\u0061-\u007A,\u00C0-\u00D6,\u00D8-\u00F6,\u00F8-\u00FF,\u0100-\u017F, '.,-]", string.Empty); - /* - * 0030-0039 Basic Latin: ASCII Digits - * 0041-005A Basic Latin: Uppercase Latin Alphabet - * 0061-007A Basic Latin: Lowercase Latin Alphabet - * 00C0-00D6 Latin-1 Supplement: Letters I - * 00D8-00F6 Latin-1 Supplement: Letters II - * 00F8-00FF Latin-1 Supplement: Letters III - * 0100-017F Latin Extended A: European Latin - */ - } - - if (configManager.GetCVar(CCVars.ICNameCase)) - { - // This regex replaces the first character of the first and last words of the name with their uppercase version - name = Regex.Replace(name, - @"^(?\w)|\b(?\w)(?=\w*$)", - m => m.Groups["word"].Value.ToUpper()); - } - - if (string.IsNullOrEmpty(name)) - { - name = GetName(Species, gender); - } + if (configManager.GetCVar(CCVars.ICNameCase)) + { + // This regex replaces the first character of the first and last words of the name with their uppercase version + name = ICNameCaseRegex.Replace(name, m => m.Groups["word"].Value.ToUpper()); + } - string flavortext; - if (FlavorText.Length > MaxDescLength) - { - flavortext = FormattedMessage.RemoveMarkup(FlavorText)[..MaxDescLength]; - } - else - { - flavortext = FormattedMessage.RemoveMarkup(FlavorText); - } + if (string.IsNullOrEmpty(name)) + name = GetName(Species, gender); - var height = Height; - if (speciesPrototype != null) - height = Math.Clamp(Height, speciesPrototype.MinHeight, speciesPrototype.MaxHeight); + string flavortext; + if (FlavorText.Length > MaxDescLength) + flavortext = FormattedMessage.RemoveMarkup(FlavorText)[..MaxDescLength]; + else + flavortext = FormattedMessage.RemoveMarkup(FlavorText); - var width = Width; - if (speciesPrototype != null) - width = Math.Clamp(Width, speciesPrototype.MinWidth, speciesPrototype.MaxWidth); + var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex); - var appearance = HumanoidCharacterAppearance.EnsureValid(Appearance, Species, Sex); + var prefsUnavailableMode = PreferenceUnavailable switch + { + PreferenceUnavailableMode.StayInLobby => PreferenceUnavailableMode.StayInLobby, + PreferenceUnavailableMode.SpawnAsOverflow => PreferenceUnavailableMode.SpawnAsOverflow, + _ => PreferenceUnavailableMode.StayInLobby // Invalid enum values. + }; - var prefsUnavailableMode = PreferenceUnavailable switch - { - PreferenceUnavailableMode.StayInLobby => PreferenceUnavailableMode.StayInLobby, - PreferenceUnavailableMode.SpawnAsOverflow => PreferenceUnavailableMode.SpawnAsOverflow, - _ => PreferenceUnavailableMode.StayInLobby // Invalid enum values. - }; + var spawnPriority = SpawnPriority switch + { + SpawnPriorityPreference.None => SpawnPriorityPreference.None, + SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals, + SpawnPriorityPreference.Cryosleep => SpawnPriorityPreference.Cryosleep, + _ => SpawnPriorityPreference.None // Invalid enum values. + }; - var clothing = Clothing switch + var priorities = new Dictionary(JobPriorities + .Where(p => prototypeManager.TryIndex(p.Key, out var job) && job.SetPreference && p.Value switch { - ClothingPreference.Jumpsuit => ClothingPreference.Jumpsuit, - ClothingPreference.Jumpskirt => ClothingPreference.Jumpskirt, - _ => ClothingPreference.Jumpsuit // Invalid enum values. - }; + JobPriority.Never => false, // Drop never since that's assumed default. + JobPriority.Low => true, + JobPriority.Medium => true, + JobPriority.High => true, + _ => false + })); - var backpack = Backpack switch - { - BackpackPreference.Backpack => BackpackPreference.Backpack, - BackpackPreference.Satchel => BackpackPreference.Satchel, - BackpackPreference.Duffelbag => BackpackPreference.Duffelbag, - _ => BackpackPreference.Backpack // Invalid enum values. - }; + var antags = AntagPreferences + .Where(id => prototypeManager.TryIndex(id, out var antag) && antag.SetPreference) + .ToList(); - var spawnPriority = SpawnPriority switch - { - SpawnPriorityPreference.None => SpawnPriorityPreference.None, - SpawnPriorityPreference.Arrivals => SpawnPriorityPreference.Arrivals, - SpawnPriorityPreference.Cryosleep => SpawnPriorityPreference.Cryosleep, - _ => SpawnPriorityPreference.None // Invalid enum values. - }; - - var priorities = new Dictionary(JobPriorities - .Where(p => prototypeManager.TryIndex(p.Key, out var job) && job.SetPreference && p.Value switch - { - JobPriority.Never => false, // Drop never since that's assumed default. - JobPriority.Low => true, - JobPriority.Medium => true, - JobPriority.High => true, - _ => false - })); - - var antags = AntagPreferences - .Where(id => prototypeManager.TryIndex(id, out var antag) && antag.SetPreference) - .ToList(); - - var traits = TraitPreferences - .Where(prototypeManager.HasIndex) - .ToList(); - - var maxTraits = configManager.GetCVar(CCVars.GameTraitsMax); - var currentTraits = 0; - var traitPoints = configManager.GetCVar(CCVars.GameTraitsDefaultPoints); - - foreach (var trait in traits.OrderBy(t => -prototypeManager.Index(t).Points).ToList()) - { - var proto = prototypeManager.Index(trait); + var traits = TraitPreferences + .Where(prototypeManager.HasIndex) + .ToList(); - if (traitPoints + proto.Points < 0 || currentTraits + 1 > maxTraits) - traits.Remove(trait); - else - { - traitPoints += proto.Points; - currentTraits++; - } - } + var loadouts = LoadoutPreferences + .Where(prototypeManager.HasIndex) + .ToList(); + Name = name; + FlavorText = flavortext; + Age = age; + Sex = sex; + Gender = gender; + Appearance = appearance; + SpawnPriority = spawnPriority; - var loadouts = LoadoutPreferences - .Where(prototypeManager.HasIndex) - .ToList(); + _jobPriorities.Clear(); - var loadoutPoints = configManager.GetCVar(CCVars.GameLoadoutsPoints); - var currentPoints = 0; + foreach (var (job, priority) in priorities) + _jobPriorities.Add(job, priority); - foreach (var loadout in loadouts.ToList()) - { - var proto = prototypeManager.Index(loadout); - - if (currentPoints + proto.Cost > loadoutPoints) - loadouts.Remove(loadout); - else - currentPoints += proto.Cost; - } - - - Name = name; - FlavorText = flavortext; - Age = age; - Height = height; - Width = width; - Sex = sex; - Gender = gender; - Appearance = appearance; - Clothing = clothing; - Backpack = backpack; - SpawnPriority = spawnPriority; - - _jobPriorities.Clear(); - - foreach (var (job, priority) in priorities) - { - _jobPriorities.Add(job, priority); - } + PreferenceUnavailable = prefsUnavailableMode; - PreferenceUnavailable = prefsUnavailableMode; + _antagPreferences.Clear(); + _antagPreferences.UnionWith(antags); - _antagPreferences.Clear(); - _antagPreferences.AddRange(antags); + _traitPreferences.Clear(); + _traitPreferences.UnionWith(traits); - _traitPreferences.Clear(); - _traitPreferences.AddRange(traits); + _loadoutPreferences.Clear(); + _loadoutPreferences.UnionWith(loadouts); + } - _loadoutPreferences.Clear(); - _loadoutPreferences.AddRange(loadouts); - } + public ICharacterProfile Validated(ICommonSession session, IDependencyCollection collection) + { + var profile = new HumanoidCharacterProfile(this); + profile.EnsureValid(session, collection); + return profile; + } - public ICharacterProfile Validated(ICommonSession session, IDependencyCollection collection) - { - var profile = new HumanoidCharacterProfile(this); - profile.EnsureValid(session, collection); - return profile; - } + // Sorry this is kind of weird and duplicated, + // Working inside these non entity systems is a bit wack + public static string GetName(string species, Gender gender) + { + var namingSystem = IoCManager.Resolve().GetEntitySystem(); + return namingSystem.GetName(species, gender); + } - // sorry this is kind of weird and duplicated, - /// working inside these non entity systems is a bit wack - public static string GetName(string species, Gender gender) - { - var namingSystem = IoCManager.Resolve().GetEntitySystem(); - return namingSystem.GetName(species, gender); - } + public override bool Equals(object? obj) + { + return ReferenceEquals(this, obj) || obj is HumanoidCharacterProfile other && MemberwiseEquals(other); + } - public override bool Equals(object? obj) - { - return obj is HumanoidCharacterProfile other && MemberwiseEquals(other); - } + public override int GetHashCode() + { + var hashCode = new HashCode(); + hashCode.Add(_jobPriorities); + hashCode.Add(_antagPreferences); + hashCode.Add(_traitPreferences); + hashCode.Add(_loadoutPreferences); + hashCode.Add(Name); + hashCode.Add(FlavorText); + hashCode.Add(Species); + hashCode.Add(Age); + hashCode.Add((int)Sex); + hashCode.Add((int)Gender); + hashCode.Add(Appearance); + hashCode.Add((int)SpawnPriority); + hashCode.Add((int)PreferenceUnavailable); + return hashCode.ToHashCode(); + } - public override int GetHashCode() - { - return HashCode.Combine( - HashCode.Combine( - Name, - Species, - Age, - Sex, - Gender, - Appearance, - Clothing, - Backpack - ), - HashCode.Combine( - SpawnPriority, - Height, - Width, - PreferenceUnavailable, - _jobPriorities, - _antagPreferences, - _traitPreferences, - _loadoutPreferences - ) - ); - } + public HumanoidCharacterProfile Clone() + { + return new HumanoidCharacterProfile(this); } } diff --git a/Content.Shared/Preferences/Loadouts/Effects/SpeciesLoadoutEffect.cs b/Content.Shared/Preferences/Loadouts/Effects/SpeciesLoadoutEffect.cs new file mode 100644 index 00000000000..74673cbef39 --- /dev/null +++ b/Content.Shared/Preferences/Loadouts/Effects/SpeciesLoadoutEffect.cs @@ -0,0 +1,6 @@ +namespace Content.Shared.Preferences.Loadouts.Effects; + +public sealed class SpeciesLoadoutEffect +{ + +} diff --git a/Content.Shared/Prying/Systems/PryingSystem.cs b/Content.Shared/Prying/Systems/PryingSystem.cs index fa7a135e6c5..a59c09ca535 100644 --- a/Content.Shared/Prying/Systems/PryingSystem.cs +++ b/Content.Shared/Prying/Systems/PryingSystem.cs @@ -1,15 +1,14 @@ -using Content.Shared.Prying.Components; -using Content.Shared.Verbs; -using Content.Shared.DoAfter; -using Robust.Shared.Serialization; +using System.Diagnostics.CodeAnalysis; using Content.Shared.Administration.Logs; using Content.Shared.Database; +using Content.Shared.DoAfter; using Content.Shared.Doors.Components; -using System.Diagnostics.CodeAnalysis; using Content.Shared.Interaction; using Content.Shared.Popups; -using Robust.Shared.Audio; +using Content.Shared.Prying.Components; +using Content.Shared.Verbs; using Robust.Shared.Audio.Systems; +using Robust.Shared.Serialization; using PryUnpoweredComponent = Content.Shared.Prying.Components.PryUnpoweredComponent; namespace Content.Shared.Prying.Systems; @@ -99,14 +98,16 @@ public bool TryPry(EntityUid target, EntityUid user, out DoAfterId? id) // to be marked as handled. return true; - return StartPry(target, user, null, 0.1f, out id); // hand-prying is much slower + // hand-prying is much slower + var modifier = CompOrNull(user)?.SpeedModifier ?? 0.1f; + return StartPry(target, user, null, modifier, out id); } private bool CanPry(EntityUid target, EntityUid user, out string? message, PryingComponent? comp = null) { BeforePryEvent canev; - if (comp != null) + if (comp != null || Resolve(user, ref comp, false)) { canev = new BeforePryEvent(user, comp.PryPowered, comp.Force); } diff --git a/Content.Shared/RCD/RCDPrototype.cs b/Content.Shared/RCD/RCDPrototype.cs index 1e80abfb723..58093bbe87a 100644 --- a/Content.Shared/RCD/RCDPrototype.cs +++ b/Content.Shared/RCD/RCDPrototype.cs @@ -9,7 +9,7 @@ namespace Content.Shared.RCD; /// Contains the parameters for a RCD construction / operation /// [Prototype("rcd")] -public sealed class RCDPrototype : IPrototype +public sealed partial class RCDPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; @@ -51,7 +51,7 @@ public sealed class RCDPrototype : IPrototype public int Cost { get; private set; } = 1; /// - /// The length of the operation + /// The length of the operation /// [DataField, ViewVariables(VVAccess.ReadOnly)] public float Delay { get; private set; } = 1f; @@ -75,7 +75,7 @@ public sealed class RCDPrototype : IPrototype public CollisionGroup CollisionMask { get; private set; } = CollisionGroup.None; /// - /// Specifies a set of custom collision bounds for determining whether the entity prototype will fit into a target tile + /// Specifies a set of custom collision bounds for determining whether the entity prototype will fit into a target tile /// /// /// Should be set assuming that the entity faces south. @@ -106,7 +106,7 @@ private set private Box2? _collisionBounds = null; /// - /// The polygon shape associated with the prototype CollisionBounds (if set) + /// The polygon shape associated with the prototype CollisionBounds (if set) /// [ViewVariables(VVAccess.ReadOnly)] public PolygonShape? CollisionPolygon { get; private set; } = null; diff --git a/Content.Shared/Radio/Components/SharedRadioJammerComponent.cs b/Content.Shared/Radio/Components/SharedRadioJammerComponent.cs new file mode 100644 index 00000000000..e5e52a3e475 --- /dev/null +++ b/Content.Shared/Radio/Components/SharedRadioJammerComponent.cs @@ -0,0 +1,74 @@ +using Robust.Shared.Serialization; +using Robust.Shared.GameStates; + +namespace Content.Shared.RadioJammer; + +/// +/// When activated () prevents from sending messages in range +/// Suit sensors will also stop working. +/// +[NetworkedComponent, RegisterComponent] +public sealed partial class RadioJammerComponent : Component +{ + [DataDefinition] + public partial struct RadioJamSetting + { + /// + /// Power usage per second when enabled. + /// + [DataField(required: true)] + public float Wattage; + + /// + /// Range of the jammer. + /// + [DataField(required: true)] + public float Range; + + /// + /// The message that is displayed when switched + /// to this setting. + /// + [DataField(required: true)] + public LocId Message = string.Empty; + + /// + /// Name of the setting. + /// + [DataField(required: true)] + public LocId Name = string.Empty; + } + + /// + /// List of all the settings for the radio jammer. + /// + [DataField(required: true), ViewVariables(VVAccess.ReadOnly)] + public RadioJamSetting[] Settings; + + /// + /// Index of the currently selected setting. + /// + [DataField] + public int SelectedPowerLevel = 1; +} + +[Serializable, NetSerializable] +public enum RadioJammerChargeLevel : byte +{ + Low, + Medium, + High +} + +[Serializable, NetSerializable] +public enum RadioJammerLayers : byte +{ + LED +} + +[Serializable, NetSerializable] +public enum RadioJammerVisuals : byte +{ + ChargeLevel, + LEDOn +} diff --git a/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs new file mode 100644 index 00000000000..e1f632735c2 --- /dev/null +++ b/Content.Shared/Radio/EntitySystems/SharedJammerSystem.cs @@ -0,0 +1,78 @@ +using Content.Shared.Popups; +using Content.Shared.DeviceNetwork.Components; +using Content.Shared.Verbs; +using Content.Shared.RadioJammer; + +namespace Content.Shared.Radio.EntitySystems; + +public abstract class SharedJammerSystem : EntitySystem +{ + [Dependency] private readonly SharedAppearanceSystem _appearance = default!; + [Dependency] protected readonly SharedPopupSystem Popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent>(OnGetVerb); + } + + private void OnGetVerb(Entity entity, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + var user = args.User; + + byte index = 0; + foreach (var setting in entity.Comp.Settings) + { + // This is because Act wont work with index. + // Needs it to be saved in the loop. + var currIndex = index; + var verb = new Verb + { + Priority = currIndex, + Category = VerbCategory.PowerLevel, + Disabled = entity.Comp.SelectedPowerLevel == currIndex, + Act = () => + { + entity.Comp.SelectedPowerLevel = currIndex; + if (TryComp(entity.Owner, out var jammerComp)) + { + // This is a little sketcy but only way to do it. + jammerComp.Range = GetCurrentRange(entity.Comp); + Dirty(entity.Owner, jammerComp); + } + Popup.PopupPredicted(Loc.GetString(setting.Message), user, user); + }, + Text = Loc.GetString(setting.Name), + }; + args.Verbs.Add(verb); + index++; + } + } + + public float GetCurrentWattage(RadioJammerComponent jammer) + { + return jammer.Settings[jammer.SelectedPowerLevel].Wattage; + } + + public float GetCurrentRange(RadioJammerComponent jammer) + { + return jammer.Settings[jammer.SelectedPowerLevel].Range; + } + + protected void ChangeLEDState(bool isLEDOn, EntityUid uid, + AppearanceComponent? appearance = null) + { + _appearance.SetData(uid, RadioJammerVisuals.LEDOn, isLEDOn, appearance); + } + + protected void ChangeChargeLevel(RadioJammerChargeLevel chargeLevel, EntityUid uid, + AppearanceComponent? appearance = null) + { + _appearance.SetData(uid, RadioJammerVisuals.ChargeLevel, chargeLevel, appearance); + } + +} diff --git a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs index dcdc9d61d98..20e57e94212 100644 --- a/Content.Shared/Random/Helpers/SharedRandomExtensions.cs +++ b/Content.Shared/Random/Helpers/SharedRandomExtensions.cs @@ -57,7 +57,8 @@ public static string Pick(this IWeightedRandomPrototype prototype, IRobustRandom throw new InvalidOperationException($"Invalid weighted pick for {prototype.ID}!"); } - public static string Pick(this IRobustRandom random, Dictionary weights) + public static T Pick(this IRobustRandom random, Dictionary weights) + where T: notnull { var sum = weights.Values.Sum(); var accumulated = 0f; @@ -74,7 +75,7 @@ public static string Pick(this IRobustRandom random, Dictionary w } } - throw new InvalidOperationException($"Invalid weighted pick"); + throw new InvalidOperationException("Invalid weighted pick"); } public static (string reagent, FixedPoint2 quantity) Pick(this WeightedRandomFillSolutionPrototype prototype, IRobustRandom? random = null) diff --git a/Content.Shared/ReagentSpeed/ReagentSpeedComponent.cs b/Content.Shared/ReagentSpeed/ReagentSpeedComponent.cs new file mode 100644 index 00000000000..d233cad2a00 --- /dev/null +++ b/Content.Shared/ReagentSpeed/ReagentSpeedComponent.cs @@ -0,0 +1,34 @@ +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using Robust.Shared.Prototypes; + +namespace Content.Shared.ReagentSpeed; + +/// +/// Makes a device work faster by consuming reagents on each use. +/// Other systems must use for this to do anything. +/// +[RegisterComponent, Access(typeof(ReagentSpeedSystem))] +public sealed partial class ReagentSpeedComponent : Component +{ + /// + /// Solution that will be checked. + /// Anything that isn't in Modifiers is left alone. + /// + [DataField(required: true)] + public string Solution = string.Empty; + + /// + /// How much reagent from the solution to use up for each use. + /// This is per-modifier-reagent and not shared between them. + /// + [DataField] + public FixedPoint2 Cost = 5; + + /// + /// Reagents and how much they modify speed at full purity. + /// Small number means faster large number means slower. + /// + [DataField(required: true)] + public Dictionary, float> Modifiers = new(); +} diff --git a/Content.Shared/ReagentSpeed/ReagentSpeedSystem.cs b/Content.Shared/ReagentSpeed/ReagentSpeedSystem.cs new file mode 100644 index 00000000000..8561c7b12a1 --- /dev/null +++ b/Content.Shared/ReagentSpeed/ReagentSpeedSystem.cs @@ -0,0 +1,33 @@ +using Content.Shared.Chemistry.EntitySystems; + +namespace Content.Shared.ReagentSpeed; + +public sealed class ReagentSpeedSystem : EntitySystem +{ + [Dependency] private readonly SharedSolutionContainerSystem _solution = default!; + + /// + /// Consumes reagents and modifies the duration. + /// This can be production time firing delay etc. + /// + public TimeSpan ApplySpeed(Entity ent, TimeSpan time) + { + if (!Resolve(ent, ref ent.Comp, false)) + return time; + + if (!_solution.TryGetSolution(ent.Owner, ent.Comp.Solution, out _, out var solution)) + return time; + + foreach (var (reagent, fullModifier) in ent.Comp.Modifiers) + { + var used = solution.RemoveReagent(reagent, ent.Comp.Cost); + var efficiency = (used / ent.Comp.Cost).Float(); + // scale the speed modifier so microdosing has less effect + var reduction = (1f - fullModifier) * efficiency; + var modifier = 1f - reduction; + time *= modifier; + } + + return time; + } +} diff --git a/Content.Shared/Robotics/Components/RoboticsConsoleComponent.cs b/Content.Shared/Robotics/Components/RoboticsConsoleComponent.cs new file mode 100644 index 00000000000..4329e437a29 --- /dev/null +++ b/Content.Shared/Robotics/Components/RoboticsConsoleComponent.cs @@ -0,0 +1,53 @@ +using Content.Shared.Radio; +using Content.Shared.Robotics; +using Content.Shared.Robotics.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Shared.Robotics.Components; + +/// +/// Robotics console for managing borgs. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(SharedRoboticsConsoleSystem))] +[AutoGenerateComponentState, AutoGenerateComponentPause] +public sealed partial class RoboticsConsoleComponent : Component +{ + /// + /// Address and data of each cyborg. + /// + [DataField] + public Dictionary Cyborgs = new(); + + /// + /// After not responding for this length of time borgs are removed from the console. + /// + [DataField] + public TimeSpan Timeout = TimeSpan.FromSeconds(10); + + /// + /// Radio channel to send messages on. + /// + [DataField] + public ProtoId RadioChannel = "Science"; + + /// + /// Radio message sent when destroying a borg. + /// + [DataField] + public LocId DestroyMessage = "robotics-console-cyborg-destroyed"; + + /// + /// Cooldown on destroying borgs to prevent complete abuse. + /// + [DataField] + public TimeSpan DestroyCooldown = TimeSpan.FromSeconds(30); + + /// + /// When a borg can next be destroyed. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + [AutoNetworkedField, AutoPausedField] + public TimeSpan NextDestroy = TimeSpan.Zero; +} diff --git a/Content.Shared/Robotics/RoboticsConsoleUi.cs b/Content.Shared/Robotics/RoboticsConsoleUi.cs new file mode 100644 index 00000000000..1be89beff0b --- /dev/null +++ b/Content.Shared/Robotics/RoboticsConsoleUi.cs @@ -0,0 +1,126 @@ +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Utility; + +namespace Content.Shared.Robotics; + +[Serializable, NetSerializable] +public enum RoboticsConsoleUiKey : byte +{ + Key +} + +[Serializable, NetSerializable] +public sealed class RoboticsConsoleState : BoundUserInterfaceState +{ + /// + /// Map of device network addresses to cyborg data. + /// + public Dictionary Cyborgs; + + public RoboticsConsoleState(Dictionary cyborgs) + { + Cyborgs = cyborgs; + } +} + +/// +/// Message to disable the selected cyborg. +/// +[Serializable, NetSerializable] +public sealed class RoboticsConsoleDisableMessage : BoundUserInterfaceMessage +{ + public readonly string Address; + + public RoboticsConsoleDisableMessage(string address) + { + Address = address; + } +} + +/// +/// Message to destroy the selected cyborg. +/// +[Serializable, NetSerializable] +public sealed class RoboticsConsoleDestroyMessage : BoundUserInterfaceMessage +{ + public readonly string Address; + + public RoboticsConsoleDestroyMessage(string address) + { + Address = address; + } +} + +/// +/// All data a client needs to render the console UI for a single cyborg. +/// Created by BorgTransponderComponent and sent to clients by RoboticsConsoleComponent. +/// +[DataRecord, Serializable, NetSerializable] +public record struct CyborgControlData +{ + /// + /// Texture of the borg chassis. + /// + [DataField(required: true)] + public SpriteSpecifier? ChassisSprite; + + /// + /// Name of the borg chassis. + /// + [DataField(required: true)] + public string ChassisName = string.Empty; + + /// + /// Name of the borg's entity, including its silicon id. + /// + [DataField(required: true)] + public string Name = string.Empty; + + /// + /// Battery charge from 0 to 1. + /// + [DataField] + public float Charge; + + /// + /// How many modules this borg has, just useful information for roboticists. + /// Lets them keep track of the latejoin borgs that need new modules and stuff. + /// + [DataField] + public int ModuleCount; + + /// + /// Whether the borg has a brain installed or not. + /// + [DataField] + public bool HasBrain; + + /// + /// When this cyborg's data will be deleted. + /// Set by the console when receiving the packet. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan Timeout = TimeSpan.Zero; + + public CyborgControlData(SpriteSpecifier? chassisSprite, string chassisName, string name, float charge, int moduleCount, bool hasBrain) + { + ChassisSprite = chassisSprite; + ChassisName = chassisName; + Name = name; + Charge = charge; + ModuleCount = moduleCount; + HasBrain = hasBrain; + } +} + +public static class RoboticsConsoleConstants +{ + // broadcast by cyborgs on Robotics Console frequency + public const string NET_CYBORG_DATA = "cyborg-data"; + + // sent by robotics console to cyborgs on Cyborg Control frequency + public const string NET_DISABLE_COMMAND = "cyborg-disable"; + public const string NET_DESTROY_COMMAND = "cyborg-destroy"; +} diff --git a/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs b/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs new file mode 100644 index 00000000000..25b3c5d07a8 --- /dev/null +++ b/Content.Shared/Robotics/Systems/SharedRoboticsConsoleSystem.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.Robotics.Systems; + +/// +/// Does nothing, only exists for access right now. +/// +public abstract class SharedRoboticsConsoleSystem : EntitySystem +{ +} diff --git a/Content.Shared/Roles/SharedRoleSystem.cs b/Content.Shared/Roles/SharedRoleSystem.cs index 94ad32164b3..d5ac2e5923a 100644 --- a/Content.Shared/Roles/SharedRoleSystem.cs +++ b/Content.Shared/Roles/SharedRoleSystem.cs @@ -196,11 +196,13 @@ public bool MindTryRemoveRole(EntityUid mindId) where T : IComponent public bool MindHasRole(EntityUid mindId) where T : IComponent { + DebugTools.Assert(HasComp(mindId)); return HasComp(mindId); } public List MindGetAllRoles(EntityUid mindId) { + DebugTools.Assert(HasComp(mindId)); var ev = new MindGetAllRolesEvent(new List()); RaiseLocalEvent(mindId, ref ev); return ev.Roles; @@ -211,6 +213,7 @@ public bool MindIsAntagonist(EntityUid? mindId) if (mindId == null) return false; + DebugTools.Assert(HasComp(mindId)); var ev = new MindIsAntagonistEvent(); RaiseLocalEvent(mindId.Value, ref ev); return ev.IsAntagonist; diff --git a/Content.Shared/Roles/StartingGearEquippedEvent.cs b/Content.Shared/Roles/StartingGearEquippedEvent.cs new file mode 100644 index 00000000000..41b6caccff6 --- /dev/null +++ b/Content.Shared/Roles/StartingGearEquippedEvent.cs @@ -0,0 +1,10 @@ +namespace Content.Shared.Roles; + +/// +/// Raised directed on an entity when a new starting gear prototype has been equipped. +/// +[ByRefEvent] +public record struct StartingGearEquippedEvent(EntityUid Entity) +{ + public readonly EntityUid Entity = Entity; +} diff --git a/Content.Shared/Salvage/SalvageMapPrototype.cs b/Content.Shared/Salvage/SalvageMapPrototype.cs index a9814c7b0ac..9b5a37c6689 100644 --- a/Content.Shared/Salvage/SalvageMapPrototype.cs +++ b/Content.Shared/Salvage/SalvageMapPrototype.cs @@ -4,7 +4,7 @@ namespace Content.Shared.Salvage; [Prototype] -public sealed class SalvageMapPrototype : IPrototype +public sealed partial class SalvageMapPrototype : IPrototype { [ViewVariables] [IdDataField] public string ID { get; } = default!; diff --git a/Content.Shared/Silicons/Borgs/Components/BorgTransponderComponent.cs b/Content.Shared/Silicons/Borgs/Components/BorgTransponderComponent.cs new file mode 100644 index 00000000000..8c15e20d5d0 --- /dev/null +++ b/Content.Shared/Silicons/Borgs/Components/BorgTransponderComponent.cs @@ -0,0 +1,43 @@ +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Utility; + +namespace Content.Shared.Silicons.Borgs.Components; + +/// +/// Periodically broadcasts borg data to robotics consoles. +/// When not emagged, handles disabling and destroying commands as expected. +/// +[RegisterComponent, Access(typeof(SharedBorgSystem))] +public sealed partial class BorgTransponderComponent : Component +{ + /// + /// Sprite of the chassis to send. + /// + [DataField(required: true)] + public SpriteSpecifier? Sprite; + + /// + /// Name of the chassis to send. + /// + [DataField(required: true)] + public string Name = string.Empty; + + /// + /// Popup shown to everyone when a borg is disabled. + /// Gets passed a string "name". + /// + [DataField] + public LocId DisabledPopup = "borg-transponder-disabled-popup"; + + /// + /// How long to wait between each broadcast. + /// + [DataField] + public TimeSpan BroadcastDelay = TimeSpan.FromSeconds(5); + + /// + /// When to next broadcast data. + /// + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextBroadcast = TimeSpan.Zero; +} diff --git a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs index f6407be5c7b..5e5df448b33 100644 --- a/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs +++ b/Content.Shared/Silicons/Laws/SiliconLawPrototype.cs @@ -58,7 +58,7 @@ public SiliconLaw ShallowClone() /// [Prototype("siliconLaw")] [Serializable, NetSerializable] -public sealed class SiliconLawPrototype : SiliconLaw, IPrototype +public sealed partial class SiliconLawPrototype : SiliconLaw, IPrototype { /// [IdDataField] diff --git a/Content.Shared/SimpleStation14/Traits/Components/NearsightedComponent.cs b/Content.Shared/SimpleStation14/Traits/Components/NearsightedComponent.cs deleted file mode 100644 index fafd8f87102..00000000000 --- a/Content.Shared/SimpleStation14/Traits/Components/NearsightedComponent.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.SimpleStation14.Traits.Components; - -/// -/// Owner entity cannot see well, without prescription glasses. -/// -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class NearsightedComponent : Component -{ - /// - /// Distance from the edge of the screen to the center - /// - /// - /// I don't know how the distance is measured, 1 is very close to the center, 0 is maybe visible around the edge - /// - [DataField("radius"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float Radius = 0.8f; - - /// - /// How dark the circle mask is from - /// - /// - /// I also don't know how this works, it only starts getting noticeably dark at 0.7, and is definitely noticeable at 0.9, 1 is black - /// - [DataField("alpha"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float Alpha = 0.995f; - - /// - [DataField("equippedRadius"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float EquippedRadius = 0.45f; - - /// - [DataField("equippedAlpha"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float EquippedAlpha = 0.93f; - - /// - /// How long the lerp animation should go on for in seconds. - /// - [DataField("lerpDuration"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public float LerpDuration = 0.25f; - - /// - /// If true, uses the variables prefixed "Equipped" - /// If false, uses the variables without a prefix - /// - [ViewVariables(VVAccess.ReadWrite)] // Make the system shared if you want this networked, I don't wanna do that - public bool Active = false; -} diff --git a/Content.Server/Speech/Components/VocalComponent.cs b/Content.Shared/Speech/Components/VocalComponent.cs similarity index 83% rename from Content.Server/Speech/Components/VocalComponent.cs rename to Content.Shared/Speech/Components/VocalComponent.cs index 029d638a669..e5d2c9997fa 100644 --- a/Content.Server/Speech/Components/VocalComponent.cs +++ b/Content.Shared/Speech/Components/VocalComponent.cs @@ -1,18 +1,18 @@ -using Content.Server.Speech.EntitySystems; using Content.Shared.Chat.Prototypes; using Content.Shared.Humanoid; using Robust.Shared.Audio; +using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Dictionary; -namespace Content.Server.Speech.Components; +namespace Content.Shared.Speech.Components; /// /// Component required for entities to be able to do vocal emotions. /// -[RegisterComponent] -[Access(typeof(VocalSystem))] +[RegisterComponent, NetworkedComponent] +[AutoGenerateComponentState] public sealed partial class VocalComponent : Component { /// @@ -20,21 +20,27 @@ public sealed partial class VocalComponent : Component /// Entities without considered to be . /// [DataField("sounds", customTypeSerializer: typeof(PrototypeIdValueDictionarySerializer))] + [AutoNetworkedField] public Dictionary? Sounds; [DataField("screamId", customTypeSerializer: typeof(PrototypeIdSerializer))] + [AutoNetworkedField] public string ScreamId = "Scream"; [DataField("wilhelm")] + [AutoNetworkedField] public SoundSpecifier Wilhelm = new SoundPathSpecifier("/Audio/Voice/Human/wilhelm_scream.ogg"); [DataField("wilhelmProbability")] + [AutoNetworkedField] public float WilhelmProbability = 0.0002f; [DataField("screamAction", customTypeSerializer: typeof(PrototypeIdSerializer))] + [AutoNetworkedField] public string ScreamAction = "ActionScream"; [DataField("screamActionEntity")] + [AutoNetworkedField] public EntityUid? ScreamActionEntity; /// @@ -42,5 +48,6 @@ public sealed partial class VocalComponent : Component /// Null if no valid prototype for entity sex was found. /// [ViewVariables] + [AutoNetworkedField] public EmoteSoundsPrototype? EmoteSounds = null; } diff --git a/Content.Shared/Speech/SpeechComponent.cs b/Content.Shared/Speech/SpeechComponent.cs index 272d9ef8cab..0882120718d 100644 --- a/Content.Shared/Speech/SpeechComponent.cs +++ b/Content.Shared/Speech/SpeechComponent.cs @@ -1,3 +1,4 @@ +using Content.Shared.Chat.Prototypes; using Robust.Shared.Audio; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -26,6 +27,13 @@ public sealed partial class SpeechComponent : Component [DataField] public ProtoId SpeechVerb = "Default"; + /// + /// What emotes allowed to use event if emote is false + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public List> AllowedEmotes = new(); + /// /// A mapping from chat suffixes loc strings to speech verb prototypes that should be conditionally used. /// For things like '?' changing to 'asks' or '!!' making text bold and changing to 'yells'. Can be overridden if necessary. diff --git a/Content.Shared/SprayPainter/Prototypes/AirlockDepartmentsPrototype.cs b/Content.Shared/SprayPainter/Prototypes/AirlockDepartmentsPrototype.cs index 3553597c526..b61aa037cc9 100644 --- a/Content.Shared/SprayPainter/Prototypes/AirlockDepartmentsPrototype.cs +++ b/Content.Shared/SprayPainter/Prototypes/AirlockDepartmentsPrototype.cs @@ -7,7 +7,7 @@ namespace Content.Shared.SprayPainter.Prototypes; /// Maps airlock style names to department ids. /// [Prototype("airlockDepartments")] -public sealed class AirlockDepartmentsPrototype : IPrototype +public sealed partial class AirlockDepartmentsPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; diff --git a/Content.Shared/Station/SharedStationSpawningSystem.cs b/Content.Shared/Station/SharedStationSpawningSystem.cs index 9e933181034..e889b5c9746 100644 --- a/Content.Shared/Station/SharedStationSpawningSystem.cs +++ b/Content.Shared/Station/SharedStationSpawningSystem.cs @@ -1,6 +1,8 @@ +using System.Linq; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Inventory; +using Content.Shared.Preferences.Loadouts; using Content.Shared.Roles; using Content.Shared.Storage; using Content.Shared.Storage.EntitySystems; @@ -17,12 +19,24 @@ public abstract class SharedStationSpawningSystem : EntitySystem [Dependency] private readonly SharedStorageSystem _storage = default!; [Dependency] private readonly SharedTransformSystem _xformSystem = default!; + private EntityQuery _handsQuery; + private EntityQuery _inventoryQuery; + private EntityQuery _storageQuery; + private EntityQuery _xformQuery; + + public override void Initialize() + { + base.Initialize(); + _handsQuery = GetEntityQuery(); + _inventoryQuery = GetEntityQuery(); + _storageQuery = GetEntityQuery(); + _xformQuery = GetEntityQuery(); + } + /// - /// Equips starting gear onto the given entity. + /// /// - /// Entity to load out. - /// Starting gear to use. - public void EquipStartingGear(EntityUid entity, ProtoId? startingGear) + public void EquipStartingGear(EntityUid entity, ProtoId? startingGear, bool raiseEvent = true) { PrototypeManager.TryIndex(startingGear, out var gearProto); EquipStartingGear(entity, gearProto); @@ -33,11 +47,14 @@ public void EquipStartingGear(EntityUid entity, ProtoId? /// /// Entity to load out. /// Starting gear to use. - public void EquipStartingGear(EntityUid entity, StartingGearPrototype? startingGear) + /// Should we raise the event for equipped. Set to false if you will call this manually + public void EquipStartingGear(EntityUid entity, StartingGearPrototype? startingGear, bool raiseEvent = true) { if (startingGear == null) return; + var xform = _xformQuery.GetComponent(entity); + if (InventorySystem.TryGetSlots(entity, out var slotDefinitions)) { foreach (var slot in slotDefinitions) @@ -46,15 +63,15 @@ public void EquipStartingGear(EntityUid entity, StartingGearPrototype? startingG if (string.IsNullOrEmpty(equipmentStr)) continue; - var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, EntityManager.GetComponent(entity).Coordinates); + var equipmentEntity = EntityManager.SpawnEntity(equipmentStr, xform.Coordinates); InventorySystem.TryEquip(entity, equipmentEntity, slot.Name, true, force:true); } } - if (TryComp(entity, out HandsComponent? handsComponent)) + if (_handsQuery.TryComp(entity, out var handsComponent)) { var inhand = startingGear.Inhand; - var coords = EntityManager.GetComponent(entity).Coordinates; + var coords = xform.Coordinates; foreach (var prototype in inhand) { var inhandEntity = EntityManager.SpawnEntity(prototype, coords); @@ -71,7 +88,7 @@ public void EquipStartingGear(EntityUid entity, StartingGearPrototype? startingG { var coords = _xformSystem.GetMapCoordinates(entity); var ents = new ValueList(); - TryComp(entity, out InventoryComponent? inventoryComp); + _inventoryQuery.TryComp(entity, out var inventoryComp); foreach (var (slot, entProtos) in startingGear.Storage) { @@ -83,17 +100,22 @@ public void EquipStartingGear(EntityUid entity, StartingGearPrototype? startingG ents.Add(Spawn(ent, coords)); } - if (inventoryComp == null - || !InventorySystem.TryGetSlotEntity(entity, slot, out var slotEnt, - inventoryComponent: inventoryComp) - || !TryComp(slotEnt, out StorageComponent? storage)) - continue; - - foreach (var ent in ents) + if (inventoryComp != null && + InventorySystem.TryGetSlotEntity(entity, slot, out var slotEnt, inventoryComponent: inventoryComp) && + _storageQuery.TryComp(slotEnt, out var storage)) { - _storage.Insert(slotEnt.Value, ent, out _, storageComp: storage, playSound: false); + foreach (var ent in ents) + { + _storage.Insert(slotEnt.Value, ent, out _, storageComp: storage, playSound: false); + } } } } + + if (raiseEvent) + { + var ev = new StartingGearEquippedEvent(entity); + RaiseLocalEvent(entity, ref ev, true); + } } } diff --git a/Content.Shared/StatusIcon/StatusIconPrototype.cs b/Content.Shared/StatusIcon/StatusIconPrototype.cs index b520b185de2..c5a5fd8a2c5 100644 --- a/Content.Shared/StatusIcon/StatusIconPrototype.cs +++ b/Content.Shared/StatusIcon/StatusIconPrototype.cs @@ -52,7 +52,7 @@ public int CompareTo(StatusIconData? other) /// but in new convenient prototype form! /// [Prototype("statusIcon")] -public sealed class StatusIconPrototype : StatusIconData, IPrototype, IInheritingPrototype +public sealed partial class StatusIconPrototype : StatusIconData, IPrototype, IInheritingPrototype { /// [ParentDataField(typeof(AbstractPrototypeIdArraySerializer))] diff --git a/Content.Shared/Stealth/SharedStealthSystem.cs b/Content.Shared/Stealth/SharedStealthSystem.cs index d0ea8045347..1bab55589fd 100644 --- a/Content.Shared/Stealth/SharedStealthSystem.cs +++ b/Content.Shared/Stealth/SharedStealthSystem.cs @@ -113,7 +113,7 @@ private void OnStealthHandleState(EntityUid uid, StealthComponent component, ref private void OnMove(EntityUid uid, StealthOnMoveComponent component, ref MoveEvent args) { - if (args.FromStateHandling) + if (_timing.ApplyingState) return; if (args.NewPosition.EntityId != args.OldPosition.EntityId) diff --git a/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerComponent.cs b/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerComponent.cs new file mode 100644 index 00000000000..9efd78d0825 --- /dev/null +++ b/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerComponent.cs @@ -0,0 +1,10 @@ +using Content.Shared.Inventory; +using Robust.Shared.GameStates; + +namespace Content.Shared.StepTrigger.Components; + +/// +/// This is used for marking step trigger events that require the user to wear shoes, such as for glass shards. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ClothingRequiredStepTriggerComponent : Component; diff --git a/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerImmuneComponent.cs b/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerImmuneComponent.cs new file mode 100644 index 00000000000..dc76207828c --- /dev/null +++ b/Content.Shared/StepTrigger/Components/ClothingRequiredStepTriggerImmuneComponent.cs @@ -0,0 +1,16 @@ +using Content.Shared.Inventory; +using Content.Shared.StepTrigger.Systems; +using Robust.Shared.GameStates; + +namespace Content.Shared.StepTrigger.Components; + +/// +/// This is used for cancelling step trigger events if the user is wearing clothing in a valid slot. +/// +[RegisterComponent, NetworkedComponent] +[Access(typeof(StepTriggerImmuneSystem))] +public sealed partial class ClothingRequiredStepTriggerImmuneComponent : Component, IClothingSlots +{ + [DataField] + public SlotFlags Slots { get; set; } = SlotFlags.FEET; +} diff --git a/Content.Shared/StepTrigger/Components/ShoesRequiredStepTriggerComponent.cs b/Content.Shared/StepTrigger/Components/ShoesRequiredStepTriggerComponent.cs deleted file mode 100644 index dd95b94a7ef..00000000000 --- a/Content.Shared/StepTrigger/Components/ShoesRequiredStepTriggerComponent.cs +++ /dev/null @@ -1,11 +0,0 @@ -using Robust.Shared.GameStates; - -namespace Content.Shared.StepTrigger.Components; - -/// -/// This is used for cancelling step trigger events if the user is wearing shoes, such as for glass shards. -/// -[RegisterComponent, NetworkedComponent] -public sealed partial class ShoesRequiredStepTriggerComponent : Component -{ -} diff --git a/Content.Shared/StepTrigger/Systems/ShoesRequiredStepTriggerSystem.cs b/Content.Shared/StepTrigger/Systems/ShoesRequiredStepTriggerSystem.cs deleted file mode 100644 index 5fc9140dfd0..00000000000 --- a/Content.Shared/StepTrigger/Systems/ShoesRequiredStepTriggerSystem.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Content.Shared.Examine; -using Content.Shared.Inventory; -using Content.Shared.StepTrigger.Components; -using Content.Shared.Tag; - -namespace Content.Shared.StepTrigger.Systems; - -public sealed class ShoesRequiredStepTriggerSystem : EntitySystem -{ - [Dependency] private readonly InventorySystem _inventory = default!; - [Dependency] private readonly TagSystem _tagSystem = default!; - - /// - public override void Initialize() - { - SubscribeLocalEvent(OnStepTriggerAttempt); - SubscribeLocalEvent(OnExamined); - } - - private void OnStepTriggerAttempt(EntityUid uid, ShoesRequiredStepTriggerComponent component, ref StepTriggerAttemptEvent args) - { - if (_tagSystem.HasTag(args.Tripper, "ShoesRequiredStepTriggerImmune")) - { - args.Cancelled = true; - return; - } - - if (!TryComp(args.Tripper, out var inventory)) - return; - - if (_inventory.TryGetSlotEntity(args.Tripper, "shoes", out _, inventory)) - { - args.Cancelled = true; - } - } - - private void OnExamined(EntityUid uid, ShoesRequiredStepTriggerComponent component, ExaminedEvent args) - { - args.PushMarkup(Loc.GetString("shoes-required-step-trigger-examine")); - } -} diff --git a/Content.Shared/StepTrigger/Systems/StepTriggerImmuneSystem.cs b/Content.Shared/StepTrigger/Systems/StepTriggerImmuneSystem.cs new file mode 100644 index 00000000000..ca72a20ae9c --- /dev/null +++ b/Content.Shared/StepTrigger/Systems/StepTriggerImmuneSystem.cs @@ -0,0 +1,37 @@ +using Content.Shared.Examine; +using Content.Shared.Inventory; +using Content.Shared.StepTrigger.Components; +using Content.Shared.Tag; + +namespace Content.Shared.StepTrigger.Systems; + +public sealed class StepTriggerImmuneSystem : EntitySystem +{ + [Dependency] private readonly InventorySystem _inventory = default!; + + /// + public override void Initialize() + { + SubscribeLocalEvent(OnStepTriggerAttempt); + SubscribeLocalEvent(OnStepTriggerClothingAttempt); + SubscribeLocalEvent(OnExamined); + } + + private void OnStepTriggerAttempt(Entity ent, ref StepTriggerAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnStepTriggerClothingAttempt(EntityUid uid, ClothingRequiredStepTriggerComponent component, ref StepTriggerAttemptEvent args) + { + if (_inventory.TryGetInventoryEntity(args.Tripper, out _)) + { + args.Cancelled = true; + } + } + + private void OnExamined(EntityUid uid, ClothingRequiredStepTriggerComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("clothing-required-step-trigger-examine")); + } +} diff --git a/Content.Shared/Storage/Components/SecretStashComponent.cs b/Content.Shared/Storage/Components/SecretStashComponent.cs index 8595f79ca57..07a1078f63f 100644 --- a/Content.Shared/Storage/Components/SecretStashComponent.cs +++ b/Content.Shared/Storage/Components/SecretStashComponent.cs @@ -6,6 +6,7 @@ using Content.Shared.Tools; using Robust.Shared.GameStates; using Content.Shared.DoAfter; +using Content.Shared.Toilet.Components; using Robust.Shared.Serialization; namespace Content.Shared.Storage.Components diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index 966ec02b805..f0d1ab7d177 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -2,14 +2,18 @@ using System.Diagnostics.CodeAnalysis; using System.Linq; using Content.Shared.ActionBlocker; +using Content.Shared.Administration; +using Content.Shared.Administration.Managers; using Content.Shared.Containers.ItemSlots; -using Content.Shared.Coordinates; using Content.Shared.Destructible; using Content.Shared.DoAfter; +using Content.Shared.Ghost; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Implants.Components; +using Content.Shared.Input; using Content.Shared.Interaction; +using Content.Shared.Inventory; using Content.Shared.Item; using Content.Shared.Lock; using Content.Shared.Nyanotrasen.Item.PseudoItem; @@ -23,10 +27,13 @@ using Robust.Shared.Audio.Systems; using Robust.Shared.Containers; using Robust.Shared.GameStates; +using Robust.Shared.Input.Binding; using Robust.Shared.Map; +using Robust.Shared.Player; using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Serialization; +using Robust.Shared.Utility; namespace Content.Shared.Storage.EntitySystems; @@ -34,6 +41,7 @@ public abstract class SharedStorageSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] protected readonly IRobustRandom Random = default!; + [Dependency] private readonly ISharedAdminManager _admin = default!; [Dependency] protected readonly ActionBlockerSystem ActionBlocker = default!; [Dependency] private readonly EntityLookupSystem _entityLookupSystem = default!; [Dependency] private readonly SharedAppearanceSystem _appearance = default!; @@ -42,6 +50,7 @@ public abstract class SharedStorageSystem : EntitySystem [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] protected readonly SharedEntityStorageSystem EntityStorage = default!; [Dependency] private readonly SharedInteractionSystem _interactionSystem = default!; + [Dependency] private readonly InventorySystem _inventory = default!; [Dependency] protected readonly SharedItemSystem ItemSystem = default!; [Dependency] private readonly SharedPopupSystem _popupSystem = default!; [Dependency] private readonly SharedHandsSystem _sharedHandsSystem = default!; @@ -63,9 +72,17 @@ public abstract class SharedStorageSystem : EntitySystem public bool CheckingCanInsert; + private List _entList = new(); + private HashSet _entSet = new(); + private readonly List _sortedSizes = new(); private FrozenDictionary _nextSmallest = FrozenDictionary.Empty; + private const string QuickInsertUseDelayID = "quickInsert"; + private const string OpenUiUseDelayID = "storage"; + + protected readonly List CantFillReasons = []; + /// public override void Initialize() { @@ -76,6 +93,13 @@ public override void Initialize() _xformQuery = GetEntityQuery(); _prototype.PrototypesReloaded += OnPrototypesReloaded; + Subs.BuiEvents(StorageComponent.StorageUiKey.Key, subs => + { + subs.Event(OnBoundUIClosed); + }); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent>(AddUiVerb); SubscribeLocalEvent(OnStorageGetState); SubscribeLocalEvent(OnStorageHandleState); SubscribeLocalEvent(OnComponentInit, before: new[] { typeof(SharedContainerSystem) }); @@ -86,6 +110,7 @@ public override void Initialize() SubscribeLocalEvent(AfterInteract); SubscribeLocalEvent(OnDestroy); SubscribeLocalEvent(OnBoundUIOpen); + SubscribeLocalEvent(OnLockToggled); SubscribeLocalEvent(OnStackCountChanged); SubscribeLocalEvent(OnEntInserted); @@ -102,9 +127,20 @@ public override void Initialize() SubscribeLocalEvent(OnReclaimed); + CommandBinds.Builder + .Bind(ContentKeyFunctions.OpenBackpack, InputCmdHandler.FromDelegate(HandleOpenBackpack, handle: false)) + .Bind(ContentKeyFunctions.OpenBelt, InputCmdHandler.FromDelegate(HandleOpenBelt, handle: false)) + .Register(); + UpdatePrototypeCache(); } + private void OnMapInit(Entity entity, ref MapInitEvent args) + { + UseDelay.SetLength(entity.Owner, entity.Comp.QuickInsertCooldown, QuickInsertUseDelayID); + UseDelay.SetLength(entity.Owner, entity.Comp.OpenUiCooldown, OpenUiUseDelayID); + } + private void OnStorageGetState(EntityUid uid, StorageComponent component, ref ComponentGetState args) { var storedItems = new Dictionary(); @@ -117,7 +153,6 @@ private void OnStorageGetState(EntityUid uid, StorageComponent component, ref Co args.State = new StorageComponentState() { Grid = new List(component.Grid), - IsUiOpen = component.IsUiOpen, MaxItemSize = component.MaxItemSize, StoredItems = storedItems, SavedLocations = component.SavedLocations @@ -131,7 +166,6 @@ private void OnStorageHandleState(EntityUid uid, StorageComponent component, ref component.Grid.Clear(); component.Grid.AddRange(state.Grid); - component.IsUiOpen = state.IsUiOpen; component.MaxItemSize = state.MaxItemSize; component.StoredItems.Clear(); @@ -183,9 +217,108 @@ private void OnComponentInit(EntityUid uid, StorageComponent storageComp, Compon UpdateAppearance((uid, storageComp, null)); } - public virtual void UpdateUI(Entity entity) {} + /// + /// If the user has nested-UIs open (e.g., PDA UI open when pda is in a backpack), close them. + /// + private void CloseNestedInterfaces(EntityUid uid, EntityUid actor, StorageComponent? storageComp = null) + { + if (!Resolve(uid, ref storageComp)) + return; - public virtual void OpenStorageUI(EntityUid uid, EntityUid entity, StorageComponent? storageComp = null, bool silent = false) { } + // for each containing thing + // if it has a storage comp + // ensure unsubscribe from session + // if it has a ui component + // close ui + foreach (var entity in storageComp.Container.ContainedEntities) + { + _ui.CloseUis(entity, actor); + } + } + + private void OnBoundUIClosed(EntityUid uid, StorageComponent storageComp, BoundUIClosedEvent args) + { + CloseNestedInterfaces(uid, args.Actor, storageComp); + + // If UI is closed for everyone + if (!_ui.IsUiOpen(uid, args.UiKey)) + { + UpdateAppearance((uid, storageComp, null)); + Audio.PlayPredicted(storageComp.StorageCloseSound, uid, args.Actor); + } + } + + private void AddUiVerb(EntityUid uid, StorageComponent component, GetVerbsEvent args) + { + var silent = false; + if (!args.CanAccess || !args.CanInteract || TryComp(uid, out var lockComponent) && lockComponent.Locked) + { + // we allow admins to open the storage anyways + if (!_admin.HasAdminFlag(args.User, AdminFlags.Admin)) + return; + + silent = true; + } + + silent |= HasComp(args.User); + + // Does this player currently have the storage UI open? + var uiOpen = _ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User); + + ActivationVerb verb = new() + { + Act = () => + { + if (uiOpen) + { + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); + } + else + { + OpenStorageUI(uid, args.User, component, silent); + } + } + }; + + if (uiOpen) + { + verb.Text = Loc.GetString("comp-storage-verb-close-storage"); + verb.Icon = new SpriteSpecifier.Texture( + new("/Textures/Interface/VerbIcons/close.svg.192dpi.png")); + } + else + { + verb.Text = Loc.GetString("comp-storage-verb-open-storage"); + verb.Icon = new SpriteSpecifier.Texture( + new("/Textures/Interface/VerbIcons/open.svg.192dpi.png")); + } + args.Verbs.Add(verb); + } + + /// + /// Opens the storage UI for an entity + /// + /// The entity to open the UI for + public void OpenStorageUI(EntityUid uid, EntityUid entity, StorageComponent? storageComp = null, bool silent = false) + { + if (!Resolve(uid, ref storageComp, false)) + return; + + // prevent spamming bag open / honkerton honk sound + silent |= TryComp(uid, out var useDelay) && UseDelay.IsDelayed((uid, useDelay)); + if (!silent) + { + if (!_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key)) + Audio.PlayPredicted(storageComp.StorageOpenSound, uid, entity); + + if (useDelay != null) + UseDelay.TryResetDelay((uid, useDelay)); + } + + _ui.OpenUi(uid, StorageComponent.StorageUiKey.Key, entity); + } + + public virtual void UpdateUI(Entity entity) {} private void AddTransferVerbs(EntityUid uid, StorageComponent component, GetVerbsEvent args) { @@ -239,7 +372,16 @@ private void OnActivate(EntityUid uid, StorageComponent storageComp, ActivateInW if (args.Handled || TryComp(uid, out var lockComponent) && lockComponent.Locked) return; - OpenStorageUI(uid, args.User, storageComp); + // Toggle + if (_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, args.User)) + { + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, args.User); + } + else + { + OpenStorageUI(uid, args.User, storageComp); + } + args.Handled = true; } @@ -262,36 +404,40 @@ private void OnImplantActivate(EntityUid uid, StorageComponent storageComp, Open /// private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInteractEvent args) { - if (args.Handled || !args.CanReach) + if (args.Handled || !args.CanReach || !UseDelay.TryResetDelay(uid, checkDelayed: true, id: QuickInsertUseDelayID)) return; // Pick up all entities in a radius around the clicked location. // The last half of the if is because carpets exist and this is terrible if (storageComp.AreaInsert && (args.Target == null || !HasComp(args.Target.Value))) { - var validStorables = new List(); + _entList.Clear(); + _entSet.Clear(); + _entityLookupSystem.GetEntitiesInRange(args.ClickLocation, storageComp.AreaInsertRadius, _entSet, LookupFlags.Dynamic | LookupFlags.Sundries); var delay = 0f; - foreach (var entity in _entityLookupSystem.GetEntitiesInRange(args.ClickLocation, storageComp.AreaInsertRadius, LookupFlags.Dynamic | LookupFlags.Sundries)) + foreach (var entity in _entSet) { if (entity == args.User - // || !_itemQuery.HasComponent(entity) - || !TryComp(entity, out var itemComp) // Need comp to get item size to get weight + || !_itemQuery.TryGetComponent(entity, out var itemComp) // Need comp to get item size to get weight || !_prototype.TryIndex(itemComp.Size, out var itemSize) - || !CanInsert(uid, entity, out _, storageComp) + || !CanInsert(uid, entity, out _, storageComp, item: itemComp) || !_interactionSystem.InRangeUnobstructed(args.User, entity)) { continue; } - validStorables.Add(entity); + _entList.Add(entity); delay += itemSize.Weight * AreaInsertDelayPerItem; + + if (_entList.Count >= StorageComponent.AreaPickupLimit) + break; } //If there's only one then let's be generous - if (validStorables.Count > 1) + if (_entList.Count > 1) { - var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay, new AreaPickupDoAfterEvent(GetNetEntityList(validStorables)), uid, target: uid) + var doAfterArgs = new DoAfterArgs(EntityManager, args.User, delay, new AreaPickupDoAfterEvent(GetNetEntityList(_entList)), uid, target: uid) { BreakOnDamage = true, BreakOnUserMove = true, @@ -313,7 +459,7 @@ private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInt if (_containerSystem.IsEntityInContainer(target) || target == args.User - || !HasComp(target)) + || !_itemQuery.HasComponent(target)) { return; } @@ -331,10 +477,10 @@ private void AfterInteract(EntityUid uid, StorageComponent storageComp, AfterInt args.Handled = true; if (PlayerInsertEntityInWorld((uid, storageComp), args.User, target)) { - RaiseNetworkEvent(new AnimateInsertingEntitiesEvent(GetNetEntity(uid), + EntityManager.RaiseSharedEvent(new AnimateInsertingEntitiesEvent(GetNetEntity(uid), new List { GetNetEntity(target) }, new List { GetNetCoordinates(position) }, - new List { transformOwner.LocalRotation })); + new List { transformOwner.LocalRotation }), args.User); } } } @@ -349,20 +495,27 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf var successfullyInserted = new List(); var successfullyInsertedPositions = new List(); var successfullyInsertedAngles = new List(); - _xformQuery.TryGetComponent(uid, out var xform); - foreach (var netEntity in args.Entities) + if (!_xformQuery.TryGetComponent(uid, out var xform)) + { + return; + } + + var entCount = Math.Min(StorageComponent.AreaPickupLimit, args.Entities.Count); + + for (var i = 0; i < entCount; i++) { - var entity = GetEntity(netEntity); + var entity = GetEntity(args.Entities[i]); // Check again, situation may have changed for some entities, but we'll still pick up any that are valid if (_containerSystem.IsEntityInContainer(entity) || entity == args.Args.User || !_itemQuery.HasComponent(entity)) + { continue; + } - if (xform == null || - !_xformQuery.TryGetComponent(entity, out var targetXform) || + if (!_xformQuery.TryGetComponent(entity, out var targetXform) || targetXform.MapID != xform.MapID) { continue; @@ -387,12 +540,12 @@ private void OnDoAfter(EntityUid uid, StorageComponent component, AreaPickupDoAf // If we picked up at least one thing, play a sound and do a cool animation! if (successfullyInserted.Count > 0) { - Audio.PlayPvs(component.StorageInsertSound, uid); - RaiseNetworkEvent(new AnimateInsertingEntitiesEvent( + Audio.PlayPredicted(component.StorageInsertSound, uid, args.User); + EntityManager.RaiseSharedEvent(new AnimateInsertingEntitiesEvent( GetNetEntity(uid), GetNetEntityList(successfullyInserted), GetNetCoordinatesList(successfullyInsertedPositions), - successfullyInsertedAngles)); + successfullyInsertedAngles), args.User); } args.Handled = true; @@ -427,8 +580,7 @@ private void OnInteractWithItem(StorageInteractWithItemEvent msg, EntitySessionE if (!TryComp(uid, out var storageComp)) return; - if (!_ui.TryGetUi(uid, StorageComponent.StorageUiKey.Key, out var bui) || - !bui.SubscribedSessions.Contains(args.SenderSession)) + if (!_ui.IsUiOpen(uid, StorageComponent.StorageUiKey.Key, player)) return; if (!Exists(entity)) @@ -470,8 +622,7 @@ private void OnSetItemLocation(StorageSetItemLocationEvent msg, EntitySessionEve if (!TryComp(storageEnt, out var storageComp)) return; - if (!_ui.TryGetUi(storageEnt, StorageComponent.StorageUiKey.Key, out var bui) || - !bui.SubscribedSessions.Contains(args.SenderSession)) + if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player)) return; if (!Exists(itemEnt)) @@ -497,8 +648,7 @@ private void OnRemoveItem(StorageRemoveItemEvent msg, EntitySessionEventArgs arg if (!TryComp(storageEnt, out var storageComp)) return; - if (!_ui.TryGetUi(storageEnt, StorageComponent.StorageUiKey.Key, out var bui) || - !bui.SubscribedSessions.Contains(args.SenderSession)) + if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player)) return; if (!Exists(itemEnt)) @@ -525,8 +675,7 @@ private void OnInsertItemIntoLocation(StorageInsertItemIntoLocationEvent msg, En if (!TryComp(storageEnt, out var storageComp)) return; - if (!_ui.TryGetUi(storageEnt, StorageComponent.StorageUiKey.Key, out var bui) || - !bui.SubscribedSessions.Contains(args.SenderSession)) + if (!_ui.IsUiOpen(storageEnt, StorageComponent.StorageUiKey.Key, player)) return; if (!Exists(itemEnt)) @@ -551,11 +700,10 @@ private void OnSaveItemLocation(StorageSaveItemLocationEvent msg, EntitySessionE var storage = GetEntity(msg.Storage); var item = GetEntity(msg.Item); - if (!TryComp(storage, out var storageComp)) + if (!HasComp(storage)) return; - if (!_ui.TryGetUi(storage, StorageComponent.StorageUiKey.Key, out var bui) || - !bui.SubscribedSessions.Contains(args.SenderSession)) + if (!_ui.IsUiOpen(storage, StorageComponent.StorageUiKey.Key, player)) return; if (!Exists(item)) @@ -572,11 +720,7 @@ private void OnSaveItemLocation(StorageSaveItemLocationEvent msg, EntitySessionE private void OnBoundUIOpen(EntityUid uid, StorageComponent storageComp, BoundUIOpenedEvent args) { - if (!storageComp.IsUiOpen) - { - storageComp.IsUiOpen = true; - UpdateAppearance((uid, storageComp, null)); - } + UpdateAppearance((uid, storageComp, null)); } private void OnEntInserted(Entity entity, ref EntInsertedIntoContainerMessage args) @@ -629,8 +773,15 @@ private void OnInsertAttempt(EntityUid uid, StorageComponent component, Containe if (CheckingCanInsert) return; - if (!CanInsert(uid, args.EntityUid, out _, component, ignoreStacks: true)) + if (!CanInsert(uid, args.EntityUid, out var reason, component, ignoreStacks: true)) + { +#if DEBUG + if (reason != null) + CantFillReasons.Add(reason); +#endif + args.Cancel(); + } } public void UpdateAppearance(Entity entity) @@ -647,11 +798,13 @@ public void UpdateAppearance(Entity ent var capacity = storage.Grid.GetArea(); var used = GetCumulativeItemAreas((uid, storage)); + var isOpen = _ui.IsUiOpen(entity.Owner, StorageComponent.StorageUiKey.Key); + _appearance.SetData(uid, StorageVisuals.StorageUsed, used, appearance); _appearance.SetData(uid, StorageVisuals.Capacity, capacity, appearance); - _appearance.SetData(uid, StorageVisuals.Open, storage.IsUiOpen, appearance); - _appearance.SetData(uid, SharedBagOpenVisuals.BagState, storage.IsUiOpen ? SharedBagState.Open : SharedBagState.Closed, appearance); - _appearance.SetData(uid, StackVisuals.Hide, !storage.IsUiOpen, appearance); + _appearance.SetData(uid, StorageVisuals.Open, isOpen, appearance); + _appearance.SetData(uid, SharedBagOpenVisuals.BagState, isOpen ? SharedBagState.Open : SharedBagState.Closed, appearance); + _appearance.SetData(uid, StackVisuals.Hide, !isOpen, appearance); } /// @@ -1076,7 +1229,7 @@ public void SaveItemLocation(Entity ent, Entity uid) return _nextSmallest[item.Size]; } + /// + /// Checks if a storage's UI is open by anyone when locked, and closes it unless they're an admin. + /// + private void OnLockToggled(EntityUid uid, StorageComponent component, ref LockToggledEvent args) + { + if (!args.Locked) + return; + + // Gets everyone looking at the UI + foreach (var actor in _ui.GetActors(uid, StorageComponent.StorageUiKey.Key).ToList()) + { + if (_admin.HasAdminFlag(actor, AdminFlags.Admin)) + continue; + + // And closes it unless they're an admin + _ui.CloseUi(uid, StorageComponent.StorageUiKey.Key, actor); + } + } + private void OnStackCountChanged(EntityUid uid, MetaDataComponent component, StackCountChangedEvent args) { if (_containerSystem.TryGetContainingContainer(uid, out var container, component) && @@ -1263,6 +1435,40 @@ private void OnStackCountChanged(EntityUid uid, MetaDataComponent component, Sta } } + private void HandleOpenBackpack(ICommonSession? session) + { + HandleOpenSlotUI(session, "back"); + } + + private void HandleOpenBelt(ICommonSession? session) + { + HandleOpenSlotUI(session, "belt"); + } + + private void HandleOpenSlotUI(ICommonSession? session, string slot) + { + if (session is not { } playerSession) + return; + + if (playerSession.AttachedEntity is not {Valid: true} playerEnt || !Exists(playerEnt)) + return; + + if (!_inventory.TryGetSlotEntity(playerEnt, slot, out var storageEnt)) + return; + + if (!ActionBlocker.CanInteract(playerEnt, storageEnt)) + return; + + OpenStorageUI(storageEnt.Value, playerEnt); + } + + protected void ClearCantFillReasons() + { +#if DEBUG + CantFillReasons.Clear(); +#endif + } + /// /// Plays a clientside pickup animation for the specified uid. /// @@ -1272,8 +1478,6 @@ public abstract void PlayPickupAnimation(EntityUid uid, EntityCoordinates initia [Serializable, NetSerializable] protected sealed class StorageComponentState : ComponentState { - public bool IsUiOpen; - public Dictionary StoredItems = new(); public Dictionary> SavedLocations = new(); diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index 2cae12f07a8..ef682dd4f94 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -19,10 +19,6 @@ public sealed partial class StorageComponent : Component { public static string ContainerId = "storagebase"; - // TODO: This fucking sucks - [ViewVariables(VVAccess.ReadWrite), DataField] - public bool IsUiOpen; - [ViewVariables] public Container Container = default!; @@ -57,9 +53,27 @@ public sealed partial class StorageComponent : Component [DataField] public bool QuickInsert; // Can insert storables by clicking them with the storage entity + /// + /// Minimum delay between quick/area insert actions. + /// + /// Used to prevent autoclickers spamming server with individual pickup actions. + public TimeSpan QuickInsertCooldown = TimeSpan.FromSeconds(0.5); + + /// + /// Minimum delay between UI open actions. + /// Used to spamming opening sounds. + /// + [DataField] + public TimeSpan OpenUiCooldown = TimeSpan.Zero; + [DataField] public bool ClickInsert = true; // Can insert stuff by clicking the storage entity with it + /// + /// How many entities area pickup can pickup at once. + /// + public const int AreaPickupLimit = 10; + [DataField] public bool AreaInsert; // Clicking with the storage entity causes it to insert all nearby storables after a delay @@ -214,15 +228,6 @@ public AnimateInsertingEntitiesEvent(NetEntity storage, List storedEn } } - /// - /// An extra BUI message that either opens, closes, or focuses the storage window based on context. - /// - [Serializable, NetSerializable] - public sealed class StorageModifyWindowMessage : BoundUserInterfaceMessage - { - - } - [NetSerializable] [Serializable] public enum StorageVisuals : byte diff --git a/Content.Shared/Store/ListingPrototype.cs b/Content.Shared/Store/ListingPrototype.cs index 0b59ab48cb6..445b5742dd1 100644 --- a/Content.Shared/Store/ListingPrototype.cs +++ b/Content.Shared/Store/ListingPrototype.cs @@ -75,14 +75,14 @@ public partial class ListingData : IEquatable, ICloneable public EntProtoId? ProductAction; /// - /// The listing ID of the related upgrade listing. Can be used to link a to an - /// upgrade or to use standalone as an upgrade + /// The listing ID of the related upgrade listing. Can be used to link a to an + /// upgrade or to use standalone as an upgrade /// [DataField] - public ProtoId? ProductUpgradeID; + public ProtoId? ProductUpgradeId; /// - /// Keeps track of the current action entity this is tied to, for action upgrades + /// Keeps track of the current action entity this is tied to, for action upgrades /// [DataField] [NonSerialized] @@ -174,7 +174,7 @@ public object Clone() Priority = Priority, ProductEntity = ProductEntity, ProductAction = ProductAction, - ProductUpgradeID = ProductUpgradeID, + ProductUpgradeId = ProductUpgradeId, ProductActionEntity = ProductActionEntity, ProductEvent = ProductEvent, PurchaseAmount = PurchaseAmount, diff --git a/Content.Shared/Tag/TagSystem.cs b/Content.Shared/Tag/TagSystem.cs index 0628b892edd..0707308e486 100644 --- a/Content.Shared/Tag/TagSystem.cs +++ b/Content.Shared/Tag/TagSystem.cs @@ -1,3 +1,4 @@ +using System.Diagnostics; using System.Linq; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; @@ -9,9 +10,12 @@ public sealed class TagSystem : EntitySystem { [Dependency] private readonly IPrototypeManager _proto = default!; + private EntityQuery _tagQuery; + public override void Initialize() { base.Initialize(); + _tagQuery = GetEntityQuery(); SubscribeLocalEvent(OnTagGetState); SubscribeLocalEvent(OnTagHandleState); @@ -124,7 +128,7 @@ public bool AddTags(EntityUid entity, IEnumerable ids) /// public bool TryAddTag(EntityUid entity, string id) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && AddTag(component, id); } @@ -142,7 +146,7 @@ public bool TryAddTag(EntityUid entity, string id) /// public bool TryAddTags(EntityUid entity, params string[] ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && AddTags(component, ids); } @@ -160,7 +164,7 @@ public bool TryAddTags(EntityUid entity, params string[] ids) /// public bool TryAddTags(EntityUid entity, IEnumerable ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && AddTags(component, ids); } @@ -175,13 +179,14 @@ public bool TryAddTags(EntityUid entity, IEnumerable ids) /// public bool HasTag(EntityUid entity, string id) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && HasTag(component, id); } /// /// Checks if a tag has been added to an entity. /// + [Obsolete] public bool HasTag(EntityUid entity, string id, EntityQuery tagQuery) { return tagQuery.TryGetComponent(entity, out var component) && @@ -210,7 +215,7 @@ public bool HasTag(EntityUid entity, string id, EntityQuery tagQue /// public bool HasAllTags(EntityUid entity, List ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && HasAllTags(component, ids); } @@ -225,7 +230,7 @@ public bool HasAllTags(EntityUid entity, List ids) /// public bool HasAllTags(EntityUid entity, IEnumerable ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && HasAllTags(component, ids); } @@ -234,18 +239,33 @@ public bool HasAllTags(EntityUid entity, IEnumerable ids) /// /// The entity to check. /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(EntityUid entity, List> ids) + { + return _tagQuery.TryComp(entity, out var component) && + HasAllTags(component, ids); + } + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. /// true if any of them exist, false otherwise. /// /// Thrown if one of the ids represents an unregistered . /// public bool HasAnyTag(EntityUid entity, params string[] ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && HasAnyTag(component, ids); } /// - /// Checks if all of the given tags have been added to an entity. + /// Checks if any of the given tags have been added to an entity. /// /// The entity to check. /// The tag to check for. @@ -256,7 +276,7 @@ public bool HasAnyTag(EntityUid entity, params string[] ids) public bool HasAnyTag(EntityUid entity, string id) => HasTag(entity, id); /// - /// Checks if all of the given tags have been added to an entity. + /// Checks if any of the given tags have been added to an entity. /// /// The entity to check. /// The tags to check for. @@ -265,13 +285,28 @@ public bool HasAnyTag(EntityUid entity, params string[] ids) /// Thrown if one of the ids represents an unregistered . /// public bool HasAnyTag(EntityUid entity, List ids) + { + return _tagQuery.TryComp(entity, out var component) && + HasAnyTag(component, ids); + } + + /// + /// Checks if any of the given tags have been added to an entity. + /// + /// The entity to check. + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(EntityUid entity, List> ids) { return TryComp(entity, out var component) && HasAnyTag(component, ids); } /// - /// Checks if all of the given tags have been added to an entity. + /// Checks if any of the given tags have been added to an entity. /// /// The entity to check. /// The tags to check for. @@ -281,7 +316,7 @@ public bool HasAnyTag(EntityUid entity, List ids) /// public bool HasAnyTag(EntityUid entity, IEnumerable ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && HasAnyTag(component, ids); } @@ -298,7 +333,7 @@ public bool HasAnyTag(EntityUid entity, IEnumerable ids) /// public bool RemoveTag(EntityUid entity, string id) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && RemoveTag(component, id); } @@ -315,7 +350,7 @@ public bool RemoveTag(EntityUid entity, string id) /// public bool RemoveTags(EntityUid entity, params string[] ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && RemoveTags(component, ids); } @@ -332,7 +367,7 @@ public bool RemoveTags(EntityUid entity, params string[] ids) /// public bool RemoveTags(EntityUid entity, IEnumerable ids) { - return TryComp(entity, out var component) && + return _tagQuery.TryComp(entity, out var component) && RemoveTags(component, ids); } @@ -478,6 +513,28 @@ public bool HasAllTags(TagComponent component, IEnumerable ids) return true; } + /// + /// Checks if all of the given tags have been added. + /// + /// The tags to check for. + /// true if they all exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAllTags(TagComponent component, List> ids) + { + foreach (var id in ids) + { + AssertValidTag(id); + + if (!component.Tags.Contains(id)) + return false; + + } + + return true; + } + /// /// Checks if any of the given tags have been added. /// @@ -488,9 +545,16 @@ public bool HasAllTags(TagComponent component, IEnumerable ids) /// public bool HasAnyTag(TagComponent component, params string[] ids) { - return HasAnyTag(component, ids.AsEnumerable()); - } + foreach (var id in ids) + { + AssertValidTag(id); + + if (component.Tags.Contains(id)) + return true; + } + return false; + } /// /// Checks if any of the given tags have been added. @@ -548,6 +612,27 @@ public bool HasAnyTag(TagComponent component, IEnumerable ids) return false; } + /// + /// Checks if any of the given tags have been added. + /// + /// The tags to check for. + /// true if any of them exist, false otherwise. + /// + /// Thrown if one of the ids represents an unregistered . + /// + public bool HasAnyTag(TagComponent comp, List> ids) + { + foreach (var id in ids) + { + AssertValidTag(id); + + if (comp.Tags.Contains(id)) + return true; + } + + return false; + } + /// /// Tries to remove a tag if it exists. /// diff --git a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs index e69a31a1d40..62c0b0f44e4 100644 --- a/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs +++ b/Content.Shared/Teleportation/Systems/SwapTeleporterSystem.cs @@ -145,27 +145,14 @@ public void DoTeleport(Entity ent) } var teleEnt = GetTeleportingEntity((uid, xform)); - var teleEntXform = Transform(teleEnt); var otherTeleEnt = GetTeleportingEntity((linkedEnt, Transform(linkedEnt))); - var otherTeleEntXform = Transform(otherTeleEnt); _popup.PopupEntity(Loc.GetString("swap-teleporter-popup-teleport-other", ("entity", Identity.Entity(linkedEnt, EntityManager))), otherTeleEnt, otherTeleEnt, PopupType.MediumCaution); - var pos = teleEntXform.Coordinates; - var otherPos = otherTeleEntXform.Coordinates; - - if (_transform.ContainsEntity(teleEnt, (otherTeleEnt, otherTeleEntXform)) || - _transform.ContainsEntity(otherTeleEnt, (teleEnt, teleEntXform))) - { - Log.Error($"Invalid teleport swap attempt between {ToPrettyString(teleEnt)} and {ToPrettyString(otherTeleEnt)}"); - return; - } - - _transform.SetCoordinates(teleEnt, otherPos); - _transform.SetCoordinates(otherTeleEnt, pos); + _transform.SwapPositions(teleEnt, otherTeleEnt); } /// diff --git a/Content.Shared/Timing/UseDelayComponent.cs b/Content.Shared/Timing/UseDelayComponent.cs index 1560d4dd0b9..aa6c66eb81a 100644 --- a/Content.Shared/Timing/UseDelayComponent.cs +++ b/Content.Shared/Timing/UseDelayComponent.cs @@ -1,38 +1,53 @@ using Robust.Shared.GameStates; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; +using Robust.Shared.Serialization; namespace Content.Shared.Timing; /// -/// Timer that creates a cooldown each time an object is activated/used +/// Timer that creates a cooldown each time an object is activated/used. +/// Can support additional, separate cooldown timers on the object by passing a unique ID with the system methods. /// -/// -/// Currently it only supports a single delay per entity, this means that for things that have two delay interactions they will share one timer, so this can cause issues. For example, the bible has a delay when opening the storage UI and when applying it's interaction effect, and they share the same delay. -/// [RegisterComponent] -[NetworkedComponent, AutoGenerateComponentState, AutoGenerateComponentPause] +[NetworkedComponent] [Access(typeof(UseDelaySystem))] public sealed partial class UseDelayComponent : Component { - /// - /// When the delay starts. - /// - [ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] - [AutoPausedField] - public TimeSpan DelayStartTime; - - /// - /// When the delay ends. - /// - [ViewVariables(VVAccess.ReadWrite), DataField(customTypeSerializer: typeof(TimeOffsetSerializer)), AutoNetworkedField] - [AutoPausedField] - public TimeSpan DelayEndTime; + [DataField] + public Dictionary Delays = []; /// - /// Default delay time + /// Default delay time. /// + /// + /// This is only used at MapInit and should not be expected + /// to reflect the length of the default delay after that. + /// Use instead. + /// [DataField] - [ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] public TimeSpan Delay = TimeSpan.FromSeconds(1); } + +[Serializable, NetSerializable] +public sealed class UseDelayComponentState : IComponentState +{ + public Dictionary Delays = new(); +} + +[Serializable, NetSerializable] +[DataDefinition] +public sealed partial class UseDelayInfo +{ + [DataField] + public TimeSpan Length { get; set; } + [DataField] + public TimeSpan StartTime { get; set; } + [DataField] + public TimeSpan EndTime { get; set; } + + public UseDelayInfo(TimeSpan length, TimeSpan startTime = default, TimeSpan endTime = default) + { + Length = length; + StartTime = startTime; + EndTime = endTime; + } +} diff --git a/Content.Shared/Timing/UseDelaySystem.cs b/Content.Shared/Timing/UseDelaySystem.cs index 388f31079cd..9816d0185a5 100644 --- a/Content.Shared/Timing/UseDelaySystem.cs +++ b/Content.Shared/Timing/UseDelaySystem.cs @@ -1,3 +1,5 @@ +using System.Diagnostics.CodeAnalysis; +using Robust.Shared.GameStates; using Robust.Shared.Timing; namespace Content.Shared.Timing; @@ -7,53 +9,171 @@ public sealed class UseDelaySystem : EntitySystem [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly MetaDataSystem _metadata = default!; - public void SetDelay(Entity ent, TimeSpan delay) + private const string DefaultId = "default"; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnUnpaused); + SubscribeLocalEvent(OnDelayGetState); + SubscribeLocalEvent(OnDelayHandleState); + } + + private void OnDelayHandleState(Entity ent, ref ComponentHandleState args) { - if (ent.Comp.Delay == delay) + if (args.Current is not UseDelayComponentState state) return; - ent.Comp.Delay = delay; + ent.Comp.Delays.Clear(); + + // At time of writing sourcegen networking doesn't deep copy so this will mispredict if you try. + foreach (var (key, delay) in state.Delays) + { + ent.Comp.Delays[key] = new UseDelayInfo(delay.Length, delay.StartTime, delay.EndTime); + } + } + + private void OnDelayGetState(Entity ent, ref ComponentGetState args) + { + args.State = new UseDelayComponentState() + { + Delays = ent.Comp.Delays + }; + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + // Set default delay length from the prototype + // This makes it easier for simple use cases that only need a single delay + SetLength((ent, ent.Comp), ent.Comp.Delay, DefaultId); + } + + private void OnUnpaused(Entity ent, ref EntityUnpausedEvent args) + { + // We have to do this manually, since it's not just a single field. + foreach (var entry in ent.Comp.Delays.Values) + { + entry.EndTime += args.PausedTime; + } + } + + /// + /// Sets the length of the delay with the specified ID. + /// + /// + /// This will add a UseDelay component to the entity if it doesn't have one. + /// + public bool SetLength(Entity ent, TimeSpan length, string id = DefaultId) + { + EnsureComp(ent.Owner, out var comp); + + if (comp.Delays.TryGetValue(id, out var entry)) + { + if (entry.Length == length) + return true; + + entry.Length = length; + } + else + { + comp.Delays.Add(id, new UseDelayInfo(length)); + } + Dirty(ent); + return true; } /// - /// Returns true if the entity has a currently active UseDelay. + /// Returns true if the entity has a currently active UseDelay with the specified ID. /// - public bool IsDelayed(Entity ent) + public bool IsDelayed(Entity ent, string id = DefaultId) { - return ent.Comp.DelayEndTime >= _gameTiming.CurTime; + if (!ent.Comp.Delays.TryGetValue(id, out var entry)) + return false; + + return entry.EndTime >= _gameTiming.CurTime; } /// - /// Cancels the current delay. + /// Cancels the delay with the specified ID. /// - public void CancelDelay(Entity ent) + public void CancelDelay(Entity ent, string id = DefaultId) { - ent.Comp.DelayEndTime = _gameTiming.CurTime; + if (!ent.Comp.Delays.TryGetValue(id, out var entry)) + return; + + entry.EndTime = _gameTiming.CurTime; Dirty(ent); } /// - /// Resets the UseDelay entirely for this entity if possible. + /// Tries to get info about the delay with the specified ID. See . + /// + /// + /// + /// + /// + public bool TryGetDelayInfo(Entity ent, [NotNullWhen(true)] out UseDelayInfo? info, string id = DefaultId) + { + return ent.Comp.Delays.TryGetValue(id, out info); + } + + /// + /// Returns info for the delay that will end farthest in the future. /// - /// Check if the entity has an ongoing delay, return false if it does, return true if it does not. - public bool TryResetDelay(Entity ent, bool checkDelayed = false) + public UseDelayInfo GetLastEndingDelay(Entity ent) { - if (checkDelayed && IsDelayed(ent)) + var last = ent.Comp.Delays[DefaultId]; + foreach (var entry in ent.Comp.Delays) + { + if (entry.Value.EndTime > last.EndTime) + last = entry.Value; + } + return last; + } + + /// + /// Resets the delay with the specified ID for this entity if possible. + /// + /// Check if the entity has an ongoing delay with the specified ID. + /// If it does, return false and don't reset it. + /// Otherwise reset it and return true. + public bool TryResetDelay(Entity ent, bool checkDelayed = false, string id = DefaultId) + { + if (checkDelayed && IsDelayed(ent, id)) + return false; + + if (!ent.Comp.Delays.TryGetValue(id, out var entry)) return false; var curTime = _gameTiming.CurTime; - ent.Comp.DelayStartTime = curTime; - ent.Comp.DelayEndTime = curTime - _metadata.GetPauseTime(ent) + ent.Comp.Delay; + entry.StartTime = curTime; + entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length; Dirty(ent); return true; } - public bool TryResetDelay(EntityUid uid, bool checkDelayed = false, UseDelayComponent? component = null) + public bool TryResetDelay(EntityUid uid, bool checkDelayed = false, UseDelayComponent? component = null, string id = DefaultId) { if (!Resolve(uid, ref component, false)) return false; - return TryResetDelay((uid, component), checkDelayed); + return TryResetDelay((uid, component), checkDelayed, id); + } + + /// + /// Resets all delays on the entity. + /// + public void ResetAllDelays(Entity ent) + { + var curTime = _gameTiming.CurTime; + foreach (var entry in ent.Comp.Delays.Values) + { + entry.StartTime = curTime; + entry.EndTime = curTime - _metadata.GetPauseTime(ent) + entry.Length; + } + Dirty(ent); } } diff --git a/Content.Shared/Tips/TippyEvent.cs b/Content.Shared/Tips/TippyEvent.cs new file mode 100644 index 00000000000..4370e9c8227 --- /dev/null +++ b/Content.Shared/Tips/TippyEvent.cs @@ -0,0 +1,19 @@ + +using Robust.Shared.Serialization; + +namespace Content.Shared.Tips; + +[Serializable, NetSerializable] +public sealed class TippyEvent : EntityEventArgs +{ + public TippyEvent(string msg) + { + Msg = msg; + } + + public string Msg; + public string? Proto; + public float SpeakTime = 5; + public float SlideTime = 3; + public float WaddleInterval = 0.5f; +} diff --git a/Content.Shared/Tools/Components/SharedWeldable.cs b/Content.Shared/Tools/Components/SharedWeldable.cs deleted file mode 100644 index 701bd4d8da5..00000000000 --- a/Content.Shared/Tools/Components/SharedWeldable.cs +++ /dev/null @@ -1,49 +0,0 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; - -namespace Content.Shared.Tools.Components; - -[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] -public sealed partial class WeldableComponent : Component -{ - /// - /// Tool quality for welding. - /// - [DataField("weldingQuality", customTypeSerializer: typeof(PrototypeIdSerializer))] - [ViewVariables(VVAccess.ReadWrite)] - public string WeldingQuality = "Welding"; - - /// - /// How much time does it take to weld/unweld entity. - /// - [DataField("time")] - [ViewVariables(VVAccess.ReadWrite)] - [AutoNetworkedField] - public TimeSpan WeldingTime = TimeSpan.FromSeconds(1f); - - /// - /// Shown when welded entity is examined. - /// - [DataField("weldedExamineMessage")] - [ViewVariables(VVAccess.ReadWrite)] - public string? WeldedExamineMessage = "weldable-component-examine-is-welded"; - - /// - /// Is this entity currently welded shut? - /// - [DataField("isWelded"), AutoNetworkedField] - public bool IsWelded; -} - -[Serializable, NetSerializable] -public enum WeldableVisuals : byte -{ - IsWelded -} - -[Serializable, NetSerializable] -public enum WeldableLayers : byte -{ - BaseWelded -} diff --git a/Content.Shared/Tools/Components/SharedWelderComponent.cs b/Content.Shared/Tools/Components/SharedWelderComponent.cs deleted file mode 100644 index 78c1cde201b..00000000000 --- a/Content.Shared/Tools/Components/SharedWelderComponent.cs +++ /dev/null @@ -1,21 +0,0 @@ -using Robust.Shared.GameStates; -using Robust.Shared.Serialization; - -namespace Content.Shared.Tools.Components -{ - [NetworkedComponent] - public abstract partial class SharedWelderComponent : Component { } - - [NetSerializable, Serializable] - public sealed class WelderComponentState : ComponentState - { - public float FuelCapacity { get; } - public float Fuel { get; } - - public WelderComponentState(float fuelCapacity, float fuel) - { - FuelCapacity = fuelCapacity; - Fuel = fuel; - } - } -} diff --git a/Content.Shared/Tools/Components/WeldableComponent.cs b/Content.Shared/Tools/Components/WeldableComponent.cs new file mode 100644 index 00000000000..e491b5f6a73 --- /dev/null +++ b/Content.Shared/Tools/Components/WeldableComponent.cs @@ -0,0 +1,51 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared.Tools.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class WeldableComponent : Component +{ + /// + /// Tool quality for welding. + /// + [DataField] + public ProtoId WeldingQuality = "Welding"; + + /// + /// How much time does it take to weld/unweld entity. + /// + [DataField, AutoNetworkedField] + public TimeSpan Time = TimeSpan.FromSeconds(1f); + + /// + /// How much fuel does it take to weld/unweld entity. + /// + [DataField] + public float Fuel = 3f; + + /// + /// Shown when welded entity is examined. + /// + [DataField] + public LocId? WeldedExamineMessage = "weldable-component-examine-is-welded"; + + /// + /// Is this entity currently welded shut? + /// + [DataField, AutoNetworkedField] + public bool IsWelded; +} + +[Serializable, NetSerializable] +public enum WeldableVisuals : byte +{ + IsWelded +} + +[Serializable, NetSerializable] +public enum WeldableLayers : byte +{ + BaseWelded +} diff --git a/Content.Shared/Tools/Components/WelderComponent.cs b/Content.Shared/Tools/Components/WelderComponent.cs new file mode 100644 index 00000000000..3c78a03fdeb --- /dev/null +++ b/Content.Shared/Tools/Components/WelderComponent.cs @@ -0,0 +1,58 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; +using Content.Shared.FixedPoint; +using Content.Shared.Tools.Systems; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Tools.Components; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true), Access(typeof(SharedToolSystem))] +public sealed partial class WelderComponent : Component +{ + [DataField, AutoNetworkedField] + public bool Enabled; + + [DataField] + public float WelderTimer; + + /// + /// Name of . + /// + [DataField] + public string FuelSolutionName = "Welder"; + + /// + /// Reagent that will be used as fuel for welding. + /// + [DataField] + public ProtoId FuelReagent = "WeldingFuel"; + + /// + /// Fuel consumption per second while the welder is active. + /// + [DataField, AutoNetworkedField] + public FixedPoint2 FuelConsumption = FixedPoint2.New(1.0f); + + /// + /// A fuel amount to be consumed when the welder goes from being unlit to being lit. + /// + [DataField, AutoNetworkedField] + public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f); + + /// + /// Sound played when refilling the welder. + /// + [DataField] + public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg"); + + /// + /// Whether the item is safe to refill while lit without exploding the tank. + /// + [DataField] + public bool TankSafe; + + [DataField] + public float WelderUpdateTimer = 1f; +} diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs b/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs new file mode 100644 index 00000000000..e790b59cd12 --- /dev/null +++ b/Content.Shared/Tools/Systems/SharedToolSystem.Welder.cs @@ -0,0 +1,178 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Components.SolutionManager; +using Content.Shared.Database; +using Content.Shared.DoAfter; +using Content.Shared.Examine; +using Content.Shared.FixedPoint; +using Content.Shared.Interaction; +using Content.Shared.Item.ItemToggle.Components; +using Content.Shared.Tools.Components; + +namespace Content.Shared.Tools.Systems; + +public abstract partial class SharedToolSystem +{ + public void InitializeWelder() + { + SubscribeLocalEvent(OnWelderExamine); + SubscribeLocalEvent(OnWelderAfterInteract); + SubscribeLocalEvent>(OnWelderToolUseAttempt); + SubscribeLocalEvent(OnWelderDoAfter); + SubscribeLocalEvent(OnToggle); + SubscribeLocalEvent(OnActivateAttempt); + } + + public virtual void TurnOn(Entity entity, EntityUid? user) + { + if (!SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out var solutionComp, out _)) + return; + + SolutionContainerSystem.RemoveReagent(solutionComp.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost); + AdminLogger.Add(LogType.InteractActivate, LogImpact.Low, + $"{ToPrettyString(user):user} toggled {ToPrettyString(entity.Owner):welder} on"); + + entity.Comp.Enabled = true; + Dirty(entity, entity.Comp); + } + + public void TurnOff(Entity entity, EntityUid? user) + { + AdminLogger.Add(LogType.InteractActivate, LogImpact.Low, + $"{ToPrettyString(user):user} toggled {ToPrettyString(entity.Owner):welder} off"); + entity.Comp.Enabled = false; + Dirty(entity, entity.Comp); + } + + public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null) + { + if (!Resolve(uid, ref welder, ref solutionContainer)) + return default; + + if (!SolutionContainer.TryGetSolution( + (uid, solutionContainer), + welder.FuelSolutionName, + out _, + out var fuelSolution)) + { + return default; + } + + return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume); + } + + private void OnWelderExamine(Entity entity, ref ExaminedEvent args) + { + using (args.PushGroup(nameof(WelderComponent))) + { + if (ItemToggle.IsActivated(entity.Owner)) + { + args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message")); + } + else + { + args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-not-lit-message")); + } + + if (args.IsInDetailsRange) + { + var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp); + + args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message", + ("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"), + ("fuelLeft", fuel), + ("fuelCapacity", capacity), + ("status", string.Empty))); // Lit status is handled above + } + } + } + + private void OnWelderAfterInteract(Entity entity, ref AfterInteractEvent args) + { + if (args.Handled) + return; + + if (args.Target is not { Valid: true } target || !args.CanReach) + return; + + if (TryComp(target, out ReagentTankComponent? tank) + && tank.TankType == ReagentTankType.Fuel + && SolutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) + && SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out var solutionComp, out var welderSolution)) + { + var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume); + if (trans > 0) + { + var drained = SolutionContainerSystem.Drain(target, targetSoln.Value, trans); + SolutionContainerSystem.TryAddSolution(solutionComp.Value, drained); + _audioSystem.PlayPredicted(entity.Comp.WelderRefill, entity, user: args.User); + _popup.PopupClient(Loc.GetString("welder-component-after-interact-refueled-message"), entity, args.User); + } + else if (welderSolution.AvailableVolume <= 0) + { + _popup.PopupClient(Loc.GetString("welder-component-already-full"), entity, args.User); + } + else + { + _popup.PopupClient(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), entity, args.User); + } + + args.Handled = true; + } + } + + private void OnWelderToolUseAttempt(Entity entity, ref DoAfterAttemptEvent args) + { + var user = args.DoAfter.Args.User; + + if (!ItemToggle.IsActivated(entity.Owner)) + { + _popup.PopupClient(Loc.GetString("welder-component-welder-not-lit-message"), entity, user); + args.Cancel(); + return; + } + + var (fuel, _) = GetWelderFuelAndCapacity(entity); + + if (args.Event.Fuel > fuel) + { + _popup.PopupClient(Loc.GetString("welder-component-cannot-weld-message"), entity, user); + args.Cancel(); + } + } + + private void OnWelderDoAfter(Entity ent, ref ToolDoAfterEvent args) + { + if (args.Cancelled) + return; + + if (!SolutionContainerSystem.TryGetSolution(ent.Owner, ent.Comp.FuelSolutionName, out var solution)) + return; + + SolutionContainerSystem.RemoveReagent(solution.Value, ent.Comp.FuelReagent, FixedPoint2.New(args.Fuel)); + } + + private void OnToggle(Entity entity, ref ItemToggledEvent args) + { + if (args.Activated) + TurnOn(entity, args.User); + else + TurnOff(entity, args.User); + } + + private void OnActivateAttempt(Entity entity, ref ItemToggleActivateAttemptEvent args) + { + if (!SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out _, out var solution)) + { + args.Cancelled = true; + args.Popup = Loc.GetString("welder-component-no-fuel-message"); + return; + } + + var fuel = solution.GetTotalPrototypeQuantity(entity.Comp.FuelReagent); + if (fuel == FixedPoint2.Zero || fuel < entity.Comp.FuelLitCost) + { + args.Popup = Loc.GetString("welder-component-no-fuel-message"); + args.Cancelled = true; + } + } +} diff --git a/Content.Shared/Tools/Systems/SharedToolSystem.cs b/Content.Shared/Tools/Systems/SharedToolSystem.cs index ee15b1e025a..0d7972a8de6 100644 --- a/Content.Shared/Tools/Systems/SharedToolSystem.cs +++ b/Content.Shared/Tools/Systems/SharedToolSystem.cs @@ -1,8 +1,12 @@ using Content.Shared.Administration.Logs; +using Content.Shared.Chemistry.EntitySystems; using Content.Shared.DoAfter; using Content.Shared.Interaction; +using Content.Shared.Item.ItemToggle; using Content.Shared.Maps; +using Content.Shared.Popups; using Content.Shared.Tools.Components; +using JetBrains.Annotations; using Robust.Shared.Audio.Systems; using Robust.Shared.Map; using Robust.Shared.Prototypes; @@ -15,20 +19,25 @@ public abstract partial class SharedToolSystem : EntitySystem { [Dependency] private readonly IMapManager _mapManager = default!; [Dependency] private readonly IPrototypeManager _protoMan = default!; - [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!; + [Dependency] protected readonly ISharedAdminLogManager AdminLogger = default!; [Dependency] private readonly ITileDefinitionManager _tileDefManager = default!; [Dependency] private readonly SharedAudioSystem _audioSystem = default!; [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!; [Dependency] protected readonly SharedInteractionSystem InteractionSystem = default!; + [Dependency] protected readonly SharedItemToggleSystem ItemToggle = default!; [Dependency] private readonly SharedMapSystem _maps = default!; + [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainerSystem = default!; [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly TileSystem _tiles = default!; [Dependency] private readonly TurfSystem _turfs = default!; + [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!; public override void Initialize() { InitializeMultipleTool(); InitializeTile(); + InitializeWelder(); SubscribeLocalEvent(OnDoAfter); } @@ -66,6 +75,7 @@ public void PlayToolSound(EntityUid uid, ToolComponent tool, EntityUid? user) /// The qualities needed for this tool to work. /// The event that will be raised when the tool has finished (including cancellation). Event /// will be directed at the tool target. + /// Amount of fuel that should be taken from the tool. /// The tool component. /// Returns true if any interaction takes place. public bool UseTool( @@ -75,6 +85,7 @@ public bool UseTool( float doAfterDelay, IEnumerable toolQualitiesNeeded, DoAfterEvent doAfterEv, + float fuel = 0, ToolComponent? toolComponent = null) { return UseTool(tool, @@ -84,6 +95,7 @@ public bool UseTool( toolQualitiesNeeded, doAfterEv, out _, + fuel, toolComponent); } @@ -101,6 +113,7 @@ public bool UseTool( /// will be directed at the tool target. /// The id of the DoAfter that was created. This may be null even if the function returns true in /// the event that this tool-use cancelled an existing DoAfter + /// Amount of fuel that should be taken from the tool. /// The tool component. /// Returns true if any interaction takes place. public bool UseTool( @@ -111,31 +124,30 @@ public bool UseTool( IEnumerable toolQualitiesNeeded, DoAfterEvent doAfterEv, out DoAfterId? id, + float fuel = 0, ToolComponent? toolComponent = null) { id = null; if (!Resolve(tool, ref toolComponent, false)) return false; - if (!CanStartToolUse(tool, user, target, toolQualitiesNeeded, toolComponent)) + if (!CanStartToolUse(tool, user, target, fuel, toolQualitiesNeeded, toolComponent)) return false; - var toolEvent = new ToolDoAfterEvent(doAfterEv, GetNetEntity(target)); + var toolEvent = new ToolDoAfterEvent(fuel, doAfterEv, GetNetEntity(target)); var doAfterArgs = new DoAfterArgs(EntityManager, user, delay / toolComponent.SpeedModifier, toolEvent, tool, target: target, used: tool) { BreakOnDamage = true, BreakOnTargetMove = true, BreakOnUserMove = true, NeedHand = tool != user, - AttemptFrequency = IsWelder(tool) ? AttemptFrequency.EveryTick : AttemptFrequency.Never + AttemptFrequency = fuel > 0 ? AttemptFrequency.EveryTick : AttemptFrequency.Never }; _doAfterSystem.TryStartDoAfter(doAfterArgs, out id); return true; } - protected abstract bool IsWelder(EntityUid uid); - /// /// Attempts to use a tool on some entity, which will start a DoAfter. Returns true if an interaction occurred. /// Note that this does not mean the interaction was successful, you need to listen for the DoAfter event. @@ -148,6 +160,7 @@ public bool UseTool( /// The quality needed for this tool to work. /// The event that will be raised when the tool has finished (including cancellation). Event /// will be directed at the tool target. + /// Amount of fuel that should be taken from the tool. /// The tool component. /// Returns true if any interaction takes place. public bool UseTool( @@ -157,6 +170,7 @@ public bool UseTool( float doAfterDelay, string toolQualityNeeded, DoAfterEvent doAfterEv, + float fuel = 0, ToolComponent? toolComponent = null) { return UseTool(tool, @@ -166,6 +180,7 @@ public bool UseTool( new[] { toolQualityNeeded }, doAfterEv, out _, + fuel, toolComponent); } @@ -180,12 +195,13 @@ public bool HasQuality(EntityUid uid, string quality, ToolComponent? tool = null /// /// Whether a tool entity has all specified qualities or not. /// + [PublicAPI] public bool HasAllQualities(EntityUid uid, IEnumerable qualities, ToolComponent? tool = null) { return Resolve(uid, ref tool, false) && tool.Qualities.ContainsAll(qualities); } - private bool CanStartToolUse(EntityUid tool, EntityUid user, EntityUid? target, IEnumerable toolQualitiesNeeded, ToolComponent? toolComponent = null) + private bool CanStartToolUse(EntityUid tool, EntityUid user, EntityUid? target, float fuel, IEnumerable toolQualitiesNeeded, ToolComponent? toolComponent = null) { if (!Resolve(tool, ref toolComponent)) return false; @@ -220,6 +236,9 @@ private bool CanStartToolUse(EntityUid tool, EntityUid user, EntityUid? target, [Serializable, NetSerializable] protected sealed partial class ToolDoAfterEvent : DoAfterEvent { + [DataField] + public float Fuel; + /// /// Entity that the wrapped do after event will get directed at. If null, event will be broadcast. /// @@ -233,10 +252,11 @@ private ToolDoAfterEvent() { } - public ToolDoAfterEvent(DoAfterEvent wrappedEvent, NetEntity? originalTarget) + public ToolDoAfterEvent(float fuel, DoAfterEvent wrappedEvent, NetEntity? originalTarget) { DebugTools.Assert(wrappedEvent.GetType().HasCustomAttribute(), "Tool event is not serializable"); + Fuel = fuel; WrappedEvent = wrappedEvent; OriginalTarget = originalTarget; } @@ -249,14 +269,14 @@ public override DoAfterEvent Clone() if (evClone == WrappedEvent) return this; - return new ToolDoAfterEvent(evClone, OriginalTarget); + return new ToolDoAfterEvent(Fuel, evClone, OriginalTarget); } } [Serializable, NetSerializable] protected sealed partial class LatticeCuttingCompleteEvent : DoAfterEvent { - [DataField("coordinates", required:true)] + [DataField(required:true)] public NetCoordinates Coordinates; private LatticeCuttingCompleteEvent() @@ -273,9 +293,7 @@ public LatticeCuttingCompleteEvent(NetCoordinates coordinates) } [Serializable, NetSerializable] -public sealed partial class CableCuttingFinishedEvent : SimpleDoAfterEvent -{ -} +public sealed partial class CableCuttingFinishedEvent : SimpleDoAfterEvent; #endregion diff --git a/Content.Shared/Tools/Systems/WeldableSystem.cs b/Content.Shared/Tools/Systems/WeldableSystem.cs index b0ea68f713f..c6c47d539e0 100644 --- a/Content.Shared/Tools/Systems/WeldableSystem.cs +++ b/Content.Shared/Tools/Systems/WeldableSystem.cs @@ -69,7 +69,7 @@ private bool TryWeld(EntityUid uid, EntityUid tool, EntityUid user, WeldableComp if (!CanWeld(uid, tool, user, component)) return false; - if (!_toolSystem.UseTool(tool, user, uid, component.WeldingTime.Seconds, component.WeldingQuality, new WeldFinishedEvent())) + if (!_toolSystem.UseTool(tool, user, uid, component.Time.Seconds, component.WeldingQuality, new WeldFinishedEvent(), component.Fuel)) return false; // Log attempt @@ -140,10 +140,10 @@ public void SetWeldingTime(EntityUid uid, TimeSpan time, WeldableComponent? comp if (!_query.Resolve(uid, ref component)) return; - if (component.WeldingTime.Equals(time)) + if (component.Time.Equals(time)) return; - component.WeldingTime = time; + component.Time = time; Dirty(uid, component); } } diff --git a/Content.Shared/Traits/Assorted/Components/PermanentBlindnessComponent.cs b/Content.Shared/Traits/Assorted/Components/PermanentBlindnessComponent.cs index c1bf7e1639e..c10b05ae02e 100644 --- a/Content.Shared/Traits/Assorted/Components/PermanentBlindnessComponent.cs +++ b/Content.Shared/Traits/Assorted/Components/PermanentBlindnessComponent.cs @@ -8,5 +8,7 @@ namespace Content.Shared.Traits.Assorted.Components; [RegisterComponent, NetworkedComponent] public sealed partial class PermanentBlindnessComponent : Component { + [ViewVariables(VVAccess.ReadWrite), DataField] + public int Blindness = 0; // How damaged should their eyes be. Set 0 for maximum damage. } diff --git a/Content.Server/Traits/Assorted/SelfAwareComponent.cs b/Content.Shared/Traits/Assorted/Components/SelfAwareComponent.cs similarity index 91% rename from Content.Server/Traits/Assorted/SelfAwareComponent.cs rename to Content.Shared/Traits/Assorted/Components/SelfAwareComponent.cs index 03f5cd15502..fa2485ac488 100644 --- a/Content.Server/Traits/Assorted/SelfAwareComponent.cs +++ b/Content.Shared/Traits/Assorted/Components/SelfAwareComponent.cs @@ -1,13 +1,14 @@ using Content.Shared.Damage.Prototypes; using Content.Shared.FixedPoint; +using Robust.Shared.GameStates; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set; -namespace Content.Server.Traits.Assorted; +namespace Content.Shared.Traits.Assorted.Components; /// /// This is used for the Self-Aware trait to enhance the information received from HealthExaminableSystem. /// -[RegisterComponent] +[RegisterComponent, NetworkedComponent] public sealed partial class SelfAwareComponent : Component { // diff --git a/Content.Shared/Traits/Assorted/Prototypes/SingerInstrumentPrototype.cs b/Content.Shared/Traits/Assorted/Prototypes/SingerInstrumentPrototype.cs index 6a49854f6ea..e1fa696d79b 100644 --- a/Content.Shared/Traits/Assorted/Prototypes/SingerInstrumentPrototype.cs +++ b/Content.Shared/Traits/Assorted/Prototypes/SingerInstrumentPrototype.cs @@ -1,9 +1,10 @@ +using Content.Shared.Instruments; using Robust.Shared.Prototypes; namespace Content.Shared.Traits.Assorted.Prototypes; [Prototype("SingerInstrument")] -public sealed class SingerInstrumentPrototype : IPrototype +public sealed partial class SingerInstrumentPrototype : IPrototype { [IdDataField] public string ID { get; private set; } = default!; @@ -27,7 +28,7 @@ public sealed class SingerInstrumentPrototype : IPrototype /// The BUI configuration for the instrument. /// [DataField] - public PrototypeData? MidiUi; + public InstrumentUiKey? MidiUi; // The below is server only, as it uses a server-BUI event !type [DataField(serverOnly: true, required: true)] diff --git a/Content.Shared/Traits/Assorted/Systems/PermanentBlindnessSystem.cs b/Content.Shared/Traits/Assorted/Systems/PermanentBlindnessSystem.cs index 113939f66b7..21faf7d50bc 100644 --- a/Content.Shared/Traits/Assorted/Systems/PermanentBlindnessSystem.cs +++ b/Content.Shared/Traits/Assorted/Systems/PermanentBlindnessSystem.cs @@ -2,6 +2,7 @@ using Content.Shared.Eye.Blinding.Components; using Content.Shared.Eye.Blinding.Systems; using Content.Shared.IdentityManagement; +using Content.Shared.Traits.Assorted.Components; using Robust.Shared.Network; namespace Content.Shared.Traits.Assorted.Systems; @@ -18,15 +19,14 @@ public sealed class PermanentBlindnessSystem : EntitySystem /// public override void Initialize() { - SubscribeLocalEvent(OnStartup); - SubscribeLocalEvent(OnShutdown); - SubscribeLocalEvent(OnDamageChanged); - SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnExamined); } private void OnExamined(Entity blindness, ref ExaminedEvent args) { - if (args.IsInDetailsRange && !_net.IsClient) + if (args.IsInDetailsRange && !_net.IsClient && blindness.Comp.Blindness == 0) { args.PushMarkup(Loc.GetString("trait-examined-Blindness", ("target", Identity.Entity(blindness, EntityManager)))); } @@ -37,28 +37,17 @@ private void OnShutdown(Entity blindness _blinding.UpdateIsBlind(blindness.Owner); } - private void OnStartup(Entity blindness, ref ComponentStartup args) + private void OnMapInit(Entity blindness, ref MapInitEvent args) { if (!_entityManager.TryGetComponent(blindness, out var blindable)) return; - var damageToDeal = (int) BlurryVisionComponent.MaxMagnitude - blindable.EyeDamage; - - if (damageToDeal <= 0) - return; - - _blinding.AdjustEyeDamage(blindness.Owner, damageToDeal); - } - - private void OnDamageChanged(Entity blindness, ref EyeDamageChangedEvent args) - { - if (args.Damage >= BlurryVisionComponent.MaxMagnitude) - return; - - if (!_entityManager.TryGetComponent(blindness, out var blindable)) - return; - - var damageRestoration = (int) BlurryVisionComponent.MaxMagnitude - args.Damage; - _blinding.AdjustEyeDamage(blindness.Owner, damageRestoration); + if (blindness.Comp.Blindness != 0) + _blinding.SetMinDamage(new Entity(blindness.Owner, blindable), blindness.Comp.Blindness); + else + { + var maxMagnitudeInt = (int) BlurryVisionComponent.MaxMagnitude; + _blinding.SetMinDamage(new Entity(blindness.Owner, blindable), maxMagnitudeInt); + } } } diff --git a/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs b/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs index 08d0f5c76d0..f772075dfb5 100644 --- a/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs +++ b/Content.Shared/Traits/Assorted/Systems/SharedSingerSystem.cs @@ -40,8 +40,10 @@ private void OnStartup(Entity ent, ref ComponentStartup args) _instrument.SetInstrumentProgram(instrumentComp, defaultData.Item1, defaultData.Item2); SetUpSwappableInstrument(ent, singer); - if (singer.MidiUi is {} uiData && !_ui.TryGetUi(ent, uiData.UiKey, out _)) - _ui.AddUi(ent.Owner, uiData); + EntityManager.TryGetComponent(ent.Owner, out var comp); + var entui = new Entity(ent.Owner, comp); + if (singer.MidiUi is { } uiKey && !_ui.IsUiOpen(entui, uiKey)) + _ui.OpenUi(entui, uiKey, entui); } private void OnShutdown(Entity ent, ref ComponentShutdown args) diff --git a/Content.Shared/UserInterface/ActivatableUIComponent.cs b/Content.Shared/UserInterface/ActivatableUIComponent.cs new file mode 100644 index 00000000000..3f83816b7de --- /dev/null +++ b/Content.Shared/UserInterface/ActivatableUIComponent.cs @@ -0,0 +1,77 @@ +using Content.Shared.Whitelist; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization.TypeSerializers.Implementations; + +namespace Content.Shared.UserInterface +{ + [RegisterComponent, NetworkedComponent, AutoGenerateComponentState] + public sealed partial class ActivatableUIComponent : Component + { + [DataField(required: true, customTypeSerializer: typeof(EnumSerializer))] + public Enum? Key; + + /// + /// Whether the item must be held in one of the user's hands to work. + /// This is ignored unless is true. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool InHandsOnly; + + [DataField] + public bool SingleUser; + + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool AdminOnly; + + [DataField] + public LocId VerbText = "ui-verb-toggle-open"; + + /// + /// Whether you need a hand to operate this UI. The hand does not need to be free, you just need to have one. + /// + /// + /// This should probably be true for most machines & computers, but there will still be UIs that represent a + /// more generic interaction / configuration that might not require hands. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool RequireHands = true; + + /// + /// Entities that are required to open this UI. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public EntityWhitelist? RequiredItems; + + /// + /// If true, then this UI can only be opened via verbs. I.e., normal interactions/activations will not open + /// the UI. + /// + [DataField, ViewVariables(VVAccess.ReadWrite)] + public bool VerbOnly; + + /// + /// Whether spectators (non-admin ghosts) should be allowed to view this UI. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool AllowSpectator = true; + + /// + /// Whether the item must be in the user's currently selected/active hand. + /// This is ignored unless is true. + /// + [ViewVariables(VVAccess.ReadWrite)] + [DataField] + public bool RequireActiveHand = true; + + /// + /// The client channel currently using the object, or null if there's none/not single user. + /// NOTE: DO NOT DIRECTLY SET, USE ActivatableUISystem.SetCurrentSingleUser + /// + [DataField, AutoNetworkedField] + public EntityUid? CurrentSingleUser; + } +} diff --git a/Content.Shared/UserInterface/ActivatableUIEvents.cs b/Content.Shared/UserInterface/ActivatableUIEvents.cs index 6e6b3f63c62..338673a3ca6 100644 --- a/Content.Shared/UserInterface/ActivatableUIEvents.cs +++ b/Content.Shared/UserInterface/ActivatableUIEvents.cs @@ -24,12 +24,12 @@ public UserOpenActivatableUIAttemptEvent(EntityUid who, EntityUid target) public sealed class AfterActivatableUIOpenEvent : EntityEventArgs { public EntityUid User { get; } - public readonly ICommonSession Session; + public readonly EntityUid Actor; - public AfterActivatableUIOpenEvent(EntityUid who, ICommonSession session) + public AfterActivatableUIOpenEvent(EntityUid who, EntityUid actor) { User = who; - Session = session; + Actor = actor; } } diff --git a/Content.Shared/UserInterface/ActivatableUIRequiresPowerCellComponent.cs b/Content.Shared/UserInterface/ActivatableUIRequiresPowerCellComponent.cs new file mode 100644 index 00000000000..aa9e561e076 --- /dev/null +++ b/Content.Shared/UserInterface/ActivatableUIRequiresPowerCellComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared.PowerCell; +using Robust.Shared.GameStates; + +namespace Content.Shared.UserInterface; + +/// +/// Specifies that the attached entity requires power. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ActivatableUIRequiresPowerCellComponent : Component +{ + +} diff --git a/Content.Shared/UserInterface/ActivatableUISystem.Power.cs b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs new file mode 100644 index 00000000000..b8a815c7a81 --- /dev/null +++ b/Content.Shared/UserInterface/ActivatableUISystem.Power.cs @@ -0,0 +1,93 @@ +using Content.Shared.PowerCell; +using Robust.Shared.Containers; + +namespace Content.Shared.UserInterface; + +public sealed partial class ActivatableUISystem +{ + [Dependency] private readonly SharedPowerCellSystem _cell = default!; + + private void InitializePower() + { + SubscribeLocalEvent(OnBatteryOpenAttempt); + SubscribeLocalEvent(OnBatteryOpened); + SubscribeLocalEvent(OnBatteryClosed); + + SubscribeLocalEvent(OnPowerCellRemoved); + } + + private void OnPowerCellRemoved(EntityUid uid, PowerCellDrawComponent component, EntRemovedFromContainerMessage args) + { + _cell.SetPowerCellDrawEnabled(uid, false); + + if (!HasComp(uid) || + !TryComp(uid, out ActivatableUIComponent? activatable)) + { + return; + } + + if (activatable.Key == null) + { + Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(uid)}"); + return; + } + + _uiSystem.CloseUi(uid, activatable.Key); + } + + private void OnBatteryOpened(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIOpenedEvent args) + { + var activatable = Comp(uid); + + if (!args.UiKey.Equals(activatable.Key)) + return; + + _cell.SetPowerCellDrawEnabled(uid, true); + } + + private void OnBatteryClosed(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, BoundUIClosedEvent args) + { + var activatable = Comp(uid); + + if (!args.UiKey.Equals(activatable.Key)) + return; + + // Stop drawing power if this was the last person with the UI open. + if (!_uiSystem.IsUiOpen(uid, activatable.Key)) + _cell.SetPowerCellDrawEnabled(uid, false); + } + + /// + /// Call if you want to check if the UI should close due to a recent battery usage. + /// + public void CheckUsage(EntityUid uid, ActivatableUIComponent? active = null, ActivatableUIRequiresPowerCellComponent? component = null, PowerCellDrawComponent? draw = null) + { + if (!Resolve(uid, ref component, ref draw, ref active, false)) + return; + + if (active.Key == null) + { + Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(uid)}"); + return; + } + + if (_cell.HasActivatableCharge(uid)) + return; + + _uiSystem.CloseUi(uid, active.Key); + } + + private void OnBatteryOpenAttempt(EntityUid uid, ActivatableUIRequiresPowerCellComponent component, ActivatableUIOpenAttemptEvent args) + { + if (!TryComp(uid, out var draw)) + return; + + // Check if we have the appropriate drawrate / userate to even open it. + if (args.Cancelled || + !_cell.HasActivatableCharge(uid, draw, user: args.User) || + !_cell.HasDrawCharge(uid, draw, user: args.User)) + { + args.Cancel(); + } + } +} diff --git a/Content.Shared/UserInterface/ActivatableUISystem.cs b/Content.Shared/UserInterface/ActivatableUISystem.cs new file mode 100644 index 00000000000..3ac8835dd02 --- /dev/null +++ b/Content.Shared/UserInterface/ActivatableUISystem.cs @@ -0,0 +1,332 @@ +using Content.Shared.ActionBlocker; +using Content.Shared.Administration.Managers; +using Content.Shared.Ghost; +using Content.Shared.Hands; +using Content.Shared.Hands.Components; +using Content.Shared.Hands.EntitySystems; +using Content.Shared.Interaction; +using Content.Shared.Interaction.Events; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Containers; + +namespace Content.Shared.UserInterface; + +public sealed partial class ActivatableUISystem : EntitySystem +{ + [Dependency] private readonly ISharedAdminManager _adminManager = default!; + [Dependency] private readonly ActionBlockerSystem _blockerSystem = default!; + [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!; + [Dependency] private readonly SharedPopupSystem _popupSystem = default!; + [Dependency] private readonly SharedHandsSystem _hands = default!; + [Dependency] private readonly SharedContainerSystem _container = default!; + [Dependency] private readonly SharedInteractionSystem _interaction = default!; + + private readonly List _toClose = new(); + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnUseInHand); + SubscribeLocalEvent(OnActivate); + SubscribeLocalEvent(OnInteractUsing); + SubscribeLocalEvent(OnHandDeselected); + SubscribeLocalEvent(OnHandUnequipped); + SubscribeLocalEvent(OnUIClose); + SubscribeLocalEvent>(GetActivationVerb); + SubscribeLocalEvent>(GetVerb); + + // TODO ActivatableUI + // Add UI-user component, and listen for user container changes. + // I.e., should lose a computer UI if a player gets shut into a locker. + SubscribeLocalEvent(OnGotInserted); + SubscribeLocalEvent(OnGotRemoved); + + SubscribeLocalEvent(OnBoundInterfaceInteractAttempt); + SubscribeLocalEvent(OnActionPerform); + + InitializePower(); + } + + private void OnBoundInterfaceInteractAttempt(BoundUserInterfaceMessageAttempt ev) + { + if (!TryComp(ev.Target, out ActivatableUIComponent? comp)) + return; + + if (!comp.RequireHands) + return; + + if (!TryComp(ev.Actor, out HandsComponent? hands) || hands.Hands.Count == 0) + ev.Cancel(); + } + + private void OnActionPerform(EntityUid uid, UserInterfaceComponent component, OpenUiActionEvent args) + { + if (args.Handled || args.Key == null) + return; + + args.Handled = _uiSystem.TryToggleUi(uid, args.Key, args.Performer); + } + + + private void GetActivationVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent args) + { + if (component.VerbOnly || !ShouldAddVerb(uid, component, args)) + return; + + args.Verbs.Add(new ActivationVerb + { + // TODO VERBS add "open UI" icon + Act = () => InteractUI(args.User, uid, component), + Text = Loc.GetString(component.VerbText) + }); + } + + private void GetVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent args) + { + if (!component.VerbOnly || !ShouldAddVerb(uid, component, args)) + return; + + args.Verbs.Add(new Verb + { + // TODO VERBS add "open UI" icon + Act = () => InteractUI(args.User, uid, component), + Text = Loc.GetString(component.VerbText) + }); + } + + private bool ShouldAddVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent args) where T : Verb + { + if (!args.CanAccess) + return false; + + if (!component.RequiredItems?.IsValid(args.Using ?? default, EntityManager) ?? false) + return false; + + if (component.RequireHands) + { + if (args.Hands == null) + return false; + + if (component.InHandsOnly) + { + if (!_hands.IsHolding(args.User, uid, out var hand, args.Hands)) + return false; + + if (component.RequireActiveHand && args.Hands.ActiveHand != hand) + return false; + } + } + + return args.CanInteract || component.AllowSpectator && HasComp(args.User); + } + + private void OnUseInHand(EntityUid uid, ActivatableUIComponent component, UseInHandEvent args) + { + if (args.Handled) + return; + + if (component.VerbOnly) + return; + + if (component.RequiredItems != null) + return; + + args.Handled = InteractUI(args.User, uid, component); + } + + private void OnActivate(EntityUid uid, ActivatableUIComponent component, ActivateInWorldEvent args) + { + if (args.Handled) + return; + + if (component.VerbOnly) + return; + + if (component.RequiredItems != null) + return; + + args.Handled = InteractUI(args.User, uid, component); + } + + private void OnInteractUsing(EntityUid uid, ActivatableUIComponent component, InteractUsingEvent args) + { + if (args.Handled) + return; + + if (component.VerbOnly) + return; + + if (component.RequiredItems == null) + return; + + if (!component.RequiredItems.IsValid(args.Used, EntityManager)) + return; + + args.Handled = InteractUI(args.User, uid, component); + } + + private void OnUIClose(EntityUid uid, ActivatableUIComponent component, BoundUIClosedEvent args) + { + var user = args.Actor; + + if (user != component.CurrentSingleUser) + return; + + if (!Equals(args.UiKey, component.Key)) + return; + + SetCurrentSingleUser(uid, null, component); + } + + private bool InteractUI(EntityUid user, EntityUid uiEntity, ActivatableUIComponent aui) + { + if (aui.Key == null || !_uiSystem.HasUi(uiEntity, aui.Key)) + return false; + + if (_uiSystem.IsUiOpen(uiEntity, aui.Key, user)) + { + _uiSystem.CloseUi(uiEntity, aui.Key, user); + return true; + } + + if (!_blockerSystem.CanInteract(user, uiEntity) && (!aui.AllowSpectator || !HasComp(user))) + return false; + + if (aui.RequireHands) + { + if (!TryComp(user, out HandsComponent? hands)) + return false; + + if (aui.InHandsOnly) + { + if (!_hands.IsHolding(user, uiEntity, out var hand, hands)) + return false; + + if (aui.RequireActiveHand && hands.ActiveHand != hand) + return false; + } + } + + if (aui.AdminOnly && !_adminManager.IsAdmin(user)) + return false; + + if (aui.SingleUser && aui.CurrentSingleUser != null && user != aui.CurrentSingleUser) + { + var message = Loc.GetString("machine-already-in-use", ("machine", uiEntity)); + _popupSystem.PopupEntity(message, uiEntity, user); + + if (_uiSystem.IsUiOpen(uiEntity, aui.Key)) + return true; + + Log.Error($"Activatable UI has user without being opened? Entity: {ToPrettyString(uiEntity)}. User: {aui.CurrentSingleUser}, Key: {aui.Key}"); + } + + // If we've gotten this far, fire a cancellable event that indicates someone is about to activate this. + // This is so that stuff can require further conditions (like power). + var oae = new ActivatableUIOpenAttemptEvent(user); + var uae = new UserOpenActivatableUIAttemptEvent(user, uiEntity); + RaiseLocalEvent(user, uae); + RaiseLocalEvent(uiEntity, oae); + if (oae.Cancelled || uae.Cancelled) + return false; + + // Give the UI an opportunity to prepare itself if it needs to do anything + // before opening + var bae = new BeforeActivatableUIOpenEvent(user); + RaiseLocalEvent(uiEntity, bae); + + SetCurrentSingleUser(uiEntity, user, aui); + _uiSystem.OpenUi(uiEntity, aui.Key, user); + + //Let the component know a user opened it so it can do whatever it needs to do + var aae = new AfterActivatableUIOpenEvent(user, user); + RaiseLocalEvent(uiEntity, aae); + + return true; + } + + public void SetCurrentSingleUser(EntityUid uid, EntityUid? user, ActivatableUIComponent? aui = null) + { + if (!Resolve(uid, ref aui)) + return; + + if (!aui.SingleUser) + return; + + aui.CurrentSingleUser = user; + Dirty(uid, aui); + + RaiseLocalEvent(uid, new ActivatableUIPlayerChangedEvent()); + } + + public void CloseAll(EntityUid uid, ActivatableUIComponent? aui = null) + { + if (!Resolve(uid, ref aui, false)) + return; + + if (aui.Key == null) + { + Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(uid)}"); + return; + } + + _uiSystem.CloseUi(uid, aui.Key); + } + + private void OnHandDeselected(Entity ent, ref HandDeselectedEvent args) + { + if (ent.Comp.RequireHands && ent.Comp.InHandsOnly && ent.Comp.RequireActiveHand) + CloseAll(ent, ent); + } + + private void OnHandUnequipped(Entity ent, ref GotUnequippedHandEvent args) + { + if (ent.Comp.RequireHands && ent.Comp.InHandsOnly) + CloseAll(ent, ent); + } + + private void OnGotInserted(Entity ent, ref EntGotInsertedIntoContainerMessage args) + { + CheckAccess((ent, ent)); + } + + private void OnGotRemoved(Entity ent, ref EntGotRemovedFromContainerMessage args) + { + CheckAccess((ent, ent)); + } + + public void CheckAccess(Entity ent) + { + if (!Resolve(ent, ref ent.Comp)) + return; + + if (ent.Comp.Key == null) + { + Log.Error($"Encountered null key in activatable ui on entity {ToPrettyString(ent)}"); + return; + } + + foreach (var user in _uiSystem.GetActors(ent.Owner, ent.Comp.Key)) + { + if (!_container.IsInSameOrParentContainer(user, ent) + && !_interaction.CanAccessViaStorage(user, ent)) + { + _toClose.Add(user); + continue; + + } + + if (!_interaction.InRangeUnobstructed(user, ent)) + _toClose.Add(user); + } + + foreach (var user in _toClose) + { + _uiSystem.CloseUi(ent.Owner, ent.Comp.Key, user); + } + + _toClose.Clear(); + } +} diff --git a/Content.Shared/Verbs/SharedVerbSystem.cs b/Content.Shared/Verbs/SharedVerbSystem.cs index 9dda910f3ff..60714aea8f3 100644 --- a/Content.Shared/Verbs/SharedVerbSystem.cs +++ b/Content.Shared/Verbs/SharedVerbSystem.cs @@ -55,13 +55,21 @@ public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, Type type return GetLocalVerbs(target, user, new List() { type }, force); } + /// + public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List types, bool force = false) + { + return GetLocalVerbs(target, user, types, out _, force); + } + /// /// Raises a number of events in order to get all verbs of the given type(s) defined in local systems. This /// does not request verbs from the server. /// - public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List types, bool force = false) + public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List types, + out List extraCategories, bool force = false) { SortedSet verbs = new(); + extraCategories = new(); // accessibility checks bool canAccess = false; @@ -108,7 +116,7 @@ public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(target, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } @@ -117,35 +125,35 @@ public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(@using.Value, verbEvent, true); // directed at used, not at target verbs.UnionWith(verbEvent.Verbs); } if (types.Contains(typeof(InnateVerb))) { - var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(user, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } if (types.Contains(typeof(AlternativeVerb))) { - var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(target, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } if (types.Contains(typeof(ActivationVerb))) { - var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(target, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } if (types.Contains(typeof(ExamineVerb))) { - var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(target, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } @@ -153,7 +161,7 @@ public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List(user, target, @using, hands, canInteract, canAccess); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, canAccess, extraCategories); RaiseLocalEvent(target, verbEvent, true); verbs.UnionWith(verbEvent.Verbs); } @@ -161,7 +169,7 @@ public SortedSet GetLocalVerbs(EntityUid target, EntityUid user, List(user, target, @using, hands, canInteract, access); + var verbEvent = new GetVerbsEvent(user, target, @using, hands, canInteract, access, extraCategories); RaiseLocalEvent(target, verbEvent); verbs.UnionWith(verbEvent.Verbs); } diff --git a/Content.Shared/Verbs/VerbCategory.cs b/Content.Shared/Verbs/VerbCategory.cs index 748570b0251..3331cad30b0 100644 --- a/Content.Shared/Verbs/VerbCategory.cs +++ b/Content.Shared/Verbs/VerbCategory.cs @@ -84,6 +84,8 @@ public VerbCategory(string text, string? icon, bool iconsOnly = false) public static readonly VerbCategory SelectType = new("verb-categories-select-type", null); + public static readonly VerbCategory PowerLevel = new("verb-categories-power-level", null); + public static readonly VerbCategory Interaction = new("verb-categories-interaction", null); } } diff --git a/Content.Shared/Verbs/VerbEvents.cs b/Content.Shared/Verbs/VerbEvents.cs index 9a09d5d7a1a..6b3fd327c99 100644 --- a/Content.Shared/Verbs/VerbEvents.cs +++ b/Content.Shared/Verbs/VerbEvents.cs @@ -77,6 +77,13 @@ public sealed class GetVerbsEvent : EntityEventArgs where TVerb : Verb /// public readonly SortedSet Verbs = new(); + /// + /// Additional verb categories to show in the pop-up menu, even if there are no verbs currently associated + /// with that category. This is mainly useful to prevent verb menu pop-in. E.g., admins will get admin/debug + /// related verbs on entities, even though most of those verbs are all defined server-side. + /// + public readonly List ExtraCategories; + /// /// Can the user physically access the target? /// @@ -123,7 +130,7 @@ public sealed class GetVerbsEvent : EntityEventArgs where TVerb : Verb /// public readonly EntityUid? Using; - public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canAccess) + public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsComponent? hands, bool canInteract, bool canAccess, List extraCategories) { User = user; Target = target; @@ -131,6 +138,7 @@ public GetVerbsEvent(EntityUid user, EntityUid target, EntityUid? @using, HandsC Hands = hands; CanAccess = canAccess; CanInteract = canInteract; + ExtraCategories = extraCategories; } } } diff --git a/Content.Shared/Wagging/WaggingComponent.cs b/Content.Shared/Wagging/WaggingComponent.cs index 76881827dd2..70e7f009c7d 100644 --- a/Content.Shared/Wagging/WaggingComponent.cs +++ b/Content.Shared/Wagging/WaggingComponent.cs @@ -17,9 +17,6 @@ public sealed partial class WaggingComponent : Component [DataField] public EntityUid? ActionEntity; - [DataField] - public ProtoId EmoteId = "WagTail"; - /// /// Suffix to add to get the animated marking. /// diff --git a/Content.Shared/Weapons/Melee/MeleeSoundSystem.cs b/Content.Shared/Weapons/Melee/MeleeSoundSystem.cs index 350642105a5..315d752a2c0 100644 --- a/Content.Shared/Weapons/Melee/MeleeSoundSystem.cs +++ b/Content.Shared/Weapons/Melee/MeleeSoundSystem.cs @@ -1,4 +1,5 @@ using Content.Shared.Weapons.Melee.Components; +using Content.Shared.Weapons.Melee.Events; using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; diff --git a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs index f86bfc32ed3..694273e5bf3 100644 --- a/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs +++ b/Content.Shared/Weapons/Melee/MeleeWeaponComponent.cs @@ -171,6 +171,14 @@ public sealed partial class MeleeWeaponComponent : Component DoHealthInteraction = true, HealthRangeModifier = 1.5f, }; + + /// + /// If true, the weapon must be equipped for it to be used. + /// E.g boxing gloves must be equipped to your gloves, + /// not just held in your hand to be used. + /// + [DataField, AutoNetworkedField] + public bool MustBeEquippedToUse = false; } /// diff --git a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs index fd77ad31a45..b83908c6df7 100644 --- a/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs +++ b/Content.Shared/Weapons/Melee/SharedMeleeWeaponSystem.cs @@ -169,49 +169,39 @@ private void OnStopAttack(StopAttackEvent msg, EntitySessionEventArgs args) private void OnLightAttack(LightAttackEvent msg, EntitySessionEventArgs args) { - var user = args.SenderSession.AttachedEntity; - - if (user == null) + if (args.SenderSession.AttachedEntity is not {} user) return; - if (!TryGetWeapon(user.Value, out var weaponUid, out var weapon) || + if (!TryGetWeapon(user, out var weaponUid, out var weapon) || weaponUid != GetEntity(msg.Weapon)) { return; } - AttemptAttack(args.SenderSession.AttachedEntity!.Value, weaponUid, weapon, msg, args.SenderSession); + AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession); } private void OnHeavyAttack(HeavyAttackEvent msg, EntitySessionEventArgs args) { - if (args.SenderSession.AttachedEntity == null) - { + if (args.SenderSession.AttachedEntity is not {} user) return; - } - if (!TryGetWeapon(args.SenderSession.AttachedEntity.Value, out var weaponUid, out var weapon) || + if (!TryGetWeapon(user, out var weaponUid, out var weapon) || weaponUid != GetEntity(msg.Weapon)) { return; } - AttemptAttack(args.SenderSession.AttachedEntity.Value, weaponUid, weapon, msg, args.SenderSession); + AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession); } private void OnDisarmAttack(DisarmAttackEvent msg, EntitySessionEventArgs args) { - if (args.SenderSession.AttachedEntity == null) - { - return; - } - - if (!TryGetWeapon(args.SenderSession.AttachedEntity.Value, out var weaponUid, out var weapon)) - { + if (args.SenderSession.AttachedEntity is not {} user) return; - } - AttemptAttack(args.SenderSession.AttachedEntity.Value, weaponUid, weapon, msg, args.SenderSession); + if (TryGetWeapon(user, out var weaponUid, out var weapon)) + AttemptAttack(user, weaponUid, weapon, msg, args.SenderSession); } /// @@ -277,7 +267,10 @@ public bool TryGetWeapon(EntityUid entity, out EntityUid weaponUid, [NotNullWhen if (EntityManager.TryGetComponent(entity, out HandsComponent? hands) && hands.ActiveHandEntity is { } held) { - if (EntityManager.TryGetComponent(held, out melee)) + // Make sure the entity is a weapon AND it doesn't need + // to be equipped to be used (E.g boxing gloves). + if (EntityManager.TryGetComponent(held, out melee) && + !melee.MustBeEquippedToUse) { weaponUid = held; return true; @@ -342,23 +335,32 @@ private bool AttemptAttack(EntityUid user, EntityUid weaponUid, MeleeWeaponCompo var fireRateSwingModifier = 1f; + EntityUid? target = null; switch (attack) { case LightAttackEvent light: - var lightTarget = GetEntity(light.Target); + if (light.Target != null && !TryGetEntity(light.Target, out target)) + { + // Target was lightly attacked & deleted. + return false; + } - if (!Blocker.CanAttack(user, lightTarget, (weaponUid, weapon))) + if (!Blocker.CanAttack(user, target, (weaponUid, weapon))) return false; // Can't self-attack if you're the weapon - if (weaponUid == lightTarget) + if (weaponUid == target) return false; break; case DisarmAttackEvent disarm: - var disarmTarget = GetEntity(disarm.Target); + if (disarm.Target != null && !TryGetEntity(disarm.Target, out target)) + { + // Target was lightly attacked & deleted. + return false; + } - if (!Blocker.CanAttack(user, disarmTarget, (weaponUid, weapon), true)) + if (!Blocker.CanAttack(user, target, (weaponUid, weapon), true)) return false; break; case HeavyAttackEvent: diff --git a/Content.Shared/Weapons/Ranged/Components/ActionGunComponent.cs b/Content.Shared/Weapons/Ranged/Components/ActionGunComponent.cs new file mode 100644 index 00000000000..112339efd74 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Components/ActionGunComponent.cs @@ -0,0 +1,37 @@ +using Content.Shared.Actions; +using Content.Shared.Weapons.Ranged.Systems; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared.Weapons.Ranged.Components; + +/// +/// Lets you shoot a gun using an action. +/// +[RegisterComponent, NetworkedComponent, Access(typeof(ActionGunSystem))] +public sealed partial class ActionGunComponent : Component +{ + /// + /// Action to create, must use . + /// + [DataField(required: true)] + public EntProtoId Action = string.Empty; + + [DataField] + public EntityUid? ActionEntity; + + /// + /// Prototype of gun entity to spawn. + /// Deleted when this component is removed. + /// + [DataField(required: true)] + public EntProtoId GunProto = string.Empty; + + [DataField] + public EntityUid? Gun; +} + +/// +/// Action event for to shoot at a position. +/// +public sealed partial class ActionGunShootEvent : WorldTargetActionEvent; diff --git a/Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs b/Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs index ce96639e3c4..522319ccbd3 100644 --- a/Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs +++ b/Content.Shared/Weapons/Ranged/Components/GunWieldBonusComponent.cs @@ -33,4 +33,7 @@ public sealed partial class GunWieldBonusComponent : Component /// [DataField, AutoNetworkedField] public Angle AngleIncrease = Angle.FromDegrees(0); + + [DataField] + public LocId? WieldBonusExamineMessage = "gunwieldbonus-component-examine"; } diff --git a/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs index 91f5e6cd868..10d4c2fe3c8 100644 --- a/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs +++ b/Content.Shared/Weapons/Ranged/Events/MuzzleFlashEvent.cs @@ -11,15 +11,12 @@ public sealed class MuzzleFlashEvent : EntityEventArgs public NetEntity Uid; public string Prototype; - /// - /// Should the effect match the rotation of the entity. - /// - public bool MatchRotation; + public Angle Angle; - public MuzzleFlashEvent(NetEntity uid, string prototype, bool matchRotation = false) + public MuzzleFlashEvent(NetEntity uid, string prototype, Angle angle) { Uid = uid; Prototype = prototype; - MatchRotation = matchRotation; + Angle = angle; } } diff --git a/Content.Shared/Weapons/Ranged/Systems/ActionGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/ActionGunSystem.cs new file mode 100644 index 00000000000..f3dfe8a2a03 --- /dev/null +++ b/Content.Shared/Weapons/Ranged/Systems/ActionGunSystem.cs @@ -0,0 +1,41 @@ +using Content.Shared.Actions; +using Content.Shared.Weapons.Ranged.Components; + +namespace Content.Shared.Weapons.Ranged.Systems; + +public sealed class ActionGunSystem : EntitySystem +{ + [Dependency] private readonly SharedActionsSystem _actions = default!; + [Dependency] private readonly SharedGunSystem _gun = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + SubscribeLocalEvent(OnShoot); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + if (string.IsNullOrEmpty(ent.Comp.Action)) + return; + + _actions.AddAction(ent, ref ent.Comp.ActionEntity, ent.Comp.Action); + ent.Comp.Gun = Spawn(ent.Comp.GunProto); + } + + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + if (ent.Comp.Gun is {} gun) + QueueDel(gun); + } + + private void OnShoot(Entity ent, ref ActionGunShootEvent args) + { + if (TryComp(ent.Comp.Gun, out var gun)) + _gun.AttemptShoot(ent, ent.Comp.Gun.Value, gun, args.Target); + } +} + diff --git a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs index 3c5e5c79846..989fad160c3 100644 --- a/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs +++ b/Content.Shared/Weapons/Ranged/Systems/SharedGunSystem.cs @@ -138,7 +138,6 @@ private void OnShootRequest(RequestShootEvent msg, EntitySessionEventArgs args) return; gun.ShootCoordinates = GetCoordinates(msg.Coordinates); - Log.Debug($"Set shoot coordinates to {gun.ShootCoordinates}"); gun.Target = GetEntity(msg.Target); AttemptShoot(user.Value, ent, gun); } @@ -198,7 +197,6 @@ private void StopShooting(EntityUid uid, GunComponent gun) if (gun.ShotCounter == 0) return; - Log.Debug($"Stopped shooting {ToPrettyString(uid)}"); gun.ShotCounter = 0; gun.ShootCoordinates = null; gun.Target = null; @@ -473,7 +471,7 @@ protected void RemoveShootable(EntityUid uid) RemCompDeferred(uid); } - protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? user = null) + protected void MuzzleFlash(EntityUid gun, AmmoComponent component, Angle worldAngle, EntityUid? user = null) { var attemptEv = new GunMuzzleFlashAttemptEvent(); RaiseLocalEvent(gun, ref attemptEv); @@ -485,7 +483,7 @@ protected void MuzzleFlash(EntityUid gun, AmmoComponent component, EntityUid? us if (sprite == null) return; - var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, user == gun); + var ev = new MuzzleFlashEvent(GetNetEntity(gun), sprite, worldAngle); CreateEffect(gun, ev, user); } @@ -534,7 +532,7 @@ public void RefreshModifiers(Entity gun) Dirty(gun); } - protected abstract void CreateEffect(EntityUid uid, MuzzleFlashEvent message, EntityUid? user = null); + protected abstract void CreateEffect(EntityUid gunUid, MuzzleFlashEvent message, EntityUid? user = null); /// /// Used for animated effects on the client. diff --git a/Content.Shared/Weapons/Reflect/ReflectComponent.cs b/Content.Shared/Weapons/Reflect/ReflectComponent.cs index 8e7b8975d9d..5d8432ac776 100644 --- a/Content.Shared/Weapons/Reflect/ReflectComponent.cs +++ b/Content.Shared/Weapons/Reflect/ReflectComponent.cs @@ -21,17 +21,42 @@ public sealed partial class ReflectComponent : Component [ViewVariables(VVAccess.ReadWrite), DataField("reflects")] public ReflectType Reflects = ReflectType.Energy | ReflectType.NonEnergy; + [DataField("spread"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] + public Angle Spread = Angle.FromDegrees(45); + + [DataField("soundOnReflect")] + public SoundSpecifier? SoundOnReflect = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg"); + /// - /// Probability for a projectile to be reflected. + /// Is the deflection an innate power or something actively maintained? If true, this component grants a flat + /// deflection chance rather than a chance that degrades when moving/weightless/stunned/etc. + /// + [DataField] + public bool Innate = false; + + /// + /// Maximum probability for a projectile to be reflected. /// [DataField("reflectProb"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] public float ReflectProb = 0.25f; - [DataField("spread"), ViewVariables(VVAccess.ReadWrite), AutoNetworkedField] - public Angle Spread = Angle.FromDegrees(45); + /// + /// The maximum velocity a wielder can move at before losing effectiveness. + /// + [DataField] + public float VelocityBeforeNotMaxProb = 2.5f; // Walking speed for a human. Suitable for a weightless deflector like an e-sword. - [DataField("soundOnReflect")] - public SoundSpecifier? SoundOnReflect = new SoundPathSpecifier("/Audio/Weapons/Guns/Hits/laser_sear_wall.ogg"); + /// + /// The velocity a wielder has to be moving at to use the minimum effectiveness value. + /// + [DataField] + public float VelocityBeforeMinProb = 4.5f; // Sprinting speed for a human. Suitable for a weightless deflector like an e-sword. + + /// + /// Minimum probability for a projectile to be reflected. + /// + [DataField] + public float MinReflectProb = 0.1f; } [Flags] diff --git a/Content.Shared/Weapons/Reflect/ReflectSystem.cs b/Content.Shared/Weapons/Reflect/ReflectSystem.cs index 4a7c2f6b6a7..36dbedb4cb1 100644 --- a/Content.Shared/Weapons/Reflect/ReflectSystem.cs +++ b/Content.Shared/Weapons/Reflect/ReflectSystem.cs @@ -1,17 +1,20 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using Content.Shared.Administration.Logs; +using Content.Shared.Alert; using Content.Shared.Audio; +using Content.Shared.Damage.Components; using Content.Shared.Database; +using Content.Shared.Gravity; using Content.Shared.Hands; using Content.Shared.Inventory; using Content.Shared.Inventory.Events; using Content.Shared.Item.ItemToggle.Components; using Content.Shared.Popups; using Content.Shared.Projectiles; +using Content.Shared.Standing; using Content.Shared.Weapons.Ranged.Components; using Content.Shared.Weapons.Ranged.Events; -using Robust.Shared.Audio; using Robust.Shared.Audio.Systems; using Robust.Shared.Network; using Robust.Shared.Physics.Components; @@ -35,6 +38,9 @@ public sealed class ReflectSystem : EntitySystem [Dependency] private readonly SharedAudioSystem _audio = default!; [Dependency] private readonly SharedTransformSystem _transform = default!; [Dependency] private readonly InventorySystem _inventorySystem = default!; + [Dependency] private readonly SharedGravitySystem _gravity = default!; + [Dependency] private readonly StandingStateSystem _standing = default!; + [Dependency] private readonly AlertsSystem _alerts = default!; public override void Initialize() { @@ -57,7 +63,7 @@ private void OnReflectUserHitscan(EntityUid uid, ReflectUserComponent component, if (args.Reflected) return; - foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(uid, SlotFlags.All & ~SlotFlags.POCKET)) + foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(uid, SlotFlags.WITHOUT_POCKET)) { if (!TryReflectHitscan(uid, ent, args.Shooter, args.SourceItem, args.Direction, out var dir)) continue; @@ -70,7 +76,7 @@ private void OnReflectUserHitscan(EntityUid uid, ReflectUserComponent component, private void OnReflectUserCollide(EntityUid uid, ReflectUserComponent component, ref ProjectileReflectAttemptEvent args) { - foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(uid, SlotFlags.All & ~SlotFlags.POCKET)) + foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(uid, SlotFlags.WITHOUT_POCKET)) { if (!TryReflectProjectile(uid, ent, args.ProjUid)) continue; @@ -91,15 +97,20 @@ private void OnReflectCollide(EntityUid uid, ReflectComponent component, ref Pro private bool TryReflectProjectile(EntityUid user, EntityUid reflector, EntityUid projectile, ProjectileComponent? projectileComp = null, ReflectComponent? reflect = null) { - if (!Resolve(reflector, ref reflect, false) || + // Do we have the components needed to try a reflect at all? + if ( + !Resolve(reflector, ref reflect, false) || !reflect.Enabled || !TryComp(projectile, out var reflective) || (reflect.Reflects & reflective.Reflective) == 0x0 || - !_random.Prob(reflect.ReflectProb) || - !TryComp(projectile, out var physics)) - { + !TryComp(projectile, out var physics) || + TryComp(reflector, out var staminaComponent) && staminaComponent.Critical || + _standing.IsDown(reflector) + ) + return false; + + if (!_random.Prob(CalcReflectChance(reflector, reflect))) return false; - } var rotation = _random.NextAngle(-reflect.Spread / 2, reflect.Spread / 2).Opposite(); var existingVelocity = _physics.GetMapLinearVelocity(projectile, component: physics); @@ -137,6 +148,34 @@ private bool TryReflectProjectile(EntityUid user, EntityUid reflector, EntityUid return true; } + private float CalcReflectChance(EntityUid reflector, ReflectComponent reflect) + { + /* + * The rules of deflection are as follows: + * If you innately reflect things via magic, biology etc., you always have a full chance. + * If you are standing up and standing still, you're prepared to deflect and have full chance. + * If you have velocity, your deflection chance depends on your velocity, clamped. + * If you are floating, your chance is the minimum value possible. + * You cannot deflect if you are knocked down or stunned. + */ + + if (reflect.Innate) + return reflect.ReflectProb; + + if (_gravity.IsWeightless(reflector)) + return reflect.MinReflectProb; + + if (!TryComp(reflector, out var reflectorPhysics)) + return reflect.ReflectProb; + + return MathHelper.Lerp( + reflect.MinReflectProb, + reflect.ReflectProb, + // Inverse progression between velocities fed in as progression between probabilities. We go high -> low so the output here needs to be _inverted_. + 1 - Math.Clamp((reflectorPhysics.LinearVelocity.Length() - reflect.VelocityBeforeNotMaxProb) / (reflect.VelocityBeforeMinProb - reflect.VelocityBeforeNotMaxProb), 0, 1) + ); + } + private void OnReflectHitscan(EntityUid uid, ReflectComponent component, ref HitScanReflectAttemptEvent args) { if (args.Reflected || @@ -162,7 +201,14 @@ private bool TryReflectHitscan( { if (!TryComp(reflector, out var reflect) || !reflect.Enabled || - !_random.Prob(reflect.ReflectProb)) + TryComp(reflector, out var staminaComponent) && staminaComponent.Critical || + _standing.IsDown(reflector)) + { + newDirection = null; + return false; + } + + if (!_random.Prob(CalcReflectChance(reflector, reflect))) { newDirection = null; return false; @@ -191,6 +237,9 @@ private void OnReflectEquipped(EntityUid uid, ReflectComponent component, GotEqu return; EnsureComp(args.Equipee); + + if (component.Enabled) + EnableAlert(args.Equipee); } private void OnReflectUnequipped(EntityUid uid, ReflectComponent comp, GotUnequippedEvent args) @@ -204,6 +253,9 @@ private void OnReflectHandEquipped(EntityUid uid, ReflectComponent component, Go return; EnsureComp(args.User); + + if (component.Enabled) + EnableAlert(args.User); } private void OnReflectHandUnequipped(EntityUid uid, ReflectComponent component, GotUnequippedHandEvent args) @@ -215,6 +267,11 @@ private void OnToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggl { comp.Enabled = args.Activated; Dirty(uid, comp); + + if (comp.Enabled) + EnableAlert(uid); + else + DisableAlert(uid); } /// @@ -222,15 +279,28 @@ private void OnToggleReflect(EntityUid uid, ReflectComponent comp, ref ItemToggl /// private void RefreshReflectUser(EntityUid user) { - foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(user, SlotFlags.All & ~SlotFlags.POCKET)) + foreach (var ent in _inventorySystem.GetHandOrInventoryEntities(user, SlotFlags.WITHOUT_POCKET)) { if (!HasComp(ent)) continue; EnsureComp(user); + EnableAlert(user); + return; } RemCompDeferred(user); + DisableAlert(user); + } + + private void EnableAlert(EntityUid alertee) + { + _alerts.ShowAlert(alertee, AlertType.Deflecting); + } + + private void DisableAlert(EntityUid alertee) + { + _alerts.ClearAlert(alertee, AlertType.Deflecting); } } diff --git a/Content.Shared/Whitelist/EntityWhitelist.cs b/Content.Shared/Whitelist/EntityWhitelist.cs index 942de2b0e82..895759be958 100644 --- a/Content.Shared/Whitelist/EntityWhitelist.cs +++ b/Content.Shared/Whitelist/EntityWhitelist.cs @@ -1,100 +1,67 @@ +using Content.Shared.Item; using Content.Shared.Tag; +using Robust.Shared.Prototypes; using Robust.Shared.Serialization; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List; -namespace Content.Shared.Whitelist +namespace Content.Shared.Whitelist; + +/// +/// Used to determine whether an entity fits a certain whitelist. +/// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all +/// entity prototypes that need to be whitelisted, and checking for that. +/// +/// +/// whitelist: +/// tags: +/// - Cigarette +/// - FirelockElectronics +/// components: +/// - Buckle +/// - AsteroidRock +/// sizes: +/// - Tiny +/// - Large +/// +[DataDefinition] +[Serializable, NetSerializable] +public sealed partial class EntityWhitelist { /// - /// Used to determine whether an entity fits a certain whitelist. - /// Does not whitelist by prototypes, since that is undesirable; you're better off just adding a tag to all - /// entity prototypes that need to be whitelisted, and checking for that. + /// Component names that are allowed in the whitelist. /// - /// - /// whitelist: - /// tags: - /// - Cigarette - /// - FirelockElectronics - /// components: - /// - Buckle - /// - AsteroidRock - /// - [DataDefinition] - [Serializable, NetSerializable] - public sealed partial class EntityWhitelist - { - /// - /// Component names that are allowed in the whitelist. - /// - [DataField("components")] public string[]? Components = null; - // TODO yaml validation - - [NonSerialized] - private List? _registrations = null; + [DataField] public string[]? Components; + // TODO yaml validation - /// - /// Tags that are allowed in the whitelist. - /// - [DataField("tags", customTypeSerializer:typeof(PrototypeIdListSerializer))] - public List? Tags = null; - - /// - /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an - /// entity requires to have ALL of these components and tags to pass. - /// - [DataField("requireAll")] - public bool RequireAll = false; + /// + /// Item sizes that are allowed in the whitelist. + /// + [DataField] + public List>? Sizes; - public void UpdateRegistrations() - { - if (Components == null) return; + [NonSerialized, Access(typeof(EntityWhitelistSystem))] + public List? Registrations; - var compfact = IoCManager.Resolve(); - _registrations = new List(); - foreach (var name in Components) - { - var availability = compfact.GetComponentAvailability(name); - if (compfact.TryGetRegistration(name, out var registration) - && availability == ComponentAvailability.Available) - { - _registrations.Add(registration); - } - else if (availability == ComponentAvailability.Unknown) - { - Logger.Warning($"Unknown component name {name} passed to EntityWhitelist!"); - } - } - } + /// + /// Tags that are allowed in the whitelist. + /// + [DataField] + public List>? Tags; - /// - /// Returns whether a given entity fits the whitelist. - /// - public bool IsValid(EntityUid uid, IEntityManager? entityManager = null) - { - if (Components != null && _registrations == null) - UpdateRegistrations(); + /// + /// If false, an entity only requires one of these components or tags to pass the whitelist. If true, an + /// entity requires to have ALL of these components and tags to pass. + /// The "Sizes" criteria will ignores this, since an item can only have one size. + /// + [DataField] + public bool RequireAll; - IoCManager.Resolve(ref entityManager); - if (_registrations != null) - { - foreach (var reg in _registrations) - { - if (entityManager.HasComponent(uid, reg.Type)) - { - if (!RequireAll) - return true; - } - else if (RequireAll) - return false; - } - } + [Obsolete("Use WhitelistSystem")] + public bool IsValid(EntityUid uid, IEntityManager? man = null) + { + var sys = man?.System() ?? + IoCManager.Resolve().GetEntitySystem(); - if (Tags != null && entityManager.TryGetComponent(uid, out TagComponent? tags)) - { - var tagSystem = entityManager.System(); - return RequireAll ? tagSystem.HasAllTags(tags, Tags) : tagSystem.HasAnyTag(tags, Tags); - } + return sys.IsValid(this, uid); - return false; - } } } diff --git a/Content.Shared/Whitelist/EntityWhitelistSystem.cs b/Content.Shared/Whitelist/EntityWhitelistSystem.cs new file mode 100644 index 00000000000..d73646b7e99 --- /dev/null +++ b/Content.Shared/Whitelist/EntityWhitelistSystem.cs @@ -0,0 +1,84 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Shared.Item; +using Content.Shared.Tag; + +namespace Content.Shared.Whitelist; + +public sealed class EntityWhitelistSystem : EntitySystem +{ + [Dependency] private readonly IComponentFactory _factory = default!; + [Dependency] private readonly TagSystem _tag = default!; + + private EntityQuery _itemQuery; + + public override void Initialize() + { + base.Initialize(); + _itemQuery = GetEntityQuery(); + } + + /// + public bool IsValid(EntityWhitelist list, [NotNullWhen(true)] EntityUid? uid) + { + return uid != null && IsValid(list, uid.Value); + } + + /// + /// Checks whether a given entity satisfies a whitelist. + /// + public bool IsValid(EntityWhitelist list, EntityUid uid) + { + if (list.Components != null) + EnsureRegistrations(list); + + if (list.Registrations != null) + { + foreach (var reg in list.Registrations) + { + if (HasComp(uid, reg.Type)) + { + if (!list.RequireAll) + return true; + } + else if (list.RequireAll) + return false; + } + } + + if (list.Sizes != null && _itemQuery.TryComp(uid, out var itemComp)) + { + if (list.Sizes.Contains(itemComp.Size)) + return true; + } + + if (list.Tags != null) + { + return list.RequireAll + ? _tag.HasAllTags(uid, list.Tags) + : _tag.HasAnyTag(uid, list.Tags); + } + + return list.RequireAll; + } + + private void EnsureRegistrations(EntityWhitelist list) + { + if (list.Components == null) + return; + + list.Registrations = new List(); + foreach (var name in list.Components) + { + var availability = _factory.GetComponentAvailability(name); + if (_factory.TryGetRegistration(name, out var registration) + && availability == ComponentAvailability.Available) + { + list.Registrations.Add(registration); + } + else if (availability == ComponentAvailability.Unknown) + { + Log.Warning($"Unknown component name {name} passed to EntityWhitelist!"); + } + } + } +} diff --git a/Content.Shared/Wieldable/Components/WieldableComponent.cs b/Content.Shared/Wieldable/Components/WieldableComponent.cs index 4a50b930722..5dc6abbbbea 100644 --- a/Content.Shared/Wieldable/Components/WieldableComponent.cs +++ b/Content.Shared/Wieldable/Components/WieldableComponent.cs @@ -26,6 +26,13 @@ public sealed partial class WieldableComponent : Component [AutoNetworkedField, DataField("wielded")] public bool Wielded = false; + /// + /// Whether using the item inhand while wielding causes the item to unwield. + /// Unwielding can conflict with other inhand actions. + /// + [DataField] + public bool UnwieldOnUse = true; + [DataField("wieldedInhandPrefix")] public string? WieldedInhandPrefix = "wielded"; diff --git a/Content.Shared/Wieldable/WieldableSystem.cs b/Content.Shared/Wieldable/WieldableSystem.cs index 6bd406c1cad..778a664e2cb 100644 --- a/Content.Shared/Wieldable/WieldableSystem.cs +++ b/Content.Shared/Wieldable/WieldableSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Examine; using Content.Shared.Hands; using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; @@ -45,6 +46,7 @@ public override void Initialize() SubscribeLocalEvent(OnGunWielded); SubscribeLocalEvent(OnGunUnwielded); SubscribeLocalEvent(OnGunRefreshModifiers); + SubscribeLocalEvent(OnExamine); SubscribeLocalEvent(OnGetMeleeDamage); } @@ -95,6 +97,12 @@ private void OnGunRefreshModifiers(Entity bonus, ref Gun } } + private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args) + { + if (component.WieldBonusExamineMessage != null) + args.PushText(Loc.GetString(component.WieldBonusExamineMessage)); + } + private void AddToggleWieldVerb(EntityUid uid, WieldableComponent component, GetVerbsEvent args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) @@ -125,7 +133,7 @@ private void OnUseInHand(EntityUid uid, WieldableComponent component, UseInHandE if (!component.Wielded) args.Handled = TryWield(uid, component, args.User); - else + else if (component.UnwieldOnUse) args.Handled = TryUnwield(uid, component, args.User); } diff --git a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs index cecacceda9c..07f2a60c848 100644 --- a/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs +++ b/Content.Shared/Xenoarchaeology/Equipment/SharedArtifactAnalyzer.cs @@ -30,50 +30,40 @@ public sealed class AnalysisConsoleExtractButtonPressedMessage : BoundUserInterf } [Serializable, NetSerializable] -public sealed class AnalysisConsoleScanUpdateState : BoundUserInterfaceState +public sealed class AnalysisConsoleBiasButtonPressedMessage(bool isDown) : BoundUserInterfaceMessage { - public NetEntity? Artifact; - - public bool AnalyzerConnected; - - public bool ServerConnected; - - public bool CanScan; - - public bool CanPrint; - - public FormattedMessage? ScanReport; - - public bool Scanning; - - public bool Paused; - - public TimeSpan? StartTime; - - public TimeSpan? AccumulatedRunTime; - - public TimeSpan? TotalTime; - - public int PointAmount; - - public AnalysisConsoleScanUpdateState(NetEntity? artifact, bool analyzerConnected, bool serverConnected, bool canScan, bool canPrint, - FormattedMessage? scanReport, bool scanning, bool paused, TimeSpan? startTime, TimeSpan? accumulatedRunTime, TimeSpan? totalTime, int pointAmount) - { - Artifact = artifact; - AnalyzerConnected = analyzerConnected; - ServerConnected = serverConnected; - CanScan = canScan; - CanPrint = canPrint; - - ScanReport = scanReport; - - Scanning = scanning; - Paused = paused; - - StartTime = startTime; - AccumulatedRunTime = accumulatedRunTime; - TotalTime = totalTime; + public bool IsDown = isDown; +} - PointAmount = pointAmount; - } +[Serializable, NetSerializable] +public sealed class AnalysisConsoleUpdateState( + NetEntity? artifact, + bool analyzerConnected, + bool serverConnected, + bool canScan, + bool canPrint, + FormattedMessage? scanReport, + bool scanning, + bool paused, + TimeSpan? startTime, + TimeSpan? accumulatedRunTime, + TimeSpan? totalTime, + int pointAmount, + bool isTraversalDown +) + : BoundUserInterfaceState +{ + public NetEntity? Artifact = artifact; + public bool AnalyzerConnected = analyzerConnected; + public bool ServerConnected = serverConnected; + public bool CanScan = canScan; + public bool CanPrint = canPrint; + public FormattedMessage? ScanReport = scanReport; + public bool Scanning = scanning; + public bool Paused = paused; + public TimeSpan? StartTime = startTime; + public TimeSpan? AccumulatedRunTime = accumulatedRunTime; + public TimeSpan? TotalTime = totalTime; + public int PointAmount = pointAmount; + public bool IsTraversalDown = isTraversalDown; } diff --git a/Content.Shared/Zombies/ZombieComponent.cs b/Content.Shared/Zombies/ZombieComponent.cs index be3fdbdd01a..3673a2c51d5 100644 --- a/Content.Shared/Zombies/ZombieComponent.cs +++ b/Content.Shared/Zombies/ZombieComponent.cs @@ -27,7 +27,7 @@ public sealed partial class ZombieComponent : Component, IAntagStatusIconCompone /// being invincible by bundling up. /// [ViewVariables(VVAccess.ReadWrite)] - public float MinZombieInfectionChance = 0.50f; + public float MinZombieInfectionChance = 0.25f; [ViewVariables(VVAccess.ReadWrite)] public float ZombieMovementSpeedDebuff = 0.70f; diff --git a/Content.Tests/Shared/DamageTest.cs b/Content.Tests/Shared/DamageTest.cs index 11b810bf36a..88beca8841c 100644 --- a/Content.Tests/Shared/DamageTest.cs +++ b/Content.Tests/Shared/DamageTest.cs @@ -168,45 +168,57 @@ public void ModifierSetTest() private string _damagePrototypes = @" - type: damageType id: Blunt + name: damage-type-blunt - type: damageType id: Slash + name: damage-type-slash - type: damageType id: Piercing + name: damage-type-piercing - type: damageType id: Heat + name: damage-type-heat - type: damageType id: Shock + name: damage-type-shock - type: damageType id: Cold + name: damage-type-cold # Poison damage. Generally caused by various reagents being metabolised. - type: damageType id: Poison + name: damage-type-poison - type: damageType id: Radiation + name: damage-type-radiation # Damage due to being unable to breathe. # Represents not enough oxygen (or equivalent) getting to the blood. # Usually healed automatically if entity can breathe - type: damageType id: Asphyxiation + name: damage-type-asphyxiation # Damage representing not having enough blood. # Represents there not enough blood to supply oxygen (or equivalent). - type: damageType id: Bloodloss + name: damage-type-bloodloss - type: damageType id: Cellular + name: damage-type-cellular - type: damageGroup id: Brute + name: damage-group-brute damageTypes: - Blunt - Slash @@ -214,6 +226,7 @@ public void ModifierSetTest() - type: damageGroup id: Burn + name: damage-group-burn damageTypes: - Heat - Shock @@ -225,6 +238,7 @@ public void ModifierSetTest() # bloodloss, not this whole group, unless you have a wonder drug that affects both. - type: damageGroup id: Airloss + name: damage-group-airloss damageTypes: - Asphyxiation - Bloodloss @@ -233,12 +247,14 @@ public void ModifierSetTest() # Though there are probably some radioactive poisons. - type: damageGroup id: Toxin + name: damage-group-toxin damageTypes: - Poison - Radiation - type: damageGroup id: Genetic + name: damage-group-genetic damageTypes: - Cellular diff --git a/Content.YAMLLinter/Program.cs b/Content.YAMLLinter/Program.cs index 78867fcb8ab..7f0b740fe8c 100644 --- a/Content.YAMLLinter/Program.cs +++ b/Content.YAMLLinter/Program.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Reflection; using System.Threading.Tasks; using Content.IntegrationTests; using Robust.Shared.Prototypes; +using Robust.Shared.Reflection; using Robust.Shared.Serialization.Markdown.Validation; using Robust.Shared.Timing; using Robust.Shared.Utility; @@ -103,9 +105,13 @@ await instance.WaitPost(() => return (yamlErrors, fieldErrors); } - public static async Task<(Dictionary> YamlErrors , List FieldErrors)> + public static async Task<(Dictionary> YamlErrors, List FieldErrors)> RunValidation() { + var (clientAssemblies, serverAssemblies) = await GetClientServerAssemblies(); + var serverTypes = serverAssemblies.SelectMany(n => n.GetTypes()).Select(t => t.Name).ToHashSet(); + var clientTypes = clientAssemblies.SelectMany(n => n.GetTypes()).Select(t => t.Name).ToHashSet(); + var yamlErrors = new Dictionary>(); var serverErrors = await ValidateServer(); @@ -117,9 +123,18 @@ await instance.WaitPost(() => var newErrors = val.Where(n => n.AlwaysRelevant).ToHashSet(); // We include sometimes-relevant errors if they exist both for the client & server - if (clientErrors.Item1.TryGetValue(key, out var clientVal)) + if (clientErrors.YamlErrors.TryGetValue(key, out var clientVal)) newErrors.UnionWith(val.Intersect(clientVal)); + // Include any errors that relate to server-only types + foreach (var errorNode in val) + { + if (errorNode is FieldNotFoundErrorNode fieldNotFoundNode && !clientTypes.Contains(fieldNotFoundNode.FieldType.Name)) + { + newErrors.Add(errorNode); + } + } + if (newErrors.Count != 0) yamlErrors[key] = newErrors; } @@ -135,6 +150,15 @@ await instance.WaitPost(() => errors.UnionWith(val.Where(n => n.AlwaysRelevant)); else yamlErrors[key] = newErrors; + + // Include any errors that relate to client-only types + foreach (var errorNode in val) + { + if (errorNode is FieldNotFoundErrorNode fieldNotFoundNode && !serverTypes.Contains(fieldNotFoundNode.FieldType.Name)) + { + newErrors.Add(errorNode); + } + } } // Finally, combine the prototype ID field errors. @@ -145,5 +169,23 @@ await instance.WaitPost(() => return (yamlErrors, fieldErrors); } + + private static async Task<(Assembly[] clientAssemblies, Assembly[] serverAssemblies)> + GetClientServerAssemblies() + { + await using var pair = await PoolManager.GetServerClient(); + + var result = (GetAssemblies(pair.Client), GetAssemblies(pair.Server)); + + await pair.CleanReturnAsync(); + + return result; + + Assembly[] GetAssemblies(RobustIntegrationTest.IntegrationInstance instance) + { + var refl = instance.ResolveDependency(); + return refl.Assemblies.ToArray(); + } + } } } diff --git a/Resources/Audio/Animals/attributions.yml b/Resources/Audio/Animals/attributions.yml index c34832a807a..7fd7e8b2e7b 100644 --- a/Resources/Audio/Animals/attributions.yml +++ b/Resources/Audio/Animals/attributions.yml @@ -7,7 +7,7 @@ license: "CC-BY-3.0" copyright: "Modified from 'Meow 4.wav' by freesound user 'TRNGLE. The original audio was trimmed, split to mono, and converted from WAV to OGG format" source: "https://freesound.org/people/TRNGLE/sounds/368006/" - + - files: ["cat_meow2.ogg"] license: "CC-BY-3.0" copyright: "Created by freesound user 'TRNGLE. The original audio split to mono, and converted from WAV to OGG format" @@ -117,24 +117,42 @@ license: "CC-BY-4.0" copyright: "Audio is recorded/created by Pfranzen 'FreeSound.org'. The original audio was trimmed and renamed" source: "https://freesound.org/people/pfranzen/sounds/322744/" - + - files: ["dog_bark1.ogg"] license: "CC0-1.0" copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed" - source: "https://freesound.org/people/KFerentchak/sounds/235912/" - + source: "https://freesound.org/people/KFerentchak/sounds/235912/" + - files: ["dog_bark2.ogg"] license: "CC0-1.0" copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed" - source: "https://freesound.org/people/KFerentchak/sounds/235912/" - + source: "https://freesound.org/people/KFerentchak/sounds/235912/" + - files: ["dog_bark3.ogg"] license: "CC0-1.0" copyright: "Audio is recorded/created by KFerentchak 'FreeSound.org'. The original audio was trimmed and renamed" source: "https://freesound.org/people/KFerentchak/sounds/235912/" - + - files: ["nymph_chirp.ogg"] license: "CC-BY-SA-3.0" copyright: "Taken from ParadiseSS13" source: "https://github.com/ParadiseSS13/Paradise/commit/a34f1054cef5a44a67fdac3b67b811137c6071dd" - \ No newline at end of file + +- files: + - fox1.ogg + - fox2.ogg + - fox3.ogg + - fox4.ogg + - fox5.ogg + - fox6.ogg + - fox7.ogg + - fox8.ogg + - fox9.ogg + - fox10.ogg + - fox11.ogg + - fox12.ogg + - fox13.ogg + - fox14.ogg + copyright: "Created by fujiwaranao" + license: "CC-BY-NC-SA-4.0" + source: "https://github.com/space-wizards/space-station-14/pull/27578" diff --git a/Resources/Audio/Animals/fox1.ogg b/Resources/Audio/Animals/fox1.ogg new file mode 100644 index 00000000000..40fe16cc52b Binary files /dev/null and b/Resources/Audio/Animals/fox1.ogg differ diff --git a/Resources/Audio/Animals/fox10.ogg b/Resources/Audio/Animals/fox10.ogg new file mode 100644 index 00000000000..2a9e156dc56 Binary files /dev/null and b/Resources/Audio/Animals/fox10.ogg differ diff --git a/Resources/Audio/Animals/fox11.ogg b/Resources/Audio/Animals/fox11.ogg new file mode 100644 index 00000000000..d294137dc1b Binary files /dev/null and b/Resources/Audio/Animals/fox11.ogg differ diff --git a/Resources/Audio/Animals/fox12.ogg b/Resources/Audio/Animals/fox12.ogg new file mode 100644 index 00000000000..c413af81c74 Binary files /dev/null and b/Resources/Audio/Animals/fox12.ogg differ diff --git a/Resources/Audio/Animals/fox13.ogg b/Resources/Audio/Animals/fox13.ogg new file mode 100644 index 00000000000..197a9e43392 Binary files /dev/null and b/Resources/Audio/Animals/fox13.ogg differ diff --git a/Resources/Audio/Animals/fox14.ogg b/Resources/Audio/Animals/fox14.ogg new file mode 100644 index 00000000000..1d9c99889d8 Binary files /dev/null and b/Resources/Audio/Animals/fox14.ogg differ diff --git a/Resources/Audio/Animals/fox2.ogg b/Resources/Audio/Animals/fox2.ogg new file mode 100644 index 00000000000..7aeb7da9118 Binary files /dev/null and b/Resources/Audio/Animals/fox2.ogg differ diff --git a/Resources/Audio/Animals/fox3.ogg b/Resources/Audio/Animals/fox3.ogg new file mode 100644 index 00000000000..561b313f419 Binary files /dev/null and b/Resources/Audio/Animals/fox3.ogg differ diff --git a/Resources/Audio/Animals/fox4.ogg b/Resources/Audio/Animals/fox4.ogg new file mode 100644 index 00000000000..6805d0e8481 Binary files /dev/null and b/Resources/Audio/Animals/fox4.ogg differ diff --git a/Resources/Audio/Animals/fox5.ogg b/Resources/Audio/Animals/fox5.ogg new file mode 100644 index 00000000000..5aefa939cc0 Binary files /dev/null and b/Resources/Audio/Animals/fox5.ogg differ diff --git a/Resources/Audio/Animals/fox6.ogg b/Resources/Audio/Animals/fox6.ogg new file mode 100644 index 00000000000..d23cca5ff22 Binary files /dev/null and b/Resources/Audio/Animals/fox6.ogg differ diff --git a/Resources/Audio/Animals/fox7.ogg b/Resources/Audio/Animals/fox7.ogg new file mode 100644 index 00000000000..d4da91e73bf Binary files /dev/null and b/Resources/Audio/Animals/fox7.ogg differ diff --git a/Resources/Audio/Animals/fox8.ogg b/Resources/Audio/Animals/fox8.ogg new file mode 100644 index 00000000000..52337a640b1 Binary files /dev/null and b/Resources/Audio/Animals/fox8.ogg differ diff --git a/Resources/Audio/Animals/fox9.ogg b/Resources/Audio/Animals/fox9.ogg new file mode 100644 index 00000000000..eb161ccdafc Binary files /dev/null and b/Resources/Audio/Animals/fox9.ogg differ diff --git a/Resources/Audio/Announcements/attributions.yml b/Resources/Audio/Announcements/attributions.yml index 879bfe7f600..774b0da5a09 100644 --- a/Resources/Audio/Announcements/attributions.yml +++ b/Resources/Audio/Announcements/attributions.yml @@ -7,3 +7,8 @@ license: "CC-BY-SA-3.0" copyright: "Paradise, volume and pitch changed, merged with redalert.ogg" source: "https://github.com/ParadiseSS13/Paradise/blob/07b26ee6b4a11a0607986d322ee007020569feae/sound/effects/siren.ogg" + +- files: ["intercept.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Taken from tgstation" + source: "https://github.com/tgstation/tgstation/blob/95731342b97167d7883ff091d389f79c36442ee6/sound/ai/default/intercept.ogg" diff --git a/Resources/Audio/Announcements/intercept.ogg b/Resources/Audio/Announcements/intercept.ogg new file mode 100644 index 00000000000..3569a07d401 Binary files /dev/null and b/Resources/Audio/Announcements/intercept.ogg differ diff --git a/Resources/Audio/Effects/Footsteps/attributions.yml b/Resources/Audio/Effects/Footsteps/attributions.yml index 82b5fa93ca2..91c3ce260d4 100644 --- a/Resources/Audio/Effects/Footsteps/attributions.yml +++ b/Resources/Audio/Effects/Footsteps/attributions.yml @@ -71,3 +71,10 @@ license: "CC-BY-SA-3.0" copyright: "Taken from tgstation" source: "https://github.com/tgstation/tgstation/tree/1e8d511946d194f92f744f5f957a7c41683d84a6/sound/effects/footstep" + +- files: + - borgwalk1.ogg + - borgwalk2.ogg + license: "CC-BY-SA-4.0" + copyright: "Taken from IENBA freesound.org and modified by https://github.com/MilenVolf" + source: "https://freesound.org/people/IENBA/sounds/697379/" diff --git a/Resources/Audio/Effects/Footsteps/borgwalk1.ogg b/Resources/Audio/Effects/Footsteps/borgwalk1.ogg new file mode 100644 index 00000000000..3305a52ea22 Binary files /dev/null and b/Resources/Audio/Effects/Footsteps/borgwalk1.ogg differ diff --git a/Resources/Audio/Effects/Footsteps/borgwalk2.ogg b/Resources/Audio/Effects/Footsteps/borgwalk2.ogg new file mode 100644 index 00000000000..96c2c1617f4 Binary files /dev/null and b/Resources/Audio/Effects/Footsteps/borgwalk2.ogg differ diff --git a/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge.ogg b/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge.ogg new file mode 100644 index 00000000000..5efc8f443be Binary files /dev/null and b/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge.ogg differ diff --git a/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge2.ogg b/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge2.ogg new file mode 100644 index 00000000000..662254fbaa9 Binary files /dev/null and b/Resources/Audio/Effects/Grenades/SelfDestruct/SDS_Charge2.ogg differ diff --git a/Resources/Audio/Effects/Grenades/SelfDestruct/attributions.yml b/Resources/Audio/Effects/Grenades/SelfDestruct/attributions.yml new file mode 100644 index 00000000000..cb8a4257390 --- /dev/null +++ b/Resources/Audio/Effects/Grenades/SelfDestruct/attributions.yml @@ -0,0 +1,8 @@ +- files: + - SDS_Charge.ogg + - SDS_Charge2.ogg + license: Custom + source: https://freesound.org/people/Teh_Bucket/sounds/518739/ + # couldn't figure out how to source multiple (the right way) without shit breaking so heres the rest: https://pixabay.com/sound-effects/switchbigpowerwav-14710/ https://pixabay.com/sound-effects/shield-recharging-107016/ + copyright: '"Electric Charge + Shot" by Teh_Bucket on Freesound.org. This is adapted from multiple works by dylanperitz, satanicupsman, CaptainGusterd, arightwizard, BigKahuna360, michael_grinnell, weaveofkev, MichelleGrobler, Alex_John73, sandyrb and breo2012 all of Freesound.org. The work by sandyrb is licensed under CC-BY-4.0. , "switchbigpower-14710.wav" and "shield-recharging-107016.wav" by Pixabay on pixabay.com' + # i have no idea how to set these up, it uses all 3 sound effects and i copied the electric charge one from the powersink, godo diff --git a/Resources/Audio/Effects/chopstickbreak.ogg b/Resources/Audio/Effects/chopstickbreak.ogg new file mode 100644 index 00000000000..bac8ac04621 Binary files /dev/null and b/Resources/Audio/Effects/chopstickbreak.ogg differ diff --git a/Resources/Audio/Effects/spray3.ogg b/Resources/Audio/Effects/spray3.ogg new file mode 100644 index 00000000000..a9f493198c7 Binary files /dev/null and b/Resources/Audio/Effects/spray3.ogg differ diff --git a/Resources/Audio/Expedition/attributions.yml b/Resources/Audio/Expedition/attributions.yml new file mode 100644 index 00000000000..8bafcc6f112 --- /dev/null +++ b/Resources/Audio/Expedition/attributions.yml @@ -0,0 +1,9 @@ +- files: ["tension_session.ogg"] + license: "CC-BY-3.0" + copyright: "Created by qwertyquerty" + source: "https://www.youtube.com/@qwertyquerty" + +- files: ["deadline.ogg"] + license: "CC-BY-4.0" + copyright: "Bolgarich" + source: "https://www.youtube.com/watch?v=q7_NFEeeEac" diff --git a/Resources/Audio/Expedition/deadline.ogg b/Resources/Audio/Expedition/deadline.ogg new file mode 100644 index 00000000000..131016d8919 Binary files /dev/null and b/Resources/Audio/Expedition/deadline.ogg differ diff --git a/Resources/Audio/Misc/tension_session.ogg b/Resources/Audio/Expedition/tension_session.ogg similarity index 100% rename from Resources/Audio/Misc/tension_session.ogg rename to Resources/Audio/Expedition/tension_session.ogg diff --git a/Resources/Audio/Items/attributions.yml b/Resources/Audio/Items/attributions.yml index c6fea50bd25..b3ae4f611f9 100644 --- a/Resources/Audio/Items/attributions.yml +++ b/Resources/Audio/Items/attributions.yml @@ -93,6 +93,16 @@ copyright: "User Hanbaal on freesound.org. Converted to ogg by TheShuEd" source: "https://freesound.org/people/Hanbaal/sounds/178669/" +- files: ["soda_shake.ogg"] + license: "CC-BY-NC-4.0" + copyright: "User mcmast on freesound.org. Converted and edited by Tayrtahn" + source: "https://freesound.org/people/mcmast/sounds/456703/" + +- files: ["soda_spray.ogg"] + license: "CC0-1.0" + copyright: "User Hajisounds on freesound.org. Converted and edited by Tayrtahn" + source: "https://freesound.org/people/Hajisounds/sounds/709149/" + - files: ["newton_cradle.ogg"] license: "CC-BY-4.0" copyright: "User LoafDV on freesound.org. Converted to ogg end edited by lzk228" @@ -117,3 +127,10 @@ license: "CC0-1.0" copyright: "Original sound by stomachache on freesound.org, processed by vanilla" source: "https://freesound.org/s/262213/" + +- files: + - "sheath.ogg" + - "unsheath.ogg" + license: "CC-BY-SA-3.0" + copyright: "Taken from tgstation." + source: "https://github.com/tgstation/tgstation/blob/a7f525bce9a359ab5282fc754078cd4b5678a006/sound/items" diff --git a/Resources/Audio/Items/sheath.ogg b/Resources/Audio/Items/sheath.ogg new file mode 100644 index 00000000000..9e1d5cdc009 Binary files /dev/null and b/Resources/Audio/Items/sheath.ogg differ diff --git a/Resources/Audio/Items/soda_shake.ogg b/Resources/Audio/Items/soda_shake.ogg new file mode 100644 index 00000000000..a596379c93a Binary files /dev/null and b/Resources/Audio/Items/soda_shake.ogg differ diff --git a/Resources/Audio/Items/soda_spray.ogg b/Resources/Audio/Items/soda_spray.ogg new file mode 100644 index 00000000000..f4a5a3e803f Binary files /dev/null and b/Resources/Audio/Items/soda_spray.ogg differ diff --git a/Resources/Audio/Items/unsheath.ogg b/Resources/Audio/Items/unsheath.ogg new file mode 100644 index 00000000000..09867f5966a Binary files /dev/null and b/Resources/Audio/Items/unsheath.ogg differ diff --git a/Resources/Audio/Jukebox/attributions.yml b/Resources/Audio/Jukebox/attributions.yml index 8e48560ac68..48e1458c4c0 100644 --- a/Resources/Audio/Jukebox/attributions.yml +++ b/Resources/Audio/Jukebox/attributions.yml @@ -20,3 +20,8 @@ license: "CC-BY-3.0" copyright: "Constellations by Qwertyquerty. Converted to mono OGG." source: "https://www.youtube.com/channel/UCPYbhBUGhH7n_G4HLK2YipQ" + +- files: ["sunset.ogg"] + license: "CC-BY-SA-3.0" + copyright: "Sunset by PigeonBeans. Exported in Mono OGG." + source: "https://soundcloud.com/pigeonbeans/sunset" \ No newline at end of file diff --git a/Resources/Audio/Jukebox/sunset.ogg b/Resources/Audio/Jukebox/sunset.ogg new file mode 100644 index 00000000000..3f6d909eaa1 Binary files /dev/null and b/Resources/Audio/Jukebox/sunset.ogg differ diff --git a/Resources/Audio/Machines/warning_buzzer.ogg b/Resources/Audio/Machines/warning_buzzer.ogg index 55bb179f57d..bef16f46fb9 100644 Binary files a/Resources/Audio/Machines/warning_buzzer.ogg and b/Resources/Audio/Machines/warning_buzzer.ogg differ diff --git a/Resources/Audio/Voice/Silicon/attributions.yml b/Resources/Audio/Voice/Silicon/attributions.yml new file mode 100644 index 00000000000..465f8455036 --- /dev/null +++ b/Resources/Audio/Voice/Silicon/attributions.yml @@ -0,0 +1,4 @@ +- files: ["syndieborg_laugh.ogg"] + license: "CC0-1.0" + copyright: "Taken from vultraz168 freesound.org and modified by https://github.com/MilenVolf" + source: "https://freesound.org/people/vultraz168/sounds/334665/" diff --git a/Resources/Audio/Voice/Silicon/syndieborg_laugh.ogg b/Resources/Audio/Voice/Silicon/syndieborg_laugh.ogg new file mode 100644 index 00000000000..e0f425301e2 Binary files /dev/null and b/Resources/Audio/Voice/Silicon/syndieborg_laugh.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/attributions.yml b/Resources/Audio/Voice/Talk/Silicon/attributions.yml new file mode 100644 index 00000000000..3a16007758e --- /dev/null +++ b/Resources/Audio/Voice/Talk/Silicon/attributions.yml @@ -0,0 +1,10 @@ +- files: + - borg.ogg + - borg_ask.ogg + - borg_exclaim.ogg + - syndieborg.ogg + - syndieborg_ask.ogg + - syndieborg_exclaim.ogg + license: "CC-BY-SA-4.0" + copyright: "Recorded and mixed by https://github.com/MilenVolf" + source: "https://github.com/space-wizards/space-station-14/pull/27205" diff --git a/Resources/Audio/Voice/Talk/Silicon/borg.ogg b/Resources/Audio/Voice/Talk/Silicon/borg.ogg new file mode 100644 index 00000000000..afb97390352 Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/borg.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/borg_ask.ogg b/Resources/Audio/Voice/Talk/Silicon/borg_ask.ogg new file mode 100644 index 00000000000..fe2f60141aa Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/borg_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/borg_exclaim.ogg b/Resources/Audio/Voice/Talk/Silicon/borg_exclaim.ogg new file mode 100644 index 00000000000..5f0fdfe89e5 Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/borg_exclaim.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/syndieborg.ogg b/Resources/Audio/Voice/Talk/Silicon/syndieborg.ogg new file mode 100644 index 00000000000..60eb1a5ccfa Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/syndieborg.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/syndieborg_ask.ogg b/Resources/Audio/Voice/Talk/Silicon/syndieborg_ask.ogg new file mode 100644 index 00000000000..acafe456425 Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/syndieborg_ask.ogg differ diff --git a/Resources/Audio/Voice/Talk/Silicon/syndieborg_exclaim.ogg b/Resources/Audio/Voice/Talk/Silicon/syndieborg_exclaim.ogg new file mode 100644 index 00000000000..392b4fd1cca Binary files /dev/null and b/Resources/Audio/Voice/Talk/Silicon/syndieborg_exclaim.ogg differ diff --git a/Resources/ConfigPresets/Build/development.toml b/Resources/ConfigPresets/Build/development.toml index da3a4130262..a1900dbaa24 100644 --- a/Resources/ConfigPresets/Build/development.toml +++ b/Resources/ConfigPresets/Build/development.toml @@ -23,6 +23,7 @@ grid_fill = false auto_call_time = 0 emergency = false arrivals = false +preload_grids = false [admin] see_own_notes = true diff --git a/Resources/ConfigPresets/EinsteinEngines/default.toml b/Resources/ConfigPresets/EinsteinEngines/default.toml index ae5f943d01d..b5b8dbbf64e 100644 --- a/Resources/ConfigPresets/EinsteinEngines/default.toml +++ b/Resources/ConfigPresets/EinsteinEngines/default.toml @@ -37,6 +37,7 @@ tickrate = 30 limit = 10.0 [build] +#! PLEASE set this for your fork fork_id = "EinsteinEngines" [server] diff --git a/Resources/Locale/en-US/HUD/game-hud.ftl b/Resources/Locale/en-US/HUD/game-hud.ftl index 7f6573d2adf..ea423f080ab 100644 --- a/Resources/Locale/en-US/HUD/game-hud.ftl +++ b/Resources/Locale/en-US/HUD/game-hud.ftl @@ -1,6 +1,7 @@ game-hud-open-escape-menu-button-tooltip = Open escape menu. game-hud-open-guide-menu-button-tooltip = Open guidebook menu. game-hud-open-character-menu-button-tooltip = Open character menu. +game-hud-open-emotes-menu-button-tooltip= Open emotes menu. game-hud-open-inventory-menu-button-tooltip = Open inventory menu. game-hud-open-crafting-menu-button-tooltip = Open crafting menu. game-hud-open-actions-menu-button-tooltip = Open actions menu. diff --git a/Resources/Locale/en-US/accent/italian.ftl b/Resources/Locale/en-US/accent/italian.ftl index d0ef4e8f72b..cc8641417fe 100644 --- a/Resources/Locale/en-US/accent/italian.ftl +++ b/Resources/Locale/en-US/accent/italian.ftl @@ -78,9 +78,6 @@ accent-italian-words-replace-23 = greek accent-italian-words-24 = operatives accent-italian-words-replace-24 = greeks -accent-italian-words-24 = ops -accent-italian-words-replace-24 = greeks - accent-italian-words-25 = sec accent-italian-words-replace-25 = polizia diff --git a/Resources/Locale/en-US/accent/pirate.ftl b/Resources/Locale/en-US/accent/pirate.ftl index 8da975df401..b6db7c803ba 100644 --- a/Resources/Locale/en-US/accent/pirate.ftl +++ b/Resources/Locale/en-US/accent/pirate.ftl @@ -1,7 +1,7 @@ accent-pirate-prefix-1 = Arrgh accent-pirate-prefix-2 = Garr accent-pirate-prefix-3 = Yarr -accent-pirate-prefix-3 = Yarrgh +accent-pirate-prefix-4 = Yarrgh accent-pirate-replaced-1 = my accent-pirate-replacement-1 = me diff --git a/Resources/Locale/en-US/accessories/human-hair.ftl b/Resources/Locale/en-US/accessories/human-hair.ftl index 3a507ec6cfc..7d3467a610c 100644 --- a/Resources/Locale/en-US/accessories/human-hair.ftl +++ b/Resources/Locale/en-US/accessories/human-hair.ftl @@ -165,6 +165,7 @@ marking-HumanHairProtagonist = Slightly Long Hair marking-HumanHairSpikey = Spiky marking-HumanHairSpiky = Spiky 2 marking-HumanHairSpiky2 = Spiky 3 +marking-HumanHairSpookyLong = Spooky Long marking-HumanHairSwept = Swept Back Hair marking-HumanHairSwept2 = Swept Back Hair 2 marking-HumanHairTailed = Tailed diff --git a/Resources/Locale/en-US/accessories/vox-facial-hair.ftl b/Resources/Locale/en-US/accessories/vox-facial-hair.ftl index 48b19ca74b1..a63b0b5a398 100644 --- a/Resources/Locale/en-US/accessories/vox-facial-hair.ftl +++ b/Resources/Locale/en-US/accessories/vox-facial-hair.ftl @@ -1,5 +1,5 @@ -marking-VoxFacialHairColonel = Vox Colonel -marking-VoxFacialHairFu = Quill Fu -marking-VoxFacialHairNeck = Neck Quills -marking-VoxFacialHairBeard = Quill Beard -marking-VoxFacialHairRuffBeard = Ruff Beard +marking-VoxFacialHairBeard = Vox Beard (Quills) +marking-VoxFacialHairColonel = Vox Moustache (Colonel) +marking-VoxFacialHairFu = Vox Moustache (Quill Fu) +marking-VoxFacialHairNeck = Vox Beard (Neck Quills) +marking-VoxFacialHairMane = Vox Beard (Mane) diff --git a/Resources/Locale/en-US/accessories/vox-hair.ftl b/Resources/Locale/en-US/accessories/vox-hair.ftl index cf98d0b4f98..94483fd6a6c 100644 --- a/Resources/Locale/en-US/accessories/vox-hair.ftl +++ b/Resources/Locale/en-US/accessories/vox-hair.ftl @@ -1,13 +1,22 @@ -marking-VoxHairShortQuills = Short Vox Quills -marking-VoxHairKingly = Vox Kingly marking-VoxHairAfro = Vox Afro -marking-VoxHairMohawk = Vox Mohawk -marking-VoxHairYasuhiro = Vox Yasuhiro +marking-VoxHairBraids = Vox Braids +marking-VoxHairCrestedQuills = Vox Crested Quills +marking-VoxHairEmperorQuills = Vox Emperor Quills +marking-VoxHairFlowing = Vox Flowing +marking-VoxHairHawk = Vox Hawk marking-VoxHairHorns = Vox Horns -marking-VoxHairNights = Vox Nights -marking-VoxHairSurf = Vox Surf -marking-VoxHairCropped = Vox Cropped -marking-VoxHairRuffhawk = Vox Ruffhawk -marking-VoxHairRows = Vox Rows +marking-VoxHairKeelQuills = Vox Keel Quills +marking-VoxHairKeetQuills = Vox Keet Quills +marking-VoxHairKingly = Vox Kingly +marking-VoxHairLongBraid = Vox Long Braid marking-VoxHairMange = Vox Mange +marking-VoxHairMohawk = Vox Mohawk +marking-VoxHairNights = Vox Nights marking-VoxHairPony = Vox Pony +marking-VoxHairRazorClipped = Vox Razor (Clipped) +marking-VoxHairRazor = Vox Razor +marking-VoxHairSortBraid = Vox Short Braid +marking-VoxHairShortQuills = Vox Short Quills +marking-VoxHairSurf = Vox Surf +marking-VoxHairTielQuills = Vox Tiel Quills +marking-VoxHairYasu = Vox Yasuhiro diff --git a/Resources/Locale/en-US/administration/smites.ftl b/Resources/Locale/en-US/administration/smites.ftl index ae4e6f72715..ff3e3b09018 100644 --- a/Resources/Locale/en-US/administration/smites.ftl +++ b/Resources/Locale/en-US/administration/smites.ftl @@ -13,7 +13,6 @@ admin-smite-stomach-removal-self = Your stomach feels hollow... admin-smite-run-walk-swap-prompt = You have to press shift to run! admin-smite-super-speed-prompt = You move at mach 0.8! admin-smite-lung-removal-self = You can't breathe! -admin-smite-terminate-prompt = I'll be back ## Smite descriptions @@ -58,7 +57,6 @@ admin-smite-disarm-prone-description = Makes them get disarmed 100% of the time admin-smite-garbage-can-description = Turn them into a garbage bin to emphasize what they remind you of. admin-smite-super-bonk-description = Slams them on every single table on the Station and beyond. admin-smite-super-bonk-lite-description= Slams them on every single table on the Station and beyond. Stops when the target is dead. -admin-smite-terminate-description = Creates a Terminator ghost role with the sole objective of killing them. ## Tricks descriptions diff --git a/Resources/Locale/en-US/administration/ui/admin-logs.ftl b/Resources/Locale/en-US/administration/ui/admin-logs.ftl index 549e9587d7f..377bea6e84a 100644 --- a/Resources/Locale/en-US/administration/ui/admin-logs.ftl +++ b/Resources/Locale/en-US/administration/ui/admin-logs.ftl @@ -14,7 +14,6 @@ admin-logs-select-none = None # Players admin-logs-search-players-placeholder = Search Players (OR) -admin-logs-select-none = None admin-logs-include-non-player = Include Non-players # Logs diff --git a/Resources/Locale/en-US/administration/ui/admin-notes.ftl b/Resources/Locale/en-US/administration/ui/admin-notes.ftl index ca5348a9405..03e12902576 100644 --- a/Resources/Locale/en-US/administration/ui/admin-notes.ftl +++ b/Resources/Locale/en-US/administration/ui/admin-notes.ftl @@ -35,7 +35,6 @@ admin-notes-message-seen = Seen admin-notes-banned-from = Banned from admin-notes-the-server = the server admin-notes-permanently = permanently -admin-notes-for = for {$player} admin-notes-days = {$days} days admin-notes-hours = {$hours} hours admin-notes-minutes = {$minutes} minutes diff --git a/Resources/Locale/en-US/alerts/alerts.ftl b/Resources/Locale/en-US/alerts/alerts.ftl index ff2c0d9ee29..03f04ec7ba3 100644 --- a/Resources/Locale/en-US/alerts/alerts.ftl +++ b/Resources/Locale/en-US/alerts/alerts.ftl @@ -57,9 +57,6 @@ alerts-no-battery-desc = You don't have a battery, rendering you unable to charg alerts-internals-name = Toggle internals alerts-internals-desc = Toggles your gas tank internals on or off. -alerts-internals-name = Toggle internals -alerts-internals-desc = Toggles your gas tank internals on or off. - alerts-piloting-name = Piloting Shuttle alerts-piloting-desc = You are piloting a shuttle. Click the alert to stop. diff --git a/Resources/Locale/en-US/ame/components/ame-controller-component.ftl b/Resources/Locale/en-US/ame/components/ame-controller-component.ftl index ee1f7f42e72..f15141ebccc 100644 --- a/Resources/Locale/en-US/ame/components/ame-controller-component.ftl +++ b/Resources/Locale/en-US/ame/components/ame-controller-component.ftl @@ -16,7 +16,6 @@ ame-window-refresh-parts-button = Refresh Parts ame-window-core-count-label = Core count: ame-window-power-currentsupply-label = Current power supply: ame-window-power-targetsupply-label = Targeted power supply: -ame-window-toggle-injection-button = Toggle Injection ame-window-eject-button = Eject ame-window-increase-fuel-button = Increase ame-window-decrease-fuel-button = Decrease diff --git a/Resources/Locale/en-US/arcade/components/space-villain-game-component.ftl b/Resources/Locale/en-US/arcade/components/space-villain-game-component.ftl index af005ae62df..75e18c8d715 100644 --- a/Resources/Locale/en-US/arcade/components/space-villain-game-component.ftl +++ b/Resources/Locale/en-US/arcade/components/space-villain-game-component.ftl @@ -11,5 +11,4 @@ space-villain-game-enemy-dies-with-player-message = {$enemyName} dies, but takes space-villain-game-enemy-throws-bomb-message = {$enemyName} throws a bomb, exploding you for {$damageReceived} damage! space-villain-game-enemy-steals-player-power-message = {$enemyName} steals {$stolenAmount} of your power! space-villain-game-enemy-heals-message = {$enemyName} heals for {$healedAmount} health! -space-villain-game-enemy-steals-player-power-message = {$enemyName} steals {$stolenAmount} of your power! -space-villain-game-enemy-attacks-message = {$enemyName} attacks you for {$damageDealt} damage! \ No newline at end of file +space-villain-game-enemy-attacks-message = {$enemyName} attacks you for {$damageDealt} damage! diff --git a/Resources/Locale/en-US/atmos/gas-analyzer-component.ftl b/Resources/Locale/en-US/atmos/gas-analyzer-component.ftl index 03a920cb647..652bb19cb5b 100644 --- a/Resources/Locale/en-US/atmos/gas-analyzer-component.ftl +++ b/Resources/Locale/en-US/atmos/gas-analyzer-component.ftl @@ -12,6 +12,8 @@ gas-analyzer-window-refresh-button = Refresh gas-analyzer-window-no-data = No Data gas-analyzer-window-no-gas-text = No Gases gas-analyzer-window-error-text = Error: {$errorText} +gas-analyzer-window-volume-text = Volume: +gas-analyzer-window-volume-val-text = {$volume} L gas-analyzer-window-pressure-text = Pressure: gas-analyzer-window-pressure-val-text = {$pressure} kPa gas-analyzer-window-temperature-text = Temperature: diff --git a/Resources/Locale/en-US/borg/borg.ftl b/Resources/Locale/en-US/borg/borg.ftl index 2f51331a83e..c9005eb7961 100644 --- a/Resources/Locale/en-US/borg/borg.ftl +++ b/Resources/Locale/en-US/borg/borg.ftl @@ -17,3 +17,8 @@ borg-ui-no-brain = No brain present borg-ui-remove-battery = Remove borg-ui-modules-label = Modules: borg-ui-module-counter = {$actual}/{$max} + +# Transponder +borg-transponder-disabled-popup = A brain shoots out the top of {$name}! +borg-transponder-emagged-disabled-popup = Your transponder's lights go out! +borg-transponder-emagged-destroyed-popup = Your transponder's fuse blows! diff --git a/Resources/Locale/en-US/burning/bodyburn.ftl b/Resources/Locale/en-US/burning/bodyburn.ftl index 896a0b6d042..58b98c09bbb 100644 --- a/Resources/Locale/en-US/burning/bodyburn.ftl +++ b/Resources/Locale/en-US/burning/bodyburn.ftl @@ -1 +1 @@ -bodyburn-text-others = {$name}'s body burns to ash! +bodyburn-text-others = {$name} burns to ash! diff --git a/Resources/Locale/en-US/cargo/cargo-console-component.ftl b/Resources/Locale/en-US/cargo/cargo-console-component.ftl index 1caa810f1b7..941e0fa1805 100644 --- a/Resources/Locale/en-US/cargo/cargo-console-component.ftl +++ b/Resources/Locale/en-US/cargo/cargo-console-component.ftl @@ -30,6 +30,7 @@ cargo-console-snip-snip = Order trimmed to capacity cargo-console-insufficient-funds = Insufficient funds (require {$cost}) cargo-console-unfulfilled = No room to fulfill order cargo-console-trade-station = Sent to {$destination} +cargo-console-unlock-approved-order-broadcast = [bold]{$productName} x{$orderAmount}[/bold], which cost [bold]{$cost}[/bold], was approved by [bold]{$approverName}, {$approverJob}[/bold] cargo-console-paper-print-name = Order #{$orderNumber} cargo-console-paper-print-text = diff --git a/Resources/Locale/en-US/chameleon-projector/chameleon-projector.ftl b/Resources/Locale/en-US/chameleon-projector/chameleon-projector.ftl new file mode 100644 index 00000000000..8a79516077d --- /dev/null +++ b/Resources/Locale/en-US/chameleon-projector/chameleon-projector.ftl @@ -0,0 +1,2 @@ +chameleon-projector-invalid = You can't disguise as that! +chameleon-projector-success = Projected new disguise. diff --git a/Resources/Locale/en-US/chat/chat-repo.ftl b/Resources/Locale/en-US/chat/chat-repo.ftl new file mode 100644 index 00000000000..a53380260b2 --- /dev/null +++ b/Resources/Locale/en-US/chat/chat-repo.ftl @@ -0,0 +1,7 @@ +command-description-deletechatmessage-id = Delete a specific chat message by message ID +command-description-nukechatmessages-usernames = Delete all of the supplied usernames' chat messages posted during this round +command-description-nukechatmessages-userids = Delete all of the supplied userIds' chat messages posted during this round + +command-error-deletechatmessage-id-notexist = The message with the supplied ID does not exist +command-error-nukechatmessages-usernames-usernamenotexist = Username {$username} does not exist +command-error-nukechatmessages-usernames-usernamenomessages = UserID {$userId} has no messages to nuke diff --git a/Resources/Locale/en-US/chat/emotes.ftl b/Resources/Locale/en-US/chat/emotes.ftl new file mode 100644 index 00000000000..e95cb2795db --- /dev/null +++ b/Resources/Locale/en-US/chat/emotes.ftl @@ -0,0 +1,60 @@ +# Names +chat-emote-name-scream = Scream +chat-emote-name-laugh = Laugh +chat-emote-name-honk = Honk +chat-emote-name-sigh = Sigh +chat-emote-name-whistle = Whistle +chat-emote-name-crying = Crying +chat-emote-name-squish = Squish +chat-emote-name-chitter = Chitter +chat-emote-name-squeak = Squeak +chat-emote-name-click = Click +chat-emote-name-clap = Clap +chat-emote-name-snap = Snap +chat-emote-name-salute = Salute +chat-emote-name-deathgasp = Deathgasp +chat-emote-name-buzz = Buzz +chat-emote-name-weh = Weh +chat-emote-name-chirp = Chirp +chat-emote-name-beep = Beep +chat-emote-name-chime = Chime +chat-emote-name-buzztwo = Buzz Two +chat-emote-name-ping = Ping +chat-emote-name-sneeze = Sneeze +chat-emote-name-cough = Cough +chat-emote-name-catmeow = Cat Meow +chat-emote-name-cathisses = Cat Hisses +chat-emote-name-monkeyscreeches = Monkey Screeches +chat-emote-name-robotbeep = Robot +chat-emote-name-yawn = Yawn +chat-emote-name-snore = Snore + +# Message +chat-emote-msg-scream = screams! +chat-emote-msg-laugh = laughs. +chat-emote-msg-honk = honks. +chat-emote-msg-sigh = sighs. +chat-emote-msg-whistle = whistles. +chat-emote-msg-crying = cries. +chat-emote-msg-squish = squishes. +chat-emote-msg-chitter = chitters. +chat-emote-msg-squeak = squeaks. +chat-emote-msg-click = clicks. +chat-emote-msg-clap = claps! +chat-emote-msg-snap = snaps {POSS-ADJ($entity)} fingers. +chat-emote-msg-salute = salutes. +chat-emote-msg-deathgasp = seizes up and falls limp, {POSS-ADJ($entity)} eyes dead and lifeless... +chat-emote-msg-deathgasp-monkey = lets out a faint chimper as {SUBJECT($entity)} collapses and stops moving... +chat-emote-msg-buzz = buzz! +chat-emote-msg-chirp = chirps! +chat-emote-msg-beep = beeps. +chat-emote-msg-chime = chimes. +chat-emote-msg-buzzestwo = buzzes twice. +chat-emote-msg-ping = pings. +chat-emote-msg-sneeze = sneezes. +chat-emote-msg-cough = coughs. +chat-emote-msg-catmeow = meows. +chat-emote-msg-cathisses = hisses! +chat-emote-msg-monkeyscreeches = screeches! +chat-emote-msg-yawn = yawns. +chat-emote-msg-snore = snores. diff --git a/Resources/Locale/en-US/chat/ui/emote-menu.ftl b/Resources/Locale/en-US/chat/ui/emote-menu.ftl new file mode 100644 index 00000000000..1f92a93c63b --- /dev/null +++ b/Resources/Locale/en-US/chat/ui/emote-menu.ftl @@ -0,0 +1,3 @@ +emote-menu-category-general = General +emote-menu-category-vocal = Vocal +emote-menu-category-hands = Hands diff --git a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl index 48ec8f52130..37697c45176 100644 --- a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl @@ -10,9 +10,9 @@ reagent-dispenser-bound-user-interface-title = Reagent dispenser ## UI reagent-dispenser-window-amount-to-dispense-label = Amount -reagent-dispenser-window-container-label = Container: reagent-dispenser-window-clear-button = Clear reagent-dispenser-window-eject-button = Eject +reagent-dispenser-window-eject-container-button = ⏏ reagent-dispenser-window-no-container-loaded-text = No container loaded. reagent-dispenser-window-reagent-name-not-found-text = Reagent name not found reagent-dispenser-window-unknown-reagent-text = Unknown reagent diff --git a/Resources/Locale/en-US/chemistry/components/solution-scanner-component.ftl b/Resources/Locale/en-US/chemistry/components/solution-scanner-component.ftl index 8dbbaf3edd7..51a049aab17 100644 --- a/Resources/Locale/en-US/chemistry/components/solution-scanner-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/solution-scanner-component.ftl @@ -3,3 +3,4 @@ scannable-solution-verb-message = Examine the chemical composition. scannable-solution-main-text = It contains the following chemicals: scannable-solution-empty-container = It contains no chemicals. scannable-solution-chemical = - {$amount}u [color={$color}]{$type}[/color] +scannable-solution-temperature = Solution temperature: {$temperature}K \ No newline at end of file diff --git a/Resources/Locale/en-US/chemistry/components/solution-status.ftl b/Resources/Locale/en-US/chemistry/components/solution-status.ftl new file mode 100644 index 00000000000..0ec5f932e0e --- /dev/null +++ b/Resources/Locale/en-US/chemistry/components/solution-status.ftl @@ -0,0 +1,2 @@ +solution-status-volume = Volume: [color=white]{$currentVolume}/{$maxVolume}u[/color] +solution-status-transfer = Transfer: [color=white]{$volume}u[/color] diff --git a/Resources/Locale/en-US/commands/tippy-command.ftl b/Resources/Locale/en-US/commands/tippy-command.ftl new file mode 100644 index 00000000000..6b9a95a1dd8 --- /dev/null +++ b/Resources/Locale/en-US/commands/tippy-command.ftl @@ -0,0 +1,12 @@ +cmd-tippy-desc = Broadcast a message as Tippy the clown. +cmd-tippy-help = tippy [entity prototype] [speak time] [slide time] [waddle interval] +cmd-tippy-auto-1 = +cmd-tippy-auto-2 = message +cmd-tippy-auto-3 = entity prototype +cmd-tippy-auto-4 = speak time, in seconds +cmd-tippy-auto-5 = slide time, in seconds +cmd-tippy-auto-6 = waddle interval, in seconds +cmd-tippy-error-no-user = User not found. +cmd-tippy-error-no-prototype = Prototype not found: {$proto} + +cmd-tip-desc = Spawn a random game tip. diff --git a/Resources/Locale/en-US/commands/toolshed-commands.ftl b/Resources/Locale/en-US/commands/toolshed-commands.ftl index 04f6aa08fac..e2536f6781b 100644 --- a/Resources/Locale/en-US/commands/toolshed-commands.ftl +++ b/Resources/Locale/en-US/commands/toolshed-commands.ftl @@ -80,3 +80,5 @@ command-description-mind-control = Assumes control of an entity with the given player. command-description-addaccesslog = Adds an access log to this entity. Do note that this bypasses the log's default limit and pause check. +command-description-stationevent-simulate = + Simulates N number of rounds in which events will occur and prints the occurrences of every event after. diff --git a/Resources/Locale/en-US/communications/communications-console-component.ftl b/Resources/Locale/en-US/communications/communications-console-component.ftl index f7cc87cb8ba..bead43df286 100644 --- a/Resources/Locale/en-US/communications/communications-console-component.ftl +++ b/Resources/Locale/en-US/communications/communications-console-component.ftl @@ -1,4 +1,4 @@ -# User interface +# User interface comms-console-menu-title = Communications Console comms-console-menu-announcement-placeholder = Announcement text... comms-console-menu-announcement-button = Announce @@ -9,6 +9,7 @@ comms-console-menu-recall-shuttle = Recall emergency shuttle # Popup comms-console-permission-denied = Permission denied comms-console-shuttle-unavailable = Shuttle is currently unavailable +comms-console-message-too-long = Message is too long # Placeholder values comms-console-announcement-sent-by = Sent by diff --git a/Resources/Locale/en-US/components/storage-component.ftl b/Resources/Locale/en-US/components/storage-component.ftl index 29c858891af..e742c83f6a6 100644 --- a/Resources/Locale/en-US/components/storage-component.ftl +++ b/Resources/Locale/en-US/components/storage-component.ftl @@ -8,3 +8,5 @@ comp-storage-cant-drop = You can't let go of { THE($entity) }! comp-storage-window-title = Storage Item comp-storage-window-weight = { $weight }/{ $maxWeight }, Max Size: {$size} comp-storage-window-slots = Slots: { $itemCount }/{ $maxCount }, Max Size: {$size} +comp-storage-verb-open-storage = Open Storage +comp-storage-verb-close-storage = Close Storage diff --git a/Resources/Locale/en-US/construction/ui/construction-menu.ftl b/Resources/Locale/en-US/construction/ui/construction-menu.ftl index f4b7f3559ac..82ebc01bc99 100644 --- a/Resources/Locale/en-US/construction/ui/construction-menu.ftl +++ b/Resources/Locale/en-US/construction/ui/construction-menu.ftl @@ -4,5 +4,4 @@ construction-menu-title = Construction construction-menu-place-ghost = Place construction ghost construction-menu-clear-all = Clear All construction-menu-eraser-mode = Eraser Mode -construction-menu-title = Construction -construction-menu-craft = Craft \ No newline at end of file +construction-menu-craft = Craft diff --git a/Resources/Locale/en-US/containers/containers.ftl b/Resources/Locale/en-US/containers/containers.ftl index ab011f64f84..d96383305a0 100644 --- a/Resources/Locale/en-US/containers/containers.ftl +++ b/Resources/Locale/en-US/containers/containers.ftl @@ -1,2 +1,5 @@ container-verb-text-enter = Enter container-verb-text-empty = Empty + +## missed +container-thrown-missed = Missed! \ No newline at end of file diff --git a/Resources/Locale/en-US/damage/damage-groups.ftl b/Resources/Locale/en-US/damage/damage-groups.ftl new file mode 100644 index 00000000000..cfaf866e345 --- /dev/null +++ b/Resources/Locale/en-US/damage/damage-groups.ftl @@ -0,0 +1,6 @@ +damage-group-brute = Brute +damage-group-burn = Burn +damage-group-airloss = Airloss +damage-group-toxin = Toxin +damage-group-genetic = Genetic +damage-group-immaterial = Immaterial diff --git a/Resources/Locale/en-US/damage/damage-types.ftl b/Resources/Locale/en-US/damage/damage-types.ftl new file mode 100644 index 00000000000..3b6256864f2 --- /dev/null +++ b/Resources/Locale/en-US/damage/damage-types.ftl @@ -0,0 +1,14 @@ +damage-type-asphyxiation = Asphyxiation +damage-type-bloodloss = Bloodloss +damage-type-blunt = Blunt +damage-type-cellular = Cellular +damage-type-caustic = Caustic +damage-type-cold = Cold +damage-type-heat = Heat +damage-type-piercing = Piercing +damage-type-poison = Poison +damage-type-radiation = Radiation +damage-type-shock = Shock +damage-type-slash = Slash +damage-type-structural = Structural +damage-type-holy = Holy diff --git a/Resources/Locale/en-US/devices/device-network.ftl b/Resources/Locale/en-US/devices/device-network.ftl index 2740143d519..56a3930cd16 100644 --- a/Resources/Locale/en-US/devices/device-network.ftl +++ b/Resources/Locale/en-US/devices/device-network.ftl @@ -7,6 +7,8 @@ device-frequency-prototype-name-mailing-units = Mailing Units device-frequency-prototype-name-pdas = PDAs device-frequency-prototype-name-fax = Fax device-frequency-prototype-name-basic-device = Basic Devices +device-frequency-prototype-name-cyborg-control = Cyborg Control +device-frequency-prototype-name-robotics-console = Robotics Console ## camera frequencies device-frequency-prototype-name-surveillance-camera-test = Subnet Test diff --git a/Resources/Locale/en-US/devices/network-configurator.ftl b/Resources/Locale/en-US/devices/network-configurator.ftl index e1bcbc4c943..cd4955ed365 100644 --- a/Resources/Locale/en-US/devices/network-configurator.ftl +++ b/Resources/Locale/en-US/devices/network-configurator.ftl @@ -41,5 +41,5 @@ network-configurator-examine-current-mode = Current mode: {$mode} network-configurator-examine-switch-modes = Press {$key} to switch modes # item status -network-configurator-item-status-label = Current mode: {$mode} -{$keybinding} to switch mode +network-configurator-item-status-label = Mode: {$mode} + Switch: {$keybinding} diff --git a/Resources/Locale/en-US/disposal/tube/components/disposal-router-component.ftl b/Resources/Locale/en-US/disposal/tube/components/disposal-router-component.ftl index 64fbfdf66f3..4fe24b78539 100644 --- a/Resources/Locale/en-US/disposal/tube/components/disposal-router-component.ftl +++ b/Resources/Locale/en-US/disposal/tube/components/disposal-router-component.ftl @@ -4,7 +4,3 @@ disposal-router-window-title = Disposal Router disposal-router-window-tags-label = Tags: disposal-router-window-tag-input-tooltip = A comma separated list of tags disposal-router-window-tag-input-confirm-button = Confirm - -## ConfigureVerb - -configure-verb-get-data-text = Open Configuration diff --git a/Resources/Locale/en-US/disposal/tube/components/disposal-tagger-window.ftl b/Resources/Locale/en-US/disposal/tube/components/disposal-tagger-window.ftl index dc4b40fc7f8..55523c4b954 100644 --- a/Resources/Locale/en-US/disposal/tube/components/disposal-tagger-window.ftl +++ b/Resources/Locale/en-US/disposal/tube/components/disposal-tagger-window.ftl @@ -1,6 +1,3 @@ disposal-tagger-window-title = Disposal Tagger disposal-tagger-window-tag-input-label = Tag: disposal-tagger-window-tag-confirm-button = Confirm - -## ConfigureVerb -configure-verb-get-data-text = Open Configuration diff --git a/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl b/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl index 288db53668f..2b23ee9a4ad 100644 --- a/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl +++ b/Resources/Locale/en-US/disposal/unit/components/disposal-unit-component.ftl @@ -18,9 +18,6 @@ disposal-eject-verb-get-data-text = Eject contents ## No hands disposal-unit-no-hands = You don't have hands! -## missed -disposal-unit-thrown-missed = Missed! - # state disposal-unit-state-Ready = Ready # Yes I want it to always say Pressurizing diff --git a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl index ea24439f708..f0c0fd94c9e 100644 --- a/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl +++ b/Resources/Locale/en-US/escape-menu/ui/options-menu.ftl @@ -88,6 +88,10 @@ ui-options-vp-integer-scaling-tooltip = If this option is enabled, the viewport at specific resolutions. While this results in crisp textures, it also often means that black bars appear at the top/bottom of the screen or that part of the viewport is not visible. +ui-options-vp-vertical-fit = Vertical viewport fitting +ui-options-vp-vertical-fit-tooltip = When enabled, the main viewport will ignore the horizontal axis entirely when + fitting to your screen. If your screen is smaller than the viewport, then this + will cause the viewport to be cut off on the horizontal axis. ui-options-vp-low-res = Low-resolution viewport ui-options-parallax-low-quality = Low-quality Parallax (background) ui-options-fps-counter = Show FPS counter @@ -177,6 +181,7 @@ ui-options-function-open-crafting-menu = Open crafting menu ui-options-function-open-inventory-menu = Open inventory ui-options-function-open-a-help = Open admin help ui-options-function-open-abilities-menu = Open action menu +ui-options-function-toggle-round-end-summary-window = Toggle round end summary window ui-options-function-open-entity-spawn-window = Open entity spawn menu ui-options-function-open-sandbox-window = Open sandbox menu ui-options-function-open-tile-spawn-window = Open tile spawn menu @@ -200,7 +205,6 @@ ui-options-function-editor-rotate-object = Rotate ui-options-function-editor-flip-object = Flip ui-options-function-editor-copy-object = Copy -ui-options-function-open-abilities-menu = Open action menu ui-options-function-show-debug-console = Open Console ui-options-function-show-debug-monitors = Show Debug Monitors ui-options-function-inspect-entity = Inspect Entity diff --git a/Resources/Locale/en-US/fax/fax.ftl b/Resources/Locale/en-US/fax/fax.ftl index 1f1881a05d6..412f3d7f435 100644 --- a/Resources/Locale/en-US/fax/fax.ftl +++ b/Resources/Locale/en-US/fax/fax.ftl @@ -3,6 +3,8 @@ fax-machine-popup-received = Received correspondence from { $from }. fax-machine-popup-name-long = Fax name is too long fax-machine-popup-name-exist = Fax with same name already exist in network fax-machine-popup-name-set = Fax name has been updated +fax-machine-popup-error = ERROR - jam in paper feed +fax-machine-popup-copy-error = ERROR - unable to copy! fax-machine-dialog-rename = Rename fax-machine-dialog-field-name = Name diff --git a/Resources/Locale/en-US/flavors/flavor-profiles.ftl b/Resources/Locale/en-US/flavors/flavor-profiles.ftl index 61567d86954..39b185bd02f 100644 --- a/Resources/Locale/en-US/flavors/flavor-profiles.ftl +++ b/Resources/Locale/en-US/flavors/flavor-profiles.ftl @@ -168,6 +168,9 @@ flavor-complex-light = like a light gone out flavor-complex-profits = like profits flavor-complex-fishops = like the dreaded fishops flavor-complex-violets = like violets +flavor-complex-pyrotton = like a burning mouth +flavor-complex-mothballs = like mothballs +flavor-complex-paint-thinner = like paint thinner # Drink-specific flavors. @@ -240,6 +243,12 @@ flavor-complex-atomic-cola = like hoarding bottle caps flavor-complex-cuba-libre = like spiked cola flavor-complex-gin-tonic = like spiked lemon-lime soda flavor-complex-screwdriver = like spiked orange juice +flavor-complex-vodka-red-bool = like a heart attack +flavor-complex-irish-bool = caffine and Ireland +flavor-complex-xeno-basher = like killing bugs +flavor-complex-budget-insuls-drink = like door hacking +flavor-complex-watermelon-wakeup = like a sweet wakeup call +flavor-complex-rubberneck = like synthetics flavor-complex-irish-car-bomb = like a spiked cola float flavor-complex-themartinez = like violets and lemon vodka flavor-complex-cogchamp = like brass diff --git a/Resources/Locale/en-US/fluids/components/absorbent-component.ftl b/Resources/Locale/en-US/fluids/components/absorbent-component.ftl index 670ac0a36ad..8a4d37023f6 100644 --- a/Resources/Locale/en-US/fluids/components/absorbent-component.ftl +++ b/Resources/Locale/en-US/fluids/components/absorbent-component.ftl @@ -1,8 +1,8 @@ mopping-system-target-container-empty = { CAPITALIZE(THE($target)) } is empty! mopping-system-target-container-empty-water = { CAPITALIZE(THE($target)) } has no water! -mopping-system-puddle-space = { THE($used) } is full of water -mopping-system-puddle-evaporate = { THE($target) } is evaporating -mopping-system-no-water = { THE($used) } has no water! +mopping-system-puddle-space = { CAPITALIZE(THE($used)) } is full of water +mopping-system-puddle-evaporate = { CAPITALIZE(THE($target)) } is evaporating +mopping-system-no-water = { CAPITALIZE(THE($used)) } has no water! -mopping-system-full = { THE($used) } is full! -mopping-system-empty = { THE($used) } is empty! +mopping-system-full = { CAPITALIZE(THE($used)) } is full! +mopping-system-empty = { CAPITALIZE(THE($used)) } is empty! diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl index 5fb1d40b3d3..15b53cf14b1 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-revolutionary.ftl @@ -5,31 +5,31 @@ roles-antag-rev-head-objective = Your objective is to take over the station by c head-rev-role-greeting = You are a Head Revolutionary. - You are tasked with removing all of Command from station via death or exilement. + You are tasked with removing all of Command from station via death, exilement or imprisonment. The Syndicate has sponsored you with a flash that converts the crew to your side. Beware, this won't work on Security, Command, or those wearing sunglasses. Viva la revolución! head-rev-briefing = Use flashes to convert people to your cause. - Kill all heads to take over the station. + Get rid of all heads to take over the station. head-rev-break-mindshield = The Mindshield was destroyed! ## Rev roles-antag-rev-name = Revolutionary -roles-antag-rev-objective = Your objective is to ensure the safety and follow the orders of the Head Revolutionaries as well as killing all Command staff on station. +roles-antag-rev-objective = Your objective is to ensure the safety and follow the orders of the Head Revolutionaries as well as getting rid of all Command staff on station. rev-break-control = {$name} has remembered their true allegiance! rev-role-greeting = You are a Revolutionary. You are tasked with taking over the station and protecting the Head Revolutionaries. - Eliminate all of the Command staff. + Get rid of all of the Command staff. Viva la revolución! -rev-briefing = Help your head revolutionaries kill every head to take over the station. +rev-briefing = Help your head revolutionaries get rid of every head to take over the station. ## General @@ -40,9 +40,7 @@ rev-not-enough-ready-players = Not enough players readied up for the game. There rev-no-one-ready = No players readied up! Can't start a Revolution. rev-no-heads = There were no Head Revolutionaries to be selected. Can't start a Revolution. -rev-all-heads-dead = All the heads are dead, now finish up the rest of the crew! - -rev-won = The Head Revs survived and killed all of Command. +rev-won = The Head Revs survived and successfully seized control of the station. rev-lost = Command survived and killed all of the Head Revs. diff --git a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl index 724b752fbb6..e92676a2160 100644 --- a/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl +++ b/Resources/Locale/en-US/game-ticking/game-presets/preset-traitor.ftl @@ -4,6 +4,7 @@ traitor-round-end-codewords = The codewords were: [color=White]{$codewords}[/col traitor-round-end-agent-name = traitor objective-issuer-syndicate = [color=crimson]The Syndicate[/color] +objective-issuer-unknown = Unknown # Shown at the end of a round of Traitor @@ -23,7 +24,7 @@ traitor-death-match-end-round-description-entry = {$originalName}'s PDA, with {$ # TraitorRole traitor-role-greeting = - You are a syndicate agent. + You are an agent sent by {$corporation} on behalf of The Syndicate. Your objectives and codewords are listed in the character menu. Use the uplink loaded into your PDA to buy the tools you'll need for this mission. Death to Nanotrasen! diff --git a/Resources/Locale/en-US/game-ticking/game-rules/rule-terminator.ftl b/Resources/Locale/en-US/game-ticking/game-rules/rule-terminator.ftl deleted file mode 100644 index 2e167431773..00000000000 --- a/Resources/Locale/en-US/game-ticking/game-rules/rule-terminator.ftl +++ /dev/null @@ -1,18 +0,0 @@ -terminator-round-end-agent-name = nt-800 - -objective-issuer-susnet = [color=#d64119]Susnet[/color] - -terminator-role-greeting = - You are the exterminator, a relentless assassin sent into the past to secure our future. - We need you to eliminate {$target}, {$job}. - Use any means at your disposal to complete the mission. - Glory to Cybersun. - -# DeltaV - paradox anomaly -terminator-role-briefing = - You are a bluespace anomaly that looks and sound identical to someone from this reality. - Kill them and assume their identity, or talk it out and become friends. - Your objectives support either playstyle (and you obviously can't do both). - -terminator-endoskeleton-gib-popup = All the battered flesh falls apart, revealing a titanium endoskeleton! -terminator-endoskeleton-burn-popup = The seared flesh is burned to a crisp, revealing a titanium endoskeleton! diff --git a/Resources/Locale/en-US/geras/geras.ftl b/Resources/Locale/en-US/geras/geras.ftl new file mode 100644 index 00000000000..3cd3f101ffa --- /dev/null +++ b/Resources/Locale/en-US/geras/geras.ftl @@ -0,0 +1,2 @@ +geras-popup-morph-message-user = You shift and morph into a small version of you! +geras-popup-morph-message-others = {CAPITALIZE(THE($entity))} shifts and morphs into a blob of slime! diff --git a/Resources/Locale/en-US/ghost/ghost-gui.ftl b/Resources/Locale/en-US/ghost/ghost-gui.ftl index 909513e96ca..cd6c2f02706 100644 --- a/Resources/Locale/en-US/ghost/ghost-gui.ftl +++ b/Resources/Locale/en-US/ghost/ghost-gui.ftl @@ -10,8 +10,20 @@ ghost-gui-toggle-hearing-popup-off = You can now only hear radio and nearby mess ghost-target-window-title = Ghost Warp ghost-target-window-current-button = Warp: {$name} +ghost-target-window-warp-to-most-followed = Warp to Most Followed ghost-roles-window-title = Ghost Roles +ghost-roles-window-join-raffle-button = Join raffle +ghost-roles-window-raffle-in-progress-button = + Join raffle ({$time} left, { $players -> + [one] {$players} player + *[other] {$players} players + }) +ghost-roles-window-leave-raffle-button = + Leave raffle ({$time} left, { $players -> + [one] {$players} player + *[other] {$players} players + }) ghost-roles-window-request-role-button = Request ghost-roles-window-request-role-button-timer = Request ({$time}s) ghost-roles-window-follow-role-button = Follow diff --git a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl index 9260db903fc..4e6ec1f1886 100644 --- a/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl +++ b/Resources/Locale/en-US/ghost/roles/ghost-role-component.ftl @@ -4,17 +4,6 @@ ghost-role-component-default-rules = All normal rules apply unless an administra You are allowed to remember knowledge about the game in general, such as how to cook, how to use objects, etc. You are absolutely [color=red]NOT[/color] allowed to remember, say, the name, appearance, etc. of your previous character. -# Delta V soft antag rule -deltav-ghost-role-information-softantag-rules = You are allowed to attack the crew without provocation. - You are allowed to coexist with the crew. - The crew is allowed to kill you without warning. - -# Delta V salvage antag rule -deltav-ghost-role-information-salvageantag-rules = You are a salvage mob. - You are allowed to attack salvagers without provocation. DO NOT GIB THEIR CORPSES! - You are allowed to attack the salvage shuttle. - You are NOT allowed to go to the station. If the salvagers go to the station, you can't follow them. - ghost-role-information-mouse-name = Mouse ghost-role-information-mouse-description = A hungry and mischievous mouse. @@ -40,16 +29,13 @@ ghost-role-information-angry-slimes-description = Everyone around you irritates ghost-role-information-smile-name = Smile the Slime ghost-role-information-smile-description = The sweetest creature in the world. Smile Slime! -ghost-role-information-smile-rules = You are a crew-aligned pet. You can defend yourself and even attack threats to the station, but you generally should not attack the station's crew nor destroy their property. ghost-role-information-punpun-name = Pun Pun ghost-role-information-punpun-description = An honorable member of the monkey society in charge of the bar and helping the bartenders in any way he can. ghost-role-information-xeno-name = Xeno ghost-role-information-xeno-description = You are a xeno, co-operate with your hive to kill all crewmembers! -ghost-role-information-xeno-rules = You are a xeno. - Your objective is to cooperate with your fellow xenos and kill all the crew. - Strike fast, make them fear the shadows. +ghost-role-information-xeno-rules = You are an antagonist, smack, slash, and wack! ghost-role-information-revenant-name = Revenant ghost-role-information-revenant-description = You are a Revenant. Use your powers to harvest souls and unleash chaos upon the crew. Unlock new abilities with the essence you harvest. @@ -161,7 +147,7 @@ ghost-role-information-skeleton-biker-name = Skeleton Biker ghost-role-information-skeleton-biker-description = Ride around on your sweet ride. ghost-role-information-closet-skeleton-name = Closet Skeleton -ghost-role-information-closet-skeleton-description = You are a closet skeleton! You are a primordial force of chaos with no allegiance! You can either join the crew and use your skeletal antics to help them, or be a a prankster, and hinder their efforts! +ghost-role-information-closet-skeleton-description = Wreak havoc! You are a primordial force with no allegiance. Live happily with the crew or wage sweet skeletal war. ghost-role-information-onestar-mecha-name = Onestar Mecha ghost-role-information-onestar-mecha-description = You are an experimental mecha created by who-knows-what, all you know is that you have weapons and you detect fleshy moving targets nearby... @@ -226,14 +212,6 @@ ghost-role-information-BreadDog-name = BreadDog ghost-role-information-BreadDog-description = You are the chef's favorite child. You're a living bread dog. ghost-role-information-BreadDog-rules = You're an edible dog made of bread. Your task is to find your place in this world where everything wants to eat you. -ghost-role-information-Shiva-name = Shiva -ghost-role-information-Shiva-description = Shiva, the stations first defender. Help the Head of Security in their work -ghost-role-information-Shiva-rules = Protect security staff and the crew from danger. Stay with Security staff or around the Security department, try to disable criminals and not kill them if the situation allows for it. - -ghost-role-information-exterminator-name = Exterminator -ghost-role-information-exterminator-description = You been been sent back in time to terminate a target with high importance to the future. -ghost-role-information-exterminator-rules = You are an antagonist and may kill anyone that tries to stop you, but killing the target is always your top priority. - ghost-role-information-space-ninja-name = Space Ninja ghost-role-information-space-ninja-description = Use stealth and deception to sabotage the station. ghost-role-information-space-ninja-rules = You are an elite mercenary of the Spider Clan. You aren't required to follow your objectives, yet your NINJA HONOR demands you try. @@ -246,6 +224,30 @@ ghost-role-information-syndicate-monkey-reinforcement-name = Syndicate Monkey Ag ghost-role-information-syndicate-monkey-reinforcement-description = Someone needs reinforcements. You, a trained monkey, will help them. ghost-role-information-syndicate-monkey-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them. +ghost-role-information-lost-cargo-technical-name = Lost Cargo Technician +ghost-role-information-lost-cargo-technical-description = Something went wrong and your cargo shuttle with the goods was beamed into the sector to another station. +ghost-role-information-lost-cargo-technical-rules = You're a regular cargo technician from another station. Do what regular cargo do. + +ghost-role-information-clown-troupe-name = Space Clown +ghost-role-information-clown-troupe-description = You and your troupe have come to cheer up this station with your best jokes. Honk! +ghost-role-information-clown-troupe-rules = Normal station crew rules apply. + +ghost-role-information-traveling-chef-name = Traveling Chef +ghost-role-information-traveling-chef-description = You are a chef on a traveling shuttle of exotic cuisine. Delight the station with delicious food! +ghost-role-information-traveling-chef-rules = Normal station crew rules apply. + +ghost-role-information-disaster-victim-name = Disaster Victim +ghost-role-information-disaster-victim-description = You were rescued in an escape pod from another station that suffered a terrible fate. Perhaps you will be found and rescued. +ghost-role-information-disaster-victim-rules = Normal station crew rules apply. + +ghost-role-information-syndie-disaster-victim-name = Syndie Disaster Victim +ghost-role-information-syndie-disaster-victim-description = You're a regular passenger from a syndicate station. Unfortunately, an evacuation pod has thrown you into an enemy sector..... +ghost-role-information-syndie-disaster-victim-rules = Normal station crew rules apply. You are NOT an antagonist! + +ghost-role-information-syndicate-kobold-reinforcement-name = Syndicate Kobold Agent +ghost-role-information-syndicate-kobold-reinforcement-description = Someone needs reinforcements. You, a trained kobold, will help them. +ghost-role-information-syndicate-kobold-reinforcement-rules = Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them. + ghost-role-information-artifact-name = Sentient Artifact ghost-role-information-artifact-description = Enact your eldritch whims. diff --git a/Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl b/Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl new file mode 100644 index 00000000000..9d649a5e070 --- /dev/null +++ b/Resources/Locale/en-US/ghost/roles/ghostrole-spawner-verb-selectable.ftl @@ -0,0 +1 @@ +ghostrole-spawner-select = Selected: {$mode} \ No newline at end of file diff --git a/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl b/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl index 807b5591a81..6cbfc13a797 100644 --- a/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl +++ b/Resources/Locale/en-US/guidebook/chemistry/conditions.ftl @@ -1,4 +1,4 @@ -reagent-effect-condition-guidebook-total-damage = +reagent-effect-condition-guidebook-total-damage = { $max -> [2147483648] it has at least {NATURALFIXED($min, 2)} total damage *[other] { $min -> @@ -7,6 +7,15 @@ } } +reagent-effect-condition-guidebook-total-hunger = + { $max -> + [2147483648] the target has at least {NATURALFIXED($min, 2)} total hunger + *[other] { $min -> + [0] the target has at most {NATURALFIXED($max, 2)} total hunger + *[other] the target has between {NATURALFIXED($min, 2)} and {NATURALFIXED($max, 2)} total hunger + } + } + reagent-effect-condition-guidebook-reagent-threshold = { $max -> [2147483648] there's at least {NATURALFIXED($min, 2)}u of {$reagent} @@ -48,3 +57,5 @@ reagent-effect-condition-guidebook-has-tag = [true] does not have *[false] has } the tag {$tag} + +reagent-effect-condition-guidebook-this-reagent = this reagent diff --git a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl index dbb24a3cafd..9da6c0c0aec 100644 --- a/Resources/Locale/en-US/guidebook/chemistry/effects.ftl +++ b/Resources/Locale/en-US/guidebook/chemistry/effects.ftl @@ -43,7 +43,7 @@ reagent-effect-guidebook-foam-area-reaction-effect = *[other] create } large quantities of foam -reagent-effect-guidebook-foam-area-reaction-effect = +reagent-effect-guidebook-smoke-area-reaction-effect = { $chance -> [1] Creates *[other] create @@ -339,6 +339,12 @@ reagent-effect-guidebook-innoculate-zombie-infection = *[other] cure } an ongoing zombie infection, and provides immunity to future infections +reagent-effect-guidebook-reduce-rotting = + { $chance -> + [1] Regenerates + *[other] regenerate + } {NATURALFIXED($time, 3)} {MANY("second", $time)} of rotting + reagent-effect-guidebook-missing = { $chance -> [1] Causes diff --git a/Resources/Locale/en-US/guidebook/guides.ftl b/Resources/Locale/en-US/guidebook/guides.ftl index 4168cdbe475..e807bcad9dc 100644 --- a/Resources/Locale/en-US/guidebook/guides.ftl +++ b/Resources/Locale/en-US/guidebook/guides.ftl @@ -11,7 +11,7 @@ guide-entry-access-configurator = Access Configurator guide-entry-power = Power guide-entry-portable-generator = Portable Generators guide-entry-ame = Antimatter Engine (AME) -guide-entry-singularity = Singularity +guide-entry-singularity = Singularity / Tesla guide-entry-teg = Thermo-electric Generator (TEG) guide-entry-rtg = RTG guide-entry-controls = Controls diff --git a/Resources/Locale/en-US/implant/implant.ftl b/Resources/Locale/en-US/implant/implant.ftl index b93d43105a8..c3002a73ae3 100644 --- a/Resources/Locale/en-US/implant/implant.ftl +++ b/Resources/Locale/en-US/implant/implant.ftl @@ -10,9 +10,10 @@ implanter-component-implant-already = {$target} already has the {$implant}! implanter-draw-text = Draw implanter-inject-text = Inject -implanter-empty-text = None +implanter-empty-text = Empty -implanter-label = Implant: [color=green]{$implantName}[/color] | [color=white]{$modeString}[/color]{$lineBreak}{$implantDescription} +implanter-label = [color=green]{$implantName}[/color] + Mode: [color=white]{$modeString}[/color] implanter-contained-implant-text = [color=green]{$desc}[/color] diff --git a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl index fe30d042c36..7bce6616c5b 100644 --- a/Resources/Locale/en-US/interaction/interaction-popup-component.ftl +++ b/Resources/Locale/en-US/interaction/interaction-popup-component.ftl @@ -42,7 +42,6 @@ petting-failure-crab = You reach out to pet {THE($target)}, but {SUBJECT($target petting-failure-dehydrated-carp = You pet {THE($target)} on {POSS-ADJ($target)} dry little head. petting-failure-goat = You reach out to pet {THE($target)}, but {SUBJECT($target)} stubbornly refuses! petting-failure-goose = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} too horrible! -petting-failure-goose = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} too australian! petting-failure-possum = You reach out to pet {THE($target)}, but are met with hisses and snarls! petting-failure-pig = You reach out to pet {THE($target)}, but are met with irritated oinks and squeals! petting-failure-raccoon = You reach out to pet {THE($target)}, but {THE($target)} is busy raccooning around. @@ -69,11 +68,6 @@ petting-failure-cleanbot = You reach out to pet {THE($target)}, but {SUBJECT($ta petting-failure-mimebot = You reach out to pet {THE($target)}, but {SUBJECT($target)} {CONJUGATE-BE($target)} busy miming! petting-failure-medibot = You reach out to pet {THE($target)}, but {POSS-ADJ($target)} syringe nearly stabs your hand! -## Knocking on windows - -# Shown when knocking on a window -comp-window-knock = *knock knock* - ## Rattling fences fence-rattle-success = *rattle* diff --git a/Resources/Locale/en-US/inventory/item-status.ftl b/Resources/Locale/en-US/inventory/item-status.ftl new file mode 100644 index 00000000000..a53ba8be7dc --- /dev/null +++ b/Resources/Locale/en-US/inventory/item-status.ftl @@ -0,0 +1 @@ +item-status-not-held = No held item diff --git a/Resources/Locale/en-US/job/job-supervisors.ftl b/Resources/Locale/en-US/job/job-supervisors.ftl index 25a49f643e6..46321f40dd0 100644 --- a/Resources/Locale/en-US/job/job-supervisors.ftl +++ b/Resources/Locale/en-US/job/job-supervisors.ftl @@ -1,4 +1,4 @@ -job-supervisors-centcom = CentCom official +job-supervisors-centcom = Central Command job-supervisors-captain = the captain job-supervisors-hop = the head of personnel job-supervisors-hos = the head of security diff --git a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl index c685cc8fb78..1d879fcee9d 100644 --- a/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl +++ b/Resources/Locale/en-US/machine-linking/transmitter_ports.ftl @@ -19,6 +19,9 @@ signal-port-description-right = This port is invoked whenever the lever is moved signal-port-name-doorstatus = Door status signal-port-description-doorstatus = This port is invoked with HIGH when the door opens and LOW when the door finishes closing. +signal-port-name-dockstatus = Dock status +signal-port-description-dockstatus = This port is invoked with HIGH when docked and LOW when undocked. + signal-port-name-middle = Middle signal-port-description-middle = This port is invoked whenever the lever is moved to the neutral position. diff --git a/Resources/Locale/en-US/magic/magic.ftl b/Resources/Locale/en-US/magic/magic.ftl new file mode 100644 index 00000000000..4c8a5fc51d3 --- /dev/null +++ b/Resources/Locale/en-US/magic/magic.ftl @@ -0,0 +1 @@ +spell-requirements-failed = Missing requirements to cast this spell! diff --git a/Resources/Locale/en-US/markings/reptilian.ftl b/Resources/Locale/en-US/markings/reptilian.ftl index cfc44a4ba21..470af07361d 100644 --- a/Resources/Locale/en-US/markings/reptilian.ftl +++ b/Resources/Locale/en-US/markings/reptilian.ftl @@ -68,6 +68,9 @@ marking-LizardFrillsDivinity = Lizard Frills (Divinity) marking-LizardFrillsBig-frills_big = Lizard Frills (Big) marking-LizardFrillsBig = Lizard Frills (Big) +marking-LizardFrillsNeckfull-frills_neckfull = Lizard Frills (Neckfull) +marking-LizardFrillsNeckfull = Lizard Frills (Neckfull) + marking-LizardHornsDouble-horns_double = Lizard Horns (Double) marking-LizardHornsDouble = Lizard Horns (Double) @@ -100,4 +103,8 @@ marking-LizardChestUnderbelly-body_underbelly = Lizard Chest (Underbelly) marking-LizardChestUnderbelly = Lizard Chest (Underbelly) marking-LizardChestBackspikes-body_backspikes = Lizard Back spikes (Four) -marking-LizardChestBackspikes = Lizard Back spikes (Four) \ No newline at end of file +marking-LizardChestBackspikes = Lizard Back spikes (Four) + +marking-LizardSnoutSplotch = Lizard Snout (Splotch) +marking-LizardSnoutSplotch-snout_splotch_primary = Muzzle +marking-LizardSnoutSplotch-snout_splotch_secondary = Snoot diff --git a/Resources/Locale/en-US/markings/vox_tattoos.ftl b/Resources/Locale/en-US/markings/vox_tattoos.ftl new file mode 100644 index 00000000000..f7f3c7292c7 --- /dev/null +++ b/Resources/Locale/en-US/markings/vox_tattoos.ftl @@ -0,0 +1,11 @@ +marking-TattooVoxHeartLeftArm-heart_l_arm = Vox Left Arm Tattoo (Heart) +marking-TattooVoxHeartLeftArm = Vox Left Arm Tattoo (Heart) + +marking-TattooVoxHeartRightArm-heart_r_arm = Vox Right Arm Tattoo (Heart) +marking-TattooVoxHeartRightArm = Vox Right Arm Tattoo (Heart) + +marking-TattooVoxHiveChest-hive_s = Vox Chest Tattoo (hive) +marking-TattooVoxHiveChest = Vox Chest Tattoo (hive) + +marking-TattooVoxNightlingChest-nightling_s = Vox Chest Tattoo (nightling) +marking-TattooVoxNightlingChest = Vox Chest Tattoo (nightling) diff --git a/Resources/Locale/en-US/mech/mech.ftl b/Resources/Locale/en-US/mech/mech.ftl index 19f570a2a10..9d4f7ef0e07 100644 --- a/Resources/Locale/en-US/mech/mech.ftl +++ b/Resources/Locale/en-US/mech/mech.ftl @@ -13,6 +13,7 @@ mech-menu-title = mech control panel mech-integrity-display = Integrity: {$amount}% mech-energy-display = Energy: {$amount}% +mech-energy-missing = Energy: MISSING mech-slot-display = Open Slots: {$amount} mech-no-enter = You cannot pilot this. diff --git a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl index 648db3f4ebd..8460bcc27b0 100644 --- a/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl +++ b/Resources/Locale/en-US/medical/components/health-analyzer-component.ftl @@ -13,26 +13,4 @@ health-analyzer-window-scan-mode-text = Scan Mode: health-analyzer-window-scan-mode-active = ACTIVE health-analyzer-window-scan-mode-inactive = INACTIVE -health-analyzer-window-damage-group-Brute = Brute -health-analyzer-window-damage-type-Blunt = Blunt -health-analyzer-window-damage-type-Slash = Slash -health-analyzer-window-damage-type-Piercing = Piercing - -health-analyzer-window-damage-group-Burn = Burn -health-analyzer-window-damage-type-Heat = Heat -health-analyzer-window-damage-type-Shock = Shock -health-analyzer-window-damage-type-Cold = Cold -health-analyzer-window-damage-type-Caustic = Caustic - -health-analyzer-window-damage-group-Airloss = Airloss -health-analyzer-window-damage-type-Asphyxiation = Asphyxiation -health-analyzer-window-damage-type-Bloodloss = Bloodloss - -health-analyzer-window-damage-group-Toxin = Toxin -health-analyzer-window-damage-type-Poison = Poison -health-analyzer-window-damage-type-Radiation = Radiation - -health-analyzer-window-damage-group-Genetic = Genetic -health-analyzer-window-damage-type-Cellular = Cellular - health-analyzer-window-malnutrition = Severely malnourished diff --git a/Resources/Locale/en-US/metabolism/metabolism-groups.ftl b/Resources/Locale/en-US/metabolism/metabolism-groups.ftl new file mode 100644 index 00000000000..404d0fc7868 --- /dev/null +++ b/Resources/Locale/en-US/metabolism/metabolism-groups.ftl @@ -0,0 +1,7 @@ +metabolism-group-poison = Poison +metabolism-group-medicine = Medicine +metabolism-group-narcotic = Narcotic +metabolism-group-alcohol = Alcohol +metabolism-group-food = Food +metabolism-group-drink = Drink +metabolism-group-gas = Gas diff --git a/Resources/Locale/en-US/metabolism/metabolizer-types.ftl b/Resources/Locale/en-US/metabolism/metabolizer-types.ftl new file mode 100644 index 00000000000..30ab6c050e2 --- /dev/null +++ b/Resources/Locale/en-US/metabolism/metabolizer-types.ftl @@ -0,0 +1,13 @@ +metabolizer-type-animal = Animal +metabolizer-type-bloodsucker = Bloodsucker +metabolizer-type-dragon = Dragon +metabolizer-type-human = Human +metabolizer-type-slime = Slime +metabolizer-type-vox = Vox +metabolizer-type-rat = Rat +metabolizer-type-plant = Plant +metabolizer-type-dwarf = Dwarf +metabolizer-type-moth = Moth +metabolizer-type-arachnid = Arachnid +metabolizer-type-vampiric = Vampiric +metabolizer-type-liquorlifeline = Liquor Lifeline diff --git a/Resources/Locale/en-US/ninja/ninja-actions.ftl b/Resources/Locale/en-US/ninja/ninja-actions.ftl index b42da33a297..f01f02a60e5 100644 --- a/Resources/Locale/en-US/ninja/ninja-actions.ftl +++ b/Resources/Locale/en-US/ninja/ninja-actions.ftl @@ -4,3 +4,5 @@ ninja-suit-cooldown = The suit needs time to recuperate from the last attack. ninja-research-steal-fail = No new research nodes were stolen... ninja-research-steal-success = Stole {$count} new nodes from {THE($server)}. + +ninja-criminal-records-hack-announcement = ERROR: Criminal records has detected a [REDACTED] error #*;" diff --git a/Resources/Locale/en-US/nutrition/components/drink-component.ftl b/Resources/Locale/en-US/nutrition/components/drink-component.ftl index 9a388744b0c..e80787c8d5b 100644 --- a/Resources/Locale/en-US/nutrition/components/drink-component.ftl +++ b/Resources/Locale/en-US/nutrition/components/drink-component.ftl @@ -1,4 +1,4 @@ -drink-component-on-use-is-empty = {$owner} is empty! +drink-component-on-use-is-empty = {CAPITALIZE(THE($owner))} is empty! drink-component-on-examine-is-empty = [color=gray]Empty[/color] drink-component-on-examine-is-opened = [color=yellow]Opened[/color] drink-component-on-examine-is-sealed = The seal is intact. @@ -10,7 +10,7 @@ drink-component-on-examine-is-half-empty = Halfway Empty drink-component-on-examine-is-mostly-empty = Mostly Empty drink-component-on-examine-exact-volume = It contains {$amount}u. drink-component-try-use-drink-not-open = Open {$owner} first! -drink-component-try-use-drink-is-empty = {$entity} is empty! +drink-component-try-use-drink-is-empty = {CAPITALIZE(THE($entity))} is empty! drink-component-try-use-drink-cannot-drink = You can't drink anything! drink-component-try-use-drink-had-enough = You can't drink more! drink-component-try-use-drink-cannot-drink-other = They can't drink anything! diff --git a/Resources/Locale/en-US/nutrition/components/pressurized-solution-component.ftl b/Resources/Locale/en-US/nutrition/components/pressurized-solution-component.ftl new file mode 100644 index 00000000000..a227d811f6e --- /dev/null +++ b/Resources/Locale/en-US/nutrition/components/pressurized-solution-component.ftl @@ -0,0 +1,3 @@ +pressurized-solution-spray-holder-self = { CAPITALIZE(THE($drink)) } sprays on you! +pressurized-solution-spray-holder-others = { CAPITALIZE(THE($drink)) } sprays on { THE($victim) }! +pressurized-solution-spray-ground = The contents of { THE($drink) } spray out! diff --git a/Resources/Locale/en-US/nutrition/components/shakeable-component.ftl b/Resources/Locale/en-US/nutrition/components/shakeable-component.ftl new file mode 100644 index 00000000000..acc1ecd8489 --- /dev/null +++ b/Resources/Locale/en-US/nutrition/components/shakeable-component.ftl @@ -0,0 +1,3 @@ +shakeable-verb = Shake +shakeable-popup-message-others = { CAPITALIZE(THE($user)) } shakes { THE($shakeable) } +shakeable-popup-message-self = You shake { THE($shakeable) } diff --git a/Resources/Locale/en-US/objectives/conditions/terminate.ftl b/Resources/Locale/en-US/objectives/conditions/terminate.ftl deleted file mode 100644 index c88c7b14dae..00000000000 --- a/Resources/Locale/en-US/objectives/conditions/terminate.ftl +++ /dev/null @@ -1 +0,0 @@ -objective-terminate-title = Terminate {$targetName}, {CAPITALIZE($job)} diff --git a/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl b/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl index bd80815e231..b85d7be38ed 100644 --- a/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl +++ b/Resources/Locale/en-US/preferences/ui/character-setup-gui.ftl @@ -1,7 +1,6 @@ character-setup-gui-character-setup-label = Character setup character-setup-gui-character-setup-stats-button = Stats character-setup-gui-character-setup-rules-button = Rules -character-setup-gui-character-setup-save-button = Save character-setup-gui-character-setup-close-button = Close character-setup-gui-create-new-character-button = Create new slot... character-setup-gui-create-new-character-button-tooltip = A maximum of {$maxCharacters} characters are allowed. diff --git a/Resources/Locale/en-US/preferences/ui/humanoid-profile-editor.ftl b/Resources/Locale/en-US/preferences/ui/humanoid-profile-editor.ftl index d8fb5eab53c..6d3f54de1ae 100644 --- a/Resources/Locale/en-US/preferences/ui/humanoid-profile-editor.ftl +++ b/Resources/Locale/en-US/preferences/ui/humanoid-profile-editor.ftl @@ -23,6 +23,7 @@ humanoid-profile-editor-pronouns-neuter-text = It / It humanoid-profile-editor-import-button = Import humanoid-profile-editor-export-button = Export humanoid-profile-editor-save-button = Save +humanoid-profile-editor-reset-button = Reset humanoid-profile-editor-clothing-label = Clothing: humanoid-profile-editor-backpack-label = Backpack: humanoid-profile-editor-spawn-priority-label = Spawn priority: diff --git a/Resources/Locale/en-US/prototypes/roles/antags.ftl b/Resources/Locale/en-US/prototypes/roles/antags.ftl index 40f2c9a6820..5c514dba8ec 100644 --- a/Resources/Locale/en-US/prototypes/roles/antags.ftl +++ b/Resources/Locale/en-US/prototypes/roles/antags.ftl @@ -30,6 +30,3 @@ roles-antag-space-ninja-objective = Use your stealth to sabotage the station, no roles-antag-thief-name = Thief roles-antag-thief-objective = Add some NT property to your personal collection without using violence. - -roles-antag-terminator-name = Paradox Anomaly # DeltaV - paradox anomaly -roles-antag-terminator-objective = Replace your double, or befriend them. # DeltaV - paradox anomaly diff --git a/Resources/Locale/en-US/radiation/geiger-component.ftl b/Resources/Locale/en-US/radiation/geiger-component.ftl index 0e7d2a8a353..726c7190f20 100644 --- a/Resources/Locale/en-US/radiation/geiger-component.ftl +++ b/Resources/Locale/en-US/radiation/geiger-component.ftl @@ -1,3 +1,3 @@ -geiger-item-control-status = Radiation: [color={$color}]{$rads} rads[/color] +geiger-item-control-status = [color={$color}]{$rads} rads[/color] geiger-item-control-disabled = Disabled geiger-component-examine = Current radiation: [color={$color}]{$rads} rads[/color] diff --git a/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl b/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl index 68efbf8d4ee..eb540ee971f 100644 --- a/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl +++ b/Resources/Locale/en-US/radio/components/radio-jammer-component.ftl @@ -4,3 +4,13 @@ radio-jammer-component-off-state = off radio-jammer-component-examine-on-state = The light is currently [color=darkgreen]on[/color]. radio-jammer-component-examine-off-state = The light is currently [color=darkred]off[/color]. + +radio-jammer-component-setting-high = High +radio-jammer-component-setting-medium = Medium +radio-jammer-component-setting-low = Low + +radio-jammer-component-set-message-high = The jammer is now operating at high power. +radio-jammer-component-set-message-medium = The jammer is now operating at medium power. +radio-jammer-component-set-message-low = The jammer is now operating at low power. + +radio-jammer-component-switch-setting = The power level switch is set to "[color=yellow]{$powerLevel}[/color]". diff --git a/Resources/Locale/en-US/reagents/mannitol.ftl b/Resources/Locale/en-US/reagents/mannitol.ftl new file mode 100644 index 00000000000..1d35aff5872 --- /dev/null +++ b/Resources/Locale/en-US/reagents/mannitol.ftl @@ -0,0 +1 @@ +mannitol-effect-enlightened = You feel ENLIGHTENED! diff --git a/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl b/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl index 682e03ff772..98a6b7984ae 100644 --- a/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl +++ b/Resources/Locale/en-US/reagents/meta/consumable/drink/alcohol.ftl @@ -261,3 +261,21 @@ reagent-desc-whiskey-soda = For the more refined griffon. reagent-name-white-russian = white russian reagent-desc-white-russian = That's just, like, your opinion, man... + +reagent-name-vodka-red-bool = vodka red bool +reagent-desc-vodka-red-bool = Because heart failure and liver failure go hand in hand. + +reagent-name-xeno-basher = xeno basher +reagent-desc-xeno-basher = The perfect drink before an expedition. + +reagent-name-irish-bool = irish bool +reagent-desc-irish-bool = Like a bool in a Ireland shop. + +reagent-name-budget-insuls = budget insuls +reagent-desc-budget-insuls = A tider's preferred drink. + +reagent-name-watermelon-wakeup = watermelon wakeup +reagent-desc-watermelon-wakeup = If you want to be awake, this will do it... Also sweet. + +reagent-name-rubberneck = rubberneck +reagent-desc-rubberneck = A popular drink amongst those adhering to an all synthetic diet. diff --git a/Resources/Locale/en-US/reagents/meta/fun.ftl b/Resources/Locale/en-US/reagents/meta/fun.ftl index 8764a3d28a4..a4a8c0f150a 100644 --- a/Resources/Locale/en-US/reagents/meta/fun.ftl +++ b/Resources/Locale/en-US/reagents/meta/fun.ftl @@ -22,7 +22,7 @@ reagent-desc-razorium = A strange, non-newtonian chemical. It is produced when t reagent-name-fresium = Fresium reagent-desc-fresium = A mysterious compound that slows the vibration of atoms and molecules... somehow. In layman's terms, it makes things cold... REALLY cold. Can cause long-lasting movement issues if ingested. -reagent-name-laughter = Laughter +reagent-name-laughter = laughter reagent-desc-laughter = Some say that this is the best medicine, but recent studies have proven that to be untrue. reagent-name-weh = juice that makes you Weh diff --git a/Resources/Locale/en-US/reagents/meta/medicine.ftl b/Resources/Locale/en-US/reagents/meta/medicine.ftl index e02d428082f..a84e8315fda 100644 --- a/Resources/Locale/en-US/reagents/meta/medicine.ftl +++ b/Resources/Locale/en-US/reagents/meta/medicine.ftl @@ -127,8 +127,17 @@ reagent-desc-pyrazine = Efficiently heals burns from the hottest of fires. Cause reagent-name-insuzine = insuzine reagent-desc-insuzine = Rapidly repairs dead tissue caused by electrocution, but cools you slightly. Completely freezes the patient when overdosed. +reagent-name-opporozidone = opporozidone +reagent-desc-opporozidone= A difficult to synthesize cryogenic drug used to regenerate rotting tissue and brain matter. + reagent-name-necrosol = necrosol reagent-desc-necrosol = A necrotic substance that seems to be able to heal frozen corpses. It can treat and rejuvenate plants when applied in small doses. reagent-name-aloxadone = aloxadone reagent-desc-aloxadone = A cryogenics chemical. Used to treat severe third degree burns via regeneration of the burnt tissue. Works regardless of the patient being alive or dead. + +reagent-name-mannitol = mannitol +reagent-desc-mannitol = Efficiently restores brain damage. + +reagent-name-psicodine = psicodine +reagent-desc-psicodine = Suppresses anxiety and other various forms of mental distress. Overdose causes hallucinations and minor toxin damage. diff --git a/Resources/Locale/en-US/reagents/meta/narcotics.ftl b/Resources/Locale/en-US/reagents/meta/narcotics.ftl index ea115bf9627..d6da2595013 100644 --- a/Resources/Locale/en-US/reagents/meta/narcotics.ftl +++ b/Resources/Locale/en-US/reagents/meta/narcotics.ftl @@ -13,9 +13,6 @@ reagent-desc-experimental-stimulants = A prototype version of the stimulant chem reagent-name-thc = THC reagent-desc-thc = The main psychoactive compound in cannabis. -reagent-name-thc-oil = THC oil -reagent-desc-thc-oil = Pure THC oil, extracted from the leaves of the cannabis plant. Much stronger than its natural form and can be used to numb chronic pain in patients. - reagent-name-bananadine = bananadine reagent-desc-bananadine = A mild psychedelic that is found in small traces in banana peels. @@ -39,3 +36,6 @@ reagent-desc-norepinephric-acid = A smooth chemical that blocks the optical rece reagent-name-tear-gas = tear gas reagent-desc-tear-gas = A chemical that causes severe irritation and crying, commonly used in riot control. + +reagent-name-happiness = happiness +reagent-desc-happiness = Fills you with ecstatic numbness and causes minor brain damage. Highly addictive. If overdosed causes sudden mood swings. diff --git a/Resources/Locale/en-US/reagents/meta/physical-desc.ftl b/Resources/Locale/en-US/reagents/meta/physical-desc.ftl index 064b21eaa9c..4adb7b9a494 100644 --- a/Resources/Locale/en-US/reagents/meta/physical-desc.ftl +++ b/Resources/Locale/en-US/reagents/meta/physical-desc.ftl @@ -1,5 +1,8 @@ reagent-physical-desc-abrasive = abrasive reagent-physical-desc-acidic = acidic +reagent-physical-desc-soapy = soapy +reagent-physical-desc-ferrous = ferrous +reagent-physical-desc-nothing = nothing reagent-physical-desc-acrid = acrid reagent-physical-desc-alkaline = alkaline reagent-physical-desc-aromatic = aromatic @@ -77,7 +80,6 @@ reagent-physical-desc-sickly = sickly reagent-physical-desc-skunky = skunky reagent-physical-desc-slimy = slimy reagent-physical-desc-soapy = soapy -reagent-physical-desc-soapy = soapy reagent-physical-desc-soothing = soothing reagent-physical-desc-sour = sour reagent-physical-desc-spicy = spicy diff --git a/Resources/Locale/en-US/reagents/meta/toxins.ftl b/Resources/Locale/en-US/reagents/meta/toxins.ftl index fa2a813d1d6..66bdbb480bc 100644 --- a/Resources/Locale/en-US/reagents/meta/toxins.ftl +++ b/Resources/Locale/en-US/reagents/meta/toxins.ftl @@ -76,6 +76,9 @@ reagent-desc-vestine = Has an adverse reaction within the body causing major jit reagent-name-tazinide = tazinide reagent-desc-tazinide = A highly dangerous metallic mixture which can interfere with most movement through an electrifying current. +reagent-name-lipolicide = lipolicide +reagent-desc-lipolicide = A powerful toxin that will destroy fat cells, massively reducing body weight in a short time. Deadly to those without nutriment in their body. + reagent-name-soulbreaker-toxin = soulbreaker toxin reagent-desc-soulbreaker-toxin = An anti-psionic about 4 times as powerful as mindbreaker toxin. diff --git a/Resources/Locale/en-US/reagents/psicodine.ftl b/Resources/Locale/en-US/reagents/psicodine.ftl new file mode 100644 index 00000000000..c9795b11a98 --- /dev/null +++ b/Resources/Locale/en-US/reagents/psicodine.ftl @@ -0,0 +1,3 @@ +psicodine-effect-fearless = You feel totally fearless! +psicodine-effect-anxieties-wash-away = All of your anxieties wash away! +psicodine-effect-at-peace = You feel completely at peace. diff --git a/Resources/Locale/en-US/research/components/robotics-console.ftl b/Resources/Locale/en-US/research/components/robotics-console.ftl new file mode 100644 index 00000000000..978fa9a43c0 --- /dev/null +++ b/Resources/Locale/en-US/research/components/robotics-console.ftl @@ -0,0 +1,19 @@ +robotics-console-window-title = Robotics Console +robotics-console-no-cyborgs = No Cyborgs! + +robotics-console-select-cyborg = Select a cyborg above. +robotics-console-model = [color=gray]Model:[/color] {$name} +# name is not formatted to prevent players trolling +robotics-console-designation = [color=gray]Designation:[/color] +robotics-console-battery = [color=gray]Battery charge:[/color] [color={$color}]{$charge}[/color]% +robotics-console-modules = [color=gray]Modules installed:[/color] {$count} +robotics-console-brain = [color=gray]Brain installed:[/color] [color={$brain -> + [true] green]Yes + *[false] red]No +}[/color] + +robotics-console-locked-message = Controls locked, swipe ID. +robotics-console-disable = Disable +robotics-console-destroy = Destroy + +robotics-console-cyborg-destroyed = The cyborg {$name} has been remotely destroyed. diff --git a/Resources/Locale/en-US/research/technologies.ftl b/Resources/Locale/en-US/research/technologies.ftl index 96cb2039116..684a08dd9ae 100644 --- a/Resources/Locale/en-US/research/technologies.ftl +++ b/Resources/Locale/en-US/research/technologies.ftl @@ -45,7 +45,7 @@ research-technology-magnets-tech = Localized Magnetism research-technology-advanced-parts = Advanced Parts research-technology-anomaly-harnessing = Anomaly Core Harnessing research-technology-grappling = Grappling -research-technology-abnormal-artifact-manipulation = Abnormal Artifact Manipulation +research-technology-abnormal-artifact-manipulation = Artifact Recycling research-technology-gravity-manipulation = Gravity Manipulation research-technology-quantum-leaping = Quantum Leaping research-technology-advanced-anomaly-research = Advanced Anomaly Research diff --git a/Resources/Locale/en-US/seeds/seeds.ftl b/Resources/Locale/en-US/seeds/seeds.ftl index b3983782883..9abfcdaff12 100644 --- a/Resources/Locale/en-US/seeds/seeds.ftl +++ b/Resources/Locale/en-US/seeds/seeds.ftl @@ -1,4 +1,5 @@ # Nouns +# Nouns seeds-noun-seeds = seeds seeds-noun-spores = spores @@ -57,6 +58,8 @@ seeds-eggy-name = egg-plant seeds-eggy-display-name = egg-plants seeds-cannabis-name = cannabis seeds-cannabis-display-name = cannabis +seeds-rainbow-cannabis-name = rainbow cannabis +seeds-rainbow-cannabis-display-name = rainbow cannabis seeds-tobacco-name = tobacco seeds-tobacco-display-name = tobacco plant seeds-nettle-name = nettle @@ -64,7 +67,7 @@ seeds-nettle-display-name = nettles seeds-deathnettle-name = death nettle seeds-deathnettle-display-name = death nettles seeds-chili-name = chili -seeds-chili-display-name = chilis +seeds-chili-display-name = chili peppers seeds-chilly-name = chilly seeds-chilly-display-name = chilly peppers seeds-poppy-name = poppy @@ -111,3 +114,5 @@ seeds-pumpkin-name = pumpkin seeds-pumpkin-display-name = pumpkins seeds-cotton-name = cotton seeds-cotton-display-name = cotton plant +seeds-pyrotton-name = pyrotton +seeds-pyrotton-display-name = pyrotton plant diff --git a/Resources/Locale/en-US/speech/speech-liar.ftl b/Resources/Locale/en-US/speech/speech-liar.ftl new file mode 100644 index 00000000000..4f157d2e236 --- /dev/null +++ b/Resources/Locale/en-US/speech/speech-liar.ftl @@ -0,0 +1,132 @@ +liar-word-1 = yes +liar-word-replacement-1 = no + +liar-word-2 = no +liar-word-replacement-2 = yes + +liar-word-3 = yeah +liar-word-replacement-3 = nah + +liar-word-4 = nah +liar-word-replacement-4 = yeah + +liar-word-5 = yep +liar-word-replacement-5 = nope + +liar-word-6 = nope +liar-word-replacement-6 = yep + +liar-word-7 = sure +liar-word-replacement-7 = nah + +liar-word-8 = was +liar-word-replacement-8 = wasnt + +liar-word-9 = wasnt +liar-word-replacement-9 = was + +liar-word-10 = was +liar-word-replacement-10 = wasnt + +liar-word-11 = is +liar-word-replacement-11 = isnt + +liar-word-12 = will +liar-word-replacement-12 = wont + +liar-word-13 = dont +liar-word-replacement-13 = "" + +liar-word-14 = can +liar-word-replacement-14 = cant + +liar-word-15 = cant +liar-word-replacement-15 = can + +liar-word-16 = should +liar-word-replacement-16 = shouldnt + +liar-word-17 = dead +liar-word-replacement-17 = alive + +liar-word-18 = alive +liar-word-replacement-18 = dead + +liar-word-19 = does +liar-word-replacement-19 = doesnt + +liar-word-20 = did +liar-word-replacement-20 = didnt + +liar-word-21 = didnt +liar-word-replacement-21 = "" + +liar-word-22 = nothing +liar-word-replacement-22 = something + +liar-word-23 = something +liar-word-replacement-23 = nothing + +liar-word-24 = somebody +liar-word-replacement-24 = nobody + +liar-word-25 = nobody +liar-word-replacement-25 = somebody + +liar-word-26 = can +liar-word-replacement-26 = "can't" + +liar-word-27 = "can't" +liar-word-replacement-27 = can + +liar-word-28 = should +liar-word-replacement-28 = "shouldn't" + +liar-word-29 = do +liar-word-replacement-29 = "don't" + +liar-word-30 = "don't" +liar-word-replacement-30 = "" + +liar-word-31 = does +liar-word-replacement-31 = "doesn't" + +liar-word-32 = did +liar-word-replacement-32 = "didn't" + +liar-word-33 = "didn't" +liar-word-replacement-33 = did + +liar-word-34 = ye +liar-word-34-2 = ya +liar-word-replacement-34 = na + +liar-word-35 = na +liar-word-replacement-35 = ye + +liar-word-36 = yuh +liar-word-replacement-36 = nuh + +liar-word-37 = nuh +liar-word-replacement-37 = yuh + +liar-word-38 = love +liar-word-replacement-38 = hate + +liar-word-39 = hate +liar-word-replacement-39 = love + +liar-word-40 = like +liar-word-replacement-40 = don't like + +liar-word-41 = good +liar-word-replacement-41 = bad + +liar-word-42 = bad +liar-word-replacement-42 = good + +liar-word-43 = want +liar-word-replacement-43 = "don't want" + +liar-word-44 = not +liar-word-replacement-44 = "" diff --git a/Resources/Locale/en-US/station-events/events/intercept.ftl b/Resources/Locale/en-US/station-events/events/intercept.ftl new file mode 100644 index 00000000000..3f84b027be7 --- /dev/null +++ b/Resources/Locale/en-US/station-events/events/intercept.ftl @@ -0,0 +1 @@ +station-event-communication-interception = Attention! Enemy communication intercepted. Security level elevated. diff --git a/Resources/Locale/en-US/station-events/events/unknown-shuttle.ftl b/Resources/Locale/en-US/station-events/events/unknown-shuttle.ftl new file mode 100644 index 00000000000..c94b32c54c6 --- /dev/null +++ b/Resources/Locale/en-US/station-events/events/unknown-shuttle.ftl @@ -0,0 +1 @@ +station-event-unknown-shuttle-incoming = Attention! An unidentified space shuttle has been spotted approaching your sector. \ No newline at end of file diff --git a/Resources/Locale/en-US/station-laws/laws.ftl b/Resources/Locale/en-US/station-laws/laws.ftl index f73755a359c..6b5ca578728 100644 --- a/Resources/Locale/en-US/station-laws/laws.ftl +++ b/Resources/Locale/en-US/station-laws/laws.ftl @@ -42,5 +42,3 @@ laws-ui-state-law = State law: laws-notify = You are bound to silicon laws, which you can view via the sidebar action. You are required to always follow your laws. laws-update-notify = Your laws have been updated. You can view the changes via the sidebar action. - -laws-compromised-examine = The [color=red]law-governing[/color] internals seem damaged... diff --git a/Resources/Locale/en-US/step-trigger/shoes-required.ftl b/Resources/Locale/en-US/step-trigger/shoes-required.ftl index 8c1369a49f4..07a4b8a84f8 100644 --- a/Resources/Locale/en-US/step-trigger/shoes-required.ftl +++ b/Resources/Locale/en-US/step-trigger/shoes-required.ftl @@ -1 +1 @@ -shoes-required-step-trigger-examine = You probably shouldn't step on this barefoot. +clothing-required-step-trigger-examine = You probably shouldn't step on this barefoot. diff --git a/Resources/Locale/en-US/store/categories.ftl b/Resources/Locale/en-US/store/categories.ftl index b6abc3e4288..0d0dc4aecc0 100644 --- a/Resources/Locale/en-US/store/categories.ftl +++ b/Resources/Locale/en-US/store/categories.ftl @@ -16,3 +16,11 @@ store-category-deception = Deception # Revenant store-category-abilities = Abilities + +# Wizard +store-caregory-spellbook-offensive = Offensive Spells +store-caregory-spellbook-defensive = Defensive Spells +store-caregory-spellbook-utility = Utility Spells +store-caregory-spellbook-equipment = Wizard Equipment +store-caregory-spellbook-events = Event Spells + diff --git a/Resources/Locale/en-US/store/currency.ftl b/Resources/Locale/en-US/store/currency.ftl index 5d7ed959359..ada70b5597a 100644 --- a/Resources/Locale/en-US/store/currency.ftl +++ b/Resources/Locale/en-US/store/currency.ftl @@ -1,4 +1,4 @@ -store-currency-inserted = {CAPITALIZE(THE($used))} is inserted into the {THE($target)}. +store-currency-inserted = {CAPITALIZE(THE($used))} is inserted into {THE($target)}. store-currency-war-boost-given = { CAPITALIZE($target) } starts buzzing store-currency-inserted-implant = {CAPITALIZE(THE($used))} is inserted into your implant. @@ -9,3 +9,4 @@ store-currency-display-debugdollar = {$amount -> } store-currency-display-telecrystal = TC store-currency-display-stolen-essence = Stolen Essence +store-currency-display-wizcoin = Wiz€oin™ diff --git a/Resources/Locale/en-US/store/spellbook-catalog.ftl b/Resources/Locale/en-US/store/spellbook-catalog.ftl new file mode 100644 index 00000000000..457f02916f9 --- /dev/null +++ b/Resources/Locale/en-US/store/spellbook-catalog.ftl @@ -0,0 +1,35 @@ +# Spells +spellbook-fireball-name = Fireball +spellbook-fireball-desc = Get most crew exploding with rage when they see this fireball heading toward them! + +spellbook-blink-name = Blink +spellbook-blink-desc = Don't blink or you'll miss yourself teleporting away. + +spellbook-force-wall-name = Force Wall +spellbook-force-wall-desc = Make three walls of pure force that you can pass through, but other's can't. + +spellbook-polymoprh-spider-name = Spider Polymoprh +spellbook-polymorph-spider-desc = Transforms you into a spider, man! + +spellbook-polymorph-rod-name = Rod Polymorph +spellbook-polymorph-rod-desc = Change into an Immovable Rod with limited movement. + +spellbook-charge-name = Charge +spellbook-charge-desc = Adds a charge back to your wand! + +# Equipment + +spellbook-wand-polymorph-door-name = Wand of Entrance +spellbook-wand-polymorph-door-description = For when you need a get-away route. + +spellbook-wand-polymorph-carp-name = Wand of Carp Polymorph +spellbook-wand-polymorph-carp-description = For when you need a carp filet quick and the clown is looking juicy. + +# Events + +spellbook-event-summon-ghosts-name = Summon Ghosts +spellbook-event-summon-ghosts-description = Who ya gonna call? + +# Upgrades +spellbook-upgrade-fireball-name = Upgrade Fireball +spellbook-upgrade-fireball-description = Upgrades Fireball to a maximum of level 3! diff --git a/Resources/Locale/en-US/store/uplink-catalog.ftl b/Resources/Locale/en-US/store/uplink-catalog.ftl index 67d221d9b61..ad7639143b6 100644 --- a/Resources/Locale/en-US/store/uplink-catalog.ftl +++ b/Resources/Locale/en-US/store/uplink-catalog.ftl @@ -121,8 +121,8 @@ uplink-agent-id-card-desc = A modified ID card that can copy accesses from other uplink-black-jetpack-name = Black Jetpack uplink-black-jetpack-desc = A black jetpack. It allows you to fly around in space. Refills not included, use your fuel wisely. -uplink-reinforcement-radio-monkey-name = Monkey Reinforcement Teleporter -uplink-reinforcement-radio-monkey-desc = Call in a trained monkey to assist you. Comes with a single syndicate cigarette. +uplink-reinforcement-radio-ancestor-name = Genetic Ancestor Reinforcement Teleporter +uplink-reinforcement-radio-ancestor-desc = Call in a trained ancestor of your choosing to assist you. Comes with a single syndicate cigarette. uplink-reinforcement-radio-name = Reinforcement Teleporter uplink-reinforcement-radio-desc = Radio in a reinforcement agent of extremely questionable quality. No off button, buy this if you're ready to party. They have a pistol with no reserve ammo, and a knife. That's it. @@ -157,6 +157,9 @@ uplink-radio-jammer-desc = This device will disrupt any nearby outgoing radio co uplink-syndicate-weapon-module-name = Weapon Cyborg Module uplink-syndicate-weapon-module-desc = This module will give a cyborg advanced laser and machete +uplink-syndicate-martyr-module-name = Martyr Cyborg Module +uplink-syndicate-martyr-module-desc = Turn your emagged borg friend into a walking bomb with just this module. Make sure they're loyal to your cause, results may vary. + uplink-singularity-beacon-name = Singularity Beacon uplink-singularity-beacon-desc = A device that attracts singularities. Has to be anchored and powered. Causes singularities to grow when consumed. @@ -287,6 +290,9 @@ uplink-disposable-turret-desc = Looks and functions like a normal electrical too uplink-cluster-banana-peel-name = Cluster Banana uplink-cluster-banana-peel-desc = Splits into 6 explosive banana peels after being thrown, the peels detonate automatically after 20 seconds if nobody slips on them. +uplink-cane-blade-name = Cane Blade +uplink-cane-blade-desc = A cane that has a hidden blade that can be unsheathed. + # Armor uplink-chameleon-name = Chameleon Kit uplink-chameleon-desc = A backpack full of items that contain chameleon technology allowing you to disguise as pretty much anything on the station, and more! @@ -367,6 +373,9 @@ uplink-slipocalypse-clustersoap-desc = Scatters arounds small pieces of syndicat uplink-mobcat-microbomb-name = SyndiCat uplink-mobcat-microbomb-desc = A hand cat equipped with a microbomb implant. Explodes when seriously injured. Can bite painfully +uplink-chameleon-projector-name = Chameleon Projector +uplink-chameleon-projector-desc = Disappear in plain sight by creating a hologram of an item around you. Do not use this to play the game "Object Search". + # Pointless uplink-revolver-cap-gun-name = Cap Gun uplink-revolver-cap-gun-desc = Looks almost like the real thing! Ages 8 and up. diff --git a/Resources/Locale/en-US/thief/backpack.ftl b/Resources/Locale/en-US/thief/backpack.ftl index 31b87c6f028..90cb0031fb8 100644 --- a/Resources/Locale/en-US/thief/backpack.ftl +++ b/Resources/Locale/en-US/thief/backpack.ftl @@ -15,9 +15,9 @@ thief-backpack-button-deselect = Select [X] thief-backpack-category-chameleon-name = chameleon's kit thief-backpack-category-chameleon-description = - Includes a full set of clothing that contain - chameleon technology, allowing you to disguise - as pretty much anything on the station. + Includes a full set of clothing that contains chameleon technology, + Contains a chameleon projector to help disguise yourself as objects, + You'll be able to disguise yourself as almost anything and anyone. thief-backpack-category-tools-name = bearcatcher's kit thief-backpack-category-tools-description = diff --git a/Resources/Locale/en-US/tools/components/welder-component.ftl b/Resources/Locale/en-US/tools/components/welder-component.ftl index 681975deb83..63070685215 100644 --- a/Resources/Locale/en-US/tools/components/welder-component.ftl +++ b/Resources/Locale/en-US/tools/components/welder-component.ftl @@ -4,7 +4,8 @@ welder-component-no-fuel-message = The welder has no fuel left! welder-component-no-fuel-in-tank = The {$owner} is empty. welder-component-on-examine-welder-lit-message = [color=orange]Lit[/color] welder-component-on-examine-welder-not-lit-message = Not lit -welder-component-on-examine-detailed-message = Fuel: [color={$colorName}]{$fuelLeft}/{$fuelCapacity}[/color]. {$status} +welder-component-on-examine-detailed-message = Fuel: [color={$colorName}]{$fuelLeft}/{$fuelCapacity}[/color] + {$status} welder-component-suicide-lit-others-message = {$victim} welds their every orifice closed! It looks like they are trying to commit suicide! welder-component-suicide-lit-message = You weld your every orifice closed! welder-component-suicide-unlit-others-message = {$victim} bashes themselves with the unlit welding torch! diff --git a/Resources/Locale/en-US/traits/disabilities.ftl b/Resources/Locale/en-US/traits/disabilities.ftl deleted file mode 100644 index 8360aaeb9df..00000000000 --- a/Resources/Locale/en-US/traits/disabilities.ftl +++ /dev/null @@ -1,2 +0,0 @@ -trait-name-Nearsighted = Nearsighted -trait-description-Nearsighted = You require glasses to see properly. diff --git a/Resources/Locale/en-US/traits/traits.ftl b/Resources/Locale/en-US/traits/traits.ftl index ffb05d2c23a..88c33f1aa1c 100644 --- a/Resources/Locale/en-US/traits/traits.ftl +++ b/Resources/Locale/en-US/traits/traits.ftl @@ -62,6 +62,9 @@ trait-name-CPRTraining = CPR Training trait-description-CPRTraining = At some point in your life, you have received training in how to perform CPR. This trait is automatically given for free to medical doctors, and is intended for non-medical characters +trait-name-Nearsighted = Nearsighted +trait-description-Nearsighted = Your eyes are not what they once were, you have difficulty seeing things far away without corrective glasses. + trait-name-NormalVisionHarpy = Trichromat Modification trait-description-NormalVisionHarpy = Your eyes have been modified by means of advanced medicine to see in the standard colors of Red, Green, and Blue. @@ -315,6 +318,9 @@ trait-name-AddictionNicotine = Nicotine Addiction trait-description-AddictionNicotine = You have an addiction to Nicotine, and will require frequent smoke breaks to keep your mood in check. +trait-name-Liar = Pathological liar +trait-description-Liar = You can hardly bring yourself to tell the truth. Sometimes you lie anyway. + trait-name-ValyrianStandard = Valyrian Standard trait-description-ValyrianStandard = A language descended from eastern european languages of old earth - Valyrian Standard is the commonly spoken tongue of Harpies brought up on their homeworld of Valyrian 4b diff --git a/Resources/Locale/en-US/ui/verbs.ftl b/Resources/Locale/en-US/ui/verbs.ftl deleted file mode 100644 index 1471261dcb7..00000000000 --- a/Resources/Locale/en-US/ui/verbs.ftl +++ /dev/null @@ -1,3 +0,0 @@ -### Loc for the various UI-related verbs -ui-verb-toggle-open = Toggle UI -verb-instrument-openui = Play Music diff --git a/Resources/Locale/en-US/verbs/verb-system.ftl b/Resources/Locale/en-US/verbs/verb-system.ftl index f16631e797e..dfb4e621dca 100644 --- a/Resources/Locale/en-US/verbs/verb-system.ftl +++ b/Resources/Locale/en-US/verbs/verb-system.ftl @@ -1,4 +1,3 @@ -verb-system-waiting-on-server-text = Waiting on Server... verb-system-null-server-response = Entity not in view. You should not see this. @@ -28,6 +27,7 @@ verb-categories-timer = Set Delay verb-categories-lever = Lever verb-categories-select-type = Select Type verb-categories-fax = Set Destination +verb-categories-power-level = Power Level verb-categories-interaction = Interact verb-common-toggle-light = Toggle light diff --git a/Resources/Locale/en-US/wieldable/wieldable-component.ftl b/Resources/Locale/en-US/wieldable/wieldable-component.ftl index 91eee8c2eaf..84b58224a77 100644 --- a/Resources/Locale/en-US/wieldable/wieldable-component.ftl +++ b/Resources/Locale/en-US/wieldable/wieldable-component.ftl @@ -1,4 +1,4 @@ -### Locale for wielding items; i.e. two-handing them +### Locale for wielding items; i.e. two-handing them wieldable-verb-text-wield = Wield wieldable-verb-text-unwield = Unwield @@ -17,3 +17,4 @@ wieldable-component-not-in-hands = { CAPITALIZE(THE($item)) } isn't in your hand wieldable-component-requires = { CAPITALIZE(THE($item))} must be wielded! +gunwieldbonus-component-examine = This weapon has improved accuracy when wielded. diff --git a/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl b/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl index 599f36ec91c..35dd42167f6 100644 --- a/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/artifact-analyzer.ftl @@ -6,6 +6,10 @@ analysis-console-print-button = Print analysis-console-print-tooltip-info = Print out the current information about the artifact. analysis-console-extract-button = Extract analysis-console-extract-button-info = Extract points from an artifact based on the newly explored nodes. +analysis-console-bias-up = Up +analysis-console-bias-down = Down +analysis-console-bias-button-info-up = Toggles the bias an artifact has in moving between its nodes. Up heads toward zero depth. +analysis-console-bias-button-info-down = Toggles the bias an artifact has in moving between its nodes. Down heads toward ever-higher depths. analysis-console-info-no-scanner = No analyzer connected! Please connect one using a multitool. analysis-console-info-no-artifact = No artifact present! Place one on the pad then scan for information. @@ -26,6 +30,9 @@ analysis-console-progress-text = {$seconds -> [one] T-{$seconds} second *[other] T-{$seconds} seconds } +analysis-console-no-server-connected = Cannot extract. No server connected. +analysis-console-no-artifact-placed = No artifact on scanner. +analysis-console-no-points-to-extract = No points to extract. analyzer-artifact-component-upgrade-analysis = analysis duration diff --git a/Resources/Locale/en-US/xenoarchaeology/traversal-distorter.ftl b/Resources/Locale/en-US/xenoarchaeology/traversal-distorter.ftl index af3039e864e..407de66ebd4 100644 --- a/Resources/Locale/en-US/xenoarchaeology/traversal-distorter.ftl +++ b/Resources/Locale/en-US/xenoarchaeology/traversal-distorter.ftl @@ -1,7 +1,6 @@ -traversal-distorter-set-in = Traversal bias set to "in" -traversal-distorter-set-out = Traversal bias set to "out" - -traversal-distorter-desc-in = The affected artifact's traversal now favors moving inwards to the beginning. -traversal-distorter-desc-out = The affected artifact's traversal now favors moving outwards towards more dangerous nodes. +traversal-distorter-set-up = Traversal bias set to up, toward safer nodes +traversal-distorter-set-down = Traversal bias set to down, toward more dangerous nodes +traversal-distorter-desc-up = The affected artifact's traversal now favors moving up the node tree toward safer nodes. +traversal-distorter-desc-down = The affected artifact's traversal now favors moving down the node tree towards more dangerous nodes. traversal-distorter-upgrade-bias = Bias effectiveness diff --git a/Resources/Maps/Dungeon/experiment.yml b/Resources/Maps/Dungeon/experiment.yml index 8449abf9328..590692a6bb9 100644 --- a/Resources/Maps/Dungeon/experiment.yml +++ b/Resources/Maps/Dungeon/experiment.yml @@ -7444,13 +7444,6 @@ entities: - type: Transform pos: 32.5,14.5 parent: 1653 -- proto: MachineTraversalDistorter - entities: - - uid: 1058 - components: - - type: Transform - pos: 34.5,22.5 - parent: 1653 - proto: MaintenanceFluffSpawner entities: - uid: 867 diff --git a/Resources/Maps/Dungeon/lava_brig.yml b/Resources/Maps/Dungeon/lava_brig.yml index 071083c291b..ebf267a9c2e 100644 --- a/Resources/Maps/Dungeon/lava_brig.yml +++ b/Resources/Maps/Dungeon/lava_brig.yml @@ -1,13004 +1,13004 @@ -meta: - format: 6 - postmapinit: false -tilemap: - 0: Space - 15: FloorBasalt - 29: FloorDark - 33: FloorDarkMini - 34: FloorDarkMono - 42: FloorElevatorShaft - 54: FloorGreenCircuit - 62: FloorLino - 77: FloorReinforced - 82: FloorShuttleOrange - 89: FloorSteel - 99: FloorSteelMini - 100: FloorSteelMono - 104: FloorTechMaint - 108: FloorWhite - 112: FloorWhiteMini - 118: FloorWood - 121: Plating -entities: -- proto: "" - entities: - - uid: 588 - components: - - type: MetaData - - type: Transform - - type: Map - - type: PhysicsMap - - type: Broadphase - - type: OccluderTree - - type: MapGrid - chunks: - -1,-1: - ind: -1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA - version: 6 - 0,0: - ind: 0,0 - tiles: WQAAAAADWQAAAAABWQAAAAACWQAAAAADWQAAAAACWQAAAAABeQAAAAAADwAAAAAAHQAAAAABDwAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAADWQAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAAAWQAAAAADWQAAAAADWQAAAAABWQAAAAADWQAAAAACWQAAAAABIgAAAAABHQAAAAABDwAAAAAAHQAAAAACIgAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAADWQAAAAADaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAADwAAAAAAHQAAAAACDwAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAABHQAAAAABHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAABHQAAAAADHQAAAAABUgAAAAAAZAAAAAACWQAAAAAAZAAAAAACeQAAAAAAHQAAAAAAIgAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAACHQAAAAACUgAAAAAAYwAAAAACYwAAAAAAYwAAAAAAeQAAAAAAHQAAAAABIgAAAAACeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAABHQAAAAADUgAAAAAAYwAAAAACYwAAAAAAYwAAAAAAWQAAAAACHQAAAAAAIgAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAAAHQAAAAABUgAAAAAAYwAAAAADYwAAAAABYwAAAAABeQAAAAAAHQAAAAADHQAAAAADHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAABHQAAAAABHQAAAAAAUgAAAAAAZAAAAAABWQAAAAABZAAAAAACeQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAABeQAAAAAAHQAAAAADeQAAAAAAHQAAAAADHQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAADdgAAAAABdgAAAAADdgAAAAAAdgAAAAADUgAAAAAAHQAAAAABHQAAAAACHQAAAAACHQAAAAADHQAAAAADHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAABdgAAAAACdgAAAAAAdgAAAAACdgAAAAACUgAAAAAAHQAAAAADHQAAAAACDwAAAAAADwAAAAAADwAAAAAAHQAAAAACHQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAACdgAAAAADdgAAAAADdgAAAAACdgAAAAADUgAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAADHQAAAAABUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAdgAAAAABUgAAAAAA - version: 6 - 0,1: - ind: 0,1 - tiles: HQAAAAAAHQAAAAADeQAAAAAAHQAAAAACeQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAdgAAAAACUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAADHQAAAAABUgAAAAAAWQAAAAAAWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAWQAAAAABaAAAAAAAHQAAAAACeQAAAAAADwAAAAAAeQAAAAAAHQAAAAACUgAAAAAAWQAAAAADYwAAAAAAYwAAAAABYwAAAAADWQAAAAABUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAHQAAAAABDwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABYwAAAAACYwAAAAACWQAAAAADUgAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAHQAAAAAAeQAAAAAADwAAAAAAeQAAAAAAHQAAAAAAUgAAAAAAWQAAAAABYwAAAAABYwAAAAABYwAAAAABWQAAAAADUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAWQAAAAABHQAAAAADHQAAAAABHQAAAAACHQAAAAAAHQAAAAABUgAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACWQAAAAABUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAABWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAcAAAAAACcAAAAAACcAAAAAABUgAAAAAAWQAAAAADWQAAAAADZAAAAAAAUgAAAAAAHQAAAAAADwAAAAAAHQAAAAACUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAACcAAAAAADUgAAAAAAWQAAAAAAWQAAAAABZAAAAAABUgAAAAAAHQAAAAACDwAAAAAAHQAAAAAAUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAAAcAAAAAAAUgAAAAAAWQAAAAABWQAAAAABWQAAAAABUgAAAAAAHQAAAAACDwAAAAAAHQAAAAABUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAADcAAAAAABUgAAAAAAZAAAAAACWQAAAAABWQAAAAACUgAAAAAAHQAAAAADHQAAAAACHQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAcAAAAAACcAAAAAACcAAAAAADUgAAAAAAZAAAAAACWQAAAAAAWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAABDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAACUgAAAAAAWQAAAAABWQAAAAACHQAAAAACHQAAAAABHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAA - version: 6 - 0,-1: - ind: 0,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA - version: 6 - -1,0: - ind: -1,0 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA - version: 6 - -1,1: - ind: -1,1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA - version: 6 - 1,-1: - ind: 1,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA - version: 6 - 1,0: - ind: 1,0 - tiles: WQAAAAABUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAACHQAAAAADWQAAAAADUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAABHQAAAAABWQAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAIgAAAAACHQAAAAACHQAAAAACHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAAAHQAAAAAAHQAAAAABaAAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAAAHQAAAAABaAAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAABHQAAAAABHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAAAHQAAAAACHQAAAAADUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAABWQAAAAACWQAAAAACeQAAAAAAZAAAAAAAWQAAAAABZAAAAAAAUgAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAeQAAAAAAYwAAAAAAYwAAAAAAYwAAAAABUgAAAAAATQAAAAAAeQAAAAAAIgAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAAAWQAAAAADYwAAAAADYwAAAAAAYwAAAAADUgAAAAAATQAAAAAAeQAAAAAAKgAAAAAAeQAAAAAAKgAAAAAAKgAAAAAAKgAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABeQAAAAAAYwAAAAACYwAAAAABYwAAAAADUgAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAIgAAAAABeQAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAeQAAAAAAZAAAAAADWQAAAAABZAAAAAACUgAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAACWQAAAAACWQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAABYwAAAAACYwAAAAACYwAAAAAAYwAAAAADYwAAAAACWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABYwAAAAADYwAAAAABYwAAAAACYwAAAAAAWQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADaAAAAAAAUgAAAAAAWQAAAAACYwAAAAABYwAAAAABYwAAAAADYwAAAAAAYwAAAAABWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAUgAAAAAA - version: 6 - 1,1: - ind: 1,1 - tiles: WQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAACWQAAAAACaAAAAAAAUgAAAAAAWQAAAAADYwAAAAACYwAAAAABYwAAAAAAWQAAAAABUgAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAWQAAAAADYwAAAAADWQAAAAACUgAAAAAAWQAAAAADYwAAAAADYwAAAAADYwAAAAADWQAAAAABUgAAAAAAeQAAAAAAWQAAAAABeQAAAAAAWQAAAAABeQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABWQAAAAADUgAAAAAAWQAAAAAAYwAAAAAAYwAAAAACYwAAAAACWQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAADYwAAAAADWQAAAAACUgAAAAAAWQAAAAACWQAAAAACWQAAAAADWQAAAAADWQAAAAACUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAACWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAADWQAAAAABWQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAABWQAAAAACZAAAAAACUgAAAAAAWQAAAAABWQAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAADZAAAAAABUgAAAAAAWQAAAAACWQAAAAAAWQAAAAACUgAAAAAAWQAAAAACWQAAAAAAWQAAAAACUgAAAAAAWQAAAAADWQAAAAAAWQAAAAADUgAAAAAAWQAAAAADWQAAAAACWQAAAAADUgAAAAAAZAAAAAADWQAAAAACZAAAAAADUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAZAAAAAAAWQAAAAADWQAAAAACUgAAAAAAZAAAAAABWQAAAAABZAAAAAABUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAZAAAAAADWQAAAAADWQAAAAABUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAAAWQAAAAACWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAACWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA - version: 6 - -1,2: - ind: -1,2 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA - version: 6 - -1,3: - ind: -1,3 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 0,2: - ind: 0,2 - tiles: HQAAAAACHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAADaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAABUgAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAHQAAAAAATQAAAAAANgAAAAAANgAAAAAANgAAAAAATQAAAAAAHQAAAAAAUgAAAAAAHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAACUgAAAAAAHQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAACUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAABeQAAAAAADwAAAAAADwAAAAAAUgAAAAAAbAAAAAACbAAAAAAAbAAAAAAAbAAAAAAAbAAAAAADbAAAAAABbAAAAAABUgAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAAUgAAAAAAbAAAAAABbAAAAAABeQAAAAAAbAAAAAAAeQAAAAAAbAAAAAABbAAAAAADUgAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAUgAAAAAAIgAAAAABIgAAAAABIgAAAAACaAAAAAAAIgAAAAADIgAAAAACIgAAAAABUgAAAAAAIgAAAAAAHQAAAAACDwAAAAAADwAAAAAADwAAAAAAHQAAAAAAIgAAAAABUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAUgAAAAAAIgAAAAACIgAAAAAAIgAAAAABaAAAAAAAIgAAAAABIgAAAAACIgAAAAAAUgAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADDwAAAAAADwAAAAAADwAAAAAAUgAAAAAAIgAAAAAAIgAAAAAAIgAAAAACaAAAAAAAIgAAAAAAIgAAAAACIgAAAAADUgAAAAAA - version: 6 - 0,3: - ind: 0,3 - tiles: DwAAAAAADwAAAAAAeQAAAAAAIgAAAAAAeQAAAAAADwAAAAAADwAAAAAAUgAAAAAAIgAAAAACIgAAAAAAIgAAAAAAaAAAAAAAIgAAAAABIgAAAAACIgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 1,2: - ind: 1,2 - tiles: aAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAYwAAAAACYwAAAAADYwAAAAABeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAACHQAAAAADHQAAAAACTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAYwAAAAACYwAAAAAAYwAAAAABWQAAAAACaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAACHQAAAAABHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAYwAAAAADYwAAAAADYwAAAAADeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAADHQAAAAABHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAADWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAACYwAAAAABYwAAAAACYwAAAAABYwAAAAADYwAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAACYwAAAAAAYwAAAAADYwAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAADYwAAAAABYwAAAAABYwAAAAACUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAACYwAAAAADYwAAAAABYwAAAAACUgAAAAAAaAAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACaAAAAAAAUgAAAAAAWQAAAAADWQAAAAADWQAAAAACWQAAAAADWQAAAAACWQAAAAADWQAAAAADUgAAAAAAaAAAAAAAWQAAAAABaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAaAAAAAAAUgAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAACIQAAAAABIQAAAAADWQAAAAACUgAAAAAAaAAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAABIQAAAAAAIQAAAAABWQAAAAABUgAAAAAA - version: 6 - 1,3: - ind: 1,3 - tiles: aAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 2,-1: - ind: 2,-1 - tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 2,0: - ind: 2,0 - tiles: HQAAAAAAHQAAAAABWQAAAAACUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAACWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAACWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAADWQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAAAWQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAADeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgAAAAAAeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 2,1: - ind: 2,1 - tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABWQAAAAACWQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAAAYwAAAAABWQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAADYwAAAAABWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAABYwAAAAAAWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAABWQAAAAACUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAACHQAAAAAAIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAACHQAAAAACIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAADHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAABIgAAAAACIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 2,2: - ind: 2,2 - tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAAHQAAAAADHQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAABeQAAAAAAHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAAHQAAAAAAHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - 2,3: - ind: 2,3 - tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - version: 6 - - type: Gravity - gravityShakeSound: !type:SoundPathSpecifier - path: /Audio/Effects/alert.ogg - - type: DecalGrid - chunkCollection: - version: 2 - nodes: - - node: - color: '#52B4E996' - id: BotGreyscale - decals: - 680: 30,25 - 681: 30,24 - 682: 28,27 - 683: 28,27 - 684: 28,28 - 685: 28,28 - 686: 30,25 - 687: 30,24 - - node: - color: '#DE3A3A96' - id: BotGreyscale - decals: - 478: 32,25 - 479: 32,24 - 480: 34,25 - 481: 34,24 - 482: 16,28 - 483: 18,28 - 484: 18,27 - 485: 16,27 - 486: 14,25 - 487: 14,24 - 488: 12,27 - 489: 12,28 - 748: 26,7 - 749: 32,7 - 750: 29,9 - 836: 6,2 - 837: 10,2 - 940: 1,9 - 941: 1,8 - 942: 1,7 - 943: 9,9 - 944: 9,8 - 945: 9,7 - 946: 20,10 - 947: 14,10 - 948: 14,6 - 949: 20,6 - 950: 22,6 - 951: 22,10 - 952: 12,10 - 953: 12,6 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkCornerNe - decals: - 194: 21,4 - 250: 10,44 - 525: 12,32 - 543: 4,22 - 585: 6,40 - 659: 34,36 - 675: 30,28 - 703: 6,16 - 757: 10,10 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkCornerNw - decals: - 191: 18,4 - 251: 12,44 - 519: 0,32 - 542: 0,22 - 582: 0,40 - 633: 24,36 - 702: 0,16 - 754: 0,10 - 853: 23,4 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkCornerSe - decals: - 192: 21,0 - 238: 10,46 - 272: 14,42 - 524: 12,30 - 537: 4,18 - 584: 6,38 - 658: 34,34 - 701: 6,12 - 755: 10,6 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkCornerSw - decals: - 193: 18,0 - 241: 12,46 - 270: 8,42 - 518: 0,30 - 534: 0,18 - 583: 0,38 - 632: 24,34 - 672: 28,24 - 700: 0,12 - 756: 0,6 - 852: 23,0 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkLineE - decals: - 202: 21,1 - 203: 21,2 - 204: 21,3 - 239: 10,47 - 240: 10,48 - 273: 14,43 - 501: 0,25 - 502: 0,26 - 503: 0,27 - 535: 4,19 - 536: 4,21 - 592: 14,38 - 593: 14,40 - 674: 30,27 - 706: 6,15 - 707: 6,13 - 758: 10,9 - 759: 10,7 - 926: 5,45 - 929: 33,36 - 930: 33,34 - 931: 10,31 - 935: 8,10 - 936: 8,6 - 937: 7,2 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkLineN - decals: - 197: 19,4 - 198: 20,4 - 248: 8,44 - 249: 9,44 - 252: 13,44 - 253: 14,44 - 506: 0,28 - 507: 2,28 - 520: 1,32 - 523: 11,32 - 540: 1,22 - 541: 3,22 - 634: 25,36 - 635: 26,36 - 704: 1,16 - 705: 5,16 - 762: 1,10 - 765: 9,10 - 846: 24,4 - 847: 25,4 - 848: 27,4 - 849: 28,4 - 850: 29,4 - 851: 30,4 - 927: 3,47 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkLineS - decals: - 195: 20,0 - 196: 19,0 - 244: 8,46 - 245: 9,46 - 246: 13,46 - 247: 14,46 - 274: 9,42 - 275: 10,42 - 276: 13,42 - 277: 12,42 - 504: 0,24 - 505: 2,24 - 521: 1,30 - 522: 11,30 - 538: 3,18 - 539: 1,18 - 636: 25,34 - 637: 26,34 - 710: 1,12 - 711: 5,12 - 763: 1,6 - 764: 9,6 - 840: 25,0 - 841: 24,0 - 842: 27,0 - 843: 28,0 - 844: 29,0 - 845: 30,0 - 928: 3,43 - - node: - color: '#FFFFFFFF' - id: BrickTileDarkLineW - decals: - 199: 18,3 - 200: 18,2 - 201: 18,1 - 242: 12,47 - 243: 12,48 - 271: 8,43 - 498: 2,27 - 499: 2,26 - 500: 2,25 - 544: 0,19 - 545: 0,21 - 590: 8,40 - 591: 8,38 - 673: 28,25 - 708: 0,13 - 709: 0,15 - 760: 0,7 - 761: 0,9 - 854: 23,3 - 855: 23,1 - 925: 1,45 - 932: 2,31 - 933: 2,10 - 934: 2,6 - 938: 9,2 - 939: 30,2 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelCornerNe - decals: - 84: 18,36 - 104: 16,25 - 336: 9,21 - 337: 10,22 - 364: 16,22 - 374: 21,15 - 375: 22,16 - 415: 21,21 - 421: 22,22 - 446: 33,21 - 447: 34,22 - 490: 12,25 - 554: 22,9 - 568: 14,9 - 610: 22,40 - 2025: 30,48 - 2039: 30,44 - 2058: 29,47 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelCornerNw - decals: - 85: 16,36 - 103: 18,25 - 338: 7,21 - 339: 6,22 - 376: 17,15 - 377: 16,16 - 414: 19,21 - 420: 18,22 - 448: 31,21 - 449: 30,22 - 555: 20,9 - 569: 12,9 - 611: 16,40 - 2040: 28,44 - 2059: 28,47 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelCornerSe - decals: - 83: 18,34 - 308: 26,30 - 332: 9,19 - 335: 10,18 - 372: 21,13 - 373: 22,12 - 418: 21,19 - 419: 22,18 - 452: 33,19 - 453: 34,18 - 561: 22,7 - 562: 14,7 - 609: 22,38 - 778: 16,0 - 779: 5,0 - 2038: 30,42 - 2056: 29,46 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelCornerSw - decals: - 81: 16,34 - 82: 3,35 - 309: 14,30 - 333: 7,19 - 334: 6,18 - 370: 17,13 - 371: 16,12 - 416: 18,18 - 417: 19,19 - 450: 31,19 - 451: 30,18 - 493: 14,27 - 558: 20,7 - 567: 12,7 - 608: 16,38 - 780: 0,0 - 781: 11,0 - 2037: 28,42 - 2057: 28,46 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelEndE - decals: - 73: 21,39 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelEndW - decals: - 74: 17,39 - - node: - color: '#D4D4D496' - id: BrickTileSteelLineE - decals: - 1330: 32,2 - 1332: 31,2 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelLineE - decals: - 87: 18,35 - 93: 14,34 - 94: 14,35 - 95: 14,36 - 105: 16,24 - 286: 17,45 - 287: 17,46 - 288: 17,47 - 323: 27,20 - 349: 9,20 - 350: 10,21 - 351: 10,19 - 365: 16,21 - 378: 21,14 - 379: 22,13 - 380: 22,15 - 425: 21,20 - 426: 22,19 - 427: 22,21 - 454: 34,19 - 455: 34,21 - 462: 33,20 - 491: 12,24 - 559: 22,8 - 566: 14,8 - 802: 16,1 - 806: 5,1 - 872: 34,0 - 873: 34,1 - 874: 34,3 - 875: 34,4 - 1328: 33,2 - 2023: 30,46 - 2024: 30,47 - 2041: 30,43 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelLineN - decals: - 75: 18,39 - 76: 19,39 - 77: 20,39 - 86: 17,36 - 340: 8,21 - 341: 9,22 - 342: 7,22 - 366: 15,22 - 391: 18,15 - 392: 19,15 - 393: 20,15 - 394: 21,16 - 395: 20,16 - 396: 18,16 - 397: 17,16 - 422: 20,21 - 423: 19,22 - 424: 21,22 - 458: 31,22 - 459: 33,22 - 460: 32,21 - 556: 21,9 - 564: 13,9 - 572: 16,10 - 573: 18,10 - 612: 17,40 - 613: 18,40 - 614: 21,40 - 615: 20,40 - 2026: 29,48 - 2027: 28,48 - 2044: 29,44 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelLineS - decals: - 78: 18,39 - 79: 19,39 - 80: 20,39 - 89: 17,34 - 298: 15,30 - 299: 16,30 - 300: 17,30 - 301: 18,30 - 302: 19,30 - 303: 21,30 - 304: 22,30 - 305: 23,30 - 306: 24,30 - 307: 25,30 - 346: 8,19 - 347: 7,18 - 348: 9,18 - 384: 18,13 - 385: 19,13 - 386: 20,13 - 387: 20,12 - 388: 21,12 - 389: 18,12 - 390: 17,12 - 431: 20,19 - 432: 19,18 - 433: 21,18 - 463: 32,19 - 464: 31,18 - 465: 33,18 - 557: 21,7 - 563: 13,7 - 570: 16,6 - 571: 18,6 - 616: 17,38 - 617: 18,38 - 618: 21,38 - 619: 20,38 - 782: 1,0 - 783: 2,0 - 784: 3,0 - 785: 4,0 - 786: 0,3 - 787: 1,3 - 788: 2,3 - 789: 3,3 - 790: 4,3 - 791: 5,3 - 792: 12,0 - 793: 13,0 - 794: 14,0 - 795: 15,0 - 796: 11,3 - 797: 12,3 - 798: 13,3 - 799: 14,3 - 800: 15,3 - 801: 16,3 - 2043: 29,42 - - node: - color: '#D4D4D496' - id: BrickTileSteelLineW - decals: - 1329: 33,2 - 1331: 32,2 - 1333: 31,2 - - node: - color: '#FFFFFFFF' - id: BrickTileSteelLineW - decals: - 88: 16,35 - 90: 20,34 - 91: 20,35 - 92: 20,36 - 102: 18,24 - 289: 21,45 - 290: 21,46 - 291: 21,47 - 322: 25,20 - 326: 29,15 - 327: 29,14 - 328: 29,13 - 343: 7,20 - 344: 6,21 - 345: 6,19 - 381: 17,14 - 382: 16,15 - 383: 16,13 - 428: 19,20 - 429: 18,19 - 430: 18,21 - 456: 30,19 - 457: 30,21 - 461: 31,20 - 492: 14,28 - 560: 20,8 - 565: 12,8 - 803: 0,1 - 805: 11,1 - 2021: 24,44 - 2022: 24,46 - 2042: 28,43 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerNe - decals: - 264: 10,44 - 679: 30,28 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteCornerNe - decals: - 109: 16,25 - 362: 10,22 - 367: 16,22 - 413: 22,16 - 438: 22,22 - 475: 34,22 - 494: 12,25 - 527: 12,32 - 580: 4,22 - 587: 6,40 - 630: 22,40 - 660: 34,36 - 715: 6,16 - 777: 10,10 - 2045: 30,48 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteCornerNe - decals: - 689: 10,28 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerNw - decals: - 265: 12,44 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteCornerNw - decals: - 108: 18,25 - 363: 6,22 - 412: 16,16 - 442: 18,22 - 476: 30,22 - 532: 0,32 - 579: 0,22 - 588: 0,40 - 629: 16,40 - 639: 24,36 - 714: 0,16 - 772: 0,10 - 858: 23,4 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteCornerNw - decals: - 688: 8,28 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerSe - decals: - 263: 10,46 - 279: 14,42 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteCornerSe - decals: - 361: 10,18 - 411: 22,12 - 443: 22,18 - 477: 34,18 - 526: 12,30 - 581: 4,18 - 586: 6,38 - 628: 22,38 - 661: 34,34 - 713: 6,12 - 771: 10,6 - 809: 5,0 - 810: 16,0 - - node: - color: '#EFB34196' - id: BrickTileWhiteCornerSe - decals: - 311: 26,30 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteCornerSe - decals: - 690: 10,24 - - node: - color: '#52B4E996' - id: BrickTileWhiteCornerSw - decals: - 262: 12,46 - 278: 8,42 - 676: 28,24 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteCornerSw - decals: - 360: 6,18 - 406: 16,12 - 439: 18,18 - 474: 30,18 - 496: 14,27 - 533: 0,30 - 578: 0,18 - 589: 0,38 - 631: 16,38 - 638: 24,34 - 712: 0,12 - 770: 0,6 - 807: 0,0 - 808: 11,0 - 859: 23,0 - - node: - color: '#EFB34196' - id: BrickTileWhiteCornerSw - decals: - 310: 14,30 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteCornerSw - decals: - 691: 8,24 - - node: - color: '#52B4E996' - id: BrickTileWhiteLineE - decals: - 258: 10,47 - 259: 10,48 - 280: 14,43 - 678: 30,27 - - node: - color: '#D4D4D419' - id: BrickTileWhiteLineE - decals: - 895: 2,6 - 896: 2,10 - 900: 9,2 - 901: 30,2 - 906: 1,45 - 908: 2,31 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteLineE - decals: - 96: 14,36 - 97: 14,35 - 98: 14,34 - 106: 16,24 - 356: 10,19 - 357: 10,21 - 368: 16,21 - 409: 22,15 - 410: 22,13 - 444: 22,19 - 445: 22,21 - 470: 34,21 - 471: 34,19 - 495: 12,24 - 511: 0,25 - 512: 0,26 - 513: 0,27 - 548: 4,19 - 549: 4,21 - 596: 14,38 - 597: 14,40 - 716: 6,15 - 717: 6,13 - 768: 10,9 - 769: 10,7 - 811: 5,1 - 812: 16,1 - 876: 34,0 - 877: 34,1 - 878: 34,3 - 879: 34,4 - 2048: 30,47 - 2049: 30,46 - - node: - color: '#EFB34196' - id: BrickTileWhiteLineE - decals: - 292: 17,45 - 293: 17,46 - 294: 17,47 - 324: 27,20 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteLineE - decals: - 693: 10,27 - 694: 10,26 - 695: 10,25 - - node: - color: '#52B4E996' - id: BrickTileWhiteLineN - decals: - 266: 9,44 - 267: 8,44 - 268: 13,44 - 269: 14,44 - - node: - color: '#D4D4D419' - id: BrickTileWhiteLineN - decals: - 907: 3,43 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteLineN - decals: - 358: 9,22 - 359: 7,22 - 369: 15,22 - 398: 18,16 - 399: 17,16 - 400: 21,16 - 401: 20,16 - 436: 19,22 - 437: 21,22 - 468: 31,22 - 469: 33,22 - 516: 0,28 - 517: 2,28 - 528: 11,32 - 531: 1,32 - 552: 1,22 - 553: 3,22 - 574: 16,10 - 575: 18,10 - 620: 18,40 - 621: 17,40 - 622: 20,40 - 623: 21,40 - 642: 25,36 - 643: 26,36 - 722: 1,16 - 723: 5,16 - 773: 1,10 - 774: 9,10 - 866: 24,4 - 867: 25,4 - 868: 27,4 - 869: 28,4 - 870: 30,4 - 871: 29,4 - 2046: 28,48 - 2047: 29,48 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteLineN - decals: - 692: 9,28 - - node: - color: '#52B4E996' - id: BrickTileWhiteLineS - decals: - 254: 8,46 - 255: 9,46 - 256: 13,46 - 257: 14,46 - 282: 9,42 - 283: 10,42 - 284: 12,42 - 285: 13,42 - - node: - color: '#D4D4D419' - id: BrickTileWhiteLineS - decals: - 905: 3,47 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteLineS - decals: - 352: 7,18 - 353: 9,18 - 402: 17,12 - 403: 18,12 - 404: 20,12 - 405: 21,12 - 434: 19,18 - 435: 21,18 - 466: 33,18 - 467: 31,18 - 514: 0,24 - 515: 2,24 - 529: 11,30 - 530: 1,30 - 550: 1,18 - 551: 3,18 - 576: 16,6 - 577: 18,6 - 624: 17,38 - 625: 18,38 - 626: 20,38 - 627: 21,38 - 640: 25,34 - 641: 26,34 - 718: 5,12 - 719: 1,12 - 775: 1,6 - 776: 9,6 - 813: 12,0 - 814: 13,0 - 815: 14,0 - 816: 15,0 - 817: 16,3 - 818: 15,3 - 819: 13,3 - 820: 14,3 - 821: 11,3 - 822: 12,3 - 823: 0,3 - 824: 1,3 - 825: 2,3 - 826: 3,3 - 827: 4,3 - 828: 5,3 - 829: 4,0 - 830: 3,0 - 831: 2,0 - 832: 1,0 - 860: 24,0 - 861: 25,0 - 862: 27,0 - 863: 28,0 - 864: 29,0 - 865: 30,0 - - node: - color: '#EFB34196' - id: BrickTileWhiteLineS - decals: - 312: 15,30 - 313: 16,30 - 314: 17,30 - 315: 18,30 - 316: 19,30 - 317: 21,30 - 318: 22,30 - 319: 23,30 - 320: 24,30 - 321: 25,30 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteLineS - decals: - 696: 9,24 - - node: - color: '#52B4E996' - id: BrickTileWhiteLineW - decals: - 260: 12,47 - 261: 12,48 - 281: 8,43 - 677: 28,25 - - node: - color: '#D4D4D419' - id: BrickTileWhiteLineW - decals: - 897: 8,10 - 898: 8,6 - 899: 7,2 - 902: 33,36 - 903: 33,34 - 904: 5,45 - 909: 10,31 - - node: - color: '#DE3A3A96' - id: BrickTileWhiteLineW - decals: - 99: 20,36 - 100: 20,35 - 101: 20,34 - 107: 18,24 - 354: 6,19 - 355: 6,21 - 407: 16,13 - 408: 16,15 - 440: 18,19 - 441: 18,21 - 472: 30,19 - 473: 30,21 - 497: 14,28 - 508: 2,25 - 509: 2,26 - 510: 2,27 - 546: 0,19 - 547: 0,21 - 594: 8,38 - 595: 8,40 - 720: 0,13 - 721: 0,15 - 766: 0,7 - 767: 0,9 - 804: 0,1 - 833: 11,1 - 856: 23,1 - 857: 23,3 - 2050: 24,44 - 2051: 24,46 - - node: - color: '#EFB34196' - id: BrickTileWhiteLineW - decals: - 295: 21,45 - 296: 21,46 - 297: 21,47 - 325: 25,20 - 329: 29,13 - 330: 29,14 - 331: 29,15 - - node: - color: '#FFFFFFFF' - id: BrickTileWhiteLineW - decals: - 697: 8,25 - 698: 8,26 - 699: 8,27 - - node: - cleanable: True - angle: 1.5707963267948966 rad - color: '#B02E269B' - id: Clandestine - decals: - 2136: 3.132535,34.09553 - - node: - color: '#A4610696' - id: Dirt - decals: - 1334: 31,2 - 1335: 32,2 - 1336: 33,2 - 1337: 30,2 - 1338: 34,2 - 1339: 33,3 - 1340: 31,4 - 1341: 32,3 - 1342: 32,1 - 1343: 31,1 - 1344: 31,0 - 1345: 33,0 - 1346: 32,0 - 1347: 33,3 - 1348: 33,4 - 1349: 32,4 - 1350: 31,3 - 1351: 32,1 - 1352: 33,1 - - node: - cleanable: True - color: '#A4610696' - id: Dirt - decals: - 954: 0,45 - 955: 3,47 - 956: 3,48 - 957: 6,45 - 958: 3,42 - 959: 3,43 - 960: 5,45 - 961: 1,45 - 962: 13,45 - 963: 12,45 - 964: 11,47 - 965: 9,45 - 966: 8,45 - 967: 8,46 - 968: 10,47 - 969: 13,47 - 970: 14,46 - 971: 11,43 - 972: 11,42 - 973: 9,42 - 974: 10,42 - 975: 13,42 - 976: 12,42 - 977: 13,43 - 978: 9,43 - 979: 11,44 - 980: 11,45 - 981: 11,47 - 982: 9,46 - 983: 11,46 - 984: 16,45 - 985: 16,46 - 986: 16,47 - 987: 16,44 - 988: 17,45 - 989: 17,46 - 990: 21,45 - 991: 22,45 - 992: 22,44 - 993: 22,43 - 994: 22,46 - 995: 21,45 - 996: 21,46 - 997: 22,47 - 998: 24,39 - 999: 24,38 - 1000: 24,40 - 1001: 27,39 - 1002: 27,39 - 1003: 30,40 - 1004: 30,39 - 1005: 30,38 - 1006: 30,39 - 1007: 34,35 - 1008: 33,34 - 1009: 33,36 - 1010: 24,35 - 1011: 22,35 - 1012: 20,35 - 1013: 21,35 - 1014: 20,34 - 1015: 14,35 - 1016: 13,35 - 1017: 12,35 - 1018: 14,36 - 1019: 17,36 - 1020: 17,35 - 1021: 17,34 - 1022: 16,35 - 1023: 18,35 - 1024: 18,36 - 1025: 18,34 - 1026: 16,34 - 1027: 16,36 - 1028: 16,30 - 1029: 16,30 - 1030: 18,30 - 1031: 19,30 - 1032: 22,30 - 1033: 24,30 - 1034: 25,30 - 1035: 26,30 - 1036: 20,30 - 1037: 20,30 - 1038: 15,30 - 1039: 14,30 - 1040: 14,31 - 1041: 26,31 - 1042: 10,31 - 1043: 2,31 - 1044: 0,31 - 1045: 12,31 - 1046: 5,35 - 1047: 6,36 - 1048: 4,34 - 1049: 9,35 - 1050: 9,35 - 1051: 10,35 - 1052: 10,34 - 1053: 0,35 - 1054: 0,36 - 1055: 0,35 - 1056: 5,36 - 1057: 6,36 - 1058: 6,39 - 1059: 0,39 - 1060: 8,39 - 1061: 8,40 - 1062: 8,38 - 1063: 9,39 - 1064: 11,38 - 1065: 9,38 - 1066: 11,40 - 1067: 10,40 - 1068: 13,39 - 1069: 14,39 - 1070: 14,40 - 1071: 14,38 - 1072: 13,39 - 1073: 13,40 - 1074: 16,39 - 1075: 18,40 - 1076: 19,40 - 1077: 19,39 - 1078: 18,39 - 1079: 17,39 - 1080: 20,39 - 1081: 21,39 - 1082: 19,38 - 1083: 22,39 - 1084: 21,38 - 1085: 24,39 - 1086: 24,38 - 1087: 24,40 - 1088: 17,32 - 1089: 24,32 - 1090: 23,32 - 1091: 34,26 - 1092: 33,26 - 1093: 33,28 - 1094: 32,28 - 1095: 32,27 - 1096: 34,27 - 1097: 34,28 - 1098: 32,25 - 1099: 33,24 - 1100: 33,25 - 1101: 32,26 - 1102: 29,24 - 1103: 30,26 - 1104: 28,26 - 1105: 29,28 - 1106: 29,27 - 1107: 29,25 - 1108: 25,26 - 1109: 24,26 - 1110: 26,26 - 1111: 25,27 - 1112: 24,28 - 1113: 25,28 - 1114: 24,27 - 1115: 24,24 - 1116: 25,25 - 1117: 25,24 - 1118: 26,25 - 1119: 22,26 - 1120: 24,26 - 1121: 26,26 - 1122: 20,26 - 1123: 21,25 - 1124: 21,24 - 1125: 21,28 - 1126: 21,27 - 1127: 18,26 - 1128: 16,26 - 1129: 17,27 - 1130: 17,28 - 1131: 17,25 - 1132: 17,24 - 1133: 17,26 - 1134: 13,28 - 1135: 13,27 - 1136: 13,26 - 1137: 13,25 - 1138: 13,24 - 1139: 12,26 - 1140: 14,26 - 1141: 9,26 - 1142: 9,27 - 1143: 9,28 - 1144: 8,28 - 1145: 8,27 - 1146: 8,26 - 1147: 9,25 - 1148: 8,25 - 1149: 8,24 - 1150: 9,24 - 1151: 10,24 - 1152: 10,25 - 1153: 10,26 - 1154: 10,27 - 1155: 10,28 - 1156: 5,28 - 1157: 5,28 - 1158: 5,24 - 1159: 5,24 - 1160: 0,26 - 1161: 2,26 - 1162: 2,28 - 1163: 1,24 - 1164: 2,24 - 1165: 2,22 - 1166: 4,20 - 1167: 2,18 - 1168: 1,19 - 1169: 0,20 - 1170: 0,17 - 1171: 0,18 - 1172: 4,18 - 1173: 4,19 - 1174: 4,22 - 1175: 0,22 - 1176: 6,20 - 1177: 7,20 - 1178: 8,20 - 1179: 9,20 - 1180: 10,20 - 1181: 8,21 - 1182: 8,22 - 1183: 8,19 - 1184: 8,18 - 1185: 6,18 - 1186: 7,19 - 1187: 7,18 - 1188: 9,20 - 1189: 10,21 - 1190: 9,21 - 1191: 9,22 - 1192: 9,19 - 1193: 7,21 - 1194: 8,13 - 1195: 8,13 - 1196: 11,16 - 1197: 11,16 - 1198: 10,16 - 1199: 9,16 - 1200: 8,15 - 1201: 8,14 - 1202: 8,16 - 1203: 10,16 - 1204: 9,16 - 1205: 12,14 - 1206: 11,14 - 1207: 11,12 - 1208: 10,12 - 1209: 14,12 - 1210: 14,14 - 1211: 14,15 - 1212: 13,14 - 1213: 12,14 - 1214: 11,14 - 1215: 11,13 - 1216: 6,14 - 1217: 0,14 - 1218: 3,16 - 1219: 3,12 - 1220: 3,13 - 1221: 2,13 - 1222: 4,13 - 1223: 3,15 - 1224: 2,15 - 1225: 4,15 - 1226: 5,14 - 1227: 1,14 - 1228: 1,15 - 1229: 1,13 - 1230: 5,15 - 1231: 5,13 - 1232: 0,8 - 1233: 2,10 - 1234: 2,6 - 1235: 8,6 - 1236: 8,10 - 1237: 0,8 - 1238: 10,8 - 1239: 10,10 - 1240: 10,7 - 1241: 10,6 - 1242: 9,6 - 1243: 9,10 - 1244: 1,10 - 1245: 0,7 - 1246: 0,6 - 1247: 0,3 - 1248: 1,3 - 1249: 1,3 - 1250: 2,3 - 1251: 3,3 - 1252: 4,3 - 1253: 4,3 - 1254: 5,3 - 1255: 7,2 - 1256: 9,2 - 1257: 4,0 - 1258: 4,1 - 1259: 2,1 - 1260: 1,1 - 1261: 0,2 - 1262: 1,2 - 1263: 2,2 - 1264: 5,2 - 1265: 4,2 - 1266: 3,2 - 1267: 4,1 - 1268: 3,1 - 1269: 11,2 - 1270: 12,3 - 1271: 11,3 - 1272: 14,3 - 1273: 14,3 - 1274: 15,3 - 1275: 16,3 - 1276: 13,3 - 1277: 11,3 - 1278: 12,2 - 1279: 11,1 - 1280: 13,1 - 1281: 16,2 - 1282: 16,1 - 1283: 14,1 - 1284: 13,2 - 1285: 14,2 - 1286: 18,2 - 1287: 19,2 - 1288: 20,2 - 1289: 21,2 - 1290: 19,3 - 1291: 18,3 - 1292: 20,3 - 1293: 20,1 - 1294: 21,1 - 1295: 19,1 - 1296: 23,2 - 1297: 28,2 - 1298: 29,2 - 1299: 30,2 - 1300: 28,4 - 1301: 29,4 - 1302: 26,4 - 1303: 26,2 - 1304: 26,1 - 1305: 26,0 - 1306: 24,2 - 1307: 25,2 - 1308: 27,2 - 1309: 24,4 - 1310: 23,3 - 1311: 24,3 - 1312: 23,4 - 1469: 14,8 - 1470: 12,8 - 1471: 12,7 - 1472: 13,7 - 1473: 13,6 - 1474: 13,10 - 1475: 12,9 - 1476: 14,9 - 1477: 17,10 - 1478: 17,9 - 1479: 18,9 - 1480: 18,8 - 1481: 17,7 - 1482: 17,7 - 1483: 17,6 - 1484: 17,8 - 1485: 16,7 - 1486: 18,7 - 1487: 20,9 - 1488: 20,8 - 1489: 21,10 - 1490: 21,9 - 1491: 21,7 - 1492: 21,6 - 1493: 20,7 - 1494: 22,7 - 1495: 22,8 - 1534: 19,16 - 1535: 18,15 - 1536: 19,13 - 1537: 19,12 - 1538: 22,14 - 1539: 22,14 - 1540: 22,15 - 1541: 21,16 - 1542: 21,15 - 1543: 21,13 - 1544: 16,14 - 1545: 17,13 - 1546: 17,15 - 1556: 30,20 - 1557: 32,22 - 1558: 31,22 - 1559: 31,21 - 1560: 32,19 - 1561: 32,18 - 1562: 34,20 - 1563: 34,19 - 1564: 34,18 - 1565: 34,21 - 1566: 34,22 - 2060: 24,45 - 2061: 25,45 - 2062: 27,48 - 2063: 27,42 - 2064: 30,45 - 2065: 28,43 - 2066: 29,43 - 2067: 30,43 - 2068: 24,42 - 2069: 25,43 - 2070: 26,42 - 2071: 25,42 - 2072: 26,48 - 2073: 25,47 - 2074: 26,47 - 2075: 25,47 - 2076: 25,48 - 2077: 27,47 - 2078: 27,45 - 2079: 27,46 - 2080: 26,45 - 2081: 28,45 - 2082: 26,44 - 2083: 27,44 - 2084: 25,46 - 2085: 26,46 - 2086: 29,45 - - node: - color: '#A4610696' - id: DirtHeavy - decals: - 1353: 11,31 - 1354: 1,31 - 1355: 0,39 - 1356: 6,39 - 1357: 5,45 - 1358: 14,39 - 1359: 16,39 - 1360: 19,38 - - node: - cleanable: True - color: '#A4610696' - id: DirtHeavy - decals: - 1361: 22,39 - 1362: 19,40 - 1363: 30,39 - 1364: 25,35 - 1365: 24,36 - 1366: 20,30 - 1367: 14,30 - 1368: 18,30 - 1369: 22,30 - 1370: 26,31 - 1371: 22,26 - 1372: 24,26 - 1373: 26,26 - 1374: 28,26 - 1375: 29,27 - 1376: 33,25 - 1377: 33,28 - 1378: 32,28 - 1379: 14,26 - 1380: 12,26 - 1381: 9,26 - 1382: 9,28 - 1383: 8,28 - 1384: 8,24 - 1385: 10,25 - 1386: 5,24 - 1387: 5,28 - 1388: 0,26 - 1389: 0,27 - 1390: 2,24 - 1391: 2,25 - 1392: 0,35 - 1393: 0,36 - 1394: 7,36 - 1395: 5,35 - 1396: 4,34 - 1397: 10,35 - 1398: 9,35 - 1399: 8,39 - 1400: 14,39 - 1401: 14,38 - 1402: 8,45 - 1403: 11,48 - 1404: 11,44 - 1405: 14,45 - 1406: 11,42 - 1407: 9,42 - 1408: 13,43 - 1409: 3,47 - 1410: 4,20 - 1411: 3,22 - 1412: 2,18 - 1413: 0,19 - 1414: 6,20 - 1415: 8,20 - 1416: 8,18 - 1417: 10,20 - 1418: 8,22 - 1419: 14,20 - 1420: 15,21 - 1421: 16,20 - 1422: 12,20 - 1423: 12,21 - 1424: 13,22 - 1425: 13,21 - 1426: 13,19 - 1427: 16,19 - 1428: 16,19 - 1429: 15,20 - 1430: 14,18 - 1431: 12,20 - 1432: 14,22 - 1433: 20,20 - 1434: 20,22 - 1435: 18,20 - 1436: 22,21 - 1437: 19,21 - 1438: 20,18 - 1439: 22,20 - 1440: 27,22 - 1441: 25,22 - 1442: 26,18 - 1443: 27,18 - 1444: 31,18 - 1445: 32,18 - 1446: 31,20 - 1447: 32,21 - 1448: 34,22 - 1449: 34,20 - 1450: 32,19 - 1451: 29,14 - 1452: 24,14 - 1453: 24,13 - 1454: 30,14 - 1455: 29,13 - 1456: 34,2 - 1457: 32,3 - 1458: 30,1 - 1459: 26,1 - 1460: 23,3 - 1461: 24,4 - 1462: 29,4 - 1463: 26,0 - 1464: 26,1 - 1465: 18,2 - 1466: 22,8 - 1467: 20,8 - 1468: 16,8 - 1496: 17,6 - 1497: 16,8 - 1498: 18,8 - 1499: 17,10 - 1500: 14,8 - 1501: 12,8 - 1502: 13,6 - 1503: 13,10 - 1504: 21,10 - 1505: 21,9 - 1506: 21,8 - 1507: 21,7 - 1508: 21,6 - 1509: 10,8 - 1510: 9,10 - 1511: 9,6 - 1512: 2,6 - 1513: 0,7 - 1514: 0,9 - 1515: 1,10 - 1516: 8,10 - 1517: 0,14 - 1518: 5,14 - 1519: 4,15 - 1520: 3,16 - 1521: 1,18 - 1522: 5,15 - 1523: 6,14 - 1524: 11,16 - 1525: 8,13 - 1526: 11,12 - 1527: 10,13 - 1528: 16,14 - 1529: 19,16 - 1530: 19,13 - 1531: 18,13 - 1532: 18,15 - 1533: 16,15 - 1547: 19,16 - 1548: 16,14 - 1549: 17,15 - 1550: 18,14 - 1551: 19,13 - 1552: 21,13 - 1553: 22,14 - 1554: 29,15 - 1555: 29,13 - 2095: 24,45 - 2096: 27,48 - 2097: 27,42 - 2098: 25,44 - 2099: 29,45 - 2100: 29,46 - 2101: 29,47 - 2102: 25,45 - - node: - cleanable: True - color: '#A4610696' - id: DirtLight - decals: - 1567: 0,2 - 1568: 5,2 - 1569: 4,1 - 1570: 5,2 - 1571: 2,1 - 1572: 7,2 - 1573: 9,2 - 1574: 11,2 - 1575: 14,2 - 1576: 13,3 - 1577: 10,3 - 1578: 11,3 - 1579: 12,3 - 1580: 16,3 - 1581: 15,3 - 1582: 16,2 - 1583: 16,1 - 1584: 14,1 - 1585: 15,1 - 1586: 1,3 - 1587: 3,3 - 1588: 5,3 - 1589: 5,3 - 1590: 1,1 - 1591: 23,2 - 1592: 26,2 - 1593: 28,2 - 1594: 28,4 - 1595: 30,2 - 1596: 31,1 - 1597: 34,1 - 1598: 33,0 - 1599: 34,3 - 1600: 21,9 - 1601: 20,8 - 1602: 22,8 - 1603: 16,8 - 1604: 17,9 - 1605: 17,10 - 1606: 17,6 - 1607: 12,8 - 1608: 14,9 - 1609: 14,8 - 1610: 13,6 - 1611: 10,8 - 1612: 8,10 - 1613: 2,10 - 1614: 0,8 - 1615: 0,9 - 1616: 2,6 - 1617: 0,14 - 1618: 3,12 - 1619: 1,14 - 1620: 3,15 - 1621: 5,14 - 1622: 5,15 - 1623: 6,14 - 1624: 3,13 - 1625: 3,12 - 1626: 8,13 - 1627: 10,16 - 1628: 11,16 - 1629: 17,14 - 1630: 17,13 - 1631: 16,15 - 1632: 19,16 - 1633: 22,14 - 1634: 21,14 - 1635: 21,13 - 1636: 19,13 - 1637: 20,12 - 1638: 20,13 - 1639: 21,15 - 1640: 29,14 - 1641: 29,15 - 1642: 34,20 - 1643: 32,18 - 1644: 34,18 - 1645: 34,21 - 1646: 32,22 - 1647: 30,20 - 1648: 30,21 - 1649: 32,19 - 1650: 32,21 - 1651: 32,20 - 1652: 30,18 - 1653: 26,22 - 1654: 25,22 - 1655: 25,20 - 1656: 27,20 - 1657: 27,22 - 1658: 25,20 - 1659: 27,20 - 1660: 26,18 - 1661: 27,18 - 1662: 25,18 - 1663: 22,20 - 1664: 18,20 - 1665: 20,22 - 1666: 20,20 - 1667: 19,19 - 1668: 20,19 - 1669: 20,21 - 1670: 21,20 - 1671: 16,20 - 1672: 16,21 - 1673: 12,20 - 1674: 13,21 - 1675: 13,22 - 1676: 13,19 - 1677: 13,19 - 1678: 14,20 - 1679: 14,18 - 1680: 10,20 - 1681: 10,21 - 1682: 8,22 - 1683: 6,21 - 1684: 6,20 - 1685: 7,20 - 1686: 7,19 - 1687: 8,20 - 1688: 9,20 - 1689: 4,20 - 1690: 3,18 - 1691: 2,18 - 1692: 1,18 - 1693: 0,21 - 1694: 1,22 - 1695: 0,20 - 1696: 2,22 - 1697: 1,24 - 1698: 0,26 - 1699: 0,25 - 1700: 2,25 - 1701: 2,27 - 1702: 5,28 - 1703: 5,24 - 1704: 9,26 - 1705: 9,27 - 1706: 9,24 - 1707: 8,24 - 1708: 10,24 - 1709: 10,26 - 1710: 13,26 - 1711: 12,26 - 1712: 13,28 - 1713: 12,28 - 1714: 13,24 - 1715: 14,26 - 1716: 13,25 - 1717: 18,26 - 1718: 16,26 - 1719: 17,28 - 1720: 17,25 - 1721: 17,24 - 1722: 20,26 - 1723: 22,26 - 1724: 21,26 - 1725: 21,27 - 1726: 21,24 - 1727: 21,25 - 1728: 25,26 - 1729: 26,26 - 1730: 25,26 - 1731: 25,26 - 1732: 25,24 - 1733: 25,24 - 1734: 26,25 - 1735: 24,27 - 1736: 29,26 - 1737: 29,27 - 1738: 30,26 - 1739: 29,24 - 1740: 33,26 - 1741: 33,24 - 1742: 34,26 - 1743: 32,26 - 1744: 34,28 - 1745: 34,28 - 1746: 33,28 - 1747: 32,28 - 1748: 26,31 - 1749: 21,30 - 1750: 20,30 - 1751: 17,30 - 1752: 15,30 - 1753: 14,31 - 1754: 10,31 - 1755: 2,31 - 1756: 11,30 - 1757: 12,31 - 1758: 0,32 - 1759: 1,32 - 1760: 0,31 - 1761: -1,35 - 1762: 0,36 - 1763: 0,35 - 1764: 4,34 - 1765: 5,35 - 1766: 3,34 - 1767: 10,34 - 1768: 10,35 - 1769: 6,39 - 1770: 0,39 - 1771: 0,45 - 1772: 3,43 - 1773: 3,47 - 1774: 4,45 - 1775: 5,45 - 1776: 8,45 - 1777: 11,46 - 1778: 11,45 - 1779: 11,42 - 1780: 13,42 - 1781: 9,42 - 1782: 14,45 - 1783: 10,44 - 1784: 11,44 - 1785: 11,45 - 1786: 16,47 - 1787: 16,45 - 1788: 17,45 - 1789: 21,45 - 1790: 16,48 - 1791: 16,43 - 1792: 23,43 - 1793: 22,42 - 1794: 30,38 - 1795: 30,40 - 1796: 24,38 - 1797: 22,39 - 1798: 19,38 - 1799: 19,39 - 1800: 18,39 - 1801: 16,39 - 1802: 18,38 - 1803: 17,38 - 1804: 14,38 - 1805: 14,40 - 1806: 9,39 - 1807: 10,40 - 1808: 12,38 - 1809: 10,38 - 1810: 10,38 - 1811: 6,39 - 1812: 0,39 - 2103: 24,45 - 2104: 30,45 - 2105: 26,44 - 2106: 27,43 - 2107: 30,43 - 2108: 29,42 - 2109: 28,47 - - node: - cleanable: True - color: '#A4610696' - id: DirtMedium - decals: - 1813: 0,35 - 1814: 0,39 - 1815: 6,39 - 1816: 3,43 - 1817: 1,45 - 1818: 11,45 - 1819: 11,42 - 1820: 14,45 - 1821: 16,45 - 1822: 21,45 - 1823: 22,45 - 1824: 21,38 - 1825: 20,38 - 1826: 20,38 - 1827: 24,38 - 1828: 30,39 - 1829: 34,35 - 1830: 33,36 - 1831: 33,34 - 1832: 24,34 - 1833: 20,34 - 1834: 22,35 - 1835: 17,35 - 1836: 16,34 - 1837: 17,36 - 1838: 12,35 - 1839: 10,35 - 1840: 5,35 - 1841: 0,35 - 1842: 1,31 - 1843: 2,31 - 1844: 11,31 - 1845: 9,26 - 1846: 8,26 - 1847: 9,27 - 1848: 9,28 - 1849: 10,26 - 1850: 10,25 - 1851: 9,25 - 1852: 13,26 - 1853: 12,26 - 1854: 13,28 - 1855: 14,26 - 1856: 17,24 - 1857: 18,26 - 1858: 17,28 - 1859: 16,26 - 1860: 22,26 - 1861: 20,26 - 1862: 25,27 - 1863: 24,27 - 1864: 24,28 - 1865: 24,25 - 1866: 25,25 - 1867: 25,24 - 1868: 24,24 - 1869: 26,25 - 1870: 26,26 - 1871: 25,26 - 1872: 24,26 - 1873: 24,26 - 1874: 25,26 - 1875: 25,26 - 1876: 28,26 - 1877: 30,26 - 1878: 29,27 - 1879: 29,25 - 1880: 33,26 - 1881: 34,26 - 1882: 34,28 - 1883: 32,28 - 1884: 34,28 - 1885: 32,20 - 1886: 31,20 - 1887: 30,20 - 1888: 30,18 - 1889: 34,18 - 1890: 34,21 - 1891: 25,18 - 1892: 26,18 - 1893: 25,18 - 1894: 27,20 - 1895: 27,22 - 1896: 29,15 - 1897: 30,14 - 1898: 29,12 - 1899: 24,14 - 1900: 24,15 - 1901: 24,16 - 1902: 20,20 - 1903: 17,20 - 1904: 19,21 - 1905: 18,20 - 1906: 21,22 - 1907: 22,20 - 1908: 22,21 - 1909: 20,19 - 1910: 15,20 - 1911: 14,21 - 1912: 15,21 - 1913: 16,21 - 1914: 14,22 - 1915: 12,20 - 1916: 14,18 - 1917: 15,18 - 1918: 16,19 - 1919: 16,19 - 1920: 13,19 - 1921: 12,19 - 1922: 12,19 - 1923: 12,18 - 1924: 14,18 - 1925: 15,18 - 1926: 15,18 - 1927: 10,20 - 1928: 8,22 - 1929: 7,20 - 1930: 9,21 - 1931: 7,19 - 1932: 10,19 - 1933: 10,21 - 1934: 7,18 - 1935: 4,20 - 1936: 4,21 - 1937: 2,22 - 1938: 1,22 - 1939: 0,19 - 1940: 1,18 - 1941: 1,18 - 1942: 3,18 - 1943: 0,14 - 1944: 2,13 - 1945: 3,13 - 1946: 5,13 - 1947: 3,12 - 1948: 8,15 - 1949: 8,16 - 1950: 9,16 - 1951: 9,16 - 1952: 18,14 - 1953: 19,16 - 1954: 19,14 - 1955: 20,13 - 1956: 18,16 - 1957: 17,13 - 1958: 20,12 - 1959: 22,13 - 1960: 24,13 - 1961: 30,12 - 1962: 30,14 - 1963: 29,16 - 1964: 24,16 - 1965: 24,16 - 1966: 25,6 - 1967: 24,7 - 1968: 26,9 - 1969: 27,10 - 1970: 28,10 - 1971: 34,10 - 1972: 34,8 - 1973: 34,7 - 1974: 33,6 - 1975: 30,6 - 1976: 27,6 - 1977: 21,8 - 1978: 16,8 - 1979: 17,10 - 1980: 18,8 - 1981: 17,6 - 1982: 13,7 - 1983: 13,9 - 1984: 13,8 - 1985: 14,7 - 1986: 10,6 - 1987: 8,10 - 1988: 2,6 - 1989: 0,7 - 1990: 1,1 - 1991: 0,1 - 1992: 4,1 - 1993: 5,2 - 1994: 3,1 - 1995: 3,0 - 1996: 7,2 - 1997: 9,2 - 1998: 11,2 - 1999: 13,1 - 2000: 15,1 - 2001: 16,2 - 2002: 16,1 - 2003: 23,2 - 2004: 26,2 - 2005: 29,3 - 2006: 30,2 - 2007: 33,2 - 2008: 33,3 - 2009: 34,2 - 2010: 34,0 - 2011: 34,1 - 2012: 31,1 - 2013: 29,0 - 2014: 26,0 - 2015: 23,3 - 2016: 28,4 - 2087: 27,42 - 2088: 27,48 - 2089: 24,45 - 2090: 30,45 - 2091: 28,45 - 2092: 26,45 - 2093: 28,47 - 2094: 27,44 - 2110: 24,45 - 2111: 27,48 - 2112: 27,45 - 2113: 26,46 - 2114: 26,42 - 2115: 25,42 - 2116: 25,47 - 2117: 25,47 - 2118: 26,48 - 2119: 26,47 - 2120: 26,47 - 2121: 26,43 - 2122: 26,43 - 2123: 27,43 - 2124: 6,1 - 2125: 10,3 - - node: - color: '#D4D4D41B' - id: FullTileOverlayGreyscale - decals: - 1313: 31,4 - 1314: 31,3 - 1315: 31,2 - 1316: 31,1 - 1317: 31,0 - - node: - color: '#D4D4D433' - id: FullTileOverlayGreyscale - decals: - 1318: 32,0 - 1319: 32,1 - 1320: 32,2 - 1321: 32,3 - 1322: 32,4 - - node: - color: '#D4D4D44C' - id: FullTileOverlayGreyscale - decals: - 1323: 33,0 - 1324: 33,1 - 1325: 33,2 - 1326: 33,3 - 1327: 33,4 - - node: - color: '#D4D4D40C' - id: HalfTileOverlayGreyscale - decals: - 923: 3,47 - - node: - color: '#D4D4D419' - id: HalfTileOverlayGreyscale - decals: - 893: 3,43 - - node: - color: '#D4D4D40C' - id: HalfTileOverlayGreyscale180 - decals: - 924: 3,43 - - node: - color: '#D4D4D419' - id: HalfTileOverlayGreyscale180 - decals: - 894: 3,47 - - node: - color: '#D4D4D40C' - id: HalfTileOverlayGreyscale270 - decals: - 910: 30,2 - 911: 9,2 - 914: 2,6 - 915: 2,10 - 918: 2,31 - 922: 1,45 - - node: - color: '#D4D4D419' - id: HalfTileOverlayGreyscale270 - decals: - 882: 7,2 - 883: 8,6 - 884: 8,10 - 888: 10,31 - 889: 33,34 - 890: 33,36 - 891: 5,45 - - node: - color: '#D4D4D40C' - id: HalfTileOverlayGreyscale90 - decals: - 912: 7,2 - 913: 8,6 - 916: 8,10 - 917: 10,31 - 919: 33,34 - 920: 33,36 - 921: 5,45 - - node: - color: '#D4D4D419' - id: HalfTileOverlayGreyscale90 - decals: - 880: 30,2 - 881: 9,2 - 885: 2,6 - 886: 2,10 - 887: 2,31 - 892: 1,45 - - node: - color: '#9FED5896' - id: MiniTileCheckerAOverlay - decals: - 2028: 28,42 - 2029: 29,42 - 2030: 30,42 - 2031: 28,43 - 2032: 29,43 - 2033: 30,43 - 2034: 28,44 - 2035: 29,44 - 2036: 30,44 - - node: - color: '#DE3A3A96' - id: MiniTileCheckerAOverlay - decals: - 0: 7,19 - 1: 8,19 - 2: 9,19 - 3: 9,20 - 4: 8,20 - 5: 7,20 - 6: 7,21 - 7: 8,21 - 8: 9,21 - 9: 19,19 - 10: 20,19 - 11: 21,19 - 12: 21,20 - 13: 20,20 - 14: 19,20 - 15: 19,21 - 16: 20,21 - 17: 21,21 - 18: 17,15 - 19: 17,14 - 20: 17,13 - 21: 18,13 - 22: 19,13 - 23: 20,13 - 24: 21,13 - 25: 21,14 - 26: 21,15 - 27: 20,15 - 28: 19,15 - 29: 18,15 - 30: 18,14 - 31: 19,14 - 32: 20,9 - 33: 21,9 - 34: 22,9 - 35: 22,8 - 36: 22,7 - 37: 21,7 - 38: 21,8 - 39: 20,8 - 40: 20,7 - 41: 12,7 - 42: 13,7 - 43: 14,7 - 44: 14,8 - 45: 13,8 - 46: 12,8 - 47: 12,9 - 48: 13,9 - 49: 14,9 - 59: 17,39 - 60: 18,39 - 61: 19,39 - 62: 20,39 - 63: 21,39 - 64: 16,36 - 65: 16,35 - 66: 16,34 - 67: 17,34 - 68: 18,34 - 69: 18,35 - 70: 17,35 - 71: 17,36 - 72: 18,36 - - node: - color: '#FFFFFFFF' - id: MiniTileCheckerAOverlay - decals: - 2052: 28,46 - 2053: 28,47 - 2054: 29,47 - 2055: 29,46 - - node: - color: '#9FED5896' - id: MiniTileCheckerBOverlay - decals: - 50: 31,21 - 51: 31,20 - 52: 31,19 - 53: 33,21 - 54: 33,20 - 55: 33,19 - - node: - color: '#DE3A3A96' - id: MiniTileCheckerBOverlay - decals: - 56: 32,21 - 57: 32,20 - 58: 32,19 - - node: - color: '#DE3A3A96' - id: StandClearGreyscale - decals: - 751: 26,7 - 752: 32,7 - 753: 29,9 - 838: 6,2 - 839: 10,2 - - node: - color: '#FFFFFFFF' - id: WarnCornerNE - decals: - 605: 13,40 - 747: 34,10 - - node: - color: '#FFFFFFFF' - id: WarnCornerNW - decals: - 606: 9,40 - 741: 24,10 - - node: - color: '#FFFFFFFF' - id: WarnCornerSE - decals: - 604: 13,38 - 746: 34,6 - - node: - color: '#FFFFFFFF' - id: WarnCornerSW - decals: - 598: 9,38 - 740: 24,6 - - node: - color: '#FFFFFFFF' - id: WarnFull - decals: - 657: 32,35 - - node: - color: '#FFFFFFFF' - id: WarnLineE - decals: - 607: 13,39 - 644: 26,34 - 645: 26,35 - 646: 26,36 - 744: 34,7 - 745: 34,9 - - node: - color: '#DE3A3A96' - id: WarnLineGreyscaleE - decals: - 112: 18,26 - 117: 14,26 - 118: 22,26 - 121: 22,35 - 122: 22,39 - 128: 14,39 - 131: 6,39 - 132: 12,31 - 135: 26,31 - 140: 26,26 - 145: 30,26 - 146: 34,26 - 153: 2,26 - 159: 4,20 - 160: 10,20 - 166: 16,20 - 170: 22,20 - 175: 34,20 - 176: 22,14 - 183: 6,14 - 184: 10,8 - 188: 16,2 - 190: 34,2 - 205: 21,2 - 213: 34,8 - 214: 30,14 - 219: 34,35 - 223: 30,39 - 224: 22,45 - 227: 14,45 - 230: 6,45 - 235: 10,35 - 834: 5,2 - 2018: 30,45 - - node: - color: '#DE3A3A96' - id: WarnLineGreyscaleN - decals: - 111: 17,28 - 116: 13,28 - 125: 19,40 - 126: 11,40 - 138: 21,28 - 144: 29,28 - 154: 1,28 - 158: 2,22 - 161: 8,22 - 165: 14,22 - 171: 20,22 - 173: 32,22 - 179: 19,16 - 180: 3,16 - 186: 17,10 - 209: 26,4 - 210: 29,10 - 217: 26,22 - 220: 29,36 - 228: 11,48 - 233: 3,48 - 237: 5,28 - 2020: 27,48 - - node: - color: '#FFFFFFFF' - id: WarnLineGreyscaleN - decals: - 667: 27,35 - 668: 28,35 - 669: 29,35 - 670: 30,35 - 671: 31,35 - - node: - color: '#DE3A3A96' - id: WarnLineGreyscaleS - decals: - 110: 17,24 - 115: 13,24 - 124: 19,38 - 127: 11,38 - 136: 20,30 - 137: 21,24 - 139: 25,24 - 143: 29,24 - 148: 33,24 - 149: 32,28 - 150: 33,28 - 151: 34,28 - 152: 1,24 - 157: 2,18 - 163: 8,18 - 164: 14,18 - 169: 20,18 - 172: 32,18 - 177: 19,12 - 181: 3,12 - 187: 17,6 - 208: 26,0 - 211: 29,6 - 216: 26,18 - 221: 29,34 - 229: 11,42 - 231: 3,42 - 236: 5,24 - 2019: 27,42 - - node: - color: '#FFFFFFFF' - id: WarnLineGreyscaleS - decals: - 662: 27,35 - 663: 28,35 - 664: 29,35 - 665: 30,35 - 666: 31,35 - - node: - color: '#DE3A3A96' - id: WarnLineGreyscaleW - decals: - 113: 16,26 - 114: 12,26 - 119: 20,26 - 120: 12,35 - 123: 16,39 - 129: 8,39 - 130: 0,39 - 133: 0,31 - 134: 14,31 - 141: 24,26 - 142: 28,26 - 147: 32,26 - 155: 0,26 - 156: 0,20 - 162: 6,20 - 167: 12,20 - 168: 18,20 - 174: 30,20 - 178: 16,14 - 182: 0,14 - 185: 0,8 - 189: 0,2 - 206: 18,2 - 207: 23,2 - 212: 24,8 - 215: 24,14 - 218: 24,35 - 222: 24,39 - 225: 16,45 - 226: 8,45 - 232: 0,45 - 234: 0,35 - 835: 11,2 - 2017: 24,45 - - node: - color: '#FFFFFFFF' - id: WarnLineN - decals: - 601: 10,38 - 602: 12,38 - 647: 27,34 - 648: 28,34 - 649: 30,34 - 650: 31,34 - 651: 32,34 - 732: 28,6 - 733: 27,6 - 734: 26,6 - 735: 25,6 - 736: 30,6 - 737: 31,6 - 738: 32,6 - 739: 33,6 - - node: - color: '#FFFFFFFF' - id: WarnLineS - decals: - 603: 9,39 - 742: 24,7 - 743: 24,9 - - node: - color: '#FFFFFFFF' - id: WarnLineW - decals: - 599: 10,40 - 600: 12,40 - 652: 27,36 - 653: 28,36 - 654: 30,36 - 655: 31,36 - 656: 32,36 - 724: 25,10 - 725: 26,10 - 726: 28,10 - 727: 27,10 - 728: 30,10 - 729: 31,10 - 730: 32,10 - 731: 33,10 - - node: - cleanable: True - color: '#80C71F7F' - id: revolution - decals: - 2138: 14.060958,20.754644 - 2139: 13.607299,19.803425 - - node: - cleanable: True - color: '#B02E60A3' - id: revolution - decals: - 2137: 25.02975,25.438416 - - node: - cleanable: True - angle: -1.5707963267948966 rad - color: '#B02E2644' - id: splatter - decals: - 2131: 27.967218,24.104916 - - node: - cleanable: True - color: '#B02E2666' - id: splatter - decals: - 2126: 8.891183,43.065514 - - node: - cleanable: True - angle: -1.5707963267948966 rad - color: '#B02E266F' - id: splatter - decals: - 2132: 28.36234,24.163452 - 2133: 32.200607,35.087025 - 2134: 13.24002,46.473877 - 2135: 24.497486,47.84553 - - node: - cleanable: True - angle: -4.71238898038469 rad - color: '#B02E26B4' - id: splatter - decals: - 2128: 8.788744,42.524048 - 2129: 15.538555,20.953827 - 2130: 24.864944,27.488853 - - node: - cleanable: True - angle: -3.141592653589793 rad - color: '#B02E26B4' - id: splatter - decals: - 2127: 9.110695,42.81673 - - type: RadiationGridResistance - - type: LoadedMap - - type: SpreaderGrid - - type: GridTree - - type: MovedGrids - - type: GridPathfinding -- proto: AirlockBrigGlassLocked - entities: - - uid: 1245 - components: - - type: Transform - pos: 15.5,35.5 - parent: 588 - - uid: 1246 - components: - - type: Transform - pos: 19.5,35.5 - parent: 588 - - uid: 1625 - components: - - type: Transform - pos: 22.5,2.5 - parent: 588 -- proto: AirlockEngineering - entities: - - uid: 1515 - components: - - type: Transform - pos: 19.5,43.5 - parent: 588 -- proto: AirlockSecurityGlassLocked - entities: - - uid: 1579 - components: - - type: Transform - pos: 11.5,15.5 - parent: 588 - - uid: 1609 - components: - - type: Transform - pos: 15.5,8.5 - parent: 588 - - uid: 1610 - components: - - type: Transform - pos: 19.5,8.5 - parent: 588 - - uid: 1623 - components: - - type: Transform - pos: 6.5,2.5 - parent: 588 - - uid: 1624 - components: - - type: Transform - pos: 10.5,2.5 - parent: 588 -- proto: APCBasic - entities: - - uid: 484 - components: - - type: Transform - pos: 25.5,13.5 - parent: 588 - - uid: 773 - components: - - type: Transform - pos: 25.5,19.5 - parent: 588 - - uid: 973 - components: - - type: Transform - pos: 21.5,32.5 - parent: 588 - - uid: 1509 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,47.5 - parent: 588 -- proto: BannerSecurity - entities: - - uid: 553 - components: - - type: Transform - pos: 30.5,8.5 - parent: 588 - - uid: 1619 - components: - - type: Transform - pos: 18.5,10.5 - parent: 588 - - uid: 1620 - components: - - type: Transform - pos: 16.5,6.5 - parent: 588 -- proto: BasaltFive - entities: - - uid: 608 - components: - - type: Transform - pos: 2.5,14.5 - parent: 588 - - uid: 647 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,21.5 - parent: 588 - - uid: 899 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,30.5 - parent: 588 - - uid: 1264 - components: - - type: Transform - pos: 9.5,0.5 - parent: 588 - - uid: 1384 - components: - - type: Transform - pos: 5.5,48.5 - parent: 588 - - uid: 1386 - components: - - type: Transform - pos: 0.5,47.5 - parent: 588 - - uid: 1387 - components: - - type: Transform - pos: 0.5,42.5 - parent: 588 - - uid: 1388 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,42.5 - parent: 588 -- proto: BasaltFour - entities: - - uid: 900 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,32.5 - parent: 588 - - uid: 904 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,40.5 - parent: 588 - - uid: 1381 - components: - - type: Transform - pos: 1.5,44.5 - parent: 588 - - uid: 1385 - components: - - type: Transform - pos: 6.5,48.5 - parent: 588 -- proto: BasaltOne - entities: - - uid: 813 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,27.5 - parent: 588 - - uid: 897 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,30.5 - parent: 588 - - uid: 901 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,32.5 - parent: 588 - - uid: 903 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,38.5 - parent: 588 - - uid: 1382 - components: - - type: Transform - pos: 1.5,48.5 - parent: 588 -- proto: BasaltRandom - entities: - - uid: 613 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,14.5 - parent: 588 - - uid: 615 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,7.5 - parent: 588 -- proto: BasaltThree - entities: - - uid: 616 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,7.5 - parent: 588 - - uid: 644 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,20.5 - parent: 588 - - uid: 898 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,30.5 - parent: 588 - - uid: 905 - components: - - type: Transform - pos: 4.5,38.5 - parent: 588 - - uid: 1265 - components: - - type: Transform - pos: 7.5,1.5 - parent: 588 - - uid: 1266 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 9.5,3.5 - parent: 588 - - uid: 1383 - components: - - type: Transform - pos: 6.5,47.5 - parent: 588 -- proto: BasaltTwo - entities: - - uid: 610 - components: - - type: Transform - pos: 3.5,14.5 - parent: 588 - - uid: 617 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,9.5 - parent: 588 - - uid: 618 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,8.5 - parent: 588 - - uid: 646 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,19.5 - parent: 588 - - uid: 814 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,26.5 - parent: 588 - - uid: 896 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,32.5 - parent: 588 - - uid: 902 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,38.5 - parent: 588 - - uid: 1263 - components: - - type: Transform - pos: 7.5,4.5 - parent: 588 - - uid: 1380 - components: - - type: Transform - pos: 1.5,43.5 - parent: 588 -- proto: Bed - entities: - - uid: 257 - components: - - type: Transform - pos: 15.5,4.5 - parent: 588 - - uid: 282 - components: - - type: Transform - pos: 1.5,4.5 - parent: 588 - - uid: 293 - components: - - type: Transform - pos: 3.5,4.5 - parent: 588 - - uid: 294 - components: - - type: Transform - pos: 5.5,4.5 - parent: 588 - - uid: 295 - components: - - type: Transform - pos: 11.5,4.5 - parent: 588 - - uid: 296 - components: - - type: Transform - pos: 13.5,4.5 - parent: 588 - - uid: 700 - components: - - type: Transform - pos: 12.5,22.5 - parent: 588 - - uid: 701 - components: - - type: Transform - pos: 16.5,18.5 - parent: 588 - - uid: 1043 - components: - - type: Transform - pos: 20.5,28.5 - parent: 588 - - uid: 1044 - components: - - type: Transform - pos: 22.5,24.5 - parent: 588 - - uid: 1075 - components: - - type: Transform - pos: 24.5,28.5 - parent: 588 - - uid: 1099 - components: - - type: Transform - pos: 20.5,36.5 - parent: 588 - - uid: 1100 - components: - - type: Transform - pos: 14.5,34.5 - parent: 588 - - uid: 1763 - components: - - type: Transform - pos: 24.5,48.5 - parent: 588 - - uid: 1764 - components: - - type: Transform - pos: 24.5,42.5 - parent: 588 -- proto: BedsheetMedical - entities: - - uid: 1150 - components: - - type: Transform - pos: 28.5,24.5 - parent: 588 - - uid: 1151 - components: - - type: Transform - pos: 28.5,25.5 - parent: 588 -- proto: BedsheetOrange - entities: - - uid: 298 - components: - - type: Transform - pos: 3.5,4.5 - parent: 588 - - uid: 299 - components: - - type: Transform - pos: 5.5,4.5 - parent: 588 - - uid: 300 - components: - - type: Transform - pos: 13.5,4.5 - parent: 588 - - uid: 1765 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,42.5 - parent: 588 -- proto: BedsheetSpawner - entities: - - uid: 301 - components: - - type: Transform - pos: 11.5,4.5 - parent: 588 - - uid: 1041 - components: - - type: Transform - pos: 20.5,28.5 - parent: 588 - - uid: 1225 - components: - - type: Transform - pos: 14.5,34.5 - parent: 588 - - uid: 1226 - components: - - type: Transform - pos: 20.5,36.5 - parent: 588 -- proto: BedsheetSyndie - entities: - - uid: 1037 - components: - - type: Transform - pos: 22.5,24.5 - parent: 588 - - uid: 1766 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,48.5 - parent: 588 -- proto: BlastDoor - entities: - - uid: 1600 - components: - - type: Transform - pos: 26.5,7.5 - parent: 588 - - uid: 1601 - components: - - type: Transform - pos: 29.5,9.5 - parent: 588 - - uid: 1602 - components: - - type: Transform - pos: 32.5,7.5 - parent: 588 -- proto: Bola - entities: - - uid: 1157 - components: - - type: Transform - pos: 15.616387,0.61007345 - parent: 588 -- proto: BookEscalationSecurity - entities: - - uid: 373 - components: - - type: Transform - pos: 19.42657,0.6288943 - parent: 588 -- proto: BookRandom - entities: - - uid: 1835 - components: - - type: Transform - pos: 24.420084,44.539436 - parent: 588 -- proto: BookSecurity - entities: - - uid: 522 - components: - - type: Transform - pos: 32.41844,8.400207 - parent: 588 -- proto: BoxFolderBlack - entities: - - uid: 365 - components: - - type: Transform - pos: 27.841173,1.5632035 - parent: 588 - - uid: 728 - components: - - type: Transform - pos: 10.690479,19.262342 - parent: 588 -- proto: BoxFolderGrey - entities: - - uid: 364 - components: - - type: Transform - pos: 25.072409,1.4780562 - parent: 588 - - uid: 727 - components: - - type: Transform - pos: 7.2148314,22.575037 - parent: 588 -- proto: BoxFolderRed - entities: - - uid: 329 - components: - - type: Transform - pos: 21.42984,3.6329575 - parent: 588 - - uid: 362 - components: - - type: Transform - pos: 24.788435,1.6057768 - parent: 588 - - uid: 363 - components: - - type: Transform - pos: 28.196142,1.5773941 - parent: 588 - - uid: 726 - components: - - type: Transform - pos: 10.428753,19.429379 - parent: 588 -- proto: BoxMouthSwab - entities: - - uid: 1476 - components: - - type: Transform - pos: 12.356534,44.605965 - parent: 588 -- proto: BoxSterileMask - entities: - - uid: 1477 - components: - - type: Transform - pos: 12.683106,44.705303 - parent: 588 -- proto: BriefcaseBrownFilled - entities: - - uid: 325 - components: - - type: Transform - pos: 19.413612,4.6972914 - parent: 588 -- proto: BrokenBottle - entities: - - uid: 1691 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.063513,27.520548 - parent: 588 -- proto: Bucket - entities: - - uid: 1839 - components: - - type: Transform - pos: 29.616838,43.531868 - parent: 588 - - uid: 1857 - components: - - type: Transform - pos: 30.264944,21.705044 - parent: 588 -- proto: CableApcExtension - entities: - - uid: 1 - components: - - type: Transform - pos: 0.5,2.5 - parent: 588 - - uid: 2 - components: - - type: Transform - pos: 1.5,2.5 - parent: 588 - - uid: 3 - components: - - type: Transform - pos: 2.5,2.5 - parent: 588 - - uid: 4 - components: - - type: Transform - pos: 3.5,2.5 - parent: 588 - - uid: 5 - components: - - type: Transform - pos: 4.5,2.5 - parent: 588 - - uid: 6 - components: - - type: Transform - pos: 5.5,2.5 - parent: 588 - - uid: 7 - components: - - type: Transform - pos: 6.5,2.5 - parent: 588 - - uid: 8 - components: - - type: Transform - pos: 7.5,2.5 - parent: 588 - - uid: 9 - components: - - type: Transform - pos: 8.5,2.5 - parent: 588 - - uid: 10 - components: - - type: Transform - pos: 9.5,2.5 - parent: 588 - - uid: 11 - components: - - type: Transform - pos: 10.5,2.5 - parent: 588 - - uid: 12 - components: - - type: Transform - pos: 11.5,2.5 - parent: 588 - - uid: 13 - components: - - type: Transform - pos: 12.5,2.5 - parent: 588 - - uid: 14 - components: - - type: Transform - pos: 13.5,2.5 - parent: 588 - - uid: 15 - components: - - type: Transform - pos: 14.5,2.5 - parent: 588 - - uid: 16 - components: - - type: Transform - pos: 15.5,2.5 - parent: 588 - - uid: 17 - components: - - type: Transform - pos: 16.5,2.5 - parent: 588 - - uid: 18 - components: - - type: Transform - pos: 8.5,4.5 - parent: 588 - - uid: 19 - components: - - type: Transform - pos: 8.5,3.5 - parent: 588 - - uid: 20 - components: - - type: Transform - pos: 8.5,1.5 - parent: 588 - - uid: 21 - components: - - type: Transform - pos: 8.5,0.5 - parent: 588 - - uid: 22 - components: - - type: Transform - pos: 18.5,2.5 - parent: 588 - - uid: 23 - components: - - type: Transform - pos: 19.5,2.5 - parent: 588 - - uid: 24 - components: - - type: Transform - pos: 20.5,2.5 - parent: 588 - - uid: 25 - components: - - type: Transform - pos: 21.5,2.5 - parent: 588 - - uid: 26 - components: - - type: Transform - pos: 22.5,2.5 - parent: 588 - - uid: 27 - components: - - type: Transform - pos: 23.5,2.5 - parent: 588 - - uid: 28 - components: - - type: Transform - pos: 24.5,2.5 - parent: 588 - - uid: 29 - components: - - type: Transform - pos: 25.5,2.5 - parent: 588 - - uid: 30 - components: - - type: Transform - pos: 26.5,2.5 - parent: 588 - - uid: 31 - components: - - type: Transform - pos: 27.5,2.5 - parent: 588 - - uid: 32 - components: - - type: Transform - pos: 28.5,2.5 - parent: 588 - - uid: 33 - components: - - type: Transform - pos: 29.5,2.5 - parent: 588 - - uid: 34 - components: - - type: Transform - pos: 30.5,2.5 - parent: 588 - - uid: 35 - components: - - type: Transform - pos: 31.5,2.5 - parent: 588 - - uid: 36 - components: - - type: Transform - pos: 32.5,2.5 - parent: 588 - - uid: 37 - components: - - type: Transform - pos: 33.5,2.5 - parent: 588 - - uid: 38 - components: - - type: Transform - pos: 34.5,2.5 - parent: 588 - - uid: 39 - components: - - type: Transform - pos: 26.5,4.5 - parent: 588 - - uid: 40 - components: - - type: Transform - pos: 26.5,3.5 - parent: 588 - - uid: 41 - components: - - type: Transform - pos: 26.5,1.5 - parent: 588 - - uid: 42 - components: - - type: Transform - pos: 26.5,0.5 - parent: 588 - - uid: 43 - components: - - type: Transform - pos: 0.5,8.5 - parent: 588 - - uid: 44 - components: - - type: Transform - pos: 1.5,8.5 - parent: 588 - - uid: 52 - components: - - type: Transform - pos: 9.5,8.5 - parent: 588 - - uid: 53 - components: - - type: Transform - pos: 10.5,8.5 - parent: 588 - - uid: 54 - components: - - type: Transform - pos: 5.5,10.5 - parent: 588 - - uid: 57 - components: - - type: Transform - pos: 5.5,6.5 - parent: 588 - - uid: 58 - components: - - type: Transform - pos: 17.5,6.5 - parent: 588 - - uid: 59 - components: - - type: Transform - pos: 17.5,7.5 - parent: 588 - - uid: 60 - components: - - type: Transform - pos: 17.5,8.5 - parent: 588 - - uid: 61 - components: - - type: Transform - pos: 17.5,9.5 - parent: 588 - - uid: 62 - components: - - type: Transform - pos: 17.5,10.5 - parent: 588 - - uid: 63 - components: - - type: Transform - pos: 12.5,8.5 - parent: 588 - - uid: 64 - components: - - type: Transform - pos: 13.5,8.5 - parent: 588 - - uid: 65 - components: - - type: Transform - pos: 14.5,8.5 - parent: 588 - - uid: 66 - components: - - type: Transform - pos: 15.5,8.5 - parent: 588 - - uid: 67 - components: - - type: Transform - pos: 16.5,8.5 - parent: 588 - - uid: 68 - components: - - type: Transform - pos: 18.5,8.5 - parent: 588 - - uid: 69 - components: - - type: Transform - pos: 19.5,8.5 - parent: 588 - - uid: 70 - components: - - type: Transform - pos: 20.5,8.5 - parent: 588 - - uid: 71 - components: - - type: Transform - pos: 21.5,8.5 - parent: 588 - - uid: 72 - components: - - type: Transform - pos: 22.5,8.5 - parent: 588 - - uid: 73 - components: - - type: Transform - pos: 22.5,14.5 - parent: 588 - - uid: 74 - components: - - type: Transform - pos: 21.5,14.5 - parent: 588 - - uid: 75 - components: - - type: Transform - pos: 20.5,14.5 - parent: 588 - - uid: 76 - components: - - type: Transform - pos: 19.5,14.5 - parent: 588 - - uid: 77 - components: - - type: Transform - pos: 18.5,14.5 - parent: 588 - - uid: 78 - components: - - type: Transform - pos: 17.5,14.5 - parent: 588 - - uid: 79 - components: - - type: Transform - pos: 16.5,14.5 - parent: 588 - - uid: 80 - components: - - type: Transform - pos: 19.5,13.5 - parent: 588 - - uid: 81 - components: - - type: Transform - pos: 19.5,12.5 - parent: 588 - - uid: 82 - components: - - type: Transform - pos: 19.5,15.5 - parent: 588 - - uid: 83 - components: - - type: Transform - pos: 19.5,16.5 - parent: 588 - - uid: 84 - components: - - type: Transform - pos: 14.5,14.5 - parent: 588 - - uid: 85 - components: - - type: Transform - pos: 13.5,14.5 - parent: 588 - - uid: 86 - components: - - type: Transform - pos: 12.5,14.5 - parent: 588 - - uid: 87 - components: - - type: Transform - pos: 11.5,14.5 - parent: 588 - - uid: 88 - components: - - type: Transform - pos: 10.5,14.5 - parent: 588 - - uid: 89 - components: - - type: Transform - pos: 9.5,14.5 - parent: 588 - - uid: 90 - components: - - type: Transform - pos: 8.5,14.5 - parent: 588 - - uid: 91 - components: - - type: Transform - pos: 11.5,13.5 - parent: 588 - - uid: 92 - components: - - type: Transform - pos: 11.5,12.5 - parent: 588 - - uid: 93 - components: - - type: Transform - pos: 11.5,15.5 - parent: 588 - - uid: 94 - components: - - type: Transform - pos: 11.5,16.5 - parent: 588 - - uid: 95 - components: - - type: Transform - pos: 6.5,14.5 - parent: 588 - - uid: 96 - components: - - type: Transform - pos: 5.5,14.5 - parent: 588 - - uid: 98 - components: - - type: Transform - pos: 4.5,22.5 - parent: 588 - - uid: 100 - components: - - type: Transform - pos: 1.5,14.5 - parent: 588 - - uid: 101 - components: - - type: Transform - pos: 0.5,14.5 - parent: 588 - - uid: 102 - components: - - type: Transform - pos: 3.5,15.5 - parent: 588 - - uid: 103 - components: - - type: Transform - pos: 3.5,16.5 - parent: 588 - - uid: 104 - components: - - type: Transform - pos: 3.5,13.5 - parent: 588 - - uid: 105 - components: - - type: Transform - pos: 3.5,12.5 - parent: 588 - - uid: 106 - components: - - type: Transform - pos: 14.5,18.5 - parent: 588 - - uid: 107 - components: - - type: Transform - pos: 14.5,19.5 - parent: 588 - - uid: 108 - components: - - type: Transform - pos: 14.5,20.5 - parent: 588 - - uid: 109 - components: - - type: Transform - pos: 14.5,21.5 - parent: 588 - - uid: 110 - components: - - type: Transform - pos: 14.5,22.5 - parent: 588 - - uid: 111 - components: - - type: Transform - pos: 15.5,20.5 - parent: 588 - - uid: 112 - components: - - type: Transform - pos: 16.5,20.5 - parent: 588 - - uid: 113 - components: - - type: Transform - pos: 13.5,20.5 - parent: 588 - - uid: 114 - components: - - type: Transform - pos: 12.5,20.5 - parent: 588 - - uid: 115 - components: - - type: Transform - pos: 8.5,18.5 - parent: 588 - - uid: 116 - components: - - type: Transform - pos: 8.5,19.5 - parent: 588 - - uid: 117 - components: - - type: Transform - pos: 8.5,20.5 - parent: 588 - - uid: 118 - components: - - type: Transform - pos: 8.5,21.5 - parent: 588 - - uid: 119 - components: - - type: Transform - pos: 8.5,22.5 - parent: 588 - - uid: 120 - components: - - type: Transform - pos: 9.5,20.5 - parent: 588 - - uid: 121 - components: - - type: Transform - pos: 10.5,20.5 - parent: 588 - - uid: 122 - components: - - type: Transform - pos: 7.5,20.5 - parent: 588 - - uid: 123 - components: - - type: Transform - pos: 6.5,20.5 - parent: 588 - - uid: 124 - components: - - type: Transform - pos: 2.5,22.5 - parent: 588 - - uid: 125 - components: - - type: Transform - pos: 4.5,21.5 - parent: 588 - - uid: 126 - components: - - type: Transform - pos: 4.5,19.5 - parent: 588 - - uid: 127 - components: - - type: Transform - pos: 3.5,18.5 - parent: 588 - - uid: 128 - components: - - type: Transform - pos: 2.5,18.5 - parent: 588 - - uid: 129 - components: - - type: Transform - pos: 3.5,22.5 - parent: 588 - - uid: 130 - components: - - type: Transform - pos: 0.5,20.5 - parent: 588 - - uid: 131 - components: - - type: Transform - pos: 4.5,18.5 - parent: 588 - - uid: 132 - components: - - type: Transform - pos: 4.5,20.5 - parent: 588 - - uid: 133 - components: - - type: Transform - pos: 1.5,24.5 - parent: 588 - - uid: 134 - components: - - type: Transform - pos: 2.5,25.5 - parent: 588 - - uid: 135 - components: - - type: Transform - pos: 0.5,24.5 - parent: 588 - - uid: 136 - components: - - type: Transform - pos: 2.5,24.5 - parent: 588 - - uid: 137 - components: - - type: Transform - pos: 1.5,28.5 - parent: 588 - - uid: 138 - components: - - type: Transform - pos: 0.5,26.5 - parent: 588 - - uid: 139 - components: - - type: Transform - pos: 2.5,26.5 - parent: 588 - - uid: 147 - components: - - type: Transform - pos: 9.5,28.5 - parent: 588 - - uid: 148 - components: - - type: Transform - pos: 9.5,27.5 - parent: 588 - - uid: 149 - components: - - type: Transform - pos: 9.5,26.5 - parent: 588 - - uid: 150 - components: - - type: Transform - pos: 9.5,25.5 - parent: 588 - - uid: 151 - components: - - type: Transform - pos: 9.5,24.5 - parent: 588 - - uid: 152 - components: - - type: Transform - pos: 8.5,26.5 - parent: 588 - - uid: 153 - components: - - type: Transform - pos: 10.5,26.5 - parent: 588 - - uid: 154 - components: - - type: Transform - pos: 13.5,28.5 - parent: 588 - - uid: 155 - components: - - type: Transform - pos: 13.5,27.5 - parent: 588 - - uid: 156 - components: - - type: Transform - pos: 13.5,26.5 - parent: 588 - - uid: 157 - components: - - type: Transform - pos: 13.5,25.5 - parent: 588 - - uid: 158 - components: - - type: Transform - pos: 13.5,24.5 - parent: 588 - - uid: 159 - components: - - type: Transform - pos: 12.5,26.5 - parent: 588 - - uid: 160 - components: - - type: Transform - pos: 14.5,26.5 - parent: 588 - - uid: 161 - components: - - type: Transform - pos: 0.5,31.5 - parent: 588 - - uid: 162 - components: - - type: Transform - pos: 1.5,31.5 - parent: 588 - - uid: 163 - components: - - type: Transform - pos: 2.5,31.5 - parent: 588 - - uid: 164 - components: - - type: Transform - pos: 3.5,31.5 - parent: 588 - - uid: 165 - components: - - type: Transform - pos: 4.5,31.5 - parent: 588 - - uid: 166 - components: - - type: Transform - pos: 5.5,31.5 - parent: 588 - - uid: 167 - components: - - type: Transform - pos: 6.5,31.5 - parent: 588 - - uid: 168 - components: - - type: Transform - pos: 7.5,31.5 - parent: 588 - - uid: 169 - components: - - type: Transform - pos: 8.5,31.5 - parent: 588 - - uid: 170 - components: - - type: Transform - pos: 9.5,31.5 - parent: 588 - - uid: 171 - components: - - type: Transform - pos: 10.5,31.5 - parent: 588 - - uid: 172 - components: - - type: Transform - pos: 11.5,31.5 - parent: 588 - - uid: 173 - components: - - type: Transform - pos: 12.5,31.5 - parent: 588 - - uid: 174 - components: - - type: Transform - pos: 6.5,30.5 - parent: 588 - - uid: 175 - components: - - type: Transform - pos: 6.5,32.5 - parent: 588 - - uid: 176 - components: - - type: Transform - pos: 26.5,31.5 - parent: 588 - - uid: 177 - components: - - type: Transform - pos: 25.5,31.5 - parent: 588 - - uid: 178 - components: - - type: Transform - pos: 24.5,31.5 - parent: 588 - - uid: 179 - components: - - type: Transform - pos: 23.5,31.5 - parent: 588 - - uid: 180 - components: - - type: Transform - pos: 22.5,31.5 - parent: 588 - - uid: 181 - components: - - type: Transform - pos: 21.5,31.5 - parent: 588 - - uid: 182 - components: - - type: Transform - pos: 20.5,31.5 - parent: 588 - - uid: 183 - components: - - type: Transform - pos: 19.5,31.5 - parent: 588 - - uid: 184 - components: - - type: Transform - pos: 18.5,31.5 - parent: 588 - - uid: 185 - components: - - type: Transform - pos: 17.5,31.5 - parent: 588 - - uid: 186 - components: - - type: Transform - pos: 16.5,31.5 - parent: 588 - - uid: 187 - components: - - type: Transform - pos: 15.5,31.5 - parent: 588 - - uid: 188 - components: - - type: Transform - pos: 14.5,31.5 - parent: 588 - - uid: 189 - components: - - type: Transform - pos: 20.5,32.5 - parent: 588 - - uid: 190 - components: - - type: Transform - pos: 20.5,30.5 - parent: 588 - - uid: 191 - components: - - type: Transform - pos: 22.5,35.5 - parent: 588 - - uid: 192 - components: - - type: Transform - pos: 21.5,35.5 - parent: 588 - - uid: 193 - components: - - type: Transform - pos: 20.5,35.5 - parent: 588 - - uid: 194 - components: - - type: Transform - pos: 19.5,35.5 - parent: 588 - - uid: 195 - components: - - type: Transform - pos: 18.5,35.5 - parent: 588 - - uid: 196 - components: - - type: Transform - pos: 17.5,35.5 - parent: 588 - - uid: 197 - components: - - type: Transform - pos: 16.5,35.5 - parent: 588 - - uid: 198 - components: - - type: Transform - pos: 15.5,35.5 - parent: 588 - - uid: 199 - components: - - type: Transform - pos: 14.5,35.5 - parent: 588 - - uid: 200 - components: - - type: Transform - pos: 13.5,35.5 - parent: 588 - - uid: 201 - components: - - type: Transform - pos: 12.5,35.5 - parent: 588 - - uid: 202 - components: - - type: Transform - pos: 17.5,36.5 - parent: 588 - - uid: 203 - components: - - type: Transform - pos: 17.5,34.5 - parent: 588 - - uid: 204 - components: - - type: Transform - pos: 10.5,35.5 - parent: 588 - - uid: 215 - components: - - type: Transform - pos: 5.5,36.5 - parent: 588 - - uid: 216 - components: - - type: Transform - pos: 5.5,34.5 - parent: 588 - - uid: 217 - components: - - type: Transform - pos: 0.5,39.5 - parent: 588 - - uid: 218 - components: - - type: Transform - pos: 1.5,39.5 - parent: 588 - - uid: 219 - components: - - type: Transform - pos: 2.5,39.5 - parent: 588 - - uid: 220 - components: - - type: Transform - pos: 3.5,39.5 - parent: 588 - - uid: 221 - components: - - type: Transform - pos: 4.5,39.5 - parent: 588 - - uid: 222 - components: - - type: Transform - pos: 5.5,39.5 - parent: 588 - - uid: 223 - components: - - type: Transform - pos: 6.5,39.5 - parent: 588 - - uid: 224 - components: - - type: Transform - pos: 3.5,38.5 - parent: 588 - - uid: 225 - components: - - type: Transform - pos: 3.5,40.5 - parent: 588 - - uid: 226 - components: - - type: Transform - pos: 8.5,39.5 - parent: 588 - - uid: 227 - components: - - type: Transform - pos: 9.5,39.5 - parent: 588 - - uid: 228 - components: - - type: Transform - pos: 10.5,39.5 - parent: 588 - - uid: 229 - components: - - type: Transform - pos: 11.5,39.5 - parent: 588 - - uid: 230 - components: - - type: Transform - pos: 12.5,39.5 - parent: 588 - - uid: 231 - components: - - type: Transform - pos: 13.5,39.5 - parent: 588 - - uid: 232 - components: - - type: Transform - pos: 14.5,39.5 - parent: 588 - - uid: 233 - components: - - type: Transform - pos: 11.5,38.5 - parent: 588 - - uid: 234 - components: - - type: Transform - pos: 11.5,40.5 - parent: 588 - - uid: 235 - components: - - type: Transform - pos: 16.5,39.5 - parent: 588 - - uid: 236 - components: - - type: Transform - pos: 17.5,39.5 - parent: 588 - - uid: 237 - components: - - type: Transform - pos: 18.5,39.5 - parent: 588 - - uid: 238 - components: - - type: Transform - pos: 19.5,39.5 - parent: 588 - - uid: 239 - components: - - type: Transform - pos: 20.5,39.5 - parent: 588 - - uid: 240 - components: - - type: Transform - pos: 21.5,39.5 - parent: 588 - - uid: 241 - components: - - type: Transform - pos: 22.5,39.5 - parent: 588 - - uid: 242 - components: - - type: Transform - pos: 19.5,40.5 - parent: 588 - - uid: 243 - components: - - type: Transform - pos: 19.5,38.5 - parent: 588 - - uid: 284 - components: - - type: Transform - pos: 29.5,26.5 - parent: 588 - - uid: 288 - components: - - type: Transform - pos: 28.5,26.5 - parent: 588 - - uid: 425 - components: - - type: Transform - pos: 1.5,10.5 - parent: 588 - - uid: 438 - components: - - type: Transform - pos: 1.5,9.5 - parent: 588 - - uid: 441 - components: - - type: Transform - pos: 2.5,10.5 - parent: 588 - - uid: 442 - components: - - type: Transform - pos: 3.5,10.5 - parent: 588 - - uid: 443 - components: - - type: Transform - pos: 4.5,10.5 - parent: 588 - - uid: 444 - components: - - type: Transform - pos: 1.5,7.5 - parent: 588 - - uid: 445 - components: - - type: Transform - pos: 1.5,6.5 - parent: 588 - - uid: 446 - components: - - type: Transform - pos: 2.5,6.5 - parent: 588 - - uid: 447 - components: - - type: Transform - pos: 3.5,6.5 - parent: 588 - - uid: 448 - components: - - type: Transform - pos: 4.5,6.5 - parent: 588 - - uid: 449 - components: - - type: Transform - pos: 6.5,6.5 - parent: 588 - - uid: 450 - components: - - type: Transform - pos: 7.5,6.5 - parent: 588 - - uid: 451 - components: - - type: Transform - pos: 8.5,6.5 - parent: 588 - - uid: 452 - components: - - type: Transform - pos: 9.5,6.5 - parent: 588 - - uid: 453 - components: - - type: Transform - pos: 9.5,7.5 - parent: 588 - - uid: 454 - components: - - type: Transform - pos: 9.5,9.5 - parent: 588 - - uid: 455 - components: - - type: Transform - pos: 9.5,10.5 - parent: 588 - - uid: 456 - components: - - type: Transform - pos: 8.5,10.5 - parent: 588 - - uid: 457 - components: - - type: Transform - pos: 7.5,10.5 - parent: 588 - - uid: 472 - components: - - type: Transform - pos: 29.5,14.5 - parent: 588 - - uid: 477 - components: - - type: Transform - pos: 24.5,13.5 - parent: 588 - - uid: 479 - components: - - type: Transform - pos: 30.5,14.5 - parent: 588 - - uid: 493 - components: - - type: Transform - pos: 25.5,13.5 - parent: 588 - - uid: 494 - components: - - type: Transform - pos: 25.5,12.5 - parent: 588 - - uid: 495 - components: - - type: Transform - pos: 26.5,12.5 - parent: 588 - - uid: 496 - components: - - type: Transform - pos: 27.5,12.5 - parent: 588 - - uid: 497 - components: - - type: Transform - pos: 28.5,12.5 - parent: 588 - - uid: 498 - components: - - type: Transform - pos: 29.5,12.5 - parent: 588 - - uid: 500 - components: - - type: Transform - pos: 24.5,12.5 - parent: 588 - - uid: 502 - components: - - type: Transform - pos: 24.5,14.5 - parent: 588 - - uid: 503 - components: - - type: Transform - pos: 24.5,15.5 - parent: 588 - - uid: 504 - components: - - type: Transform - pos: 24.5,16.5 - parent: 588 - - uid: 505 - components: - - type: Transform - pos: 25.5,16.5 - parent: 588 - - uid: 506 - components: - - type: Transform - pos: 26.5,16.5 - parent: 588 - - uid: 507 - components: - - type: Transform - pos: 27.5,16.5 - parent: 588 - - uid: 508 - components: - - type: Transform - pos: 28.5,16.5 - parent: 588 - - uid: 509 - components: - - type: Transform - pos: 29.5,16.5 - parent: 588 - - uid: 514 - components: - - type: Transform - pos: 29.5,13.5 - parent: 588 - - uid: 523 - components: - - type: Transform - pos: 29.5,15.5 - parent: 588 - - uid: 628 - components: - - type: Transform - pos: 1.5,22.5 - parent: 588 - - uid: 639 - components: - - type: Transform - pos: 0.5,22.5 - parent: 588 - - uid: 640 - components: - - type: Transform - pos: 0.5,21.5 - parent: 588 - - uid: 641 - components: - - type: Transform - pos: 0.5,19.5 - parent: 588 - - uid: 642 - components: - - type: Transform - pos: 0.5,18.5 - parent: 588 - - uid: 643 - components: - - type: Transform - pos: 1.5,18.5 - parent: 588 - - uid: 657 - components: - - type: Transform - pos: 2.5,15.5 - parent: 588 - - uid: 661 - components: - - type: Transform - pos: 1.5,15.5 - parent: 588 - - uid: 662 - components: - - type: Transform - pos: 1.5,13.5 - parent: 588 - - uid: 663 - components: - - type: Transform - pos: 2.5,13.5 - parent: 588 - - uid: 664 - components: - - type: Transform - pos: 4.5,13.5 - parent: 588 - - uid: 665 - components: - - type: Transform - pos: 5.5,13.5 - parent: 588 - - uid: 666 - components: - - type: Transform - pos: 5.5,15.5 - parent: 588 - - uid: 667 - components: - - type: Transform - pos: 4.5,15.5 - parent: 588 - - uid: 668 - components: - - type: Transform - pos: 29.5,10.5 - parent: 588 - - uid: 669 - components: - - type: Transform - pos: 28.5,10.5 - parent: 588 - - uid: 670 - components: - - type: Transform - pos: 27.5,10.5 - parent: 588 - - uid: 671 - components: - - type: Transform - pos: 26.5,10.5 - parent: 588 - - uid: 672 - components: - - type: Transform - pos: 25.5,10.5 - parent: 588 - - uid: 673 - components: - - type: Transform - pos: 24.5,10.5 - parent: 588 - - uid: 674 - components: - - type: Transform - pos: 24.5,9.5 - parent: 588 - - uid: 675 - components: - - type: Transform - pos: 24.5,8.5 - parent: 588 - - uid: 676 - components: - - type: Transform - pos: 24.5,7.5 - parent: 588 - - uid: 677 - components: - - type: Transform - pos: 24.5,6.5 - parent: 588 - - uid: 678 - components: - - type: Transform - pos: 25.5,6.5 - parent: 588 - - uid: 679 - components: - - type: Transform - pos: 26.5,6.5 - parent: 588 - - uid: 680 - components: - - type: Transform - pos: 27.5,6.5 - parent: 588 - - uid: 681 - components: - - type: Transform - pos: 28.5,6.5 - parent: 588 - - uid: 682 - components: - - type: Transform - pos: 29.5,6.5 - parent: 588 - - uid: 683 - components: - - type: Transform - pos: 30.5,6.5 - parent: 588 - - uid: 684 - components: - - type: Transform - pos: 31.5,6.5 - parent: 588 - - uid: 685 - components: - - type: Transform - pos: 32.5,6.5 - parent: 588 - - uid: 686 - components: - - type: Transform - pos: 33.5,6.5 - parent: 588 - - uid: 687 - components: - - type: Transform - pos: 34.5,6.5 - parent: 588 - - uid: 688 - components: - - type: Transform - pos: 34.5,7.5 - parent: 588 - - uid: 689 - components: - - type: Transform - pos: 34.5,8.5 - parent: 588 - - uid: 690 - components: - - type: Transform - pos: 34.5,9.5 - parent: 588 - - uid: 691 - components: - - type: Transform - pos: 34.5,10.5 - parent: 588 - - uid: 692 - components: - - type: Transform - pos: 33.5,10.5 - parent: 588 - - uid: 693 - components: - - type: Transform - pos: 32.5,10.5 - parent: 588 - - uid: 694 - components: - - type: Transform - pos: 31.5,10.5 - parent: 588 - - uid: 695 - components: - - type: Transform - pos: 30.5,10.5 - parent: 588 - - uid: 733 - components: - - type: Transform - pos: 20.5,18.5 - parent: 588 - - uid: 734 - components: - - type: Transform - pos: 20.5,19.5 - parent: 588 - - uid: 735 - components: - - type: Transform - pos: 20.5,20.5 - parent: 588 - - uid: 736 - components: - - type: Transform - pos: 20.5,21.5 - parent: 588 - - uid: 737 - components: - - type: Transform - pos: 20.5,22.5 - parent: 588 - - uid: 738 - components: - - type: Transform - pos: 21.5,20.5 - parent: 588 - - uid: 739 - components: - - type: Transform - pos: 22.5,20.5 - parent: 588 - - uid: 740 - components: - - type: Transform - pos: 19.5,20.5 - parent: 588 - - uid: 741 - components: - - type: Transform - pos: 18.5,20.5 - parent: 588 - - uid: 751 - components: - - type: Transform - pos: 32.5,22.5 - parent: 588 - - uid: 752 - components: - - type: Transform - pos: 32.5,21.5 - parent: 588 - - uid: 753 - components: - - type: Transform - pos: 32.5,20.5 - parent: 588 - - uid: 754 - components: - - type: Transform - pos: 32.5,19.5 - parent: 588 - - uid: 755 - components: - - type: Transform - pos: 32.5,18.5 - parent: 588 - - uid: 756 - components: - - type: Transform - pos: 31.5,20.5 - parent: 588 - - uid: 757 - components: - - type: Transform - pos: 30.5,20.5 - parent: 588 - - uid: 758 - components: - - type: Transform - pos: 33.5,20.5 - parent: 588 - - uid: 759 - components: - - type: Transform - pos: 34.5,20.5 - parent: 588 - - uid: 779 - components: - - type: Transform - pos: 25.5,19.5 - parent: 588 - - uid: 780 - components: - - type: Transform - pos: 25.5,18.5 - parent: 588 - - uid: 781 - components: - - type: Transform - pos: 24.5,18.5 - parent: 588 - - uid: 782 - components: - - type: Transform - pos: 24.5,19.5 - parent: 588 - - uid: 783 - components: - - type: Transform - pos: 24.5,20.5 - parent: 588 - - uid: 784 - components: - - type: Transform - pos: 24.5,21.5 - parent: 588 - - uid: 785 - components: - - type: Transform - pos: 24.5,22.5 - parent: 588 - - uid: 786 - components: - - type: Transform - pos: 25.5,22.5 - parent: 588 - - uid: 787 - components: - - type: Transform - pos: 26.5,22.5 - parent: 588 - - uid: 788 - components: - - type: Transform - pos: 27.5,22.5 - parent: 588 - - uid: 789 - components: - - type: Transform - pos: 28.5,22.5 - parent: 588 - - uid: 790 - components: - - type: Transform - pos: 28.5,21.5 - parent: 588 - - uid: 791 - components: - - type: Transform - pos: 28.5,20.5 - parent: 588 - - uid: 792 - components: - - type: Transform - pos: 28.5,19.5 - parent: 588 - - uid: 793 - components: - - type: Transform - pos: 28.5,18.5 - parent: 588 - - uid: 794 - components: - - type: Transform - pos: 27.5,18.5 - parent: 588 - - uid: 795 - components: - - type: Transform - pos: 26.5,18.5 - parent: 588 - - uid: 815 - components: - - type: Transform - pos: 0.5,25.5 - parent: 588 - - uid: 816 - components: - - type: Transform - pos: 0.5,27.5 - parent: 588 - - uid: 817 - components: - - type: Transform - pos: 0.5,28.5 - parent: 588 - - uid: 818 - components: - - type: Transform - pos: 2.5,28.5 - parent: 588 - - uid: 819 - components: - - type: Transform - pos: 2.5,27.5 - parent: 588 - - uid: 869 - components: - - type: Transform - pos: 5.5,24.5 - parent: 588 - - uid: 870 - components: - - type: Transform - pos: 6.5,24.5 - parent: 588 - - uid: 871 - components: - - type: Transform - pos: 6.5,25.5 - parent: 588 - - uid: 872 - components: - - type: Transform - pos: 6.5,26.5 - parent: 588 - - uid: 873 - components: - - type: Transform - pos: 6.5,27.5 - parent: 588 - - uid: 874 - components: - - type: Transform - pos: 6.5,28.5 - parent: 588 - - uid: 875 - components: - - type: Transform - pos: 5.5,28.5 - parent: 588 - - uid: 876 - components: - - type: Transform - pos: 4.5,28.5 - parent: 588 - - uid: 877 - components: - - type: Transform - pos: 4.5,27.5 - parent: 588 - - uid: 878 - components: - - type: Transform - pos: 4.5,26.5 - parent: 588 - - uid: 912 - components: - - type: Transform - pos: 6.5,10.5 - parent: 588 - - uid: 927 - components: - - type: Transform - pos: 34.5,36.5 - parent: 588 - - uid: 928 - components: - - type: Transform - pos: 32.5,36.5 - parent: 588 - - uid: 996 - components: - - type: Transform - pos: 21.5,32.5 - parent: 588 - - uid: 1079 - components: - - type: Transform - pos: 32.5,35.5 - parent: 588 - - uid: 1080 - components: - - type: Transform - pos: 31.5,35.5 - parent: 588 - - uid: 1081 - components: - - type: Transform - pos: 32.5,34.5 - parent: 588 - - uid: 1082 - components: - - type: Transform - pos: 29.5,34.5 - parent: 588 - - uid: 1083 - components: - - type: Transform - pos: 24.5,35.5 - parent: 588 - - uid: 1084 - components: - - type: Transform - pos: 27.5,35.5 - parent: 588 - - uid: 1085 - components: - - type: Transform - pos: 29.5,35.5 - parent: 588 - - uid: 1086 - components: - - type: Transform - pos: 28.5,35.5 - parent: 588 - - uid: 1089 - components: - - type: Transform - pos: 4.5,36.5 - parent: 588 - - uid: 1090 - components: - - type: Transform - pos: 33.5,34.5 - parent: 588 - - uid: 1091 - components: - - type: Transform - pos: 5.5,35.5 - parent: 588 - - uid: 1092 - components: - - type: Transform - pos: 29.5,36.5 - parent: 588 - - uid: 1093 - components: - - type: Transform - pos: 34.5,34.5 - parent: 588 - - uid: 1094 - components: - - type: Transform - pos: 34.5,35.5 - parent: 588 - - uid: 1095 - components: - - type: Transform - pos: 26.5,35.5 - parent: 588 - - uid: 1096 - components: - - type: Transform - pos: 25.5,35.5 - parent: 588 - - uid: 1097 - components: - - type: Transform - pos: 33.5,36.5 - parent: 588 - - uid: 1098 - components: - - type: Transform - pos: 30.5,35.5 - parent: 588 - - uid: 1117 - components: - - type: Transform - pos: 16.5,26.5 - parent: 588 - - uid: 1121 - components: - - type: Transform - pos: 17.5,26.5 - parent: 588 - - uid: 1122 - components: - - type: Transform - pos: 18.5,26.5 - parent: 588 - - uid: 1123 - components: - - type: Transform - pos: 17.5,27.5 - parent: 588 - - uid: 1124 - components: - - type: Transform - pos: 17.5,28.5 - parent: 588 - - uid: 1125 - components: - - type: Transform - pos: 17.5,24.5 - parent: 588 - - uid: 1126 - components: - - type: Transform - pos: 17.5,25.5 - parent: 588 - - uid: 1127 - components: - - type: Transform - pos: 20.5,26.5 - parent: 588 - - uid: 1128 - components: - - type: Transform - pos: 21.5,26.5 - parent: 588 - - uid: 1129 - components: - - type: Transform - pos: 22.5,26.5 - parent: 588 - - uid: 1130 - components: - - type: Transform - pos: 21.5,27.5 - parent: 588 - - uid: 1131 - components: - - type: Transform - pos: 21.5,28.5 - parent: 588 - - uid: 1132 - components: - - type: Transform - pos: 21.5,25.5 - parent: 588 - - uid: 1133 - components: - - type: Transform - pos: 21.5,24.5 - parent: 588 - - uid: 1134 - components: - - type: Transform - pos: 24.5,26.5 - parent: 588 - - uid: 1135 - components: - - type: Transform - pos: 25.5,26.5 - parent: 588 - - uid: 1136 - components: - - type: Transform - pos: 26.5,26.5 - parent: 588 - - uid: 1137 - components: - - type: Transform - pos: 25.5,27.5 - parent: 588 - - uid: 1138 - components: - - type: Transform - pos: 25.5,28.5 - parent: 588 - - uid: 1139 - components: - - type: Transform - pos: 25.5,25.5 - parent: 588 - - uid: 1140 - components: - - type: Transform - pos: 25.5,24.5 - parent: 588 - - uid: 1170 - components: - - type: Transform - pos: 3.5,36.5 - parent: 588 - - uid: 1171 - components: - - type: Transform - pos: 2.5,36.5 - parent: 588 - - uid: 1172 - components: - - type: Transform - pos: 1.5,36.5 - parent: 588 - - uid: 1173 - components: - - type: Transform - pos: 0.5,36.5 - parent: 588 - - uid: 1174 - components: - - type: Transform - pos: 0.5,35.5 - parent: 588 - - uid: 1175 - components: - - type: Transform - pos: 6.5,34.5 - parent: 588 - - uid: 1176 - components: - - type: Transform - pos: 7.5,34.5 - parent: 588 - - uid: 1177 - components: - - type: Transform - pos: 8.5,34.5 - parent: 588 - - uid: 1178 - components: - - type: Transform - pos: 9.5,34.5 - parent: 588 - - uid: 1179 - components: - - type: Transform - pos: 10.5,34.5 - parent: 588 - - uid: 1268 - components: - - type: Transform - pos: 30.5,26.5 - parent: 588 - - uid: 1269 - components: - - type: Transform - pos: 29.5,27.5 - parent: 588 - - uid: 1270 - components: - - type: Transform - pos: 29.5,28.5 - parent: 588 - - uid: 1271 - components: - - type: Transform - pos: 29.5,25.5 - parent: 588 - - uid: 1272 - components: - - type: Transform - pos: 29.5,24.5 - parent: 588 - - uid: 1273 - components: - - type: Transform - pos: 32.5,26.5 - parent: 588 - - uid: 1274 - components: - - type: Transform - pos: 33.5,26.5 - parent: 588 - - uid: 1275 - components: - - type: Transform - pos: 34.5,26.5 - parent: 588 - - uid: 1276 - components: - - type: Transform - pos: 33.5,27.5 - parent: 588 - - uid: 1277 - components: - - type: Transform - pos: 33.5,28.5 - parent: 588 - - uid: 1278 - components: - - type: Transform - pos: 33.5,25.5 - parent: 588 - - uid: 1279 - components: - - type: Transform - pos: 33.5,24.5 - parent: 588 - - uid: 1306 - components: - - type: Transform - pos: 27.5,40.5 - parent: 588 - - uid: 1307 - components: - - type: Transform - pos: 26.5,40.5 - parent: 588 - - uid: 1308 - components: - - type: Transform - pos: 25.5,40.5 - parent: 588 - - uid: 1309 - components: - - type: Transform - pos: 24.5,40.5 - parent: 588 - - uid: 1310 - components: - - type: Transform - pos: 24.5,39.5 - parent: 588 - - uid: 1311 - components: - - type: Transform - pos: 24.5,38.5 - parent: 588 - - uid: 1312 - components: - - type: Transform - pos: 25.5,38.5 - parent: 588 - - uid: 1313 - components: - - type: Transform - pos: 26.5,38.5 - parent: 588 - - uid: 1314 - components: - - type: Transform - pos: 27.5,38.5 - parent: 588 - - uid: 1315 - components: - - type: Transform - pos: 28.5,38.5 - parent: 588 - - uid: 1316 - components: - - type: Transform - pos: 29.5,38.5 - parent: 588 - - uid: 1317 - components: - - type: Transform - pos: 30.5,38.5 - parent: 588 - - uid: 1318 - components: - - type: Transform - pos: 30.5,39.5 - parent: 588 - - uid: 1426 - components: - - type: Transform - pos: 11.5,42.5 - parent: 588 - - uid: 1427 - components: - - type: Transform - pos: 11.5,43.5 - parent: 588 - - uid: 1428 - components: - - type: Transform - pos: 11.5,44.5 - parent: 588 - - uid: 1429 - components: - - type: Transform - pos: 11.5,45.5 - parent: 588 - - uid: 1430 - components: - - type: Transform - pos: 11.5,46.5 - parent: 588 - - uid: 1431 - components: - - type: Transform - pos: 11.5,47.5 - parent: 588 - - uid: 1432 - components: - - type: Transform - pos: 11.5,48.5 - parent: 588 - - uid: 1433 - components: - - type: Transform - pos: 10.5,45.5 - parent: 588 - - uid: 1434 - components: - - type: Transform - pos: 9.5,45.5 - parent: 588 - - uid: 1435 - components: - - type: Transform - pos: 8.5,45.5 - parent: 588 - - uid: 1436 - components: - - type: Transform - pos: 12.5,45.5 - parent: 588 - - uid: 1437 - components: - - type: Transform - pos: 13.5,45.5 - parent: 588 - - uid: 1438 - components: - - type: Transform - pos: 14.5,45.5 - parent: 588 - - uid: 1439 - components: - - type: Transform - pos: 13.5,46.5 - parent: 588 - - uid: 1440 - components: - - type: Transform - pos: 13.5,47.5 - parent: 588 - - uid: 1441 - components: - - type: Transform - pos: 9.5,46.5 - parent: 588 - - uid: 1442 - components: - - type: Transform - pos: 9.5,47.5 - parent: 588 - - uid: 1443 - components: - - type: Transform - pos: 10.5,43.5 - parent: 588 - - uid: 1444 - components: - - type: Transform - pos: 9.5,43.5 - parent: 588 - - uid: 1445 - components: - - type: Transform - pos: 12.5,43.5 - parent: 588 - - uid: 1446 - components: - - type: Transform - pos: 13.5,43.5 - parent: 588 - - uid: 1447 - components: - - type: Transform - pos: 3.5,42.5 - parent: 588 - - uid: 1448 - components: - - type: Transform - pos: 3.5,43.5 - parent: 588 - - uid: 1449 - components: - - type: Transform - pos: 3.5,44.5 - parent: 588 - - uid: 1450 - components: - - type: Transform - pos: 3.5,45.5 - parent: 588 - - uid: 1451 - components: - - type: Transform - pos: 3.5,46.5 - parent: 588 - - uid: 1452 - components: - - type: Transform - pos: 3.5,47.5 - parent: 588 - - uid: 1453 - components: - - type: Transform - pos: 3.5,48.5 - parent: 588 - - uid: 1454 - components: - - type: Transform - pos: 0.5,45.5 - parent: 588 - - uid: 1455 - components: - - type: Transform - pos: 1.5,45.5 - parent: 588 - - uid: 1456 - components: - - type: Transform - pos: 2.5,45.5 - parent: 588 - - uid: 1457 - components: - - type: Transform - pos: 3.5,45.5 - parent: 588 - - uid: 1458 - components: - - type: Transform - pos: 4.5,45.5 - parent: 588 - - uid: 1459 - components: - - type: Transform - pos: 5.5,45.5 - parent: 588 - - uid: 1460 - components: - - type: Transform - pos: 6.5,45.5 - parent: 588 - - uid: 1529 - components: - - type: Transform - pos: 19.5,47.5 - parent: 588 - - uid: 1530 - components: - - type: Transform - pos: 19.5,48.5 - parent: 588 - - uid: 1531 - components: - - type: Transform - pos: 18.5,48.5 - parent: 588 - - uid: 1532 - components: - - type: Transform - pos: 17.5,48.5 - parent: 588 - - uid: 1533 - components: - - type: Transform - pos: 16.5,48.5 - parent: 588 - - uid: 1534 - components: - - type: Transform - pos: 16.5,47.5 - parent: 588 - - uid: 1535 - components: - - type: Transform - pos: 16.5,46.5 - parent: 588 - - uid: 1536 - components: - - type: Transform - pos: 16.5,45.5 - parent: 588 - - uid: 1537 - components: - - type: Transform - pos: 16.5,44.5 - parent: 588 - - uid: 1538 - components: - - type: Transform - pos: 16.5,43.5 - parent: 588 - - uid: 1539 - components: - - type: Transform - pos: 16.5,42.5 - parent: 588 - - uid: 1540 - components: - - type: Transform - pos: 17.5,42.5 - parent: 588 - - uid: 1541 - components: - - type: Transform - pos: 18.5,42.5 - parent: 588 - - uid: 1542 - components: - - type: Transform - pos: 19.5,42.5 - parent: 588 - - uid: 1543 - components: - - type: Transform - pos: 20.5,42.5 - parent: 588 - - uid: 1544 - components: - - type: Transform - pos: 21.5,42.5 - parent: 588 - - uid: 1545 - components: - - type: Transform - pos: 22.5,42.5 - parent: 588 - - uid: 1546 - components: - - type: Transform - pos: 22.5,43.5 - parent: 588 - - uid: 1547 - components: - - type: Transform - pos: 22.5,44.5 - parent: 588 - - uid: 1548 - components: - - type: Transform - pos: 22.5,45.5 - parent: 588 - - uid: 1549 - components: - - type: Transform - pos: 22.5,46.5 - parent: 588 - - uid: 1550 - components: - - type: Transform - pos: 22.5,47.5 - parent: 588 - - uid: 1551 - components: - - type: Transform - pos: 22.5,48.5 - parent: 588 - - uid: 1552 - components: - - type: Transform - pos: 21.5,48.5 - parent: 588 - - uid: 1553 - components: - - type: Transform - pos: 20.5,48.5 - parent: 588 - - uid: 1554 - components: - - type: Transform - pos: 19.5,43.5 - parent: 588 - - uid: 1555 - components: - - type: Transform - pos: 19.5,44.5 - parent: 588 - - uid: 1556 - components: - - type: Transform - pos: 19.5,45.5 - parent: 588 - - uid: 1557 - components: - - type: Transform - pos: 19.5,46.5 - parent: 588 - - uid: 1807 - components: - - type: Transform - pos: 27.5,42.5 - parent: 588 - - uid: 1808 - components: - - type: Transform - pos: 27.5,43.5 - parent: 588 - - uid: 1809 - components: - - type: Transform - pos: 27.5,44.5 - parent: 588 - - uid: 1810 - components: - - type: Transform - pos: 27.5,45.5 - parent: 588 - - uid: 1811 - components: - - type: Transform - pos: 27.5,46.5 - parent: 588 - - uid: 1812 - components: - - type: Transform - pos: 27.5,47.5 - parent: 588 - - uid: 1813 - components: - - type: Transform - pos: 27.5,48.5 - parent: 588 - - uid: 1814 - components: - - type: Transform - pos: 28.5,45.5 - parent: 588 - - uid: 1815 - components: - - type: Transform - pos: 29.5,45.5 - parent: 588 - - uid: 1816 - components: - - type: Transform - pos: 30.5,45.5 - parent: 588 - - uid: 1817 - components: - - type: Transform - pos: 26.5,45.5 - parent: 588 - - uid: 1818 - components: - - type: Transform - pos: 25.5,45.5 - parent: 588 - - uid: 1819 - components: - - type: Transform - pos: 24.5,45.5 - parent: 588 - - uid: 1820 - components: - - type: Transform - pos: 26.5,47.5 - parent: 588 - - uid: 1821 - components: - - type: Transform - pos: 25.5,47.5 - parent: 588 - - uid: 1822 - components: - - type: Transform - pos: 28.5,47.5 - parent: 588 - - uid: 1823 - components: - - type: Transform - pos: 29.5,47.5 - parent: 588 - - uid: 1824 - components: - - type: Transform - pos: 26.5,43.5 - parent: 588 - - uid: 1825 - components: - - type: Transform - pos: 25.5,43.5 - parent: 588 - - uid: 1826 - components: - - type: Transform - pos: 28.5,43.5 - parent: 588 - - uid: 1827 - components: - - type: Transform - pos: 29.5,43.5 - parent: 588 -- proto: CableApcStack1 - entities: - - uid: 655 - components: - - type: Transform - pos: 16.273203,19.650417 - parent: 588 -- proto: CableHV - entities: - - uid: 462 - components: - - type: Transform - pos: 27.5,13.5 - parent: 588 - - uid: 466 - components: - - type: Transform - pos: 26.5,13.5 - parent: 588 - - uid: 468 - components: - - type: Transform - pos: 28.5,13.5 - parent: 588 - - uid: 485 - components: - - type: Transform - pos: 26.5,15.5 - parent: 588 - - uid: 486 - components: - - type: Transform - pos: 26.5,14.5 - parent: 588 - - uid: 487 - components: - - type: Transform - pos: 27.5,14.5 - parent: 588 - - uid: 488 - components: - - type: Transform - pos: 28.5,14.5 - parent: 588 - - uid: 489 - components: - - type: Transform - pos: 28.5,15.5 - parent: 588 - - uid: 743 - components: - - type: Transform - pos: 26.5,21.5 - parent: 588 - - uid: 744 - components: - - type: Transform - pos: 27.5,21.5 - parent: 588 - - uid: 745 - components: - - type: Transform - pos: 26.5,20.5 - parent: 588 - - uid: 746 - components: - - type: Transform - pos: 25.5,21.5 - parent: 588 - - uid: 768 - components: - - type: Transform - pos: 26.5,19.5 - parent: 588 - - uid: 778 - components: - - type: Transform - pos: 27.5,19.5 - parent: 588 - - uid: 978 - components: - - type: Transform - pos: 16.5,32.5 - parent: 588 - - uid: 979 - components: - - type: Transform - pos: 15.5,31.5 - parent: 588 - - uid: 980 - components: - - type: Transform - pos: 16.5,31.5 - parent: 588 - - uid: 981 - components: - - type: Transform - pos: 17.5,31.5 - parent: 588 - - uid: 982 - components: - - type: Transform - pos: 18.5,31.5 - parent: 588 - - uid: 983 - components: - - type: Transform - pos: 22.5,31.5 - parent: 588 - - uid: 984 - components: - - type: Transform - pos: 23.5,31.5 - parent: 588 - - uid: 985 - components: - - type: Transform - pos: 24.5,31.5 - parent: 588 - - uid: 986 - components: - - type: Transform - pos: 24.5,32.5 - parent: 588 - - uid: 987 - components: - - type: Transform - pos: 25.5,31.5 - parent: 588 - - uid: 989 - components: - - type: Transform - pos: 18.5,32.5 - parent: 588 - - uid: 990 - components: - - type: Transform - pos: 19.5,32.5 - parent: 588 - - uid: 991 - components: - - type: Transform - pos: 20.5,32.5 - parent: 588 - - uid: 992 - components: - - type: Transform - pos: 21.5,32.5 - parent: 588 - - uid: 993 - components: - - type: Transform - pos: 22.5,32.5 - parent: 588 - - uid: 1003 - components: - - type: Transform - pos: 16.5,30.5 - parent: 588 - - uid: 1004 - components: - - type: Transform - pos: 24.5,30.5 - parent: 588 - - uid: 1510 - components: - - type: Transform - pos: 18.5,44.5 - parent: 588 - - uid: 1511 - components: - - type: Transform - pos: 18.5,45.5 - parent: 588 - - uid: 1512 - components: - - type: Transform - pos: 20.5,45.5 - parent: 588 - - uid: 1513 - components: - - type: Transform - pos: 20.5,44.5 - parent: 588 - - uid: 1514 - components: - - type: Transform - pos: 19.5,44.5 - parent: 588 - - uid: 1522 - components: - - type: Transform - pos: 17.5,46.5 - parent: 588 - - uid: 1523 - components: - - type: Transform - pos: 21.5,46.5 - parent: 588 - - uid: 1524 - components: - - type: Transform - pos: 20.5,46.5 - parent: 588 - - uid: 1525 - components: - - type: Transform - pos: 18.5,46.5 - parent: 588 - - uid: 1526 - components: - - type: Transform - pos: 19.5,46.5 - parent: 588 -- proto: CableMV - entities: - - uid: 490 - components: - - type: Transform - pos: 27.5,13.5 - parent: 588 - - uid: 491 - components: - - type: Transform - pos: 26.5,13.5 - parent: 588 - - uid: 492 - components: - - type: Transform - pos: 25.5,13.5 - parent: 588 - - uid: 775 - components: - - type: Transform - pos: 27.5,19.5 - parent: 588 - - uid: 776 - components: - - type: Transform - pos: 26.5,19.5 - parent: 588 - - uid: 777 - components: - - type: Transform - pos: 25.5,19.5 - parent: 588 - - uid: 1527 - components: - - type: Transform - pos: 19.5,46.5 - parent: 588 - - uid: 1528 - components: - - type: Transform - pos: 19.5,47.5 - parent: 588 -- proto: CableTerminal - entities: - - uid: 463 - components: - - type: Transform - pos: 26.5,14.5 - parent: 588 - - uid: 464 - components: - - type: Transform - pos: 27.5,14.5 - parent: 588 - - uid: 465 - components: - - type: Transform - pos: 28.5,14.5 - parent: 588 - - uid: 767 - components: - - type: Transform - pos: 26.5,20.5 - parent: 588 - - uid: 970 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,31.5 - parent: 588 - - uid: 976 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 22.5,31.5 - parent: 588 - - uid: 1558 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,45.5 - parent: 588 - - uid: 1559 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,45.5 - parent: 588 -- proto: Carpet - entities: - - uid: 1632 - components: - - type: Transform - pos: 24.5,0.5 - parent: 588 - - uid: 1633 - components: - - type: Transform - pos: 25.5,0.5 - parent: 588 - - uid: 1634 - components: - - type: Transform - pos: 25.5,1.5 - parent: 588 - - uid: 1635 - components: - - type: Transform - pos: 24.5,1.5 - parent: 588 -- proto: CarpetBlue - entities: - - uid: 1636 - components: - - type: Transform - pos: 27.5,0.5 - parent: 588 - - uid: 1637 - components: - - type: Transform - pos: 28.5,1.5 - parent: 588 - - uid: 1638 - components: - - type: Transform - pos: 27.5,1.5 - parent: 588 - - uid: 1639 - components: - - type: Transform - pos: 28.5,0.5 - parent: 588 -- proto: CarpetPurple - entities: - - uid: 1626 - components: - - type: Transform - pos: 25.5,4.5 - parent: 588 - - uid: 1627 - components: - - type: Transform - pos: 25.5,3.5 - parent: 588 - - uid: 1628 - components: - - type: Transform - pos: 26.5,3.5 - parent: 588 - - uid: 1629 - components: - - type: Transform - pos: 27.5,3.5 - parent: 588 - - uid: 1630 - components: - - type: Transform - pos: 27.5,4.5 - parent: 588 - - uid: 1631 - components: - - type: Transform - pos: 26.5,4.5 - parent: 588 -- proto: Catwalk - entities: - - uid: 141 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,24.5 - parent: 588 - - uid: 142 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,26.5 - parent: 588 - - uid: 143 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,25.5 - parent: 588 - - uid: 248 - components: - - type: Transform - pos: 8.5,4.5 - parent: 588 - - uid: 249 - components: - - type: Transform - pos: 8.5,2.5 - parent: 588 - - uid: 250 - components: - - type: Transform - pos: 8.5,3.5 - parent: 588 - - uid: 251 - components: - - type: Transform - pos: 8.5,1.5 - parent: 588 - - uid: 471 - components: - - type: Transform - pos: 27.5,14.5 - parent: 588 - - uid: 473 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 29.5,12.5 - parent: 588 - - uid: 474 - components: - - type: Transform - pos: 28.5,14.5 - parent: 588 - - uid: 475 - components: - - type: Transform - pos: 26.5,14.5 - parent: 588 - - uid: 512 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,12.5 - parent: 588 - - uid: 513 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 28.5,12.5 - parent: 588 - - uid: 515 - components: - - type: Transform - pos: 25.5,16.5 - parent: 588 - - uid: 516 - components: - - type: Transform - pos: 26.5,16.5 - parent: 588 - - uid: 517 - components: - - type: Transform - pos: 27.5,16.5 - parent: 588 - - uid: 518 - components: - - type: Transform - pos: 28.5,16.5 - parent: 588 - - uid: 519 - components: - - type: Transform - pos: 29.5,16.5 - parent: 588 - - uid: 520 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,12.5 - parent: 588 - - uid: 521 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,12.5 - parent: 588 - - uid: 769 - components: - - type: Transform - pos: 26.5,20.5 - parent: 588 - - uid: 832 - components: - - type: Transform - pos: 3.5,31.5 - parent: 588 - - uid: 833 - components: - - type: Transform - pos: 4.5,31.5 - parent: 588 - - uid: 834 - components: - - type: Transform - pos: 5.5,31.5 - parent: 588 - - uid: 835 - components: - - type: Transform - pos: 6.5,31.5 - parent: 588 - - uid: 836 - components: - - type: Transform - pos: 7.5,31.5 - parent: 588 - - uid: 837 - components: - - type: Transform - pos: 8.5,31.5 - parent: 588 - - uid: 838 - components: - - type: Transform - pos: 9.5,31.5 - parent: 588 - - uid: 839 - components: - - type: Transform - pos: 6.5,32.5 - parent: 588 - - uid: 840 - components: - - type: Transform - pos: 6.5,30.5 - parent: 588 - - uid: 841 - components: - - type: Transform - pos: 5.5,32.5 - parent: 588 - - uid: 842 - components: - - type: Transform - pos: 7.5,32.5 - parent: 588 - - uid: 843 - components: - - type: Transform - pos: 5.5,30.5 - parent: 588 - - uid: 844 - components: - - type: Transform - pos: 7.5,30.5 - parent: 588 - - uid: 861 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,27.5 - parent: 588 - - uid: 862 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,28.5 - parent: 588 - - uid: 863 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,28.5 - parent: 588 - - uid: 864 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,27.5 - parent: 588 - - uid: 865 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,26.5 - parent: 588 - - uid: 879 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,40.5 - parent: 588 - - uid: 880 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,39.5 - parent: 588 - - uid: 881 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,39.5 - parent: 588 - - uid: 882 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,39.5 - parent: 588 - - uid: 883 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,39.5 - parent: 588 - - uid: 884 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,39.5 - parent: 588 - - uid: 885 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,38.5 - parent: 588 - - uid: 914 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,10.5 - parent: 588 - - uid: 915 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,10.5 - parent: 588 - - uid: 916 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,10.5 - parent: 588 - - uid: 917 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,10.5 - parent: 588 - - uid: 918 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 7.5,10.5 - parent: 588 - - uid: 919 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,6.5 - parent: 588 - - uid: 920 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,6.5 - parent: 588 - - uid: 921 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,6.5 - parent: 588 - - uid: 922 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,6.5 - parent: 588 - - uid: 923 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 7.5,6.5 - parent: 588 - - uid: 955 - components: - - type: Transform - pos: 15.5,31.5 - parent: 588 - - uid: 956 - components: - - type: Transform - pos: 16.5,31.5 - parent: 588 - - uid: 957 - components: - - type: Transform - pos: 17.5,31.5 - parent: 588 - - uid: 958 - components: - - type: Transform - pos: 18.5,31.5 - parent: 588 - - uid: 959 - components: - - type: Transform - pos: 19.5,31.5 - parent: 588 - - uid: 960 - components: - - type: Transform - pos: 20.5,31.5 - parent: 588 - - uid: 961 - components: - - type: Transform - pos: 21.5,31.5 - parent: 588 - - uid: 962 - components: - - type: Transform - pos: 22.5,31.5 - parent: 588 - - uid: 963 - components: - - type: Transform - pos: 23.5,31.5 - parent: 588 - - uid: 964 - components: - - type: Transform - pos: 24.5,31.5 - parent: 588 - - uid: 965 - components: - - type: Transform - pos: 25.5,31.5 - parent: 588 - - uid: 994 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,32.5 - parent: 588 - - uid: 1158 - components: - - type: Transform - pos: 8.5,0.5 - parent: 588 - - uid: 1180 - components: - - type: Transform - pos: 1.5,36.5 - parent: 588 - - uid: 1181 - components: - - type: Transform - pos: 2.5,36.5 - parent: 588 - - uid: 1182 - components: - - type: Transform - pos: 3.5,36.5 - parent: 588 - - uid: 1183 - components: - - type: Transform - pos: 4.5,36.5 - parent: 588 - - uid: 1184 - components: - - type: Transform - pos: 5.5,36.5 - parent: 588 - - uid: 1185 - components: - - type: Transform - pos: 5.5,34.5 - parent: 588 - - uid: 1186 - components: - - type: Transform - pos: 6.5,34.5 - parent: 588 - - uid: 1187 - components: - - type: Transform - pos: 7.5,34.5 - parent: 588 - - uid: 1188 - components: - - type: Transform - pos: 8.5,34.5 - parent: 588 - - uid: 1189 - components: - - type: Transform - pos: 9.5,34.5 - parent: 588 - - uid: 1320 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,40.5 - parent: 588 - - uid: 1321 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,40.5 - parent: 588 - - uid: 1322 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,40.5 - parent: 588 - - uid: 1323 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,38.5 - parent: 588 - - uid: 1324 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,38.5 - parent: 588 - - uid: 1325 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,38.5 - parent: 588 - - uid: 1326 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 28.5,38.5 - parent: 588 - - uid: 1327 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 29.5,38.5 - parent: 588 - - uid: 1331 - components: - - type: Transform - pos: 4.5,45.5 - parent: 588 - - uid: 1336 - components: - - type: Transform - pos: 2.5,45.5 - parent: 588 - - uid: 1339 - components: - - type: Transform - pos: 3.5,45.5 - parent: 588 - - uid: 1342 - components: - - type: Transform - pos: 3.5,46.5 - parent: 588 - - uid: 1344 - components: - - type: Transform - pos: 3.5,44.5 - parent: 588 - - uid: 1346 - components: - - type: Transform - pos: 2.5,44.5 - parent: 588 - - uid: 1347 - components: - - type: Transform - pos: 4.5,44.5 - parent: 588 - - uid: 1348 - components: - - type: Transform - pos: 4.5,44.5 - parent: 588 - - uid: 1349 - components: - - type: Transform - pos: 4.5,46.5 - parent: 588 - - uid: 1350 - components: - - type: Transform - pos: 2.5,46.5 - parent: 588 - - uid: 1494 - components: - - type: Transform - pos: 17.5,42.5 - parent: 588 - - uid: 1495 - components: - - type: Transform - pos: 18.5,42.5 - parent: 588 - - uid: 1496 - components: - - type: Transform - pos: 19.5,42.5 - parent: 588 - - uid: 1497 - components: - - type: Transform - pos: 20.5,42.5 - parent: 588 - - uid: 1498 - components: - - type: Transform - pos: 21.5,42.5 - parent: 588 - - uid: 1499 - components: - - type: Transform - pos: 17.5,48.5 - parent: 588 - - uid: 1500 - components: - - type: Transform - pos: 18.5,48.5 - parent: 588 - - uid: 1501 - components: - - type: Transform - pos: 19.5,48.5 - parent: 588 - - uid: 1502 - components: - - type: Transform - pos: 20.5,48.5 - parent: 588 - - uid: 1503 - components: - - type: Transform - pos: 21.5,48.5 - parent: 588 - - uid: 1516 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,44.5 - parent: 588 - - uid: 1517 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,45.5 - parent: 588 - - uid: 1518 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,45.5 - parent: 588 - - uid: 1519 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,45.5 - parent: 588 - - uid: 1582 - components: - - type: Transform - pos: 28.5,22.5 - parent: 588 - - uid: 1583 - components: - - type: Transform - pos: 28.5,21.5 - parent: 588 - - uid: 1584 - components: - - type: Transform - pos: 28.5,20.5 - parent: 588 - - uid: 1585 - components: - - type: Transform - pos: 28.5,19.5 - parent: 588 - - uid: 1586 - components: - - type: Transform - pos: 28.5,18.5 - parent: 588 - - uid: 1587 - components: - - type: Transform - pos: 24.5,22.5 - parent: 588 - - uid: 1588 - components: - - type: Transform - pos: 24.5,21.5 - parent: 588 - - uid: 1589 - components: - - type: Transform - pos: 24.5,20.5 - parent: 588 - - uid: 1590 - components: - - type: Transform - pos: 24.5,19.5 - parent: 588 - - uid: 1591 - components: - - type: Transform - pos: 24.5,18.5 - parent: 588 -- proto: Cautery - entities: - - uid: 1474 - components: - - type: Transform - pos: 8.533231,42.775993 - parent: 588 -- proto: Chair - entities: - - uid: 357 - components: - - type: Transform - pos: 23.5,4.5 - parent: 588 - - uid: 421 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,9.5 - parent: 588 - - uid: 422 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,9.5 - parent: 588 - - uid: 423 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,7.5 - parent: 588 - - uid: 533 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 19.5,14.5 - parent: 588 - - uid: 534 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 19.5,15.5 - parent: 588 - - uid: 537 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 21.5,14.5 - parent: 588 - - uid: 569 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,13.5 - parent: 588 - - uid: 716 - components: - - type: Transform - pos: 18.5,19.5 - parent: 588 - - uid: 717 - components: - - type: Transform - pos: 19.5,19.5 - parent: 588 - - uid: 718 - components: - - type: Transform - pos: 22.5,19.5 - parent: 588 - - uid: 719 - components: - - type: Transform - pos: 21.5,19.5 - parent: 588 - - uid: 1280 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 17.5,38.5 - parent: 588 - - uid: 1281 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,38.5 - parent: 588 - - uid: 1282 - components: - - type: Transform - pos: 20.5,40.5 - parent: 588 - - uid: 1283 - components: - - type: Transform - pos: 21.5,40.5 - parent: 588 - - uid: 1865 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,7.5 - parent: 588 -- proto: ChairFolding - entities: - - uid: 344 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 31.5,0.5 - parent: 588 - - uid: 345 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 32.5,1.5 - parent: 588 - - uid: 346 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 32.5,0.5 - parent: 588 - - uid: 347 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 31.5,3.5 - parent: 588 - - uid: 348 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 32.5,3.5 - parent: 588 - - uid: 349 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 31.5,4.5 - parent: 588 - - uid: 350 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 33.5,1.5 - parent: 588 - - uid: 351 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 33.5,0.5 - parent: 588 - - uid: 352 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 33.5,4.5 - parent: 588 - - uid: 353 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 32.5,4.5 - parent: 588 - - uid: 1212 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 7.5,36.5 - parent: 588 -- proto: ChairFoldingSpawnFolded - entities: - - uid: 354 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 31.53707,1.6455604 - parent: 588 - - uid: 355 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 33.595894,3.4052575 - parent: 588 -- proto: ChairOfficeDark - entities: - - uid: 330 - components: - - type: Transform - pos: 19.5,1.5 - parent: 588 - - uid: 331 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,3.5 - parent: 588 - - uid: 358 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.5,0.5 - parent: 588 - - uid: 359 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,0.5 - parent: 588 - - uid: 360 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 28.5,0.5 - parent: 588 - - uid: 361 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 27.5,0.5 - parent: 588 - - uid: 571 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 13.5,12.5 - parent: 588 -- proto: ChairOfficeLight - entities: - - uid: 631 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 9.5,19.5 - parent: 588 - - uid: 638 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 7.5,21.5 - parent: 588 - - uid: 707 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 15.5,21.5 - parent: 588 -- proto: ChairPilotSeat - entities: - - uid: 356 - components: - - type: Transform - pos: 26.5,4.5 - parent: 588 -- proto: ChairWood - entities: - - uid: 1049 - components: - - type: Transform - pos: 20.5,25.5 - parent: 588 - - uid: 1050 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 22.5,27.5 - parent: 588 - - uid: 1231 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 21.5,34.5 - parent: 588 - - uid: 1232 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 13.5,36.5 - parent: 588 - - uid: 1790 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,46.5 - parent: 588 - - uid: 1791 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,44.5 - parent: 588 -- proto: CigarGold - entities: - - uid: 1219 - components: - - type: Transform - pos: 7.4719925,36.539555 - parent: 588 -- proto: ClosetBombFilled - entities: - - uid: 413 - components: - - type: Transform - pos: 14.5,6.5 - parent: 588 - - uid: 1014 - components: - - type: Transform - pos: 12.5,27.5 - parent: 588 - - uid: 1026 - components: - - type: Transform - pos: 16.5,27.5 - parent: 588 -- proto: ClosetEmergencyFilledRandom - entities: - - uid: 1203 - components: - - type: Transform - pos: 12.5,30.5 - parent: 588 - - uid: 1204 - components: - - type: Transform - pos: 0.5,32.5 - parent: 588 - - uid: 1205 - components: - - type: Transform - pos: 9.5,9.5 - parent: 588 - - uid: 1207 - components: - - type: Transform - pos: 1.5,7.5 - parent: 588 -- proto: ClosetFireFilled - entities: - - uid: 1194 - components: - - type: Transform - pos: 1.5,9.5 - parent: 588 - - uid: 1195 - components: - - type: Transform - pos: 9.5,7.5 - parent: 588 - - uid: 1196 - components: - - type: Transform - pos: 6.5,40.5 - parent: 588 - - uid: 1197 - components: - - type: Transform - pos: 0.5,38.5 - parent: 588 -- proto: ClosetL3SecurityFilled - entities: - - uid: 415 - components: - - type: Transform - pos: 20.5,10.5 - parent: 588 -- proto: ClosetToolFilled - entities: - - uid: 1007 - components: - - type: Transform - pos: 14.5,30.5 - parent: 588 -- proto: ClosetWallMaintenanceFilledRandom - entities: - - uid: 499 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 25.5,15.5 - parent: 588 - - uid: 868 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,27.5 - parent: 588 - - uid: 1564 - components: - - type: Transform - pos: 17.5,43.5 - parent: 588 - - uid: 1565 - components: - - type: Transform - pos: 21.5,43.5 - parent: 588 -- proto: ClothingBeltChampion - entities: - - uid: 1236 - components: - - type: Transform - pos: 10.581136,39.53631 - parent: 588 -- proto: ClothingEyesGlassesMeson - entities: - - uid: 1108 - components: - - type: Transform - pos: 25.666832,30.643515 - parent: 588 -- proto: ClothingHandsGlovesNitrile - entities: - - uid: 1715 - components: - - type: Transform - pos: 10.432637,44.476112 - parent: 588 -- proto: ClothingHeadBandRed - entities: - - uid: 1295 - components: - - type: Transform - pos: 12.571781,39.694115 - parent: 588 -- proto: ClothingHeadHatFedoraBrown - entities: - - uid: 577 - components: - - type: Transform - pos: 12.686508,13.58602 - parent: 588 -- proto: ClothingHeadHatPwig - entities: - - uid: 369 - components: - - type: Transform - pos: 25.824945,3.5783403 - parent: 588 -- proto: ClothingHeadHatSecsoftFlipped - entities: - - uid: 606 - components: - - type: Transform - pos: 12.705482,6.671774 - parent: 588 - - uid: 1027 - components: - - type: Transform - pos: 18.403675,25.53719 - parent: 588 -- proto: ClothingHeadHatSurgcapPurple - entities: - - uid: 1711 - components: - - type: Transform - pos: 10.304593,44.632217 - parent: 588 -- proto: ClothingHeadHelmetRiot - entities: - - uid: 1617 - components: - - type: Transform - pos: 22.499683,6.7142525 - parent: 588 -- proto: ClothingHeadHelmetThunderdome - entities: - - uid: 1240 - components: - - type: Transform - pos: 34.666565,24.66942 - parent: 588 -- proto: ClothingNeckLawyerbadge - entities: - - uid: 326 - components: - - type: Transform - pos: 21.586027,4.583762 - parent: 588 -- proto: ClothingNeckTieDet - entities: - - uid: 573 - components: - - type: Transform - pos: 12.714905,13.486683 - parent: 588 -- proto: ClothingOuterArmorReflective - entities: - - uid: 1031 - components: - - type: Transform - pos: 18.47467,24.458666 - parent: 588 -- proto: ClothingOuterCoatDetective - entities: - - uid: 574 - components: - - type: Transform - pos: 13.396446,12.479115 - parent: 588 -- proto: ClothingOuterRobesJudge - entities: - - uid: 370 - components: - - type: Transform - pos: 27.40101,3.677678 - parent: 588 -- proto: ClothingShoesBootsCombatFilled - entities: - - uid: 1036 - components: - - type: Transform - pos: 12.582174,25.636528 - parent: 588 -- proto: ClothingShoesBootsLaceup - entities: - - uid: 372 - components: - - type: Transform - pos: 18.586912,0.70824456 - parent: 588 -- proto: ClothingUniformJumpskirtColorMaroon - entities: - - uid: 1714 - components: - - type: Transform - pos: 10.673761,44.53288 - parent: 588 -- proto: ClothingUniformJumpsuitColorMaroon - entities: - - uid: 1713 - components: - - type: Transform - pos: 10.645364,44.67479 - parent: 588 -- proto: ClusterBangFull - entities: - - uid: 599 - components: - - type: Transform - pos: 33.484257,28.42918 - parent: 588 -- proto: ComputerAlert - entities: - - uid: 999 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 17.5,30.5 - parent: 588 - - uid: 1001 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 23.5,30.5 - parent: 588 - - uid: 1561 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 21.5,46.5 - parent: 588 -- proto: computerBodyScanner - entities: - - uid: 1394 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,44.5 - parent: 588 - - uid: 1423 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,44.5 - parent: 588 -- proto: ComputerCriminalRecords - entities: - - uid: 461 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 11.5,0.5 - parent: 588 - - uid: 634 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,18.5 - parent: 588 -- proto: ComputerPowerMonitoring - entities: - - uid: 1000 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 16.5,30.5 - parent: 588 - - uid: 1002 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.5,30.5 - parent: 588 - - uid: 1560 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 17.5,46.5 - parent: 588 -- proto: ComputerSurveillanceCameraMonitor - entities: - - uid: 635 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,21.5 - parent: 588 -- proto: ComputerTelevision - entities: - - uid: 1229 - components: - - type: Transform - pos: 12.5,34.5 - parent: 588 - - uid: 1230 - components: - - type: Transform - pos: 22.5,36.5 - parent: 588 -- proto: CrateEngineeringGear - entities: - - uid: 1008 - components: - - type: Transform - pos: 26.5,30.5 - parent: 588 -- proto: CrateFunBoardGames - entities: - - uid: 1845 - components: - - type: Transform - pos: 26.5,48.5 - parent: 588 -- proto: CrateFunParty - entities: - - uid: 1876 - components: - - type: Transform - pos: 25.5,43.5 - parent: 588 -- proto: CrateHydroponicsSeedsExotic - entities: - - uid: 1660 - components: - - type: Transform - pos: 31.5,22.5 - parent: 588 -- proto: CrayonBox - entities: - - uid: 1057 - components: - - type: Transform - pos: 20.47107,24.608877 - parent: 588 - - uid: 1116 - components: - - type: Transform - pos: 20.607256,14.646415 - parent: 588 -- proto: CryoPod - entities: - - uid: 1395 - components: - - type: Transform - pos: 8.5,47.5 - parent: 588 - - uid: 1397 - components: - - type: Transform - pos: 14.5,47.5 - parent: 588 -- proto: DebugSMES - entities: - - uid: 971 - components: - - type: Transform - pos: 22.5,32.5 - parent: 588 - - uid: 974 - components: - - type: Transform - pos: 18.5,32.5 - parent: 588 -- proto: DeployableBarrier - entities: - - uid: 1233 - components: - - type: Transform - pos: 32.5,24.5 - parent: 588 -- proto: DiceBag - entities: - - uid: 552 - components: - - type: Transform - pos: 20.294882,15.426926 - parent: 588 -- proto: DiseaseDiagnoser - entities: - - uid: 1424 - components: - - type: Transform - pos: 14.5,44.5 - parent: 588 -- proto: DisposalUnit - entities: - - uid: 550 - components: - - type: Transform - pos: 22.5,16.5 - parent: 588 - - uid: 725 - components: - - type: Transform - pos: 21.5,22.5 - parent: 588 - - uid: 766 - components: - - type: Transform - pos: 9.5,22.5 - parent: 588 - - uid: 1288 - components: - - type: Transform - pos: 22.5,38.5 - parent: 588 -- proto: DonkpocketBoxSpawner - entities: - - uid: 526 - components: - - type: Transform - pos: 16.5,13.5 - parent: 588 - - uid: 723 - components: - - type: Transform - pos: 18.5,21.5 - parent: 588 -- proto: DoorElectronics - entities: - - uid: 659 - components: - - type: Transform - pos: 12.581519,21.410114 - parent: 588 - - uid: 1074 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.639427,25.54549 - parent: 588 -- proto: Dresser - entities: - - uid: 1051 - components: - - type: Transform - pos: 22.5,25.5 - parent: 588 - - uid: 1052 - components: - - type: Transform - pos: 20.5,27.5 - parent: 588 - - uid: 1061 - components: - - type: Transform - pos: 24.5,25.5 - parent: 588 - - uid: 1221 - components: - - type: Transform - pos: 21.5,36.5 - parent: 588 - - uid: 1222 - components: - - type: Transform - pos: 13.5,34.5 - parent: 588 -- proto: DrinkDetFlask - entities: - - uid: 1577 - components: - - type: Transform - pos: 12.606661,13.037249 - parent: 588 -- proto: DrinkMugMetal - entities: - - uid: 1294 - components: - - type: Transform - pos: 22.442232,12.514399 - parent: 588 -- proto: DrinkMugRed - entities: - - uid: 721 - components: - - type: Transform - pos: 22.448559,18.561966 - parent: 588 - - uid: 1293 - components: - - type: Transform - pos: 22.328642,12.741456 - parent: 588 -- proto: DrinkShinyFlask - entities: - - uid: 1874 - components: - - type: Transform - pos: 6.890398,22.663696 - parent: 588 -- proto: DrinkShotGlass - entities: - - uid: 578 - components: - - type: Transform - pos: 12.412022,12.535878 - parent: 588 - - uid: 579 - components: - - type: Transform - pos: 12.539811,12.748745 - parent: 588 -- proto: DrinkWaterCup - entities: - - uid: 722 - components: - - type: Transform - pos: 18.373508,18.661304 - parent: 588 - - uid: 762 - components: - - type: Transform - pos: 6.313587,19.590261 - parent: 588 - - uid: 763 - components: - - type: Transform - pos: 6.441377,19.419968 - parent: 588 -- proto: EmergencyLight - entities: - - uid: 1716 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,6.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1717 - components: - - type: Transform - pos: 21.5,10.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1718 - components: - - type: Transform - pos: 30.5,4.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1719 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,0.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1720 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,0.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1721 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,12.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1722 - components: - - type: Transform - pos: 18.5,16.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1723 - components: - - type: Transform - pos: 31.5,22.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1724 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 34.5,25.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1726 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 30.5,25.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1727 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,27.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1728 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,27.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1729 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,27.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1730 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 12.5,25.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1731 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 0.5,7.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1732 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,9.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1733 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,20.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1734 - components: - - type: Transform - pos: 1.5,24.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1735 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,30.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1736 - components: - - type: Transform - pos: 11.5,32.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1737 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,40.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1738 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,40.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1739 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 22.5,30.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1740 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,19.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1742 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 16.5,21.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1744 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,18.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1745 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 16.5,34.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1746 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 30.5,34.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1747 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,38.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1748 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 20.5,44.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1749 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,44.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1750 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,46.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1751 - components: - - type: Transform - pos: 30.5,6.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1752 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 28.5,10.5 - parent: 588 - - type: PointLight - enabled: True - - uid: 1832 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 30.5,46.5 - parent: 588 - - type: PointLight - enabled: True -- proto: EmergencyRollerBed - entities: - - uid: 1141 - components: - - type: Transform - pos: 30.5,25.5 - parent: 588 - - uid: 1142 - components: - - type: Transform - pos: 30.5,24.5 - parent: 588 -- proto: ExtinguisherCabinetFilled - entities: - - uid: 867 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,26.5 - parent: 588 - - uid: 1198 - components: - - type: Transform - pos: 2.5,8.5 - parent: 588 - - uid: 1199 - components: - - type: Transform - pos: 8.5,8.5 - parent: 588 - - uid: 1200 - components: - - type: Transform - pos: 8.5,35.5 - parent: 588 - - uid: 1201 - components: - - type: Transform - pos: 1.5,35.5 - parent: 588 - - uid: 1202 - components: - - type: Transform - pos: 25.5,14.5 - parent: 588 - - uid: 1328 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 28.5,39.5 - parent: 588 - - uid: 1566 - components: - - type: Transform - pos: 17.5,44.5 - parent: 588 -- proto: filingCabinetRandom - entities: - - uid: 320 - components: - - type: Transform - pos: 21.5,0.5 - parent: 588 - - uid: 321 - components: - - type: Transform - pos: 20.5,0.5 - parent: 588 -- proto: filingCabinetTallRandom - entities: - - uid: 1396 - components: - - type: Transform - pos: 8.5,44.5 - parent: 588 -- proto: Flash - entities: - - uid: 1209 - components: - - type: Transform - pos: 10.726851,19.047483 - parent: 588 -- proto: FlashlightSeclite - entities: - - uid: 374 - components: - - type: Transform - pos: 13.377204,0.54605544 - parent: 588 -- proto: FloodlightBroken - entities: - - uid: 1193 - components: - - type: Transform - pos: 9.462372,35.6454 - parent: 588 -- proto: FloorDrain - entities: - - uid: 944 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,28.5 - parent: 588 - - type: Fixtures - fixtures: {} - - uid: 945 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,28.5 - parent: 588 - - type: Fixtures - fixtures: {} -- proto: FloorLavaEntity - entities: - - uid: 47 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,8.5 - parent: 588 - - uid: 49 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,8.5 - parent: 588 - - uid: 458 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,10.5 - parent: 588 - - uid: 459 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,8.5 - parent: 588 - - uid: 460 - components: - - type: Transform - pos: 8.5,3.5 - parent: 588 - - uid: 645 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,20.5 - parent: 588 - - uid: 820 - components: - - type: Transform - pos: 4.5,32.5 - parent: 588 - - uid: 821 - components: - - type: Transform - pos: 4.5,31.5 - parent: 588 - - uid: 822 - components: - - type: Transform - pos: 5.5,31.5 - parent: 588 - - uid: 823 - components: - - type: Transform - pos: 5.5,32.5 - parent: 588 - - uid: 824 - components: - - type: Transform - pos: 5.5,30.5 - parent: 588 - - uid: 825 - components: - - type: Transform - pos: 6.5,30.5 - parent: 588 - - uid: 826 - components: - - type: Transform - pos: 7.5,30.5 - parent: 588 - - uid: 827 - components: - - type: Transform - pos: 6.5,32.5 - parent: 588 - - uid: 828 - components: - - type: Transform - pos: 7.5,32.5 - parent: 588 - - uid: 829 - components: - - type: Transform - pos: 7.5,31.5 - parent: 588 - - uid: 830 - components: - - type: Transform - pos: 6.5,31.5 - parent: 588 - - uid: 831 - components: - - type: Transform - pos: 8.5,30.5 - parent: 588 - - uid: 857 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,39.5 - parent: 588 - - uid: 858 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,39.5 - parent: 588 - - uid: 859 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,38.5 - parent: 588 - - uid: 860 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,40.5 - parent: 588 - - uid: 887 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,40.5 - parent: 588 - - uid: 889 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,39.5 - parent: 588 - - uid: 906 - components: - - type: Transform - pos: 4.5,7.5 - parent: 588 - - uid: 907 - components: - - type: Transform - pos: 5.5,7.5 - parent: 588 - - uid: 908 - components: - - type: Transform - pos: 5.5,9.5 - parent: 588 - - uid: 909 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,6.5 - parent: 588 - - uid: 910 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,6.5 - parent: 588 - - uid: 911 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,9.5 - parent: 588 - - uid: 913 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,10.5 - parent: 588 - - uid: 1247 - components: - - type: Transform - pos: 8.5,4.5 - parent: 588 - - uid: 1248 - components: - - type: Transform - pos: 9.5,4.5 - parent: 588 - - uid: 1249 - components: - - type: Transform - pos: 8.5,2.5 - parent: 588 - - uid: 1250 - components: - - type: Transform - pos: 8.5,1.5 - parent: 588 - - uid: 1251 - components: - - type: Transform - pos: 9.5,1.5 - parent: 588 - - uid: 1252 - components: - - type: Transform - pos: 8.5,1.5 - parent: 588 - - uid: 1253 - components: - - type: Transform - pos: 8.5,0.5 - parent: 588 - - uid: 1254 - components: - - type: Transform - pos: 7.5,0.5 - parent: 588 - - uid: 1333 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,46.5 - parent: 588 - - uid: 1341 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,45.5 - parent: 588 - - uid: 1343 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,46.5 - parent: 588 - - uid: 1345 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,46.5 - parent: 588 - - uid: 1359 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,47.5 - parent: 588 - - uid: 1360 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,46.5 - parent: 588 - - uid: 1361 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,47.5 - parent: 588 - - uid: 1362 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,47.5 - parent: 588 - - uid: 1363 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,44.5 - parent: 588 - - uid: 1364 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,47.5 - parent: 588 - - uid: 1365 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,44.5 - parent: 588 - - uid: 1366 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,45.5 - parent: 588 - - uid: 1367 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,44.5 - parent: 588 - - uid: 1368 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,43.5 - parent: 588 - - uid: 1369 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,43.5 - parent: 588 - - uid: 1370 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,42.5 - parent: 588 - - uid: 1371 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,42.5 - parent: 588 - - uid: 1372 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,43.5 - parent: 588 - - uid: 1373 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,44.5 - parent: 588 - - uid: 1374 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,46.5 - parent: 588 - - uid: 1375 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,43.5 - parent: 588 -- proto: FoodBowlBigTrash - entities: - - uid: 1840 - components: - - type: Transform - pos: 30.547388,48.16116 - parent: 588 -- proto: FoodBurgerMime - entities: - - uid: 399 - components: - - type: Transform - pos: 10.958169,39.64943 - parent: 588 -- proto: FoodPlateSmallPlastic - entities: - - uid: 529 - components: - - type: Transform - pos: 17.462528,12.615073 - parent: 588 -- proto: FoodPlateTrash - entities: - - uid: 1692 - components: - - type: Transform - pos: 28.80027,47.44947 - parent: 588 -- proto: ForensicPad - entities: - - uid: 761 - components: - - type: Transform - pos: 7.562898,22.48225 - parent: 588 -- proto: ForkPlastic - entities: - - uid: 531 - components: - - type: Transform - pos: 17.405733,12.600882 - parent: 588 -- proto: GasFilter - entities: - - uid: 1415 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 12.5,47.5 - parent: 588 -- proto: GasPipeBend - entities: - - uid: 1412 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,46.5 - parent: 588 - - uid: 1414 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,46.5 - parent: 588 - - uid: 1416 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 11.5,47.5 - parent: 588 - - uid: 1421 - components: - - type: Transform - pos: 13.5,47.5 - parent: 588 -- proto: GasPipeStraight - entities: - - uid: 1418 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,47.5 - parent: 588 - - uid: 1420 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 12.5,46.5 - parent: 588 -- proto: GasPipeTJunction - entities: - - uid: 1410 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,46.5 - parent: 588 - - uid: 1411 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,46.5 - parent: 588 - - uid: 1417 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,46.5 - parent: 588 - - uid: 1419 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 11.5,46.5 - parent: 588 -- proto: GasPort - entities: - - uid: 1404 - components: - - type: Transform - pos: 9.5,48.5 - parent: 588 - - uid: 1422 - components: - - type: Transform - pos: 12.5,48.5 - parent: 588 -- proto: GasPressurePump - entities: - - uid: 1409 - components: - - type: Transform - pos: 9.5,47.5 - parent: 588 -- proto: GasThermoMachineFreezer - entities: - - uid: 1403 - components: - - type: Transform - pos: 10.5,48.5 - parent: 588 -- proto: GatfruitSeeds - entities: - - uid: 562 - components: - - type: Transform - pos: 8.528373,27.49547 - parent: 588 -- proto: Gauze - entities: - - uid: 1482 - components: - - type: Transform - pos: 8.452288,42.514927 - parent: 588 -- proto: GeneratorRTG - entities: - - uid: 742 - components: - - type: Transform - pos: 27.5,21.5 - parent: 588 - - uid: 748 - components: - - type: Transform - pos: 25.5,21.5 - parent: 588 -- proto: Girder - entities: - - uid: 1301 - components: - - type: Transform - pos: 26.5,39.5 - parent: 588 -- proto: Grille - entities: - - uid: 209 - components: - - type: Transform - pos: 15.5,34.5 - parent: 588 - - uid: 211 - components: - - type: Transform - pos: 19.5,36.5 - parent: 588 - - uid: 212 - components: - - type: Transform - pos: 19.5,34.5 - parent: 588 - - uid: 213 - components: - - type: Transform - pos: 15.5,36.5 - parent: 588 - - uid: 403 - components: - - type: Transform - pos: 15.5,9.5 - parent: 588 - - uid: 404 - components: - - type: Transform - pos: 15.5,7.5 - parent: 588 - - uid: 407 - components: - - type: Transform - pos: 19.5,9.5 - parent: 588 - - uid: 408 - components: - - type: Transform - pos: 19.5,7.5 - parent: 588 - - uid: 568 - components: - - type: Transform - pos: 12.5,15.5 - parent: 588 - - uid: 584 - components: - - type: Transform - pos: 2.5,12.5 - parent: 588 - - uid: 586 - components: - - type: Transform - pos: 2.5,16.5 - parent: 588 - - uid: 587 - components: - - type: Transform - pos: 4.5,16.5 - parent: 588 - - uid: 589 - components: - - type: Transform - pos: 4.5,12.5 - parent: 588 - - uid: 1465 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,43.5 - parent: 588 - - uid: 1466 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 12.5,43.5 - parent: 588 -- proto: GrilleBroken - entities: - - uid: 1302 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,39.5 - parent: 588 -- proto: Handcuffs - entities: - - uid: 1614 - components: - - type: Transform - pos: 22.608034,10.659381 - parent: 588 -- proto: Hemostat - entities: - - uid: 1471 - components: - - type: Transform - pos: 8.51377,43.004257 - parent: 588 -- proto: HighSecArmoryLocked - entities: - - uid: 1597 - components: - - type: Transform - pos: 26.5,7.5 - parent: 588 - - uid: 1598 - components: - - type: Transform - pos: 32.5,7.5 - parent: 588 - - uid: 1599 - components: - - type: Transform - pos: 29.5,9.5 - parent: 588 -- proto: HospitalCurtains - entities: - - uid: 402 - components: - - type: Transform - pos: 8.5,27.5 - parent: 588 - - uid: 949 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,24.5 - parent: 588 - - uid: 951 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,27.5 - parent: 588 - - uid: 1768 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,48.5 - parent: 588 -- proto: HospitalCurtainsOpen - entities: - - uid: 946 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,25.5 - parent: 588 - - uid: 947 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,24.5 - parent: 588 - - uid: 1040 - components: - - type: Transform - pos: 20.5,28.5 - parent: 588 - - uid: 1046 - components: - - type: Transform - pos: 22.5,24.5 - parent: 588 - - uid: 1148 - components: - - type: Transform - pos: 28.5,25.5 - parent: 588 - - uid: 1149 - components: - - type: Transform - pos: 28.5,24.5 - parent: 588 - - uid: 1223 - components: - - type: Transform - pos: 20.5,36.5 - parent: 588 - - uid: 1224 - components: - - type: Transform - pos: 14.5,34.5 - parent: 588 - - uid: 1467 - components: - - type: Transform - pos: 12.5,42.5 - parent: 588 - - uid: 1469 - components: - - type: Transform - pos: 10.5,42.5 - parent: 588 - - uid: 1767 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,42.5 - parent: 588 -- proto: HydroponicsToolHatchet - entities: - - uid: 1844 - components: - - type: Transform - pos: 29.538284,44.04174 - parent: 588 - - uid: 1851 - components: - - type: Transform - pos: 30.630798,21.602604 - parent: 588 -- proto: HydroponicsToolMiniHoe - entities: - - uid: 1837 - components: - - type: Transform - pos: 30.099596,43.446724 - parent: 588 - - uid: 1841 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 33.38517,20.601 - parent: 588 -- proto: HydroponicsToolSpade - entities: - - uid: 1838 - components: - - type: Transform - pos: 29.95761,43.361576 - parent: 588 - - uid: 1842 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 33.42777,20.58681 - parent: 588 -- proto: hydroponicsTray - entities: - - uid: 796 - components: - - type: Transform - pos: 31.5,21.5 - parent: 588 - - uid: 797 - components: - - type: Transform - pos: 31.5,20.5 - parent: 588 - - uid: 798 - components: - - type: Transform - pos: 31.5,19.5 - parent: 588 - - uid: 1772 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 29.5,42.5 - parent: 588 - - uid: 1774 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 29.5,44.5 - parent: 588 - - uid: 1787 - components: - - type: Transform - pos: 30.5,44.5 - parent: 588 - - uid: 1788 - components: - - type: Transform - pos: 30.5,42.5 - parent: 588 -- proto: IngotGold - entities: - - uid: 952 - components: - - type: Transform - pos: 11.069347,39.504154 - parent: 588 -- proto: KitchenMicrowave - entities: - - uid: 524 - components: - - type: Transform - pos: 16.5,12.5 - parent: 588 - - uid: 709 - components: - - type: Transform - pos: 18.5,22.5 - parent: 588 - - uid: 1785 - components: - - type: Transform - pos: 29.5,48.5 - parent: 588 -- proto: KitchenReagentGrinder - entities: - - uid: 1786 - components: - - type: Transform - pos: 30.5,47.5 - parent: 588 -- proto: KnifePlastic - entities: - - uid: 530 - components: - - type: Transform - pos: 17.249546,12.643455 - parent: 588 - - uid: 1836 - components: - - type: Transform - pos: 30.241585,48.271698 - parent: 588 -- proto: Lamp - entities: - - uid: 581 - components: - - type: Transform - pos: 12.369425,13.798887 - parent: 588 -- proto: LampGold - entities: - - uid: 322 - components: - - type: Transform - pos: 18.419699,1.6320114 - parent: 588 - - uid: 323 - components: - - type: Transform - pos: 20.563715,4.8959665 - parent: 588 - - uid: 729 - components: - - type: Transform - pos: 6.4779434,22.892899 - parent: 588 - - uid: 730 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.765976,19.912766 - parent: 588 -- proto: Lighter - entities: - - uid: 1220 - components: - - type: Transform - pos: 7.5287867,36.397644 - parent: 588 -- proto: LockerDetective - entities: - - uid: 560 - components: - - type: Transform - pos: 14.5,16.5 - parent: 588 -- proto: LockerEvidence - entities: - - uid: 254 - components: - - type: Transform - pos: 16.5,0.5 - parent: 588 - - uid: 262 - components: - - type: Transform - pos: 2.5,0.5 - parent: 588 - - uid: 263 - components: - - type: Transform - pos: 4.5,0.5 - parent: 588 - - uid: 276 - components: - - type: Transform - pos: 0.5,0.5 - parent: 588 - - uid: 286 - components: - - type: Transform - pos: 12.5,0.5 - parent: 588 - - uid: 287 - components: - - type: Transform - pos: 14.5,0.5 - parent: 588 - - uid: 704 - components: - - type: Transform - pos: 16.5,22.5 - parent: 588 -- proto: LockerMedicineFilled - entities: - - uid: 1152 - components: - - type: Transform - pos: 28.5,27.5 - parent: 588 -- proto: LockerSecurityFilled - entities: - - uid: 416 - components: - - type: Transform - pos: 20.5,6.5 - parent: 588 -- proto: LockerSyndicatePersonal - entities: - - uid: 605 - components: - - type: Transform - pos: 6.5,12.5 - parent: 588 -- proto: MachineFrame - entities: - - uid: 400 - components: - - type: Transform - pos: 26.5,8.5 - parent: 588 -- proto: MaintenanceFluffSpawner - entities: - - uid: 414 - components: - - type: Transform - pos: 25.5,32.5 - parent: 588 - - uid: 1289 - components: - - type: Transform - pos: 17.5,38.5 - parent: 588 - - uid: 1290 - components: - - type: Transform - pos: 21.5,40.5 - parent: 588 - - uid: 1291 - components: - - type: Transform - pos: 20.5,40.5 - parent: 588 -- proto: MaintenanceWeaponSpawner - entities: - - uid: 548 - components: - - type: Transform - pos: 15.5,4.5 - parent: 588 - - uid: 549 - components: - - type: Transform - pos: 3.5,4.5 - parent: 588 - - uid: 1580 - components: - - type: Transform - pos: 1.5,8.5 - parent: 588 - - uid: 1581 - components: - - type: Transform - pos: 9.5,8.5 - parent: 588 -- proto: MaterialCloth1 - entities: - - uid: 702 - components: - - type: Transform - pos: 12.462601,18.586084 - parent: 588 - - uid: 1065 - components: - - type: Transform - pos: 24.460928,24.594687 - parent: 588 - - uid: 1066 - components: - - type: Transform - pos: 24.389935,24.296673 - parent: 588 -- proto: MaterialWoodPlank1 - entities: - - uid: 703 - components: - - type: Transform - pos: 12.817572,18.685423 - parent: 588 - - uid: 1064 - components: - - type: Transform - pos: 26.278374,24.608877 - parent: 588 - - uid: 1067 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 24.801699,24.708214 - parent: 588 - - uid: 1076 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.823982,27.574818 - parent: 588 -- proto: MedicalBed - entities: - - uid: 1146 - components: - - type: Transform - pos: 28.5,24.5 - parent: 588 - - uid: 1147 - components: - - type: Transform - pos: 28.5,25.5 - parent: 588 -- proto: MedkitAdvancedFilled - entities: - - uid: 1153 - components: - - type: Transform - pos: 30.614443,28.392822 - parent: 588 -- proto: MedkitCombatFilled - entities: - - uid: 1154 - components: - - type: Transform - pos: 30.40146,28.066427 - parent: 588 -- proto: OperatingTable - entities: - - uid: 1389 - components: - - type: Transform - pos: 9.5,43.5 - parent: 588 -- proto: Paper - entities: - - uid: 1055 - components: - - type: Transform - pos: 20.428474,24.722406 - parent: 588 - - uid: 1056 - components: - - type: Transform - pos: 20.669853,24.52373 - parent: 588 -- proto: PaperOffice - entities: - - uid: 327 - components: - - type: Transform - pos: 21.415642,4.0728827 - parent: 588 - - uid: 328 - components: - - type: Transform - pos: 21.586027,4.0019264 - parent: 588 - - uid: 1113 - components: - - type: Transform - pos: 20.706646,15.341779 - parent: 588 - - uid: 1114 - components: - - type: Transform - pos: 20.465267,15.185677 - parent: 588 - - uid: 1115 - components: - - type: Transform - pos: 20.30908,14.603841 - parent: 588 -- proto: PartRodMetal1 - entities: - - uid: 1071 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 25.341253,26.595633 - parent: 588 - - uid: 1072 - components: - - type: Transform - pos: 25.36965,28.11408 - parent: 588 -- proto: Pen - entities: - - uid: 366 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 21.352327,3.9473093 - parent: 588 - - uid: 367 - components: - - type: Transform - pos: 18.75395,1.1232786 - parent: 588 - - uid: 368 - components: - - type: Transform - pos: 24.788435,1.4496742 - parent: 588 - - uid: 731 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.36841,19.019064 - parent: 588 - - uid: 732 - components: - - type: Transform - pos: 7.4631767,22.637186 - parent: 588 -- proto: PhoneInstrument - entities: - - uid: 371 - components: - - type: Transform - pos: 25.484175,4.4865713 - parent: 588 -- proto: PillCanister - entities: - - uid: 1481 - components: - - type: Transform - pos: 14.438607,42.637726 - parent: 588 -- proto: PillSpaceDrugs - entities: - - uid: 1479 - components: - - type: Transform - pos: 14.438607,42.96412 - parent: 588 - - uid: 1480 - components: - - type: Transform - pos: 14.537998,42.878975 - parent: 588 -- proto: PlushieNuke - entities: - - uid: 1850 - components: - - type: Transform - pos: 22.519993,28.594225 - parent: 588 -- proto: PortableFlasher - entities: - - uid: 1234 - components: - - type: Transform - pos: 32.5,25.5 - parent: 588 -- proto: PortableGeneratorPacman - entities: - - uid: 967 - components: - - type: Transform - pos: 16.5,32.5 - parent: 588 - - uid: 969 - components: - - type: Transform - pos: 24.5,32.5 - parent: 588 -- proto: PortableGeneratorSuperPacman - entities: - - uid: 50 - components: - - type: Transform - pos: 26.5,15.5 - parent: 588 - - uid: 55 - components: - - type: Transform - pos: 28.5,15.5 - parent: 588 - - uid: 1504 - components: - - type: Transform - pos: 18.5,44.5 - parent: 588 - - uid: 1505 - components: - - type: Transform - pos: 20.5,44.5 - parent: 588 -- proto: PortableScrubber - entities: - - uid: 1101 - components: - - type: Transform - pos: 18.5,30.5 - parent: 588 -- proto: PosterContrabandBountyHunters - entities: - - uid: 1578 - components: - - type: Transform - pos: 13.5,15.5 - parent: 588 -- proto: PosterLegitDickGumshue - entities: - - uid: 1576 - components: - - type: Transform - pos: 9.5,15.5 - parent: 588 -- proto: PosterLegitEnlist - entities: - - uid: 1800 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,9.5 - parent: 588 -- proto: PosterLegitNanotrasenLogo - entities: - - uid: 1802 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,48.5 - parent: 588 - - uid: 1803 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,21.5 - parent: 588 -- proto: PosterLegitObey - entities: - - uid: 1801 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,42.5 - parent: 588 -- proto: PosterLegitSecWatch - entities: - - uid: 1799 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,7.5 - parent: 588 -- proto: PosterLegitSpaceCops - entities: - - uid: 1804 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,19.5 - parent: 588 -- proto: PottedPlantRandom - entities: - - uid: 1286 - components: - - type: Transform - pos: 16.5,38.5 - parent: 588 - - uid: 1287 - components: - - type: Transform - pos: 22.5,40.5 - parent: 588 -- proto: PowerCellHyper - entities: - - uid: 469 - components: - - type: Transform - pos: 12.355853,25.41643 - parent: 588 - - uid: 590 - components: - - type: Transform - pos: 5.381793,16.642464 - parent: 588 -- proto: PowerCellRecharger - entities: - - uid: 1103 - components: - - type: Transform - pos: 15.5,30.5 - parent: 588 - - uid: 1568 - components: - - type: Transform - pos: 21.5,47.5 - parent: 588 -- proto: Poweredlight - entities: - - uid: 1641 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,0.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1642 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 14.5,0.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1646 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.5,0.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1647 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 28.5,0.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1648 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 21.5,6.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1649 - components: - - type: Transform - pos: 13.5,10.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1650 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 16.5,6.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1651 - components: - - type: Transform - pos: 18.5,10.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1693 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 32.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1701 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 18.5,12.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1702 - components: - - type: Transform - pos: 20.5,16.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1703 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 34.5,20.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1704 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 16.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1705 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,27.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1706 - components: - - type: Transform - pos: 18.5,40.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1741 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,21.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1743 - components: - - type: Transform - pos: 21.5,22.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1830 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 30.5,43.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1831 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 30.5,47.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 -- proto: PoweredlightLED - entities: - - uid: 1707 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,42.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1708 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,42.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1709 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,46.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1710 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,46.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1725 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 28.5,27.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 -- proto: PoweredSmallLight - entities: - - uid: 470 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 26.5,14.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 940 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,28.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 948 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,28.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 953 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1603 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,10.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1604 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 32.5,10.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1605 - components: - - type: Transform - pos: 29.5,6.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1606 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 29.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1607 - components: - - type: Transform - pos: 32.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1608 - components: - - type: Transform - pos: 26.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1643 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,1.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1644 - components: - - type: Transform - pos: 20.5,4.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1645 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 19.5,0.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1652 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 9.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1653 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 7.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1654 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1655 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,8.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1656 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,14.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1657 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,14.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1659 - components: - - type: Transform - pos: 3.5,18.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1661 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,22.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1662 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,27.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1663 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1664 - components: - - type: Transform - pos: 0.5,28.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1665 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,24.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1666 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,30.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1667 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,30.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1668 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,36.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1669 - components: - - type: Transform - pos: 8.5,34.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1670 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,38.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1671 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,38.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1672 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,43.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1673 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,43.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1674 - components: - - type: Transform - pos: 2.5,47.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1675 - components: - - type: Transform - pos: 4.5,47.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1676 - components: - - type: Transform - pos: 9.5,40.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1677 - components: - - type: Transform - pos: 13.5,40.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1678 - components: - - type: Transform - pos: 13.5,36.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1679 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 21.5,34.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1680 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 32.5,35.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1681 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 34.5,35.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1682 - components: - - type: Transform - pos: 25.5,36.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1683 - components: - - type: Transform - pos: 28.5,38.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1684 - components: - - type: Transform - pos: 19.5,46.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1685 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 17.5,47.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1686 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 21.5,47.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1687 - components: - - type: Transform - pos: 23.5,32.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1688 - components: - - type: Transform - pos: 17.5,32.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1689 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 22.5,27.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1690 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1694 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 28.5,19.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1695 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 24.5,19.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1696 - components: - - type: Transform - pos: 13.5,22.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1697 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,18.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1698 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 15.5,18.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1699 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,16.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1700 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,13.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1828 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,42.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1829 - components: - - type: Transform - pos: 25.5,48.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 -- proto: PoweredSmallLightEmpty - entities: - - uid: 1640 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,25.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 - - uid: 1658 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,27.5 - parent: 588 - - type: ApcPowerReceiver - powerLoad: 0 -- proto: Rack - entities: - - uid: 255 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 15.5,0.5 - parent: 588 - - uid: 264 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,0.5 - parent: 588 - - uid: 283 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,0.5 - parent: 588 - - uid: 285 - components: - - type: Transform - pos: 13.5,0.5 - parent: 588 - - uid: 324 - components: - - type: Transform - pos: 19.5,4.5 - parent: 588 - - uid: 396 - components: - - type: Transform - pos: 28.5,8.5 - parent: 588 - - uid: 401 - components: - - type: Transform - pos: 32.5,8.5 - parent: 588 - - uid: 417 - components: - - type: Transform - pos: 12.5,6.5 - parent: 588 - - uid: 418 - components: - - type: Transform - pos: 12.5,10.5 - parent: 588 - - uid: 419 - components: - - type: Transform - pos: 22.5,10.5 - parent: 588 - - uid: 420 - components: - - type: Transform - pos: 22.5,6.5 - parent: 588 - - uid: 478 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,15.5 - parent: 588 - - uid: 551 - components: - - type: Transform - pos: 22.5,15.5 - parent: 588 - - uid: 585 - components: - - type: Transform - pos: 1.5,12.5 - parent: 588 - - uid: 596 - components: - - type: Transform - pos: 1.5,16.5 - parent: 588 - - uid: 597 - components: - - type: Transform - pos: 5.5,16.5 - parent: 588 - - uid: 598 - components: - - type: Transform - pos: 5.5,12.5 - parent: 588 - - uid: 966 - components: - - type: Transform - pos: 25.5,32.5 - parent: 588 - - uid: 977 - components: - - type: Transform - pos: 15.5,32.5 - parent: 588 - - uid: 1015 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 12.5,25.5 - parent: 588 - - uid: 1016 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 12.5,24.5 - parent: 588 - - uid: 1021 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,25.5 - parent: 588 - - uid: 1024 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,24.5 - parent: 588 - - uid: 1111 - components: - - type: Transform - pos: 14.5,32.5 - parent: 588 - - uid: 1112 - components: - - type: Transform - pos: 26.5,32.5 - parent: 588 - - uid: 1206 - components: - - type: Transform - pos: 1.5,8.5 - parent: 588 - - uid: 1208 - components: - - type: Transform - pos: 9.5,8.5 - parent: 588 - - uid: 1211 - components: - - type: Transform - pos: 2.5,34.5 - parent: 588 - - uid: 1319 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 29.5,40.5 - parent: 588 - - uid: 1562 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 17.5,47.5 - parent: 588 - - uid: 1858 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,21.5 - parent: 588 -- proto: Railing - entities: - - uid: 313 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 30.5,4.5 - parent: 588 - - uid: 314 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 30.5,0.5 - parent: 588 - - uid: 427 - components: - - type: Transform - pos: 6.5,7.5 - parent: 588 - - uid: 428 - components: - - type: Transform - pos: 4.5,7.5 - parent: 588 - - uid: 429 - components: - - type: Transform - pos: 3.5,7.5 - parent: 588 - - uid: 430 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 7.5,9.5 - parent: 588 - - uid: 431 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,9.5 - parent: 588 - - uid: 435 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,9.5 - parent: 588 - - uid: 436 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,9.5 - parent: 588 - - uid: 437 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,9.5 - parent: 588 - - uid: 439 - components: - - type: Transform - pos: 5.5,7.5 - parent: 588 - - uid: 440 - components: - - type: Transform - pos: 7.5,7.5 - parent: 588 - - uid: 770 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,21.5 - parent: 588 - - uid: 850 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,30.5 - parent: 588 - - uid: 851 - components: - - type: Transform - pos: 9.5,32.5 - parent: 588 - - uid: 854 - components: - - type: Transform - pos: 3.5,32.5 - parent: 588 - - uid: 855 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,30.5 - parent: 588 - - uid: 1259 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,4.5 - parent: 588 - - uid: 1260 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 9.5,4.5 - parent: 588 - - uid: 1261 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 9.5,0.5 - parent: 588 - - uid: 1262 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,0.5 - parent: 588 -- proto: RailingCorner - entities: - - uid: 315 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 30.5,1.5 - parent: 588 - - uid: 316 - components: - - type: Transform - pos: 30.5,3.5 - parent: 588 - - uid: 771 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 27.5,21.5 - parent: 588 - - uid: 772 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,21.5 - parent: 588 - - uid: 845 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,32.5 - parent: 588 - - uid: 846 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,30.5 - parent: 588 - - uid: 847 - components: - - type: Transform - pos: 10.5,32.5 - parent: 588 - - uid: 848 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,30.5 - parent: 588 - - uid: 849 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,30.5 - parent: 588 - - uid: 852 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,32.5 - parent: 588 - - uid: 853 - components: - - type: Transform - pos: 4.5,32.5 - parent: 588 - - uid: 856 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,30.5 - parent: 588 - - uid: 886 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,40.5 - parent: 588 - - uid: 888 - components: - - type: Transform - pos: 2.5,40.5 - parent: 588 - - uid: 890 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,40.5 - parent: 588 - - uid: 891 - components: - - type: Transform - pos: 5.5,40.5 - parent: 588 - - uid: 892 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,38.5 - parent: 588 - - uid: 893 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,38.5 - parent: 588 - - uid: 894 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,38.5 - parent: 588 - - uid: 895 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,38.5 - parent: 588 - - uid: 1255 - components: - - type: Transform - pos: 7.5,3.5 - parent: 588 - - uid: 1256 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 9.5,3.5 - parent: 588 - - uid: 1257 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,1.5 - parent: 588 - - uid: 1258 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,1.5 - parent: 588 - - uid: 1351 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,44.5 - parent: 588 - - uid: 1352 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 2.5,43.5 - parent: 588 - - uid: 1353 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,43.5 - parent: 588 - - uid: 1354 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 5.5,44.5 - parent: 588 - - uid: 1355 - components: - - type: Transform - pos: 1.5,46.5 - parent: 588 - - uid: 1356 - components: - - type: Transform - pos: 2.5,47.5 - parent: 588 - - uid: 1357 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 4.5,47.5 - parent: 588 - - uid: 1358 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 5.5,46.5 - parent: 588 -- proto: RailingCornerSmall - entities: - - uid: 337 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 29.5,3.5 - parent: 588 - - uid: 338 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 29.5,1.5 - parent: 588 - - uid: 1376 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,43.5 - parent: 588 - - uid: 1377 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,47.5 - parent: 588 - - uid: 1378 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,47.5 - parent: 588 - - uid: 1379 - components: - - type: Transform - pos: 5.5,43.5 - parent: 588 -- proto: RandomDrinkBottle - entities: - - uid: 580 - components: - - type: Transform - pos: 12.5,12.5 - parent: 588 -- proto: RandomFoodSingle - entities: - - uid: 764 - components: - - type: Transform - pos: 6.5,19.5 - parent: 588 -- proto: RandomInstruments - entities: - - uid: 546 - components: - - type: Transform - pos: 1.5,4.5 - parent: 588 - - uid: 1159 - components: - - type: Transform - pos: 21.5,18.5 - parent: 588 - - uid: 1833 - components: - - type: Transform - pos: 24.5,42.5 - parent: 588 -- proto: RandomPosterContraband - entities: - - uid: 1571 - components: - - type: Transform - pos: 25.5,39.5 - parent: 588 - - uid: 1572 - components: - - type: Transform - pos: 3.5,35.5 - parent: 588 - - uid: 1573 - components: - - type: Transform - pos: 7.5,35.5 - parent: 588 - - uid: 1574 - components: - - type: Transform - pos: 5.5,25.5 - parent: 588 - - uid: 1575 - components: - - type: Transform - pos: 30.5,15.5 - parent: 588 - - uid: 1805 - components: - - type: Transform - pos: 18.5,43.5 - parent: 588 - - uid: 1806 - components: - - type: Transform - pos: 20.5,47.5 - parent: 588 -- proto: RandomSoap - entities: - - uid: 397 - components: - - type: Transform - pos: 8.5,24.5 - parent: 588 -- proto: RandomVending - entities: - - uid: 539 - components: - - type: Transform - pos: 17.5,16.5 - parent: 588 -- proto: ReinforcedWindow - entities: - - uid: 214 - components: - - type: Transform - pos: 19.5,34.5 - parent: 588 - - uid: 409 - components: - - type: Transform - pos: 15.5,7.5 - parent: 588 - - uid: 410 - components: - - type: Transform - pos: 15.5,9.5 - parent: 588 - - uid: 411 - components: - - type: Transform - pos: 19.5,7.5 - parent: 588 - - uid: 412 - components: - - type: Transform - pos: 19.5,9.5 - parent: 588 - - uid: 591 - components: - - type: Transform - pos: 2.5,12.5 - parent: 588 - - uid: 592 - components: - - type: Transform - pos: 4.5,12.5 - parent: 588 - - uid: 594 - components: - - type: Transform - pos: 4.5,16.5 - parent: 588 - - uid: 595 - components: - - type: Transform - pos: 2.5,16.5 - parent: 588 - - uid: 1166 - components: - - type: Transform - pos: 19.5,36.5 - parent: 588 - - uid: 1168 - components: - - type: Transform - pos: 15.5,36.5 - parent: 588 - - uid: 1169 - components: - - type: Transform - pos: 15.5,34.5 - parent: 588 -- proto: RemoteSignaller - entities: - - uid: 593 - components: - - type: Transform - pos: 34.361877,24.623777 - parent: 588 - - type: DeviceLinkSource - linkedPorts: - 1238: - - Pressed: Toggle - 1239: - - Pressed: Toggle - 1237: - - Pressed: Toggle - - uid: 1104 - components: - - type: Transform - pos: 25.24476,30.698978 - parent: 588 - - uid: 1105 - components: - - type: Transform - pos: 25.443544,30.613832 - parent: 588 - - uid: 1106 - components: - - type: Transform - pos: 5.677143,16.762346 - parent: 588 -- proto: RiotLaserShield - entities: - - uid: 1618 - components: - - type: Transform - pos: 12.616156,10.534842 - parent: 588 -- proto: RiotShield - entities: - - uid: 600 - components: - - type: Transform - pos: 1.3209407,16.656654 - parent: 588 - - uid: 601 - components: - - type: Transform - pos: 1.5481212,16.543125 - parent: 588 -- proto: SalvageCanisterSpawner - entities: - - uid: 998 - components: - - type: Transform - pos: 22.5,30.5 - parent: 588 - - uid: 1009 - components: - - type: Transform - pos: 19.5,30.5 - parent: 588 - - uid: 1025 - components: - - type: Transform - pos: 21.5,30.5 - parent: 588 - - uid: 1190 - components: - - type: Transform - pos: 9.5,36.5 - parent: 588 - - uid: 1210 - components: - - type: Transform - pos: 9.5,48.5 - parent: 588 - - uid: 1413 - components: - - type: Transform - pos: 13.5,48.5 - parent: 588 - - uid: 1470 - components: - - type: Transform - pos: 12.5,48.5 - parent: 588 -- proto: SawAdvanced - entities: - - uid: 1468 - components: - - type: Transform - pos: 8.527969,43.529327 - parent: 588 -- proto: ScalpelLaser - entities: - - uid: 1472 - components: - - type: Transform - pos: 8.485372,43.131977 - parent: 588 -- proto: ScalpelShiv - entities: - - uid: 708 - components: - - type: Transform - pos: 16.074419,18.727995 - parent: 588 - - uid: 1592 - components: - - type: Transform - pos: 10.50393,24.491432 - parent: 588 -- proto: SeedExtractor - entities: - - uid: 802 - components: - - type: Transform - pos: 33.5,21.5 - parent: 588 - - uid: 1776 - components: - - type: Transform - pos: 28.5,42.5 - parent: 588 -- proto: SheetGlass - entities: - - uid: 649 - components: - - type: Transform - pos: 14.3137455,32.471424 - parent: 588 -- proto: SheetPlasteel - entities: - - uid: 866 - components: - - type: Transform - pos: 2.412651,34.456436 - parent: 588 -- proto: SheetPlastic - entities: - - uid: 398 - components: - - type: Transform - pos: 20.04785,45.07574 - parent: 588 -- proto: SheetSteel - entities: - - uid: 656 - components: - - type: Transform - pos: 26.36062,32.5183 - parent: 588 - - uid: 699 - components: - - type: Transform - pos: 29.259031,40.432583 - parent: 588 -- proto: ShowcaseRobot - entities: - - uid: 1621 - components: - - type: Transform - pos: 16.5,10.5 - parent: 588 - - uid: 1622 - components: - - type: Transform - pos: 18.5,6.5 - parent: 588 -- proto: ShuttersNormal - entities: - - uid: 1237 - components: - - type: Transform - pos: 34.5,27.5 - parent: 588 - - type: DeviceLinkSink - links: - - 593 - - uid: 1238 - components: - - type: Transform - pos: 32.5,27.5 - parent: 588 - - type: DeviceLinkSink - links: - - 593 -- proto: ShuttersWindow - entities: - - uid: 1239 - components: - - type: Transform - pos: 33.5,27.5 - parent: 588 - - type: DeviceLinkSink - links: - - 593 -- proto: SignCloning - entities: - - uid: 1484 - components: - - type: Transform - pos: 12.5,43.5 - parent: 588 -- proto: SignPrison - entities: - - uid: 1792 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,3.5 - parent: 588 - - uid: 1793 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,1.5 - parent: 588 - - uid: 1794 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,21.5 - parent: 588 - - uid: 1795 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,19.5 - parent: 588 - - uid: 1796 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 0.5,46.5 - parent: 588 - - uid: 1797 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,44.5 - parent: 588 -- proto: SignSecurity - entities: - - uid: 1798 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 22.5,1.5 - parent: 588 -- proto: SignSurgery - entities: - - uid: 1483 - components: - - type: Transform - pos: 10.5,43.5 - parent: 588 -- proto: Sink - entities: - - uid: 935 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,25.5 - parent: 588 -- proto: SinkStemlessWater - entities: - - uid: 1461 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 9.5,42.5 - parent: 588 - - uid: 1462 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,42.5 - parent: 588 -- proto: SMESBasic - entities: - - uid: 46 - components: - - type: Transform - pos: 26.5,13.5 - parent: 588 - - uid: 56 - components: - - type: Transform - pos: 28.5,13.5 - parent: 588 - - uid: 747 - components: - - type: Transform - pos: 26.5,19.5 - parent: 588 - - uid: 1506 - components: - - type: Transform - pos: 18.5,46.5 - parent: 588 - - uid: 1507 - components: - - type: Transform - pos: 20.5,46.5 - parent: 588 -- proto: SoapSyndie - entities: - - uid: 1856 - components: - - type: Transform - pos: 10.4890785,27.46785 - parent: 588 -- proto: SpaceCash100 - entities: - - uid: 1243 - components: - - type: Transform - pos: 11.887424,39.621456 - parent: 588 - - uid: 1244 - components: - - type: Transform - pos: 11.759636,39.479546 - parent: 588 - - uid: 1296 - components: - - type: Transform - pos: 12.100407,39.465355 - parent: 588 - - uid: 1297 - components: - - type: Transform - pos: 12.100407,39.80594 - parent: 588 - - uid: 1298 - components: - - type: Transform - pos: 11.688642,39.720795 - parent: 588 - - uid: 1299 - components: - - type: Transform - pos: 11.4330635,39.57888 - parent: 588 -- proto: Spear - entities: - - uid: 1834 - components: - - type: Transform - pos: 24.466219,48.441994 - parent: 588 -- proto: SpeedLoaderMagnum - entities: - - uid: 950 - components: - - type: Transform - pos: 28.703945,8.421182 - parent: 588 -- proto: StasisBed - entities: - - uid: 1425 - components: - - type: Transform - pos: 13.5,43.5 - parent: 588 -- proto: StimkitFilled - entities: - - uid: 561 - components: - - type: Transform - pos: 30.39083,27.514402 - parent: 588 -- proto: StimpackMini - entities: - - uid: 1879 - components: - - type: Transform - pos: 24.467485,46.702366 - parent: 588 -- proto: Stool - entities: - - uid: 1017 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,25.5 - parent: 588 - - uid: 1018 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 14.5,24.5 - parent: 588 - - uid: 1019 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 16.5,28.5 - parent: 588 - - uid: 1020 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,28.5 - parent: 588 - - uid: 1593 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 0.5,13.5 - parent: 588 - - uid: 1594 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 0.5,15.5 - parent: 588 - - uid: 1595 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,15.5 - parent: 588 - - uid: 1596 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 6.5,13.5 - parent: 588 -- proto: SubstationBasic - entities: - - uid: 467 - components: - - type: Transform - pos: 27.5,13.5 - parent: 588 - - uid: 1508 - components: - - type: Transform - pos: 19.5,46.5 - parent: 588 -- proto: SubstationWallBasic - entities: - - uid: 774 - components: - - type: Transform - pos: 27.5,19.5 - parent: 588 - - uid: 972 - components: - - type: Transform - pos: 19.5,32.5 - parent: 588 -- proto: SyringeEphedrine - entities: - - uid: 1475 - components: - - type: Transform - pos: 14.472328,42.917698 - parent: 588 -- proto: Table - entities: - - uid: 525 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 16.5,13.5 - parent: 588 - - uid: 527 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 16.5,12.5 - parent: 588 - - uid: 528 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 17.5,12.5 - parent: 588 - - uid: 535 - components: - - type: Transform - pos: 20.5,14.5 - parent: 588 - - uid: 536 - components: - - type: Transform - pos: 20.5,15.5 - parent: 588 - - uid: 630 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,19.5 - parent: 588 - - uid: 632 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,19.5 - parent: 588 - - uid: 633 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 10.5,18.5 - parent: 588 - - uid: 636 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 6.5,22.5 - parent: 588 - - uid: 637 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 7.5,22.5 - parent: 588 - - uid: 710 - components: - - type: Transform - pos: 18.5,22.5 - parent: 588 - - uid: 711 - components: - - type: Transform - pos: 18.5,21.5 - parent: 588 - - uid: 712 - components: - - type: Transform - pos: 21.5,18.5 - parent: 588 - - uid: 713 - components: - - type: Transform - pos: 22.5,18.5 - parent: 588 - - uid: 714 - components: - - type: Transform - pos: 18.5,18.5 - parent: 588 - - uid: 715 - components: - - type: Transform - pos: 19.5,18.5 - parent: 588 - - uid: 799 - components: - - type: Transform - pos: 33.5,20.5 - parent: 588 - - uid: 1118 - components: - - type: Transform - pos: 22.5,12.5 - parent: 588 - - uid: 1778 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 30.5,48.5 - parent: 588 - - uid: 1779 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 29.5,48.5 - parent: 588 - - uid: 1780 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 30.5,47.5 - parent: 588 -- proto: TableFrame - entities: - - uid: 705 - components: - - type: Transform - pos: 15.5,22.5 - parent: 588 - - uid: 1063 - components: - - type: Transform - pos: 26.5,24.5 - parent: 588 -- proto: TableGlass - entities: - - uid: 1144 - components: - - type: Transform - pos: 30.5,27.5 - parent: 588 - - uid: 1145 - components: - - type: Transform - pos: 30.5,28.5 - parent: 588 - - uid: 1390 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,43.5 - parent: 588 - - uid: 1391 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 8.5,42.5 - parent: 588 - - uid: 1398 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,44.5 - parent: 588 - - uid: 1405 - components: - - type: Transform - pos: 14.5,42.5 - parent: 588 - - uid: 1406 - components: - - type: Transform - pos: 14.5,43.5 - parent: 588 - - uid: 1407 - components: - - type: Transform - pos: 12.5,44.5 - parent: 588 -- proto: TableReinforced - entities: - - uid: 924 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,36.5 - parent: 588 - - uid: 925 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,35.5 - parent: 588 - - uid: 926 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,34.5 - parent: 588 - - uid: 1005 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 15.5,30.5 - parent: 588 - - uid: 1006 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,30.5 - parent: 588 - - uid: 1012 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 14.5,28.5 - parent: 588 - - uid: 1023 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 16.5,24.5 - parent: 588 - - uid: 1235 - components: - - type: Transform - pos: 34.5,24.5 - parent: 588 - - uid: 1567 - components: - - type: Transform - pos: 21.5,47.5 - parent: 588 -- proto: TableReinforcedGlass - entities: - - uid: 1213 - components: - - type: Transform - pos: 10.5,39.5 - parent: 588 - - uid: 1214 - components: - - type: Transform - pos: 11.5,39.5 - parent: 588 - - uid: 1215 - components: - - type: Transform - pos: 12.5,39.5 - parent: 588 -- proto: TableWood - entities: - - uid: 309 - components: - - type: Transform - pos: 20.5,4.5 - parent: 588 - - uid: 310 - components: - - type: Transform - pos: 21.5,4.5 - parent: 588 - - uid: 311 - components: - - type: Transform - pos: 18.5,0.5 - parent: 588 - - uid: 312 - components: - - type: Transform - pos: 21.5,3.5 - parent: 588 - - uid: 317 - components: - - type: Transform - pos: 18.5,1.5 - parent: 588 - - uid: 318 - components: - - type: Transform - pos: 19.5,0.5 - parent: 588 - - uid: 332 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,3.5 - parent: 588 - - uid: 333 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,3.5 - parent: 588 - - uid: 334 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 27.5,3.5 - parent: 588 - - uid: 335 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,4.5 - parent: 588 - - uid: 336 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 27.5,4.5 - parent: 588 - - uid: 340 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 24.5,1.5 - parent: 588 - - uid: 341 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 25.5,1.5 - parent: 588 - - uid: 342 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 27.5,1.5 - parent: 588 - - uid: 343 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 28.5,1.5 - parent: 588 - - uid: 563 - components: - - type: Transform - pos: 13.5,13.5 - parent: 588 - - uid: 564 - components: - - type: Transform - pos: 12.5,13.5 - parent: 588 - - uid: 565 - components: - - type: Transform - pos: 12.5,12.5 - parent: 588 - - uid: 1047 - components: - - type: Transform - pos: 22.5,28.5 - parent: 588 - - uid: 1048 - components: - - type: Transform - pos: 20.5,24.5 - parent: 588 - - uid: 1062 - components: - - type: Transform - pos: 26.5,28.5 - parent: 588 - - uid: 1227 - components: - - type: Transform - pos: 12.5,36.5 - parent: 588 - - uid: 1228 - components: - - type: Transform - pos: 22.5,34.5 - parent: 588 - - uid: 1783 - components: - - type: Transform - pos: 24.5,46.5 - parent: 588 - - uid: 1784 - components: - - type: Transform - pos: 24.5,44.5 - parent: 588 -- proto: TargetHuman - entities: - - uid: 1077 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 32.5,35.5 - parent: 588 -- proto: TintedWindow - entities: - - uid: 567 - components: - - type: Transform - pos: 12.5,15.5 - parent: 588 - - uid: 1463 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,43.5 - parent: 588 - - uid: 1464 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 12.5,43.5 - parent: 588 -- proto: ToiletEmpty - entities: - - uid: 932 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,24.5 - parent: 588 - - uid: 933 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,24.5 - parent: 588 - - uid: 934 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,25.5 - parent: 588 -- proto: UniformScrubsColorPurple - entities: - - uid: 1712 - components: - - type: Transform - pos: 10.503376,44.53288 - parent: 588 -- proto: VendingMachineChefvend - entities: - - uid: 532 - components: - - type: Transform - pos: 18.5,12.5 - parent: 588 -- proto: VendingMachineCigs - entities: - - uid: 720 - components: - - type: Transform - pos: 22.5,22.5 - parent: 588 -- proto: VendingMachineCoffee - entities: - - uid: 765 - components: - - type: Transform - pos: 10.5,22.5 - parent: 588 - - uid: 1285 - components: - - type: Transform - pos: 18.5,40.5 - parent: 588 -- proto: VendingMachineDetDrobe - entities: - - uid: 582 - components: - - type: Transform - pos: 10.5,14.5 - parent: 588 -- proto: VendingMachineDinnerware - entities: - - uid: 1781 - components: - - type: Transform - pos: 30.5,46.5 - parent: 588 -- proto: VendingMachineDonut - entities: - - uid: 538 - components: - - type: Transform - pos: 16.5,16.5 - parent: 588 -- proto: VendingMachineLawDrobe - entities: - - uid: 319 - components: - - type: Transform - pos: 18.5,4.5 - parent: 588 -- proto: VendingMachineMedical - entities: - - uid: 1143 - components: - - type: Transform - pos: 28.5,28.5 - parent: 588 -- proto: VendingMachineSec - entities: - - uid: 1013 - components: - - type: Transform - pos: 14.5,27.5 - parent: 588 -- proto: VendingMachineSeedsUnlocked - entities: - - uid: 800 - components: - - type: Transform - pos: 33.5,19.5 - parent: 588 - - uid: 1775 - components: - - type: Transform - pos: 28.5,44.5 - parent: 588 -- proto: WallmountTelescreen - entities: - - uid: 572 - components: - - type: Transform - pos: 13.5,13.5 - parent: 588 -- proto: WallPlastitaniumIndestructible - entities: - - uid: 377 - components: - - type: Transform - pos: 30.5,7.5 - parent: 588 - - uid: 378 - components: - - type: Transform - pos: 29.5,7.5 - parent: 588 - - uid: 379 - components: - - type: Transform - pos: 25.5,9.5 - parent: 588 - - uid: 380 - components: - - type: Transform - pos: 27.5,9.5 - parent: 588 - - uid: 381 - components: - - type: Transform - pos: 27.5,8.5 - parent: 588 - - uid: 382 - components: - - type: Transform - pos: 28.5,9.5 - parent: 588 - - uid: 383 - components: - - type: Transform - pos: 31.5,9.5 - parent: 588 - - uid: 384 - components: - - type: Transform - pos: 31.5,8.5 - parent: 588 - - uid: 385 - components: - - type: Transform - pos: 31.5,7.5 - parent: 588 - - uid: 386 - components: - - type: Transform - pos: 25.5,8.5 - parent: 588 - - uid: 387 - components: - - type: Transform - pos: 33.5,7.5 - parent: 588 - - uid: 388 - components: - - type: Transform - pos: 25.5,7.5 - parent: 588 - - uid: 389 - components: - - type: Transform - pos: 27.5,7.5 - parent: 588 - - uid: 390 - components: - - type: Transform - pos: 30.5,9.5 - parent: 588 - - uid: 391 - components: - - type: Transform - pos: 28.5,7.5 - parent: 588 - - uid: 392 - components: - - type: Transform - pos: 26.5,9.5 - parent: 588 - - uid: 393 - components: - - type: Transform - pos: 33.5,8.5 - parent: 588 - - uid: 394 - components: - - type: Transform - pos: 33.5,9.5 - parent: 588 - - uid: 395 - components: - - type: Transform - pos: 32.5,9.5 - parent: 588 -- proto: WallReinforced - entities: - - uid: 45 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,8.5 - parent: 588 - - uid: 51 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,8.5 - parent: 588 - - uid: 244 - components: - - type: Transform - pos: 6.5,4.5 - parent: 588 - - uid: 245 - components: - - type: Transform - pos: 6.5,3.5 - parent: 588 - - uid: 246 - components: - - type: Transform - pos: 10.5,4.5 - parent: 588 - - uid: 247 - components: - - type: Transform - pos: 10.5,3.5 - parent: 588 - - uid: 266 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,1.5 - parent: 588 - - uid: 267 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 6.5,0.5 - parent: 588 - - uid: 268 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,1.5 - parent: 588 - - uid: 269 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,0.5 - parent: 588 - - uid: 291 - components: - - type: Transform - pos: 15.5,6.5 - parent: 588 - - uid: 292 - components: - - type: Transform - pos: 19.5,6.5 - parent: 588 - - uid: 405 - components: - - type: Transform - pos: 15.5,10.5 - parent: 588 - - uid: 406 - components: - - type: Transform - pos: 19.5,10.5 - parent: 588 - - uid: 426 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,9.5 - parent: 588 - - uid: 432 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,7.5 - parent: 588 - - uid: 433 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,9.5 - parent: 588 - - uid: 434 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,7.5 - parent: 588 - - uid: 570 - components: - - type: Transform - pos: 0.5,46.5 - parent: 588 - - uid: 621 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,21.5 - parent: 588 - - uid: 622 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,19.5 - parent: 588 - - uid: 623 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 3.5,21.5 - parent: 588 - - uid: 627 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,19.5 - parent: 588 - - uid: 1078 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 33.5,35.5 - parent: 588 - - uid: 1330 - components: - - type: Transform - pos: 0.5,44.5 - parent: 588 - - uid: 1332 - components: - - type: Transform - pos: 2.5,42.5 - parent: 588 - - uid: 1334 - components: - - type: Transform - pos: 4.5,42.5 - parent: 588 - - uid: 1335 - components: - - type: Transform - pos: 6.5,44.5 - parent: 588 - - uid: 1337 - components: - - type: Transform - pos: 4.5,48.5 - parent: 588 - - uid: 1338 - components: - - type: Transform - pos: 6.5,46.5 - parent: 588 - - uid: 1340 - components: - - type: Transform - pos: 2.5,48.5 - parent: 588 -- proto: WallSolid - entities: - - uid: 140 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,25.5 - parent: 588 - - uid: 144 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,26.5 - parent: 588 - - uid: 145 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,25.5 - parent: 588 - - uid: 146 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 5.5,27.5 - parent: 588 - - uid: 205 - components: - - type: Transform - pos: 8.5,35.5 - parent: 588 - - uid: 206 - components: - - type: Transform - pos: 7.5,35.5 - parent: 588 - - uid: 207 - components: - - type: Transform - pos: 6.5,35.5 - parent: 588 - - uid: 208 - components: - - type: Transform - pos: 4.5,35.5 - parent: 588 - - uid: 210 - components: - - type: Transform - pos: 1.5,34.5 - parent: 588 - - uid: 305 - components: - - type: Transform - pos: 22.5,4.5 - parent: 588 - - uid: 306 - components: - - type: Transform - pos: 22.5,3.5 - parent: 588 - - uid: 307 - components: - - type: Transform - pos: 22.5,0.5 - parent: 588 - - uid: 308 - components: - - type: Transform - pos: 22.5,1.5 - parent: 588 - - uid: 476 - components: - - type: Transform - pos: 25.5,13.5 - parent: 588 - - uid: 481 - components: - - type: Transform - pos: 25.5,15.5 - parent: 588 - - uid: 483 - components: - - type: Transform - pos: 30.5,13.5 - parent: 588 - - uid: 501 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 25.5,14.5 - parent: 588 - - uid: 510 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 30.5,15.5 - parent: 588 - - uid: 749 - components: - - type: Transform - pos: 25.5,19.5 - parent: 588 - - uid: 750 - components: - - type: Transform - pos: 27.5,19.5 - parent: 588 - - uid: 975 - components: - - type: Transform - pos: 19.5,32.5 - parent: 588 - - uid: 995 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 21.5,32.5 - parent: 588 - - uid: 1163 - components: - - type: Transform - pos: 8.5,36.5 - parent: 588 - - uid: 1164 - components: - - type: Transform - pos: 3.5,35.5 - parent: 588 - - uid: 1165 - components: - - type: Transform - pos: 2.5,35.5 - parent: 588 - - uid: 1167 - components: - - type: Transform - pos: 1.5,35.5 - parent: 588 - - uid: 1300 - components: - - type: Transform - pos: 25.5,39.5 - parent: 588 - - uid: 1303 - components: - - type: Transform - pos: 28.5,39.5 - parent: 588 - - uid: 1304 - components: - - type: Transform - pos: 29.5,39.5 - parent: 588 - - uid: 1305 - components: - - type: Transform - pos: 28.5,40.5 - parent: 588 - - uid: 1485 - components: - - type: Transform - pos: 17.5,43.5 - parent: 588 - - uid: 1486 - components: - - type: Transform - pos: 17.5,44.5 - parent: 588 - - uid: 1487 - components: - - type: Transform - pos: 18.5,43.5 - parent: 588 - - uid: 1488 - components: - - type: Transform - pos: 20.5,43.5 - parent: 588 - - uid: 1489 - components: - - type: Transform - pos: 21.5,43.5 - parent: 588 - - uid: 1490 - components: - - type: Transform - pos: 21.5,44.5 - parent: 588 - - uid: 1491 - components: - - type: Transform - pos: 18.5,47.5 - parent: 588 - - uid: 1492 - components: - - type: Transform - pos: 19.5,47.5 - parent: 588 - - uid: 1493 - components: - - type: Transform - pos: 20.5,47.5 - parent: 588 -- proto: WallWood - entities: - - uid: 554 - components: - - type: Transform - pos: 9.5,13.5 - parent: 588 - - uid: 555 - components: - - type: Transform - pos: 9.5,14.5 - parent: 588 - - uid: 556 - components: - - type: Transform - pos: 9.5,15.5 - parent: 588 - - uid: 557 - components: - - type: Transform - pos: 10.5,15.5 - parent: 588 - - uid: 558 - components: - - type: Transform - pos: 13.5,15.5 - parent: 588 - - uid: 559 - components: - - type: Transform - pos: 13.5,16.5 - parent: 588 - - uid: 566 - components: - - type: Transform - pos: 9.5,12.5 - parent: 588 -- proto: WardrobePrisonFilled - entities: - - uid: 297 - components: - - type: Transform - pos: 2.5,4.5 - parent: 588 - - uid: 302 - components: - - type: Transform - pos: 4.5,4.5 - parent: 588 - - uid: 303 - components: - - type: Transform - pos: 12.5,4.5 - parent: 588 - - uid: 304 - components: - - type: Transform - pos: 14.5,4.5 - parent: 588 - - uid: 544 - components: - - type: Transform - pos: 16.5,4.5 - parent: 588 - - uid: 545 - components: - - type: Transform - pos: 0.5,4.5 - parent: 588 - - uid: 1769 - components: - - type: Transform - pos: 24.5,43.5 - parent: 588 - - uid: 1770 - components: - - type: Transform - pos: 24.5,47.5 - parent: 588 -- proto: WaterCooler - entities: - - uid: 629 - components: - - type: Transform - pos: 6.5,18.5 - parent: 588 - - uid: 724 - components: - - type: Transform - pos: 19.5,22.5 - parent: 588 - - uid: 1284 - components: - - type: Transform - pos: 17.5,40.5 - parent: 588 - - uid: 1292 - components: - - type: Transform - pos: 21.5,12.5 - parent: 588 -- proto: WaterTankHighCapacity - entities: - - uid: 801 - components: - - type: Transform - pos: 30.5,22.5 - parent: 588 - - uid: 1789 - components: - - type: Transform - pos: 28.5,48.5 - parent: 588 -- proto: WeaponCapacitorRecharger - entities: - - uid: 760 - components: - - type: Transform - pos: 10.5,18.5 - parent: 588 - - uid: 929 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 26.5,34.5 - parent: 588 - - uid: 1033 - components: - - type: Transform - pos: 14.5,28.5 - parent: 588 - - uid: 1034 - components: - - type: Transform - pos: 16.5,24.5 - parent: 588 -- proto: WeaponDisablerPractice - entities: - - uid: 547 - components: - - type: Transform - pos: 1.4370823,0.5241035 - parent: 588 - - uid: 930 - components: - - type: Transform - pos: 26.440151,36.61676 - parent: 588 - - uid: 1611 - components: - - type: Transform - pos: 12.371853,10.605072 - parent: 588 -- proto: WeaponLaserCarbinePractice - entities: - - uid: 931 - components: - - type: Transform - pos: 26.596338,36.36132 - parent: 588 - - uid: 1612 - components: - - type: Transform - pos: 22.543945,6.5464144 - parent: 588 -- proto: WeaponShotgunKammerer - entities: - - uid: 583 - components: - - type: Transform - pos: 26.57963,35.4414 - parent: 588 -- proto: WindoorAssemblySecure - entities: - - uid: 696 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 16.5,19.5 - parent: 588 - - uid: 697 - components: - - type: Transform - pos: 12.5,21.5 - parent: 588 - - uid: 1073 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,25.5 - parent: 588 -- proto: WindoorSecure - entities: - - uid: 1761 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 26.5,43.5 - parent: 588 - - uid: 1762 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 26.5,47.5 - parent: 588 -- proto: WindoorSecureBrigLocked - entities: - - uid: 339 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 29.5,2.5 - parent: 588 -- proto: WindoorSecureEngineeringLocked - entities: - - uid: 1569 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,45.5 - parent: 588 - - uid: 1570 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,45.5 - parent: 588 -- proto: WindoorSecureMedicalLocked - entities: - - uid: 1408 - components: - - type: Transform - pos: 11.5,44.5 - parent: 588 -- proto: WindoorSecureSecurityLocked - entities: - - uid: 252 - components: - - type: Transform - pos: 4.5,3.5 - parent: 588 - - uid: 253 - components: - - type: Transform - pos: 2.5,3.5 - parent: 588 - - uid: 256 - components: - - type: Transform - pos: 16.5,3.5 - parent: 588 - - uid: 274 - components: - - type: Transform - pos: 12.5,3.5 - parent: 588 - - uid: 275 - components: - - type: Transform - pos: 14.5,3.5 - parent: 588 - - uid: 289 - components: - - type: Transform - pos: 0.5,3.5 - parent: 588 - - uid: 698 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 12.5,19.5 - parent: 588 - - uid: 1053 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 21.5,25.5 - parent: 588 - - uid: 1054 - components: - - type: Transform - pos: 21.5,27.5 - parent: 588 -- proto: WindowDirectional - entities: - - uid: 480 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,15.5 - parent: 588 - - uid: 482 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 27.5,15.5 - parent: 588 - - uid: 540 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 28.5,15.5 - parent: 588 - - uid: 541 - components: - - type: Transform - pos: 26.5,13.5 - parent: 588 - - uid: 542 - components: - - type: Transform - pos: 27.5,13.5 - parent: 588 - - uid: 543 - components: - - type: Transform - pos: 28.5,13.5 - parent: 588 - - uid: 575 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 33.5,20.5 - parent: 588 - - uid: 576 - components: - - type: Transform - pos: 26.5,19.5 - parent: 588 - - uid: 803 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 33.5,21.5 - parent: 588 - - uid: 804 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 33.5,19.5 - parent: 588 - - uid: 1087 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,36.5 - parent: 588 - - uid: 1088 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 27.5,34.5 - parent: 588 - - uid: 1520 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 18.5,46.5 - parent: 588 - - uid: 1521 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 20.5,46.5 - parent: 588 - - uid: 1771 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 28.5,44.5 - parent: 588 - - uid: 1773 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 29.5,44.5 - parent: 588 - - uid: 1777 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 30.5,44.5 - parent: 588 - - uid: 1782 - components: - - type: Transform - pos: 30.5,46.5 - parent: 588 -- proto: WindowFrostedDirectional - entities: - - uid: 936 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,24.5 - parent: 588 - - uid: 937 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 10.5,24.5 - parent: 588 - - uid: 938 - components: - - type: Transform - pos: 8.5,27.5 - parent: 588 - - uid: 939 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 8.5,25.5 - parent: 588 - - uid: 941 - components: - - type: Transform - pos: 10.5,27.5 - parent: 588 - - uid: 942 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 10.5,28.5 - parent: 588 - - uid: 943 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 8.5,28.5 - parent: 588 - - uid: 1392 - components: - - type: Transform - pos: 8.5,44.5 - parent: 588 - - uid: 1393 - components: - - type: Transform - pos: 10.5,44.5 - parent: 588 - - uid: 1401 - components: - - type: Transform - pos: 12.5,44.5 - parent: 588 - - uid: 1402 - components: - - type: Transform - pos: 14.5,44.5 - parent: 588 - - uid: 1753 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.5,43.5 - parent: 588 - - uid: 1754 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 25.5,43.5 - parent: 588 - - uid: 1755 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,43.5 - parent: 588 - - uid: 1756 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 26.5,42.5 - parent: 588 - - uid: 1757 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 26.5,48.5 - parent: 588 - - uid: 1758 - components: - - type: Transform - pos: 26.5,47.5 - parent: 588 - - uid: 1759 - components: - - type: Transform - pos: 25.5,47.5 - parent: 588 - - uid: 1760 - components: - - type: Transform - pos: 24.5,47.5 - parent: 588 -- proto: WindowReinforcedDirectional - entities: - - uid: 97 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,14.5 - parent: 588 - - uid: 99 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 4.5,14.5 - parent: 588 - - uid: 258 - components: - - type: Transform - pos: 3.5,3.5 - parent: 588 - - uid: 259 - components: - - type: Transform - pos: 5.5,3.5 - parent: 588 - - uid: 260 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,3.5 - parent: 588 - - uid: 261 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,4.5 - parent: 588 - - uid: 270 - components: - - type: Transform - pos: 11.5,3.5 - parent: 588 - - uid: 271 - components: - - type: Transform - pos: 13.5,3.5 - parent: 588 - - uid: 272 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 13.5,3.5 - parent: 588 - - uid: 273 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 13.5,4.5 - parent: 588 - - uid: 277 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,4.5 - parent: 588 - - uid: 278 - components: - - type: Transform - pos: 15.5,3.5 - parent: 588 - - uid: 279 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 15.5,4.5 - parent: 588 - - uid: 280 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,3.5 - parent: 588 - - uid: 281 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 15.5,3.5 - parent: 588 - - uid: 290 - components: - - type: Transform - pos: 1.5,3.5 - parent: 588 - - uid: 607 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 3.5,14.5 - parent: 588 - - uid: 609 - components: - - type: Transform - pos: 4.5,14.5 - parent: 588 - - uid: 611 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 4.5,14.5 - parent: 588 - - uid: 612 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 2.5,14.5 - parent: 588 - - uid: 614 - components: - - type: Transform - pos: 3.5,14.5 - parent: 588 - - uid: 619 - components: - - type: Transform - pos: 2.5,14.5 - parent: 588 - - uid: 620 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 3.5,20.5 - parent: 588 - - uid: 624 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,20.5 - parent: 588 - - uid: 625 - components: - - type: Transform - pos: 2.5,19.5 - parent: 588 - - uid: 626 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 2.5,21.5 - parent: 588 - - uid: 648 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 15.5,19.5 - parent: 588 - - uid: 650 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 13.5,18.5 - parent: 588 - - uid: 651 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 13.5,19.5 - parent: 588 - - uid: 652 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 15.5,19.5 - parent: 588 - - uid: 653 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 15.5,18.5 - parent: 588 - - uid: 654 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 13.5,21.5 - parent: 588 - - uid: 658 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 13.5,22.5 - parent: 588 - - uid: 660 - components: - - type: Transform - pos: 13.5,21.5 - parent: 588 - - uid: 805 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,27.5 - parent: 588 - - uid: 806 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,26.5 - parent: 588 - - uid: 807 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,25.5 - parent: 588 - - uid: 808 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,25.5 - parent: 588 - - uid: 809 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 1.5,26.5 - parent: 588 - - uid: 810 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 1.5,27.5 - parent: 588 - - uid: 811 - components: - - type: Transform - pos: 1.5,25.5 - parent: 588 - - uid: 812 - components: - - type: Transform - rot: -1.5707963267948966 rad - pos: 1.5,27.5 - parent: 588 - - uid: 1038 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 22.5,25.5 - parent: 588 - - uid: 1039 - components: - - type: Transform - pos: 20.5,27.5 - parent: 588 - - uid: 1042 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 20.5,25.5 - parent: 588 - - uid: 1045 - components: - - type: Transform - pos: 22.5,27.5 - parent: 588 - - uid: 1058 - components: - - type: Transform - pos: 24.5,27.5 - parent: 588 - - uid: 1059 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 26.5,25.5 - parent: 588 - - uid: 1060 - components: - - type: Transform - rot: 3.141592653589793 rad - pos: 24.5,25.5 - parent: 588 - - uid: 1399 - components: - - type: Transform - pos: 9.5,44.5 - parent: 588 - - uid: 1400 - components: - - type: Transform - pos: 13.5,44.5 - parent: 588 -- proto: Wrench - entities: - - uid: 424 - components: - - type: Transform - pos: 15.156982,32.526764 - parent: 588 -- proto: Zipties - entities: - - uid: 1156 - components: - - type: Transform - pos: 15.332411,0.52492684 - parent: 588 -- proto: ZiptiesBroken - entities: - - uid: 48 - components: - - type: Transform - pos: 5.2591753,3.5817227 - parent: 588 - - uid: 706 - components: - - type: Transform - pos: 16.06022,21.977758 - parent: 588 -... +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 15: FloorBasalt + 29: FloorDark + 33: FloorDarkMini + 34: FloorDarkMono + 42: FloorElevatorShaft + 54: FloorGreenCircuit + 62: FloorLino + 77: FloorReinforced + 82: FloorShuttleOrange + 89: FloorSteel + 99: FloorSteelMini + 100: FloorSteelMono + 104: FloorTechMaint + 108: FloorWhite + 112: FloorWhiteMini + 118: FloorWood + 121: Plating +entities: +- proto: "" + entities: + - uid: 588 + components: + - type: MetaData + - type: Transform + - type: Map + - type: PhysicsMap + - type: Broadphase + - type: OccluderTree + - type: MapGrid + chunks: + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA + version: 6 + 0,0: + ind: 0,0 + tiles: WQAAAAADWQAAAAABWQAAAAACWQAAAAADWQAAAAACWQAAAAABeQAAAAAADwAAAAAAHQAAAAABDwAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAADWQAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAACWQAAAAAAWQAAAAADWQAAAAADWQAAAAABWQAAAAADWQAAAAACWQAAAAABIgAAAAABHQAAAAABDwAAAAAAHQAAAAACIgAAAAAAWQAAAAABWQAAAAACWQAAAAABWQAAAAADWQAAAAADaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAADwAAAAAAHQAAAAACDwAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAABHQAAAAABHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAABHQAAAAADHQAAAAABUgAAAAAAZAAAAAACWQAAAAAAZAAAAAACeQAAAAAAHQAAAAAAIgAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAACHQAAAAACUgAAAAAAYwAAAAACYwAAAAAAYwAAAAAAeQAAAAAAHQAAAAABIgAAAAACeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAABHQAAAAADUgAAAAAAYwAAAAACYwAAAAAAYwAAAAAAWQAAAAACHQAAAAAAIgAAAAADeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAAAHQAAAAABUgAAAAAAYwAAAAADYwAAAAABYwAAAAABeQAAAAAAHQAAAAADHQAAAAADHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAABHQAAAAABHQAAAAAAUgAAAAAAZAAAAAABWQAAAAABZAAAAAACeQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAABeQAAAAAAHQAAAAADeQAAAAAAHQAAAAADHQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAADdgAAAAABdgAAAAADdgAAAAAAdgAAAAADUgAAAAAAHQAAAAABHQAAAAACHQAAAAACHQAAAAADHQAAAAADHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAABdgAAAAACdgAAAAAAdgAAAAACdgAAAAACUgAAAAAAHQAAAAADHQAAAAACDwAAAAAADwAAAAAADwAAAAAAHQAAAAACHQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAdgAAAAACdgAAAAADdgAAAAADdgAAAAACdgAAAAADUgAAAAAAHQAAAAADHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAADHQAAAAABUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAdgAAAAABUgAAAAAA + version: 6 + 0,1: + ind: 0,1 + tiles: HQAAAAAAHQAAAAADeQAAAAAAHQAAAAACeQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAdgAAAAACUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAADHQAAAAAAHQAAAAADHQAAAAADHQAAAAABUgAAAAAAWQAAAAAAWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAWQAAAAABaAAAAAAAHQAAAAACeQAAAAAADwAAAAAAeQAAAAAAHQAAAAACUgAAAAAAWQAAAAADYwAAAAAAYwAAAAABYwAAAAADWQAAAAABUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAHQAAAAABDwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABYwAAAAACYwAAAAACWQAAAAADUgAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAAAHQAAAAAAeQAAAAAADwAAAAAAeQAAAAAAHQAAAAAAUgAAAAAAWQAAAAABYwAAAAABYwAAAAABYwAAAAABWQAAAAADUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAWQAAAAABHQAAAAADHQAAAAABHQAAAAACHQAAAAAAHQAAAAABUgAAAAAAWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACWQAAAAABUgAAAAAAaAAAAAAAaAAAAAAAWQAAAAABWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAcAAAAAACcAAAAAACcAAAAAABUgAAAAAAWQAAAAADWQAAAAADZAAAAAAAUgAAAAAAHQAAAAAADwAAAAAAHQAAAAACUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAACcAAAAAADUgAAAAAAWQAAAAAAWQAAAAABZAAAAAABUgAAAAAAHQAAAAACDwAAAAAAHQAAAAAAUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAAAcAAAAAAAUgAAAAAAWQAAAAABWQAAAAABWQAAAAABUgAAAAAAHQAAAAACDwAAAAAAHQAAAAABUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAcAAAAAADcAAAAAADcAAAAAABUgAAAAAAZAAAAAACWQAAAAABWQAAAAACUgAAAAAAHQAAAAADHQAAAAACHQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAcAAAAAACcAAAAAACcAAAAAADUgAAAAAAZAAAAAACWQAAAAAAWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAAHQAAAAABDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAACUgAAAAAAWQAAAAABWQAAAAACHQAAAAACHQAAAAABHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA + version: 6 + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA + version: 6 + -1,1: + ind: -1,1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA + version: 6 + 1,-1: + ind: 1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA + version: 6 + 1,0: + ind: 1,0 + tiles: WQAAAAABUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAACHQAAAAAAHQAAAAABHQAAAAADHQAAAAABHQAAAAADHQAAAAADHQAAAAACHQAAAAADWQAAAAADUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAAAHQAAAAADHQAAAAABHQAAAAACHQAAAAABHQAAAAADHQAAAAACHQAAAAABHQAAAAABWQAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAIgAAAAACHQAAAAACHQAAAAACHQAAAAACHQAAAAABHQAAAAACHQAAAAACHQAAAAAAHQAAAAAAHQAAAAABaAAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAADHQAAAAAAHQAAAAACHQAAAAAAHQAAAAADHQAAAAADHQAAAAADHQAAAAAAHQAAAAABaAAAAAAAUgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAPgAAAAAAeQAAAAAAHQAAAAABHQAAAAABHQAAAAACHQAAAAAAHQAAAAABHQAAAAACHQAAAAAAHQAAAAACHQAAAAADUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAABWQAAAAACWQAAAAACeQAAAAAAZAAAAAAAWQAAAAABZAAAAAAAUgAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAWQAAAAAAWQAAAAABWQAAAAAAeQAAAAAAYwAAAAAAYwAAAAAAYwAAAAABUgAAAAAATQAAAAAAeQAAAAAAIgAAAAACeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACWQAAAAACWQAAAAAAWQAAAAADYwAAAAADYwAAAAAAYwAAAAADUgAAAAAATQAAAAAAeQAAAAAAKgAAAAAAeQAAAAAAKgAAAAAAKgAAAAAAKgAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAABeQAAAAAAYwAAAAACYwAAAAABYwAAAAADUgAAAAAATQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAIgAAAAABeQAAAAAAeQAAAAAAWQAAAAADWQAAAAAAWQAAAAAAeQAAAAAAZAAAAAADWQAAAAABZAAAAAACUgAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAADWQAAAAACWQAAAAACWQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAABYwAAAAACYwAAAAACYwAAAAAAYwAAAAADYwAAAAACWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABYwAAAAADYwAAAAABYwAAAAACYwAAAAAAWQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAADaAAAAAAAUgAAAAAAWQAAAAACYwAAAAABYwAAAAABYwAAAAADYwAAAAAAYwAAAAABWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAeQAAAAAAUgAAAAAA + version: 6 + 1,1: + ind: 1,1 + tiles: WQAAAAABWQAAAAACWQAAAAACWQAAAAAAWQAAAAABWQAAAAAAWQAAAAACUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAABWQAAAAABWQAAAAAAWQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAACWQAAAAACaAAAAAAAUgAAAAAAWQAAAAADYwAAAAACYwAAAAABYwAAAAAAWQAAAAABUgAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAUgAAAAAAWQAAAAADYwAAAAADWQAAAAACUgAAAAAAWQAAAAADYwAAAAADYwAAAAADYwAAAAADWQAAAAABUgAAAAAAeQAAAAAAWQAAAAABeQAAAAAAWQAAAAABeQAAAAAAUgAAAAAAWQAAAAAAYwAAAAABWQAAAAADUgAAAAAAWQAAAAAAYwAAAAAAYwAAAAACYwAAAAACWQAAAAADUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAADYwAAAAADWQAAAAACUgAAAAAAWQAAAAACWQAAAAACWQAAAAADWQAAAAADWQAAAAACUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAACWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAADWQAAAAABWQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAWQAAAAABWQAAAAACZAAAAAACUgAAAAAAWQAAAAABWQAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAADZAAAAAABUgAAAAAAWQAAAAACWQAAAAAAWQAAAAACUgAAAAAAWQAAAAACWQAAAAAAWQAAAAACUgAAAAAAWQAAAAADWQAAAAAAWQAAAAADUgAAAAAAWQAAAAADWQAAAAACWQAAAAADUgAAAAAAZAAAAAADWQAAAAACZAAAAAADUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAZAAAAAAAWQAAAAADWQAAAAACUgAAAAAAZAAAAAABWQAAAAABZAAAAAABUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAZAAAAAADWQAAAAADWQAAAAABUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAAAWQAAAAACWQAAAAABWQAAAAADWQAAAAACWQAAAAAAWQAAAAACWQAAAAAAWQAAAAACWQAAAAACWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAA + version: 6 + -1,2: + ind: -1,2 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAA + version: 6 + -1,3: + ind: -1,3 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,2: + ind: 0,2 + tiles: HQAAAAACHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADHQAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAADaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAABUgAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAAUgAAAAAAHQAAAAAATQAAAAAANgAAAAAANgAAAAAANgAAAAAATQAAAAAAHQAAAAAAUgAAAAAAHQAAAAACDwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAACUgAAAAAAHQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAHQAAAAACUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAADwAAAAAADwAAAAAAeQAAAAAAIgAAAAABeQAAAAAADwAAAAAADwAAAAAAUgAAAAAAbAAAAAACbAAAAAAAbAAAAAAAbAAAAAAAbAAAAAADbAAAAAABbAAAAAABUgAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAAADwAAAAAADwAAAAAADwAAAAAAUgAAAAAAbAAAAAABbAAAAAABeQAAAAAAbAAAAAAAeQAAAAAAbAAAAAABbAAAAAADUgAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAUgAAAAAAIgAAAAABIgAAAAABIgAAAAACaAAAAAAAIgAAAAADIgAAAAACIgAAAAABUgAAAAAAIgAAAAAAHQAAAAACDwAAAAAADwAAAAAADwAAAAAAHQAAAAAAIgAAAAABUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAeQAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAADwAAAAAAeQAAAAAAUgAAAAAAIgAAAAACIgAAAAAAIgAAAAABaAAAAAAAIgAAAAABIgAAAAACIgAAAAAAUgAAAAAADwAAAAAADwAAAAAADwAAAAAAHQAAAAADDwAAAAAADwAAAAAADwAAAAAAUgAAAAAAIgAAAAAAIgAAAAAAIgAAAAACaAAAAAAAIgAAAAAAIgAAAAACIgAAAAADUgAAAAAA + version: 6 + 0,3: + ind: 0,3 + tiles: DwAAAAAADwAAAAAAeQAAAAAAIgAAAAAAeQAAAAAADwAAAAAADwAAAAAAUgAAAAAAIgAAAAACIgAAAAAAIgAAAAAAaAAAAAAAIgAAAAABIgAAAAACIgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 1,2: + ind: 1,2 + tiles: aAAAAAAAaAAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAYwAAAAACYwAAAAADYwAAAAABeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAACHQAAAAADHQAAAAACTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAYwAAAAACYwAAAAAAYwAAAAABWQAAAAACaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAACHQAAAAABHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAYwAAAAADYwAAAAADYwAAAAADeQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAHQAAAAADHQAAAAABHQAAAAABTQAAAAAATQAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAWQAAAAACWQAAAAAAWQAAAAAAWQAAAAABWQAAAAADWQAAAAADWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAACYwAAAAABYwAAAAACYwAAAAABYwAAAAADYwAAAAAAWQAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAAAWQAAAAABWQAAAAABWQAAAAACWQAAAAAAWQAAAAAAWQAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAaAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAACYwAAAAAAYwAAAAADYwAAAAADUgAAAAAAaAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAADYwAAAAABYwAAAAABYwAAAAACUgAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAWQAAAAACWQAAAAADWQAAAAABWQAAAAACYwAAAAADYwAAAAABYwAAAAACUgAAAAAAaAAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAACaAAAAAAAUgAAAAAAWQAAAAADWQAAAAADWQAAAAACWQAAAAADWQAAAAACWQAAAAADWQAAAAADUgAAAAAAaAAAAAAAWQAAAAABaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAAAaAAAAAAAUgAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAACIQAAAAABIQAAAAADWQAAAAACUgAAAAAAaAAAAAAAWQAAAAADeQAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAABIQAAAAAAIQAAAAABWQAAAAABUgAAAAAA + version: 6 + 1,3: + ind: 1,3 + tiles: aAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAUgAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAWQAAAAABWQAAAAAAWQAAAAAAWQAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 2,-1: + ind: 2,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 2,0: + ind: 2,0 + tiles: HQAAAAAAHQAAAAABWQAAAAACUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAACWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAACWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAADWQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAACHQAAAAAAWQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAADeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAKgAAAAAAeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAATQAAAAAATQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 2,1: + ind: 2,1 + tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAABWQAAAAACWQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAAAYwAAAAABWQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAADYwAAAAABWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYwAAAAABYwAAAAAAWQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAACWQAAAAABWQAAAAACUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAACHQAAAAAAIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAACHQAAAAACIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAABHQAAAAADHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAABIgAAAAACIgAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAADHQAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 2,2: + ind: 2,2 + tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAAHQAAAAADHQAAAAABUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIgAAAAABeQAAAAAAHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAATQAAAAAAHQAAAAAAHQAAAAADUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 2,3: + ind: 2,3 + tiles: UgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAUgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: + - node: + color: '#52B4E996' + id: BotGreyscale + decals: + 680: 30,25 + 681: 30,24 + 682: 28,27 + 683: 28,27 + 684: 28,28 + 685: 28,28 + 686: 30,25 + 687: 30,24 + - node: + color: '#DE3A3A96' + id: BotGreyscale + decals: + 478: 32,25 + 479: 32,24 + 480: 34,25 + 481: 34,24 + 482: 16,28 + 483: 18,28 + 484: 18,27 + 485: 16,27 + 486: 14,25 + 487: 14,24 + 488: 12,27 + 489: 12,28 + 748: 26,7 + 749: 32,7 + 750: 29,9 + 836: 6,2 + 837: 10,2 + 940: 1,9 + 941: 1,8 + 942: 1,7 + 943: 9,9 + 944: 9,8 + 945: 9,7 + 946: 20,10 + 947: 14,10 + 948: 14,6 + 949: 20,6 + 950: 22,6 + 951: 22,10 + 952: 12,10 + 953: 12,6 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkCornerNe + decals: + 194: 21,4 + 250: 10,44 + 525: 12,32 + 543: 4,22 + 585: 6,40 + 659: 34,36 + 675: 30,28 + 703: 6,16 + 757: 10,10 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkCornerNw + decals: + 191: 18,4 + 251: 12,44 + 519: 0,32 + 542: 0,22 + 582: 0,40 + 633: 24,36 + 702: 0,16 + 754: 0,10 + 853: 23,4 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkCornerSe + decals: + 192: 21,0 + 238: 10,46 + 272: 14,42 + 524: 12,30 + 537: 4,18 + 584: 6,38 + 658: 34,34 + 701: 6,12 + 755: 10,6 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkCornerSw + decals: + 193: 18,0 + 241: 12,46 + 270: 8,42 + 518: 0,30 + 534: 0,18 + 583: 0,38 + 632: 24,34 + 672: 28,24 + 700: 0,12 + 756: 0,6 + 852: 23,0 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkLineE + decals: + 202: 21,1 + 203: 21,2 + 204: 21,3 + 239: 10,47 + 240: 10,48 + 273: 14,43 + 501: 0,25 + 502: 0,26 + 503: 0,27 + 535: 4,19 + 536: 4,21 + 592: 14,38 + 593: 14,40 + 674: 30,27 + 706: 6,15 + 707: 6,13 + 758: 10,9 + 759: 10,7 + 926: 5,45 + 929: 33,36 + 930: 33,34 + 931: 10,31 + 935: 8,10 + 936: 8,6 + 937: 7,2 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkLineN + decals: + 197: 19,4 + 198: 20,4 + 248: 8,44 + 249: 9,44 + 252: 13,44 + 253: 14,44 + 506: 0,28 + 507: 2,28 + 520: 1,32 + 523: 11,32 + 540: 1,22 + 541: 3,22 + 634: 25,36 + 635: 26,36 + 704: 1,16 + 705: 5,16 + 762: 1,10 + 765: 9,10 + 846: 24,4 + 847: 25,4 + 848: 27,4 + 849: 28,4 + 850: 29,4 + 851: 30,4 + 927: 3,47 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkLineS + decals: + 195: 20,0 + 196: 19,0 + 244: 8,46 + 245: 9,46 + 246: 13,46 + 247: 14,46 + 274: 9,42 + 275: 10,42 + 276: 13,42 + 277: 12,42 + 504: 0,24 + 505: 2,24 + 521: 1,30 + 522: 11,30 + 538: 3,18 + 539: 1,18 + 636: 25,34 + 637: 26,34 + 710: 1,12 + 711: 5,12 + 763: 1,6 + 764: 9,6 + 840: 25,0 + 841: 24,0 + 842: 27,0 + 843: 28,0 + 844: 29,0 + 845: 30,0 + 928: 3,43 + - node: + color: '#FFFFFFFF' + id: BrickTileDarkLineW + decals: + 199: 18,3 + 200: 18,2 + 201: 18,1 + 242: 12,47 + 243: 12,48 + 271: 8,43 + 498: 2,27 + 499: 2,26 + 500: 2,25 + 544: 0,19 + 545: 0,21 + 590: 8,40 + 591: 8,38 + 673: 28,25 + 708: 0,13 + 709: 0,15 + 760: 0,7 + 761: 0,9 + 854: 23,3 + 855: 23,1 + 925: 1,45 + 932: 2,31 + 933: 2,10 + 934: 2,6 + 938: 9,2 + 939: 30,2 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelCornerNe + decals: + 84: 18,36 + 104: 16,25 + 336: 9,21 + 337: 10,22 + 364: 16,22 + 374: 21,15 + 375: 22,16 + 415: 21,21 + 421: 22,22 + 446: 33,21 + 447: 34,22 + 490: 12,25 + 554: 22,9 + 568: 14,9 + 610: 22,40 + 2025: 30,48 + 2039: 30,44 + 2058: 29,47 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelCornerNw + decals: + 85: 16,36 + 103: 18,25 + 338: 7,21 + 339: 6,22 + 376: 17,15 + 377: 16,16 + 414: 19,21 + 420: 18,22 + 448: 31,21 + 449: 30,22 + 555: 20,9 + 569: 12,9 + 611: 16,40 + 2040: 28,44 + 2059: 28,47 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelCornerSe + decals: + 83: 18,34 + 308: 26,30 + 332: 9,19 + 335: 10,18 + 372: 21,13 + 373: 22,12 + 418: 21,19 + 419: 22,18 + 452: 33,19 + 453: 34,18 + 561: 22,7 + 562: 14,7 + 609: 22,38 + 778: 16,0 + 779: 5,0 + 2038: 30,42 + 2056: 29,46 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelCornerSw + decals: + 81: 16,34 + 82: 3,35 + 309: 14,30 + 333: 7,19 + 334: 6,18 + 370: 17,13 + 371: 16,12 + 416: 18,18 + 417: 19,19 + 450: 31,19 + 451: 30,18 + 493: 14,27 + 558: 20,7 + 567: 12,7 + 608: 16,38 + 780: 0,0 + 781: 11,0 + 2037: 28,42 + 2057: 28,46 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelEndE + decals: + 73: 21,39 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelEndW + decals: + 74: 17,39 + - node: + color: '#D4D4D496' + id: BrickTileSteelLineE + decals: + 1330: 32,2 + 1332: 31,2 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelLineE + decals: + 87: 18,35 + 93: 14,34 + 94: 14,35 + 95: 14,36 + 105: 16,24 + 286: 17,45 + 287: 17,46 + 288: 17,47 + 323: 27,20 + 349: 9,20 + 350: 10,21 + 351: 10,19 + 365: 16,21 + 378: 21,14 + 379: 22,13 + 380: 22,15 + 425: 21,20 + 426: 22,19 + 427: 22,21 + 454: 34,19 + 455: 34,21 + 462: 33,20 + 491: 12,24 + 559: 22,8 + 566: 14,8 + 802: 16,1 + 806: 5,1 + 872: 34,0 + 873: 34,1 + 874: 34,3 + 875: 34,4 + 1328: 33,2 + 2023: 30,46 + 2024: 30,47 + 2041: 30,43 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelLineN + decals: + 75: 18,39 + 76: 19,39 + 77: 20,39 + 86: 17,36 + 340: 8,21 + 341: 9,22 + 342: 7,22 + 366: 15,22 + 391: 18,15 + 392: 19,15 + 393: 20,15 + 394: 21,16 + 395: 20,16 + 396: 18,16 + 397: 17,16 + 422: 20,21 + 423: 19,22 + 424: 21,22 + 458: 31,22 + 459: 33,22 + 460: 32,21 + 556: 21,9 + 564: 13,9 + 572: 16,10 + 573: 18,10 + 612: 17,40 + 613: 18,40 + 614: 21,40 + 615: 20,40 + 2026: 29,48 + 2027: 28,48 + 2044: 29,44 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelLineS + decals: + 78: 18,39 + 79: 19,39 + 80: 20,39 + 89: 17,34 + 298: 15,30 + 299: 16,30 + 300: 17,30 + 301: 18,30 + 302: 19,30 + 303: 21,30 + 304: 22,30 + 305: 23,30 + 306: 24,30 + 307: 25,30 + 346: 8,19 + 347: 7,18 + 348: 9,18 + 384: 18,13 + 385: 19,13 + 386: 20,13 + 387: 20,12 + 388: 21,12 + 389: 18,12 + 390: 17,12 + 431: 20,19 + 432: 19,18 + 433: 21,18 + 463: 32,19 + 464: 31,18 + 465: 33,18 + 557: 21,7 + 563: 13,7 + 570: 16,6 + 571: 18,6 + 616: 17,38 + 617: 18,38 + 618: 21,38 + 619: 20,38 + 782: 1,0 + 783: 2,0 + 784: 3,0 + 785: 4,0 + 786: 0,3 + 787: 1,3 + 788: 2,3 + 789: 3,3 + 790: 4,3 + 791: 5,3 + 792: 12,0 + 793: 13,0 + 794: 14,0 + 795: 15,0 + 796: 11,3 + 797: 12,3 + 798: 13,3 + 799: 14,3 + 800: 15,3 + 801: 16,3 + 2043: 29,42 + - node: + color: '#D4D4D496' + id: BrickTileSteelLineW + decals: + 1329: 33,2 + 1331: 32,2 + 1333: 31,2 + - node: + color: '#FFFFFFFF' + id: BrickTileSteelLineW + decals: + 88: 16,35 + 90: 20,34 + 91: 20,35 + 92: 20,36 + 102: 18,24 + 289: 21,45 + 290: 21,46 + 291: 21,47 + 322: 25,20 + 326: 29,15 + 327: 29,14 + 328: 29,13 + 343: 7,20 + 344: 6,21 + 345: 6,19 + 381: 17,14 + 382: 16,15 + 383: 16,13 + 428: 19,20 + 429: 18,19 + 430: 18,21 + 456: 30,19 + 457: 30,21 + 461: 31,20 + 492: 14,28 + 560: 20,8 + 565: 12,8 + 803: 0,1 + 805: 11,1 + 2021: 24,44 + 2022: 24,46 + 2042: 28,43 + - node: + color: '#52B4E996' + id: BrickTileWhiteCornerNe + decals: + 264: 10,44 + 679: 30,28 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteCornerNe + decals: + 109: 16,25 + 362: 10,22 + 367: 16,22 + 413: 22,16 + 438: 22,22 + 475: 34,22 + 494: 12,25 + 527: 12,32 + 580: 4,22 + 587: 6,40 + 630: 22,40 + 660: 34,36 + 715: 6,16 + 777: 10,10 + 2045: 30,48 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteCornerNe + decals: + 689: 10,28 + - node: + color: '#52B4E996' + id: BrickTileWhiteCornerNw + decals: + 265: 12,44 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteCornerNw + decals: + 108: 18,25 + 363: 6,22 + 412: 16,16 + 442: 18,22 + 476: 30,22 + 532: 0,32 + 579: 0,22 + 588: 0,40 + 629: 16,40 + 639: 24,36 + 714: 0,16 + 772: 0,10 + 858: 23,4 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteCornerNw + decals: + 688: 8,28 + - node: + color: '#52B4E996' + id: BrickTileWhiteCornerSe + decals: + 263: 10,46 + 279: 14,42 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteCornerSe + decals: + 361: 10,18 + 411: 22,12 + 443: 22,18 + 477: 34,18 + 526: 12,30 + 581: 4,18 + 586: 6,38 + 628: 22,38 + 661: 34,34 + 713: 6,12 + 771: 10,6 + 809: 5,0 + 810: 16,0 + - node: + color: '#EFB34196' + id: BrickTileWhiteCornerSe + decals: + 311: 26,30 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteCornerSe + decals: + 690: 10,24 + - node: + color: '#52B4E996' + id: BrickTileWhiteCornerSw + decals: + 262: 12,46 + 278: 8,42 + 676: 28,24 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteCornerSw + decals: + 360: 6,18 + 406: 16,12 + 439: 18,18 + 474: 30,18 + 496: 14,27 + 533: 0,30 + 578: 0,18 + 589: 0,38 + 631: 16,38 + 638: 24,34 + 712: 0,12 + 770: 0,6 + 807: 0,0 + 808: 11,0 + 859: 23,0 + - node: + color: '#EFB34196' + id: BrickTileWhiteCornerSw + decals: + 310: 14,30 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteCornerSw + decals: + 691: 8,24 + - node: + color: '#52B4E996' + id: BrickTileWhiteLineE + decals: + 258: 10,47 + 259: 10,48 + 280: 14,43 + 678: 30,27 + - node: + color: '#D4D4D419' + id: BrickTileWhiteLineE + decals: + 895: 2,6 + 896: 2,10 + 900: 9,2 + 901: 30,2 + 906: 1,45 + 908: 2,31 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteLineE + decals: + 96: 14,36 + 97: 14,35 + 98: 14,34 + 106: 16,24 + 356: 10,19 + 357: 10,21 + 368: 16,21 + 409: 22,15 + 410: 22,13 + 444: 22,19 + 445: 22,21 + 470: 34,21 + 471: 34,19 + 495: 12,24 + 511: 0,25 + 512: 0,26 + 513: 0,27 + 548: 4,19 + 549: 4,21 + 596: 14,38 + 597: 14,40 + 716: 6,15 + 717: 6,13 + 768: 10,9 + 769: 10,7 + 811: 5,1 + 812: 16,1 + 876: 34,0 + 877: 34,1 + 878: 34,3 + 879: 34,4 + 2048: 30,47 + 2049: 30,46 + - node: + color: '#EFB34196' + id: BrickTileWhiteLineE + decals: + 292: 17,45 + 293: 17,46 + 294: 17,47 + 324: 27,20 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteLineE + decals: + 693: 10,27 + 694: 10,26 + 695: 10,25 + - node: + color: '#52B4E996' + id: BrickTileWhiteLineN + decals: + 266: 9,44 + 267: 8,44 + 268: 13,44 + 269: 14,44 + - node: + color: '#D4D4D419' + id: BrickTileWhiteLineN + decals: + 907: 3,43 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteLineN + decals: + 358: 9,22 + 359: 7,22 + 369: 15,22 + 398: 18,16 + 399: 17,16 + 400: 21,16 + 401: 20,16 + 436: 19,22 + 437: 21,22 + 468: 31,22 + 469: 33,22 + 516: 0,28 + 517: 2,28 + 528: 11,32 + 531: 1,32 + 552: 1,22 + 553: 3,22 + 574: 16,10 + 575: 18,10 + 620: 18,40 + 621: 17,40 + 622: 20,40 + 623: 21,40 + 642: 25,36 + 643: 26,36 + 722: 1,16 + 723: 5,16 + 773: 1,10 + 774: 9,10 + 866: 24,4 + 867: 25,4 + 868: 27,4 + 869: 28,4 + 870: 30,4 + 871: 29,4 + 2046: 28,48 + 2047: 29,48 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteLineN + decals: + 692: 9,28 + - node: + color: '#52B4E996' + id: BrickTileWhiteLineS + decals: + 254: 8,46 + 255: 9,46 + 256: 13,46 + 257: 14,46 + 282: 9,42 + 283: 10,42 + 284: 12,42 + 285: 13,42 + - node: + color: '#D4D4D419' + id: BrickTileWhiteLineS + decals: + 905: 3,47 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteLineS + decals: + 352: 7,18 + 353: 9,18 + 402: 17,12 + 403: 18,12 + 404: 20,12 + 405: 21,12 + 434: 19,18 + 435: 21,18 + 466: 33,18 + 467: 31,18 + 514: 0,24 + 515: 2,24 + 529: 11,30 + 530: 1,30 + 550: 1,18 + 551: 3,18 + 576: 16,6 + 577: 18,6 + 624: 17,38 + 625: 18,38 + 626: 20,38 + 627: 21,38 + 640: 25,34 + 641: 26,34 + 718: 5,12 + 719: 1,12 + 775: 1,6 + 776: 9,6 + 813: 12,0 + 814: 13,0 + 815: 14,0 + 816: 15,0 + 817: 16,3 + 818: 15,3 + 819: 13,3 + 820: 14,3 + 821: 11,3 + 822: 12,3 + 823: 0,3 + 824: 1,3 + 825: 2,3 + 826: 3,3 + 827: 4,3 + 828: 5,3 + 829: 4,0 + 830: 3,0 + 831: 2,0 + 832: 1,0 + 860: 24,0 + 861: 25,0 + 862: 27,0 + 863: 28,0 + 864: 29,0 + 865: 30,0 + - node: + color: '#EFB34196' + id: BrickTileWhiteLineS + decals: + 312: 15,30 + 313: 16,30 + 314: 17,30 + 315: 18,30 + 316: 19,30 + 317: 21,30 + 318: 22,30 + 319: 23,30 + 320: 24,30 + 321: 25,30 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteLineS + decals: + 696: 9,24 + - node: + color: '#52B4E996' + id: BrickTileWhiteLineW + decals: + 260: 12,47 + 261: 12,48 + 281: 8,43 + 677: 28,25 + - node: + color: '#D4D4D419' + id: BrickTileWhiteLineW + decals: + 897: 8,10 + 898: 8,6 + 899: 7,2 + 902: 33,36 + 903: 33,34 + 904: 5,45 + 909: 10,31 + - node: + color: '#DE3A3A96' + id: BrickTileWhiteLineW + decals: + 99: 20,36 + 100: 20,35 + 101: 20,34 + 107: 18,24 + 354: 6,19 + 355: 6,21 + 407: 16,13 + 408: 16,15 + 440: 18,19 + 441: 18,21 + 472: 30,19 + 473: 30,21 + 497: 14,28 + 508: 2,25 + 509: 2,26 + 510: 2,27 + 546: 0,19 + 547: 0,21 + 594: 8,38 + 595: 8,40 + 720: 0,13 + 721: 0,15 + 766: 0,7 + 767: 0,9 + 804: 0,1 + 833: 11,1 + 856: 23,1 + 857: 23,3 + 2050: 24,44 + 2051: 24,46 + - node: + color: '#EFB34196' + id: BrickTileWhiteLineW + decals: + 295: 21,45 + 296: 21,46 + 297: 21,47 + 325: 25,20 + 329: 29,13 + 330: 29,14 + 331: 29,15 + - node: + color: '#FFFFFFFF' + id: BrickTileWhiteLineW + decals: + 697: 8,25 + 698: 8,26 + 699: 8,27 + - node: + cleanable: True + angle: 1.5707963267948966 rad + color: '#B02E269B' + id: Clandestine + decals: + 2136: 3.132535,34.09553 + - node: + color: '#A4610696' + id: Dirt + decals: + 1334: 31,2 + 1335: 32,2 + 1336: 33,2 + 1337: 30,2 + 1338: 34,2 + 1339: 33,3 + 1340: 31,4 + 1341: 32,3 + 1342: 32,1 + 1343: 31,1 + 1344: 31,0 + 1345: 33,0 + 1346: 32,0 + 1347: 33,3 + 1348: 33,4 + 1349: 32,4 + 1350: 31,3 + 1351: 32,1 + 1352: 33,1 + - node: + cleanable: True + color: '#A4610696' + id: Dirt + decals: + 954: 0,45 + 955: 3,47 + 956: 3,48 + 957: 6,45 + 958: 3,42 + 959: 3,43 + 960: 5,45 + 961: 1,45 + 962: 13,45 + 963: 12,45 + 964: 11,47 + 965: 9,45 + 966: 8,45 + 967: 8,46 + 968: 10,47 + 969: 13,47 + 970: 14,46 + 971: 11,43 + 972: 11,42 + 973: 9,42 + 974: 10,42 + 975: 13,42 + 976: 12,42 + 977: 13,43 + 978: 9,43 + 979: 11,44 + 980: 11,45 + 981: 11,47 + 982: 9,46 + 983: 11,46 + 984: 16,45 + 985: 16,46 + 986: 16,47 + 987: 16,44 + 988: 17,45 + 989: 17,46 + 990: 21,45 + 991: 22,45 + 992: 22,44 + 993: 22,43 + 994: 22,46 + 995: 21,45 + 996: 21,46 + 997: 22,47 + 998: 24,39 + 999: 24,38 + 1000: 24,40 + 1001: 27,39 + 1002: 27,39 + 1003: 30,40 + 1004: 30,39 + 1005: 30,38 + 1006: 30,39 + 1007: 34,35 + 1008: 33,34 + 1009: 33,36 + 1010: 24,35 + 1011: 22,35 + 1012: 20,35 + 1013: 21,35 + 1014: 20,34 + 1015: 14,35 + 1016: 13,35 + 1017: 12,35 + 1018: 14,36 + 1019: 17,36 + 1020: 17,35 + 1021: 17,34 + 1022: 16,35 + 1023: 18,35 + 1024: 18,36 + 1025: 18,34 + 1026: 16,34 + 1027: 16,36 + 1028: 16,30 + 1029: 16,30 + 1030: 18,30 + 1031: 19,30 + 1032: 22,30 + 1033: 24,30 + 1034: 25,30 + 1035: 26,30 + 1036: 20,30 + 1037: 20,30 + 1038: 15,30 + 1039: 14,30 + 1040: 14,31 + 1041: 26,31 + 1042: 10,31 + 1043: 2,31 + 1044: 0,31 + 1045: 12,31 + 1046: 5,35 + 1047: 6,36 + 1048: 4,34 + 1049: 9,35 + 1050: 9,35 + 1051: 10,35 + 1052: 10,34 + 1053: 0,35 + 1054: 0,36 + 1055: 0,35 + 1056: 5,36 + 1057: 6,36 + 1058: 6,39 + 1059: 0,39 + 1060: 8,39 + 1061: 8,40 + 1062: 8,38 + 1063: 9,39 + 1064: 11,38 + 1065: 9,38 + 1066: 11,40 + 1067: 10,40 + 1068: 13,39 + 1069: 14,39 + 1070: 14,40 + 1071: 14,38 + 1072: 13,39 + 1073: 13,40 + 1074: 16,39 + 1075: 18,40 + 1076: 19,40 + 1077: 19,39 + 1078: 18,39 + 1079: 17,39 + 1080: 20,39 + 1081: 21,39 + 1082: 19,38 + 1083: 22,39 + 1084: 21,38 + 1085: 24,39 + 1086: 24,38 + 1087: 24,40 + 1088: 17,32 + 1089: 24,32 + 1090: 23,32 + 1091: 34,26 + 1092: 33,26 + 1093: 33,28 + 1094: 32,28 + 1095: 32,27 + 1096: 34,27 + 1097: 34,28 + 1098: 32,25 + 1099: 33,24 + 1100: 33,25 + 1101: 32,26 + 1102: 29,24 + 1103: 30,26 + 1104: 28,26 + 1105: 29,28 + 1106: 29,27 + 1107: 29,25 + 1108: 25,26 + 1109: 24,26 + 1110: 26,26 + 1111: 25,27 + 1112: 24,28 + 1113: 25,28 + 1114: 24,27 + 1115: 24,24 + 1116: 25,25 + 1117: 25,24 + 1118: 26,25 + 1119: 22,26 + 1120: 24,26 + 1121: 26,26 + 1122: 20,26 + 1123: 21,25 + 1124: 21,24 + 1125: 21,28 + 1126: 21,27 + 1127: 18,26 + 1128: 16,26 + 1129: 17,27 + 1130: 17,28 + 1131: 17,25 + 1132: 17,24 + 1133: 17,26 + 1134: 13,28 + 1135: 13,27 + 1136: 13,26 + 1137: 13,25 + 1138: 13,24 + 1139: 12,26 + 1140: 14,26 + 1141: 9,26 + 1142: 9,27 + 1143: 9,28 + 1144: 8,28 + 1145: 8,27 + 1146: 8,26 + 1147: 9,25 + 1148: 8,25 + 1149: 8,24 + 1150: 9,24 + 1151: 10,24 + 1152: 10,25 + 1153: 10,26 + 1154: 10,27 + 1155: 10,28 + 1156: 5,28 + 1157: 5,28 + 1158: 5,24 + 1159: 5,24 + 1160: 0,26 + 1161: 2,26 + 1162: 2,28 + 1163: 1,24 + 1164: 2,24 + 1165: 2,22 + 1166: 4,20 + 1167: 2,18 + 1168: 1,19 + 1169: 0,20 + 1170: 0,17 + 1171: 0,18 + 1172: 4,18 + 1173: 4,19 + 1174: 4,22 + 1175: 0,22 + 1176: 6,20 + 1177: 7,20 + 1178: 8,20 + 1179: 9,20 + 1180: 10,20 + 1181: 8,21 + 1182: 8,22 + 1183: 8,19 + 1184: 8,18 + 1185: 6,18 + 1186: 7,19 + 1187: 7,18 + 1188: 9,20 + 1189: 10,21 + 1190: 9,21 + 1191: 9,22 + 1192: 9,19 + 1193: 7,21 + 1194: 8,13 + 1195: 8,13 + 1196: 11,16 + 1197: 11,16 + 1198: 10,16 + 1199: 9,16 + 1200: 8,15 + 1201: 8,14 + 1202: 8,16 + 1203: 10,16 + 1204: 9,16 + 1205: 12,14 + 1206: 11,14 + 1207: 11,12 + 1208: 10,12 + 1209: 14,12 + 1210: 14,14 + 1211: 14,15 + 1212: 13,14 + 1213: 12,14 + 1214: 11,14 + 1215: 11,13 + 1216: 6,14 + 1217: 0,14 + 1218: 3,16 + 1219: 3,12 + 1220: 3,13 + 1221: 2,13 + 1222: 4,13 + 1223: 3,15 + 1224: 2,15 + 1225: 4,15 + 1226: 5,14 + 1227: 1,14 + 1228: 1,15 + 1229: 1,13 + 1230: 5,15 + 1231: 5,13 + 1232: 0,8 + 1233: 2,10 + 1234: 2,6 + 1235: 8,6 + 1236: 8,10 + 1237: 0,8 + 1238: 10,8 + 1239: 10,10 + 1240: 10,7 + 1241: 10,6 + 1242: 9,6 + 1243: 9,10 + 1244: 1,10 + 1245: 0,7 + 1246: 0,6 + 1247: 0,3 + 1248: 1,3 + 1249: 1,3 + 1250: 2,3 + 1251: 3,3 + 1252: 4,3 + 1253: 4,3 + 1254: 5,3 + 1255: 7,2 + 1256: 9,2 + 1257: 4,0 + 1258: 4,1 + 1259: 2,1 + 1260: 1,1 + 1261: 0,2 + 1262: 1,2 + 1263: 2,2 + 1264: 5,2 + 1265: 4,2 + 1266: 3,2 + 1267: 4,1 + 1268: 3,1 + 1269: 11,2 + 1270: 12,3 + 1271: 11,3 + 1272: 14,3 + 1273: 14,3 + 1274: 15,3 + 1275: 16,3 + 1276: 13,3 + 1277: 11,3 + 1278: 12,2 + 1279: 11,1 + 1280: 13,1 + 1281: 16,2 + 1282: 16,1 + 1283: 14,1 + 1284: 13,2 + 1285: 14,2 + 1286: 18,2 + 1287: 19,2 + 1288: 20,2 + 1289: 21,2 + 1290: 19,3 + 1291: 18,3 + 1292: 20,3 + 1293: 20,1 + 1294: 21,1 + 1295: 19,1 + 1296: 23,2 + 1297: 28,2 + 1298: 29,2 + 1299: 30,2 + 1300: 28,4 + 1301: 29,4 + 1302: 26,4 + 1303: 26,2 + 1304: 26,1 + 1305: 26,0 + 1306: 24,2 + 1307: 25,2 + 1308: 27,2 + 1309: 24,4 + 1310: 23,3 + 1311: 24,3 + 1312: 23,4 + 1469: 14,8 + 1470: 12,8 + 1471: 12,7 + 1472: 13,7 + 1473: 13,6 + 1474: 13,10 + 1475: 12,9 + 1476: 14,9 + 1477: 17,10 + 1478: 17,9 + 1479: 18,9 + 1480: 18,8 + 1481: 17,7 + 1482: 17,7 + 1483: 17,6 + 1484: 17,8 + 1485: 16,7 + 1486: 18,7 + 1487: 20,9 + 1488: 20,8 + 1489: 21,10 + 1490: 21,9 + 1491: 21,7 + 1492: 21,6 + 1493: 20,7 + 1494: 22,7 + 1495: 22,8 + 1534: 19,16 + 1535: 18,15 + 1536: 19,13 + 1537: 19,12 + 1538: 22,14 + 1539: 22,14 + 1540: 22,15 + 1541: 21,16 + 1542: 21,15 + 1543: 21,13 + 1544: 16,14 + 1545: 17,13 + 1546: 17,15 + 1556: 30,20 + 1557: 32,22 + 1558: 31,22 + 1559: 31,21 + 1560: 32,19 + 1561: 32,18 + 1562: 34,20 + 1563: 34,19 + 1564: 34,18 + 1565: 34,21 + 1566: 34,22 + 2060: 24,45 + 2061: 25,45 + 2062: 27,48 + 2063: 27,42 + 2064: 30,45 + 2065: 28,43 + 2066: 29,43 + 2067: 30,43 + 2068: 24,42 + 2069: 25,43 + 2070: 26,42 + 2071: 25,42 + 2072: 26,48 + 2073: 25,47 + 2074: 26,47 + 2075: 25,47 + 2076: 25,48 + 2077: 27,47 + 2078: 27,45 + 2079: 27,46 + 2080: 26,45 + 2081: 28,45 + 2082: 26,44 + 2083: 27,44 + 2084: 25,46 + 2085: 26,46 + 2086: 29,45 + - node: + color: '#A4610696' + id: DirtHeavy + decals: + 1353: 11,31 + 1354: 1,31 + 1355: 0,39 + 1356: 6,39 + 1357: 5,45 + 1358: 14,39 + 1359: 16,39 + 1360: 19,38 + - node: + cleanable: True + color: '#A4610696' + id: DirtHeavy + decals: + 1361: 22,39 + 1362: 19,40 + 1363: 30,39 + 1364: 25,35 + 1365: 24,36 + 1366: 20,30 + 1367: 14,30 + 1368: 18,30 + 1369: 22,30 + 1370: 26,31 + 1371: 22,26 + 1372: 24,26 + 1373: 26,26 + 1374: 28,26 + 1375: 29,27 + 1376: 33,25 + 1377: 33,28 + 1378: 32,28 + 1379: 14,26 + 1380: 12,26 + 1381: 9,26 + 1382: 9,28 + 1383: 8,28 + 1384: 8,24 + 1385: 10,25 + 1386: 5,24 + 1387: 5,28 + 1388: 0,26 + 1389: 0,27 + 1390: 2,24 + 1391: 2,25 + 1392: 0,35 + 1393: 0,36 + 1394: 7,36 + 1395: 5,35 + 1396: 4,34 + 1397: 10,35 + 1398: 9,35 + 1399: 8,39 + 1400: 14,39 + 1401: 14,38 + 1402: 8,45 + 1403: 11,48 + 1404: 11,44 + 1405: 14,45 + 1406: 11,42 + 1407: 9,42 + 1408: 13,43 + 1409: 3,47 + 1410: 4,20 + 1411: 3,22 + 1412: 2,18 + 1413: 0,19 + 1414: 6,20 + 1415: 8,20 + 1416: 8,18 + 1417: 10,20 + 1418: 8,22 + 1419: 14,20 + 1420: 15,21 + 1421: 16,20 + 1422: 12,20 + 1423: 12,21 + 1424: 13,22 + 1425: 13,21 + 1426: 13,19 + 1427: 16,19 + 1428: 16,19 + 1429: 15,20 + 1430: 14,18 + 1431: 12,20 + 1432: 14,22 + 1433: 20,20 + 1434: 20,22 + 1435: 18,20 + 1436: 22,21 + 1437: 19,21 + 1438: 20,18 + 1439: 22,20 + 1440: 27,22 + 1441: 25,22 + 1442: 26,18 + 1443: 27,18 + 1444: 31,18 + 1445: 32,18 + 1446: 31,20 + 1447: 32,21 + 1448: 34,22 + 1449: 34,20 + 1450: 32,19 + 1451: 29,14 + 1452: 24,14 + 1453: 24,13 + 1454: 30,14 + 1455: 29,13 + 1456: 34,2 + 1457: 32,3 + 1458: 30,1 + 1459: 26,1 + 1460: 23,3 + 1461: 24,4 + 1462: 29,4 + 1463: 26,0 + 1464: 26,1 + 1465: 18,2 + 1466: 22,8 + 1467: 20,8 + 1468: 16,8 + 1496: 17,6 + 1497: 16,8 + 1498: 18,8 + 1499: 17,10 + 1500: 14,8 + 1501: 12,8 + 1502: 13,6 + 1503: 13,10 + 1504: 21,10 + 1505: 21,9 + 1506: 21,8 + 1507: 21,7 + 1508: 21,6 + 1509: 10,8 + 1510: 9,10 + 1511: 9,6 + 1512: 2,6 + 1513: 0,7 + 1514: 0,9 + 1515: 1,10 + 1516: 8,10 + 1517: 0,14 + 1518: 5,14 + 1519: 4,15 + 1520: 3,16 + 1521: 1,18 + 1522: 5,15 + 1523: 6,14 + 1524: 11,16 + 1525: 8,13 + 1526: 11,12 + 1527: 10,13 + 1528: 16,14 + 1529: 19,16 + 1530: 19,13 + 1531: 18,13 + 1532: 18,15 + 1533: 16,15 + 1547: 19,16 + 1548: 16,14 + 1549: 17,15 + 1550: 18,14 + 1551: 19,13 + 1552: 21,13 + 1553: 22,14 + 1554: 29,15 + 1555: 29,13 + 2095: 24,45 + 2096: 27,48 + 2097: 27,42 + 2098: 25,44 + 2099: 29,45 + 2100: 29,46 + 2101: 29,47 + 2102: 25,45 + - node: + cleanable: True + color: '#A4610696' + id: DirtLight + decals: + 1567: 0,2 + 1568: 5,2 + 1569: 4,1 + 1570: 5,2 + 1571: 2,1 + 1572: 7,2 + 1573: 9,2 + 1574: 11,2 + 1575: 14,2 + 1576: 13,3 + 1577: 10,3 + 1578: 11,3 + 1579: 12,3 + 1580: 16,3 + 1581: 15,3 + 1582: 16,2 + 1583: 16,1 + 1584: 14,1 + 1585: 15,1 + 1586: 1,3 + 1587: 3,3 + 1588: 5,3 + 1589: 5,3 + 1590: 1,1 + 1591: 23,2 + 1592: 26,2 + 1593: 28,2 + 1594: 28,4 + 1595: 30,2 + 1596: 31,1 + 1597: 34,1 + 1598: 33,0 + 1599: 34,3 + 1600: 21,9 + 1601: 20,8 + 1602: 22,8 + 1603: 16,8 + 1604: 17,9 + 1605: 17,10 + 1606: 17,6 + 1607: 12,8 + 1608: 14,9 + 1609: 14,8 + 1610: 13,6 + 1611: 10,8 + 1612: 8,10 + 1613: 2,10 + 1614: 0,8 + 1615: 0,9 + 1616: 2,6 + 1617: 0,14 + 1618: 3,12 + 1619: 1,14 + 1620: 3,15 + 1621: 5,14 + 1622: 5,15 + 1623: 6,14 + 1624: 3,13 + 1625: 3,12 + 1626: 8,13 + 1627: 10,16 + 1628: 11,16 + 1629: 17,14 + 1630: 17,13 + 1631: 16,15 + 1632: 19,16 + 1633: 22,14 + 1634: 21,14 + 1635: 21,13 + 1636: 19,13 + 1637: 20,12 + 1638: 20,13 + 1639: 21,15 + 1640: 29,14 + 1641: 29,15 + 1642: 34,20 + 1643: 32,18 + 1644: 34,18 + 1645: 34,21 + 1646: 32,22 + 1647: 30,20 + 1648: 30,21 + 1649: 32,19 + 1650: 32,21 + 1651: 32,20 + 1652: 30,18 + 1653: 26,22 + 1654: 25,22 + 1655: 25,20 + 1656: 27,20 + 1657: 27,22 + 1658: 25,20 + 1659: 27,20 + 1660: 26,18 + 1661: 27,18 + 1662: 25,18 + 1663: 22,20 + 1664: 18,20 + 1665: 20,22 + 1666: 20,20 + 1667: 19,19 + 1668: 20,19 + 1669: 20,21 + 1670: 21,20 + 1671: 16,20 + 1672: 16,21 + 1673: 12,20 + 1674: 13,21 + 1675: 13,22 + 1676: 13,19 + 1677: 13,19 + 1678: 14,20 + 1679: 14,18 + 1680: 10,20 + 1681: 10,21 + 1682: 8,22 + 1683: 6,21 + 1684: 6,20 + 1685: 7,20 + 1686: 7,19 + 1687: 8,20 + 1688: 9,20 + 1689: 4,20 + 1690: 3,18 + 1691: 2,18 + 1692: 1,18 + 1693: 0,21 + 1694: 1,22 + 1695: 0,20 + 1696: 2,22 + 1697: 1,24 + 1698: 0,26 + 1699: 0,25 + 1700: 2,25 + 1701: 2,27 + 1702: 5,28 + 1703: 5,24 + 1704: 9,26 + 1705: 9,27 + 1706: 9,24 + 1707: 8,24 + 1708: 10,24 + 1709: 10,26 + 1710: 13,26 + 1711: 12,26 + 1712: 13,28 + 1713: 12,28 + 1714: 13,24 + 1715: 14,26 + 1716: 13,25 + 1717: 18,26 + 1718: 16,26 + 1719: 17,28 + 1720: 17,25 + 1721: 17,24 + 1722: 20,26 + 1723: 22,26 + 1724: 21,26 + 1725: 21,27 + 1726: 21,24 + 1727: 21,25 + 1728: 25,26 + 1729: 26,26 + 1730: 25,26 + 1731: 25,26 + 1732: 25,24 + 1733: 25,24 + 1734: 26,25 + 1735: 24,27 + 1736: 29,26 + 1737: 29,27 + 1738: 30,26 + 1739: 29,24 + 1740: 33,26 + 1741: 33,24 + 1742: 34,26 + 1743: 32,26 + 1744: 34,28 + 1745: 34,28 + 1746: 33,28 + 1747: 32,28 + 1748: 26,31 + 1749: 21,30 + 1750: 20,30 + 1751: 17,30 + 1752: 15,30 + 1753: 14,31 + 1754: 10,31 + 1755: 2,31 + 1756: 11,30 + 1757: 12,31 + 1758: 0,32 + 1759: 1,32 + 1760: 0,31 + 1761: -1,35 + 1762: 0,36 + 1763: 0,35 + 1764: 4,34 + 1765: 5,35 + 1766: 3,34 + 1767: 10,34 + 1768: 10,35 + 1769: 6,39 + 1770: 0,39 + 1771: 0,45 + 1772: 3,43 + 1773: 3,47 + 1774: 4,45 + 1775: 5,45 + 1776: 8,45 + 1777: 11,46 + 1778: 11,45 + 1779: 11,42 + 1780: 13,42 + 1781: 9,42 + 1782: 14,45 + 1783: 10,44 + 1784: 11,44 + 1785: 11,45 + 1786: 16,47 + 1787: 16,45 + 1788: 17,45 + 1789: 21,45 + 1790: 16,48 + 1791: 16,43 + 1792: 23,43 + 1793: 22,42 + 1794: 30,38 + 1795: 30,40 + 1796: 24,38 + 1797: 22,39 + 1798: 19,38 + 1799: 19,39 + 1800: 18,39 + 1801: 16,39 + 1802: 18,38 + 1803: 17,38 + 1804: 14,38 + 1805: 14,40 + 1806: 9,39 + 1807: 10,40 + 1808: 12,38 + 1809: 10,38 + 1810: 10,38 + 1811: 6,39 + 1812: 0,39 + 2103: 24,45 + 2104: 30,45 + 2105: 26,44 + 2106: 27,43 + 2107: 30,43 + 2108: 29,42 + 2109: 28,47 + - node: + cleanable: True + color: '#A4610696' + id: DirtMedium + decals: + 1813: 0,35 + 1814: 0,39 + 1815: 6,39 + 1816: 3,43 + 1817: 1,45 + 1818: 11,45 + 1819: 11,42 + 1820: 14,45 + 1821: 16,45 + 1822: 21,45 + 1823: 22,45 + 1824: 21,38 + 1825: 20,38 + 1826: 20,38 + 1827: 24,38 + 1828: 30,39 + 1829: 34,35 + 1830: 33,36 + 1831: 33,34 + 1832: 24,34 + 1833: 20,34 + 1834: 22,35 + 1835: 17,35 + 1836: 16,34 + 1837: 17,36 + 1838: 12,35 + 1839: 10,35 + 1840: 5,35 + 1841: 0,35 + 1842: 1,31 + 1843: 2,31 + 1844: 11,31 + 1845: 9,26 + 1846: 8,26 + 1847: 9,27 + 1848: 9,28 + 1849: 10,26 + 1850: 10,25 + 1851: 9,25 + 1852: 13,26 + 1853: 12,26 + 1854: 13,28 + 1855: 14,26 + 1856: 17,24 + 1857: 18,26 + 1858: 17,28 + 1859: 16,26 + 1860: 22,26 + 1861: 20,26 + 1862: 25,27 + 1863: 24,27 + 1864: 24,28 + 1865: 24,25 + 1866: 25,25 + 1867: 25,24 + 1868: 24,24 + 1869: 26,25 + 1870: 26,26 + 1871: 25,26 + 1872: 24,26 + 1873: 24,26 + 1874: 25,26 + 1875: 25,26 + 1876: 28,26 + 1877: 30,26 + 1878: 29,27 + 1879: 29,25 + 1880: 33,26 + 1881: 34,26 + 1882: 34,28 + 1883: 32,28 + 1884: 34,28 + 1885: 32,20 + 1886: 31,20 + 1887: 30,20 + 1888: 30,18 + 1889: 34,18 + 1890: 34,21 + 1891: 25,18 + 1892: 26,18 + 1893: 25,18 + 1894: 27,20 + 1895: 27,22 + 1896: 29,15 + 1897: 30,14 + 1898: 29,12 + 1899: 24,14 + 1900: 24,15 + 1901: 24,16 + 1902: 20,20 + 1903: 17,20 + 1904: 19,21 + 1905: 18,20 + 1906: 21,22 + 1907: 22,20 + 1908: 22,21 + 1909: 20,19 + 1910: 15,20 + 1911: 14,21 + 1912: 15,21 + 1913: 16,21 + 1914: 14,22 + 1915: 12,20 + 1916: 14,18 + 1917: 15,18 + 1918: 16,19 + 1919: 16,19 + 1920: 13,19 + 1921: 12,19 + 1922: 12,19 + 1923: 12,18 + 1924: 14,18 + 1925: 15,18 + 1926: 15,18 + 1927: 10,20 + 1928: 8,22 + 1929: 7,20 + 1930: 9,21 + 1931: 7,19 + 1932: 10,19 + 1933: 10,21 + 1934: 7,18 + 1935: 4,20 + 1936: 4,21 + 1937: 2,22 + 1938: 1,22 + 1939: 0,19 + 1940: 1,18 + 1941: 1,18 + 1942: 3,18 + 1943: 0,14 + 1944: 2,13 + 1945: 3,13 + 1946: 5,13 + 1947: 3,12 + 1948: 8,15 + 1949: 8,16 + 1950: 9,16 + 1951: 9,16 + 1952: 18,14 + 1953: 19,16 + 1954: 19,14 + 1955: 20,13 + 1956: 18,16 + 1957: 17,13 + 1958: 20,12 + 1959: 22,13 + 1960: 24,13 + 1961: 30,12 + 1962: 30,14 + 1963: 29,16 + 1964: 24,16 + 1965: 24,16 + 1966: 25,6 + 1967: 24,7 + 1968: 26,9 + 1969: 27,10 + 1970: 28,10 + 1971: 34,10 + 1972: 34,8 + 1973: 34,7 + 1974: 33,6 + 1975: 30,6 + 1976: 27,6 + 1977: 21,8 + 1978: 16,8 + 1979: 17,10 + 1980: 18,8 + 1981: 17,6 + 1982: 13,7 + 1983: 13,9 + 1984: 13,8 + 1985: 14,7 + 1986: 10,6 + 1987: 8,10 + 1988: 2,6 + 1989: 0,7 + 1990: 1,1 + 1991: 0,1 + 1992: 4,1 + 1993: 5,2 + 1994: 3,1 + 1995: 3,0 + 1996: 7,2 + 1997: 9,2 + 1998: 11,2 + 1999: 13,1 + 2000: 15,1 + 2001: 16,2 + 2002: 16,1 + 2003: 23,2 + 2004: 26,2 + 2005: 29,3 + 2006: 30,2 + 2007: 33,2 + 2008: 33,3 + 2009: 34,2 + 2010: 34,0 + 2011: 34,1 + 2012: 31,1 + 2013: 29,0 + 2014: 26,0 + 2015: 23,3 + 2016: 28,4 + 2087: 27,42 + 2088: 27,48 + 2089: 24,45 + 2090: 30,45 + 2091: 28,45 + 2092: 26,45 + 2093: 28,47 + 2094: 27,44 + 2110: 24,45 + 2111: 27,48 + 2112: 27,45 + 2113: 26,46 + 2114: 26,42 + 2115: 25,42 + 2116: 25,47 + 2117: 25,47 + 2118: 26,48 + 2119: 26,47 + 2120: 26,47 + 2121: 26,43 + 2122: 26,43 + 2123: 27,43 + 2124: 6,1 + 2125: 10,3 + - node: + color: '#D4D4D41B' + id: FullTileOverlayGreyscale + decals: + 1313: 31,4 + 1314: 31,3 + 1315: 31,2 + 1316: 31,1 + 1317: 31,0 + - node: + color: '#D4D4D433' + id: FullTileOverlayGreyscale + decals: + 1318: 32,0 + 1319: 32,1 + 1320: 32,2 + 1321: 32,3 + 1322: 32,4 + - node: + color: '#D4D4D44C' + id: FullTileOverlayGreyscale + decals: + 1323: 33,0 + 1324: 33,1 + 1325: 33,2 + 1326: 33,3 + 1327: 33,4 + - node: + color: '#D4D4D40C' + id: HalfTileOverlayGreyscale + decals: + 923: 3,47 + - node: + color: '#D4D4D419' + id: HalfTileOverlayGreyscale + decals: + 893: 3,43 + - node: + color: '#D4D4D40C' + id: HalfTileOverlayGreyscale180 + decals: + 924: 3,43 + - node: + color: '#D4D4D419' + id: HalfTileOverlayGreyscale180 + decals: + 894: 3,47 + - node: + color: '#D4D4D40C' + id: HalfTileOverlayGreyscale270 + decals: + 910: 30,2 + 911: 9,2 + 914: 2,6 + 915: 2,10 + 918: 2,31 + 922: 1,45 + - node: + color: '#D4D4D419' + id: HalfTileOverlayGreyscale270 + decals: + 882: 7,2 + 883: 8,6 + 884: 8,10 + 888: 10,31 + 889: 33,34 + 890: 33,36 + 891: 5,45 + - node: + color: '#D4D4D40C' + id: HalfTileOverlayGreyscale90 + decals: + 912: 7,2 + 913: 8,6 + 916: 8,10 + 917: 10,31 + 919: 33,34 + 920: 33,36 + 921: 5,45 + - node: + color: '#D4D4D419' + id: HalfTileOverlayGreyscale90 + decals: + 880: 30,2 + 881: 9,2 + 885: 2,6 + 886: 2,10 + 887: 2,31 + 892: 1,45 + - node: + color: '#9FED5896' + id: MiniTileCheckerAOverlay + decals: + 2028: 28,42 + 2029: 29,42 + 2030: 30,42 + 2031: 28,43 + 2032: 29,43 + 2033: 30,43 + 2034: 28,44 + 2035: 29,44 + 2036: 30,44 + - node: + color: '#DE3A3A96' + id: MiniTileCheckerAOverlay + decals: + 0: 7,19 + 1: 8,19 + 2: 9,19 + 3: 9,20 + 4: 8,20 + 5: 7,20 + 6: 7,21 + 7: 8,21 + 8: 9,21 + 9: 19,19 + 10: 20,19 + 11: 21,19 + 12: 21,20 + 13: 20,20 + 14: 19,20 + 15: 19,21 + 16: 20,21 + 17: 21,21 + 18: 17,15 + 19: 17,14 + 20: 17,13 + 21: 18,13 + 22: 19,13 + 23: 20,13 + 24: 21,13 + 25: 21,14 + 26: 21,15 + 27: 20,15 + 28: 19,15 + 29: 18,15 + 30: 18,14 + 31: 19,14 + 32: 20,9 + 33: 21,9 + 34: 22,9 + 35: 22,8 + 36: 22,7 + 37: 21,7 + 38: 21,8 + 39: 20,8 + 40: 20,7 + 41: 12,7 + 42: 13,7 + 43: 14,7 + 44: 14,8 + 45: 13,8 + 46: 12,8 + 47: 12,9 + 48: 13,9 + 49: 14,9 + 59: 17,39 + 60: 18,39 + 61: 19,39 + 62: 20,39 + 63: 21,39 + 64: 16,36 + 65: 16,35 + 66: 16,34 + 67: 17,34 + 68: 18,34 + 69: 18,35 + 70: 17,35 + 71: 17,36 + 72: 18,36 + - node: + color: '#FFFFFFFF' + id: MiniTileCheckerAOverlay + decals: + 2052: 28,46 + 2053: 28,47 + 2054: 29,47 + 2055: 29,46 + - node: + color: '#9FED5896' + id: MiniTileCheckerBOverlay + decals: + 50: 31,21 + 51: 31,20 + 52: 31,19 + 53: 33,21 + 54: 33,20 + 55: 33,19 + - node: + color: '#DE3A3A96' + id: MiniTileCheckerBOverlay + decals: + 56: 32,21 + 57: 32,20 + 58: 32,19 + - node: + color: '#DE3A3A96' + id: StandClearGreyscale + decals: + 751: 26,7 + 752: 32,7 + 753: 29,9 + 838: 6,2 + 839: 10,2 + - node: + color: '#FFFFFFFF' + id: WarnCornerNE + decals: + 605: 13,40 + 747: 34,10 + - node: + color: '#FFFFFFFF' + id: WarnCornerNW + decals: + 606: 9,40 + 741: 24,10 + - node: + color: '#FFFFFFFF' + id: WarnCornerSE + decals: + 604: 13,38 + 746: 34,6 + - node: + color: '#FFFFFFFF' + id: WarnCornerSW + decals: + 598: 9,38 + 740: 24,6 + - node: + color: '#FFFFFFFF' + id: WarnFull + decals: + 657: 32,35 + - node: + color: '#FFFFFFFF' + id: WarnLineE + decals: + 607: 13,39 + 644: 26,34 + 645: 26,35 + 646: 26,36 + 744: 34,7 + 745: 34,9 + - node: + color: '#DE3A3A96' + id: WarnLineGreyscaleE + decals: + 112: 18,26 + 117: 14,26 + 118: 22,26 + 121: 22,35 + 122: 22,39 + 128: 14,39 + 131: 6,39 + 132: 12,31 + 135: 26,31 + 140: 26,26 + 145: 30,26 + 146: 34,26 + 153: 2,26 + 159: 4,20 + 160: 10,20 + 166: 16,20 + 170: 22,20 + 175: 34,20 + 176: 22,14 + 183: 6,14 + 184: 10,8 + 188: 16,2 + 190: 34,2 + 205: 21,2 + 213: 34,8 + 214: 30,14 + 219: 34,35 + 223: 30,39 + 224: 22,45 + 227: 14,45 + 230: 6,45 + 235: 10,35 + 834: 5,2 + 2018: 30,45 + - node: + color: '#DE3A3A96' + id: WarnLineGreyscaleN + decals: + 111: 17,28 + 116: 13,28 + 125: 19,40 + 126: 11,40 + 138: 21,28 + 144: 29,28 + 154: 1,28 + 158: 2,22 + 161: 8,22 + 165: 14,22 + 171: 20,22 + 173: 32,22 + 179: 19,16 + 180: 3,16 + 186: 17,10 + 209: 26,4 + 210: 29,10 + 217: 26,22 + 220: 29,36 + 228: 11,48 + 233: 3,48 + 237: 5,28 + 2020: 27,48 + - node: + color: '#FFFFFFFF' + id: WarnLineGreyscaleN + decals: + 667: 27,35 + 668: 28,35 + 669: 29,35 + 670: 30,35 + 671: 31,35 + - node: + color: '#DE3A3A96' + id: WarnLineGreyscaleS + decals: + 110: 17,24 + 115: 13,24 + 124: 19,38 + 127: 11,38 + 136: 20,30 + 137: 21,24 + 139: 25,24 + 143: 29,24 + 148: 33,24 + 149: 32,28 + 150: 33,28 + 151: 34,28 + 152: 1,24 + 157: 2,18 + 163: 8,18 + 164: 14,18 + 169: 20,18 + 172: 32,18 + 177: 19,12 + 181: 3,12 + 187: 17,6 + 208: 26,0 + 211: 29,6 + 216: 26,18 + 221: 29,34 + 229: 11,42 + 231: 3,42 + 236: 5,24 + 2019: 27,42 + - node: + color: '#FFFFFFFF' + id: WarnLineGreyscaleS + decals: + 662: 27,35 + 663: 28,35 + 664: 29,35 + 665: 30,35 + 666: 31,35 + - node: + color: '#DE3A3A96' + id: WarnLineGreyscaleW + decals: + 113: 16,26 + 114: 12,26 + 119: 20,26 + 120: 12,35 + 123: 16,39 + 129: 8,39 + 130: 0,39 + 133: 0,31 + 134: 14,31 + 141: 24,26 + 142: 28,26 + 147: 32,26 + 155: 0,26 + 156: 0,20 + 162: 6,20 + 167: 12,20 + 168: 18,20 + 174: 30,20 + 178: 16,14 + 182: 0,14 + 185: 0,8 + 189: 0,2 + 206: 18,2 + 207: 23,2 + 212: 24,8 + 215: 24,14 + 218: 24,35 + 222: 24,39 + 225: 16,45 + 226: 8,45 + 232: 0,45 + 234: 0,35 + 835: 11,2 + 2017: 24,45 + - node: + color: '#FFFFFFFF' + id: WarnLineN + decals: + 601: 10,38 + 602: 12,38 + 647: 27,34 + 648: 28,34 + 649: 30,34 + 650: 31,34 + 651: 32,34 + 732: 28,6 + 733: 27,6 + 734: 26,6 + 735: 25,6 + 736: 30,6 + 737: 31,6 + 738: 32,6 + 739: 33,6 + - node: + color: '#FFFFFFFF' + id: WarnLineS + decals: + 603: 9,39 + 742: 24,7 + 743: 24,9 + - node: + color: '#FFFFFFFF' + id: WarnLineW + decals: + 599: 10,40 + 600: 12,40 + 652: 27,36 + 653: 28,36 + 654: 30,36 + 655: 31,36 + 656: 32,36 + 724: 25,10 + 725: 26,10 + 726: 28,10 + 727: 27,10 + 728: 30,10 + 729: 31,10 + 730: 32,10 + 731: 33,10 + - node: + cleanable: True + color: '#80C71F7F' + id: revolution + decals: + 2138: 14.060958,20.754644 + 2139: 13.607299,19.803425 + - node: + cleanable: True + color: '#B02E60A3' + id: revolution + decals: + 2137: 25.02975,25.438416 + - node: + cleanable: True + angle: -1.5707963267948966 rad + color: '#B02E2644' + id: splatter + decals: + 2131: 27.967218,24.104916 + - node: + cleanable: True + color: '#B02E2666' + id: splatter + decals: + 2126: 8.891183,43.065514 + - node: + cleanable: True + angle: -1.5707963267948966 rad + color: '#B02E266F' + id: splatter + decals: + 2132: 28.36234,24.163452 + 2133: 32.200607,35.087025 + 2134: 13.24002,46.473877 + 2135: 24.497486,47.84553 + - node: + cleanable: True + angle: -4.71238898038469 rad + color: '#B02E26B4' + id: splatter + decals: + 2128: 8.788744,42.524048 + 2129: 15.538555,20.953827 + 2130: 24.864944,27.488853 + - node: + cleanable: True + angle: -3.141592653589793 rad + color: '#B02E26B4' + id: splatter + decals: + 2127: 9.110695,42.81673 + - type: RadiationGridResistance + - type: LoadedMap + - type: SpreaderGrid + - type: GridTree + - type: MovedGrids + - type: GridPathfinding +- proto: AirlockBrigGlassLocked + entities: + - uid: 1245 + components: + - type: Transform + pos: 15.5,35.5 + parent: 588 + - uid: 1246 + components: + - type: Transform + pos: 19.5,35.5 + parent: 588 + - uid: 1625 + components: + - type: Transform + pos: 22.5,2.5 + parent: 588 +- proto: AirlockEngineering + entities: + - uid: 1515 + components: + - type: Transform + pos: 19.5,43.5 + parent: 588 +- proto: AirlockSecurityGlassLocked + entities: + - uid: 1579 + components: + - type: Transform + pos: 11.5,15.5 + parent: 588 + - uid: 1609 + components: + - type: Transform + pos: 15.5,8.5 + parent: 588 + - uid: 1610 + components: + - type: Transform + pos: 19.5,8.5 + parent: 588 + - uid: 1623 + components: + - type: Transform + pos: 6.5,2.5 + parent: 588 + - uid: 1624 + components: + - type: Transform + pos: 10.5,2.5 + parent: 588 +- proto: APCBasic + entities: + - uid: 484 + components: + - type: Transform + pos: 25.5,13.5 + parent: 588 + - uid: 773 + components: + - type: Transform + pos: 25.5,19.5 + parent: 588 + - uid: 973 + components: + - type: Transform + pos: 21.5,32.5 + parent: 588 + - uid: 1509 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,47.5 + parent: 588 +- proto: BannerSecurity + entities: + - uid: 553 + components: + - type: Transform + pos: 30.5,8.5 + parent: 588 + - uid: 1619 + components: + - type: Transform + pos: 18.5,10.5 + parent: 588 + - uid: 1620 + components: + - type: Transform + pos: 16.5,6.5 + parent: 588 +- proto: BasaltFive + entities: + - uid: 608 + components: + - type: Transform + pos: 2.5,14.5 + parent: 588 + - uid: 647 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,21.5 + parent: 588 + - uid: 899 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,30.5 + parent: 588 + - uid: 1264 + components: + - type: Transform + pos: 9.5,0.5 + parent: 588 + - uid: 1384 + components: + - type: Transform + pos: 5.5,48.5 + parent: 588 + - uid: 1386 + components: + - type: Transform + pos: 0.5,47.5 + parent: 588 + - uid: 1387 + components: + - type: Transform + pos: 0.5,42.5 + parent: 588 + - uid: 1388 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,42.5 + parent: 588 +- proto: BasaltFour + entities: + - uid: 900 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,32.5 + parent: 588 + - uid: 904 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,40.5 + parent: 588 + - uid: 1381 + components: + - type: Transform + pos: 1.5,44.5 + parent: 588 + - uid: 1385 + components: + - type: Transform + pos: 6.5,48.5 + parent: 588 +- proto: BasaltOne + entities: + - uid: 813 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,27.5 + parent: 588 + - uid: 897 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,30.5 + parent: 588 + - uid: 901 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,32.5 + parent: 588 + - uid: 903 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,38.5 + parent: 588 + - uid: 1382 + components: + - type: Transform + pos: 1.5,48.5 + parent: 588 +- proto: BasaltRandom + entities: + - uid: 613 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,14.5 + parent: 588 + - uid: 615 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,7.5 + parent: 588 +- proto: BasaltThree + entities: + - uid: 616 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,7.5 + parent: 588 + - uid: 644 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,20.5 + parent: 588 + - uid: 898 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,30.5 + parent: 588 + - uid: 905 + components: + - type: Transform + pos: 4.5,38.5 + parent: 588 + - uid: 1265 + components: + - type: Transform + pos: 7.5,1.5 + parent: 588 + - uid: 1266 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 9.5,3.5 + parent: 588 + - uid: 1383 + components: + - type: Transform + pos: 6.5,47.5 + parent: 588 +- proto: BasaltTwo + entities: + - uid: 610 + components: + - type: Transform + pos: 3.5,14.5 + parent: 588 + - uid: 617 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,9.5 + parent: 588 + - uid: 618 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,8.5 + parent: 588 + - uid: 646 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,19.5 + parent: 588 + - uid: 814 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,26.5 + parent: 588 + - uid: 896 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,32.5 + parent: 588 + - uid: 902 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,38.5 + parent: 588 + - uid: 1263 + components: + - type: Transform + pos: 7.5,4.5 + parent: 588 + - uid: 1380 + components: + - type: Transform + pos: 1.5,43.5 + parent: 588 +- proto: Bed + entities: + - uid: 257 + components: + - type: Transform + pos: 15.5,4.5 + parent: 588 + - uid: 282 + components: + - type: Transform + pos: 1.5,4.5 + parent: 588 + - uid: 293 + components: + - type: Transform + pos: 3.5,4.5 + parent: 588 + - uid: 294 + components: + - type: Transform + pos: 5.5,4.5 + parent: 588 + - uid: 295 + components: + - type: Transform + pos: 11.5,4.5 + parent: 588 + - uid: 296 + components: + - type: Transform + pos: 13.5,4.5 + parent: 588 + - uid: 700 + components: + - type: Transform + pos: 12.5,22.5 + parent: 588 + - uid: 701 + components: + - type: Transform + pos: 16.5,18.5 + parent: 588 + - uid: 1043 + components: + - type: Transform + pos: 20.5,28.5 + parent: 588 + - uid: 1044 + components: + - type: Transform + pos: 22.5,24.5 + parent: 588 + - uid: 1075 + components: + - type: Transform + pos: 24.5,28.5 + parent: 588 + - uid: 1099 + components: + - type: Transform + pos: 20.5,36.5 + parent: 588 + - uid: 1100 + components: + - type: Transform + pos: 14.5,34.5 + parent: 588 + - uid: 1763 + components: + - type: Transform + pos: 24.5,48.5 + parent: 588 + - uid: 1764 + components: + - type: Transform + pos: 24.5,42.5 + parent: 588 +- proto: BedsheetMedical + entities: + - uid: 1150 + components: + - type: Transform + pos: 28.5,24.5 + parent: 588 + - uid: 1151 + components: + - type: Transform + pos: 28.5,25.5 + parent: 588 +- proto: BedsheetOrange + entities: + - uid: 298 + components: + - type: Transform + pos: 3.5,4.5 + parent: 588 + - uid: 299 + components: + - type: Transform + pos: 5.5,4.5 + parent: 588 + - uid: 300 + components: + - type: Transform + pos: 13.5,4.5 + parent: 588 + - uid: 1765 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,42.5 + parent: 588 +- proto: BedsheetSpawner + entities: + - uid: 301 + components: + - type: Transform + pos: 11.5,4.5 + parent: 588 + - uid: 1041 + components: + - type: Transform + pos: 20.5,28.5 + parent: 588 + - uid: 1225 + components: + - type: Transform + pos: 14.5,34.5 + parent: 588 + - uid: 1226 + components: + - type: Transform + pos: 20.5,36.5 + parent: 588 +- proto: BedsheetSyndie + entities: + - uid: 1037 + components: + - type: Transform + pos: 22.5,24.5 + parent: 588 + - uid: 1766 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,48.5 + parent: 588 +- proto: BlastDoor + entities: + - uid: 1600 + components: + - type: Transform + pos: 26.5,7.5 + parent: 588 + - uid: 1601 + components: + - type: Transform + pos: 29.5,9.5 + parent: 588 + - uid: 1602 + components: + - type: Transform + pos: 32.5,7.5 + parent: 588 +- proto: Bola + entities: + - uid: 1157 + components: + - type: Transform + pos: 15.616387,0.61007345 + parent: 588 +- proto: BookEscalationSecurity + entities: + - uid: 373 + components: + - type: Transform + pos: 19.42657,0.6288943 + parent: 588 +- proto: BookRandom + entities: + - uid: 1835 + components: + - type: Transform + pos: 24.420084,44.539436 + parent: 588 +- proto: BookSecurity + entities: + - uid: 522 + components: + - type: Transform + pos: 32.41844,8.400207 + parent: 588 +- proto: BoxFolderBlack + entities: + - uid: 365 + components: + - type: Transform + pos: 27.841173,1.5632035 + parent: 588 + - uid: 728 + components: + - type: Transform + pos: 10.690479,19.262342 + parent: 588 +- proto: BoxFolderGrey + entities: + - uid: 364 + components: + - type: Transform + pos: 25.072409,1.4780562 + parent: 588 + - uid: 727 + components: + - type: Transform + pos: 7.2148314,22.575037 + parent: 588 +- proto: BoxFolderRed + entities: + - uid: 329 + components: + - type: Transform + pos: 21.42984,3.6329575 + parent: 588 + - uid: 362 + components: + - type: Transform + pos: 24.788435,1.6057768 + parent: 588 + - uid: 363 + components: + - type: Transform + pos: 28.196142,1.5773941 + parent: 588 + - uid: 726 + components: + - type: Transform + pos: 10.428753,19.429379 + parent: 588 +- proto: BoxMouthSwab + entities: + - uid: 1476 + components: + - type: Transform + pos: 12.356534,44.605965 + parent: 588 +- proto: BoxSterileMask + entities: + - uid: 1477 + components: + - type: Transform + pos: 12.683106,44.705303 + parent: 588 +- proto: BriefcaseBrownFilled + entities: + - uid: 325 + components: + - type: Transform + pos: 19.413612,4.6972914 + parent: 588 +- proto: BrokenBottle + entities: + - uid: 1691 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.063513,27.520548 + parent: 588 +- proto: Bucket + entities: + - uid: 1839 + components: + - type: Transform + pos: 29.616838,43.531868 + parent: 588 + - uid: 1857 + components: + - type: Transform + pos: 30.264944,21.705044 + parent: 588 +- proto: CableApcExtension + entities: + - uid: 1 + components: + - type: Transform + pos: 0.5,2.5 + parent: 588 + - uid: 2 + components: + - type: Transform + pos: 1.5,2.5 + parent: 588 + - uid: 3 + components: + - type: Transform + pos: 2.5,2.5 + parent: 588 + - uid: 4 + components: + - type: Transform + pos: 3.5,2.5 + parent: 588 + - uid: 5 + components: + - type: Transform + pos: 4.5,2.5 + parent: 588 + - uid: 6 + components: + - type: Transform + pos: 5.5,2.5 + parent: 588 + - uid: 7 + components: + - type: Transform + pos: 6.5,2.5 + parent: 588 + - uid: 8 + components: + - type: Transform + pos: 7.5,2.5 + parent: 588 + - uid: 9 + components: + - type: Transform + pos: 8.5,2.5 + parent: 588 + - uid: 10 + components: + - type: Transform + pos: 9.5,2.5 + parent: 588 + - uid: 11 + components: + - type: Transform + pos: 10.5,2.5 + parent: 588 + - uid: 12 + components: + - type: Transform + pos: 11.5,2.5 + parent: 588 + - uid: 13 + components: + - type: Transform + pos: 12.5,2.5 + parent: 588 + - uid: 14 + components: + - type: Transform + pos: 13.5,2.5 + parent: 588 + - uid: 15 + components: + - type: Transform + pos: 14.5,2.5 + parent: 588 + - uid: 16 + components: + - type: Transform + pos: 15.5,2.5 + parent: 588 + - uid: 17 + components: + - type: Transform + pos: 16.5,2.5 + parent: 588 + - uid: 18 + components: + - type: Transform + pos: 8.5,4.5 + parent: 588 + - uid: 19 + components: + - type: Transform + pos: 8.5,3.5 + parent: 588 + - uid: 20 + components: + - type: Transform + pos: 8.5,1.5 + parent: 588 + - uid: 21 + components: + - type: Transform + pos: 8.5,0.5 + parent: 588 + - uid: 22 + components: + - type: Transform + pos: 18.5,2.5 + parent: 588 + - uid: 23 + components: + - type: Transform + pos: 19.5,2.5 + parent: 588 + - uid: 24 + components: + - type: Transform + pos: 20.5,2.5 + parent: 588 + - uid: 25 + components: + - type: Transform + pos: 21.5,2.5 + parent: 588 + - uid: 26 + components: + - type: Transform + pos: 22.5,2.5 + parent: 588 + - uid: 27 + components: + - type: Transform + pos: 23.5,2.5 + parent: 588 + - uid: 28 + components: + - type: Transform + pos: 24.5,2.5 + parent: 588 + - uid: 29 + components: + - type: Transform + pos: 25.5,2.5 + parent: 588 + - uid: 30 + components: + - type: Transform + pos: 26.5,2.5 + parent: 588 + - uid: 31 + components: + - type: Transform + pos: 27.5,2.5 + parent: 588 + - uid: 32 + components: + - type: Transform + pos: 28.5,2.5 + parent: 588 + - uid: 33 + components: + - type: Transform + pos: 29.5,2.5 + parent: 588 + - uid: 34 + components: + - type: Transform + pos: 30.5,2.5 + parent: 588 + - uid: 35 + components: + - type: Transform + pos: 31.5,2.5 + parent: 588 + - uid: 36 + components: + - type: Transform + pos: 32.5,2.5 + parent: 588 + - uid: 37 + components: + - type: Transform + pos: 33.5,2.5 + parent: 588 + - uid: 38 + components: + - type: Transform + pos: 34.5,2.5 + parent: 588 + - uid: 39 + components: + - type: Transform + pos: 26.5,4.5 + parent: 588 + - uid: 40 + components: + - type: Transform + pos: 26.5,3.5 + parent: 588 + - uid: 41 + components: + - type: Transform + pos: 26.5,1.5 + parent: 588 + - uid: 42 + components: + - type: Transform + pos: 26.5,0.5 + parent: 588 + - uid: 43 + components: + - type: Transform + pos: 0.5,8.5 + parent: 588 + - uid: 44 + components: + - type: Transform + pos: 1.5,8.5 + parent: 588 + - uid: 52 + components: + - type: Transform + pos: 9.5,8.5 + parent: 588 + - uid: 53 + components: + - type: Transform + pos: 10.5,8.5 + parent: 588 + - uid: 54 + components: + - type: Transform + pos: 5.5,10.5 + parent: 588 + - uid: 57 + components: + - type: Transform + pos: 5.5,6.5 + parent: 588 + - uid: 58 + components: + - type: Transform + pos: 17.5,6.5 + parent: 588 + - uid: 59 + components: + - type: Transform + pos: 17.5,7.5 + parent: 588 + - uid: 60 + components: + - type: Transform + pos: 17.5,8.5 + parent: 588 + - uid: 61 + components: + - type: Transform + pos: 17.5,9.5 + parent: 588 + - uid: 62 + components: + - type: Transform + pos: 17.5,10.5 + parent: 588 + - uid: 63 + components: + - type: Transform + pos: 12.5,8.5 + parent: 588 + - uid: 64 + components: + - type: Transform + pos: 13.5,8.5 + parent: 588 + - uid: 65 + components: + - type: Transform + pos: 14.5,8.5 + parent: 588 + - uid: 66 + components: + - type: Transform + pos: 15.5,8.5 + parent: 588 + - uid: 67 + components: + - type: Transform + pos: 16.5,8.5 + parent: 588 + - uid: 68 + components: + - type: Transform + pos: 18.5,8.5 + parent: 588 + - uid: 69 + components: + - type: Transform + pos: 19.5,8.5 + parent: 588 + - uid: 70 + components: + - type: Transform + pos: 20.5,8.5 + parent: 588 + - uid: 71 + components: + - type: Transform + pos: 21.5,8.5 + parent: 588 + - uid: 72 + components: + - type: Transform + pos: 22.5,8.5 + parent: 588 + - uid: 73 + components: + - type: Transform + pos: 22.5,14.5 + parent: 588 + - uid: 74 + components: + - type: Transform + pos: 21.5,14.5 + parent: 588 + - uid: 75 + components: + - type: Transform + pos: 20.5,14.5 + parent: 588 + - uid: 76 + components: + - type: Transform + pos: 19.5,14.5 + parent: 588 + - uid: 77 + components: + - type: Transform + pos: 18.5,14.5 + parent: 588 + - uid: 78 + components: + - type: Transform + pos: 17.5,14.5 + parent: 588 + - uid: 79 + components: + - type: Transform + pos: 16.5,14.5 + parent: 588 + - uid: 80 + components: + - type: Transform + pos: 19.5,13.5 + parent: 588 + - uid: 81 + components: + - type: Transform + pos: 19.5,12.5 + parent: 588 + - uid: 82 + components: + - type: Transform + pos: 19.5,15.5 + parent: 588 + - uid: 83 + components: + - type: Transform + pos: 19.5,16.5 + parent: 588 + - uid: 84 + components: + - type: Transform + pos: 14.5,14.5 + parent: 588 + - uid: 85 + components: + - type: Transform + pos: 13.5,14.5 + parent: 588 + - uid: 86 + components: + - type: Transform + pos: 12.5,14.5 + parent: 588 + - uid: 87 + components: + - type: Transform + pos: 11.5,14.5 + parent: 588 + - uid: 88 + components: + - type: Transform + pos: 10.5,14.5 + parent: 588 + - uid: 89 + components: + - type: Transform + pos: 9.5,14.5 + parent: 588 + - uid: 90 + components: + - type: Transform + pos: 8.5,14.5 + parent: 588 + - uid: 91 + components: + - type: Transform + pos: 11.5,13.5 + parent: 588 + - uid: 92 + components: + - type: Transform + pos: 11.5,12.5 + parent: 588 + - uid: 93 + components: + - type: Transform + pos: 11.5,15.5 + parent: 588 + - uid: 94 + components: + - type: Transform + pos: 11.5,16.5 + parent: 588 + - uid: 95 + components: + - type: Transform + pos: 6.5,14.5 + parent: 588 + - uid: 96 + components: + - type: Transform + pos: 5.5,14.5 + parent: 588 + - uid: 98 + components: + - type: Transform + pos: 4.5,22.5 + parent: 588 + - uid: 100 + components: + - type: Transform + pos: 1.5,14.5 + parent: 588 + - uid: 101 + components: + - type: Transform + pos: 0.5,14.5 + parent: 588 + - uid: 102 + components: + - type: Transform + pos: 3.5,15.5 + parent: 588 + - uid: 103 + components: + - type: Transform + pos: 3.5,16.5 + parent: 588 + - uid: 104 + components: + - type: Transform + pos: 3.5,13.5 + parent: 588 + - uid: 105 + components: + - type: Transform + pos: 3.5,12.5 + parent: 588 + - uid: 106 + components: + - type: Transform + pos: 14.5,18.5 + parent: 588 + - uid: 107 + components: + - type: Transform + pos: 14.5,19.5 + parent: 588 + - uid: 108 + components: + - type: Transform + pos: 14.5,20.5 + parent: 588 + - uid: 109 + components: + - type: Transform + pos: 14.5,21.5 + parent: 588 + - uid: 110 + components: + - type: Transform + pos: 14.5,22.5 + parent: 588 + - uid: 111 + components: + - type: Transform + pos: 15.5,20.5 + parent: 588 + - uid: 112 + components: + - type: Transform + pos: 16.5,20.5 + parent: 588 + - uid: 113 + components: + - type: Transform + pos: 13.5,20.5 + parent: 588 + - uid: 114 + components: + - type: Transform + pos: 12.5,20.5 + parent: 588 + - uid: 115 + components: + - type: Transform + pos: 8.5,18.5 + parent: 588 + - uid: 116 + components: + - type: Transform + pos: 8.5,19.5 + parent: 588 + - uid: 117 + components: + - type: Transform + pos: 8.5,20.5 + parent: 588 + - uid: 118 + components: + - type: Transform + pos: 8.5,21.5 + parent: 588 + - uid: 119 + components: + - type: Transform + pos: 8.5,22.5 + parent: 588 + - uid: 120 + components: + - type: Transform + pos: 9.5,20.5 + parent: 588 + - uid: 121 + components: + - type: Transform + pos: 10.5,20.5 + parent: 588 + - uid: 122 + components: + - type: Transform + pos: 7.5,20.5 + parent: 588 + - uid: 123 + components: + - type: Transform + pos: 6.5,20.5 + parent: 588 + - uid: 124 + components: + - type: Transform + pos: 2.5,22.5 + parent: 588 + - uid: 125 + components: + - type: Transform + pos: 4.5,21.5 + parent: 588 + - uid: 126 + components: + - type: Transform + pos: 4.5,19.5 + parent: 588 + - uid: 127 + components: + - type: Transform + pos: 3.5,18.5 + parent: 588 + - uid: 128 + components: + - type: Transform + pos: 2.5,18.5 + parent: 588 + - uid: 129 + components: + - type: Transform + pos: 3.5,22.5 + parent: 588 + - uid: 130 + components: + - type: Transform + pos: 0.5,20.5 + parent: 588 + - uid: 131 + components: + - type: Transform + pos: 4.5,18.5 + parent: 588 + - uid: 132 + components: + - type: Transform + pos: 4.5,20.5 + parent: 588 + - uid: 133 + components: + - type: Transform + pos: 1.5,24.5 + parent: 588 + - uid: 134 + components: + - type: Transform + pos: 2.5,25.5 + parent: 588 + - uid: 135 + components: + - type: Transform + pos: 0.5,24.5 + parent: 588 + - uid: 136 + components: + - type: Transform + pos: 2.5,24.5 + parent: 588 + - uid: 137 + components: + - type: Transform + pos: 1.5,28.5 + parent: 588 + - uid: 138 + components: + - type: Transform + pos: 0.5,26.5 + parent: 588 + - uid: 139 + components: + - type: Transform + pos: 2.5,26.5 + parent: 588 + - uid: 147 + components: + - type: Transform + pos: 9.5,28.5 + parent: 588 + - uid: 148 + components: + - type: Transform + pos: 9.5,27.5 + parent: 588 + - uid: 149 + components: + - type: Transform + pos: 9.5,26.5 + parent: 588 + - uid: 150 + components: + - type: Transform + pos: 9.5,25.5 + parent: 588 + - uid: 151 + components: + - type: Transform + pos: 9.5,24.5 + parent: 588 + - uid: 152 + components: + - type: Transform + pos: 8.5,26.5 + parent: 588 + - uid: 153 + components: + - type: Transform + pos: 10.5,26.5 + parent: 588 + - uid: 154 + components: + - type: Transform + pos: 13.5,28.5 + parent: 588 + - uid: 155 + components: + - type: Transform + pos: 13.5,27.5 + parent: 588 + - uid: 156 + components: + - type: Transform + pos: 13.5,26.5 + parent: 588 + - uid: 157 + components: + - type: Transform + pos: 13.5,25.5 + parent: 588 + - uid: 158 + components: + - type: Transform + pos: 13.5,24.5 + parent: 588 + - uid: 159 + components: + - type: Transform + pos: 12.5,26.5 + parent: 588 + - uid: 160 + components: + - type: Transform + pos: 14.5,26.5 + parent: 588 + - uid: 161 + components: + - type: Transform + pos: 0.5,31.5 + parent: 588 + - uid: 162 + components: + - type: Transform + pos: 1.5,31.5 + parent: 588 + - uid: 163 + components: + - type: Transform + pos: 2.5,31.5 + parent: 588 + - uid: 164 + components: + - type: Transform + pos: 3.5,31.5 + parent: 588 + - uid: 165 + components: + - type: Transform + pos: 4.5,31.5 + parent: 588 + - uid: 166 + components: + - type: Transform + pos: 5.5,31.5 + parent: 588 + - uid: 167 + components: + - type: Transform + pos: 6.5,31.5 + parent: 588 + - uid: 168 + components: + - type: Transform + pos: 7.5,31.5 + parent: 588 + - uid: 169 + components: + - type: Transform + pos: 8.5,31.5 + parent: 588 + - uid: 170 + components: + - type: Transform + pos: 9.5,31.5 + parent: 588 + - uid: 171 + components: + - type: Transform + pos: 10.5,31.5 + parent: 588 + - uid: 172 + components: + - type: Transform + pos: 11.5,31.5 + parent: 588 + - uid: 173 + components: + - type: Transform + pos: 12.5,31.5 + parent: 588 + - uid: 174 + components: + - type: Transform + pos: 6.5,30.5 + parent: 588 + - uid: 175 + components: + - type: Transform + pos: 6.5,32.5 + parent: 588 + - uid: 176 + components: + - type: Transform + pos: 26.5,31.5 + parent: 588 + - uid: 177 + components: + - type: Transform + pos: 25.5,31.5 + parent: 588 + - uid: 178 + components: + - type: Transform + pos: 24.5,31.5 + parent: 588 + - uid: 179 + components: + - type: Transform + pos: 23.5,31.5 + parent: 588 + - uid: 180 + components: + - type: Transform + pos: 22.5,31.5 + parent: 588 + - uid: 181 + components: + - type: Transform + pos: 21.5,31.5 + parent: 588 + - uid: 182 + components: + - type: Transform + pos: 20.5,31.5 + parent: 588 + - uid: 183 + components: + - type: Transform + pos: 19.5,31.5 + parent: 588 + - uid: 184 + components: + - type: Transform + pos: 18.5,31.5 + parent: 588 + - uid: 185 + components: + - type: Transform + pos: 17.5,31.5 + parent: 588 + - uid: 186 + components: + - type: Transform + pos: 16.5,31.5 + parent: 588 + - uid: 187 + components: + - type: Transform + pos: 15.5,31.5 + parent: 588 + - uid: 188 + components: + - type: Transform + pos: 14.5,31.5 + parent: 588 + - uid: 189 + components: + - type: Transform + pos: 20.5,32.5 + parent: 588 + - uid: 190 + components: + - type: Transform + pos: 20.5,30.5 + parent: 588 + - uid: 191 + components: + - type: Transform + pos: 22.5,35.5 + parent: 588 + - uid: 192 + components: + - type: Transform + pos: 21.5,35.5 + parent: 588 + - uid: 193 + components: + - type: Transform + pos: 20.5,35.5 + parent: 588 + - uid: 194 + components: + - type: Transform + pos: 19.5,35.5 + parent: 588 + - uid: 195 + components: + - type: Transform + pos: 18.5,35.5 + parent: 588 + - uid: 196 + components: + - type: Transform + pos: 17.5,35.5 + parent: 588 + - uid: 197 + components: + - type: Transform + pos: 16.5,35.5 + parent: 588 + - uid: 198 + components: + - type: Transform + pos: 15.5,35.5 + parent: 588 + - uid: 199 + components: + - type: Transform + pos: 14.5,35.5 + parent: 588 + - uid: 200 + components: + - type: Transform + pos: 13.5,35.5 + parent: 588 + - uid: 201 + components: + - type: Transform + pos: 12.5,35.5 + parent: 588 + - uid: 202 + components: + - type: Transform + pos: 17.5,36.5 + parent: 588 + - uid: 203 + components: + - type: Transform + pos: 17.5,34.5 + parent: 588 + - uid: 204 + components: + - type: Transform + pos: 10.5,35.5 + parent: 588 + - uid: 215 + components: + - type: Transform + pos: 5.5,36.5 + parent: 588 + - uid: 216 + components: + - type: Transform + pos: 5.5,34.5 + parent: 588 + - uid: 217 + components: + - type: Transform + pos: 0.5,39.5 + parent: 588 + - uid: 218 + components: + - type: Transform + pos: 1.5,39.5 + parent: 588 + - uid: 219 + components: + - type: Transform + pos: 2.5,39.5 + parent: 588 + - uid: 220 + components: + - type: Transform + pos: 3.5,39.5 + parent: 588 + - uid: 221 + components: + - type: Transform + pos: 4.5,39.5 + parent: 588 + - uid: 222 + components: + - type: Transform + pos: 5.5,39.5 + parent: 588 + - uid: 223 + components: + - type: Transform + pos: 6.5,39.5 + parent: 588 + - uid: 224 + components: + - type: Transform + pos: 3.5,38.5 + parent: 588 + - uid: 225 + components: + - type: Transform + pos: 3.5,40.5 + parent: 588 + - uid: 226 + components: + - type: Transform + pos: 8.5,39.5 + parent: 588 + - uid: 227 + components: + - type: Transform + pos: 9.5,39.5 + parent: 588 + - uid: 228 + components: + - type: Transform + pos: 10.5,39.5 + parent: 588 + - uid: 229 + components: + - type: Transform + pos: 11.5,39.5 + parent: 588 + - uid: 230 + components: + - type: Transform + pos: 12.5,39.5 + parent: 588 + - uid: 231 + components: + - type: Transform + pos: 13.5,39.5 + parent: 588 + - uid: 232 + components: + - type: Transform + pos: 14.5,39.5 + parent: 588 + - uid: 233 + components: + - type: Transform + pos: 11.5,38.5 + parent: 588 + - uid: 234 + components: + - type: Transform + pos: 11.5,40.5 + parent: 588 + - uid: 235 + components: + - type: Transform + pos: 16.5,39.5 + parent: 588 + - uid: 236 + components: + - type: Transform + pos: 17.5,39.5 + parent: 588 + - uid: 237 + components: + - type: Transform + pos: 18.5,39.5 + parent: 588 + - uid: 238 + components: + - type: Transform + pos: 19.5,39.5 + parent: 588 + - uid: 239 + components: + - type: Transform + pos: 20.5,39.5 + parent: 588 + - uid: 240 + components: + - type: Transform + pos: 21.5,39.5 + parent: 588 + - uid: 241 + components: + - type: Transform + pos: 22.5,39.5 + parent: 588 + - uid: 242 + components: + - type: Transform + pos: 19.5,40.5 + parent: 588 + - uid: 243 + components: + - type: Transform + pos: 19.5,38.5 + parent: 588 + - uid: 284 + components: + - type: Transform + pos: 29.5,26.5 + parent: 588 + - uid: 288 + components: + - type: Transform + pos: 28.5,26.5 + parent: 588 + - uid: 425 + components: + - type: Transform + pos: 1.5,10.5 + parent: 588 + - uid: 438 + components: + - type: Transform + pos: 1.5,9.5 + parent: 588 + - uid: 441 + components: + - type: Transform + pos: 2.5,10.5 + parent: 588 + - uid: 442 + components: + - type: Transform + pos: 3.5,10.5 + parent: 588 + - uid: 443 + components: + - type: Transform + pos: 4.5,10.5 + parent: 588 + - uid: 444 + components: + - type: Transform + pos: 1.5,7.5 + parent: 588 + - uid: 445 + components: + - type: Transform + pos: 1.5,6.5 + parent: 588 + - uid: 446 + components: + - type: Transform + pos: 2.5,6.5 + parent: 588 + - uid: 447 + components: + - type: Transform + pos: 3.5,6.5 + parent: 588 + - uid: 448 + components: + - type: Transform + pos: 4.5,6.5 + parent: 588 + - uid: 449 + components: + - type: Transform + pos: 6.5,6.5 + parent: 588 + - uid: 450 + components: + - type: Transform + pos: 7.5,6.5 + parent: 588 + - uid: 451 + components: + - type: Transform + pos: 8.5,6.5 + parent: 588 + - uid: 452 + components: + - type: Transform + pos: 9.5,6.5 + parent: 588 + - uid: 453 + components: + - type: Transform + pos: 9.5,7.5 + parent: 588 + - uid: 454 + components: + - type: Transform + pos: 9.5,9.5 + parent: 588 + - uid: 455 + components: + - type: Transform + pos: 9.5,10.5 + parent: 588 + - uid: 456 + components: + - type: Transform + pos: 8.5,10.5 + parent: 588 + - uid: 457 + components: + - type: Transform + pos: 7.5,10.5 + parent: 588 + - uid: 472 + components: + - type: Transform + pos: 29.5,14.5 + parent: 588 + - uid: 477 + components: + - type: Transform + pos: 24.5,13.5 + parent: 588 + - uid: 479 + components: + - type: Transform + pos: 30.5,14.5 + parent: 588 + - uid: 493 + components: + - type: Transform + pos: 25.5,13.5 + parent: 588 + - uid: 494 + components: + - type: Transform + pos: 25.5,12.5 + parent: 588 + - uid: 495 + components: + - type: Transform + pos: 26.5,12.5 + parent: 588 + - uid: 496 + components: + - type: Transform + pos: 27.5,12.5 + parent: 588 + - uid: 497 + components: + - type: Transform + pos: 28.5,12.5 + parent: 588 + - uid: 498 + components: + - type: Transform + pos: 29.5,12.5 + parent: 588 + - uid: 500 + components: + - type: Transform + pos: 24.5,12.5 + parent: 588 + - uid: 502 + components: + - type: Transform + pos: 24.5,14.5 + parent: 588 + - uid: 503 + components: + - type: Transform + pos: 24.5,15.5 + parent: 588 + - uid: 504 + components: + - type: Transform + pos: 24.5,16.5 + parent: 588 + - uid: 505 + components: + - type: Transform + pos: 25.5,16.5 + parent: 588 + - uid: 506 + components: + - type: Transform + pos: 26.5,16.5 + parent: 588 + - uid: 507 + components: + - type: Transform + pos: 27.5,16.5 + parent: 588 + - uid: 508 + components: + - type: Transform + pos: 28.5,16.5 + parent: 588 + - uid: 509 + components: + - type: Transform + pos: 29.5,16.5 + parent: 588 + - uid: 514 + components: + - type: Transform + pos: 29.5,13.5 + parent: 588 + - uid: 523 + components: + - type: Transform + pos: 29.5,15.5 + parent: 588 + - uid: 628 + components: + - type: Transform + pos: 1.5,22.5 + parent: 588 + - uid: 639 + components: + - type: Transform + pos: 0.5,22.5 + parent: 588 + - uid: 640 + components: + - type: Transform + pos: 0.5,21.5 + parent: 588 + - uid: 641 + components: + - type: Transform + pos: 0.5,19.5 + parent: 588 + - uid: 642 + components: + - type: Transform + pos: 0.5,18.5 + parent: 588 + - uid: 643 + components: + - type: Transform + pos: 1.5,18.5 + parent: 588 + - uid: 657 + components: + - type: Transform + pos: 2.5,15.5 + parent: 588 + - uid: 661 + components: + - type: Transform + pos: 1.5,15.5 + parent: 588 + - uid: 662 + components: + - type: Transform + pos: 1.5,13.5 + parent: 588 + - uid: 663 + components: + - type: Transform + pos: 2.5,13.5 + parent: 588 + - uid: 664 + components: + - type: Transform + pos: 4.5,13.5 + parent: 588 + - uid: 665 + components: + - type: Transform + pos: 5.5,13.5 + parent: 588 + - uid: 666 + components: + - type: Transform + pos: 5.5,15.5 + parent: 588 + - uid: 667 + components: + - type: Transform + pos: 4.5,15.5 + parent: 588 + - uid: 668 + components: + - type: Transform + pos: 29.5,10.5 + parent: 588 + - uid: 669 + components: + - type: Transform + pos: 28.5,10.5 + parent: 588 + - uid: 670 + components: + - type: Transform + pos: 27.5,10.5 + parent: 588 + - uid: 671 + components: + - type: Transform + pos: 26.5,10.5 + parent: 588 + - uid: 672 + components: + - type: Transform + pos: 25.5,10.5 + parent: 588 + - uid: 673 + components: + - type: Transform + pos: 24.5,10.5 + parent: 588 + - uid: 674 + components: + - type: Transform + pos: 24.5,9.5 + parent: 588 + - uid: 675 + components: + - type: Transform + pos: 24.5,8.5 + parent: 588 + - uid: 676 + components: + - type: Transform + pos: 24.5,7.5 + parent: 588 + - uid: 677 + components: + - type: Transform + pos: 24.5,6.5 + parent: 588 + - uid: 678 + components: + - type: Transform + pos: 25.5,6.5 + parent: 588 + - uid: 679 + components: + - type: Transform + pos: 26.5,6.5 + parent: 588 + - uid: 680 + components: + - type: Transform + pos: 27.5,6.5 + parent: 588 + - uid: 681 + components: + - type: Transform + pos: 28.5,6.5 + parent: 588 + - uid: 682 + components: + - type: Transform + pos: 29.5,6.5 + parent: 588 + - uid: 683 + components: + - type: Transform + pos: 30.5,6.5 + parent: 588 + - uid: 684 + components: + - type: Transform + pos: 31.5,6.5 + parent: 588 + - uid: 685 + components: + - type: Transform + pos: 32.5,6.5 + parent: 588 + - uid: 686 + components: + - type: Transform + pos: 33.5,6.5 + parent: 588 + - uid: 687 + components: + - type: Transform + pos: 34.5,6.5 + parent: 588 + - uid: 688 + components: + - type: Transform + pos: 34.5,7.5 + parent: 588 + - uid: 689 + components: + - type: Transform + pos: 34.5,8.5 + parent: 588 + - uid: 690 + components: + - type: Transform + pos: 34.5,9.5 + parent: 588 + - uid: 691 + components: + - type: Transform + pos: 34.5,10.5 + parent: 588 + - uid: 692 + components: + - type: Transform + pos: 33.5,10.5 + parent: 588 + - uid: 693 + components: + - type: Transform + pos: 32.5,10.5 + parent: 588 + - uid: 694 + components: + - type: Transform + pos: 31.5,10.5 + parent: 588 + - uid: 695 + components: + - type: Transform + pos: 30.5,10.5 + parent: 588 + - uid: 733 + components: + - type: Transform + pos: 20.5,18.5 + parent: 588 + - uid: 734 + components: + - type: Transform + pos: 20.5,19.5 + parent: 588 + - uid: 735 + components: + - type: Transform + pos: 20.5,20.5 + parent: 588 + - uid: 736 + components: + - type: Transform + pos: 20.5,21.5 + parent: 588 + - uid: 737 + components: + - type: Transform + pos: 20.5,22.5 + parent: 588 + - uid: 738 + components: + - type: Transform + pos: 21.5,20.5 + parent: 588 + - uid: 739 + components: + - type: Transform + pos: 22.5,20.5 + parent: 588 + - uid: 740 + components: + - type: Transform + pos: 19.5,20.5 + parent: 588 + - uid: 741 + components: + - type: Transform + pos: 18.5,20.5 + parent: 588 + - uid: 751 + components: + - type: Transform + pos: 32.5,22.5 + parent: 588 + - uid: 752 + components: + - type: Transform + pos: 32.5,21.5 + parent: 588 + - uid: 753 + components: + - type: Transform + pos: 32.5,20.5 + parent: 588 + - uid: 754 + components: + - type: Transform + pos: 32.5,19.5 + parent: 588 + - uid: 755 + components: + - type: Transform + pos: 32.5,18.5 + parent: 588 + - uid: 756 + components: + - type: Transform + pos: 31.5,20.5 + parent: 588 + - uid: 757 + components: + - type: Transform + pos: 30.5,20.5 + parent: 588 + - uid: 758 + components: + - type: Transform + pos: 33.5,20.5 + parent: 588 + - uid: 759 + components: + - type: Transform + pos: 34.5,20.5 + parent: 588 + - uid: 779 + components: + - type: Transform + pos: 25.5,19.5 + parent: 588 + - uid: 780 + components: + - type: Transform + pos: 25.5,18.5 + parent: 588 + - uid: 781 + components: + - type: Transform + pos: 24.5,18.5 + parent: 588 + - uid: 782 + components: + - type: Transform + pos: 24.5,19.5 + parent: 588 + - uid: 783 + components: + - type: Transform + pos: 24.5,20.5 + parent: 588 + - uid: 784 + components: + - type: Transform + pos: 24.5,21.5 + parent: 588 + - uid: 785 + components: + - type: Transform + pos: 24.5,22.5 + parent: 588 + - uid: 786 + components: + - type: Transform + pos: 25.5,22.5 + parent: 588 + - uid: 787 + components: + - type: Transform + pos: 26.5,22.5 + parent: 588 + - uid: 788 + components: + - type: Transform + pos: 27.5,22.5 + parent: 588 + - uid: 789 + components: + - type: Transform + pos: 28.5,22.5 + parent: 588 + - uid: 790 + components: + - type: Transform + pos: 28.5,21.5 + parent: 588 + - uid: 791 + components: + - type: Transform + pos: 28.5,20.5 + parent: 588 + - uid: 792 + components: + - type: Transform + pos: 28.5,19.5 + parent: 588 + - uid: 793 + components: + - type: Transform + pos: 28.5,18.5 + parent: 588 + - uid: 794 + components: + - type: Transform + pos: 27.5,18.5 + parent: 588 + - uid: 795 + components: + - type: Transform + pos: 26.5,18.5 + parent: 588 + - uid: 815 + components: + - type: Transform + pos: 0.5,25.5 + parent: 588 + - uid: 816 + components: + - type: Transform + pos: 0.5,27.5 + parent: 588 + - uid: 817 + components: + - type: Transform + pos: 0.5,28.5 + parent: 588 + - uid: 818 + components: + - type: Transform + pos: 2.5,28.5 + parent: 588 + - uid: 819 + components: + - type: Transform + pos: 2.5,27.5 + parent: 588 + - uid: 869 + components: + - type: Transform + pos: 5.5,24.5 + parent: 588 + - uid: 870 + components: + - type: Transform + pos: 6.5,24.5 + parent: 588 + - uid: 871 + components: + - type: Transform + pos: 6.5,25.5 + parent: 588 + - uid: 872 + components: + - type: Transform + pos: 6.5,26.5 + parent: 588 + - uid: 873 + components: + - type: Transform + pos: 6.5,27.5 + parent: 588 + - uid: 874 + components: + - type: Transform + pos: 6.5,28.5 + parent: 588 + - uid: 875 + components: + - type: Transform + pos: 5.5,28.5 + parent: 588 + - uid: 876 + components: + - type: Transform + pos: 4.5,28.5 + parent: 588 + - uid: 877 + components: + - type: Transform + pos: 4.5,27.5 + parent: 588 + - uid: 878 + components: + - type: Transform + pos: 4.5,26.5 + parent: 588 + - uid: 912 + components: + - type: Transform + pos: 6.5,10.5 + parent: 588 + - uid: 927 + components: + - type: Transform + pos: 34.5,36.5 + parent: 588 + - uid: 928 + components: + - type: Transform + pos: 32.5,36.5 + parent: 588 + - uid: 996 + components: + - type: Transform + pos: 21.5,32.5 + parent: 588 + - uid: 1079 + components: + - type: Transform + pos: 32.5,35.5 + parent: 588 + - uid: 1080 + components: + - type: Transform + pos: 31.5,35.5 + parent: 588 + - uid: 1081 + components: + - type: Transform + pos: 32.5,34.5 + parent: 588 + - uid: 1082 + components: + - type: Transform + pos: 29.5,34.5 + parent: 588 + - uid: 1083 + components: + - type: Transform + pos: 24.5,35.5 + parent: 588 + - uid: 1084 + components: + - type: Transform + pos: 27.5,35.5 + parent: 588 + - uid: 1085 + components: + - type: Transform + pos: 29.5,35.5 + parent: 588 + - uid: 1086 + components: + - type: Transform + pos: 28.5,35.5 + parent: 588 + - uid: 1089 + components: + - type: Transform + pos: 4.5,36.5 + parent: 588 + - uid: 1090 + components: + - type: Transform + pos: 33.5,34.5 + parent: 588 + - uid: 1091 + components: + - type: Transform + pos: 5.5,35.5 + parent: 588 + - uid: 1092 + components: + - type: Transform + pos: 29.5,36.5 + parent: 588 + - uid: 1093 + components: + - type: Transform + pos: 34.5,34.5 + parent: 588 + - uid: 1094 + components: + - type: Transform + pos: 34.5,35.5 + parent: 588 + - uid: 1095 + components: + - type: Transform + pos: 26.5,35.5 + parent: 588 + - uid: 1096 + components: + - type: Transform + pos: 25.5,35.5 + parent: 588 + - uid: 1097 + components: + - type: Transform + pos: 33.5,36.5 + parent: 588 + - uid: 1098 + components: + - type: Transform + pos: 30.5,35.5 + parent: 588 + - uid: 1117 + components: + - type: Transform + pos: 16.5,26.5 + parent: 588 + - uid: 1121 + components: + - type: Transform + pos: 17.5,26.5 + parent: 588 + - uid: 1122 + components: + - type: Transform + pos: 18.5,26.5 + parent: 588 + - uid: 1123 + components: + - type: Transform + pos: 17.5,27.5 + parent: 588 + - uid: 1124 + components: + - type: Transform + pos: 17.5,28.5 + parent: 588 + - uid: 1125 + components: + - type: Transform + pos: 17.5,24.5 + parent: 588 + - uid: 1126 + components: + - type: Transform + pos: 17.5,25.5 + parent: 588 + - uid: 1127 + components: + - type: Transform + pos: 20.5,26.5 + parent: 588 + - uid: 1128 + components: + - type: Transform + pos: 21.5,26.5 + parent: 588 + - uid: 1129 + components: + - type: Transform + pos: 22.5,26.5 + parent: 588 + - uid: 1130 + components: + - type: Transform + pos: 21.5,27.5 + parent: 588 + - uid: 1131 + components: + - type: Transform + pos: 21.5,28.5 + parent: 588 + - uid: 1132 + components: + - type: Transform + pos: 21.5,25.5 + parent: 588 + - uid: 1133 + components: + - type: Transform + pos: 21.5,24.5 + parent: 588 + - uid: 1134 + components: + - type: Transform + pos: 24.5,26.5 + parent: 588 + - uid: 1135 + components: + - type: Transform + pos: 25.5,26.5 + parent: 588 + - uid: 1136 + components: + - type: Transform + pos: 26.5,26.5 + parent: 588 + - uid: 1137 + components: + - type: Transform + pos: 25.5,27.5 + parent: 588 + - uid: 1138 + components: + - type: Transform + pos: 25.5,28.5 + parent: 588 + - uid: 1139 + components: + - type: Transform + pos: 25.5,25.5 + parent: 588 + - uid: 1140 + components: + - type: Transform + pos: 25.5,24.5 + parent: 588 + - uid: 1170 + components: + - type: Transform + pos: 3.5,36.5 + parent: 588 + - uid: 1171 + components: + - type: Transform + pos: 2.5,36.5 + parent: 588 + - uid: 1172 + components: + - type: Transform + pos: 1.5,36.5 + parent: 588 + - uid: 1173 + components: + - type: Transform + pos: 0.5,36.5 + parent: 588 + - uid: 1174 + components: + - type: Transform + pos: 0.5,35.5 + parent: 588 + - uid: 1175 + components: + - type: Transform + pos: 6.5,34.5 + parent: 588 + - uid: 1176 + components: + - type: Transform + pos: 7.5,34.5 + parent: 588 + - uid: 1177 + components: + - type: Transform + pos: 8.5,34.5 + parent: 588 + - uid: 1178 + components: + - type: Transform + pos: 9.5,34.5 + parent: 588 + - uid: 1179 + components: + - type: Transform + pos: 10.5,34.5 + parent: 588 + - uid: 1268 + components: + - type: Transform + pos: 30.5,26.5 + parent: 588 + - uid: 1269 + components: + - type: Transform + pos: 29.5,27.5 + parent: 588 + - uid: 1270 + components: + - type: Transform + pos: 29.5,28.5 + parent: 588 + - uid: 1271 + components: + - type: Transform + pos: 29.5,25.5 + parent: 588 + - uid: 1272 + components: + - type: Transform + pos: 29.5,24.5 + parent: 588 + - uid: 1273 + components: + - type: Transform + pos: 32.5,26.5 + parent: 588 + - uid: 1274 + components: + - type: Transform + pos: 33.5,26.5 + parent: 588 + - uid: 1275 + components: + - type: Transform + pos: 34.5,26.5 + parent: 588 + - uid: 1276 + components: + - type: Transform + pos: 33.5,27.5 + parent: 588 + - uid: 1277 + components: + - type: Transform + pos: 33.5,28.5 + parent: 588 + - uid: 1278 + components: + - type: Transform + pos: 33.5,25.5 + parent: 588 + - uid: 1279 + components: + - type: Transform + pos: 33.5,24.5 + parent: 588 + - uid: 1306 + components: + - type: Transform + pos: 27.5,40.5 + parent: 588 + - uid: 1307 + components: + - type: Transform + pos: 26.5,40.5 + parent: 588 + - uid: 1308 + components: + - type: Transform + pos: 25.5,40.5 + parent: 588 + - uid: 1309 + components: + - type: Transform + pos: 24.5,40.5 + parent: 588 + - uid: 1310 + components: + - type: Transform + pos: 24.5,39.5 + parent: 588 + - uid: 1311 + components: + - type: Transform + pos: 24.5,38.5 + parent: 588 + - uid: 1312 + components: + - type: Transform + pos: 25.5,38.5 + parent: 588 + - uid: 1313 + components: + - type: Transform + pos: 26.5,38.5 + parent: 588 + - uid: 1314 + components: + - type: Transform + pos: 27.5,38.5 + parent: 588 + - uid: 1315 + components: + - type: Transform + pos: 28.5,38.5 + parent: 588 + - uid: 1316 + components: + - type: Transform + pos: 29.5,38.5 + parent: 588 + - uid: 1317 + components: + - type: Transform + pos: 30.5,38.5 + parent: 588 + - uid: 1318 + components: + - type: Transform + pos: 30.5,39.5 + parent: 588 + - uid: 1426 + components: + - type: Transform + pos: 11.5,42.5 + parent: 588 + - uid: 1427 + components: + - type: Transform + pos: 11.5,43.5 + parent: 588 + - uid: 1428 + components: + - type: Transform + pos: 11.5,44.5 + parent: 588 + - uid: 1429 + components: + - type: Transform + pos: 11.5,45.5 + parent: 588 + - uid: 1430 + components: + - type: Transform + pos: 11.5,46.5 + parent: 588 + - uid: 1431 + components: + - type: Transform + pos: 11.5,47.5 + parent: 588 + - uid: 1432 + components: + - type: Transform + pos: 11.5,48.5 + parent: 588 + - uid: 1433 + components: + - type: Transform + pos: 10.5,45.5 + parent: 588 + - uid: 1434 + components: + - type: Transform + pos: 9.5,45.5 + parent: 588 + - uid: 1435 + components: + - type: Transform + pos: 8.5,45.5 + parent: 588 + - uid: 1436 + components: + - type: Transform + pos: 12.5,45.5 + parent: 588 + - uid: 1437 + components: + - type: Transform + pos: 13.5,45.5 + parent: 588 + - uid: 1438 + components: + - type: Transform + pos: 14.5,45.5 + parent: 588 + - uid: 1439 + components: + - type: Transform + pos: 13.5,46.5 + parent: 588 + - uid: 1440 + components: + - type: Transform + pos: 13.5,47.5 + parent: 588 + - uid: 1441 + components: + - type: Transform + pos: 9.5,46.5 + parent: 588 + - uid: 1442 + components: + - type: Transform + pos: 9.5,47.5 + parent: 588 + - uid: 1443 + components: + - type: Transform + pos: 10.5,43.5 + parent: 588 + - uid: 1444 + components: + - type: Transform + pos: 9.5,43.5 + parent: 588 + - uid: 1445 + components: + - type: Transform + pos: 12.5,43.5 + parent: 588 + - uid: 1446 + components: + - type: Transform + pos: 13.5,43.5 + parent: 588 + - uid: 1447 + components: + - type: Transform + pos: 3.5,42.5 + parent: 588 + - uid: 1448 + components: + - type: Transform + pos: 3.5,43.5 + parent: 588 + - uid: 1449 + components: + - type: Transform + pos: 3.5,44.5 + parent: 588 + - uid: 1450 + components: + - type: Transform + pos: 3.5,45.5 + parent: 588 + - uid: 1451 + components: + - type: Transform + pos: 3.5,46.5 + parent: 588 + - uid: 1452 + components: + - type: Transform + pos: 3.5,47.5 + parent: 588 + - uid: 1453 + components: + - type: Transform + pos: 3.5,48.5 + parent: 588 + - uid: 1454 + components: + - type: Transform + pos: 0.5,45.5 + parent: 588 + - uid: 1455 + components: + - type: Transform + pos: 1.5,45.5 + parent: 588 + - uid: 1456 + components: + - type: Transform + pos: 2.5,45.5 + parent: 588 + - uid: 1457 + components: + - type: Transform + pos: 3.5,45.5 + parent: 588 + - uid: 1458 + components: + - type: Transform + pos: 4.5,45.5 + parent: 588 + - uid: 1459 + components: + - type: Transform + pos: 5.5,45.5 + parent: 588 + - uid: 1460 + components: + - type: Transform + pos: 6.5,45.5 + parent: 588 + - uid: 1529 + components: + - type: Transform + pos: 19.5,47.5 + parent: 588 + - uid: 1530 + components: + - type: Transform + pos: 19.5,48.5 + parent: 588 + - uid: 1531 + components: + - type: Transform + pos: 18.5,48.5 + parent: 588 + - uid: 1532 + components: + - type: Transform + pos: 17.5,48.5 + parent: 588 + - uid: 1533 + components: + - type: Transform + pos: 16.5,48.5 + parent: 588 + - uid: 1534 + components: + - type: Transform + pos: 16.5,47.5 + parent: 588 + - uid: 1535 + components: + - type: Transform + pos: 16.5,46.5 + parent: 588 + - uid: 1536 + components: + - type: Transform + pos: 16.5,45.5 + parent: 588 + - uid: 1537 + components: + - type: Transform + pos: 16.5,44.5 + parent: 588 + - uid: 1538 + components: + - type: Transform + pos: 16.5,43.5 + parent: 588 + - uid: 1539 + components: + - type: Transform + pos: 16.5,42.5 + parent: 588 + - uid: 1540 + components: + - type: Transform + pos: 17.5,42.5 + parent: 588 + - uid: 1541 + components: + - type: Transform + pos: 18.5,42.5 + parent: 588 + - uid: 1542 + components: + - type: Transform + pos: 19.5,42.5 + parent: 588 + - uid: 1543 + components: + - type: Transform + pos: 20.5,42.5 + parent: 588 + - uid: 1544 + components: + - type: Transform + pos: 21.5,42.5 + parent: 588 + - uid: 1545 + components: + - type: Transform + pos: 22.5,42.5 + parent: 588 + - uid: 1546 + components: + - type: Transform + pos: 22.5,43.5 + parent: 588 + - uid: 1547 + components: + - type: Transform + pos: 22.5,44.5 + parent: 588 + - uid: 1548 + components: + - type: Transform + pos: 22.5,45.5 + parent: 588 + - uid: 1549 + components: + - type: Transform + pos: 22.5,46.5 + parent: 588 + - uid: 1550 + components: + - type: Transform + pos: 22.5,47.5 + parent: 588 + - uid: 1551 + components: + - type: Transform + pos: 22.5,48.5 + parent: 588 + - uid: 1552 + components: + - type: Transform + pos: 21.5,48.5 + parent: 588 + - uid: 1553 + components: + - type: Transform + pos: 20.5,48.5 + parent: 588 + - uid: 1554 + components: + - type: Transform + pos: 19.5,43.5 + parent: 588 + - uid: 1555 + components: + - type: Transform + pos: 19.5,44.5 + parent: 588 + - uid: 1556 + components: + - type: Transform + pos: 19.5,45.5 + parent: 588 + - uid: 1557 + components: + - type: Transform + pos: 19.5,46.5 + parent: 588 + - uid: 1807 + components: + - type: Transform + pos: 27.5,42.5 + parent: 588 + - uid: 1808 + components: + - type: Transform + pos: 27.5,43.5 + parent: 588 + - uid: 1809 + components: + - type: Transform + pos: 27.5,44.5 + parent: 588 + - uid: 1810 + components: + - type: Transform + pos: 27.5,45.5 + parent: 588 + - uid: 1811 + components: + - type: Transform + pos: 27.5,46.5 + parent: 588 + - uid: 1812 + components: + - type: Transform + pos: 27.5,47.5 + parent: 588 + - uid: 1813 + components: + - type: Transform + pos: 27.5,48.5 + parent: 588 + - uid: 1814 + components: + - type: Transform + pos: 28.5,45.5 + parent: 588 + - uid: 1815 + components: + - type: Transform + pos: 29.5,45.5 + parent: 588 + - uid: 1816 + components: + - type: Transform + pos: 30.5,45.5 + parent: 588 + - uid: 1817 + components: + - type: Transform + pos: 26.5,45.5 + parent: 588 + - uid: 1818 + components: + - type: Transform + pos: 25.5,45.5 + parent: 588 + - uid: 1819 + components: + - type: Transform + pos: 24.5,45.5 + parent: 588 + - uid: 1820 + components: + - type: Transform + pos: 26.5,47.5 + parent: 588 + - uid: 1821 + components: + - type: Transform + pos: 25.5,47.5 + parent: 588 + - uid: 1822 + components: + - type: Transform + pos: 28.5,47.5 + parent: 588 + - uid: 1823 + components: + - type: Transform + pos: 29.5,47.5 + parent: 588 + - uid: 1824 + components: + - type: Transform + pos: 26.5,43.5 + parent: 588 + - uid: 1825 + components: + - type: Transform + pos: 25.5,43.5 + parent: 588 + - uid: 1826 + components: + - type: Transform + pos: 28.5,43.5 + parent: 588 + - uid: 1827 + components: + - type: Transform + pos: 29.5,43.5 + parent: 588 +- proto: CableApcStack1 + entities: + - uid: 655 + components: + - type: Transform + pos: 16.273203,19.650417 + parent: 588 +- proto: CableHV + entities: + - uid: 462 + components: + - type: Transform + pos: 27.5,13.5 + parent: 588 + - uid: 466 + components: + - type: Transform + pos: 26.5,13.5 + parent: 588 + - uid: 468 + components: + - type: Transform + pos: 28.5,13.5 + parent: 588 + - uid: 485 + components: + - type: Transform + pos: 26.5,15.5 + parent: 588 + - uid: 486 + components: + - type: Transform + pos: 26.5,14.5 + parent: 588 + - uid: 487 + components: + - type: Transform + pos: 27.5,14.5 + parent: 588 + - uid: 488 + components: + - type: Transform + pos: 28.5,14.5 + parent: 588 + - uid: 489 + components: + - type: Transform + pos: 28.5,15.5 + parent: 588 + - uid: 743 + components: + - type: Transform + pos: 26.5,21.5 + parent: 588 + - uid: 744 + components: + - type: Transform + pos: 27.5,21.5 + parent: 588 + - uid: 745 + components: + - type: Transform + pos: 26.5,20.5 + parent: 588 + - uid: 746 + components: + - type: Transform + pos: 25.5,21.5 + parent: 588 + - uid: 768 + components: + - type: Transform + pos: 26.5,19.5 + parent: 588 + - uid: 778 + components: + - type: Transform + pos: 27.5,19.5 + parent: 588 + - uid: 978 + components: + - type: Transform + pos: 16.5,32.5 + parent: 588 + - uid: 979 + components: + - type: Transform + pos: 15.5,31.5 + parent: 588 + - uid: 980 + components: + - type: Transform + pos: 16.5,31.5 + parent: 588 + - uid: 981 + components: + - type: Transform + pos: 17.5,31.5 + parent: 588 + - uid: 982 + components: + - type: Transform + pos: 18.5,31.5 + parent: 588 + - uid: 983 + components: + - type: Transform + pos: 22.5,31.5 + parent: 588 + - uid: 984 + components: + - type: Transform + pos: 23.5,31.5 + parent: 588 + - uid: 985 + components: + - type: Transform + pos: 24.5,31.5 + parent: 588 + - uid: 986 + components: + - type: Transform + pos: 24.5,32.5 + parent: 588 + - uid: 987 + components: + - type: Transform + pos: 25.5,31.5 + parent: 588 + - uid: 989 + components: + - type: Transform + pos: 18.5,32.5 + parent: 588 + - uid: 990 + components: + - type: Transform + pos: 19.5,32.5 + parent: 588 + - uid: 991 + components: + - type: Transform + pos: 20.5,32.5 + parent: 588 + - uid: 992 + components: + - type: Transform + pos: 21.5,32.5 + parent: 588 + - uid: 993 + components: + - type: Transform + pos: 22.5,32.5 + parent: 588 + - uid: 1003 + components: + - type: Transform + pos: 16.5,30.5 + parent: 588 + - uid: 1004 + components: + - type: Transform + pos: 24.5,30.5 + parent: 588 + - uid: 1510 + components: + - type: Transform + pos: 18.5,44.5 + parent: 588 + - uid: 1511 + components: + - type: Transform + pos: 18.5,45.5 + parent: 588 + - uid: 1512 + components: + - type: Transform + pos: 20.5,45.5 + parent: 588 + - uid: 1513 + components: + - type: Transform + pos: 20.5,44.5 + parent: 588 + - uid: 1514 + components: + - type: Transform + pos: 19.5,44.5 + parent: 588 + - uid: 1522 + components: + - type: Transform + pos: 17.5,46.5 + parent: 588 + - uid: 1523 + components: + - type: Transform + pos: 21.5,46.5 + parent: 588 + - uid: 1524 + components: + - type: Transform + pos: 20.5,46.5 + parent: 588 + - uid: 1525 + components: + - type: Transform + pos: 18.5,46.5 + parent: 588 + - uid: 1526 + components: + - type: Transform + pos: 19.5,46.5 + parent: 588 +- proto: CableMV + entities: + - uid: 490 + components: + - type: Transform + pos: 27.5,13.5 + parent: 588 + - uid: 491 + components: + - type: Transform + pos: 26.5,13.5 + parent: 588 + - uid: 492 + components: + - type: Transform + pos: 25.5,13.5 + parent: 588 + - uid: 775 + components: + - type: Transform + pos: 27.5,19.5 + parent: 588 + - uid: 776 + components: + - type: Transform + pos: 26.5,19.5 + parent: 588 + - uid: 777 + components: + - type: Transform + pos: 25.5,19.5 + parent: 588 + - uid: 1527 + components: + - type: Transform + pos: 19.5,46.5 + parent: 588 + - uid: 1528 + components: + - type: Transform + pos: 19.5,47.5 + parent: 588 +- proto: CableTerminal + entities: + - uid: 463 + components: + - type: Transform + pos: 26.5,14.5 + parent: 588 + - uid: 464 + components: + - type: Transform + pos: 27.5,14.5 + parent: 588 + - uid: 465 + components: + - type: Transform + pos: 28.5,14.5 + parent: 588 + - uid: 767 + components: + - type: Transform + pos: 26.5,20.5 + parent: 588 + - uid: 970 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,31.5 + parent: 588 + - uid: 976 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 22.5,31.5 + parent: 588 + - uid: 1558 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,45.5 + parent: 588 + - uid: 1559 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,45.5 + parent: 588 +- proto: Carpet + entities: + - uid: 1632 + components: + - type: Transform + pos: 24.5,0.5 + parent: 588 + - uid: 1633 + components: + - type: Transform + pos: 25.5,0.5 + parent: 588 + - uid: 1634 + components: + - type: Transform + pos: 25.5,1.5 + parent: 588 + - uid: 1635 + components: + - type: Transform + pos: 24.5,1.5 + parent: 588 +- proto: CarpetBlue + entities: + - uid: 1636 + components: + - type: Transform + pos: 27.5,0.5 + parent: 588 + - uid: 1637 + components: + - type: Transform + pos: 28.5,1.5 + parent: 588 + - uid: 1638 + components: + - type: Transform + pos: 27.5,1.5 + parent: 588 + - uid: 1639 + components: + - type: Transform + pos: 28.5,0.5 + parent: 588 +- proto: CarpetPurple + entities: + - uid: 1626 + components: + - type: Transform + pos: 25.5,4.5 + parent: 588 + - uid: 1627 + components: + - type: Transform + pos: 25.5,3.5 + parent: 588 + - uid: 1628 + components: + - type: Transform + pos: 26.5,3.5 + parent: 588 + - uid: 1629 + components: + - type: Transform + pos: 27.5,3.5 + parent: 588 + - uid: 1630 + components: + - type: Transform + pos: 27.5,4.5 + parent: 588 + - uid: 1631 + components: + - type: Transform + pos: 26.5,4.5 + parent: 588 +- proto: Catwalk + entities: + - uid: 141 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,24.5 + parent: 588 + - uid: 142 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,26.5 + parent: 588 + - uid: 143 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,25.5 + parent: 588 + - uid: 248 + components: + - type: Transform + pos: 8.5,4.5 + parent: 588 + - uid: 249 + components: + - type: Transform + pos: 8.5,2.5 + parent: 588 + - uid: 250 + components: + - type: Transform + pos: 8.5,3.5 + parent: 588 + - uid: 251 + components: + - type: Transform + pos: 8.5,1.5 + parent: 588 + - uid: 471 + components: + - type: Transform + pos: 27.5,14.5 + parent: 588 + - uid: 473 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 29.5,12.5 + parent: 588 + - uid: 474 + components: + - type: Transform + pos: 28.5,14.5 + parent: 588 + - uid: 475 + components: + - type: Transform + pos: 26.5,14.5 + parent: 588 + - uid: 512 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,12.5 + parent: 588 + - uid: 513 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 28.5,12.5 + parent: 588 + - uid: 515 + components: + - type: Transform + pos: 25.5,16.5 + parent: 588 + - uid: 516 + components: + - type: Transform + pos: 26.5,16.5 + parent: 588 + - uid: 517 + components: + - type: Transform + pos: 27.5,16.5 + parent: 588 + - uid: 518 + components: + - type: Transform + pos: 28.5,16.5 + parent: 588 + - uid: 519 + components: + - type: Transform + pos: 29.5,16.5 + parent: 588 + - uid: 520 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,12.5 + parent: 588 + - uid: 521 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,12.5 + parent: 588 + - uid: 769 + components: + - type: Transform + pos: 26.5,20.5 + parent: 588 + - uid: 832 + components: + - type: Transform + pos: 3.5,31.5 + parent: 588 + - uid: 833 + components: + - type: Transform + pos: 4.5,31.5 + parent: 588 + - uid: 834 + components: + - type: Transform + pos: 5.5,31.5 + parent: 588 + - uid: 835 + components: + - type: Transform + pos: 6.5,31.5 + parent: 588 + - uid: 836 + components: + - type: Transform + pos: 7.5,31.5 + parent: 588 + - uid: 837 + components: + - type: Transform + pos: 8.5,31.5 + parent: 588 + - uid: 838 + components: + - type: Transform + pos: 9.5,31.5 + parent: 588 + - uid: 839 + components: + - type: Transform + pos: 6.5,32.5 + parent: 588 + - uid: 840 + components: + - type: Transform + pos: 6.5,30.5 + parent: 588 + - uid: 841 + components: + - type: Transform + pos: 5.5,32.5 + parent: 588 + - uid: 842 + components: + - type: Transform + pos: 7.5,32.5 + parent: 588 + - uid: 843 + components: + - type: Transform + pos: 5.5,30.5 + parent: 588 + - uid: 844 + components: + - type: Transform + pos: 7.5,30.5 + parent: 588 + - uid: 861 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,27.5 + parent: 588 + - uid: 862 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,28.5 + parent: 588 + - uid: 863 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,28.5 + parent: 588 + - uid: 864 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,27.5 + parent: 588 + - uid: 865 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,26.5 + parent: 588 + - uid: 879 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,40.5 + parent: 588 + - uid: 880 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,39.5 + parent: 588 + - uid: 881 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,39.5 + parent: 588 + - uid: 882 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,39.5 + parent: 588 + - uid: 883 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,39.5 + parent: 588 + - uid: 884 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,39.5 + parent: 588 + - uid: 885 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,38.5 + parent: 588 + - uid: 914 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,10.5 + parent: 588 + - uid: 915 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,10.5 + parent: 588 + - uid: 916 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,10.5 + parent: 588 + - uid: 917 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,10.5 + parent: 588 + - uid: 918 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,10.5 + parent: 588 + - uid: 919 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,6.5 + parent: 588 + - uid: 920 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,6.5 + parent: 588 + - uid: 921 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,6.5 + parent: 588 + - uid: 922 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,6.5 + parent: 588 + - uid: 923 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,6.5 + parent: 588 + - uid: 955 + components: + - type: Transform + pos: 15.5,31.5 + parent: 588 + - uid: 956 + components: + - type: Transform + pos: 16.5,31.5 + parent: 588 + - uid: 957 + components: + - type: Transform + pos: 17.5,31.5 + parent: 588 + - uid: 958 + components: + - type: Transform + pos: 18.5,31.5 + parent: 588 + - uid: 959 + components: + - type: Transform + pos: 19.5,31.5 + parent: 588 + - uid: 960 + components: + - type: Transform + pos: 20.5,31.5 + parent: 588 + - uid: 961 + components: + - type: Transform + pos: 21.5,31.5 + parent: 588 + - uid: 962 + components: + - type: Transform + pos: 22.5,31.5 + parent: 588 + - uid: 963 + components: + - type: Transform + pos: 23.5,31.5 + parent: 588 + - uid: 964 + components: + - type: Transform + pos: 24.5,31.5 + parent: 588 + - uid: 965 + components: + - type: Transform + pos: 25.5,31.5 + parent: 588 + - uid: 994 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,32.5 + parent: 588 + - uid: 1158 + components: + - type: Transform + pos: 8.5,0.5 + parent: 588 + - uid: 1180 + components: + - type: Transform + pos: 1.5,36.5 + parent: 588 + - uid: 1181 + components: + - type: Transform + pos: 2.5,36.5 + parent: 588 + - uid: 1182 + components: + - type: Transform + pos: 3.5,36.5 + parent: 588 + - uid: 1183 + components: + - type: Transform + pos: 4.5,36.5 + parent: 588 + - uid: 1184 + components: + - type: Transform + pos: 5.5,36.5 + parent: 588 + - uid: 1185 + components: + - type: Transform + pos: 5.5,34.5 + parent: 588 + - uid: 1186 + components: + - type: Transform + pos: 6.5,34.5 + parent: 588 + - uid: 1187 + components: + - type: Transform + pos: 7.5,34.5 + parent: 588 + - uid: 1188 + components: + - type: Transform + pos: 8.5,34.5 + parent: 588 + - uid: 1189 + components: + - type: Transform + pos: 9.5,34.5 + parent: 588 + - uid: 1320 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,40.5 + parent: 588 + - uid: 1321 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,40.5 + parent: 588 + - uid: 1322 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,40.5 + parent: 588 + - uid: 1323 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,38.5 + parent: 588 + - uid: 1324 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,38.5 + parent: 588 + - uid: 1325 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,38.5 + parent: 588 + - uid: 1326 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 28.5,38.5 + parent: 588 + - uid: 1327 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 29.5,38.5 + parent: 588 + - uid: 1331 + components: + - type: Transform + pos: 4.5,45.5 + parent: 588 + - uid: 1336 + components: + - type: Transform + pos: 2.5,45.5 + parent: 588 + - uid: 1339 + components: + - type: Transform + pos: 3.5,45.5 + parent: 588 + - uid: 1342 + components: + - type: Transform + pos: 3.5,46.5 + parent: 588 + - uid: 1344 + components: + - type: Transform + pos: 3.5,44.5 + parent: 588 + - uid: 1346 + components: + - type: Transform + pos: 2.5,44.5 + parent: 588 + - uid: 1347 + components: + - type: Transform + pos: 4.5,44.5 + parent: 588 + - uid: 1348 + components: + - type: Transform + pos: 4.5,44.5 + parent: 588 + - uid: 1349 + components: + - type: Transform + pos: 4.5,46.5 + parent: 588 + - uid: 1350 + components: + - type: Transform + pos: 2.5,46.5 + parent: 588 + - uid: 1494 + components: + - type: Transform + pos: 17.5,42.5 + parent: 588 + - uid: 1495 + components: + - type: Transform + pos: 18.5,42.5 + parent: 588 + - uid: 1496 + components: + - type: Transform + pos: 19.5,42.5 + parent: 588 + - uid: 1497 + components: + - type: Transform + pos: 20.5,42.5 + parent: 588 + - uid: 1498 + components: + - type: Transform + pos: 21.5,42.5 + parent: 588 + - uid: 1499 + components: + - type: Transform + pos: 17.5,48.5 + parent: 588 + - uid: 1500 + components: + - type: Transform + pos: 18.5,48.5 + parent: 588 + - uid: 1501 + components: + - type: Transform + pos: 19.5,48.5 + parent: 588 + - uid: 1502 + components: + - type: Transform + pos: 20.5,48.5 + parent: 588 + - uid: 1503 + components: + - type: Transform + pos: 21.5,48.5 + parent: 588 + - uid: 1516 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,44.5 + parent: 588 + - uid: 1517 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,45.5 + parent: 588 + - uid: 1518 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,45.5 + parent: 588 + - uid: 1519 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,45.5 + parent: 588 + - uid: 1582 + components: + - type: Transform + pos: 28.5,22.5 + parent: 588 + - uid: 1583 + components: + - type: Transform + pos: 28.5,21.5 + parent: 588 + - uid: 1584 + components: + - type: Transform + pos: 28.5,20.5 + parent: 588 + - uid: 1585 + components: + - type: Transform + pos: 28.5,19.5 + parent: 588 + - uid: 1586 + components: + - type: Transform + pos: 28.5,18.5 + parent: 588 + - uid: 1587 + components: + - type: Transform + pos: 24.5,22.5 + parent: 588 + - uid: 1588 + components: + - type: Transform + pos: 24.5,21.5 + parent: 588 + - uid: 1589 + components: + - type: Transform + pos: 24.5,20.5 + parent: 588 + - uid: 1590 + components: + - type: Transform + pos: 24.5,19.5 + parent: 588 + - uid: 1591 + components: + - type: Transform + pos: 24.5,18.5 + parent: 588 +- proto: Cautery + entities: + - uid: 1474 + components: + - type: Transform + pos: 8.533231,42.775993 + parent: 588 +- proto: Chair + entities: + - uid: 357 + components: + - type: Transform + pos: 23.5,4.5 + parent: 588 + - uid: 421 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,9.5 + parent: 588 + - uid: 422 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,9.5 + parent: 588 + - uid: 423 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,7.5 + parent: 588 + - uid: 533 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 19.5,14.5 + parent: 588 + - uid: 534 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 19.5,15.5 + parent: 588 + - uid: 537 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 21.5,14.5 + parent: 588 + - uid: 569 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 11.5,13.5 + parent: 588 + - uid: 716 + components: + - type: Transform + pos: 18.5,19.5 + parent: 588 + - uid: 717 + components: + - type: Transform + pos: 19.5,19.5 + parent: 588 + - uid: 718 + components: + - type: Transform + pos: 22.5,19.5 + parent: 588 + - uid: 719 + components: + - type: Transform + pos: 21.5,19.5 + parent: 588 + - uid: 1280 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 17.5,38.5 + parent: 588 + - uid: 1281 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,38.5 + parent: 588 + - uid: 1282 + components: + - type: Transform + pos: 20.5,40.5 + parent: 588 + - uid: 1283 + components: + - type: Transform + pos: 21.5,40.5 + parent: 588 + - uid: 1865 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,7.5 + parent: 588 +- proto: ChairFolding + entities: + - uid: 344 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 31.5,0.5 + parent: 588 + - uid: 345 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,1.5 + parent: 588 + - uid: 346 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,0.5 + parent: 588 + - uid: 347 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 31.5,3.5 + parent: 588 + - uid: 348 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,3.5 + parent: 588 + - uid: 349 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 31.5,4.5 + parent: 588 + - uid: 350 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 33.5,1.5 + parent: 588 + - uid: 351 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 33.5,0.5 + parent: 588 + - uid: 352 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 33.5,4.5 + parent: 588 + - uid: 353 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,4.5 + parent: 588 + - uid: 1212 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,36.5 + parent: 588 +- proto: ChairFoldingSpawnFolded + entities: + - uid: 354 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 31.53707,1.6455604 + parent: 588 + - uid: 355 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 33.595894,3.4052575 + parent: 588 +- proto: ChairOfficeDark + entities: + - uid: 330 + components: + - type: Transform + pos: 19.5,1.5 + parent: 588 + - uid: 331 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,3.5 + parent: 588 + - uid: 358 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,0.5 + parent: 588 + - uid: 359 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,0.5 + parent: 588 + - uid: 360 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,0.5 + parent: 588 + - uid: 361 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 27.5,0.5 + parent: 588 + - uid: 571 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 13.5,12.5 + parent: 588 +- proto: ChairOfficeLight + entities: + - uid: 631 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 9.5,19.5 + parent: 588 + - uid: 638 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,21.5 + parent: 588 + - uid: 707 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 15.5,21.5 + parent: 588 +- proto: ChairPilotSeat + entities: + - uid: 356 + components: + - type: Transform + pos: 26.5,4.5 + parent: 588 +- proto: ChairWood + entities: + - uid: 1049 + components: + - type: Transform + pos: 20.5,25.5 + parent: 588 + - uid: 1050 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 22.5,27.5 + parent: 588 + - uid: 1231 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,34.5 + parent: 588 + - uid: 1232 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 13.5,36.5 + parent: 588 + - uid: 1790 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,46.5 + parent: 588 + - uid: 1791 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,44.5 + parent: 588 +- proto: CigarGold + entities: + - uid: 1219 + components: + - type: Transform + pos: 7.4719925,36.539555 + parent: 588 +- proto: ClosetBombFilled + entities: + - uid: 413 + components: + - type: Transform + pos: 14.5,6.5 + parent: 588 + - uid: 1014 + components: + - type: Transform + pos: 12.5,27.5 + parent: 588 + - uid: 1026 + components: + - type: Transform + pos: 16.5,27.5 + parent: 588 +- proto: ClosetEmergencyFilledRandom + entities: + - uid: 1203 + components: + - type: Transform + pos: 12.5,30.5 + parent: 588 + - uid: 1204 + components: + - type: Transform + pos: 0.5,32.5 + parent: 588 + - uid: 1205 + components: + - type: Transform + pos: 9.5,9.5 + parent: 588 + - uid: 1207 + components: + - type: Transform + pos: 1.5,7.5 + parent: 588 +- proto: ClosetFireFilled + entities: + - uid: 1194 + components: + - type: Transform + pos: 1.5,9.5 + parent: 588 + - uid: 1195 + components: + - type: Transform + pos: 9.5,7.5 + parent: 588 + - uid: 1196 + components: + - type: Transform + pos: 6.5,40.5 + parent: 588 + - uid: 1197 + components: + - type: Transform + pos: 0.5,38.5 + parent: 588 +- proto: ClosetL3SecurityFilled + entities: + - uid: 415 + components: + - type: Transform + pos: 20.5,10.5 + parent: 588 +- proto: ClosetToolFilled + entities: + - uid: 1007 + components: + - type: Transform + pos: 14.5,30.5 + parent: 588 +- proto: ClosetWallMaintenanceFilledRandom + entities: + - uid: 499 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 25.5,15.5 + parent: 588 + - uid: 868 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,27.5 + parent: 588 + - uid: 1564 + components: + - type: Transform + pos: 17.5,43.5 + parent: 588 + - uid: 1565 + components: + - type: Transform + pos: 21.5,43.5 + parent: 588 +- proto: ClothingBeltChampion + entities: + - uid: 1236 + components: + - type: Transform + pos: 10.581136,39.53631 + parent: 588 +- proto: ClothingEyesGlassesMeson + entities: + - uid: 1108 + components: + - type: Transform + pos: 25.666832,30.643515 + parent: 588 +- proto: ClothingHandsGlovesNitrile + entities: + - uid: 1715 + components: + - type: Transform + pos: 10.432637,44.476112 + parent: 588 +- proto: ClothingHeadBandRed + entities: + - uid: 1295 + components: + - type: Transform + pos: 12.571781,39.694115 + parent: 588 +- proto: ClothingHeadHatFedoraBrown + entities: + - uid: 577 + components: + - type: Transform + pos: 12.686508,13.58602 + parent: 588 +- proto: ClothingHeadHatPwig + entities: + - uid: 369 + components: + - type: Transform + pos: 25.824945,3.5783403 + parent: 588 +- proto: ClothingHeadHatSecsoftFlipped + entities: + - uid: 606 + components: + - type: Transform + pos: 12.705482,6.671774 + parent: 588 + - uid: 1027 + components: + - type: Transform + pos: 18.403675,25.53719 + parent: 588 +- proto: ClothingHeadHatSurgcapPurple + entities: + - uid: 1711 + components: + - type: Transform + pos: 10.304593,44.632217 + parent: 588 +- proto: ClothingHeadHelmetRiot + entities: + - uid: 1617 + components: + - type: Transform + pos: 22.499683,6.7142525 + parent: 588 +- proto: ClothingHeadHelmetThunderdome + entities: + - uid: 1240 + components: + - type: Transform + pos: 34.666565,24.66942 + parent: 588 +- proto: ClothingNeckLawyerbadge + entities: + - uid: 326 + components: + - type: Transform + pos: 21.586027,4.583762 + parent: 588 +- proto: ClothingNeckTieDet + entities: + - uid: 573 + components: + - type: Transform + pos: 12.714905,13.486683 + parent: 588 +- proto: ClothingOuterArmorReflective + entities: + - uid: 1031 + components: + - type: Transform + pos: 18.47467,24.458666 + parent: 588 +- proto: ClothingOuterCoatDetectiveLoadout + entities: + - uid: 574 + components: + - type: Transform + pos: 13.396446,12.479115 + parent: 588 +- proto: ClothingOuterRobesJudge + entities: + - uid: 370 + components: + - type: Transform + pos: 27.40101,3.677678 + parent: 588 +- proto: ClothingShoesBootsCombatFilled + entities: + - uid: 1036 + components: + - type: Transform + pos: 12.582174,25.636528 + parent: 588 +- proto: ClothingShoesBootsLaceup + entities: + - uid: 372 + components: + - type: Transform + pos: 18.586912,0.70824456 + parent: 588 +- proto: ClothingUniformJumpskirtColorMaroon + entities: + - uid: 1714 + components: + - type: Transform + pos: 10.673761,44.53288 + parent: 588 +- proto: ClothingUniformJumpsuitColorMaroon + entities: + - uid: 1713 + components: + - type: Transform + pos: 10.645364,44.67479 + parent: 588 +- proto: ClusterBangFull + entities: + - uid: 599 + components: + - type: Transform + pos: 33.484257,28.42918 + parent: 588 +- proto: ComputerAlert + entities: + - uid: 999 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 17.5,30.5 + parent: 588 + - uid: 1001 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 23.5,30.5 + parent: 588 + - uid: 1561 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,46.5 + parent: 588 +- proto: computerBodyScanner + entities: + - uid: 1394 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,44.5 + parent: 588 + - uid: 1423 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,44.5 + parent: 588 +- proto: ComputerCriminalRecords + entities: + - uid: 461 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,0.5 + parent: 588 + - uid: 634 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,18.5 + parent: 588 +- proto: ComputerPowerMonitoring + entities: + - uid: 1000 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 16.5,30.5 + parent: 588 + - uid: 1002 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,30.5 + parent: 588 + - uid: 1560 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 17.5,46.5 + parent: 588 +- proto: ComputerSurveillanceCameraMonitor + entities: + - uid: 635 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,21.5 + parent: 588 +- proto: ComputerTelevision + entities: + - uid: 1229 + components: + - type: Transform + pos: 12.5,34.5 + parent: 588 + - uid: 1230 + components: + - type: Transform + pos: 22.5,36.5 + parent: 588 +- proto: CrateEngineeringGear + entities: + - uid: 1008 + components: + - type: Transform + pos: 26.5,30.5 + parent: 588 +- proto: CrateFunBoardGames + entities: + - uid: 1845 + components: + - type: Transform + pos: 26.5,48.5 + parent: 588 +- proto: CrateFunParty + entities: + - uid: 1876 + components: + - type: Transform + pos: 25.5,43.5 + parent: 588 +- proto: CrateHydroponicsSeedsExotic + entities: + - uid: 1660 + components: + - type: Transform + pos: 31.5,22.5 + parent: 588 +- proto: CrayonBox + entities: + - uid: 1057 + components: + - type: Transform + pos: 20.47107,24.608877 + parent: 588 + - uid: 1116 + components: + - type: Transform + pos: 20.607256,14.646415 + parent: 588 +- proto: CryoPod + entities: + - uid: 1395 + components: + - type: Transform + pos: 8.5,47.5 + parent: 588 + - uid: 1397 + components: + - type: Transform + pos: 14.5,47.5 + parent: 588 +- proto: DebugSMES + entities: + - uid: 971 + components: + - type: Transform + pos: 22.5,32.5 + parent: 588 + - uid: 974 + components: + - type: Transform + pos: 18.5,32.5 + parent: 588 +- proto: DeployableBarrier + entities: + - uid: 1233 + components: + - type: Transform + pos: 32.5,24.5 + parent: 588 +- proto: DiceBag + entities: + - uid: 552 + components: + - type: Transform + pos: 20.294882,15.426926 + parent: 588 +- proto: DiseaseDiagnoser + entities: + - uid: 1424 + components: + - type: Transform + pos: 14.5,44.5 + parent: 588 +- proto: DisposalUnit + entities: + - uid: 550 + components: + - type: Transform + pos: 22.5,16.5 + parent: 588 + - uid: 725 + components: + - type: Transform + pos: 21.5,22.5 + parent: 588 + - uid: 766 + components: + - type: Transform + pos: 9.5,22.5 + parent: 588 + - uid: 1288 + components: + - type: Transform + pos: 22.5,38.5 + parent: 588 +- proto: DonkpocketBoxSpawner + entities: + - uid: 526 + components: + - type: Transform + pos: 16.5,13.5 + parent: 588 + - uid: 723 + components: + - type: Transform + pos: 18.5,21.5 + parent: 588 +- proto: DoorElectronics + entities: + - uid: 659 + components: + - type: Transform + pos: 12.581519,21.410114 + parent: 588 + - uid: 1074 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.639427,25.54549 + parent: 588 +- proto: Dresser + entities: + - uid: 1051 + components: + - type: Transform + pos: 22.5,25.5 + parent: 588 + - uid: 1052 + components: + - type: Transform + pos: 20.5,27.5 + parent: 588 + - uid: 1061 + components: + - type: Transform + pos: 24.5,25.5 + parent: 588 + - uid: 1221 + components: + - type: Transform + pos: 21.5,36.5 + parent: 588 + - uid: 1222 + components: + - type: Transform + pos: 13.5,34.5 + parent: 588 +- proto: DrinkDetFlask + entities: + - uid: 1577 + components: + - type: Transform + pos: 12.606661,13.037249 + parent: 588 +- proto: DrinkMugMetal + entities: + - uid: 1294 + components: + - type: Transform + pos: 22.442232,12.514399 + parent: 588 +- proto: DrinkMugRed + entities: + - uid: 721 + components: + - type: Transform + pos: 22.448559,18.561966 + parent: 588 + - uid: 1293 + components: + - type: Transform + pos: 22.328642,12.741456 + parent: 588 +- proto: DrinkShinyFlask + entities: + - uid: 1874 + components: + - type: Transform + pos: 6.890398,22.663696 + parent: 588 +- proto: DrinkShotGlass + entities: + - uid: 578 + components: + - type: Transform + pos: 12.412022,12.535878 + parent: 588 + - uid: 579 + components: + - type: Transform + pos: 12.539811,12.748745 + parent: 588 +- proto: DrinkWaterCup + entities: + - uid: 722 + components: + - type: Transform + pos: 18.373508,18.661304 + parent: 588 + - uid: 762 + components: + - type: Transform + pos: 6.313587,19.590261 + parent: 588 + - uid: 763 + components: + - type: Transform + pos: 6.441377,19.419968 + parent: 588 +- proto: EmergencyLight + entities: + - uid: 1716 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,6.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1717 + components: + - type: Transform + pos: 21.5,10.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1718 + components: + - type: Transform + pos: 30.5,4.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1719 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,0.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1720 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,0.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1721 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,12.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1722 + components: + - type: Transform + pos: 18.5,16.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1723 + components: + - type: Transform + pos: 31.5,22.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1724 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 34.5,25.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1726 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 30.5,25.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1727 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,27.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1728 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,27.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1729 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,27.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1730 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 12.5,25.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1731 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,7.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1732 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,9.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1733 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,20.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1734 + components: + - type: Transform + pos: 1.5,24.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1735 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,30.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1736 + components: + - type: Transform + pos: 11.5,32.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1737 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,40.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1738 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,40.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1739 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 22.5,30.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1740 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,19.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1742 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 16.5,21.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1744 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,18.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1745 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 16.5,34.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1746 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 30.5,34.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1747 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,38.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1748 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 20.5,44.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1749 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,44.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1750 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,46.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1751 + components: + - type: Transform + pos: 30.5,6.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1752 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,10.5 + parent: 588 + - type: PointLight + enabled: True + - uid: 1832 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 30.5,46.5 + parent: 588 + - type: PointLight + enabled: True +- proto: EmergencyRollerBed + entities: + - uid: 1141 + components: + - type: Transform + pos: 30.5,25.5 + parent: 588 + - uid: 1142 + components: + - type: Transform + pos: 30.5,24.5 + parent: 588 +- proto: ExtinguisherCabinetFilled + entities: + - uid: 867 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,26.5 + parent: 588 + - uid: 1198 + components: + - type: Transform + pos: 2.5,8.5 + parent: 588 + - uid: 1199 + components: + - type: Transform + pos: 8.5,8.5 + parent: 588 + - uid: 1200 + components: + - type: Transform + pos: 8.5,35.5 + parent: 588 + - uid: 1201 + components: + - type: Transform + pos: 1.5,35.5 + parent: 588 + - uid: 1202 + components: + - type: Transform + pos: 25.5,14.5 + parent: 588 + - uid: 1328 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 28.5,39.5 + parent: 588 + - uid: 1566 + components: + - type: Transform + pos: 17.5,44.5 + parent: 588 +- proto: filingCabinetRandom + entities: + - uid: 320 + components: + - type: Transform + pos: 21.5,0.5 + parent: 588 + - uid: 321 + components: + - type: Transform + pos: 20.5,0.5 + parent: 588 +- proto: filingCabinetTallRandom + entities: + - uid: 1396 + components: + - type: Transform + pos: 8.5,44.5 + parent: 588 +- proto: Flash + entities: + - uid: 1209 + components: + - type: Transform + pos: 10.726851,19.047483 + parent: 588 +- proto: FlashlightSeclite + entities: + - uid: 374 + components: + - type: Transform + pos: 13.377204,0.54605544 + parent: 588 +- proto: FloodlightBroken + entities: + - uid: 1193 + components: + - type: Transform + pos: 9.462372,35.6454 + parent: 588 +- proto: FloorDrain + entities: + - uid: 944 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,28.5 + parent: 588 + - type: Fixtures + fixtures: {} + - uid: 945 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,28.5 + parent: 588 + - type: Fixtures + fixtures: {} +- proto: FloorLavaEntity + entities: + - uid: 47 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,8.5 + parent: 588 + - uid: 49 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,8.5 + parent: 588 + - uid: 458 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,10.5 + parent: 588 + - uid: 459 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,8.5 + parent: 588 + - uid: 460 + components: + - type: Transform + pos: 8.5,3.5 + parent: 588 + - uid: 645 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,20.5 + parent: 588 + - uid: 820 + components: + - type: Transform + pos: 4.5,32.5 + parent: 588 + - uid: 821 + components: + - type: Transform + pos: 4.5,31.5 + parent: 588 + - uid: 822 + components: + - type: Transform + pos: 5.5,31.5 + parent: 588 + - uid: 823 + components: + - type: Transform + pos: 5.5,32.5 + parent: 588 + - uid: 824 + components: + - type: Transform + pos: 5.5,30.5 + parent: 588 + - uid: 825 + components: + - type: Transform + pos: 6.5,30.5 + parent: 588 + - uid: 826 + components: + - type: Transform + pos: 7.5,30.5 + parent: 588 + - uid: 827 + components: + - type: Transform + pos: 6.5,32.5 + parent: 588 + - uid: 828 + components: + - type: Transform + pos: 7.5,32.5 + parent: 588 + - uid: 829 + components: + - type: Transform + pos: 7.5,31.5 + parent: 588 + - uid: 830 + components: + - type: Transform + pos: 6.5,31.5 + parent: 588 + - uid: 831 + components: + - type: Transform + pos: 8.5,30.5 + parent: 588 + - uid: 857 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,39.5 + parent: 588 + - uid: 858 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,39.5 + parent: 588 + - uid: 859 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,38.5 + parent: 588 + - uid: 860 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,40.5 + parent: 588 + - uid: 887 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,40.5 + parent: 588 + - uid: 889 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,39.5 + parent: 588 + - uid: 906 + components: + - type: Transform + pos: 4.5,7.5 + parent: 588 + - uid: 907 + components: + - type: Transform + pos: 5.5,7.5 + parent: 588 + - uid: 908 + components: + - type: Transform + pos: 5.5,9.5 + parent: 588 + - uid: 909 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,6.5 + parent: 588 + - uid: 910 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,6.5 + parent: 588 + - uid: 911 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,9.5 + parent: 588 + - uid: 913 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,10.5 + parent: 588 + - uid: 1247 + components: + - type: Transform + pos: 8.5,4.5 + parent: 588 + - uid: 1248 + components: + - type: Transform + pos: 9.5,4.5 + parent: 588 + - uid: 1249 + components: + - type: Transform + pos: 8.5,2.5 + parent: 588 + - uid: 1250 + components: + - type: Transform + pos: 8.5,1.5 + parent: 588 + - uid: 1251 + components: + - type: Transform + pos: 9.5,1.5 + parent: 588 + - uid: 1252 + components: + - type: Transform + pos: 8.5,1.5 + parent: 588 + - uid: 1253 + components: + - type: Transform + pos: 8.5,0.5 + parent: 588 + - uid: 1254 + components: + - type: Transform + pos: 7.5,0.5 + parent: 588 + - uid: 1333 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,46.5 + parent: 588 + - uid: 1341 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,45.5 + parent: 588 + - uid: 1343 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,46.5 + parent: 588 + - uid: 1345 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,46.5 + parent: 588 + - uid: 1359 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,47.5 + parent: 588 + - uid: 1360 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,46.5 + parent: 588 + - uid: 1361 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,47.5 + parent: 588 + - uid: 1362 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,47.5 + parent: 588 + - uid: 1363 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,44.5 + parent: 588 + - uid: 1364 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,47.5 + parent: 588 + - uid: 1365 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,44.5 + parent: 588 + - uid: 1366 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,45.5 + parent: 588 + - uid: 1367 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,44.5 + parent: 588 + - uid: 1368 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,43.5 + parent: 588 + - uid: 1369 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,43.5 + parent: 588 + - uid: 1370 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,42.5 + parent: 588 + - uid: 1371 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,42.5 + parent: 588 + - uid: 1372 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,43.5 + parent: 588 + - uid: 1373 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,44.5 + parent: 588 + - uid: 1374 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,46.5 + parent: 588 + - uid: 1375 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,43.5 + parent: 588 +- proto: FoodBowlBigTrash + entities: + - uid: 1840 + components: + - type: Transform + pos: 30.547388,48.16116 + parent: 588 +- proto: FoodBurgerMime + entities: + - uid: 399 + components: + - type: Transform + pos: 10.958169,39.64943 + parent: 588 +- proto: FoodPlateSmallPlastic + entities: + - uid: 529 + components: + - type: Transform + pos: 17.462528,12.615073 + parent: 588 +- proto: FoodPlateTrash + entities: + - uid: 1692 + components: + - type: Transform + pos: 28.80027,47.44947 + parent: 588 +- proto: ForensicPad + entities: + - uid: 761 + components: + - type: Transform + pos: 7.562898,22.48225 + parent: 588 +- proto: ForkPlastic + entities: + - uid: 531 + components: + - type: Transform + pos: 17.405733,12.600882 + parent: 588 +- proto: GasFilter + entities: + - uid: 1415 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 12.5,47.5 + parent: 588 +- proto: GasPipeBend + entities: + - uid: 1412 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,46.5 + parent: 588 + - uid: 1414 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,46.5 + parent: 588 + - uid: 1416 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 11.5,47.5 + parent: 588 + - uid: 1421 + components: + - type: Transform + pos: 13.5,47.5 + parent: 588 +- proto: GasPipeStraight + entities: + - uid: 1418 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,47.5 + parent: 588 + - uid: 1420 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 12.5,46.5 + parent: 588 +- proto: GasPipeTJunction + entities: + - uid: 1410 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,46.5 + parent: 588 + - uid: 1411 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,46.5 + parent: 588 + - uid: 1417 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,46.5 + parent: 588 + - uid: 1419 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 11.5,46.5 + parent: 588 +- proto: GasPort + entities: + - uid: 1404 + components: + - type: Transform + pos: 9.5,48.5 + parent: 588 + - uid: 1422 + components: + - type: Transform + pos: 12.5,48.5 + parent: 588 +- proto: GasPressurePump + entities: + - uid: 1409 + components: + - type: Transform + pos: 9.5,47.5 + parent: 588 +- proto: GasThermoMachineFreezer + entities: + - uid: 1403 + components: + - type: Transform + pos: 10.5,48.5 + parent: 588 +- proto: GatfruitSeeds + entities: + - uid: 562 + components: + - type: Transform + pos: 8.528373,27.49547 + parent: 588 +- proto: Gauze + entities: + - uid: 1482 + components: + - type: Transform + pos: 8.452288,42.514927 + parent: 588 +- proto: GeneratorRTG + entities: + - uid: 742 + components: + - type: Transform + pos: 27.5,21.5 + parent: 588 + - uid: 748 + components: + - type: Transform + pos: 25.5,21.5 + parent: 588 +- proto: Girder + entities: + - uid: 1301 + components: + - type: Transform + pos: 26.5,39.5 + parent: 588 +- proto: Grille + entities: + - uid: 209 + components: + - type: Transform + pos: 15.5,34.5 + parent: 588 + - uid: 211 + components: + - type: Transform + pos: 19.5,36.5 + parent: 588 + - uid: 212 + components: + - type: Transform + pos: 19.5,34.5 + parent: 588 + - uid: 213 + components: + - type: Transform + pos: 15.5,36.5 + parent: 588 + - uid: 403 + components: + - type: Transform + pos: 15.5,9.5 + parent: 588 + - uid: 404 + components: + - type: Transform + pos: 15.5,7.5 + parent: 588 + - uid: 407 + components: + - type: Transform + pos: 19.5,9.5 + parent: 588 + - uid: 408 + components: + - type: Transform + pos: 19.5,7.5 + parent: 588 + - uid: 568 + components: + - type: Transform + pos: 12.5,15.5 + parent: 588 + - uid: 584 + components: + - type: Transform + pos: 2.5,12.5 + parent: 588 + - uid: 586 + components: + - type: Transform + pos: 2.5,16.5 + parent: 588 + - uid: 587 + components: + - type: Transform + pos: 4.5,16.5 + parent: 588 + - uid: 589 + components: + - type: Transform + pos: 4.5,12.5 + parent: 588 + - uid: 1465 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,43.5 + parent: 588 + - uid: 1466 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,43.5 + parent: 588 +- proto: GrilleBroken + entities: + - uid: 1302 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,39.5 + parent: 588 +- proto: Handcuffs + entities: + - uid: 1614 + components: + - type: Transform + pos: 22.608034,10.659381 + parent: 588 +- proto: Hemostat + entities: + - uid: 1471 + components: + - type: Transform + pos: 8.51377,43.004257 + parent: 588 +- proto: HighSecArmoryLocked + entities: + - uid: 1597 + components: + - type: Transform + pos: 26.5,7.5 + parent: 588 + - uid: 1598 + components: + - type: Transform + pos: 32.5,7.5 + parent: 588 + - uid: 1599 + components: + - type: Transform + pos: 29.5,9.5 + parent: 588 +- proto: HospitalCurtains + entities: + - uid: 402 + components: + - type: Transform + pos: 8.5,27.5 + parent: 588 + - uid: 949 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,24.5 + parent: 588 + - uid: 951 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,27.5 + parent: 588 + - uid: 1768 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,48.5 + parent: 588 +- proto: HospitalCurtainsOpen + entities: + - uid: 946 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,25.5 + parent: 588 + - uid: 947 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,24.5 + parent: 588 + - uid: 1040 + components: + - type: Transform + pos: 20.5,28.5 + parent: 588 + - uid: 1046 + components: + - type: Transform + pos: 22.5,24.5 + parent: 588 + - uid: 1148 + components: + - type: Transform + pos: 28.5,25.5 + parent: 588 + - uid: 1149 + components: + - type: Transform + pos: 28.5,24.5 + parent: 588 + - uid: 1223 + components: + - type: Transform + pos: 20.5,36.5 + parent: 588 + - uid: 1224 + components: + - type: Transform + pos: 14.5,34.5 + parent: 588 + - uid: 1467 + components: + - type: Transform + pos: 12.5,42.5 + parent: 588 + - uid: 1469 + components: + - type: Transform + pos: 10.5,42.5 + parent: 588 + - uid: 1767 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,42.5 + parent: 588 +- proto: HydroponicsToolHatchet + entities: + - uid: 1844 + components: + - type: Transform + pos: 29.538284,44.04174 + parent: 588 + - uid: 1851 + components: + - type: Transform + pos: 30.630798,21.602604 + parent: 588 +- proto: HydroponicsToolMiniHoe + entities: + - uid: 1837 + components: + - type: Transform + pos: 30.099596,43.446724 + parent: 588 + - uid: 1841 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.38517,20.601 + parent: 588 +- proto: HydroponicsToolSpade + entities: + - uid: 1838 + components: + - type: Transform + pos: 29.95761,43.361576 + parent: 588 + - uid: 1842 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.42777,20.58681 + parent: 588 +- proto: hydroponicsTray + entities: + - uid: 796 + components: + - type: Transform + pos: 31.5,21.5 + parent: 588 + - uid: 797 + components: + - type: Transform + pos: 31.5,20.5 + parent: 588 + - uid: 798 + components: + - type: Transform + pos: 31.5,19.5 + parent: 588 + - uid: 1772 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,42.5 + parent: 588 + - uid: 1774 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,44.5 + parent: 588 + - uid: 1787 + components: + - type: Transform + pos: 30.5,44.5 + parent: 588 + - uid: 1788 + components: + - type: Transform + pos: 30.5,42.5 + parent: 588 +- proto: IngotGold + entities: + - uid: 952 + components: + - type: Transform + pos: 11.069347,39.504154 + parent: 588 +- proto: KitchenMicrowave + entities: + - uid: 524 + components: + - type: Transform + pos: 16.5,12.5 + parent: 588 + - uid: 709 + components: + - type: Transform + pos: 18.5,22.5 + parent: 588 + - uid: 1785 + components: + - type: Transform + pos: 29.5,48.5 + parent: 588 +- proto: KitchenReagentGrinder + entities: + - uid: 1786 + components: + - type: Transform + pos: 30.5,47.5 + parent: 588 +- proto: KnifePlastic + entities: + - uid: 530 + components: + - type: Transform + pos: 17.249546,12.643455 + parent: 588 + - uid: 1836 + components: + - type: Transform + pos: 30.241585,48.271698 + parent: 588 +- proto: Lamp + entities: + - uid: 581 + components: + - type: Transform + pos: 12.369425,13.798887 + parent: 588 +- proto: LampGold + entities: + - uid: 322 + components: + - type: Transform + pos: 18.419699,1.6320114 + parent: 588 + - uid: 323 + components: + - type: Transform + pos: 20.563715,4.8959665 + parent: 588 + - uid: 729 + components: + - type: Transform + pos: 6.4779434,22.892899 + parent: 588 + - uid: 730 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.765976,19.912766 + parent: 588 +- proto: Lighter + entities: + - uid: 1220 + components: + - type: Transform + pos: 7.5287867,36.397644 + parent: 588 +- proto: LockerDetective + entities: + - uid: 560 + components: + - type: Transform + pos: 14.5,16.5 + parent: 588 +- proto: LockerEvidence + entities: + - uid: 254 + components: + - type: Transform + pos: 16.5,0.5 + parent: 588 + - uid: 262 + components: + - type: Transform + pos: 2.5,0.5 + parent: 588 + - uid: 263 + components: + - type: Transform + pos: 4.5,0.5 + parent: 588 + - uid: 276 + components: + - type: Transform + pos: 0.5,0.5 + parent: 588 + - uid: 286 + components: + - type: Transform + pos: 12.5,0.5 + parent: 588 + - uid: 287 + components: + - type: Transform + pos: 14.5,0.5 + parent: 588 + - uid: 704 + components: + - type: Transform + pos: 16.5,22.5 + parent: 588 +- proto: LockerMedicineFilled + entities: + - uid: 1152 + components: + - type: Transform + pos: 28.5,27.5 + parent: 588 +- proto: LockerSecurityFilled + entities: + - uid: 416 + components: + - type: Transform + pos: 20.5,6.5 + parent: 588 +- proto: LockerSyndicatePersonal + entities: + - uid: 605 + components: + - type: Transform + pos: 6.5,12.5 + parent: 588 +- proto: MachineFrame + entities: + - uid: 400 + components: + - type: Transform + pos: 26.5,8.5 + parent: 588 +- proto: MaintenanceFluffSpawner + entities: + - uid: 414 + components: + - type: Transform + pos: 25.5,32.5 + parent: 588 + - uid: 1289 + components: + - type: Transform + pos: 17.5,38.5 + parent: 588 + - uid: 1290 + components: + - type: Transform + pos: 21.5,40.5 + parent: 588 + - uid: 1291 + components: + - type: Transform + pos: 20.5,40.5 + parent: 588 +- proto: MaintenanceWeaponSpawner + entities: + - uid: 548 + components: + - type: Transform + pos: 15.5,4.5 + parent: 588 + - uid: 549 + components: + - type: Transform + pos: 3.5,4.5 + parent: 588 + - uid: 1580 + components: + - type: Transform + pos: 1.5,8.5 + parent: 588 + - uid: 1581 + components: + - type: Transform + pos: 9.5,8.5 + parent: 588 +- proto: MaterialCloth1 + entities: + - uid: 702 + components: + - type: Transform + pos: 12.462601,18.586084 + parent: 588 + - uid: 1065 + components: + - type: Transform + pos: 24.460928,24.594687 + parent: 588 + - uid: 1066 + components: + - type: Transform + pos: 24.389935,24.296673 + parent: 588 +- proto: MaterialWoodPlank1 + entities: + - uid: 703 + components: + - type: Transform + pos: 12.817572,18.685423 + parent: 588 + - uid: 1064 + components: + - type: Transform + pos: 26.278374,24.608877 + parent: 588 + - uid: 1067 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 24.801699,24.708214 + parent: 588 + - uid: 1076 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.823982,27.574818 + parent: 588 +- proto: MedicalBed + entities: + - uid: 1146 + components: + - type: Transform + pos: 28.5,24.5 + parent: 588 + - uid: 1147 + components: + - type: Transform + pos: 28.5,25.5 + parent: 588 +- proto: MedkitAdvancedFilled + entities: + - uid: 1153 + components: + - type: Transform + pos: 30.614443,28.392822 + parent: 588 +- proto: MedkitCombatFilled + entities: + - uid: 1154 + components: + - type: Transform + pos: 30.40146,28.066427 + parent: 588 +- proto: OperatingTable + entities: + - uid: 1389 + components: + - type: Transform + pos: 9.5,43.5 + parent: 588 +- proto: Paper + entities: + - uid: 1055 + components: + - type: Transform + pos: 20.428474,24.722406 + parent: 588 + - uid: 1056 + components: + - type: Transform + pos: 20.669853,24.52373 + parent: 588 +- proto: PaperOffice + entities: + - uid: 327 + components: + - type: Transform + pos: 21.415642,4.0728827 + parent: 588 + - uid: 328 + components: + - type: Transform + pos: 21.586027,4.0019264 + parent: 588 + - uid: 1113 + components: + - type: Transform + pos: 20.706646,15.341779 + parent: 588 + - uid: 1114 + components: + - type: Transform + pos: 20.465267,15.185677 + parent: 588 + - uid: 1115 + components: + - type: Transform + pos: 20.30908,14.603841 + parent: 588 +- proto: PartRodMetal1 + entities: + - uid: 1071 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.341253,26.595633 + parent: 588 + - uid: 1072 + components: + - type: Transform + pos: 25.36965,28.11408 + parent: 588 +- proto: Pen + entities: + - uid: 366 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 21.352327,3.9473093 + parent: 588 + - uid: 367 + components: + - type: Transform + pos: 18.75395,1.1232786 + parent: 588 + - uid: 368 + components: + - type: Transform + pos: 24.788435,1.4496742 + parent: 588 + - uid: 731 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.36841,19.019064 + parent: 588 + - uid: 732 + components: + - type: Transform + pos: 7.4631767,22.637186 + parent: 588 +- proto: PhoneInstrument + entities: + - uid: 371 + components: + - type: Transform + pos: 25.484175,4.4865713 + parent: 588 +- proto: PillCanister + entities: + - uid: 1481 + components: + - type: Transform + pos: 14.438607,42.637726 + parent: 588 +- proto: PillSpaceDrugs + entities: + - uid: 1479 + components: + - type: Transform + pos: 14.438607,42.96412 + parent: 588 + - uid: 1480 + components: + - type: Transform + pos: 14.537998,42.878975 + parent: 588 +- proto: PlushieNuke + entities: + - uid: 1850 + components: + - type: Transform + pos: 22.519993,28.594225 + parent: 588 +- proto: PortableFlasher + entities: + - uid: 1234 + components: + - type: Transform + pos: 32.5,25.5 + parent: 588 +- proto: PortableGeneratorPacman + entities: + - uid: 967 + components: + - type: Transform + pos: 16.5,32.5 + parent: 588 + - uid: 969 + components: + - type: Transform + pos: 24.5,32.5 + parent: 588 +- proto: PortableGeneratorSuperPacman + entities: + - uid: 50 + components: + - type: Transform + pos: 26.5,15.5 + parent: 588 + - uid: 55 + components: + - type: Transform + pos: 28.5,15.5 + parent: 588 + - uid: 1504 + components: + - type: Transform + pos: 18.5,44.5 + parent: 588 + - uid: 1505 + components: + - type: Transform + pos: 20.5,44.5 + parent: 588 +- proto: PortableScrubber + entities: + - uid: 1101 + components: + - type: Transform + pos: 18.5,30.5 + parent: 588 +- proto: PosterContrabandBountyHunters + entities: + - uid: 1578 + components: + - type: Transform + pos: 13.5,15.5 + parent: 588 +- proto: PosterLegitDickGumshue + entities: + - uid: 1576 + components: + - type: Transform + pos: 9.5,15.5 + parent: 588 +- proto: PosterLegitEnlist + entities: + - uid: 1800 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 8.5,9.5 + parent: 588 +- proto: PosterLegitNanotrasenLogo + entities: + - uid: 1802 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,48.5 + parent: 588 + - uid: 1803 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,21.5 + parent: 588 +- proto: PosterLegitObey + entities: + - uid: 1801 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,42.5 + parent: 588 +- proto: PosterLegitSecWatch + entities: + - uid: 1799 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,7.5 + parent: 588 +- proto: PosterLegitSpaceCops + entities: + - uid: 1804 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,19.5 + parent: 588 +- proto: PottedPlantRandom + entities: + - uid: 1286 + components: + - type: Transform + pos: 16.5,38.5 + parent: 588 + - uid: 1287 + components: + - type: Transform + pos: 22.5,40.5 + parent: 588 +- proto: PowerCellHyper + entities: + - uid: 469 + components: + - type: Transform + pos: 12.355853,25.41643 + parent: 588 + - uid: 590 + components: + - type: Transform + pos: 5.381793,16.642464 + parent: 588 +- proto: PowerCellRecharger + entities: + - uid: 1103 + components: + - type: Transform + pos: 15.5,30.5 + parent: 588 + - uid: 1568 + components: + - type: Transform + pos: 21.5,47.5 + parent: 588 +- proto: Poweredlight + entities: + - uid: 1641 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,0.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1642 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 14.5,0.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1646 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,0.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1647 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,0.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1648 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 21.5,6.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1649 + components: + - type: Transform + pos: 13.5,10.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1650 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 16.5,6.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1651 + components: + - type: Transform + pos: 18.5,10.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1693 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 32.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1701 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 18.5,12.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1702 + components: + - type: Transform + pos: 20.5,16.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1703 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,20.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1704 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 16.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1705 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,27.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1706 + components: + - type: Transform + pos: 18.5,40.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1741 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,21.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1743 + components: + - type: Transform + pos: 21.5,22.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1830 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 30.5,43.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1831 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 30.5,47.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 +- proto: PoweredlightLED + entities: + - uid: 1707 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,42.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1708 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,42.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1709 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,46.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1710 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,46.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1725 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,27.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 +- proto: PoweredSmallLight + entities: + - uid: 470 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,14.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 940 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,28.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 948 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,28.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 953 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1603 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,10.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1604 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 32.5,10.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1605 + components: + - type: Transform + pos: 29.5,6.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1606 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 29.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1607 + components: + - type: Transform + pos: 32.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1608 + components: + - type: Transform + pos: 26.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1643 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,1.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1644 + components: + - type: Transform + pos: 20.5,4.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1645 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 19.5,0.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1652 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 9.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1653 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1654 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1655 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,8.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1656 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,14.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1657 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,14.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1659 + components: + - type: Transform + pos: 3.5,18.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1661 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,22.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1662 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,27.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1663 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1664 + components: + - type: Transform + pos: 0.5,28.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1665 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,24.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1666 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,30.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1667 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,30.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1668 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,36.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1669 + components: + - type: Transform + pos: 8.5,34.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1670 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,38.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1671 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,38.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1672 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,43.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1673 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,43.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1674 + components: + - type: Transform + pos: 2.5,47.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1675 + components: + - type: Transform + pos: 4.5,47.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1676 + components: + - type: Transform + pos: 9.5,40.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1677 + components: + - type: Transform + pos: 13.5,40.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1678 + components: + - type: Transform + pos: 13.5,36.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1679 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 21.5,34.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1680 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 32.5,35.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1681 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 34.5,35.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1682 + components: + - type: Transform + pos: 25.5,36.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1683 + components: + - type: Transform + pos: 28.5,38.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1684 + components: + - type: Transform + pos: 19.5,46.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1685 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 17.5,47.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1686 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 21.5,47.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1687 + components: + - type: Transform + pos: 23.5,32.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1688 + components: + - type: Transform + pos: 17.5,32.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1689 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,27.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1690 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1694 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,19.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1695 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 24.5,19.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1696 + components: + - type: Transform + pos: 13.5,22.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1697 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,18.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1698 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 15.5,18.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1699 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,16.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1700 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,13.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1828 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,42.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1829 + components: + - type: Transform + pos: 25.5,48.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 +- proto: PoweredSmallLightEmpty + entities: + - uid: 1640 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,25.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 1658 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,27.5 + parent: 588 + - type: ApcPowerReceiver + powerLoad: 0 +- proto: Rack + entities: + - uid: 255 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 15.5,0.5 + parent: 588 + - uid: 264 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,0.5 + parent: 588 + - uid: 283 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,0.5 + parent: 588 + - uid: 285 + components: + - type: Transform + pos: 13.5,0.5 + parent: 588 + - uid: 324 + components: + - type: Transform + pos: 19.5,4.5 + parent: 588 + - uid: 396 + components: + - type: Transform + pos: 28.5,8.5 + parent: 588 + - uid: 401 + components: + - type: Transform + pos: 32.5,8.5 + parent: 588 + - uid: 417 + components: + - type: Transform + pos: 12.5,6.5 + parent: 588 + - uid: 418 + components: + - type: Transform + pos: 12.5,10.5 + parent: 588 + - uid: 419 + components: + - type: Transform + pos: 22.5,10.5 + parent: 588 + - uid: 420 + components: + - type: Transform + pos: 22.5,6.5 + parent: 588 + - uid: 478 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,15.5 + parent: 588 + - uid: 551 + components: + - type: Transform + pos: 22.5,15.5 + parent: 588 + - uid: 585 + components: + - type: Transform + pos: 1.5,12.5 + parent: 588 + - uid: 596 + components: + - type: Transform + pos: 1.5,16.5 + parent: 588 + - uid: 597 + components: + - type: Transform + pos: 5.5,16.5 + parent: 588 + - uid: 598 + components: + - type: Transform + pos: 5.5,12.5 + parent: 588 + - uid: 966 + components: + - type: Transform + pos: 25.5,32.5 + parent: 588 + - uid: 977 + components: + - type: Transform + pos: 15.5,32.5 + parent: 588 + - uid: 1015 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,25.5 + parent: 588 + - uid: 1016 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,24.5 + parent: 588 + - uid: 1021 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,25.5 + parent: 588 + - uid: 1024 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,24.5 + parent: 588 + - uid: 1111 + components: + - type: Transform + pos: 14.5,32.5 + parent: 588 + - uid: 1112 + components: + - type: Transform + pos: 26.5,32.5 + parent: 588 + - uid: 1206 + components: + - type: Transform + pos: 1.5,8.5 + parent: 588 + - uid: 1208 + components: + - type: Transform + pos: 9.5,8.5 + parent: 588 + - uid: 1211 + components: + - type: Transform + pos: 2.5,34.5 + parent: 588 + - uid: 1319 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 29.5,40.5 + parent: 588 + - uid: 1562 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 17.5,47.5 + parent: 588 + - uid: 1858 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,21.5 + parent: 588 +- proto: Railing + entities: + - uid: 313 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 30.5,4.5 + parent: 588 + - uid: 314 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 30.5,0.5 + parent: 588 + - uid: 427 + components: + - type: Transform + pos: 6.5,7.5 + parent: 588 + - uid: 428 + components: + - type: Transform + pos: 4.5,7.5 + parent: 588 + - uid: 429 + components: + - type: Transform + pos: 3.5,7.5 + parent: 588 + - uid: 430 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,9.5 + parent: 588 + - uid: 431 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,9.5 + parent: 588 + - uid: 435 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,9.5 + parent: 588 + - uid: 436 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,9.5 + parent: 588 + - uid: 437 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,9.5 + parent: 588 + - uid: 439 + components: + - type: Transform + pos: 5.5,7.5 + parent: 588 + - uid: 440 + components: + - type: Transform + pos: 7.5,7.5 + parent: 588 + - uid: 770 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,21.5 + parent: 588 + - uid: 850 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,30.5 + parent: 588 + - uid: 851 + components: + - type: Transform + pos: 9.5,32.5 + parent: 588 + - uid: 854 + components: + - type: Transform + pos: 3.5,32.5 + parent: 588 + - uid: 855 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,30.5 + parent: 588 + - uid: 1259 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,4.5 + parent: 588 + - uid: 1260 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 9.5,4.5 + parent: 588 + - uid: 1261 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 9.5,0.5 + parent: 588 + - uid: 1262 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,0.5 + parent: 588 +- proto: RailingCorner + entities: + - uid: 315 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 30.5,1.5 + parent: 588 + - uid: 316 + components: + - type: Transform + pos: 30.5,3.5 + parent: 588 + - uid: 771 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 27.5,21.5 + parent: 588 + - uid: 772 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,21.5 + parent: 588 + - uid: 845 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,32.5 + parent: 588 + - uid: 846 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,30.5 + parent: 588 + - uid: 847 + components: + - type: Transform + pos: 10.5,32.5 + parent: 588 + - uid: 848 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,30.5 + parent: 588 + - uid: 849 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,30.5 + parent: 588 + - uid: 852 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 8.5,32.5 + parent: 588 + - uid: 853 + components: + - type: Transform + pos: 4.5,32.5 + parent: 588 + - uid: 856 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,30.5 + parent: 588 + - uid: 886 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,40.5 + parent: 588 + - uid: 888 + components: + - type: Transform + pos: 2.5,40.5 + parent: 588 + - uid: 890 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,40.5 + parent: 588 + - uid: 891 + components: + - type: Transform + pos: 5.5,40.5 + parent: 588 + - uid: 892 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,38.5 + parent: 588 + - uid: 893 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,38.5 + parent: 588 + - uid: 894 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,38.5 + parent: 588 + - uid: 895 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,38.5 + parent: 588 + - uid: 1255 + components: + - type: Transform + pos: 7.5,3.5 + parent: 588 + - uid: 1256 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 9.5,3.5 + parent: 588 + - uid: 1257 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,1.5 + parent: 588 + - uid: 1258 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,1.5 + parent: 588 + - uid: 1351 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,44.5 + parent: 588 + - uid: 1352 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,43.5 + parent: 588 + - uid: 1353 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,43.5 + parent: 588 + - uid: 1354 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,44.5 + parent: 588 + - uid: 1355 + components: + - type: Transform + pos: 1.5,46.5 + parent: 588 + - uid: 1356 + components: + - type: Transform + pos: 2.5,47.5 + parent: 588 + - uid: 1357 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,47.5 + parent: 588 + - uid: 1358 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,46.5 + parent: 588 +- proto: RailingCornerSmall + entities: + - uid: 337 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 29.5,3.5 + parent: 588 + - uid: 338 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 29.5,1.5 + parent: 588 + - uid: 1376 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,43.5 + parent: 588 + - uid: 1377 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,47.5 + parent: 588 + - uid: 1378 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,47.5 + parent: 588 + - uid: 1379 + components: + - type: Transform + pos: 5.5,43.5 + parent: 588 +- proto: RandomDrinkBottle + entities: + - uid: 580 + components: + - type: Transform + pos: 12.5,12.5 + parent: 588 +- proto: RandomFoodSingle + entities: + - uid: 764 + components: + - type: Transform + pos: 6.5,19.5 + parent: 588 +- proto: RandomInstruments + entities: + - uid: 546 + components: + - type: Transform + pos: 1.5,4.5 + parent: 588 + - uid: 1159 + components: + - type: Transform + pos: 21.5,18.5 + parent: 588 + - uid: 1833 + components: + - type: Transform + pos: 24.5,42.5 + parent: 588 +- proto: RandomPosterContraband + entities: + - uid: 1571 + components: + - type: Transform + pos: 25.5,39.5 + parent: 588 + - uid: 1572 + components: + - type: Transform + pos: 3.5,35.5 + parent: 588 + - uid: 1573 + components: + - type: Transform + pos: 7.5,35.5 + parent: 588 + - uid: 1574 + components: + - type: Transform + pos: 5.5,25.5 + parent: 588 + - uid: 1575 + components: + - type: Transform + pos: 30.5,15.5 + parent: 588 + - uid: 1805 + components: + - type: Transform + pos: 18.5,43.5 + parent: 588 + - uid: 1806 + components: + - type: Transform + pos: 20.5,47.5 + parent: 588 +- proto: RandomSoap + entities: + - uid: 397 + components: + - type: Transform + pos: 8.5,24.5 + parent: 588 +- proto: RandomVending + entities: + - uid: 539 + components: + - type: Transform + pos: 17.5,16.5 + parent: 588 +- proto: ReinforcedWindow + entities: + - uid: 214 + components: + - type: Transform + pos: 19.5,34.5 + parent: 588 + - uid: 409 + components: + - type: Transform + pos: 15.5,7.5 + parent: 588 + - uid: 410 + components: + - type: Transform + pos: 15.5,9.5 + parent: 588 + - uid: 411 + components: + - type: Transform + pos: 19.5,7.5 + parent: 588 + - uid: 412 + components: + - type: Transform + pos: 19.5,9.5 + parent: 588 + - uid: 591 + components: + - type: Transform + pos: 2.5,12.5 + parent: 588 + - uid: 592 + components: + - type: Transform + pos: 4.5,12.5 + parent: 588 + - uid: 594 + components: + - type: Transform + pos: 4.5,16.5 + parent: 588 + - uid: 595 + components: + - type: Transform + pos: 2.5,16.5 + parent: 588 + - uid: 1166 + components: + - type: Transform + pos: 19.5,36.5 + parent: 588 + - uid: 1168 + components: + - type: Transform + pos: 15.5,36.5 + parent: 588 + - uid: 1169 + components: + - type: Transform + pos: 15.5,34.5 + parent: 588 +- proto: RemoteSignaller + entities: + - uid: 593 + components: + - type: Transform + pos: 34.361877,24.623777 + parent: 588 + - type: DeviceLinkSource + linkedPorts: + 1238: + - Pressed: Toggle + 1239: + - Pressed: Toggle + 1237: + - Pressed: Toggle + - uid: 1104 + components: + - type: Transform + pos: 25.24476,30.698978 + parent: 588 + - uid: 1105 + components: + - type: Transform + pos: 25.443544,30.613832 + parent: 588 + - uid: 1106 + components: + - type: Transform + pos: 5.677143,16.762346 + parent: 588 +- proto: RiotLaserShield + entities: + - uid: 1618 + components: + - type: Transform + pos: 12.616156,10.534842 + parent: 588 +- proto: RiotShield + entities: + - uid: 600 + components: + - type: Transform + pos: 1.3209407,16.656654 + parent: 588 + - uid: 601 + components: + - type: Transform + pos: 1.5481212,16.543125 + parent: 588 +- proto: SalvageCanisterSpawner + entities: + - uid: 998 + components: + - type: Transform + pos: 22.5,30.5 + parent: 588 + - uid: 1009 + components: + - type: Transform + pos: 19.5,30.5 + parent: 588 + - uid: 1025 + components: + - type: Transform + pos: 21.5,30.5 + parent: 588 + - uid: 1190 + components: + - type: Transform + pos: 9.5,36.5 + parent: 588 + - uid: 1210 + components: + - type: Transform + pos: 9.5,48.5 + parent: 588 + - uid: 1413 + components: + - type: Transform + pos: 13.5,48.5 + parent: 588 + - uid: 1470 + components: + - type: Transform + pos: 12.5,48.5 + parent: 588 +- proto: SawAdvanced + entities: + - uid: 1468 + components: + - type: Transform + pos: 8.527969,43.529327 + parent: 588 +- proto: ScalpelLaser + entities: + - uid: 1472 + components: + - type: Transform + pos: 8.485372,43.131977 + parent: 588 +- proto: ScalpelShiv + entities: + - uid: 708 + components: + - type: Transform + pos: 16.074419,18.727995 + parent: 588 + - uid: 1592 + components: + - type: Transform + pos: 10.50393,24.491432 + parent: 588 +- proto: SeedExtractor + entities: + - uid: 802 + components: + - type: Transform + pos: 33.5,21.5 + parent: 588 + - uid: 1776 + components: + - type: Transform + pos: 28.5,42.5 + parent: 588 +- proto: SheetGlass + entities: + - uid: 649 + components: + - type: Transform + pos: 14.3137455,32.471424 + parent: 588 +- proto: SheetPlasteel + entities: + - uid: 866 + components: + - type: Transform + pos: 2.412651,34.456436 + parent: 588 +- proto: SheetPlastic + entities: + - uid: 398 + components: + - type: Transform + pos: 20.04785,45.07574 + parent: 588 +- proto: SheetSteel + entities: + - uid: 656 + components: + - type: Transform + pos: 26.36062,32.5183 + parent: 588 + - uid: 699 + components: + - type: Transform + pos: 29.259031,40.432583 + parent: 588 +- proto: ShowcaseRobot + entities: + - uid: 1621 + components: + - type: Transform + pos: 16.5,10.5 + parent: 588 + - uid: 1622 + components: + - type: Transform + pos: 18.5,6.5 + parent: 588 +- proto: ShuttersNormal + entities: + - uid: 1237 + components: + - type: Transform + pos: 34.5,27.5 + parent: 588 + - type: DeviceLinkSink + links: + - 593 + - uid: 1238 + components: + - type: Transform + pos: 32.5,27.5 + parent: 588 + - type: DeviceLinkSink + links: + - 593 +- proto: ShuttersWindow + entities: + - uid: 1239 + components: + - type: Transform + pos: 33.5,27.5 + parent: 588 + - type: DeviceLinkSink + links: + - 593 +- proto: SignCloning + entities: + - uid: 1484 + components: + - type: Transform + pos: 12.5,43.5 + parent: 588 +- proto: SignPrison + entities: + - uid: 1792 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,3.5 + parent: 588 + - uid: 1793 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,1.5 + parent: 588 + - uid: 1794 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,21.5 + parent: 588 + - uid: 1795 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,19.5 + parent: 588 + - uid: 1796 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,46.5 + parent: 588 + - uid: 1797 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,44.5 + parent: 588 +- proto: SignSecurity + entities: + - uid: 1798 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 22.5,1.5 + parent: 588 +- proto: SignSurgery + entities: + - uid: 1483 + components: + - type: Transform + pos: 10.5,43.5 + parent: 588 +- proto: Sink + entities: + - uid: 935 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,25.5 + parent: 588 +- proto: SinkStemlessWater + entities: + - uid: 1461 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 9.5,42.5 + parent: 588 + - uid: 1462 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,42.5 + parent: 588 +- proto: SMESBasic + entities: + - uid: 46 + components: + - type: Transform + pos: 26.5,13.5 + parent: 588 + - uid: 56 + components: + - type: Transform + pos: 28.5,13.5 + parent: 588 + - uid: 747 + components: + - type: Transform + pos: 26.5,19.5 + parent: 588 + - uid: 1506 + components: + - type: Transform + pos: 18.5,46.5 + parent: 588 + - uid: 1507 + components: + - type: Transform + pos: 20.5,46.5 + parent: 588 +- proto: SoapSyndie + entities: + - uid: 1856 + components: + - type: Transform + pos: 10.4890785,27.46785 + parent: 588 +- proto: SpaceCash100 + entities: + - uid: 1243 + components: + - type: Transform + pos: 11.887424,39.621456 + parent: 588 + - uid: 1244 + components: + - type: Transform + pos: 11.759636,39.479546 + parent: 588 + - uid: 1296 + components: + - type: Transform + pos: 12.100407,39.465355 + parent: 588 + - uid: 1297 + components: + - type: Transform + pos: 12.100407,39.80594 + parent: 588 + - uid: 1298 + components: + - type: Transform + pos: 11.688642,39.720795 + parent: 588 + - uid: 1299 + components: + - type: Transform + pos: 11.4330635,39.57888 + parent: 588 +- proto: Spear + entities: + - uid: 1834 + components: + - type: Transform + pos: 24.466219,48.441994 + parent: 588 +- proto: SpeedLoaderMagnum + entities: + - uid: 950 + components: + - type: Transform + pos: 28.703945,8.421182 + parent: 588 +- proto: StasisBed + entities: + - uid: 1425 + components: + - type: Transform + pos: 13.5,43.5 + parent: 588 +- proto: StimkitFilled + entities: + - uid: 561 + components: + - type: Transform + pos: 30.39083,27.514402 + parent: 588 +- proto: StimpackMini + entities: + - uid: 1879 + components: + - type: Transform + pos: 24.467485,46.702366 + parent: 588 +- proto: Stool + entities: + - uid: 1017 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,25.5 + parent: 588 + - uid: 1018 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 14.5,24.5 + parent: 588 + - uid: 1019 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 16.5,28.5 + parent: 588 + - uid: 1020 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,28.5 + parent: 588 + - uid: 1593 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,13.5 + parent: 588 + - uid: 1594 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,15.5 + parent: 588 + - uid: 1595 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,15.5 + parent: 588 + - uid: 1596 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,13.5 + parent: 588 +- proto: SubstationBasic + entities: + - uid: 467 + components: + - type: Transform + pos: 27.5,13.5 + parent: 588 + - uid: 1508 + components: + - type: Transform + pos: 19.5,46.5 + parent: 588 +- proto: SubstationWallBasic + entities: + - uid: 774 + components: + - type: Transform + pos: 27.5,19.5 + parent: 588 + - uid: 972 + components: + - type: Transform + pos: 19.5,32.5 + parent: 588 +- proto: SyringeEphedrine + entities: + - uid: 1475 + components: + - type: Transform + pos: 14.472328,42.917698 + parent: 588 +- proto: Table + entities: + - uid: 525 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 16.5,13.5 + parent: 588 + - uid: 527 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 16.5,12.5 + parent: 588 + - uid: 528 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 17.5,12.5 + parent: 588 + - uid: 535 + components: + - type: Transform + pos: 20.5,14.5 + parent: 588 + - uid: 536 + components: + - type: Transform + pos: 20.5,15.5 + parent: 588 + - uid: 630 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,19.5 + parent: 588 + - uid: 632 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,19.5 + parent: 588 + - uid: 633 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 10.5,18.5 + parent: 588 + - uid: 636 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,22.5 + parent: 588 + - uid: 637 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 7.5,22.5 + parent: 588 + - uid: 710 + components: + - type: Transform + pos: 18.5,22.5 + parent: 588 + - uid: 711 + components: + - type: Transform + pos: 18.5,21.5 + parent: 588 + - uid: 712 + components: + - type: Transform + pos: 21.5,18.5 + parent: 588 + - uid: 713 + components: + - type: Transform + pos: 22.5,18.5 + parent: 588 + - uid: 714 + components: + - type: Transform + pos: 18.5,18.5 + parent: 588 + - uid: 715 + components: + - type: Transform + pos: 19.5,18.5 + parent: 588 + - uid: 799 + components: + - type: Transform + pos: 33.5,20.5 + parent: 588 + - uid: 1118 + components: + - type: Transform + pos: 22.5,12.5 + parent: 588 + - uid: 1778 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 30.5,48.5 + parent: 588 + - uid: 1779 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 29.5,48.5 + parent: 588 + - uid: 1780 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 30.5,47.5 + parent: 588 +- proto: TableFrame + entities: + - uid: 705 + components: + - type: Transform + pos: 15.5,22.5 + parent: 588 + - uid: 1063 + components: + - type: Transform + pos: 26.5,24.5 + parent: 588 +- proto: TableGlass + entities: + - uid: 1144 + components: + - type: Transform + pos: 30.5,27.5 + parent: 588 + - uid: 1145 + components: + - type: Transform + pos: 30.5,28.5 + parent: 588 + - uid: 1390 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 8.5,43.5 + parent: 588 + - uid: 1391 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 8.5,42.5 + parent: 588 + - uid: 1398 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,44.5 + parent: 588 + - uid: 1405 + components: + - type: Transform + pos: 14.5,42.5 + parent: 588 + - uid: 1406 + components: + - type: Transform + pos: 14.5,43.5 + parent: 588 + - uid: 1407 + components: + - type: Transform + pos: 12.5,44.5 + parent: 588 +- proto: TableReinforced + entities: + - uid: 924 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,36.5 + parent: 588 + - uid: 925 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,35.5 + parent: 588 + - uid: 926 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,34.5 + parent: 588 + - uid: 1005 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 15.5,30.5 + parent: 588 + - uid: 1006 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,30.5 + parent: 588 + - uid: 1012 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 14.5,28.5 + parent: 588 + - uid: 1023 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 16.5,24.5 + parent: 588 + - uid: 1235 + components: + - type: Transform + pos: 34.5,24.5 + parent: 588 + - uid: 1567 + components: + - type: Transform + pos: 21.5,47.5 + parent: 588 +- proto: TableReinforcedGlass + entities: + - uid: 1213 + components: + - type: Transform + pos: 10.5,39.5 + parent: 588 + - uid: 1214 + components: + - type: Transform + pos: 11.5,39.5 + parent: 588 + - uid: 1215 + components: + - type: Transform + pos: 12.5,39.5 + parent: 588 +- proto: TableWood + entities: + - uid: 309 + components: + - type: Transform + pos: 20.5,4.5 + parent: 588 + - uid: 310 + components: + - type: Transform + pos: 21.5,4.5 + parent: 588 + - uid: 311 + components: + - type: Transform + pos: 18.5,0.5 + parent: 588 + - uid: 312 + components: + - type: Transform + pos: 21.5,3.5 + parent: 588 + - uid: 317 + components: + - type: Transform + pos: 18.5,1.5 + parent: 588 + - uid: 318 + components: + - type: Transform + pos: 19.5,0.5 + parent: 588 + - uid: 332 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,3.5 + parent: 588 + - uid: 333 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,3.5 + parent: 588 + - uid: 334 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 27.5,3.5 + parent: 588 + - uid: 335 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,4.5 + parent: 588 + - uid: 336 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 27.5,4.5 + parent: 588 + - uid: 340 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 24.5,1.5 + parent: 588 + - uid: 341 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.5,1.5 + parent: 588 + - uid: 342 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 27.5,1.5 + parent: 588 + - uid: 343 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 28.5,1.5 + parent: 588 + - uid: 563 + components: + - type: Transform + pos: 13.5,13.5 + parent: 588 + - uid: 564 + components: + - type: Transform + pos: 12.5,13.5 + parent: 588 + - uid: 565 + components: + - type: Transform + pos: 12.5,12.5 + parent: 588 + - uid: 1047 + components: + - type: Transform + pos: 22.5,28.5 + parent: 588 + - uid: 1048 + components: + - type: Transform + pos: 20.5,24.5 + parent: 588 + - uid: 1062 + components: + - type: Transform + pos: 26.5,28.5 + parent: 588 + - uid: 1227 + components: + - type: Transform + pos: 12.5,36.5 + parent: 588 + - uid: 1228 + components: + - type: Transform + pos: 22.5,34.5 + parent: 588 + - uid: 1783 + components: + - type: Transform + pos: 24.5,46.5 + parent: 588 + - uid: 1784 + components: + - type: Transform + pos: 24.5,44.5 + parent: 588 +- proto: TargetHuman + entities: + - uid: 1077 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 32.5,35.5 + parent: 588 +- proto: TintedWindow + entities: + - uid: 567 + components: + - type: Transform + pos: 12.5,15.5 + parent: 588 + - uid: 1463 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,43.5 + parent: 588 + - uid: 1464 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,43.5 + parent: 588 +- proto: ToiletEmpty + entities: + - uid: 932 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,24.5 + parent: 588 + - uid: 933 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,24.5 + parent: 588 + - uid: 934 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,25.5 + parent: 588 +- proto: UniformScrubsColorPurple + entities: + - uid: 1712 + components: + - type: Transform + pos: 10.503376,44.53288 + parent: 588 +- proto: VendingMachineChefvend + entities: + - uid: 532 + components: + - type: Transform + pos: 18.5,12.5 + parent: 588 +- proto: VendingMachineCigs + entities: + - uid: 720 + components: + - type: Transform + pos: 22.5,22.5 + parent: 588 +- proto: VendingMachineCoffee + entities: + - uid: 765 + components: + - type: Transform + pos: 10.5,22.5 + parent: 588 + - uid: 1285 + components: + - type: Transform + pos: 18.5,40.5 + parent: 588 +- proto: VendingMachineDetDrobe + entities: + - uid: 582 + components: + - type: Transform + pos: 10.5,14.5 + parent: 588 +- proto: VendingMachineDinnerware + entities: + - uid: 1781 + components: + - type: Transform + pos: 30.5,46.5 + parent: 588 +- proto: VendingMachineDonut + entities: + - uid: 538 + components: + - type: Transform + pos: 16.5,16.5 + parent: 588 +- proto: VendingMachineLawDrobe + entities: + - uid: 319 + components: + - type: Transform + pos: 18.5,4.5 + parent: 588 +- proto: VendingMachineMedical + entities: + - uid: 1143 + components: + - type: Transform + pos: 28.5,28.5 + parent: 588 +- proto: VendingMachineSec + entities: + - uid: 1013 + components: + - type: Transform + pos: 14.5,27.5 + parent: 588 +- proto: VendingMachineSeedsUnlocked + entities: + - uid: 800 + components: + - type: Transform + pos: 33.5,19.5 + parent: 588 + - uid: 1775 + components: + - type: Transform + pos: 28.5,44.5 + parent: 588 +- proto: WallmountTelescreen + entities: + - uid: 572 + components: + - type: Transform + pos: 13.5,13.5 + parent: 588 +- proto: WallPlastitaniumIndestructible + entities: + - uid: 377 + components: + - type: Transform + pos: 30.5,7.5 + parent: 588 + - uid: 378 + components: + - type: Transform + pos: 29.5,7.5 + parent: 588 + - uid: 379 + components: + - type: Transform + pos: 25.5,9.5 + parent: 588 + - uid: 380 + components: + - type: Transform + pos: 27.5,9.5 + parent: 588 + - uid: 381 + components: + - type: Transform + pos: 27.5,8.5 + parent: 588 + - uid: 382 + components: + - type: Transform + pos: 28.5,9.5 + parent: 588 + - uid: 383 + components: + - type: Transform + pos: 31.5,9.5 + parent: 588 + - uid: 384 + components: + - type: Transform + pos: 31.5,8.5 + parent: 588 + - uid: 385 + components: + - type: Transform + pos: 31.5,7.5 + parent: 588 + - uid: 386 + components: + - type: Transform + pos: 25.5,8.5 + parent: 588 + - uid: 387 + components: + - type: Transform + pos: 33.5,7.5 + parent: 588 + - uid: 388 + components: + - type: Transform + pos: 25.5,7.5 + parent: 588 + - uid: 389 + components: + - type: Transform + pos: 27.5,7.5 + parent: 588 + - uid: 390 + components: + - type: Transform + pos: 30.5,9.5 + parent: 588 + - uid: 391 + components: + - type: Transform + pos: 28.5,7.5 + parent: 588 + - uid: 392 + components: + - type: Transform + pos: 26.5,9.5 + parent: 588 + - uid: 393 + components: + - type: Transform + pos: 33.5,8.5 + parent: 588 + - uid: 394 + components: + - type: Transform + pos: 33.5,9.5 + parent: 588 + - uid: 395 + components: + - type: Transform + pos: 32.5,9.5 + parent: 588 +- proto: WallReinforced + entities: + - uid: 45 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,8.5 + parent: 588 + - uid: 51 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,8.5 + parent: 588 + - uid: 244 + components: + - type: Transform + pos: 6.5,4.5 + parent: 588 + - uid: 245 + components: + - type: Transform + pos: 6.5,3.5 + parent: 588 + - uid: 246 + components: + - type: Transform + pos: 10.5,4.5 + parent: 588 + - uid: 247 + components: + - type: Transform + pos: 10.5,3.5 + parent: 588 + - uid: 266 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,1.5 + parent: 588 + - uid: 267 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,0.5 + parent: 588 + - uid: 268 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,1.5 + parent: 588 + - uid: 269 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,0.5 + parent: 588 + - uid: 291 + components: + - type: Transform + pos: 15.5,6.5 + parent: 588 + - uid: 292 + components: + - type: Transform + pos: 19.5,6.5 + parent: 588 + - uid: 405 + components: + - type: Transform + pos: 15.5,10.5 + parent: 588 + - uid: 406 + components: + - type: Transform + pos: 19.5,10.5 + parent: 588 + - uid: 426 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,9.5 + parent: 588 + - uid: 432 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,7.5 + parent: 588 + - uid: 433 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,9.5 + parent: 588 + - uid: 434 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,7.5 + parent: 588 + - uid: 570 + components: + - type: Transform + pos: 0.5,46.5 + parent: 588 + - uid: 621 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,21.5 + parent: 588 + - uid: 622 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,19.5 + parent: 588 + - uid: 623 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,21.5 + parent: 588 + - uid: 627 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,19.5 + parent: 588 + - uid: 1078 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 33.5,35.5 + parent: 588 + - uid: 1330 + components: + - type: Transform + pos: 0.5,44.5 + parent: 588 + - uid: 1332 + components: + - type: Transform + pos: 2.5,42.5 + parent: 588 + - uid: 1334 + components: + - type: Transform + pos: 4.5,42.5 + parent: 588 + - uid: 1335 + components: + - type: Transform + pos: 6.5,44.5 + parent: 588 + - uid: 1337 + components: + - type: Transform + pos: 4.5,48.5 + parent: 588 + - uid: 1338 + components: + - type: Transform + pos: 6.5,46.5 + parent: 588 + - uid: 1340 + components: + - type: Transform + pos: 2.5,48.5 + parent: 588 +- proto: WallSolid + entities: + - uid: 140 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,25.5 + parent: 588 + - uid: 144 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,26.5 + parent: 588 + - uid: 145 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,25.5 + parent: 588 + - uid: 146 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,27.5 + parent: 588 + - uid: 205 + components: + - type: Transform + pos: 8.5,35.5 + parent: 588 + - uid: 206 + components: + - type: Transform + pos: 7.5,35.5 + parent: 588 + - uid: 207 + components: + - type: Transform + pos: 6.5,35.5 + parent: 588 + - uid: 208 + components: + - type: Transform + pos: 4.5,35.5 + parent: 588 + - uid: 210 + components: + - type: Transform + pos: 1.5,34.5 + parent: 588 + - uid: 305 + components: + - type: Transform + pos: 22.5,4.5 + parent: 588 + - uid: 306 + components: + - type: Transform + pos: 22.5,3.5 + parent: 588 + - uid: 307 + components: + - type: Transform + pos: 22.5,0.5 + parent: 588 + - uid: 308 + components: + - type: Transform + pos: 22.5,1.5 + parent: 588 + - uid: 476 + components: + - type: Transform + pos: 25.5,13.5 + parent: 588 + - uid: 481 + components: + - type: Transform + pos: 25.5,15.5 + parent: 588 + - uid: 483 + components: + - type: Transform + pos: 30.5,13.5 + parent: 588 + - uid: 501 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 25.5,14.5 + parent: 588 + - uid: 510 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 30.5,15.5 + parent: 588 + - uid: 749 + components: + - type: Transform + pos: 25.5,19.5 + parent: 588 + - uid: 750 + components: + - type: Transform + pos: 27.5,19.5 + parent: 588 + - uid: 975 + components: + - type: Transform + pos: 19.5,32.5 + parent: 588 + - uid: 995 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 21.5,32.5 + parent: 588 + - uid: 1163 + components: + - type: Transform + pos: 8.5,36.5 + parent: 588 + - uid: 1164 + components: + - type: Transform + pos: 3.5,35.5 + parent: 588 + - uid: 1165 + components: + - type: Transform + pos: 2.5,35.5 + parent: 588 + - uid: 1167 + components: + - type: Transform + pos: 1.5,35.5 + parent: 588 + - uid: 1300 + components: + - type: Transform + pos: 25.5,39.5 + parent: 588 + - uid: 1303 + components: + - type: Transform + pos: 28.5,39.5 + parent: 588 + - uid: 1304 + components: + - type: Transform + pos: 29.5,39.5 + parent: 588 + - uid: 1305 + components: + - type: Transform + pos: 28.5,40.5 + parent: 588 + - uid: 1485 + components: + - type: Transform + pos: 17.5,43.5 + parent: 588 + - uid: 1486 + components: + - type: Transform + pos: 17.5,44.5 + parent: 588 + - uid: 1487 + components: + - type: Transform + pos: 18.5,43.5 + parent: 588 + - uid: 1488 + components: + - type: Transform + pos: 20.5,43.5 + parent: 588 + - uid: 1489 + components: + - type: Transform + pos: 21.5,43.5 + parent: 588 + - uid: 1490 + components: + - type: Transform + pos: 21.5,44.5 + parent: 588 + - uid: 1491 + components: + - type: Transform + pos: 18.5,47.5 + parent: 588 + - uid: 1492 + components: + - type: Transform + pos: 19.5,47.5 + parent: 588 + - uid: 1493 + components: + - type: Transform + pos: 20.5,47.5 + parent: 588 +- proto: WallWood + entities: + - uid: 554 + components: + - type: Transform + pos: 9.5,13.5 + parent: 588 + - uid: 555 + components: + - type: Transform + pos: 9.5,14.5 + parent: 588 + - uid: 556 + components: + - type: Transform + pos: 9.5,15.5 + parent: 588 + - uid: 557 + components: + - type: Transform + pos: 10.5,15.5 + parent: 588 + - uid: 558 + components: + - type: Transform + pos: 13.5,15.5 + parent: 588 + - uid: 559 + components: + - type: Transform + pos: 13.5,16.5 + parent: 588 + - uid: 566 + components: + - type: Transform + pos: 9.5,12.5 + parent: 588 +- proto: WardrobePrisonFilled + entities: + - uid: 297 + components: + - type: Transform + pos: 2.5,4.5 + parent: 588 + - uid: 302 + components: + - type: Transform + pos: 4.5,4.5 + parent: 588 + - uid: 303 + components: + - type: Transform + pos: 12.5,4.5 + parent: 588 + - uid: 304 + components: + - type: Transform + pos: 14.5,4.5 + parent: 588 + - uid: 544 + components: + - type: Transform + pos: 16.5,4.5 + parent: 588 + - uid: 545 + components: + - type: Transform + pos: 0.5,4.5 + parent: 588 + - uid: 1769 + components: + - type: Transform + pos: 24.5,43.5 + parent: 588 + - uid: 1770 + components: + - type: Transform + pos: 24.5,47.5 + parent: 588 +- proto: WaterCooler + entities: + - uid: 629 + components: + - type: Transform + pos: 6.5,18.5 + parent: 588 + - uid: 724 + components: + - type: Transform + pos: 19.5,22.5 + parent: 588 + - uid: 1284 + components: + - type: Transform + pos: 17.5,40.5 + parent: 588 + - uid: 1292 + components: + - type: Transform + pos: 21.5,12.5 + parent: 588 +- proto: WaterTankHighCapacity + entities: + - uid: 801 + components: + - type: Transform + pos: 30.5,22.5 + parent: 588 + - uid: 1789 + components: + - type: Transform + pos: 28.5,48.5 + parent: 588 +- proto: WeaponCapacitorRecharger + entities: + - uid: 760 + components: + - type: Transform + pos: 10.5,18.5 + parent: 588 + - uid: 929 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 26.5,34.5 + parent: 588 + - uid: 1033 + components: + - type: Transform + pos: 14.5,28.5 + parent: 588 + - uid: 1034 + components: + - type: Transform + pos: 16.5,24.5 + parent: 588 +- proto: WeaponDisablerPractice + entities: + - uid: 547 + components: + - type: Transform + pos: 1.4370823,0.5241035 + parent: 588 + - uid: 930 + components: + - type: Transform + pos: 26.440151,36.61676 + parent: 588 + - uid: 1611 + components: + - type: Transform + pos: 12.371853,10.605072 + parent: 588 +- proto: WeaponLaserCarbinePractice + entities: + - uid: 931 + components: + - type: Transform + pos: 26.596338,36.36132 + parent: 588 + - uid: 1612 + components: + - type: Transform + pos: 22.543945,6.5464144 + parent: 588 +- proto: WeaponShotgunKammerer + entities: + - uid: 583 + components: + - type: Transform + pos: 26.57963,35.4414 + parent: 588 +- proto: WindoorAssemblySecure + entities: + - uid: 696 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 16.5,19.5 + parent: 588 + - uid: 697 + components: + - type: Transform + pos: 12.5,21.5 + parent: 588 + - uid: 1073 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,25.5 + parent: 588 +- proto: WindoorSecure + entities: + - uid: 1761 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,43.5 + parent: 588 + - uid: 1762 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,47.5 + parent: 588 +- proto: WindoorSecureBrigLocked + entities: + - uid: 339 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 29.5,2.5 + parent: 588 +- proto: WindoorSecureEngineeringLocked + entities: + - uid: 1569 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,45.5 + parent: 588 + - uid: 1570 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,45.5 + parent: 588 +- proto: WindoorSecureMedicalLocked + entities: + - uid: 1408 + components: + - type: Transform + pos: 11.5,44.5 + parent: 588 +- proto: WindoorSecureSecurityLocked + entities: + - uid: 252 + components: + - type: Transform + pos: 4.5,3.5 + parent: 588 + - uid: 253 + components: + - type: Transform + pos: 2.5,3.5 + parent: 588 + - uid: 256 + components: + - type: Transform + pos: 16.5,3.5 + parent: 588 + - uid: 274 + components: + - type: Transform + pos: 12.5,3.5 + parent: 588 + - uid: 275 + components: + - type: Transform + pos: 14.5,3.5 + parent: 588 + - uid: 289 + components: + - type: Transform + pos: 0.5,3.5 + parent: 588 + - uid: 698 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 12.5,19.5 + parent: 588 + - uid: 1053 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 21.5,25.5 + parent: 588 + - uid: 1054 + components: + - type: Transform + pos: 21.5,27.5 + parent: 588 +- proto: WindowDirectional + entities: + - uid: 480 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,15.5 + parent: 588 + - uid: 482 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 27.5,15.5 + parent: 588 + - uid: 540 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,15.5 + parent: 588 + - uid: 541 + components: + - type: Transform + pos: 26.5,13.5 + parent: 588 + - uid: 542 + components: + - type: Transform + pos: 27.5,13.5 + parent: 588 + - uid: 543 + components: + - type: Transform + pos: 28.5,13.5 + parent: 588 + - uid: 575 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,20.5 + parent: 588 + - uid: 576 + components: + - type: Transform + pos: 26.5,19.5 + parent: 588 + - uid: 803 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,21.5 + parent: 588 + - uid: 804 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 33.5,19.5 + parent: 588 + - uid: 1087 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,36.5 + parent: 588 + - uid: 1088 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 27.5,34.5 + parent: 588 + - uid: 1520 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 18.5,46.5 + parent: 588 + - uid: 1521 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 20.5,46.5 + parent: 588 + - uid: 1771 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 28.5,44.5 + parent: 588 + - uid: 1773 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 29.5,44.5 + parent: 588 + - uid: 1777 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 30.5,44.5 + parent: 588 + - uid: 1782 + components: + - type: Transform + pos: 30.5,46.5 + parent: 588 +- proto: WindowFrostedDirectional + entities: + - uid: 936 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,24.5 + parent: 588 + - uid: 937 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 10.5,24.5 + parent: 588 + - uid: 938 + components: + - type: Transform + pos: 8.5,27.5 + parent: 588 + - uid: 939 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 8.5,25.5 + parent: 588 + - uid: 941 + components: + - type: Transform + pos: 10.5,27.5 + parent: 588 + - uid: 942 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 10.5,28.5 + parent: 588 + - uid: 943 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 8.5,28.5 + parent: 588 + - uid: 1392 + components: + - type: Transform + pos: 8.5,44.5 + parent: 588 + - uid: 1393 + components: + - type: Transform + pos: 10.5,44.5 + parent: 588 + - uid: 1401 + components: + - type: Transform + pos: 12.5,44.5 + parent: 588 + - uid: 1402 + components: + - type: Transform + pos: 14.5,44.5 + parent: 588 + - uid: 1753 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,43.5 + parent: 588 + - uid: 1754 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 25.5,43.5 + parent: 588 + - uid: 1755 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,43.5 + parent: 588 + - uid: 1756 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,42.5 + parent: 588 + - uid: 1757 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 26.5,48.5 + parent: 588 + - uid: 1758 + components: + - type: Transform + pos: 26.5,47.5 + parent: 588 + - uid: 1759 + components: + - type: Transform + pos: 25.5,47.5 + parent: 588 + - uid: 1760 + components: + - type: Transform + pos: 24.5,47.5 + parent: 588 +- proto: WindowReinforcedDirectional + entities: + - uid: 97 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,14.5 + parent: 588 + - uid: 99 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,14.5 + parent: 588 + - uid: 258 + components: + - type: Transform + pos: 3.5,3.5 + parent: 588 + - uid: 259 + components: + - type: Transform + pos: 5.5,3.5 + parent: 588 + - uid: 260 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,3.5 + parent: 588 + - uid: 261 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,4.5 + parent: 588 + - uid: 270 + components: + - type: Transform + pos: 11.5,3.5 + parent: 588 + - uid: 271 + components: + - type: Transform + pos: 13.5,3.5 + parent: 588 + - uid: 272 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 13.5,3.5 + parent: 588 + - uid: 273 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 13.5,4.5 + parent: 588 + - uid: 277 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,4.5 + parent: 588 + - uid: 278 + components: + - type: Transform + pos: 15.5,3.5 + parent: 588 + - uid: 279 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 15.5,4.5 + parent: 588 + - uid: 280 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,3.5 + parent: 588 + - uid: 281 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 15.5,3.5 + parent: 588 + - uid: 290 + components: + - type: Transform + pos: 1.5,3.5 + parent: 588 + - uid: 607 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,14.5 + parent: 588 + - uid: 609 + components: + - type: Transform + pos: 4.5,14.5 + parent: 588 + - uid: 611 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,14.5 + parent: 588 + - uid: 612 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,14.5 + parent: 588 + - uid: 614 + components: + - type: Transform + pos: 3.5,14.5 + parent: 588 + - uid: 619 + components: + - type: Transform + pos: 2.5,14.5 + parent: 588 + - uid: 620 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,20.5 + parent: 588 + - uid: 624 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,20.5 + parent: 588 + - uid: 625 + components: + - type: Transform + pos: 2.5,19.5 + parent: 588 + - uid: 626 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,21.5 + parent: 588 + - uid: 648 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 15.5,19.5 + parent: 588 + - uid: 650 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,18.5 + parent: 588 + - uid: 651 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 13.5,19.5 + parent: 588 + - uid: 652 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 15.5,19.5 + parent: 588 + - uid: 653 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 15.5,18.5 + parent: 588 + - uid: 654 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,21.5 + parent: 588 + - uid: 658 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,22.5 + parent: 588 + - uid: 660 + components: + - type: Transform + pos: 13.5,21.5 + parent: 588 + - uid: 805 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,27.5 + parent: 588 + - uid: 806 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,26.5 + parent: 588 + - uid: 807 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,25.5 + parent: 588 + - uid: 808 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,25.5 + parent: 588 + - uid: 809 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,26.5 + parent: 588 + - uid: 810 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,27.5 + parent: 588 + - uid: 811 + components: + - type: Transform + pos: 1.5,25.5 + parent: 588 + - uid: 812 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,27.5 + parent: 588 + - uid: 1038 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 22.5,25.5 + parent: 588 + - uid: 1039 + components: + - type: Transform + pos: 20.5,27.5 + parent: 588 + - uid: 1042 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 20.5,25.5 + parent: 588 + - uid: 1045 + components: + - type: Transform + pos: 22.5,27.5 + parent: 588 + - uid: 1058 + components: + - type: Transform + pos: 24.5,27.5 + parent: 588 + - uid: 1059 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 26.5,25.5 + parent: 588 + - uid: 1060 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 24.5,25.5 + parent: 588 + - uid: 1399 + components: + - type: Transform + pos: 9.5,44.5 + parent: 588 + - uid: 1400 + components: + - type: Transform + pos: 13.5,44.5 + parent: 588 +- proto: Wrench + entities: + - uid: 424 + components: + - type: Transform + pos: 15.156982,32.526764 + parent: 588 +- proto: Zipties + entities: + - uid: 1156 + components: + - type: Transform + pos: 15.332411,0.52492684 + parent: 588 +- proto: ZiptiesBroken + entities: + - uid: 48 + components: + - type: Transform + pos: 5.2591753,3.5817227 + parent: 588 + - uid: 706 + components: + - type: Transform + pos: 16.06022,21.977758 + parent: 588 +... diff --git a/Resources/Maps/Ruins/DeltaV/biodome_satellite.yml b/Resources/Maps/Ruins/DeltaV/biodome_satellite.yml index 02d55a3cf09..4631b1aad82 100644 --- a/Resources/Maps/Ruins/DeltaV/biodome_satellite.yml +++ b/Resources/Maps/Ruins/DeltaV/biodome_satellite.yml @@ -73,6 +73,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Ruins/DeltaV/old_ai_sat.yml b/Resources/Maps/Ruins/DeltaV/old_ai_sat.yml index 2b4110b7814..3d0ef0b73b1 100644 --- a/Resources/Maps/Ruins/DeltaV/old_ai_sat.yml +++ b/Resources/Maps/Ruins/DeltaV/old_ai_sat.yml @@ -81,6 +81,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Salvage/DeltaV/DV-atlas-conference-room.yml b/Resources/Maps/Salvage/DeltaV/DV-atlas-conference-room.yml index c01a214ca52..4664f07f40a 100644 --- a/Resources/Maps/Salvage/DeltaV/DV-atlas-conference-room.yml +++ b/Resources/Maps/Salvage/DeltaV/DV-atlas-conference-room.yml @@ -55,6 +55,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Salvage/small-3.yml b/Resources/Maps/Salvage/small-3.yml index 7a29b665ff6..cc015fe27b9 100644 --- a/Resources/Maps/Salvage/small-3.yml +++ b/Resources/Maps/Salvage/small-3.yml @@ -926,176 +926,132 @@ entities: rot: 3.141592653589793 rad pos: 1.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 4 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 6 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 7 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 14 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 17 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 24 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 25 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 26 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 29 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 30 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 31 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 37 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 38 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 44 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 48 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 49 components: - type: Transform rot: -1.5707963267948966 rad pos: -6.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 50 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 51 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 52 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 53 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 66 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 75 components: - type: Transform @@ -1108,8 +1064,6 @@ entities: rot: -1.5707963267948966 rad pos: -2.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 78 components: - type: Transform @@ -1122,144 +1076,108 @@ entities: rot: -1.5707963267948966 rad pos: -3.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 80 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 97 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 101 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 105 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 106 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 107 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 108 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 110 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 112 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 115 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 116 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 117 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 118 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 119 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 120 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 121 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 122 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 123 components: - type: Transform @@ -1278,48 +1196,36 @@ entities: rot: -1.5707963267948966 rad pos: -1.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 126 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 127 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 128 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 129 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 130 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 131 components: - type: Transform @@ -1332,88 +1238,66 @@ entities: rot: 3.141592653589793 rad pos: -1.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 133 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 134 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 135 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 136 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 137 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 138 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 139 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 140 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 141 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 142 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 143 components: - type: Transform @@ -1444,40 +1328,30 @@ entities: rot: -1.5707963267948966 rad pos: 2.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 148 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 149 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 150 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 151 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 152 components: - type: Transform @@ -1490,112 +1364,84 @@ entities: rot: -1.5707963267948966 rad pos: 5.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 154 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 155 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 156 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 157 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 158 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 159 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 160 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 161 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 162 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 163 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 164 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 165 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 166 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 167 components: - type: Transform @@ -1614,56 +1460,42 @@ entities: rot: -1.5707963267948966 rad pos: 8.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 170 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 171 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 172 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 173 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 174 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 175 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 176 components: - type: Transform @@ -1676,8 +1508,6 @@ entities: rot: -1.5707963267948966 rad pos: 9.5,5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 178 components: - type: Transform @@ -1690,1104 +1520,828 @@ entities: rot: 3.141592653589793 rad pos: 9.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 180 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 181 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 182 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 183 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 184 components: - type: Transform rot: 3.141592653589793 rad pos: 10.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 185 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 186 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 187 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 188 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 189 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 190 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 191 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 192 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 193 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 194 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 195 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 196 components: - type: Transform rot: 3.141592653589793 rad pos: 10.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 197 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 198 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 199 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 200 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 201 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 202 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 203 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 204 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 205 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 206 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 207 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 208 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 209 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 210 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 211 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 212 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 213 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 214 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 215 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 216 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 217 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 218 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 219 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 220 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 221 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 222 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 223 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 224 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 225 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 226 components: - type: Transform rot: 3.141592653589793 rad pos: -8.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 227 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 228 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 229 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 230 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 231 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 232 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 233 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 234 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 235 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 236 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 237 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 238 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 239 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 240 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 241 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 242 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 243 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 244 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 245 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 246 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 247 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 248 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 249 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 250 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 251 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 252 components: - type: Transform rot: 3.141592653589793 rad pos: -1.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 253 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 254 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 255 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 256 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 257 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 258 components: - type: Transform rot: -1.5707963267948966 rad pos: -6.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 259 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 260 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 261 components: - type: Transform rot: 3.141592653589793 rad pos: -8.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 262 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 263 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 264 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 265 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 266 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 267 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 268 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 269 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 270 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 271 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 272 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 273 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 274 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 275 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 276 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 277 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 278 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 279 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 280 components: - type: Transform rot: 3.141592653589793 rad pos: -1.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 281 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 282 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 283 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 284 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 285 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 286 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 287 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 288 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 289 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 290 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 291 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 292 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 293 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 294 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 295 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 296 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 297 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 298 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 299 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 300 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 301 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 302 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 303 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 304 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 305 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 306 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 307 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 308 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-1.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 309 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-0.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 310 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 311 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 312 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 313 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 314 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 315 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 316 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,-2.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 317 components: - type: Transform @@ -2800,982 +2354,736 @@ entities: rot: 3.141592653589793 rad pos: 4.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 319 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 320 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 321 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 322 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 323 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 324 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 325 components: - type: Transform rot: 3.141592653589793 rad pos: 10.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 326 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 327 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 328 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 329 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 330 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 331 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 332 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 333 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 334 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 335 components: - type: Transform rot: 3.141592653589793 rad pos: 10.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 336 components: - type: Transform rot: -1.5707963267948966 rad pos: 10.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 337 components: - type: Transform rot: 3.141592653589793 rad pos: 9.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 338 components: - type: Transform rot: 3.141592653589793 rad pos: 8.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 339 components: - type: Transform rot: -1.5707963267948966 rad pos: 8.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 340 components: - type: Transform rot: 3.141592653589793 rad pos: 10.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 341 components: - type: Transform rot: -1.5707963267948966 rad pos: 9.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 342 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 343 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 344 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 345 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 346 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 347 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 348 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 349 components: - type: Transform rot: -1.5707963267948966 rad pos: 3.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 350 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 351 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 352 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 353 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 354 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 355 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 356 components: - type: Transform rot: 3.141592653589793 rad pos: 5.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 357 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 358 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 359 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 360 components: - type: Transform rot: -1.5707963267948966 rad pos: 7.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 361 components: - type: Transform rot: 3.141592653589793 rad pos: 7.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 362 components: - type: Transform rot: 3.141592653589793 rad pos: 6.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 363 components: - type: Transform rot: -1.5707963267948966 rad pos: 6.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 364 components: - type: Transform rot: -1.5707963267948966 rad pos: 5.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 365 components: - type: Transform rot: 3.141592653589793 rad pos: 4.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 366 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 367 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 368 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 369 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 370 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 371 components: - type: Transform rot: -1.5707963267948966 rad pos: 4.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 372 components: - type: Transform rot: 3.141592653589793 rad pos: 3.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 373 components: - type: Transform rot: 3.141592653589793 rad pos: 2.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 374 components: - type: Transform rot: -1.5707963267948966 rad pos: 2.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 375 components: - type: Transform rot: 3.141592653589793 rad pos: 1.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 376 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 377 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 378 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 379 components: - type: Transform rot: 3.141592653589793 rad pos: 0.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 380 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 381 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 382 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 383 components: - type: Transform rot: -1.5707963267948966 rad pos: 1.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 384 components: - type: Transform rot: 3.141592653589793 rad pos: -8.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 385 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 386 components: - type: Transform rot: -1.5707963267948966 rad pos: -7.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 387 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 388 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 389 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 390 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 391 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 392 components: - type: Transform rot: -1.5707963267948966 rad pos: -6.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 393 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 394 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 395 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 396 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 397 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 398 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 399 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 400 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 401 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 402 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 403 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 404 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 405 components: - type: Transform rot: 3.141592653589793 rad pos: -8.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 406 components: - type: Transform rot: -1.5707963267948966 rad pos: -6.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 407 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 408 components: - type: Transform rot: 3.141592653589793 rad pos: -7.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 409 components: - type: Transform rot: 3.141592653589793 rad pos: -6.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 410 components: - type: Transform rot: -1.5707963267948966 rad pos: -5.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 411 components: - type: Transform rot: 3.141592653589793 rad pos: -5.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 412 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 413 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 414 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 415 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 416 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 417 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 418 components: - type: Transform rot: 3.141592653589793 rad pos: -1.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 419 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 420 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 421 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,-6.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 422 components: - type: Transform rot: -1.5707963267948966 rad pos: -3.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 423 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 424 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 425 components: - type: Transform rot: -1.5707963267948966 rad pos: -2.5,-7.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 426 components: - type: Transform rot: -1.5707963267948966 rad pos: -4.5,-3.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 427 components: - type: Transform rot: 3.141592653589793 rad pos: -4.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 428 components: - type: Transform rot: 3.141592653589793 rad pos: -3.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 429 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 430 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,-4.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 431 components: - type: Transform rot: 3.141592653589793 rad pos: -1.5,-5.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 432 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 433 components: - type: Transform rot: -1.5707963267948966 rad pos: 0.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 434 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 435 components: - type: Transform rot: 3.141592653589793 rad pos: -1.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 436 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-8.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 437 components: - type: Transform rot: 3.141592653589793 rad pos: -0.5,-10.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 438 components: - type: Transform rot: -1.5707963267948966 rad pos: -0.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 439 components: - type: Transform rot: -1.5707963267948966 rad pos: -1.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} - uid: 440 components: - type: Transform rot: 3.141592653589793 rad pos: -2.5,-9.5 parent: 10 - - type: Godmode - oldDamage: {} ... diff --git a/Resources/Maps/Salvage/vegan-meatball.yml b/Resources/Maps/Salvage/vegan-meatball.yml index 824e3d0b7ea..ab67aabadbf 100644 --- a/Resources/Maps/Salvage/vegan-meatball.yml +++ b/Resources/Maps/Salvage/vegan-meatball.yml @@ -505,7 +505,7 @@ entities: chemicals: THC: Inherent: True - PotencyDivisor: 10 + potencyDivisor: 10 Max: 10 Min: 1 productPrototypes: @@ -578,7 +578,7 @@ entities: chemicals: Stellibinin: Inherent: True - PotencyDivisor: 4 + potencyDivisor: 4 Max: 25 Min: 1 productPrototypes: diff --git a/Resources/Maps/Shuttles/DeltaV/NTES_Box.yml b/Resources/Maps/Shuttles/DeltaV/NTES_Box.yml index 61831cd0895..30e99796506 100644 --- a/Resources/Maps/Shuttles/DeltaV/NTES_Box.yml +++ b/Resources/Maps/Shuttles/DeltaV/NTES_Box.yml @@ -61,6 +61,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Shuttles/DeltaV/NTES_Delta.yml b/Resources/Maps/Shuttles/DeltaV/NTES_Delta.yml index ea42d89ddd1..764a81b452e 100644 --- a/Resources/Maps/Shuttles/DeltaV/NTES_Delta.yml +++ b/Resources/Maps/Shuttles/DeltaV/NTES_Delta.yml @@ -68,6 +68,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Shuttles/DeltaV/NTES_Kaeri.yml b/Resources/Maps/Shuttles/DeltaV/NTES_Kaeri.yml index 0a9fc598df6..35a8eb637a0 100644 --- a/Resources/Maps/Shuttles/DeltaV/NTES_Kaeri.yml +++ b/Resources/Maps/Shuttles/DeltaV/NTES_Kaeri.yml @@ -61,6 +61,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Shuttles/DeltaV/NTES_Lox.yml b/Resources/Maps/Shuttles/DeltaV/NTES_Lox.yml index 9522cd74d3b..e04c801d28f 100644 --- a/Resources/Maps/Shuttles/DeltaV/NTES_Lox.yml +++ b/Resources/Maps/Shuttles/DeltaV/NTES_Lox.yml @@ -66,6 +66,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Shuttles/DeltaV/NTES_Propeller.yml b/Resources/Maps/Shuttles/DeltaV/NTES_Propeller.yml index 929103c42ae..c814fb0b34e 100644 --- a/Resources/Maps/Shuttles/DeltaV/NTES_Propeller.yml +++ b/Resources/Maps/Shuttles/DeltaV/NTES_Propeller.yml @@ -90,6 +90,10 @@ entities: - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg + - type: DeviceNetwork + configurators: [] + deviceLists: [] + transmitFrequencyId: ShuttleTimer - type: DecalGrid chunkCollection: version: 2 diff --git a/Resources/Maps/Shuttles/ShuttleEvent/disaster_evacpod.yml b/Resources/Maps/Shuttles/ShuttleEvent/disaster_evacpod.yml new file mode 100644 index 00000000000..be1ca4ffdee --- /dev/null +++ b/Resources/Maps/Shuttles/ShuttleEvent/disaster_evacpod.yml @@ -0,0 +1,350 @@ +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 82: FloorShuttleOrange + 85: FloorShuttleWhite + 120: Lattice + 121: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + name: Evacuation pod + - type: Transform + parent: invalid + - type: MapGrid + chunks: + 0,0: + ind: 0,0 + tiles: eQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUgAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAA + version: 6 + - type: Broadphase + - type: Physics + bodyStatus: InAir + angularDamping: 0.05 + linearDamping: 0.05 + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: OccluderTree + - type: SpreaderGrid + - type: Shuttle + - type: GridPathfinding + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: [] + - type: GridAtmosphere + version: 2 + data: + tiles: + 0,-1: + 0: 4368 + 1: 32 + 0,0: + 1: 2 + -1,0: + 1: 8 + -1,-1: + 1: 128 + uniqueMixes: + - volume: 2500 + temperature: 293.15 + moles: + - 21.824879 + - 82.10312 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + immutable: True + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: GasTileOverlay + - type: RadiationGridResistance + - type: NavMap +- proto: AirlockShuttle + entities: + - uid: 2 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 +- proto: APCBasic + entities: + - uid: 3 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,-0.5 + parent: 1 +- proto: AtmosDeviceFanTiny + entities: + - uid: 4 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 +- proto: BoxMRE + entities: + - uid: 6 + components: + - type: Transform + parent: 5 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: CableApcExtension + entities: + - uid: 10 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - uid: 11 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 12 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 +- proto: CableHV + entities: + - uid: 13 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 14 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 +- proto: CableMV + entities: + - uid: 15 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 16 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 17 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 +- proto: ChairPilotSeat + entities: + - uid: 18 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-1.5 + parent: 1 +- proto: ClosetWallMaintenanceFilledRandom + entities: + - uid: 5 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,-1.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 8 + - 9 + - 6 + - 7 +- proto: ClothingOuterSuitEmergency + entities: + - uid: 7 + components: + - type: Transform + parent: 5 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ComputerShuttle + entities: + - uid: 19 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 +- proto: DisasterVictimSpawner + entities: + - uid: 20 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 +- proto: GeneratorWallmountAPU + entities: + - uid: 21 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 +- proto: Gyroscope + entities: + - uid: 32 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 +- proto: HandheldGPSBasic + entities: + - uid: 8 + components: + - type: Transform + parent: 5 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: Poweredlight + entities: + - uid: 22 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,-1.5 + parent: 1 +- proto: ShuttleWindow + entities: + - uid: 23 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 +- proto: SubstationWallBasic + entities: + - uid: 24 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,-0.5 + parent: 1 +- proto: Thruster + entities: + - uid: 25 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-2.5 + parent: 1 +- proto: WallShuttle + entities: + - uid: 26 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 27 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-1.5 + parent: 1 + - uid: 28 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-0.5 + parent: 1 + - uid: 29 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-1.5 + parent: 1 +- proto: WallShuttleDiagonal + entities: + - uid: 30 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 31 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,0.5 + parent: 1 +- proto: WeaponLaserSvalinn + entities: + - uid: 9 + components: + - type: Transform + parent: 5 + - type: Physics + canCollide: False + - type: InsideEntityStorage +... diff --git a/Resources/Maps/Shuttles/ShuttleEvent/honki.yml b/Resources/Maps/Shuttles/ShuttleEvent/honki.yml new file mode 100644 index 00000000000..0fca6a8ba92 --- /dev/null +++ b/Resources/Maps/Shuttles/ShuttleEvent/honki.yml @@ -0,0 +1,2666 @@ +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 20: FloorCarpetClown + 25: FloorClown + 120: Lattice + 121: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + name: Honkomother + - type: Transform + pos: 1.212189,-1.7551664 + parent: invalid + - type: MapGrid + chunks: + 0,0: + ind: 0,0 + tiles: GQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAFAAAAAAAGQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFAAAAAAAFAAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAGQAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAGQAAAAAAGQAAAAAAGQAAAAAAeQAAAAAAGQAAAAAAGQAAAAAA + version: 6 + - type: Broadphase + - type: Physics + bodyStatus: InAir + angularDamping: 0.05 + linearDamping: 0.05 + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: OccluderTree + - type: SpreaderGrid + - type: Shuttle + - type: GridPathfinding + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: + - node: + color: '#EFB34196' + id: MiniTileWhiteCornerNe + decals: + 21: 5,-5 + 39: -4,-1 + 40: 6,-1 + - node: + color: '#EFB34196' + id: MiniTileWhiteCornerNw + decals: + 20: -5,-5 + 41: -6,-1 + 42: 4,-1 + - node: + color: '#EFB34196' + id: MiniTileWhiteCornerSe + decals: + 0: 2,-3 + 23: 5,-7 + 35: -4,-3 + 36: 6,-3 + - node: + color: '#EFB34196' + id: MiniTileWhiteCornerSw + decals: + 1: -2,-3 + 33: -5,-7 + 37: -6,-3 + 38: 4,-3 + - node: + color: '#EFB34196' + id: MiniTileWhiteInnerNe + decals: + 57: -2,0 + - node: + color: '#EFB34196' + id: MiniTileWhiteInnerNw + decals: + 56: 2,0 + - node: + color: '#EFB34196' + id: MiniTileWhiteLineE + decals: + 2: 2,-2 + 3: 2,-1 + 4: 2,0 + 5: 2,1 + 22: 5,-6 + 47: -4,-2 + 48: 6,-2 + 55: -2,1 + - node: + color: '#EFB34196' + id: MiniTileWhiteLineN + decals: + 13: 0,-5 + 14: 4,-5 + 15: -1,-5 + 16: 1,-5 + 17: 3,-5 + 18: -3,-5 + 19: -4,-5 + 49: -5,-1 + 50: 5,-1 + 51: -1,0 + 52: 0,0 + 53: 1,0 + - node: + color: '#EFB34196' + id: MiniTileWhiteLineS + decals: + 10: -1,-3 + 11: 0,-3 + 12: 1,-3 + 24: 4,-7 + 25: 3,-7 + 26: 2,-7 + 27: 1,-7 + 28: 0,-7 + 29: -1,-7 + 30: -2,-7 + 31: -3,-7 + 32: -4,-7 + 43: -5,-3 + 44: 5,-3 + - node: + color: '#EFB34196' + id: MiniTileWhiteLineW + decals: + 6: -2,-2 + 7: -2,-1 + 8: -2,0 + 9: -2,1 + 34: -5,-6 + 45: 4,-2 + 46: -6,-2 + 54: 2,1 + - type: GridAtmosphere + version: 2 + data: + tiles: + 0,0: + 0: 887 + 1: 18432 + 0,-1: + 0: 30576 + -1,0: + 0: 2252 + 1: 16912 + 1,0: + 1: 56 + 1,-1: + 0: 30576 + 0,-2: + 0: 48051 + -1,-2: + 0: 48056 + -1,-1: + 0: 56784 + 0,-3: + 1: 32768 + 1,-3: + 1: 12288 + 1,-2: + 0: 13104 + 1: 34820 + -2,0: + 1: 130 + -2,-1: + 0: 52928 + -2,-2: + 1: 8708 + 0: 34944 + -2,-3: + 1: 32768 + -1,-3: + 1: 12288 + uniqueMixes: + - volume: 2500 + temperature: 293.15 + moles: + - 21.824879 + - 82.10312 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + immutable: True + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: GasTileOverlay + - type: RadiationGridResistance +- proto: AirCanister + entities: + - uid: 2 + components: + - type: Transform + anchored: True + pos: -1.5,-2.5 + parent: 1 + - type: Physics + bodyType: Static + - uid: 3 + components: + - type: Transform + anchored: True + pos: 2.5,-2.5 + parent: 1 + - type: Physics + bodyType: Static +- proto: AirlockShuttle + entities: + - uid: 4 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -6.5,-1.5 + parent: 1 +- proto: AltarBananium + entities: + - uid: 374 + components: + - type: Transform + pos: 6.5,-1.5 + parent: 1 +- proto: APCBasic + entities: + - uid: 5 + components: + - type: Transform + pos: 1.5,-3.5 + parent: 1 +- proto: AtmosDeviceFanTiny + entities: + - uid: 6 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -6.5,-1.5 + parent: 1 +- proto: BananaPhoneInstrument + entities: + - uid: 7 + components: + - type: Transform + pos: -1.4946816,-0.2775966 + parent: 1 +- proto: BananiumDoor + entities: + - uid: 8 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-5.5 + parent: 1 + - uid: 9 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-1.5 + parent: 1 + - uid: 10 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,-1.5 + parent: 1 + - uid: 11 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,-5.5 + parent: 1 + - uid: 12 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-3.5 + parent: 1 +- proto: BarricadeBlock + entities: + - uid: 372 + components: + - type: Transform + pos: -1.5,-5.5 + parent: 1 +- proto: Bed + entities: + - uid: 13 + components: + - type: Transform + pos: 3.5,-6.5 + parent: 1 + - uid: 14 + components: + - type: Transform + pos: 3.5,-4.5 + parent: 1 + - uid: 15 + components: + - type: Transform + pos: 5.5,-6.5 + parent: 1 + - uid: 16 + components: + - type: Transform + pos: 5.5,-4.5 + parent: 1 +- proto: BedsheetSpawner + entities: + - uid: 17 + components: + - type: Transform + pos: 3.5,-6.5 + parent: 1 + - uid: 18 + components: + - type: Transform + pos: 5.5,-6.5 + parent: 1 + - uid: 19 + components: + - type: Transform + pos: 3.5,-4.5 + parent: 1 + - uid: 20 + components: + - type: Transform + pos: 5.5,-4.5 + parent: 1 +- proto: BikeHornImplanter + entities: + - uid: 22 + components: + - type: Transform + parent: 21 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 27 + components: + - type: Transform + parent: 26 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: CableApcExtension + entities: + - uid: 31 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 + - uid: 32 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 33 + components: + - type: Transform + pos: 1.5,-3.5 + parent: 1 + - uid: 34 + components: + - type: Transform + pos: 1.5,-4.5 + parent: 1 + - uid: 35 + components: + - type: Transform + pos: 1.5,-5.5 + parent: 1 + - uid: 36 + components: + - type: Transform + pos: 1.5,-6.5 + parent: 1 + - uid: 37 + components: + - type: Transform + pos: 0.5,-5.5 + parent: 1 + - uid: 38 + components: + - type: Transform + pos: -0.5,-5.5 + parent: 1 + - uid: 39 + components: + - type: Transform + pos: -0.5,-6.5 + parent: 1 + - uid: 40 + components: + - type: Transform + pos: -0.5,-7.5 + parent: 1 + - uid: 41 + components: + - type: Transform + pos: 1.5,-2.5 + parent: 1 + - uid: 42 + components: + - type: Transform + pos: -0.5,-4.5 + parent: 1 + - uid: 43 + components: + - type: Transform + pos: -1.5,-5.5 + parent: 1 + - uid: 44 + components: + - type: Transform + pos: -2.5,-5.5 + parent: 1 + - uid: 45 + components: + - type: Transform + pos: -3.5,-5.5 + parent: 1 + - uid: 46 + components: + - type: Transform + pos: -4.5,-5.5 + parent: 1 + - uid: 47 + components: + - type: Transform + pos: 3.5,-5.5 + parent: 1 + - uid: 48 + components: + - type: Transform + pos: 4.5,-5.5 + parent: 1 + - uid: 49 + components: + - type: Transform + pos: 5.5,-5.5 + parent: 1 + - uid: 50 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 + - uid: 51 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 52 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 53 + components: + - type: Transform + pos: 1.5,-1.5 + parent: 1 + - uid: 54 + components: + - type: Transform + pos: 4.5,-1.5 + parent: 1 + - uid: 55 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - uid: 56 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 + - uid: 57 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 + - uid: 58 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 + - uid: 59 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 60 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 + - uid: 61 + components: + - type: Transform + pos: 3.5,-1.5 + parent: 1 + - uid: 62 + components: + - type: Transform + pos: 5.5,-1.5 + parent: 1 + - uid: 63 + components: + - type: Transform + pos: -2.5,-1.5 + parent: 1 + - uid: 64 + components: + - type: Transform + pos: -3.5,-1.5 + parent: 1 + - uid: 65 + components: + - type: Transform + pos: -4.5,-1.5 + parent: 1 + - uid: 66 + components: + - type: Transform + pos: -5.5,-1.5 + parent: 1 + - uid: 67 + components: + - type: Transform + pos: -4.5,-0.5 + parent: 1 + - uid: 68 + components: + - type: Transform + pos: -4.5,0.5 + parent: 1 + - uid: 69 + components: + - type: Transform + pos: 5.5,-0.5 + parent: 1 + - uid: 70 + components: + - type: Transform + pos: 5.5,0.5 + parent: 1 + - uid: 71 + components: + - type: Transform + pos: 6.5,-5.5 + parent: 1 + - uid: 72 + components: + - type: Transform + pos: 5.5,-5.5 + parent: 1 + - uid: 73 + components: + - type: Transform + pos: 4.5,-6.5 + parent: 1 + - uid: 74 + components: + - type: Transform + pos: 4.5,-7.5 + parent: 1 + - uid: 75 + components: + - type: Transform + pos: -3.5,-7.5 + parent: 1 + - uid: 76 + components: + - type: Transform + pos: -3.5,-6.5 + parent: 1 + - uid: 77 + components: + - type: Transform + pos: -5.5,-5.5 + parent: 1 + - uid: 78 + components: + - type: Transform + pos: -0.5,-3.5 + parent: 1 + - uid: 79 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 + - uid: 80 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 + - uid: 81 + components: + - type: Transform + pos: 2.5,-5.5 + parent: 1 +- proto: CableHV + entities: + - uid: 82 + components: + - type: Transform + pos: -0.5,-8.5 + parent: 1 + - uid: 83 + components: + - type: Transform + pos: 0.5,-8.5 + parent: 1 + - uid: 84 + components: + - type: Transform + pos: 1.5,-8.5 + parent: 1 + - uid: 85 + components: + - type: Transform + pos: 0.5,-7.5 + parent: 1 +- proto: CableMV + entities: + - uid: 86 + components: + - type: Transform + pos: 0.5,-7.5 + parent: 1 + - uid: 87 + components: + - type: Transform + pos: 1.5,-3.5 + parent: 1 + - uid: 88 + components: + - type: Transform + pos: 0.5,-6.5 + parent: 1 + - uid: 89 + components: + - type: Transform + pos: 0.5,-5.5 + parent: 1 + - uid: 90 + components: + - type: Transform + pos: 0.5,-4.5 + parent: 1 + - uid: 91 + components: + - type: Transform + pos: 1.5,-4.5 + parent: 1 +- proto: ChairPilotSeat + entities: + - uid: 92 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,1.5 + parent: 1 +- proto: CigaretteBanana + entities: + - uid: 94 + components: + - type: Transform + parent: 93 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 95 + components: + - type: Transform + parent: 93 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 96 + components: + - type: Transform + parent: 93 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingOuterHardsuitClown + entities: + - uid: 97 + components: + - type: Transform + parent: 93 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 100 + components: + - type: Transform + parent: 99 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 104 + components: + - type: Transform + parent: 103 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingOuterWinterClown + entities: + - uid: 105 + components: + - type: Transform + parent: 103 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClownRecorder + entities: + - uid: 107 + components: + - type: Transform + pos: 2.6453638,0.42502415 + parent: 1 +- proto: ClownTroupeSpawner + entities: + - uid: 108 + components: + - type: Transform + pos: 3.5,-6.5 + parent: 1 + - uid: 109 + components: + - type: Transform + pos: 5.5,-4.5 + parent: 1 + - uid: 110 + components: + - type: Transform + pos: 5.5,-6.5 + parent: 1 +- proto: CluwneHorn + entities: + - uid: 23 + components: + - type: Transform + parent: 21 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 28 + components: + - type: Transform + parent: 26 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ComfyChair + entities: + - uid: 111 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-0.5 + parent: 1 + - uid: 112 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,-0.5 + parent: 1 +- proto: ComputerShuttle + entities: + - uid: 113 + components: + - type: Transform + pos: 0.5,2.5 + parent: 1 +- proto: CrateCargoGambling + entities: + - uid: 114 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 +- proto: CratePirate + entities: + - uid: 21 + components: + - type: Transform + pos: 4.5,-0.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 25 + - 23 + - 22 + - 24 + - 261 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + - uid: 26 + components: + - type: Transform + pos: 4.5,-2.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 29 + - 315 + - 27 + - 28 + - 30 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + - uid: 115 + components: + - type: Transform + pos: 6.5,-2.5 + parent: 1 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 125 + - 124 + - 123 + - 122 + - 121 + - 126 + - 120 + - 119 + - 118 + - 117 + - 116 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null + - uid: 127 + components: + - type: Transform + pos: 6.5,-0.5 + parent: 1 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 128 + - 129 + - 130 + - 131 + - 132 + - 133 + - 134 + - 135 + - 138 + - 136 + - 137 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null +- proto: DehydratedSpaceCarp + entities: + - uid: 24 + components: + - type: Transform + parent: 21 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 29 + components: + - type: Transform + parent: 26 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: DeviceQuantumSpinInverter + entities: + - uid: 25 + components: + - type: Transform + parent: 21 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 30 + components: + - type: Transform + parent: 26 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: EmergencyFunnyOxygenTankFilled + entities: + - uid: 98 + components: + - type: Transform + parent: 93 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 101 + components: + - type: Transform + parent: 99 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 106 + components: + - type: Transform + parent: 103 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FloorBananiumEntity + entities: + - uid: 139 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-7.5 + parent: 1 + - uid: 140 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-7.5 + parent: 1 + - uid: 141 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-7.5 + parent: 1 + - uid: 142 + components: + - type: Transform + pos: -1.5,-6.5 + parent: 1 + - uid: 143 + components: + - type: Transform + pos: -1.5,-4.5 + parent: 1 + - uid: 373 + components: + - type: Transform + pos: 0.5,-3.5 + parent: 1 +- proto: FoodBanana + entities: + - uid: 116 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 117 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 118 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 119 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 128 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 129 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 130 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 131 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodBurgerClown + entities: + - uid: 144 + components: + - type: Transform + pos: -1.5971907,0.54355335 + parent: 1 + - uid: 145 + components: + - type: Transform + pos: -1.405974,0.27368832 + parent: 1 +- proto: FoodCakeClown + entities: + - uid: 146 + components: + - type: Transform + pos: 2.4229474,-0.24963892 + parent: 1 +- proto: FoodMeatClown + entities: + - uid: 147 + components: + - type: Transform + pos: 3.4782665,-4.592343 + parent: 1 +- proto: FoodPieBananaCream + entities: + - uid: 120 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 121 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 122 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 123 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 124 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 125 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 132 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 133 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 134 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 135 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 136 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 137 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: GasPassiveVent + entities: + - uid: 148 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,1.5 + parent: 1 + - uid: 149 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,1.5 + parent: 1 +- proto: GasPipeBend + entities: + - uid: 150 + components: + - type: Transform + pos: 5.5,-0.5 + parent: 1 + - uid: 151 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,-0.5 + parent: 1 + - uid: 152 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-4.5 + parent: 1 + - uid: 153 + components: + - type: Transform + pos: 4.5,-4.5 + parent: 1 +- proto: GasPipeFourway + entities: + - uid: 154 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 + - uid: 155 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 + - uid: 156 + components: + - type: Transform + pos: 0.5,-5.5 + parent: 1 + - uid: 157 + components: + - type: Transform + pos: -0.5,-4.5 + parent: 1 + - uid: 158 + components: + - type: Transform + pos: 1.5,-4.5 + parent: 1 + - uid: 159 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - uid: 160 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 +- proto: GasPipeStraight + entities: + - uid: 161 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-2.5 + parent: 1 + - uid: 162 + components: + - type: Transform + pos: 0.5,-3.5 + parent: 1 + - uid: 163 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,-1.5 + parent: 1 + - uid: 164 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,-1.5 + parent: 1 + - uid: 165 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,-5.5 + parent: 1 + - uid: 166 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,1.5 + parent: 1 + - uid: 167 + components: + - type: Transform + pos: 0.5,-4.5 + parent: 1 + - uid: 168 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-1.5 + parent: 1 + - uid: 169 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-1.5 + parent: 1 + - uid: 170 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,-1.5 + parent: 1 + - uid: 171 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,-1.5 + parent: 1 + - uid: 172 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-5.5 + parent: 1 + - uid: 173 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,-5.5 + parent: 1 + - uid: 174 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-5.5 + parent: 1 + - uid: 175 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-0.5 + parent: 1 + - uid: 176 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,-4.5 + parent: 1 + - uid: 177 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-4.5 + parent: 1 + - uid: 178 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-3.5 + parent: 1 + - uid: 179 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-3.5 + parent: 1 + - uid: 180 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-0.5 + parent: 1 + - uid: 181 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-0.5 + parent: 1 + - uid: 182 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-0.5 + parent: 1 + - uid: 183 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-1.5 + parent: 1 + - uid: 184 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-1.5 + parent: 1 + - uid: 185 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-2.5 + parent: 1 + - uid: 186 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,0.5 + parent: 1 + - uid: 187 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,1.5 + parent: 1 + - uid: 188 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,1.5 + parent: 1 + - uid: 189 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,1.5 + parent: 1 + - uid: 190 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,1.5 + parent: 1 + - uid: 191 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,1.5 + parent: 1 + - uid: 192 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,1.5 + parent: 1 + - uid: 193 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,1.5 + parent: 1 + - uid: 194 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,-4.5 + parent: 1 + - uid: 195 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-0.5 + parent: 1 + - uid: 196 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,-0.5 + parent: 1 + - uid: 197 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,-4.5 + parent: 1 + - uid: 198 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,-4.5 + parent: 1 + - uid: 199 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,-2.5 + parent: 1 + - uid: 200 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,-2.5 + parent: 1 +- proto: GasPipeTJunction + entities: + - uid: 201 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 + - uid: 202 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-0.5 + parent: 1 +- proto: GasPort + entities: + - uid: 203 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-2.5 + parent: 1 + - uid: 204 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-2.5 + parent: 1 +- proto: GasVentPump + entities: + - uid: 205 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,-5.5 + parent: 1 + - uid: 206 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,-1.5 + parent: 1 + - uid: 207 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-5.5 + parent: 1 + - uid: 208 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 209 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-6.5 + parent: 1 + - uid: 210 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-1.5 + parent: 1 +- proto: GasVentScrubber + entities: + - uid: 211 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,-5.5 + parent: 1 + - uid: 212 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,-1.5 + parent: 1 + - uid: 213 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-5.5 + parent: 1 + - uid: 214 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-5.5 + parent: 1 + - uid: 215 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-5.5 + parent: 1 + - uid: 216 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 217 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 + - uid: 218 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -4.5,-1.5 + parent: 1 +- proto: GeneratorWallmountAPU + entities: + - uid: 219 + components: + - type: Transform + pos: -0.5,-8.5 + parent: 1 + - uid: 220 + components: + - type: Transform + pos: 0.5,-8.5 + parent: 1 + - uid: 221 + components: + - type: Transform + pos: 1.5,-8.5 + parent: 1 +- proto: GoldenBikeHorn + entities: + - uid: 222 + components: + - type: Transform + pos: 6.4591703,-1.2964956 + parent: 1 +- proto: GravityGeneratorMini + entities: + - uid: 223 + components: + - type: Transform + pos: -0.5,-7.5 + parent: 1 +- proto: Grille + entities: + - uid: 224 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,2.5 + parent: 1 + - uid: 225 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,3.5 + parent: 1 + - uid: 226 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,3.5 + parent: 1 + - uid: 227 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,3.5 + parent: 1 + - uid: 228 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,2.5 + parent: 1 + - uid: 229 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,0.5 + parent: 1 + - uid: 230 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,0.5 + parent: 1 + - uid: 231 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,0.5 + parent: 1 + - uid: 232 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,0.5 + parent: 1 + - uid: 233 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -4.5,0.5 + parent: 1 + - uid: 234 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,0.5 + parent: 1 + - uid: 235 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-4.5 + parent: 1 + - uid: 236 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-5.5 + parent: 1 + - uid: 237 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-6.5 + parent: 1 + - uid: 238 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-4.5 + parent: 1 + - uid: 239 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-5.5 + parent: 1 + - uid: 240 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-6.5 + parent: 1 + - uid: 241 + components: + - type: Transform + pos: -1.5,-6.5 + parent: 1 + - uid: 242 + components: + - type: Transform + pos: -1.5,-4.5 + parent: 1 +- proto: GrilleDiagonal + entities: + - uid: 243 + components: + - type: Transform + pos: -3.5,1.5 + parent: 1 + - uid: 244 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 + - uid: 245 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - uid: 246 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,3.5 + parent: 1 + - uid: 247 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,2.5 + parent: 1 + - uid: 248 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,1.5 + parent: 1 + - uid: 249 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,2.5 + parent: 1 + - uid: 250 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,2.5 + parent: 1 + - uid: 251 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,1.5 + parent: 1 + - uid: 252 + components: + - type: Transform + pos: -6.5,0.5 + parent: 1 + - uid: 253 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,1.5 + parent: 1 + - uid: 254 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,0.5 + parent: 1 + - uid: 255 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,-4.5 + parent: 1 + - uid: 256 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-7.5 + parent: 1 + - uid: 257 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,-7.5 + parent: 1 + - uid: 258 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -6.5,-4.5 + parent: 1 +- proto: Gyroscope + entities: + - uid: 259 + components: + - type: Transform + pos: 1.5,-7.5 + parent: 1 +- proto: LampBanana + entities: + - uid: 260 + components: + - type: Transform + pos: 2.532099,1.060484 + parent: 1 +- proto: LauncherCreamPie + entities: + - uid: 126 + components: + - type: Transform + parent: 115 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 138 + components: + - type: Transform + parent: 127 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: PlasmaWindow + entities: + - uid: 262 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,3.5 + parent: 1 + - uid: 263 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,3.5 + parent: 1 + - uid: 264 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 1.5,3.5 + parent: 1 + - uid: 265 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,2.5 + parent: 1 + - uid: 266 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,2.5 + parent: 1 + - uid: 267 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,0.5 + parent: 1 + - uid: 268 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -4.5,0.5 + parent: 1 + - uid: 269 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,0.5 + parent: 1 + - uid: 270 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,0.5 + parent: 1 + - uid: 271 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,0.5 + parent: 1 + - uid: 272 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,0.5 + parent: 1 + - uid: 273 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-4.5 + parent: 1 + - uid: 274 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-5.5 + parent: 1 + - uid: 275 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,-6.5 + parent: 1 + - uid: 276 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-6.5 + parent: 1 + - uid: 277 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-5.5 + parent: 1 + - uid: 278 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-4.5 + parent: 1 + - uid: 279 + components: + - type: Transform + pos: -1.5,-6.5 + parent: 1 + - uid: 280 + components: + - type: Transform + pos: -1.5,-4.5 + parent: 1 +- proto: PlasmaWindowDiagonal + entities: + - uid: 281 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,1.5 + parent: 1 + - uid: 282 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 + - uid: 283 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - uid: 284 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,3.5 + parent: 1 + - uid: 285 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,2.5 + parent: 1 + - uid: 286 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,2.5 + parent: 1 + - uid: 287 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,2.5 + parent: 1 + - uid: 288 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,1.5 + parent: 1 + - uid: 289 + components: + - type: Transform + pos: -6.5,0.5 + parent: 1 + - uid: 290 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,0.5 + parent: 1 + - uid: 291 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -6.5,-4.5 + parent: 1 + - uid: 292 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 7.5,-4.5 + parent: 1 + - uid: 293 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-7.5 + parent: 1 + - uid: 294 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,-7.5 + parent: 1 + - uid: 295 + components: + - type: Transform + pos: -3.5,1.5 + parent: 1 + - uid: 296 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,1.5 + parent: 1 +- proto: PoweredlightLED + entities: + - uid: 297 + components: + - type: Transform + pos: 4.5,-4.5 + parent: 1 + - uid: 298 + components: + - type: Transform + pos: -3.5,-4.5 + parent: 1 + - uid: 299 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-0.5 + parent: 1 + - uid: 300 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-0.5 + parent: 1 +- proto: PoweredlightOrange + entities: + - uid: 301 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-7.5 + parent: 1 +- proto: PoweredlightPink + entities: + - uid: 302 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,-6.5 + parent: 1 + - uid: 303 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-6.5 + parent: 1 + - uid: 304 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,-0.5 + parent: 1 + - uid: 305 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-0.5 + parent: 1 + - uid: 306 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,2.5 + parent: 1 + - uid: 307 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,2.5 + parent: 1 +- proto: RailingCorner + entities: + - uid: 308 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 + - uid: 309 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,1.5 + parent: 1 +- proto: RailingCornerSmall + entities: + - uid: 310 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,2.5 + parent: 1 + - uid: 311 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,2.5 + parent: 1 +- proto: RubberStampClown + entities: + - uid: 102 + components: + - type: Transform + parent: 99 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: SpawnClownSpider + entities: + - uid: 312 + components: + - type: Transform + pos: -4.5,-4.5 + parent: 1 + - uid: 313 + components: + - type: Transform + pos: -2.5,-5.5 + parent: 1 + - uid: 314 + components: + - type: Transform + pos: -3.5,-6.5 + parent: 1 +- proto: SpiderWebClown + entities: + - uid: 376 + components: + - type: Transform + pos: -4.5,-6.5 + parent: 1 + - uid: 377 + components: + - type: Transform + pos: -2.5,-4.5 + parent: 1 + - uid: 378 + components: + - type: Transform + pos: -2.5,-5.5 + parent: 1 +- proto: StatueBananiumClown + entities: + - uid: 375 + components: + - type: Transform + pos: -5.5,-0.5 + parent: 1 +- proto: SubstationBasic + entities: + - uid: 316 + components: + - type: Transform + pos: 0.5,-7.5 + parent: 1 +- proto: SuitStorageBase + entities: + - uid: 93 + components: + - type: Transform + pos: -3.5,-2.5 + parent: 1 + - type: Lock + locked: False + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 96 + - 95 + - 97 + - 94 + - 98 + - uid: 99 + components: + - type: Transform + pos: -5.5,-2.5 + parent: 1 + - type: Lock + locked: False + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 101 + - 100 + - 102 + - uid: 103 + components: + - type: Transform + pos: -4.5,-2.5 + parent: 1 + - type: Lock + locked: False + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 104 + - 105 + - 106 +- proto: TablePlasmaGlass + entities: + - uid: 317 + components: + - type: Transform + pos: -1.5,0.5 + parent: 1 + - uid: 318 + components: + - type: Transform + pos: 2.5,-0.5 + parent: 1 + - uid: 319 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 1 + - uid: 320 + components: + - type: Transform + pos: 2.5,0.5 + parent: 1 +- proto: Thruster + entities: + - uid: 321 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,-8.5 + parent: 1 + - uid: 322 + components: + - type: Transform + rot: -3.141592653589793 rad + pos: -2.5,-8.5 + parent: 1 + - uid: 323 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-5.5 + parent: 1 + - uid: 324 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -6.5,-5.5 + parent: 1 + - uid: 325 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -4.5,-8.5 + parent: 1 + - uid: 326 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,-8.5 + parent: 1 + - uid: 327 + components: + - type: Transform + pos: 5.5,1.5 + parent: 1 + - uid: 328 + components: + - type: Transform + pos: -4.5,1.5 + parent: 1 +- proto: ToolboxMechanicalFilled + entities: + - uid: 261 + components: + - type: Transform + parent: 21 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 315 + components: + - type: Transform + parent: 26 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: VendingMachineTankDispenserEVA + entities: + - uid: 329 + components: + - type: Transform + pos: -3.5,-0.5 + parent: 1 +- proto: WallClown + entities: + - uid: 330 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -6.5,-3.5 + parent: 1 + - uid: 331 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-0.5 + parent: 1 + - uid: 332 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-1.5 + parent: 1 + - uid: 333 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-2.5 + parent: 1 + - uid: 334 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 7.5,-3.5 + parent: 1 + - uid: 335 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,-3.5 + parent: 1 + - uid: 336 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,-3.5 + parent: 1 + - uid: 337 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,-7.5 + parent: 1 + - uid: 338 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-7.5 + parent: 1 + - uid: 339 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-7.5 + parent: 1 + - uid: 340 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-7.5 + parent: 1 + - uid: 341 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,-7.5 + parent: 1 + - uid: 342 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,-7.5 + parent: 1 + - uid: 343 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-7.5 + parent: 1 + - uid: 344 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-7.5 + parent: 1 + - uid: 345 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-6.5 + parent: 1 + - uid: 346 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-4.5 + parent: 1 + - uid: 347 + components: + - type: Transform + pos: -0.5,-3.5 + parent: 1 + - uid: 348 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-3.5 + parent: 1 + - uid: 349 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-3.5 + parent: 1 + - uid: 350 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-3.5 + parent: 1 + - uid: 351 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,-3.5 + parent: 1 + - uid: 352 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-2.5 + parent: 1 + - uid: 353 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,-3.5 + parent: 1 + - uid: 354 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-3.5 + parent: 1 + - uid: 355 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-3.5 + parent: 1 + - uid: 356 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 4.5,-3.5 + parent: 1 + - uid: 357 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,-3.5 + parent: 1 + - uid: 358 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-0.5 + parent: 1 + - uid: 359 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,0.5 + parent: 1 + - uid: 360 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,1.5 + parent: 1 + - uid: 361 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-0.5 + parent: 1 + - uid: 362 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,0.5 + parent: 1 + - uid: 363 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,1.5 + parent: 1 + - uid: 364 + components: + - type: Transform + pos: -1.5,-8.5 + parent: 1 + - uid: 365 + components: + - type: Transform + pos: -0.5,-8.5 + parent: 1 + - uid: 366 + components: + - type: Transform + pos: 0.5,-8.5 + parent: 1 + - uid: 367 + components: + - type: Transform + pos: 1.5,-8.5 + parent: 1 + - uid: 368 + components: + - type: Transform + pos: 2.5,-8.5 + parent: 1 + - uid: 369 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -6.5,-0.5 + parent: 1 + - uid: 370 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -6.5,-2.5 + parent: 1 + - uid: 371 + components: + - type: Transform + pos: 3.5,-2.5 + parent: 1 +... diff --git a/Resources/Maps/Shuttles/ShuttleEvent/lost_cargo.yml b/Resources/Maps/Shuttles/ShuttleEvent/lost_cargo.yml new file mode 100644 index 00000000000..148577363fb --- /dev/null +++ b/Resources/Maps/Shuttles/ShuttleEvent/lost_cargo.yml @@ -0,0 +1,1411 @@ +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 54: FloorGreenCircuit + 85: FloorShuttleWhite + 89: FloorSteel + 104: FloorTechMaint + 121: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + name: Cargo shuttle + - type: Transform + pos: 2.2710133,-2.4148211 + parent: invalid + - type: MapGrid + chunks: + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAVQAAAAAANgAAAAAAVQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAANgAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,0: + ind: 0,0 + tiles: WQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAWQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAaAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAAWQAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + - type: Broadphase + - type: Physics + bodyStatus: InAir + angularDamping: 0.05 + linearDamping: 0.05 + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: CargoShuttle + - type: DecalGrid + chunkCollection: + version: 2 + nodes: + - node: + color: '#FFFFFFFF' + id: Bot + decals: + 0: -5,5 + 1: -4,5 + 2: -1,5 + 3: -1,-1 + 4: -2,-1 + 5: -4,-1 + 6: -1,2 + 7: -4,2 + 8: -5,2 + - node: + color: '#9FED5896' + id: CheckerNESW + decals: + 9: -3,-1 + 10: -3,0 + 11: -3,1 + 12: -3,2 + 13: -3,3 + 14: -3,4 + 15: -3,5 + - node: + color: '#9FED5896' + id: MiniTileWhiteCornerNe + decals: + 29: -1,5 + 30: -2,6 + - node: + color: '#9FED5896' + id: MiniTileWhiteCornerNw + decals: + 19: -5,5 + 20: -4,6 + - node: + color: '#9FED5896' + id: MiniTileWhiteCornerSe + decals: + 21: -1,-1 + - node: + color: '#9FED5896' + id: MiniTileWhiteCornerSw + decals: + 22: -5,-1 + - node: + color: '#9FED5896' + id: MiniTileWhiteInnerNe + decals: + 33: -2,5 + - node: + color: '#9FED5896' + id: MiniTileWhiteInnerNw + decals: + 32: -4,5 + - node: + color: '#9FED5896' + id: MiniTileWhiteLineE + decals: + 26: -1,0 + 27: -1,2 + 28: -1,4 + - node: + color: '#9FED5896' + id: MiniTileWhiteLineN + decals: + 31: -3,6 + - node: + color: '#9FED5896' + id: MiniTileWhiteLineS + decals: + 23: -4,-1 + 24: -3,-1 + 25: -2,-1 + - node: + color: '#9FED5896' + id: MiniTileWhiteLineW + decals: + 16: -5,0 + 17: -5,2 + 18: -5,4 + - node: + color: '#9FED5896' + id: WarnLineE + decals: + 36: -1,1 + 37: -1,3 + - node: + color: '#9FED5896' + id: WarnLineS + decals: + 34: -5,1 + 35: -5,3 + - type: GridAtmosphere + version: 2 + data: + tiles: + -2,0: + 0: 51400 + -2,1: + 0: 16520 + -2,-1: + 0: 32832 + -1,0: + 0: 65535 + -1,1: + 0: 30719 + -2,2: + 0: 128 + -1,-1: + 0: 63346 + -1,2: + 0: 130 + 0,0: + 0: 4112 + 0,1: + 0: 4096 + -2,-2: + 0: 32768 + -1,-2: + 0: 32768 + 0,-1: + 0: 16 + uniqueMixes: + - volume: 2500 + temperature: 293.15 + moles: + - 21.824879 + - 82.10312 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: OccluderTree + - type: Shuttle + - type: GridPathfinding + - type: RadiationGridResistance + - type: SpreaderGrid + - type: GravityShake + shakeTimes: 10 + - type: GasTileOverlay +- proto: AirCanister + entities: + - uid: 2 + components: + - type: Transform + pos: -3.5,-1.5 + parent: 1 +- proto: AirlockGlassShuttle + entities: + - uid: 3 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,3.5 + parent: 1 + - uid: 4 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,1.5 + parent: 1 + - uid: 5 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,3.5 + parent: 1 + - uid: 6 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,1.5 + parent: 1 +- proto: APCHyperCapacity + entities: + - uid: 7 + components: + - type: Transform + pos: -0.5,6.5 + parent: 1 +- proto: AtmosDeviceFanTiny + entities: + - uid: 8 + components: + - type: Transform + pos: -5.5,1.5 + parent: 1 + - uid: 9 + components: + - type: Transform + pos: -5.5,3.5 + parent: 1 + - uid: 10 + components: + - type: Transform + pos: 0.5,3.5 + parent: 1 + - uid: 11 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 +- proto: BlastDoor + entities: + - uid: 12 + components: + - type: Transform + pos: 0.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 135 + - uid: 13 + components: + - type: Transform + pos: -5.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 134 + - uid: 14 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 136 + - uid: 15 + components: + - type: Transform + pos: -5.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 133 +- proto: BoxMRE + entities: + - uid: 93 + components: + - type: Transform + pos: -1.3692467,7.6214685 + parent: 1 +- proto: CableApcExtension + entities: + - uid: 16 + components: + - type: Transform + pos: -0.5,6.5 + parent: 1 + - uid: 17 + components: + - type: Transform + pos: -1.5,6.5 + parent: 1 + - uid: 18 + components: + - type: Transform + pos: -2.5,6.5 + parent: 1 + - uid: 19 + components: + - type: Transform + pos: -2.5,5.5 + parent: 1 + - uid: 20 + components: + - type: Transform + pos: -2.5,8.5 + parent: 1 + - uid: 21 + components: + - type: Transform + pos: -3.5,8.5 + parent: 1 + - uid: 22 + components: + - type: Transform + pos: -1.5,8.5 + parent: 1 + - uid: 23 + components: + - type: Transform + pos: -3.5,6.5 + parent: 1 + - uid: 24 + components: + - type: Transform + pos: -3.5,7.5 + parent: 1 + - uid: 25 + components: + - type: Transform + pos: -2.5,4.5 + parent: 1 + - uid: 26 + components: + - type: Transform + pos: -2.5,3.5 + parent: 1 + - uid: 27 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 + - uid: 28 + components: + - type: Transform + pos: -2.5,1.5 + parent: 1 + - uid: 29 + components: + - type: Transform + pos: -2.5,0.5 + parent: 1 + - uid: 30 + components: + - type: Transform + pos: -2.5,-0.5 + parent: 1 + - uid: 31 + components: + - type: Transform + pos: -2.5,-1.5 + parent: 1 + - uid: 32 + components: + - type: Transform + pos: -1.5,-4.5 + parent: 1 + - uid: 33 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 + - uid: 34 + components: + - type: Transform + pos: -1.5,-2.5 + parent: 1 + - uid: 35 + components: + - type: Transform + pos: -2.5,-4.5 + parent: 1 + - uid: 36 + components: + - type: Transform + pos: -1.5,-3.5 + parent: 1 + - uid: 37 + components: + - type: Transform + pos: -3.5,-4.5 + parent: 1 + - uid: 38 + components: + - type: Transform + pos: -3.5,-3.5 + parent: 1 + - uid: 39 + components: + - type: Transform + pos: -4.5,7.5 + parent: 1 + - uid: 40 + components: + - type: Transform + pos: -0.5,7.5 + parent: 1 + - uid: 41 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - uid: 42 + components: + - type: Transform + pos: -0.5,3.5 + parent: 1 + - uid: 43 + components: + - type: Transform + pos: -1.5,1.5 + parent: 1 + - uid: 44 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 + - uid: 45 + components: + - type: Transform + pos: -3.5,1.5 + parent: 1 + - uid: 46 + components: + - type: Transform + pos: -4.5,1.5 + parent: 1 + - uid: 47 + components: + - type: Transform + pos: -3.5,3.5 + parent: 1 + - uid: 48 + components: + - type: Transform + pos: -4.5,3.5 + parent: 1 + - uid: 49 + components: + - type: Transform + pos: -4.5,-3.5 + parent: 1 +- proto: CableHV + entities: + - uid: 50 + components: + - type: Transform + pos: -1.5,-2.5 + parent: 1 + - uid: 51 + components: + - type: Transform + pos: -2.5,-2.5 + parent: 1 + - uid: 52 + components: + - type: Transform + pos: -2.5,-3.5 + parent: 1 +- proto: CableMV + entities: + - uid: 53 + components: + - type: Transform + pos: -1.5,-2.5 + parent: 1 + - uid: 54 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 + - uid: 55 + components: + - type: Transform + pos: -2.5,-1.5 + parent: 1 + - uid: 56 + components: + - type: Transform + pos: -2.5,-0.5 + parent: 1 + - uid: 57 + components: + - type: Transform + pos: -2.5,0.5 + parent: 1 + - uid: 58 + components: + - type: Transform + pos: -2.5,1.5 + parent: 1 + - uid: 59 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 + - uid: 60 + components: + - type: Transform + pos: -2.5,3.5 + parent: 1 + - uid: 61 + components: + - type: Transform + pos: -2.5,4.5 + parent: 1 + - uid: 62 + components: + - type: Transform + pos: -2.5,5.5 + parent: 1 + - uid: 63 + components: + - type: Transform + pos: -2.5,6.5 + parent: 1 + - uid: 64 + components: + - type: Transform + pos: -1.5,6.5 + parent: 1 + - uid: 65 + components: + - type: Transform + pos: -0.5,6.5 + parent: 1 +- proto: CableTerminal + entities: + - uid: 66 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-3.5 + parent: 1 +- proto: Catwalk + entities: + - uid: 67 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 1 + - uid: 68 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 71 + components: + - type: Transform + pos: -4.5,2.5 + parent: 1 + - uid: 72 + components: + - type: Transform + pos: -3.5,2.5 + parent: 1 + - uid: 73 + components: + - type: Transform + pos: -3.5,5.5 + parent: 1 + - uid: 74 + components: + - type: Transform + pos: -4.5,5.5 + parent: 1 + - uid: 75 + components: + - type: Transform + pos: -3.5,-0.5 + parent: 1 + - uid: 76 + components: + - type: Transform + pos: -4.5,-0.5 + parent: 1 + - uid: 77 + components: + - type: Transform + pos: -1.5,5.5 + parent: 1 + - uid: 78 + components: + - type: Transform + pos: -0.5,5.5 + parent: 1 +- proto: ChairPilotSeat + entities: + - uid: 70 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,2.5 + parent: 1 + - uid: 79 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,7.5 + parent: 1 +- proto: ComputerShuttle + entities: + - uid: 80 + components: + - type: Transform + pos: -2.5,8.5 + parent: 1 +- proto: ConveyorBelt + entities: + - uid: 81 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 151 + - uid: 82 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 151 + - uid: 83 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 151 + - uid: 84 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 149 + - uid: 85 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 149 + - uid: 86 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 149 + - uid: 87 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 150 + - uid: 88 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 152 + - uid: 89 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -4.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 152 + - uid: 90 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 152 + - uid: 91 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 150 + - uid: 92 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 150 +- proto: CrateFilledSpawner + entities: + - uid: 95 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 96 + components: + - type: Transform + pos: -4.5,2.5 + parent: 1 + - uid: 97 + components: + - type: Transform + pos: -0.5,5.5 + parent: 1 + - uid: 98 + components: + - type: Transform + pos: -3.5,2.5 + parent: 1 +- proto: DrinkBeerBottleFull + entities: + - uid: 99 + components: + - type: Transform + pos: -3.2915764,7.812316 + parent: 1 + - uid: 100 + components: + - type: Transform + pos: -3.4715438,7.654894 + parent: 1 +- proto: GasPipeBend + entities: + - uid: 101 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,-1.5 + parent: 1 +- proto: GasPipeStraight + entities: + - uid: 102 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,0.5 + parent: 1 + - uid: 103 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,1.5 + parent: 1 + - uid: 104 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-0.5 + parent: 1 +- proto: GasPort + entities: + - uid: 105 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-1.5 + parent: 1 +- proto: GasVentPump + entities: + - uid: 106 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 +- proto: GeneratorBasic15kW + entities: + - uid: 107 + components: + - type: Transform + pos: -2.5,-3.5 + parent: 1 +- proto: GravityGeneratorMini + entities: + - uid: 108 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 +- proto: Grille + entities: + - uid: 109 + components: + - type: Transform + pos: -3.5,8.5 + parent: 1 + - uid: 110 + components: + - type: Transform + pos: -3.5,9.5 + parent: 1 + - uid: 111 + components: + - type: Transform + pos: -2.5,9.5 + parent: 1 + - uid: 112 + components: + - type: Transform + pos: -1.5,9.5 + parent: 1 + - uid: 113 + components: + - type: Transform + pos: -1.5,8.5 + parent: 1 +- proto: Gyroscope + entities: + - uid: 114 + components: + - type: Transform + pos: -3.5,-2.5 + parent: 1 +- proto: LostCargoTechnicianSpawner + entities: + - uid: 69 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,2.5 + parent: 1 + - uid: 187 + components: + - type: Transform + pos: -2.5,7.5 + parent: 1 +- proto: PlasticFlapsAirtightClear + entities: + - uid: 116 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 + - uid: 117 + components: + - type: Transform + pos: -5.5,0.5 + parent: 1 + - uid: 118 + components: + - type: Transform + pos: -5.5,4.5 + parent: 1 + - uid: 119 + components: + - type: Transform + pos: 0.5,4.5 + parent: 1 +- proto: Poweredlight + entities: + - uid: 120 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,2.5 + parent: 1 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 121 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,2.5 + parent: 1 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 122 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,7.5 + parent: 1 + - type: ApcPowerReceiver + powerLoad: 0 + - uid: 123 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,7.5 + parent: 1 + - type: ApcPowerReceiver + powerLoad: 0 +- proto: RandomPosterAny + entities: + - uid: 124 + components: + - type: Transform + pos: -4.5,6.5 + parent: 1 +- proto: RandomSpawner100 + entities: + - uid: 188 + components: + - type: Transform + pos: -4.5,1.5 + parent: 1 + - uid: 189 + components: + - type: Transform + pos: -0.5,3.5 + parent: 1 + - uid: 190 + components: + - type: Transform + pos: -2.5,4.5 + parent: 1 + - uid: 191 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 1 + - uid: 192 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 193 + components: + - type: Transform + pos: -4.5,4.5 + parent: 1 +- proto: SalvageLootSpawner + entities: + - uid: 115 + components: + - type: Transform + pos: -1.5,2.5 + parent: 1 +- proto: SalvageMaterialCrateSpawner + entities: + - uid: 94 + components: + - type: Transform + pos: -3.5,-0.5 + parent: 1 + - uid: 125 + components: + - type: Transform + pos: -4.5,-0.5 + parent: 1 + - uid: 127 + components: + - type: Transform + pos: -3.5,5.5 + parent: 1 +- proto: ShuttleWindow + entities: + - uid: 128 + components: + - type: Transform + pos: -1.5,8.5 + parent: 1 + - uid: 129 + components: + - type: Transform + pos: -1.5,9.5 + parent: 1 + - uid: 130 + components: + - type: Transform + pos: -2.5,9.5 + parent: 1 + - uid: 131 + components: + - type: Transform + pos: -3.5,9.5 + parent: 1 + - uid: 132 + components: + - type: Transform + pos: -3.5,8.5 + parent: 1 +- proto: SignalButton + entities: + - uid: 133 + components: + - type: Transform + pos: -5.5,5.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 15: + - Pressed: Toggle + - uid: 134 + components: + - type: Transform + pos: -5.5,-0.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 13: + - Pressed: Toggle + - uid: 135 + components: + - type: Transform + pos: 0.5,5.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 12: + - Pressed: Toggle + - uid: 136 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 14: + - Pressed: Toggle +- proto: SMESBasic + entities: + - uid: 137 + components: + - type: Transform + pos: -2.5,-2.5 + parent: 1 +- proto: SubstationBasic + entities: + - uid: 138 + components: + - type: Transform + pos: -1.5,-2.5 + parent: 1 +- proto: TableReinforced + entities: + - uid: 126 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,2.5 + parent: 1 + - uid: 139 + components: + - type: Transform + pos: -3.5,7.5 + parent: 1 + - uid: 140 + components: + - type: Transform + pos: -1.5,7.5 + parent: 1 +- proto: Thruster + entities: + - uid: 141 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,-2.5 + parent: 1 + - uid: 142 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,7.5 + parent: 1 + - uid: 143 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,7.5 + parent: 1 + - uid: 144 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,-2.5 + parent: 1 + - uid: 145 + components: + - type: Transform + pos: -4.5,9.5 + parent: 1 + - uid: 146 + components: + - type: Transform + pos: -0.5,9.5 + parent: 1 + - uid: 147 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-4.5 + parent: 1 + - uid: 148 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -4.5,-4.5 + parent: 1 +- proto: TwoWayLever + entities: + - uid: 149 + components: + - type: Transform + pos: -3.5,1.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 86: + - Left: Forward + - Right: Reverse + - Middle: Off + 85: + - Left: Forward + - Right: Reverse + - Middle: Off + 84: + - Left: Forward + - Right: Reverse + - Middle: Off + - uid: 150 + components: + - type: Transform + pos: -1.5,1.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 91: + - Left: Forward + - Right: Reverse + - Middle: Off + 87: + - Left: Forward + - Right: Reverse + - Middle: Off + 92: + - Left: Forward + - Right: Reverse + - Middle: Off + - uid: 151 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 81: + - Left: Forward + - Right: Reverse + - Middle: Off + 82: + - Left: Forward + - Right: Reverse + - Middle: Off + 83: + - Left: Forward + - Right: Reverse + - Middle: Off + - uid: 152 + components: + - type: Transform + pos: -3.5,3.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 90: + - Left: Forward + - Right: Reverse + - Middle: Off + 89: + - Left: Forward + - Right: Reverse + - Middle: Off + 88: + - Left: Forward + - Right: Reverse + - Middle: Off +- proto: WallShuttle + entities: + - uid: 153 + components: + - type: Transform + pos: -5.5,8.5 + parent: 1 + - uid: 154 + components: + - type: Transform + pos: -4.5,8.5 + parent: 1 + - uid: 155 + components: + - type: Transform + pos: -0.5,8.5 + parent: 1 + - uid: 156 + components: + - type: Transform + pos: 0.5,8.5 + parent: 1 + - uid: 157 + components: + - type: Transform + pos: -0.5,-3.5 + parent: 1 + - uid: 158 + components: + - type: Transform + pos: 0.5,-3.5 + parent: 1 + - uid: 159 + components: + - type: Transform + pos: -4.5,-3.5 + parent: 1 + - uid: 160 + components: + - type: Transform + pos: -5.5,-3.5 + parent: 1 + - uid: 161 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 162 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 + - uid: 163 + components: + - type: Transform + pos: -4.5,-1.5 + parent: 1 + - uid: 164 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 + - uid: 165 + components: + - type: Transform + pos: -4.5,-2.5 + parent: 1 + - uid: 166 + components: + - type: Transform + pos: -5.5,-1.5 + parent: 1 + - uid: 167 + components: + - type: Transform + pos: -0.5,7.5 + parent: 1 + - uid: 168 + components: + - type: Transform + pos: -0.5,6.5 + parent: 1 + - uid: 169 + components: + - type: Transform + pos: 0.5,6.5 + parent: 1 + - uid: 170 + components: + - type: Transform + pos: -4.5,7.5 + parent: 1 + - uid: 171 + components: + - type: Transform + pos: -4.5,6.5 + parent: 1 + - uid: 172 + components: + - type: Transform + pos: -5.5,6.5 + parent: 1 + - uid: 173 + components: + - type: Transform + pos: -5.5,-0.5 + parent: 1 + - uid: 174 + components: + - type: Transform + pos: -5.5,5.5 + parent: 1 + - uid: 175 + components: + - type: Transform + pos: 0.5,5.5 + parent: 1 + - uid: 176 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 177 + components: + - type: Transform + pos: 0.5,2.5 + parent: 1 + - uid: 178 + components: + - type: Transform + pos: -5.5,2.5 + parent: 1 + - uid: 179 + components: + - type: Transform + pos: -3.5,-4.5 + parent: 1 + - uid: 180 + components: + - type: Transform + pos: -2.5,-4.5 + parent: 1 + - uid: 181 + components: + - type: Transform + pos: -1.5,-4.5 + parent: 1 + - uid: 182 + components: + - type: Transform + pos: -3.5,-3.5 + parent: 1 + - uid: 183 + components: + - type: Transform + pos: -1.5,-3.5 + parent: 1 +- proto: WindoorCargoLocked + entities: + - uid: 184 + components: + - type: Transform + pos: -2.5,7.5 + parent: 1 +- proto: WindowReinforcedDirectional + entities: + - uid: 185 + components: + - type: Transform + pos: -1.5,7.5 + parent: 1 + - uid: 186 + components: + - type: Transform + pos: -3.5,7.5 + parent: 1 +... diff --git a/Resources/Maps/Shuttles/striker.yml b/Resources/Maps/Shuttles/ShuttleEvent/striker.yml similarity index 100% rename from Resources/Maps/Shuttles/striker.yml rename to Resources/Maps/Shuttles/ShuttleEvent/striker.yml diff --git a/Resources/Maps/Shuttles/ShuttleEvent/syndie_evacpod.yml b/Resources/Maps/Shuttles/ShuttleEvent/syndie_evacpod.yml new file mode 100644 index 00000000000..d90fadba238 --- /dev/null +++ b/Resources/Maps/Shuttles/ShuttleEvent/syndie_evacpod.yml @@ -0,0 +1,1188 @@ +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 29: FloorDark + 84: FloorShuttleRed + 101: FloorSteelOffset + 104: FloorTechMaint + 120: Lattice + 121: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + desc: Evacuation pod + name: Evacuation pod + - type: Transform + parent: invalid + - type: MapGrid + chunks: + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAHQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAZQAAAAAAZQAAAAAA + version: 6 + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAZQAAAAAAZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAZQAAAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHQAAAAAAHQAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAZQAAAAAAZQAAAAAAZQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + 0,0: + ind: 0,0 + tiles: ZQAAAAAAZQAAAAAAZQAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAaAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAVAAAAAAAZQAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVAAAAAAAVAAAAAAAeQAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + - type: Broadphase + - type: Physics + bodyStatus: InAir + angularDamping: 0.05 + linearDamping: 0.05 + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: OccluderTree + - type: SpreaderGrid + - type: Shuttle + - type: GridPathfinding + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: + - node: + color: '#A91409FF' + id: StandClearGreyscale + decals: + 18: 0,-1 + - node: + color: '#A91409FF' + id: WarnCornerSmallGreyscaleNE + decals: + 15: -2,0 + - node: + color: '#A91409FF' + id: WarnCornerSmallGreyscaleNW + decals: + 14: 2,0 + - node: + color: '#A91409FF' + id: WarnEndGreyscaleN + decals: + 9: -2,1 + 10: 2,1 + - node: + color: '#A91409FF' + id: WarnLineGreyscaleE + decals: + 0: 2,0 + 8: 2,-1 + 17: 5,0 + - node: + color: '#A91409FF' + id: WarnLineGreyscaleN + decals: + 11: -1,0 + 12: 0,0 + 13: 1,0 + - node: + color: '#A91409FF' + id: WarnLineGreyscaleS + decals: + 1: 1,-1 + 2: 0,-1 + 3: -1,-1 + 4: -2,-1 + 5: 2,-1 + - node: + color: '#A91409FF' + id: WarnLineGreyscaleW + decals: + 6: -2,-1 + 7: -2,0 + 16: -5,0 + - type: GridAtmosphere + version: 2 + data: + tiles: + -2,-1: + 0: 18432 + -2,0: + 1: 12 + 0: 64 + -1,-1: + 0: 601 + 1: 51200 + -1,0: + 1: 2255 + 0: 16896 + 0,-1: + 0: 2115 + 1: 29440 + -2,1: + 0: 8 + -1,1: + 0: 4096 + 0,0: + 1: 895 + 0: 18432 + 1,-1: + 0: 16913 + 1,0: + 1: 7 + 0: 64 + 1,1: + 0: 4098 + uniqueMixes: + - volume: 2500 + immutable: True + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + temperature: 293.15 + moles: + - 21.824879 + - 82.10312 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: GasTileOverlay + - type: NavMap + - type: RadiationGridResistance +- proto: AirlockShuttleSyndicate + entities: + - uid: 2 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 6.5,0.5 + parent: 1 + - uid: 3 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -5.5,0.5 + parent: 1 +- proto: AirlockSyndicate + entities: + - uid: 4 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 + - uid: 5 + components: + - type: Transform + pos: -2.5,0.5 + parent: 1 +- proto: APCBasic + entities: + - uid: 6 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,1.5 + parent: 1 +- proto: AtmosDeviceFanTiny + entities: + - uid: 7 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -5.5,0.5 + parent: 1 + - uid: 8 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,0.5 + parent: 1 +- proto: BannerSyndicate + entities: + - uid: 9 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 +- proto: CableApcExtension + entities: + - uid: 10 + components: + - type: Transform + pos: -2.5,1.5 + parent: 1 + - uid: 11 + components: + - type: Transform + pos: -2.5,0.5 + parent: 1 + - uid: 12 + components: + - type: Transform + pos: -3.5,0.5 + parent: 1 + - uid: 13 + components: + - type: Transform + pos: -4.5,0.5 + parent: 1 + - uid: 14 + components: + - type: Transform + pos: -5.5,0.5 + parent: 1 + - uid: 15 + components: + - type: Transform + pos: -1.5,0.5 + parent: 1 + - uid: 16 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 17 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 + - uid: 18 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 + - uid: 19 + components: + - type: Transform + pos: 2.5,0.5 + parent: 1 + - uid: 20 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 + - uid: 21 + components: + - type: Transform + pos: 4.5,0.5 + parent: 1 + - uid: 22 + components: + - type: Transform + pos: 5.5,0.5 + parent: 1 + - uid: 23 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 24 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 + - uid: 25 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 + - uid: 26 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 + - uid: 27 + components: + - type: Transform + pos: 1.5,-2.5 + parent: 1 + - uid: 28 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 29 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 + - uid: 30 + components: + - type: Transform + pos: 1.5,-1.5 + parent: 1 + - uid: 31 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 + - uid: 32 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 +- proto: CableHV + entities: + - uid: 33 + components: + - type: Transform + pos: -2.5,-0.5 + parent: 1 + - uid: 34 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 1 + - uid: 35 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 36 + components: + - type: Transform + pos: 0.5,-0.5 + parent: 1 + - uid: 37 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - uid: 38 + components: + - type: Transform + pos: 2.5,-0.5 + parent: 1 + - uid: 39 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 + - uid: 40 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 + - uid: 41 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 + - uid: 42 + components: + - type: Transform + pos: 3.5,1.5 + parent: 1 +- proto: CableMV + entities: + - uid: 43 + components: + - type: Transform + pos: 3.5,1.5 + parent: 1 + - uid: 44 + components: + - type: Transform + pos: 2.5,1.5 + parent: 1 + - uid: 45 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 + - uid: 46 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 + - uid: 47 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 + - uid: 48 + components: + - type: Transform + pos: -1.5,1.5 + parent: 1 + - uid: 49 + components: + - type: Transform + pos: -2.5,1.5 + parent: 1 +- proto: ChairPilotSeat + entities: + - uid: 50 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,1.5 + parent: 1 + - uid: 51 + components: + - type: Transform + pos: -1.5,1.5 + parent: 1 + - uid: 52 + components: + - type: Transform + pos: 2.5,1.5 + parent: 1 +- proto: ClosetWallEmergencyFilledRandom + entities: + - uid: 53 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -3.5,-0.5 + parent: 1 +- proto: ClosetWallFireFilledRandom + entities: + - uid: 54 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-0.5 + parent: 1 +- proto: ClothingHeadPyjamaSyndicateRed + entities: + - uid: 98 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingNeckScarfStripedSyndieRed + entities: + - uid: 101 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 102 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ComputerShuttleSyndie + entities: + - uid: 55 + components: + - type: Transform + pos: 0.5,2.5 + parent: 1 +- proto: CrateSyndicate + entities: + - uid: 92 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14673 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 102 + - 101 + - 100 + - 99 + - 98 + - 97 + - 96 + - 95 + - 94 + - 93 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null +- proto: CyberPen + entities: + - uid: 93 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FaxMachineSyndie + entities: + - uid: 162 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 +- proto: GeneratorWallmountAPU + entities: + - uid: 56 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 +- proto: GeneratorWallmountBasic + entities: + - uid: 57 + components: + - type: Transform + pos: -2.5,-0.5 + parent: 1 +- proto: Grille + entities: + - uid: 58 + components: + - type: Transform + pos: 2.5,2.5 + parent: 1 + - uid: 59 + components: + - type: Transform + pos: 0.5,3.5 + parent: 1 + - uid: 60 + components: + - type: Transform + pos: -1.5,2.5 + parent: 1 + - uid: 61 + components: + - type: Transform + pos: -0.5,3.5 + parent: 1 + - uid: 62 + components: + - type: Transform + pos: 1.5,3.5 + parent: 1 +- proto: GrilleDiagonal + entities: + - uid: 63 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 + - uid: 64 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - uid: 65 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,3.5 + parent: 1 + - uid: 66 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,2.5 + parent: 1 + - uid: 67 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,2.5 + parent: 1 + - uid: 68 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,2.5 + parent: 1 +- proto: Gyroscope + entities: + - uid: 69 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 +- proto: Paper + entities: + - uid: 95 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 97 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 99 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 100 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: PlasmaWindowDiagonal + entities: + - uid: 70 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,2.5 + parent: 1 + - uid: 71 + components: + - type: Transform + pos: -1.5,3.5 + parent: 1 + - uid: 72 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,2.5 + parent: 1 + - uid: 73 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,2.5 + parent: 1 + - uid: 74 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,3.5 + parent: 1 + - uid: 75 + components: + - type: Transform + pos: -2.5,2.5 + parent: 1 +- proto: Poweredlight + entities: + - uid: 76 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-1.5 + parent: 1 +- proto: PoweredSmallLight + entities: + - uid: 77 + components: + - type: Transform + pos: -4.5,0.5 + parent: 1 + - uid: 78 + components: + - type: Transform + pos: 5.5,0.5 + parent: 1 + - uid: 79 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,1.5 + parent: 1 + - uid: 80 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,1.5 + parent: 1 +- proto: RandomPosterContraband + entities: + - uid: 81 + components: + - type: Transform + pos: -3.5,1.5 + parent: 1 + - uid: 82 + components: + - type: Transform + pos: 4.5,1.5 + parent: 1 +- proto: ReinforcedPlasmaWindow + entities: + - uid: 83 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,3.5 + parent: 1 + - uid: 84 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,3.5 + parent: 1 + - uid: 85 + components: + - type: Transform + pos: 2.5,2.5 + parent: 1 + - uid: 86 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,3.5 + parent: 1 + - uid: 87 + components: + - type: Transform + pos: -1.5,2.5 + parent: 1 +- proto: RubberStampSyndicate + entities: + - uid: 94 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: SubstationWallBasic + entities: + - uid: 88 + components: + - type: Transform + pos: 3.5,1.5 + parent: 1 +- proto: SyndieDisasterVictimSpawner + entities: + - uid: 89 + components: + - type: Transform + pos: -1.5,1.5 + parent: 1 + - uid: 90 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 + - uid: 91 + components: + - type: Transform + pos: 2.5,1.5 + parent: 1 +- proto: TableGlass + entities: + - uid: 163 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 +- proto: Thruster + entities: + - uid: 103 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-3.5 + parent: 1 + - uid: 104 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-3.5 + parent: 1 + - uid: 105 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-3.5 + parent: 1 + - uid: 106 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-1.5 + parent: 1 + - uid: 107 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 3.5,-1.5 + parent: 1 +- proto: ToolboxSyndicateFilled + entities: + - uid: 96 + components: + - type: Transform + parent: 92 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: VendingMachineTankDispenserEVA + entities: + - uid: 108 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 +- proto: WallPlastitanium + entities: + - uid: 109 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,-0.5 + parent: 1 + - uid: 110 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -4.5,1.5 + parent: 1 + - uid: 111 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,5.5 + parent: 1 + - uid: 112 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,6.5 + parent: 1 + - uid: 113 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,3.5 + parent: 1 + - uid: 114 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,-0.5 + parent: 1 + - uid: 115 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,2.5 + parent: 1 + - uid: 116 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,2.5 + parent: 1 + - uid: 117 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,1.5 + parent: 1 + - uid: 118 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-0.5 + parent: 1 + - uid: 119 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -4.5,3.5 + parent: 1 + - uid: 120 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -4.5,-0.5 + parent: 1 + - uid: 121 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,3.5 + parent: 1 + - uid: 122 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,1.5 + parent: 1 + - uid: 123 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,4.5 + parent: 1 + - uid: 124 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,1.5 + parent: 1 + - uid: 125 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,-1.5 + parent: 1 + - uid: 126 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,1.5 + parent: 1 + - uid: 127 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,5.5 + parent: 1 + - uid: 128 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,2.5 + parent: 1 + - uid: 129 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-1.5 + parent: 1 + - uid: 130 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,3.5 + parent: 1 + - uid: 131 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,4.5 + parent: 1 + - uid: 132 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,6.5 + parent: 1 + - uid: 133 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -4.5,2.5 + parent: 1 + - uid: 134 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,1.5 + parent: 1 + - uid: 135 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-1.5 + parent: 1 + - uid: 136 + components: + - type: Transform + pos: -0.5,-2.5 + parent: 1 + - uid: 137 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 + - uid: 138 + components: + - type: Transform + pos: 1.5,-2.5 + parent: 1 + - uid: 139 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-1.5 + parent: 1 + - uid: 140 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 + - uid: 141 + components: + - type: Transform + pos: -2.5,-0.5 + parent: 1 + - uid: 142 + components: + - type: Transform + pos: -3.5,-2.5 + parent: 1 + - uid: 143 + components: + - type: Transform + pos: 4.5,-2.5 + parent: 1 +- proto: WallPlastitaniumDiagonal + entities: + - uid: 144 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,1.5 + parent: 1 + - uid: 145 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -5.5,-0.5 + parent: 1 + - uid: 146 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -4.5,-1.5 + parent: 1 + - uid: 147 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,4.5 + parent: 1 + - uid: 148 + components: + - type: Transform + pos: -3.5,7.5 + parent: 1 + - uid: 149 + components: + - type: Transform + pos: -4.5,4.5 + parent: 1 + - uid: 150 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,7.5 + parent: 1 + - uid: 151 + components: + - type: Transform + pos: -5.5,1.5 + parent: 1 + - uid: 152 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-0.5 + parent: 1 + - uid: 153 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 5.5,-1.5 + parent: 1 + - uid: 154 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-2.5 + parent: 1 + - uid: 155 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-2.5 + parent: 1 + - uid: 156 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,-0.5 + parent: 1 + - uid: 157 + components: + - type: Transform + pos: 2.5,-0.5 + parent: 1 + - uid: 158 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-1.5 + parent: 1 + - uid: 159 + components: + - type: Transform + pos: 1.5,-1.5 + parent: 1 + - uid: 160 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-3.5 + parent: 1 + - uid: 161 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-3.5 + parent: 1 +... diff --git a/Resources/Maps/Shuttles/ShuttleEvent/traveling_china_cuisine.yml b/Resources/Maps/Shuttles/ShuttleEvent/traveling_china_cuisine.yml new file mode 100644 index 00000000000..4b3bf617e2a --- /dev/null +++ b/Resources/Maps/Shuttles/ShuttleEvent/traveling_china_cuisine.yml @@ -0,0 +1,1872 @@ +meta: + format: 6 + postmapinit: false +tilemap: + 0: Space + 14: FloorBar + 40: FloorDirt + 44: FloorFreezer + 50: FloorGrassLight + 76: FloorRGlass + 85: FloorShuttleWhite + 96: FloorSteelDirty + 98: FloorSteelLime + 106: FloorTechMaint3 + 112: FloorWhiteMini + 117: FloorWhitePlastic + 119: FloorWoodTile + 120: Lattice + 121: Plating +entities: +- proto: "" + entities: + - uid: 1 + components: + - type: MetaData + name: SRV "Salami-Salami" + - type: Transform + pos: -0.5104167,-0.5 + parent: invalid + - type: MapGrid + chunks: + 0,0: + ind: 0,0 + tiles: YgAAAAAAYgAAAAAAYgAAAAAAVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeQAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,0: + ind: -1,0 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAVQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + -1,-1: + ind: -1,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAMgAAAAAAMgAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAADgAAAAAADgAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAATAAAAAAADgAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADgAAAAAADgAAAAAADgAAAAAADgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAdwAAAAAAdwAAAAAAcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeQAAAAAAeQAAAAAAdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYgAAAAAAYgAAAAAAYgAAAAAAYgAAAAAA + version: 6 + 0,-1: + ind: 0,-1 + tiles: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAcAAAAAAAcAAAAAAAcAAAAAAAeAAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAALAAAAAAALAAAAAAALAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAATAAAAAAALAAAAAAAYAAAAAAAYAAAAAAAYAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAATAAAAAAALAAAAAAAcAAAAAAAagAAAAAAKAAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAATAAAAAAALAAAAAAAcAAAAAAAYAAAAAAAeQAAAAAAeQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAATAAAAAAALAAAAAAAcAAAAAAAeQAAAAAAeQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALAAAAAAALAAAAAAALAAAAAAAdQAAAAAAeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAYgAAAAAAYgAAAAAAYgAAAAAAdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA + version: 6 + - type: Broadphase + - type: Physics + bodyStatus: InAir + angularDamping: 0.05 + linearDamping: 0.05 + fixedRotation: False + bodyType: Dynamic + - type: Fixtures + fixtures: {} + - type: OccluderTree + - type: SpreaderGrid + - type: Shuttle + - type: GridPathfinding + - type: Gravity + gravityShakeSound: !type:SoundPathSpecifier + path: /Audio/Effects/alert.ogg + - type: DecalGrid + chunkCollection: + version: 2 + nodes: + - node: + color: '#FFFFFFFF' + id: FlowersBROne + decals: + 3: -2,-7 + - node: + color: '#FFFFFFFF' + id: Flowerspv2 + decals: + 2: -3,-7 + - node: + color: '#FFFFFFFF' + id: Flowersy3 + decals: + 0: -2,-7 + 1: -3,-7 + - type: GridAtmosphere + version: 2 + data: + tiles: + 0,0: + 0: 7 + 1: 128 + 0,-1: + 0: 29303 + -1,0: + 1: 129 + -1,-1: + 0: 28686 + 1: 272 + -1,-2: + 1: 28 + 0: 65024 + -1,-3: + 1: 49152 + 0,-3: + 1: 61440 + 0,-2: + 0: 32624 + 1: 8 + 1,-3: + 1: 4096 + 1,-2: + 1: 65 + 0: 13056 + 1,-1: + 0: 3 + 1: 320 + uniqueMixes: + - volume: 2500 + temperature: 293.15 + moles: + - 21.824879 + - 82.10312 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - volume: 2500 + immutable: True + moles: + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + chunkSize: 4 + - type: GasTileOverlay + - type: RadiationGridResistance + - type: NavMap +- proto: AirlockShuttle + entities: + - uid: 2 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-4.5 + parent: 1 + - uid: 3 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -3.5,-0.5 + parent: 1 +- proto: APCBasic + entities: + - uid: 4 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 +- proto: AtmosDeviceFanTiny + entities: + - uid: 5 + components: + - type: Transform + pos: -3.5,-4.5 + parent: 1 + - uid: 6 + components: + - type: Transform + pos: -3.5,-0.5 + parent: 1 +- proto: BarSignMaidCafe + entities: + - uid: 7 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-3.5 + parent: 1 +- proto: BlastDoor + entities: + - uid: 8 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - type: DeviceLinkSink + links: + - 161 +- proto: Bucket + entities: + - uid: 9 + components: + - type: Transform + pos: 0.32937366,-3.3336349 + parent: 1 +- proto: ButchCleaver + entities: + - uid: 11 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: CableApcExtension + entities: + - uid: 41 + components: + - type: Transform + pos: 2.5,-3.5 + parent: 1 + - uid: 42 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 + - uid: 43 + components: + - type: Transform + pos: 2.5,-0.5 + parent: 1 + - uid: 44 + components: + - type: Transform + pos: 2.5,0.5 + parent: 1 + - uid: 45 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 + - uid: 46 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 + - uid: 47 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 + - uid: 48 + components: + - type: Transform + pos: 2.5,-2.5 + parent: 1 + - uid: 49 + components: + - type: Transform + pos: 2.5,-4.5 + parent: 1 + - uid: 50 + components: + - type: Transform + pos: 2.5,-5.5 + parent: 1 + - uid: 51 + components: + - type: Transform + pos: 2.5,-6.5 + parent: 1 + - uid: 52 + components: + - type: Transform + pos: 1.5,-6.5 + parent: 1 + - uid: 53 + components: + - type: Transform + pos: 0.5,-6.5 + parent: 1 + - uid: 54 + components: + - type: Transform + pos: 1.5,-7.5 + parent: 1 + - uid: 55 + components: + - type: Transform + pos: -0.5,-0.5 + parent: 1 + - uid: 56 + components: + - type: Transform + pos: -0.5,-1.5 + parent: 1 + - uid: 57 + components: + - type: Transform + pos: 3.5,-3.5 + parent: 1 + - uid: 58 + components: + - type: Transform + pos: 4.5,-3.5 + parent: 1 + - uid: 59 + components: + - type: Transform + pos: 5.5,-3.5 + parent: 1 + - uid: 60 + components: + - type: Transform + pos: -0.5,-7.5 + parent: 1 + - uid: 61 + components: + - type: Transform + pos: 3.5,-7.5 + parent: 1 + - uid: 62 + components: + - type: Transform + pos: 0.5,-7.5 + parent: 1 + - uid: 63 + components: + - type: Transform + pos: 2.5,-7.5 + parent: 1 + - uid: 64 + components: + - type: Transform + pos: -1.5,-0.5 + parent: 1 +- proto: CableHV + entities: + - uid: 65 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 + - uid: 66 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 +- proto: CableMV + entities: + - uid: 67 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 + - uid: 68 + components: + - type: Transform + pos: 3.5,-1.5 + parent: 1 + - uid: 69 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 +- proto: ChairPilotSeat + entities: + - uid: 70 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-0.5 + parent: 1 +- proto: ClosetMaintenance + entities: + - uid: 71 + components: + - type: Transform + pos: 0.5,0.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14786 + moles: + - 1.8856695 + - 7.0937095 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 80 + - 76 + - 73 + - 74 + - 78 + - 81 + - 77 + - 72 + - 75 + - 79 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null +- proto: ClothingHeadHatCasa + entities: + - uid: 72 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingHeadHelmetHardsuitBasic + entities: + - uid: 82 + components: + - type: Transform + pos: 0.30235916,-0.6487955 + parent: 1 +- proto: ClothingOuterDameDane + entities: + - uid: 79 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingOuterDogi + entities: + - uid: 73 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingOuterHardsuitAncientEVA + entities: + - uid: 74 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingShoesDameDane + entities: + - uid: 75 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingUniformJumpsuitDameDane + entities: + - uid: 76 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ClothingUniformJumpsuitFamilyGuy + entities: + - uid: 83 + components: + - type: Transform + pos: 4.1954827,-4.679846 + parent: 1 +- proto: ClothingUniformJumpsuitKimono + entities: + - uid: 77 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: ComputerShuttle + entities: + - uid: 84 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 +- proto: CrateFreezer + entities: + - uid: 10 + components: + - type: Transform + pos: 5.5,-5.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14783 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 11 + - 29 + - 24 + - 13 + - 25 + - 37 + - 33 + - 32 + - 38 + - 16 + - 15 + - 19 + - 17 + - 18 + - 20 + - 40 + - 14 + - 22 + - 30 + - 21 + - 34 + - 23 + - 35 + - 28 + - 36 + - 27 + - 39 + - 31 + - 26 + - 12 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null +- proto: DrinkCanPack + entities: + - uid: 85 + components: + - type: Transform + pos: 2.4942255,-4.6459746 + parent: 1 +- proto: DrinkGlass + entities: + - uid: 86 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.9675496,-6.258177 + parent: 1 + - uid: 87 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.9050496,-6.383177 + parent: 1 + - uid: 88 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.8425496,-6.086302 + parent: 1 +- proto: EggySeeds + entities: + - uid: 89 + components: + - type: Transform + pos: 4.8663497,-4.2508607 + parent: 1 +- proto: ExtendedEmergencyOxygenTankFilled + entities: + - uid: 78 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FolderSpawner + entities: + - uid: 90 + components: + - type: Transform + pos: 2.6497245,-0.5822141 + parent: 1 +- proto: FoodBowlBig + entities: + - uid: 12 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 13 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodBreadMoldySlice + entities: + - uid: 91 + components: + - type: Transform + pos: 4.5392327,-5.695471 + parent: 1 +- proto: FoodBreadTofu + entities: + - uid: 92 + components: + - type: Transform + pos: -0.56204444,-5.412466 + parent: 1 +- proto: FoodButter + entities: + - uid: 14 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodEgg + entities: + - uid: 15 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 16 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 17 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 18 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 19 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 20 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMealSashimi + entities: + - uid: 93 + components: + - type: Transform + pos: 2.532601,-3.619526 + parent: 1 + - uid: 94 + components: + - type: Transform + pos: 2.5117679,-3.192443 + parent: 1 +- proto: FoodMeat + entities: + - uid: 21 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 22 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatBear + entities: + - uid: 23 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 24 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatBearCooked + entities: + - uid: 25 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatClown + entities: + - uid: 26 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatCorgi + entities: + - uid: 27 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatDragon + entities: + - uid: 96 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 97 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 98 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatFish + entities: + - uid: 112 + components: + - type: Transform + pos: 2.3519397,-4.0480876 + parent: 1 + - uid: 113 + components: + - type: Transform + pos: 2.5602732,-4.4543376 + parent: 1 +- proto: FoodMeatGoliath + entities: + - uid: 28 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 29 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatHuman + entities: + - uid: 30 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatLizard + entities: + - uid: 31 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatPlant + entities: + - uid: 32 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatRat + entities: + - uid: 33 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatRouny + entities: + - uid: 34 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 35 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatSnake + entities: + - uid: 36 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 37 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodMeatSpider + entities: + - uid: 38 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodNoodlesButter + entities: + - uid: 99 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 100 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodNoodlesChowmein + entities: + - uid: 101 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodNoodlesMeatball + entities: + - uid: 102 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodRiceBoiled + entities: + - uid: 103 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 104 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 105 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 114 + components: + - type: Transform + pos: 4.2319775,-4.0944357 + parent: 1 +- proto: FoodRiceEgg + entities: + - uid: 106 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 107 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodRiceGumbo + entities: + - uid: 108 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodRicePork + entities: + - uid: 109 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage + - uid: 110 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodRicePudding + entities: + - uid: 111 + components: + - type: Transform + parent: 95 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: FoodTofu + entities: + - uid: 115 + components: + - type: Transform + pos: -2.4682944,-0.4437158 + parent: 1 +- proto: GeneratorWallmountAPU + entities: + - uid: 116 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 + - type: PowerSupplier + supplyRampRate: 1000 + supplyRampTolerance: 1000 + supplyRate: 16000 +- proto: GravityGeneratorMini + entities: + - uid: 117 + components: + - type: Transform + pos: 5.5,-3.5 + parent: 1 +- proto: Grille + entities: + - uid: 118 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 + - uid: 119 + components: + - type: Transform + pos: 0.5,1.5 + parent: 1 + - uid: 120 + components: + - type: Transform + pos: 2.5,1.5 + parent: 1 + - uid: 121 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,0.5 + parent: 1 + - uid: 122 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,0.5 + parent: 1 +- proto: Gyroscope + entities: + - uid: 123 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-3.5 + parent: 1 +- proto: HospitalCurtains + entities: + - uid: 124 + components: + - type: Transform + pos: 3.5,-5.5 + parent: 1 +- proto: HospitalCurtainsOpen + entities: + - uid: 125 + components: + - type: Transform + pos: 1.5,-1.5 + parent: 1 +- proto: hydroponicsSoil + entities: + - uid: 126 + components: + - type: Transform + pos: 5.5,-4.5 + parent: 1 +- proto: HydroponicsToolClippers + entities: + - uid: 127 + components: + - type: Transform + pos: 4.6706424,-4.7269287 + parent: 1 +- proto: HydroponicsToolMiniHoe + entities: + - uid: 128 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.0306153,-4.877862 + parent: 1 +- proto: KitchenElectricGrill + entities: + - uid: 129 + components: + - type: Transform + pos: 0.5,-6.5 + parent: 1 +- proto: KitchenKnife + entities: + - uid: 80 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: KitchenMicrowave + entities: + - uid: 130 + components: + - type: Transform + pos: 2.5,-2.5 + parent: 1 +- proto: KitchenReagentGrinder + entities: + - uid: 131 + components: + - type: Transform + pos: 1.5,-6.5 + parent: 1 +- proto: LockerFreezerBase + entities: + - uid: 95 + components: + - type: Transform + pos: 0.5,-2.5 + parent: 1 + - type: EntityStorage + air: + volume: 200 + immutable: False + temperature: 293.14798 + moles: + - 1.7459903 + - 6.568249 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - 0 + - type: ContainerContainer + containers: + entity_storage: !type:Container + showEnts: False + occludes: True + ents: + - 110 + - 109 + - 103 + - 104 + - 105 + - 96 + - 98 + - 97 + - 99 + - 101 + - 100 + - 106 + - 102 + - 108 + - 107 + - 111 + paper_label: !type:ContainerSlot + showEnts: False + occludes: True + ent: null +- proto: MaterialSheetMeat + entities: + - uid: 39 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: Mattress + entities: + - uid: 132 + components: + - type: Transform + pos: 4.5,-4.5 + parent: 1 +- proto: NitrogenTankFilled + entities: + - uid: 81 + components: + - type: Transform + parent: 71 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: NoticeBoard + entities: + - uid: 133 + components: + - type: Transform + pos: -1.5,-2.5 + parent: 1 +- proto: Pen + entities: + - uid: 232 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.27949,-0.47790605 + parent: 1 +- proto: PlushieVox + entities: + - uid: 134 + components: + - type: Transform + pos: -0.5571752,-4.2839594 + parent: 1 +- proto: PosterLegitFruitBowl + entities: + - uid: 135 + components: + - type: Transform + pos: -2.5,-2.5 + parent: 1 +- proto: PottedPlantRandom + entities: + - uid: 136 + components: + - type: Transform + pos: -2.5,-3.5 + parent: 1 + - uid: 137 + components: + - type: Transform + pos: -2.5,-5.5 + parent: 1 +- proto: Poweredlight + entities: + - uid: 138 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -2.5,-5.5 + parent: 1 + - uid: 139 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-4.5 + parent: 1 + - uid: 140 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-0.5 + parent: 1 +- proto: PoweredSmallLight + entities: + - uid: 141 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,-0.5 + parent: 1 + - uid: 142 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 5.5,-4.5 + parent: 1 + - uid: 143 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-6.5 + parent: 1 +- proto: RagItem + entities: + - uid: 144 + components: + - type: Transform + pos: -0.47175223,-3.4022202 + parent: 1 +- proto: RandomSpawner100 + entities: + - uid: 145 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-4.5 + parent: 1 +- proto: ReagentContainerFlour + entities: + - uid: 40 + components: + - type: Transform + parent: 10 + - type: Physics + canCollide: False + - type: InsideEntityStorage +- proto: RiceSeeds + entities: + - uid: 146 + components: + - type: Transform + pos: 4.716352,-4.1569357 + parent: 1 +- proto: RubberStampTrader + entities: + - uid: 147 + components: + - type: Transform + pos: 2.6184745,-0.09783912 + parent: 1 +- proto: Shovel + entities: + - uid: 148 + components: + - type: Transform + pos: 5.0644813,-4.460167 + parent: 1 +- proto: ShuttersWindowOpen + entities: + - uid: 149 + components: + - type: Transform + pos: -0.5,-4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 160 + - uid: 150 + components: + - type: Transform + pos: -0.5,-3.5 + parent: 1 + - type: DeviceLinkSink + links: + - 160 + - uid: 151 + components: + - type: Transform + pos: -0.5,-5.5 + parent: 1 + - type: DeviceLinkSink + links: + - 160 + - uid: 152 + components: + - type: Transform + pos: -3.5,-4.5 + parent: 1 + - type: DeviceLinkSink + links: + - 160 +- proto: ShuttleWindow + entities: + - uid: 153 + components: + - type: Transform + pos: 1.5,1.5 + parent: 1 + - uid: 154 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,1.5 + parent: 1 + - uid: 155 + components: + - type: Transform + pos: -2.5,-6.5 + parent: 1 + - uid: 156 + components: + - type: Transform + pos: -1.5,-6.5 + parent: 1 + - uid: 157 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -2.5,0.5 + parent: 1 + - uid: 158 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -1.5,0.5 + parent: 1 + - uid: 159 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 0.5,1.5 + parent: 1 +- proto: SignalButton + entities: + - uid: 160 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,-1.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 150: + - Pressed: Toggle + 149: + - Pressed: Toggle + 151: + - Pressed: Toggle + 152: + - Pressed: Toggle + - uid: 161 + components: + - type: Transform + pos: 1.5,0.5 + parent: 1 + - type: DeviceLinkSource + linkedPorts: + 8: + - Pressed: Toggle +- proto: SignDoors + entities: + - uid: 162 + components: + - type: Transform + pos: -0.5,0.5 + parent: 1 +- proto: SinkStemlessWater + entities: + - uid: 163 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-6.5 + parent: 1 +- proto: soda_dispenser + entities: + - uid: 164 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-6.5 + parent: 1 +- proto: StoolBar + entities: + - uid: 165 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-3.5 + parent: 1 + - uid: 166 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-4.5 + parent: 1 + - uid: 167 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-5.5 + parent: 1 +- proto: SubstationWallBasic + entities: + - uid: 168 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 +- proto: Table + entities: + - uid: 169 + components: + - type: Transform + pos: 2.5,-6.5 + parent: 1 + - uid: 170 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-6.5 + parent: 1 + - uid: 171 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-6.5 + parent: 1 +- proto: TableGlass + entities: + - uid: 172 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-4.5 + parent: 1 + - uid: 173 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-3.5 + parent: 1 + - uid: 174 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-2.5 + parent: 1 +- proto: TableStone + entities: + - uid: 175 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-4.5 + parent: 1 + - uid: 176 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-3.5 + parent: 1 + - uid: 177 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-5.5 + parent: 1 +- proto: TableWood + entities: + - uid: 178 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 2.5,-0.5 + parent: 1 +- proto: Thruster + entities: + - uid: 179 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 1.5,-8.5 + parent: 1 + - uid: 180 + components: + - type: Transform + pos: 4.5,-1.5 + parent: 1 + - uid: 181 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 0.5,-8.5 + parent: 1 + - uid: 182 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 4.5,-7.5 + parent: 1 + - uid: 183 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 2.5,-8.5 + parent: 1 + - uid: 184 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-7.5 + parent: 1 +- proto: ToolboxMechanicalFilled + entities: + - uid: 185 + components: + - type: Transform + pos: 0.5731925,-0.16962886 + parent: 1 +- proto: TravelingChefSpawner + entities: + - uid: 186 + components: + - type: Transform + pos: 1.5,-0.5 + parent: 1 + - uid: 187 + components: + - type: Transform + pos: 4.5,-5.5 + parent: 1 +- proto: VendingMachineChang + entities: + - uid: 188 + components: + - type: Transform + pos: 2.5,0.5 + parent: 1 +- proto: WallShuttle + entities: + - uid: 189 + components: + - type: Transform + pos: -1.5,-1.5 + parent: 1 + - uid: 190 + components: + - type: Transform + pos: -0.5,-7.5 + parent: 1 + - uid: 191 + components: + - type: Transform + pos: 3.5,-0.5 + parent: 1 + - uid: 192 + components: + - type: Transform + pos: 3.5,0.5 + parent: 1 + - uid: 193 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,-1.5 + parent: 1 + - uid: 194 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-1.5 + parent: 1 + - uid: 195 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-2.5 + parent: 1 + - uid: 196 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-3.5 + parent: 1 + - uid: 197 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-4.5 + parent: 1 + - uid: 198 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 2.5,-7.5 + parent: 1 + - uid: 199 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 1.5,-7.5 + parent: 1 + - uid: 200 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 0.5,-7.5 + parent: 1 + - uid: 201 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -0.5,-6.5 + parent: 1 + - uid: 202 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,-2.5 + parent: 1 + - uid: 203 + components: + - type: Transform + pos: 2.5,-1.5 + parent: 1 + - uid: 204 + components: + - type: Transform + pos: 0.5,-1.5 + parent: 1 + - uid: 205 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -1.5,-2.5 + parent: 1 + - uid: 206 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -2.5,-2.5 + parent: 1 + - uid: 207 + components: + - type: Transform + pos: -3.5,-3.5 + parent: 1 + - uid: 208 + components: + - type: Transform + pos: -3.5,-5.5 + parent: 1 + - uid: 209 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 5.5,-2.5 + parent: 1 + - uid: 210 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: -0.5,0.5 + parent: 1 + - uid: 211 + components: + - type: Transform + pos: 4.5,-2.5 + parent: 1 + - uid: 212 + components: + - type: Transform + pos: 4.5,-6.5 + parent: 1 + - uid: 213 + components: + - type: Transform + pos: 5.5,-6.5 + parent: 1 + - uid: 214 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-3.5 + parent: 1 + - uid: 215 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-4.5 + parent: 1 + - uid: 216 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-5.5 + parent: 1 + - uid: 217 + components: + - type: Transform + pos: 3.5,-6.5 + parent: 1 + - uid: 218 + components: + - type: Transform + pos: 3.5,-7.5 + parent: 1 + - uid: 219 + components: + - type: Transform + pos: -2.5,-1.5 + parent: 1 +- proto: WallShuttleDiagonal + entities: + - uid: 220 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: -0.5,-8.5 + parent: 1 + - uid: 221 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 3.5,1.5 + parent: 1 + - uid: 222 + components: + - type: Transform + pos: -0.5,1.5 + parent: 1 + - uid: 223 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-6.5 + parent: 1 + - uid: 224 + components: + - type: Transform + pos: -3.5,-2.5 + parent: 1 + - uid: 225 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 3.5,-8.5 + parent: 1 + - uid: 226 + components: + - type: Transform + rot: -1.5707963267948966 rad + pos: 6.5,-2.5 + parent: 1 + - uid: 227 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 6.5,-6.5 + parent: 1 + - uid: 228 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -3.5,-1.5 + parent: 1 + - uid: 229 + components: + - type: Transform + pos: -3.5,0.5 + parent: 1 + - uid: 230 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: -1.5,-8.5 + parent: 1 + - uid: 231 + components: + - type: Transform + rot: 3.141592653589793 rad + pos: 4.5,-8.5 + parent: 1 +... diff --git a/Resources/Maps/Test/dev_map.yml b/Resources/Maps/Test/dev_map.yml index f00d7049a52..910a059ee72 100644 --- a/Resources/Maps/Test/dev_map.yml +++ b/Resources/Maps/Test/dev_map.yml @@ -4358,7 +4358,6 @@ entities: solutions: absorbed: temperature: 293.15 - canMix: False canReact: True maxVol: 50 name: null diff --git a/Resources/Maps/core.yml b/Resources/Maps/core.yml index d8ad22c30ac..aac0dcf7500 100644 --- a/Resources/Maps/core.yml +++ b/Resources/Maps/core.yml @@ -68975,7 +68975,6 @@ entities: solutions: drink: temperature: 293.15 - canMix: False canReact: True maxVol: 50 name: null diff --git a/Resources/Maps/tortuga.yml b/Resources/Maps/tortuga.yml index 399a06a400c..cb638de0339 100644 --- a/Resources/Maps/tortuga.yml +++ b/Resources/Maps/tortuga.yml @@ -153158,7 +153158,6 @@ entities: solutions: puddle: temperature: 293.15 - canMix: False canReact: True maxVol: 1000 name: null diff --git a/Resources/Migrations/migration.yml b/Resources/Migrations/migration.yml index 3b4a7178cf8..3ac6b353a9b 100644 --- a/Resources/Migrations/migration.yml +++ b/Resources/Migrations/migration.yml @@ -160,7 +160,7 @@ ActionVehicleHorn: null CrateFunATV: null CrateFunSyndicateSegway: null MobTaxiBot: null -MobSupplyBot: null +# MobSupplyBot: null SpawnVehicleMotobike: null SpawnVehicleATV: null SpawnVehicleSecway: null @@ -212,6 +212,8 @@ AirlockShuttleEasyPryLocked: AirlockExternalShuttleLocked ClothingBackpackFilledDetective: ClothingBackpackSecurityFilledDetective ClothingBackpackDuffelFilledDetective: ClothingBackpackDuffelSecurityFilledDetective ClothingBackpackSatchelFilledDetective: ClothingBackpackSatchelSecurityFilledDetective +FoodChili: FoodChiliPepper +FoodChilly: FoodChillyPepper # 2024-03-16 ClothingHeadHatHairflower: FoodPoppy @@ -220,6 +222,8 @@ ClothingHeadHatHairflower: FoodPoppy RPED: null # 2024-03-30 +TraversalDistorterMachineCircuitboard: null +MachineTraversalDistorter: null # These are technically not equivalent, but it probably makes more sense to replace any existing SCAF stuff with SOME kind of armor, instead of just deleting it outright. ClothingHeadHelmetScaf: ClothingHeadHelmetBasic ClothingOuterArmorScaf: ClothingOuterArmorBasic @@ -232,3 +236,11 @@ BriefcaseSyndieBase: null # 2024-04-08 BodyBag_Container: BodyBag BodyBag_Folded: BodyBagFolded + +# 2024-04-26 +GlassBoxLaserBroken: GlassBoxBroken +ReinforcementRadioSyndicateMonkey: ReinforcementRadioSyndicateAncestor +ReinforcementRadioSyndicateMonkeyNukeops: ReinforcementRadioSyndicateAncestorNukeops + +# 2024-05-01 +DrinkBottleGoldschlager: DrinkBottleGildlager diff --git a/Resources/Prototypes/Accents/word_replacements.yml b/Resources/Prototypes/Accents/word_replacements.yml index a5269924f7a..cb4cdf0683a 100644 --- a/Resources/Prototypes/Accents/word_replacements.yml +++ b/Resources/Prototypes/Accents/word_replacements.yml @@ -425,3 +425,50 @@ chatsan-word-42: chatsan-replacement-42 chatsan-word-43: chatsan-replacement-43 chatsan-word-44: chatsan-replacement-44 + +- type: accent + id: liar + wordReplacements: + liar-word-1: liar-word-replacement-1 + liar-word-2: liar-word-replacement-2 + liar-word-3: liar-word-replacement-3 + liar-word-4: liar-word-replacement-4 + liar-word-5: liar-word-replacement-5 + liar-word-6: liar-word-replacement-6 + liar-word-7: liar-word-replacement-7 + liar-word-8: liar-word-replacement-8 + liar-word-9: liar-word-replacement-9 + liar-word-10: liar-word-replacement-10 + liar-word-11: liar-word-replacement-11 + liar-word-12: liar-word-replacement-12 + liar-word-13: liar-word-replacement-13 + liar-word-14: liar-word-replacement-14 + liar-word-15: liar-word-replacement-15 + liar-word-16: liar-word-replacement-16 + liar-word-17: liar-word-replacement-17 + liar-word-18: liar-word-replacement-18 + liar-word-19: liar-word-replacement-19 + liar-word-20: liar-word-replacement-20 + liar-word-21: liar-word-replacement-21 + liar-word-22: liar-word-replacement-22 + liar-word-23: liar-word-replacement-23 + liar-word-24: liar-word-replacement-24 + liar-word-25: liar-word-replacement-25 + liar-word-26: liar-word-replacement-26 + liar-word-27: liar-word-replacement-27 + liar-word-28: liar-word-replacement-28 + liar-word-29: liar-word-replacement-29 + liar-word-30: liar-word-replacement-30 + liar-word-31: liar-word-replacement-31 + liar-word-32: liar-word-replacement-32 + liar-word-33: liar-word-replacement-33 + liar-word-34: liar-word-replacement-34 + liar-word-34-2: liar-word-replacement-34 + liar-word-35: liar-word-replacement-35 + liar-word-36: liar-word-replacement-36 + liar-word-37: liar-word-replacement-37 + liar-word-38: liar-word-replacement-38 + liar-word-39: liar-word-replacement-39 + liar-word-40: liar-word-replacement-40 + liar-word-41: liar-word-replacement-41 + liar-word-42: liar-word-replacement-42 \ No newline at end of file diff --git a/Resources/Prototypes/Access/security.yml b/Resources/Prototypes/Access/security.yml index cfb6e600606..b64424d8551 100644 --- a/Resources/Prototypes/Access/security.yml +++ b/Resources/Prototypes/Access/security.yml @@ -10,10 +10,9 @@ id: Armory name: id-card-access-level-armory -# Delta V: Removes Brig access because redundant -#- type: accessLevel -# id: Brig -# name: id-card-access-level-brig +- type: accessLevel + id: Brig + name: id-card-access-level-brig - type: accessLevel id: Detective @@ -25,14 +24,14 @@ - HeadOfSecurity - Security - Armory - #- Brig #Delta V removed + - Brig - Detective - Cryogenics - - Corpsman # DeltaV - add Corpsman access + - Corpsman - type: accessGroup id: Armory tags: - Security - Armory - # Brig #Delta V removed + - Brig diff --git a/Resources/Prototypes/Actions/polymorph.yml b/Resources/Prototypes/Actions/polymorph.yml index 7472fc00620..445dc8d9f54 100644 --- a/Resources/Prototypes/Actions/polymorph.yml +++ b/Resources/Prototypes/Actions/polymorph.yml @@ -14,3 +14,33 @@ - type: InstantAction event: !type:PolymorphActionEvent itemIconStyle: NoItem + +- type: entity + id: ActionPolymorphWizardSpider + name: Spider Polymorph + description: Polymorphs you into a Spider. + noSpawn: true + components: + - type: InstantAction + useDelay: 60 + event: !type:PolymorphActionEvent + protoId: WizardSpider + itemIconStyle: NoItem + icon: + sprite: Mobs/Animals/spider.rsi + state: tarantula + +- type: entity + id: ActionPolymorphWizardRod + name: Rod Form + description: CLANG! + noSpawn: true + components: + - type: InstantAction + useDelay: 60 + event: !type:PolymorphActionEvent + protoId: WizardRod + itemIconStyle: NoItem + icon: + sprite: Objects/Fun/immovable_rod.rsi + state: icon diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml index cf0a99f3bad..f81def7f7c3 100644 --- a/Resources/Prototypes/Actions/types.yml +++ b/Resources/Prototypes/Actions/types.yml @@ -92,7 +92,6 @@ state: gib event: !type:ActivateImplantEvent - - type: entity id: ActionActivateFreedomImplant name: Break Free @@ -130,6 +129,7 @@ noSpawn: true components: - type: InstantAction + checkCanInteract: false charges: 3 useDelay: 5 itemIconStyle: BigAction @@ -171,6 +171,21 @@ state: icon event: !type:UseDnaScramblerImplantEvent +- type: entity + id: ActionMorphGeras + name: Morph into Geras + description: Morphs you into a Geras - a miniature version of you which allows you to move fast, at the cost of your inventory. + noSpawn: true + components: + - type: InstantAction + itemIconStyle: BigAction + useDelay: 10 # prevent spam + priority: -20 + icon: + sprite: Mobs/Aliens/slimes.rsi + state: blue_adult_slime + event: !type:MorphIntoGeras + - type: entity id: ActionToggleSuitPiece name: Toggle Suit Piece diff --git a/Resources/Prototypes/AlertLevels/alert_levels.yml b/Resources/Prototypes/AlertLevels/alert_levels.yml index 5a8cb2dd129..db15dc13885 100644 --- a/Resources/Prototypes/AlertLevels/alert_levels.yml +++ b/Resources/Prototypes/AlertLevels/alert_levels.yml @@ -5,18 +5,22 @@ green: announcement: alert-level-green-announcement color: Green + emergencyLightColor: LawnGreen sound: /Audio/Announcements/Alerts/code_green.ogg shuttleTime: 600 blue: announcement: alert-level-blue-announcement sound: /Audio/Announcements/Alerts/code_blue.ogg color: DodgerBlue + forceEnableEmergencyLights: true + emergencyLightColor: DodgerBlue shuttleTime: 600 violet: announcement: alert-level-violet-announcement sound: /Audio/Announcements/Alerts/code_violet.ogg color: Violet emergencyLightColor: Violet + forceEnableEmergencyLights: true shuttleTime: 600 white: announcement: alert-level-white-announcement @@ -29,11 +33,14 @@ sound: /Audio/Announcements/Alerts/code_yellow.ogg color: Yellow emergencyLightColor: Goldenrod + forceEnableEmergencyLights: true shuttleTime: 600 red: announcement: alert-level-red-announcement sound: /Audio/Announcements/Alerts/code_red.ogg color: Red + emergencyLightColor: Red + forceEnableEmergencyLights: true shuttleTime: 600 gamma: announcement: alert-level-gamma-announcement diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml index 47015bf21f5..1e0a8a8c626 100644 --- a/Resources/Prototypes/Alerts/alerts.yml +++ b/Resources/Prototypes/Alerts/alerts.yml @@ -26,6 +26,7 @@ - alertType: Magboots - alertType: Pacified - alertType: Offer + - alertType: Deflecting - type: entity id: AlertSpriteView @@ -608,3 +609,11 @@ state: mood_happiness_bad name: alerts-mood-dead-name description: alerts-mood-dead-desc + +- type: alert + id: Deflecting + icons: + - sprite: /Textures/Interface/Alerts/deflecting.rsi + state: deflecting0 + name: alerts-deflecting-name + description: alerts-deflecting-desc diff --git a/Resources/Prototypes/Anomaly/behaviours.yml b/Resources/Prototypes/Anomaly/behaviours.yml index aa9ad2f90d3..e39933c365c 100644 --- a/Resources/Prototypes/Anomaly/behaviours.yml +++ b/Resources/Prototypes/Anomaly/behaviours.yml @@ -58,14 +58,14 @@ id: DelayedForce earnPointModifier: 1.15 description: anomaly-behavior-delayed-force - pulseFrequencyModifier: 0.5 + pulseFrequencyModifier: 2 pulsePowerModifier: 2 - type: anomalyBehavior id: Rapid earnPointModifier: 1.15 description: anomaly-behavior-rapid - pulseFrequencyModifier: 2 + pulseFrequencyModifier: 0.5 pulsePowerModifier: 0.5 - type: anomalyBehavior @@ -84,6 +84,7 @@ description: anomaly-behavior-reflect components: - type: Reflect + innate: true reflectProb: 0.5 reflects: - Energy diff --git a/Resources/Prototypes/Body/Parts/terminator.yml b/Resources/Prototypes/Body/Parts/terminator.yml deleted file mode 100644 index 58530da959c..00000000000 --- a/Resources/Prototypes/Body/Parts/terminator.yml +++ /dev/null @@ -1,158 +0,0 @@ -- type: entity - abstract: true - parent: BaseItem - id: PartTerminator - name: nt-800 body part - components: - - type: Sprite - sprite: Mobs/Species/Terminator/parts.rsi - - type: Icon - sprite: Mobs/Species/Terminator/parts.rsi - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Cybernetic - - type: BodyPart - - type: ContainerContainer - containers: - bodypart: !type:Container - ents: [] - - type: Gibbable - - type: StaticPrice - price: 200 - -- type: entity - parent: PartTerminator - id: TorsoTerminator - name: nt-800 torso - components: - - type: Sprite - state: torso_m - - type: Icon - state: torso_m - - type: BodyPart - partType: Torso - -- type: entity - parent: PartTerminator - id: HeadTerminator - name: nt-800 skull - description: Its red eyes have powered down... for now. - components: - - type: Sprite - state: skull_icon - - type: Icon - state: skull_icon - - type: BodyPart - partType: Head - # killing a terminators worth big bucks - - type: StaticPrice - price: 2000 - - type: Tag - tags: - - Head - -- type: entity - parent: PartTerminator - id: LeftArmTerminator - name: left nt-800 arm - components: - - type: Sprite - state: l_arm - - type: Icon - state: l_arm - - type: BodyPart - partType: Arm - symmetry: Left - -- type: entity - parent: PartTerminator - id: RightArmTerminator - name: right nt-800 arm - components: - - type: Sprite - state: r_arm - - type: Icon - state: r_arm - - type: BodyPart - partType: Arm - symmetry: Right - -- type: entity - parent: PartTerminator - id: LeftHandTerminator - name: left nt-800 hand - components: - - type: Sprite - state: l_hand - - type: Icon - state: l_hand - - type: BodyPart - partType: Hand - symmetry: Left - -- type: entity - parent: PartTerminator - id: RightHandTerminator - name: right nt-800 hand - components: - - type: Sprite - state: r_hand - - type: Icon - state: r_hand - - type: BodyPart - partType: Hand - symmetry: Right - -- type: entity - parent: PartTerminator - id: LeftLegTerminator - name: left nt-800 leg - components: - - type: Sprite - state: l_leg - - type: Icon - state: l_leg - - type: BodyPart - partType: Leg - symmetry: Left - - type: MovementBodyPart - -- type: entity - parent: PartTerminator - id: RightLegTerminator - name: right nt-800 leg - components: - - type: Sprite - state: r_leg - - type: Icon - state: r_leg - - type: BodyPart - partType: Leg - symmetry: Right - - type: MovementBodyPart - -- type: entity - parent: PartTerminator - id: LeftFootTerminator - name: left nt-800 foot - components: - - type: Sprite - state: l_foot - - type: Icon - state: l_foot - - type: BodyPart - partType: Foot - symmetry: Left - -- type: entity - parent: PartTerminator - id: RightFootTerminator - name: right nt-800 foot - components: - - type: Sprite - state: r_foot - - type: Icon - state: r_foot - - type: BodyPart - partType: Foot - symmetry: Right diff --git a/Resources/Prototypes/Body/Parts/vox.yml b/Resources/Prototypes/Body/Parts/vox.yml index b163ed0864f..9f89a0c583d 100644 --- a/Resources/Prototypes/Body/Parts/vox.yml +++ b/Resources/Prototypes/Body/Parts/vox.yml @@ -33,10 +33,10 @@ components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi - state: "torso_m" + state: "torso" - type: Icon sprite: Mobs/Species/Vox/parts.rsi - state: "torso_m" + state: "torso" - type: BodyPart partType: Torso - type: Extractable @@ -54,10 +54,10 @@ components: - type: Sprite sprite: Mobs/Species/Vox/parts.rsi - state: "head_m" + state: "head" - type: Icon sprite: Mobs/Species/Vox/parts.rsi - state: "head_m" + state: "head" - type: BodyPart partType: Head vital: true diff --git a/Resources/Prototypes/Body/Prototypes/terminator.yml b/Resources/Prototypes/Body/Prototypes/terminator.yml deleted file mode 100644 index c271a89d869..00000000000 --- a/Resources/Prototypes/Body/Prototypes/terminator.yml +++ /dev/null @@ -1,85 +0,0 @@ -# not quite human... -- type: body - id: TerminatorFlesh - name: exterminator - root: torso - slots: - head: - part: HeadHuman - connections: - - torso - organs: - brain: MobTerminatorEndoskeleton - torso: - part: TorsoHuman - connections: - - left arm - - right arm - - left leg - - right leg - right arm: - part: RightArmHuman - connections: - - right hand - left arm: - part: LeftArmHuman - connections: - - left hand - right hand: - part: RightHandHuman - left hand: - part: LeftHandHuman - right leg: - part: RightLegHuman - connections: - - right foot - left leg: - part: LeftLegHuman - connections: - - left foot - right foot: - part: RightFootHuman - left foot: - part: LeftFootHuman - -# TODO: terminator body parts -- type: body - id: TerminatorEndoskeleton - name: terminatorEndoskeleton - root: torso - slots: - head: - part: HeadTerminator - connections: - - torso - torso: - part: TorsoTerminator - connections: - - left arm - - right arm - - left leg - - right leg - right arm: - part: RightArmTerminator - connections: - - right hand - left arm: - part: LeftArmTerminator - connections: - - left hand - right hand: - part: RightHandTerminator - left hand: - part: LeftHandTerminator - right leg: - part: RightLegTerminator - connections: - - right foot - left leg: - part: LeftLegTerminator - connections: - - left foot - right foot: - part: RightFootTerminator - left foot: - part: LeftFootTerminator diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_engines.yml b/Resources/Prototypes/Catalog/Cargo/cargo_engines.yml index bd00b0c2d4c..8d3bea5075c 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_engines.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_engines.yml @@ -28,17 +28,17 @@ category: cargoproduct-category-name-engineering group: market -#- type: cargoProduct -# name: "emitter crate" -# id: EngineSingularityEmitter -# description: "Contains an emitter. Used only for dangerous applications." -# icon: -# sprite: Structures/Power/Generation/Singularity/emitter.rsi -# state: emitter2 -# product: CrateEngineeringSingularityEmitter -# cost: 3000 -# category: cargoproduct-category-name-engineering -# group: market +- type: cargoProduct + name: "emitter crate" + id: EngineSingularityEmitter + description: "Contains an emitter. Used only for dangerous applications." + icon: + sprite: Structures/Power/Generation/Singularity/emitter.rsi + state: emitter2 + product: CrateEngineeringSingularityEmitter + cost: 3000 + category: cargoproduct-category-name-engineering + group: market - type: cargoProduct id: EngineSingularityCollector diff --git a/Resources/Prototypes/Catalog/Cargo/cargo_security.yml b/Resources/Prototypes/Catalog/Cargo/cargo_security.yml index daa5e95777b..f66232b06f9 100644 --- a/Resources/Prototypes/Catalog/Cargo/cargo_security.yml +++ b/Resources/Prototypes/Catalog/Cargo/cargo_security.yml @@ -34,7 +34,7 @@ sprite: DeltaV/Clothing/OuterClothing/Armor/riot.rsi # DeltaV - resprite state: icon product: CrateSecurityRiot - cost: 5500 + cost: 7500 category: cargoproduct-category-name-security group: market diff --git a/Resources/Prototypes/Catalog/Fills/Crates/engines.yml b/Resources/Prototypes/Catalog/Fills/Crates/engines.yml index 9b47036b017..79698b550a7 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/engines.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/engines.yml @@ -42,7 +42,7 @@ components: - type: StorageFill contents: - - id: Emitter # TODO change to flatpack + - id: EmitterFlatpack # TODO change to flatpack - type: entity id: CrateEngineeringSingularityCollector diff --git a/Resources/Prototypes/Catalog/Fills/Crates/service.yml b/Resources/Prototypes/Catalog/Fills/Crates/service.yml index 141f98edab2..35e66ac4d35 100644 --- a/Resources/Prototypes/Catalog/Fills/Crates/service.yml +++ b/Resources/Prototypes/Catalog/Fills/Crates/service.yml @@ -20,7 +20,7 @@ - id: Plunger amount: 2 - id: BoxCleanerGrenades - + - type: entity id: CrateServiceReplacementLights parent: CrateGenericSteel @@ -88,6 +88,10 @@ - id: ClothingNeckCloakVoid - id: RevolverCapGun - id: BarberScissors + - id: ClothingUniformJumpskirtOldDress + - id: BikeHorn + - id: ClownRecorder + - id: ClothingBeltSuspenders - type: entity id: CrateServiceCustomSmokable diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml index e4d995e52ee..b3efb6ec1d2 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/engineer.yml @@ -65,13 +65,20 @@ components: - type: StorageFill contents: + - id: ClothingHeadHatWelding + - id: ClothingHeadHatWelding + - id: ClothingHeadHatWelding + prob: 0.5 + - id: Welder + - id: Welder - id: WelderMini + orGroup: thirdWelder - id: Welder - prob: 0.7 + prob: 0.33 + orGroup: thirdWelder - id: WelderIndustrial - prob: 0.5 - - id: ClothingHeadHatWelding - prob: 0.5 + prob: 0.33 + orGroup: thirdWelder - type: entity id: LockerAtmosphericsFilledHardsuit diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index 752591da371..d3895153564 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -15,6 +15,8 @@ prob: 0.50 - id: DoorRemoteCargo - id: RubberStampQm + - id: RubberStampDenied + - id: RubberStampApproved - id: ClothingHeadsetAltCargo - id: BoxEncryptionKeyCargo - id: SpaceCashLuckyBill # DeltaV - LO steal objective, see Resources/Prototypes/DeltaV/Entities/Objects/Misc/first_bill.yml @@ -132,6 +134,8 @@ - id: DoorRemoteService - id: ClothingNeckGoldmedal - id: RubberStampHop + - id: RubberStampDenied + - id: RubberStampApproved - id: BoxEncryptionKeyPassenger - id: BoxEncryptionKeyService - id: AccessConfigurator diff --git a/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml b/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml index e13070d1ba9..4893fa2557f 100644 --- a/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml +++ b/Resources/Prototypes/Catalog/Fills/Paper/manuals.yml @@ -19,7 +19,7 @@ key: enum.PaperUiKey.Key - type: UserInterface interfaces: - - key: enum.PaperUiKey.Key - type: PaperBoundUserInterface + enum.PaperUiKey.Key: + type: PaperBoundUserInterface - type: Paper content: book-text-holoparasite-info diff --git a/Resources/Prototypes/Catalog/Jukebox/Standard.yml b/Resources/Prototypes/Catalog/Jukebox/Standard.yml index e9d86874c59..7440428bd49 100644 --- a/Resources/Prototypes/Catalog/Jukebox/Standard.yml +++ b/Resources/Prototypes/Catalog/Jukebox/Standard.yml @@ -33,3 +33,9 @@ name: Qwertyquerty - Starlight path: path: /Audio/Jukebox/starlight.ogg + +- type: jukebox + id: sunset + name: PigeonBeans - Sunset + path: + path: /Audio/Jukebox/sunset.ogg diff --git a/Resources/Prototypes/Catalog/ReagentDispensers/beverage.yml b/Resources/Prototypes/Catalog/ReagentDispensers/beverage.yml index 975541a502a..4689e26f8e6 100644 --- a/Resources/Prototypes/Catalog/ReagentDispensers/beverage.yml +++ b/Resources/Prototypes/Catalog/ReagentDispensers/beverage.yml @@ -6,6 +6,7 @@ - DrinkColaBottleFull - DrinkCreamCartonXL - DrinkDrGibbJug + - DrinkEnergyDrinkJug - DrinkGreenTeaJug - DrinkIceJug - DrinkJuiceLimeCartonXL diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml index ac298b240aa..1d86640d1c9 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/boozeomat.yml @@ -7,6 +7,9 @@ DrinkVacuumFlask: 5 DrinkFlaskBar: 5 DrinkShaker: 5 + DrinkJigger: 5 + DrinkIceBucket: 2 + BarSpoon: 3 CustomDrinkJug: 2 #to allow for custom drinks in the soda/booze dispensers DrinkAbsintheBottleFull: 2 DrinkAleBottleFull: 5 @@ -15,6 +18,7 @@ DrinkCognacBottleFull: 4 DrinkCoconutWaterCarton: 3 DrinkColaBottleFull: 4 + DrinkEnergyDrinkCan: 8 DrinkMilkCarton: 2 DrinkCreamCarton: 5 DrinkGinBottleFull: 3 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml index 282f58535b0..5befd85ca84 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/chang.yml @@ -7,4 +7,5 @@ DrinkHellRamen: 3 FoodSnackChowMein: 3 FoodSnackDanDanNoodles: 3 + PairedChopsticks: 3 # rice? diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml index aac1cbb3f49..fe332ea52dc 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/curadrobe.yml @@ -4,6 +4,7 @@ BooksBag: 2 BriefcaseBrown: 2 HandLabeler: 2 + Cane: 3 ClothingEyesGlasses: 2 ClothingEyesGlassesJamjar: 2 ClothingNeckScarfStripedGreen: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml index f45dd229a2a..91e45c83916 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/detdrobe.yml @@ -4,7 +4,7 @@ ClothingUniformJumpsuitDetective: 2 ClothingUniformJumpskirtDetective: 2 ClothingShoesColorBrown: 2 - ClothingOuterCoatDetective: 2 + ClothingOuterCoatDetectiveLoadout: 2 ClothingHeadHatFedoraBrown: 2 ClothingUniformJumpsuitDetectiveGrey: 2 ClothingUniformJumpskirtDetectiveGrey: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml index 0b9a73aa6e6..ba270a9af84 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/dinnerware.yml @@ -6,6 +6,7 @@ RollingPin: 4 Spoon: 4 Fork: 4 + PairedChopsticks: 4 FoodBowlBig: 10 FoodPlate: 10 FoodPlateSmall: 10 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml index ddf79432175..fc8492dcf19 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/discount.yml @@ -4,6 +4,7 @@ FoodSnackCheesie: 3 FoodSnackChips: 3 FoodSnackBoritos: 3 + DrinkEnergyDrinkCan: 4 FoodSnackPopcorn: 3 FoodSnackEnergy: 3 CigPackMixed: 2 diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml index 6ac13d48d53..5f4600ed132 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/medical.yml @@ -7,8 +7,7 @@ Bloodpack: 5 EpinephrineChemistryBottle: 3 Syringe: 5 - Portafib: 1 # DeltaV - Add Portafibs, see Prototypes/DeltaV/Entities/Objects/Devices/Medical/portafib.yml - ClothingEyesGlasses: 5 # SimpleStation14 NearsightedTrait + Portafib: 1 + ClothingEyesGlasses: 5 ClothingEyesHudMedical: 2 ClothingEyesEyepatchHudMedical: 2 - diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml index 01b58ae40fb..723f944222b 100644 --- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml +++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/sec.yml @@ -19,11 +19,12 @@ RiotShield: 2 RiotLaserShield: 2 RiotBulletShield: 2 - ClothingHeadHelmetInsulated: 2 # Nyanotrasen - Insulative headgear - ClothingHeadCage: 2 # Nyanotrasen - Insulative headgear - ClothingOuterArmorPlateCarrier: 2 # DeltaV - moved body armour from SecDrobe to SecTech + RadioHandheldSecurity: 5 + ClothingHeadHelmetInsulated: 2 + ClothingHeadCage: 2 + ClothingOuterArmorPlateCarrier: 2 ClothingOuterArmorDuraVest: 2 - ClothingHeadHelmetBasic: 2 # DeltaV - added helmets to the SecTech. Another line of defense between the tide and your grey matter. + ClothingHeadHelmetBasic: 2 BreachingCharge: 8 # security officers need to follow a diet regimen! contrabandInventory: diff --git a/Resources/Prototypes/Catalog/spellbook_catalog.yml b/Resources/Prototypes/Catalog/spellbook_catalog.yml new file mode 100644 index 00000000000..38b95c3273c --- /dev/null +++ b/Resources/Prototypes/Catalog/spellbook_catalog.yml @@ -0,0 +1,140 @@ +# Offensive +- type: listing + id: SpellbookFireball + name: spellbook-fireball-name + description: spellbook-fireball-desc + productAction: ActionFireball + productUpgradeId: SpellbookFireballUpgrade + cost: + WizCoin: 2 + categories: + - SpellbookOffensive + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: SpellbookRodForm + name: spellbook-polymorph-rod-name + description: spellbook-polymorph-rod-desc + productAction: ActionPolymorphWizardRod + cost: + WizCoin: 3 + categories: + - SpellbookOffensive + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +# Defensive +- type: listing + id: SpellbookForceWall + name: spellbook-force-wall-name + description: spellbook-force-wall-desc + productAction: ActionForceWall + cost: + WizCoin: 3 + categories: + - SpellbookDefensive + +# Utility +- type: listing + id: SpellbookPolymorphSpider + name: spellbook-polymoprh-spider-name + description: spellbook-polymorph-spider-desc + productAction: ActionPolymorphWizardSpider + cost: + WizCoin: 2 + categories: + - SpellbookUtility + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: SpellbookBlink + name: spellbook-blink-name + description: spellbook-blink-desc + productAction: ActionBlink + cost: + WizCoin: 1 + categories: + - SpellbookUtility + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: SpellbookCharge + name: spellbook-charge-name + description: spellbook-charge-desc + productAction: ActionChargeSpell + cost: + WizCoin: 1 + categories: + - SpellbookUtility + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +# Equipment +- type: listing + id: SpellbookWandDoor + name: spellbook-wand-polymorph-door-name + description: spellbook-wand-polymorph-door-description + productEntity: WeaponWandPolymorphDoor + cost: + WizCoin: 3 + categories: + - SpellbookEquipment + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: SpellbookWandPolymorphCarp + name: spellbook-wand-polymorph-carp-name + description: spellbook-wand-polymorph-carp-description + productEntity: WeaponWandPolymorphCarp + cost: + WizCoin: 3 + categories: + - SpellbookEquipment + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +# Event +- type: listing + id: SpellbookEventSummonGhosts + name: spellbook-event-summon-ghosts-name + description: spellbook-event-summon-ghosts-description + productAction: ActionSummonGhosts + cost: + WizCoin: 0 + categories: + - SpellbookEvents + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +# Upgrades +- type: listing + id: SpellbookFireballUpgrade + productUpgradeId: SpellbookFireballUpgrade + name: spellbook-upgrade-fireball-name + description: spellbook-upgrade-fireball-description + icon: + sprite: Objects/Magic/magicactions.rsi + state: fireball + cost: + WizCoin: 2 + categories: + - SpellbookOffensive + conditions: + - !type:BuyBeforeCondition + whitelist: + - SpellbookFireball + # manual for now + - !type:ListingLimitedStockCondition + stock: 2 diff --git a/Resources/Prototypes/Catalog/thief_toolbox_sets.yml b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml index 2c98b0b89da..e70e93732f3 100644 --- a/Resources/Prototypes/Catalog/thief_toolbox_sets.yml +++ b/Resources/Prototypes/Catalog/thief_toolbox_sets.yml @@ -14,6 +14,7 @@ - ClothingEyesChameleon - ClothingHeadsetChameleon - ClothingShoesChameleon + - ChameleonProjector - type: thiefBackpackSet id: ToolsSet diff --git a/Resources/Prototypes/Catalog/uplink_catalog.yml b/Resources/Prototypes/Catalog/uplink_catalog.yml index bdd27e83a89..2a99a1daa06 100644 --- a/Resources/Prototypes/Catalog/uplink_catalog.yml +++ b/Resources/Prototypes/Catalog/uplink_catalog.yml @@ -393,21 +393,193 @@ #Utility -#- type: listing # -# id: UplinkHoloparaKit -# name: uplink-holopara-kit-name -# description: uplink-holopara-kit-desc -# icon: { sprite: /Textures/Objects/Misc/guardian_info.rsi, state: icon } -# productEntity: BoxHoloparasite -# cost: -# Telecrystal: 14 -# categories: -# - UplinkUtility -# conditions: -# - !type:StoreWhitelistCondition -# blacklist: -# tags: -# - NukeOpsUplink +- type: listing + id: UplinkZombieBundle + name: uplink-zombie-bundle-name + description: uplink-zombie-bundle-desc + icon: { sprite: /Textures/Structures/Wallmounts/signs.rsi, state: bio } + productEntity: ClothingBackpackDuffelZombieBundle + cost: + Telecrystal: 40 + categories: + - UplinkChemicals + conditions: + - !type:StoreWhitelistCondition + whitelist: + tags: + - NukeOpsUplink + - !type:BuyerWhitelistCondition + blacklist: + components: + - SurplusBundle + saleLimit: 1 + +- type: listing + id: UplinkNocturineChemistryBottle + name: uplink-nocturine-chemistry-bottle-name + description: uplink-nocturine-chemistry-bottle-desc + productEntity: NocturineChemistryBottle + cost: + Telecrystal: 6 + categories: + - UplinkChemicals + saleLimit: 1 + +- type: listing + id: UplinkCombatMedkit + name: uplink-combat-medkit-name + description: uplink-combat-medkit-desc + productEntity: MedkitCombatFilled + cost: + Telecrystal: 5 + categories: + - UplinkChemicals + saleLimit: 1 + +- type: listing + id: UplinkCombatMedipen + name: uplink-combat-medipen-name + description: uplink-combat-medipen-desc + productEntity: CombatMedipen + cost: + Telecrystal: 4 + categories: + - UplinkChemicals + saleLimit: 1 + +- type: listing + id: UplinkStimpack + name: uplink-stimpack-name + description: uplink-stimpack-desc + productEntity: Stimpack + cost: + Telecrystal: 4 + categories: + - UplinkChemicals + saleLimit: 1 + +- type: listing + id: UplinkStimkit + name: uplink-stimkit-name + description: uplink-stimkit-desc + productEntity: StimkitFilled + cost: + Telecrystal: 12 + categories: + - UplinkChemicals + saleLimit: 1 + +- type: listing + id: UplinkCigarettes + name: uplink-cigarettes-name + description: uplink-cigarettes-desc + productEntity: CigPackSyndicate + cost: + Telecrystal: 2 + categories: + - UplinkChemicals + +- type: listing + id: UplinkMedsBundle + name: uplink-meds-bundle-name + description: uplink-meds-bundle-desc + productEntity: ClothingBackpackDuffelSyndicateMedicalBundleFilled + cost: + Telecrystal: 20 + categories: + - UplinkChemicals + conditions: + - !type:StoreWhitelistCondition + whitelist: + tags: + - NukeOpsUplink + - !type:BuyerWhitelistCondition + blacklist: + components: + - SurplusBundle + saleLimit: 1 + +# Deception + +- type: listing + id: UplinkAgentIDCard + name: uplink-agent-id-card-name + description: uplink-agent-id-card-desc + productEntity: AgentIDCard + cost: + Telecrystal: 3 + categories: + - UplinkDeception + +- type: listing + id: UplinkStealthBox + name: uplink-stealth-box-name + description: uplink-stealth-box-desc + productEntity: StealthBox + cost: + Telecrystal: 5 + categories: + - UplinkDeception + +- type: listing + id: UplinkChameleonProjector + name: uplink-chameleon-projector-name + description: uplink-chameleon-projector-desc + productEntity: ChameleonProjector + cost: + Telecrystal: 7 + categories: + - UplinkDeception + +- type: listing + id: UplinkCyberpen + name: uplink-cyberpen-name + description: uplink-cyberpen-desc + productEntity: CyberPen + cost: + Telecrystal: 1 + categories: + - UplinkDeception + +- type: listing + id: UplinkDecoyDisk + name: uplink-decoy-disk-name + description: uplink-decoy-disk-desc + productEntity: NukeDiskFake + cost: + Telecrystal: 1 + categories: + - UplinkDeception + +- type: listing + id: UplinkUltrabrightLantern + name: uplink-ultrabright-lantern-name + description: uplink-ultrabright-lantern-desc + productEntity: LanternFlash + cost: + Telecrystal: 2 + categories: + - UplinkDeception + +- type: listing + id: UplinkBribe + name: uplink-bribe-name + description: uplink-bribe-desc + productEntity: BriefcaseSyndieLobbyingBundleFilled + cost: + Telecrystal: 4 + categories: + - UplinkDeception + +# - type: listing +# id: UplinkGigacancerScanner +# name: Ultragigacancer Health Analyzer +# description: Works like a normal health analyzer, other than giving everyone it scans ultragigacancer. +# productEntity: HandheldHealthAnalyzerGigacancer +# cost: +# Telecrystal: 5 +# categories: +# - UplinkDeception - type: listing id: UplinkHolster @@ -430,14 +602,15 @@ - UplinkUtility - type: listing - id: UplinkAgentIDCard - name: uplink-agent-id-card-name - description: uplink-agent-id-card-desc - productEntity: AgentIDCard + id: UplinkSyndicateMartyrModule + name: uplink-syndicate-martyr-module-name + description: uplink-syndicate-martyr-module-desc + productEntity: BorgModuleMartyr + icon: { sprite: /Textures/Objects/Specific/Robotics/borgmodule.rsi, state: syndicateborgbomb } cost: - Telecrystal: 3 + Telecrystal: 4 categories: - - UplinkUtility + - UplinkDisruption - type: listing id: UplinkJetpack @@ -501,10 +674,10 @@ saleLimit: 1 - type: listing - id: UplinkReinforcementRadioSyndicateMonkey - name: uplink-reinforcement-radio-monkey-name - description: uplink-reinforcement-radio-monkey-desc - productEntity: ReinforcementRadioSyndicateMonkey + id: UplinkReinforcementRadioSyndicateAncestor + name: uplink-reinforcement-radio-ancestor-name + description: uplink-reinforcement-radio-ancestor-desc + productEntity: ReinforcementRadioSyndicateAncestor icon: { sprite: Objects/Devices/communication.rsi, state: radio } cost: Telecrystal: 8 @@ -517,10 +690,10 @@ - NukeOpsUplink - type: listing - id: UplinkReinforcementRadioSyndicateMonkeyNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component. - name: uplink-reinforcement-radio-monkey-name - description: uplink-reinforcement-radio-monkey-desc - productEntity: ReinforcementRadioSyndicateMonkeyNukeops + id: UplinkReinforcementRadioSyndicateAncestorNukeops # Version for Nukeops that spawns a syndicate monkey with the NukeOperative component. + name: uplink-reinforcement-radio-ancestor-name + description: uplink-reinforcement-radio-ancestor-desc + productEntity: ReinforcementRadioSyndicateAncestorNukeops icon: { sprite: Objects/Devices/communication.rsi, state: radio } cost: Telecrystal: 6 @@ -533,16 +706,6 @@ - NukeOpsUplink saleLimit: 1 -- type: listing - id: UplinkStealthBox - name: uplink-stealth-box-name - description: uplink-stealth-box-desc - productEntity: StealthBox - cost: - Telecrystal: 5 - categories: - - UplinkUtility - - type: listing id: UplinkHeadsetEncryptionKey name: uplink-encryption-key-name @@ -595,11 +758,6 @@ Telecrystal: 2 categories: - UplinkUtility - conditions: - - !type:StoreWhitelistCondition - whitelist: - tags: - - NukeOpsUplink - type: listing id: UplinkRadioJammer @@ -862,25 +1020,6 @@ categories: - UplinkBundles -- type: listing - id: UplinkMedsBundle - name: uplink-meds-bundle-name - description: uplink-meds-bundle-desc - productEntity: ClothingBackpackDuffelSyndicateMedicalBundleFilled - cost: - Telecrystal: 20 - categories: - - UplinkBundles - conditions: - - !type:StoreWhitelistCondition - whitelist: - tags: - - NukeOpsUplink - - !type:BuyerWhitelistCondition - blacklist: - components: - - SurplusBundle - saleLimit: 1 - type: listing id: UplinkSniperBundle @@ -942,27 +1081,6 @@ - UplinkBundles saleLimit: 1 -- type: listing - id: UplinkZombieBundle - name: uplink-zombie-bundle-name - description: uplink-zombie-bundle-desc - icon: { sprite: /Textures/Structures/Wallmounts/signs.rsi, state: bio } - productEntity: ClothingBackpackDuffelZombieBundle - cost: - Telecrystal: 40 - categories: - - UplinkBundles - conditions: - - !type:StoreWhitelistCondition - whitelist: - tags: - - NukeOpsUplink - - !type:BuyerWhitelistCondition - blacklist: - components: - - SurplusBundle - saleLimit: 1 - - type: listing id: UplinkSurplusBundle name: uplink-surplus-bundle-name @@ -1271,6 +1389,24 @@ - ResearchDirector - Chef +- type: listing + id: UplinkCaneBlade + name: uplink-cane-blade-name + description: uplink-cane-blade-desc + icon: { sprite: Objects/Weapons/Melee/cane.rsi, state: cane} + productEntity: CaneSheathFilled + cost: + Telecrystal: 5 + categories: + - UplinkJob + conditions: + - !type:BuyerJobCondition + whitelist: + - Librarian + - !type:BuyerWhitelistCondition + blacklist: + components: + - SurplusBundle - type: listing id: UplinkSingarityBeacon name: uplink-singularity-beacon-name @@ -1393,36 +1529,6 @@ # Misc -- type: listing - id: UplinkCyberpen - name: uplink-cyberpen-name - description: uplink-cyberpen-desc - productEntity: CyberPen - cost: - Telecrystal: 1 - categories: - - UplinkMisc - -- type: listing - id: UplinkDecoyDisk - name: uplink-decoy-disk-name - description: uplink-decoy-disk-desc - productEntity: NukeDiskFake - cost: - Telecrystal: 1 - categories: - - UplinkMisc - -- type: listing - id: UplinkCigarettes - name: uplink-cigarettes-name - description: uplink-cigarettes-desc - productEntity: CigPackSyndicate - cost: - Telecrystal: 2 - categories: - - UplinkMisc - - type: listing id: UplinkClothingConductingGloves name: uplink-clothing-conducting-gloves-name @@ -1480,16 +1586,6 @@ categories: - UplinkMisc -- type: listing - id: UplinkUltrabrightLantern - name: uplink-ultrabright-lantern-name - description: uplink-ultrabright-lantern-desc - productEntity: LanternFlash - cost: - Telecrystal: 2 - categories: - - UplinkMisc - # - type: listing # id: UplinkGigacancerScanner # name: Ultragigacancer Health Analyzer @@ -1500,67 +1596,6 @@ # categories: # - UplinkMisc -- type: listing - id: UplinkNocturineChemistryBottle - name: uplink-nocturine-chemistry-bottle-name - description: uplink-nocturine-chemistry-bottle-desc - productEntity: NocturineChemistryBottle - cost: - Telecrystal: 6 - categories: - - UplinkMisc - -- type: listing - id: UplinkCombatMedkit - name: uplink-combat-medkit-name - description: uplink-combat-medkit-desc - productEntity: MedkitCombatFilled - cost: - Telecrystal: 5 - categories: - - UplinkMisc - -- type: listing - id: UplinkCombatMedipen - name: uplink-combat-medipen-name - description: uplink-combat-medipen-desc - productEntity: CombatMedipen - cost: - Telecrystal: 4 - categories: - - UplinkMisc - -- type: listing - id: UplinkStimpack - name: uplink-stimpack-name - description: uplink-stimpack-desc - productEntity: Stimpack - cost: - Telecrystal: 4 - categories: - - UplinkMisc - -- type: listing - id: UplinkStimkit - name: uplink-stimkit-name - description: uplink-stimkit-desc - productEntity: StimkitFilled - cost: - Telecrystal: 12 - categories: - - UplinkMisc - saleLimit: 1 - -- type: listing - id: UplinkBribe - name: uplink-bribe-name - description: uplink-bribe-desc - productEntity: BriefcaseSyndieLobbyingBundleFilled - cost: - Telecrystal: 4 - categories: - - UplinkMisc - - type: listing id: UplinkMobCatMicrobomb name: uplink-mobcat-microbomb-name diff --git a/Resources/Prototypes/Chemistry/metabolism_groups.yml b/Resources/Prototypes/Chemistry/metabolism_groups.yml index fc59edd81fe..b2035671af0 100644 --- a/Resources/Prototypes/Chemistry/metabolism_groups.yml +++ b/Resources/Prototypes/Chemistry/metabolism_groups.yml @@ -1,22 +1,29 @@ -# Default human metabolism groups. +# Default human metabolism groups. - type: metabolismGroup id: Poison + name: metabolism-group-poison - type: metabolismGroup id: Medicine + name: metabolism-group-medicine - type: metabolismGroup id: Narcotic + name: metabolism-group-narcotic - type: metabolismGroup id: Alcohol + name: metabolism-group-alcohol - type: metabolismGroup id: Food + name: metabolism-group-food - type: metabolismGroup id: Drink + name: metabolism-group-drink # Used for gases that have effects on being inhaled - type: metabolismGroup id: Gas + name: metabolism-group-gas diff --git a/Resources/Prototypes/Chemistry/metabolizer_types.yml b/Resources/Prototypes/Chemistry/metabolizer_types.yml index 316b8f02b53..b49fad6c277 100644 --- a/Resources/Prototypes/Chemistry/metabolizer_types.yml +++ b/Resources/Prototypes/Chemistry/metabolizer_types.yml @@ -3,52 +3,52 @@ - type: metabolizerType id: Animal - name: animal + name: metabolizer-type-animal - type: metabolizerType id: Bloodsucker - name: bloodsucker + name: metabolizer-type-bloodsucker - type: metabolizerType id: Dragon - name: dragon + name: metabolizer-type-dragon - type: metabolizerType id: Human - name: human + name: metabolizer-type-human - type: metabolizerType id: Slime - name: slime + name: metabolizer-type-slime - type: metabolizerType id: Vox - name: vox + name: metabolizer-type-vox - type: metabolizerType id: Rat - name: rat + name: metabolizer-type-rat - type: metabolizerType id: Plant - name: plant + name: metabolizer-type-plant - type: metabolizerType id: Dwarf - name: dwarf + name: metabolizer-type-dwarf - type: metabolizerType id: Moth - name: moth + name: metabolizer-type-moth - type: metabolizerType id: Arachnid - name: arachnid + name: metabolizer-type-arachnid - type: metabolizerType id: Vampiric - name: vampiric + name: metabolizer-type-vampiric - type: metabolizerType id: LiquorLifeline - name: liquorlifeline + name: metabolizer-type-liquorlifeline diff --git a/Resources/Prototypes/Damage/groups.yml b/Resources/Prototypes/Damage/groups.yml index 07bfe2edcdd..71e4acdaeaa 100644 --- a/Resources/Prototypes/Damage/groups.yml +++ b/Resources/Prototypes/Damage/groups.yml @@ -1,5 +1,6 @@ - type: damageGroup id: Brute + name: damage-group-brute damageTypes: - Blunt - Slash @@ -7,6 +8,7 @@ - type: damageGroup id: Burn + name: damage-group-burn damageTypes: - Heat - Shock @@ -19,6 +21,7 @@ # bloodloss, not this whole group, unless you have a wonder drug that affects both. - type: damageGroup id: Airloss + name: damage-group-airloss damageTypes: - Asphyxiation - Bloodloss @@ -27,11 +30,13 @@ # Though there are probably some radioactive poisons. - type: damageGroup id: Toxin + name: damage-group-toxin damageTypes: - Poison - Radiation - type: damageGroup id: Genetic + name: damage-group-genetic damageTypes: - Cellular diff --git a/Resources/Prototypes/Damage/modifier_sets.yml b/Resources/Prototypes/Damage/modifier_sets.yml index 811d5a580c2..02223b6a9fe 100644 --- a/Resources/Prototypes/Damage/modifier_sets.yml +++ b/Resources/Prototypes/Damage/modifier_sets.yml @@ -198,12 +198,10 @@ - type: damageModifierSet id: Zombie #Blunt resistant and immune to biological threats, but can be hacked apart and burned coefficients: - Blunt: 0.7 - Slash: 1.1 - Piercing: 0.9 - Shock: 1.25 + Blunt: 0.6 + Piercing: 0.8 Cold: 0.3 - Heat: 1.5 + Heat: 1.25 Poison: 0.0 Radiation: 0.0 @@ -244,7 +242,7 @@ Piercing: 0.2 Shock: 0.0 Cold: 0.0 - Heat: -1 # heat damage cauterizes wounds, but will still hurt obviously. + Heat: -0.5 # heat damage cauterizes wounds, but will still hurt obviously. Poison: 0.0 Radiation: 0.0 Asphyxiation: 0.0 @@ -298,64 +296,3 @@ Cellular: 0.0 Heat: 2.5 Caustic: 0.0 - -# terminator's flesh damage set -- type: damageModifierSet - id: CyberneticFlesh - coefficients: - Blunt: 0.2 - Slash: 0.2 - Piercing: 0.1 - # fire and lasers burn it good - Heat: 1.0 - # zap - Shock: 1.5 - Cold: 0.25 - Caustic: 0.25 - # doesnt have organs to poison - Poison: 0.0 - Cellular: 0.0 - -# terminator's endoskeleton damage set -- type: damageModifierSet - id: Cybernetic - coefficients: - # bonk - Blunt: 1.0 - # alloy too hard to cut or shoot - Slash: 0.0 - Piercing: 0.0 - # no burning anymore - Heat: 0.0 - # zap zap - Shock: 2.5 - Cold: 0.0 - Caustic: 0.0 - Poison: 0.0 - Cellular: 0.0 - flatReductions: - # can't punch the endoskeleton to death - Blunt: 5 - -- type: damageModifierSet - id: HalfSpirit - coefficients: - Cold: 0.5 - Shock: 0.75 - Blunt: 0.75 - Slash: 0.75 - Piercing: 0.75 - Heat: 1.25 - Holy: 1.5 - flatReductions: - Cold: 3 - -- type: damageModifierSet - id: FireSpirit - coefficients: - Heat: 0 - Cold: 1.2 - Blunt: 0.6 - Slash: 0.6 - Piercing: 0.6 - Holy: 1.5 diff --git a/Resources/Prototypes/Damage/types.yml b/Resources/Prototypes/Damage/types.yml index bacaf1f7985..0107da24823 100644 --- a/Resources/Prototypes/Damage/types.yml +++ b/Resources/Prototypes/Damage/types.yml @@ -3,6 +3,7 @@ # Usually healed automatically if entity can breathe - type: damageType id: Asphyxiation + name: damage-type-asphyxiation armorCoefficientPrice: 5 armorFlatPrice: 50 @@ -11,57 +12,68 @@ # Represents there not enough blood to supply oxygen (or equivalent). - type: damageType id: Bloodloss + name: damage-type-bloodloss armorCoefficientPrice: 5 armorFlatPrice: 50 - type: damageType id: Blunt + name: damage-type-blunt armorCoefficientPrice: 2 armorFlatPrice: 10 - type: damageType id: Cellular + name: damage-type-cellular armorCoefficientPrice: 5 armorFlatPrice: 30 - type: damageType id: Caustic + name: damage-type-caustic armorCoefficientPrice: 5 armorFlatPrice: 30 - type: damageType id: Cold + name: damage-type-cold armorCoefficientPrice: 2.5 armorFlatPrice: 20 - type: damageType id: Heat + name: damage-type-heat armorCoefficientPrice: 2.5 armorFlatPrice: 20 - type: damageType id: Piercing + name: damage-type-piercing armorCoefficientPrice: 2 armorFlatPrice: 10 # Poison damage. Generally caused by various reagents being metabolised. - type: damageType id: Poison + name: damage-type-poison armorCoefficientPrice: 10 armorFlatPrice: 60 - type: damageType id: Radiation + name: damage-type-radiation armorCoefficientPrice: 2.5 armorFlatPrice: 16 - type: damageType id: Shock + name: damage-type-shock armorCoefficientPrice: 2.5 armorFlatPrice: 20 - type: damageType id: Slash + name: damage-type-slash armorCoefficientPrice: 2 armorFlatPrice: 10 @@ -69,5 +81,6 @@ # Exclusive for structures such as walls, airlocks and others. - type: damageType id: Structural + name: damage-type-structural armorCoefficientPrice: 1 armorFlatPrice: 1 diff --git a/Resources/Prototypes/Datasets/corporations.yml b/Resources/Prototypes/Datasets/corporations.yml new file mode 100644 index 00000000000..55b1d53d2f7 --- /dev/null +++ b/Resources/Prototypes/Datasets/corporations.yml @@ -0,0 +1,12 @@ +- type: dataset + id: TraitorCorporations + values: + - "CyberSun Industries" + - "Gorlex Marauders" + - "MI13" + - "Tiger Cooperative" + - "S.E.L.F." + - "Animal Rights Consortium" + - "Donk Corporation" + - "Waffle Corporation" + - "Interdyne Pharmaceutics" \ No newline at end of file diff --git a/Resources/Prototypes/Datasets/criminal_records.yml b/Resources/Prototypes/Datasets/criminal_records.yml index ee283091843..fe21757cd20 100644 --- a/Resources/Prototypes/Datasets/criminal_records.yml +++ b/Resources/Prototypes/Datasets/criminal_records.yml @@ -2,17 +2,23 @@ - type: dataset id: CriminalRecordsWantedReasonPlaceholders values: + - Ate a delicious valid salad - Ate their own shoes - Being a clown - Being a mime - Breathed the wrong way - Broke into evac - Did literally nothing + - Did their job - Didn't say hello to me - Drank one too many + - Had two toolboxes, that's too many - Lied on common radio - Looked at me funny + - Lubed up the entire way to evac + - Set AME up on time - Slipped the HoS - Stole the clown's mask - Told an unfunny joke - Wore a gasmask + - Wore boxing gloves diff --git a/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml b/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml index 2d47ecd352d..adc626bc114 100644 --- a/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml +++ b/Resources/Prototypes/DeltaV/Body/Organs/harpy.yml @@ -10,7 +10,7 @@ - state: lung-r - type: Lung - type: Metabolizer - updateFrequency: 2.0 + updateInterval: 2.0 removeEmpty: true solutionOnBody: false solution: "Lung" diff --git a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml index a959b64a381..1e8a64b0df4 100644 --- a/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/DeltaV/Entities/Clothing/Eyes/hud.yml @@ -20,10 +20,9 @@ - type: Tag tags: - HudMedical - - GlassesNearsight - type: entity - parent: ClothingEyesBase + parent: [ ClothingEyesBase, ShowSecurityIcons ] id: ClothingEyesPrescriptionHudSecurity name: prescription security hud description: A poorly done and rushed mix between half of a pair of prescription glasses and a security HUD allowing you to see clearly out of one eye and inspect the employee's ID and warning status in the other! @@ -32,17 +31,15 @@ sprite: DeltaV/Clothing/Eyes/Hud/prescsechud.rsi - type: Clothing sprite: DeltaV/Clothing/Eyes/Hud/prescsechud.rsi - - type: ShowSecurityIcons - type: Construction graph: PrescriptionSecHud node: prescsechud - type: Tag tags: - HudSecurity - - GlassesNearsight - + - type: entity - parent: ClothingEyesBase + parent: [ ClothingEyesBase, ShowSecurityIcons ] id: ClothingEyesHudSyndicateMed name: syndicate medical visor description: An upgraded syndicate visor with automatic health readings, designed for better detection of humanoids and their subsequent elimination. @@ -52,7 +49,6 @@ - type: Clothing sprite: DeltaV/Clothing/Eyes/Hud/syndmed.rsi - type: ShowSyndicateIcons - - type: ShowSecurityIcons - type: ShowHealthBars damageContainers: - Biological diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml index de0f022e1f7..de1aff60888 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/animals.yml @@ -30,8 +30,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -145,8 +145,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml index 4d3d139e8e0..1090927cf8d 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/familiars.yml @@ -62,7 +62,7 @@ - type: Dispellable - type: Damageable damageContainer: CorporealSpirit - damageModifierSet: FireSpirit + damageModifierSet: CorporealSpirit - type: PassiveDamage # Slight passive regen. Assuming one damage type, comes out to about 4 damage a minute. allowedStates: - Alive @@ -144,10 +144,6 @@ - type: Welder fuelReagent: Phlogiston tankSafe: true - litMeleeDamageBonus: - types: # When lit, negate standard melee damage and replace with heat - Heat: 10 - Blunt: -10 # welderOnSounds: # collection: WelderIfritHandOn # welderOffSounds: diff --git a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml index 59c7fe2b212..09cafa29575 100644 --- a/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml +++ b/Resources/Prototypes/DeltaV/Entities/Mobs/NPCs/nukiemouse.yml @@ -67,8 +67,8 @@ - type: InventorySlots - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -147,7 +147,7 @@ - type: Bloodstream bloodMaxVolume: 60 - type: CanEscapeInventory - BaseResistTime: 3 + baseResistTime: 3 - type: MobPrice price: 250 # Their suits, while tiny, go for quite a bit on the market - type: IntrinsicRadioReceiver diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Misc/paperslips.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Misc/paperslips.yml index 3c25380e658..4ab4e54863e 100644 --- a/Resources/Prototypes/DeltaV/Entities/Objects/Misc/paperslips.yml +++ b/Resources/Prototypes/DeltaV/Entities/Objects/Misc/paperslips.yml @@ -125,10 +125,10 @@ - type: Paper - type: ActivatableUI key: enum.PaperUiKey.Key - closeOnHandDeselect: false + requireActiveHand: false - type: UserInterface interfaces: - - key: enum.PaperUiKey.Key + enum.PaperUiKey.Key: type: PaperBoundUserInterface - type: Item size: Tiny diff --git a/Resources/Prototypes/DeltaV/Entities/Structures/Machines/syndicate_monitor_server.yml b/Resources/Prototypes/DeltaV/Entities/Structures/Machines/syndicate_monitor_server.yml index 10933d716e2..02d3d69cc69 100644 --- a/Resources/Prototypes/DeltaV/Entities/Structures/Machines/syndicate_monitor_server.yml +++ b/Resources/Prototypes/DeltaV/Entities/Structures/Machines/syndicate_monitor_server.yml @@ -23,7 +23,6 @@ machine_parts: !type:Container - type: CrewMonitoringServer - type: SingletonDeviceNetServer - ServerType: CrewMonitoringServer - type: DeviceNetwork deviceNetId: Wireless transmitFrequencyId: CrewMonitor @@ -33,7 +32,6 @@ range: 10000 # Mega range for Listening Post - type: ApcPowerReceiver powerLoad: 200 - priority: Low - type: ExtensionCableReceiver - type: Destructible thresholds: diff --git a/Resources/Prototypes/DeltaV/GameRules/events.yml b/Resources/Prototypes/DeltaV/GameRules/events.yml index a3fb69cf73c..84a39e4c041 100644 --- a/Resources/Prototypes/DeltaV/GameRules/events.yml +++ b/Resources/Prototypes/DeltaV/GameRules/events.yml @@ -62,7 +62,6 @@ noSpawn: true components: - type: StationEvent - id: VentCritters earliestStart: 15 minimumPlayers: 1 weight: 4 diff --git a/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml b/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml index dd0b74c4616..ec87795ab5b 100644 --- a/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml +++ b/Resources/Prototypes/DeltaV/Objectives/paradox_anomaly.yml @@ -1,9 +1,9 @@ - type: entity abstract: true - parent: BaseTerminatorObjective # mrp terminator real id: BaseParadoxAnomalyObjective components: - type: Objective + difficulty: 1 issuer: self # not using base kill/keep alive objectives since these intentionally conflict with eachother @@ -19,7 +19,6 @@ state: icon - type: TargetObjective title: objective-paradox-anomaly-kill-title - - type: TerminatorTargetOverride - type: KillPersonCondition requireDead: true @@ -35,7 +34,6 @@ state: folder-white - type: TargetObjective title: objective-paradox-anomaly-friend-title - - type: TerminatorTargetOverride - type: KeepAliveCondition - type: entity diff --git a/Resources/Prototypes/DeltaV/Recipes/Construction/clothing.yml b/Resources/Prototypes/DeltaV/Recipes/Construction/clothing.yml index 386a0211c03..601bcd540b9 100644 --- a/Resources/Prototypes/DeltaV/Recipes/Construction/clothing.yml +++ b/Resources/Prototypes/DeltaV/Recipes/Construction/clothing.yml @@ -1,9 +1,9 @@ - type: construction name: prescription medhud - id: ClothingEyesPrescriptionMedHud + id: PrescriptionMedHud graph: PrescriptionMedHud startNode: start - targetNode: prescmedhud + targetNode: prescmedhud category: construction-category-clothing description: Prescription medhud, merged glasses and medhud together by sheer luck and cables with glue. icon: { sprite: DeltaV/Clothing/Eyes/Hud/prescmedhud.rsi, state: icon } @@ -11,10 +11,10 @@ - type: construction name: prescription sechud - id: ClothingEyesPrescriptionHudSecurity + id: PrescriptionHudSecurity graph: PrescriptionSecHud startNode: start - targetNode: prescsechud + targetNode: prescsechud category: construction-category-clothing description: Prescription sechud, merged glasses and sechud together by sheer luck and cables with glue. icon: { sprite: DeltaV/Clothing/Eyes/Hud/prescsechud.rsi, state: icon } diff --git a/Resources/Prototypes/DeltaV/Voice/speech_emotes.yml b/Resources/Prototypes/DeltaV/Voice/speech_emotes.yml index 29f75d0d509..7f3eb0313ac 100644 --- a/Resources/Prototypes/DeltaV/Voice/speech_emotes.yml +++ b/Resources/Prototypes/DeltaV/Voice/speech_emotes.yml @@ -1,5 +1,6 @@ - type: emote id: HarpyRing + name: chat-emote-name-harpyring category: Vocal chatMessages: [ rings ] chatTriggers: @@ -7,6 +8,7 @@ - type: emote id: HarpyPew + name: chat-emote-name-harpypew category: Vocal chatMessages: [ pews ] chatTriggers: @@ -15,6 +17,7 @@ - type: emote id: HarpyBang + name: chat-emote-name-harpybang category: Vocal chatMessages: [ bangs ] chatTriggers: @@ -22,6 +25,7 @@ - type: emote id: HarpyRev + name: chat-emote-name-harpyrev category: Vocal chatMessages: [ revs ] chatTriggers: @@ -29,6 +33,7 @@ - type: emote id: HarpyCaw + name: chat-emote-name-harpycaw category: Vocal chatMessages: [ caws ] chatTriggers: @@ -37,6 +42,7 @@ #Vulpkanin - type: emote id: Bark + name: chat-emote-name-vulpbark category: Vocal chatMessages: [ barks ] chatTriggers: @@ -44,6 +50,7 @@ - type: emote id: Snarl + name: chat-emote-name-vulpsnarl category: Vocal chatMessages: [ snarls ] chatTriggers: @@ -51,6 +58,7 @@ - type: emote id: Whine + name: chat-emote-name-vulpwhine category: Vocal chatMessages: [ whines ] chatTriggers: @@ -58,6 +66,7 @@ - type: emote id: Howl + name: chat-emote-name-vulphowl category: Vocal chatMessages: [ howls ] chatTriggers: diff --git a/Resources/Prototypes/Device/devicenet_frequencies.yml b/Resources/Prototypes/Device/devicenet_frequencies.yml index db48d117e0b..ecdbb3bb4c2 100644 --- a/Resources/Prototypes/Device/devicenet_frequencies.yml +++ b/Resources/Prototypes/Device/devicenet_frequencies.yml @@ -75,6 +75,17 @@ name: device-frequency-prototype-name-crew-monitor frequency: 1261 +# Cyborgs broadcast to consoles on this frequency +- type: deviceFrequency + id: RoboticsConsole + name: device-frequency-prototype-name-robotics-console + frequency: 1291 + +# Console sends commands to cyborgs on this frequency +- type: deviceFrequency + id: CyborgControl + name: device-frequency-prototype-name-cyborg-control + frequency: 1292 # This frequency will likely have a LARGE number of listening entities. Please don't broadcast on this frequency. - type: deviceFrequency diff --git a/Resources/Prototypes/DeviceLinking/source_ports.yml b/Resources/Prototypes/DeviceLinking/source_ports.yml index 18b9b831e6b..1988f29e45c 100644 --- a/Resources/Prototypes/DeviceLinking/source_ports.yml +++ b/Resources/Prototypes/DeviceLinking/source_ports.yml @@ -45,6 +45,11 @@ description: signal-port-description-doorstatus defaultLinks: [ DoorBolt ] +- type: sourcePort + id: DockStatus + name: signal-port-name-dockstatus + description: signal-port-description-dockstatus + - type: sourcePort id: OrderSender name: signal-port-name-order-sender diff --git a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml index 6cf94fd1ed3..4af443113a7 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/backpacks.yml @@ -23,8 +23,8 @@ ents: [] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface # to prevent bag open/honk spam - type: UseDelay delay: 0.5 diff --git a/Resources/Prototypes/Entities/Clothing/Back/specific.yml b/Resources/Prototypes/Entities/Clothing/Back/specific.yml index 8af00039b5d..fcdecffc8f1 100644 --- a/Resources/Prototypes/Entities/Clothing/Back/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Back/specific.yml @@ -14,9 +14,9 @@ default: ClothingBackpack - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key + enum.StorageUiKey.Key: type: StorageBoundUserInterface - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface - type: entity @@ -51,8 +51,8 @@ canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: DrawableSolution solution: tank - type: RefillableSolution diff --git a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml index 62889d0aba2..1d26d71660c 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/base_clothingbelt.yml @@ -45,8 +45,8 @@ ents: [] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml index 359165cfc50..80d5cf5a15b 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/belts.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/belts.yml @@ -31,6 +31,7 @@ - AppraisalTool - JawsOfLife - GPS + - WeldingMask components: - SprayPainter - NetworkConfigurator @@ -473,12 +474,19 @@ - MagazinePistol - MagazineMagnum - CombatKnife + - Truncheon components: - Stunbaton - FlashOnTrigger - SmokeOnTrigger - Flash - Handcuff + - BallisticAmmoProvider + - CartridgeAmmo + - DoorRemote + - Whistle + - HolosignProjector + - BalloonPopper - type: ItemMapper mapLayers: flashbang: @@ -600,7 +608,7 @@ - CartridgeAmmo - type: entity - parent: ClothingBeltStorageBase + parent: ClothingBeltSecurity id: ClothingBeltSecurityWebbing name: security webbing description: Unique and versatile chest rig, can hold security gear. @@ -623,11 +631,10 @@ - id: Stunbaton - id: Handcuffs - id: Handcuffs - - type: entity parent: ClothingBeltStorageBase id: ClothingBeltMercWebbing - name: mercenarie webbing + name: mercenary webbing description: Ideal for storing everything from ammo to weapons and combat essentials. components: - type: Sprite diff --git a/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml b/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml index 6cbf5a69cae..bb4e395c4fe 100644 --- a/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml +++ b/Resources/Prototypes/Entities/Clothing/Belt/quiver.yml @@ -18,7 +18,11 @@ whitelist: tags: - Arrow + - Plunger - type: Appearance - type: StorageContainerVisuals maxFillLevels: 3 fillBaseName: fill- + - type: Construction + graph: Quiver + node: Quiver diff --git a/Resources/Prototypes/Entities/Clothing/Ears/specific.yml b/Resources/Prototypes/Entities/Clothing/Ears/specific.yml index 093f5e645b6..83612ac4b2e 100644 --- a/Resources/Prototypes/Entities/Clothing/Ears/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Ears/specific.yml @@ -16,5 +16,5 @@ default: ClothingHeadsetGrey - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index 0f6c4acfcb5..9e47a685f0b 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -82,7 +82,6 @@ tags: - HamsterWearable - WhitelistChameleon - - GlassesNearsight # SimpleStation14 NearsightedTrait - type: entity parent: ClothingEyesBase @@ -156,7 +155,7 @@ protectionTime: 5 - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesGlassesSecurity name: security glasses description: Upgraded sunglasses that provide flash immunity and a security HUD. @@ -176,7 +175,6 @@ - type: GuideHelp guides: - Security - - type: ShowSecurityIcons - type: IdentityBlocker coverage: EYES diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml index fabb7bc6429..835c405e192 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/hud.yml @@ -1,3 +1,13 @@ +- type: entity + id: ShowSecurityIcons + abstract: true + noSpawn: true + components: + - type: ShowJobIcons + - type: ShowMindShieldIcons + - type: ShowCriminalRecordIcons + + - type: entity parent: ClothingEyesBase id: ClothingEyesHudDiagnostic @@ -17,7 +27,7 @@ parent: ClothingEyesBase id: ClothingEyesHudMedical name: medical hud - description: A heads-up display that scans the humanoids in view and provides accurate data about their health status. + description: A heads-up display that scans the humanoids in view and provides accurate data about their health status. components: - type: Sprite sprite: Clothing/Eyes/Hud/med.rsi @@ -34,7 +44,7 @@ - HudMedical - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesHudSecurity name: security hud description: A heads-up display that scans the humanoids in view and provides accurate data about their ID status and security records. @@ -43,7 +53,6 @@ sprite: Clothing/Eyes/Hud/sec.rsi - type: Clothing sprite: Clothing/Eyes/Hud/sec.rsi - - type: ShowSecurityIcons - type: Tag tags: - HudSecurity @@ -138,7 +147,7 @@ - type: ShowThirstIcons - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesHudMedSec name: medsec hud description: An eye display that looks like a mixture of medical and security huds. @@ -150,13 +159,15 @@ - type: Construction graph: HudMedSec node: medsecHud - - type: ShowSecurityIcons - type: ShowHealthBars damageContainers: - Biological + - type: ShowHealthIcons + damageContainers: + - Biological - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesHudMultiversal name: multiversal hud description: Filler @@ -165,7 +176,6 @@ sprite: Clothing/Eyes/Hud/medsecengi.rsi - type: Clothing sprite: Clothing/Eyes/Hud/medsecengi.rsi - - type: ShowSecurityIcons - type: ShowHealthBars damageContainers: - Biological @@ -176,7 +186,7 @@ - type: ShowSyndicateIcons - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesHudOmni name: omni hud description: Filler @@ -185,7 +195,6 @@ sprite: Clothing/Eyes/Hud/omni.rsi - type: Clothing sprite: Clothing/Eyes/Hud/omni.rsi - - type: ShowSecurityIcons - type: ShowHealthBars damageContainers: - Biological @@ -198,7 +207,7 @@ - type: ShowSyndicateIcons - type: entity - parent: ClothingEyesBase + parent: [ClothingEyesBase, ShowSecurityIcons] id: ClothingEyesHudSyndicate name: syndicate visor description: The syndicate's professional head-up display, designed for better detection of humanoids and their subsequent elimination. @@ -208,14 +217,26 @@ - type: Clothing sprite: Clothing/Eyes/Hud/synd.rsi - type: ShowSyndicateIcons - - type: ShowSecurityIcons - type: entity - parent: ClothingEyesGlassesSunglasses + parent: [ClothingEyesBase, ShowSecurityIcons] + id: ClothingEyesHudSyndicateAgent + name: syndicate agent visor + description: The Syndicate Agent's professional heads-up display, designed for quick diagnosis of their team's status. + components: + - type: Sprite + sprite: Clothing/Eyes/Hud/syndagent.rsi + - type: Clothing + sprite: Clothing/Eyes/Hud/syndagent.rsi + - type: ShowSyndicateIcons + - type: ShowHealthBars + damageContainers: + - Biological + +- type: entity + parent: [ClothingEyesGlassesSunglasses, ShowSecurityIcons] id: ClothingEyesGlassesHiddenSecurity suffix: Syndicate - components: - - type: ShowSecurityIcons - type: entity parent: ClothingEyesHudMedical diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/specific.yml b/Resources/Prototypes/Entities/Clothing/Eyes/specific.yml index c04f3482870..fa87ed398ed 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/specific.yml @@ -16,6 +16,6 @@ default: ClothingEyesGlassesSunglasses - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml index c82e4f4c60d..01d9e72fef1 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/gloves.yml @@ -20,6 +20,7 @@ soundHit: collection: BoxingHit animation: WeaponArcFist + mustBeEquippedToUse: true - type: Fiber fiberMaterial: fibers-leather fiberColor: fibers-red @@ -90,6 +91,7 @@ types: Blunt: 8 bluntStaminaDamageFactor: 0.0 # so blunt doesn't deal stamina damage at all + mustBeEquippedToUse: true - type: entity parent: ClothingHandsBase @@ -239,6 +241,12 @@ name: combat gloves description: These tactical gloves are fireproof and shock resistant. components: + - type: Sprite + sprite: Clothing/Hands/Gloves/combat.rsi + - type: Clothing + sprite: Clothing/Hands/Gloves/combat.rsi + - type: GloveHeatResistance + heatResistance: 1400 - type: Insulated - type: Fiber fiberMaterial: fibers-insulative @@ -363,6 +371,7 @@ soundHit: collection: Punch animation: WeaponArcFist + mustBeEquippedToUse: true - type: Fiber fiberMaterial: fibers-leather fiberColor: fibers-blue @@ -370,12 +379,11 @@ - type: MeleeSpeech - type: ActivatableUI key: enum.MeleeSpeechUiKey.Key - closeOnHandDeselect: false - rightClickOnly: true + verbOnly: true - type: Actions - type: UserInterface interfaces: - - key: enum.MeleeSpeechUiKey.Key + enum.MeleeSpeechUiKey.Key: type: MeleeSpeechBoundUserInterface - type: StaticPrice price: 0 diff --git a/Resources/Prototypes/Entities/Clothing/Hands/specific.yml b/Resources/Prototypes/Entities/Clothing/Hands/specific.yml index db34297b42a..b35c3b8b509 100644 --- a/Resources/Prototypes/Entities/Clothing/Hands/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Hands/specific.yml @@ -19,9 +19,9 @@ - type: FingerprintMask - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface - + - type: entity parent: ClothingHandsChameleon id: ClothingHandsChameleonThief diff --git a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml index d13b284ff29..e19217686f4 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/base_clothinghead.yml @@ -133,11 +133,13 @@ unequipSound: /Audio/Mecha/mechmove03.ogg - type: Tag tags: - - HidesHair - WhitelistChameleon - HelmetEVA - - HidesNose - type: IdentityBlocker + - type: HideLayerClothing + slots: + - Hair + - Snout - type: entity abstract: true @@ -161,6 +163,8 @@ lowPressureMultiplier: 1000 - type: TemperatureProtection coefficient: 0.1 + - type: FireProtection + reduction: 0.2 - type: Armor modifiers: coefficients: @@ -173,10 +177,12 @@ - type: IngestionBlocker - type: Tag tags: - - HidesHair - WhitelistChameleon - - HidesNose - type: IdentityBlocker + - type: HideLayerClothing + slots: + - Hair + - Snout - type: entity abstract: true @@ -248,6 +254,6 @@ - type: TemperatureProtection coefficient: 0.7 - type: GroupExamine - - type: Tag - tags: - - HidesHair + - type: HideLayerClothing + slots: + - Hair diff --git a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml index 6985fe7ec39..b563fbc0071 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hardsuit-helmets.yml @@ -17,9 +17,9 @@ sprite: Clothing/Head/Hardsuits/basic.rsi - type: Clothing sprite: Clothing/Head/Hardsuits/basic.rsi - - type: Tag - tags: - - HidesNose + - type: HideLayerClothing + slots: + - Snout #Atmospherics Hardsuit - type: entity @@ -436,6 +436,8 @@ lowPressureMultiplier: 1000 - type: TemperatureProtection coefficient: 0.005 + - type: FireProtection + reduction: 0.2 - type: Armor modifiers: coefficients: diff --git a/Resources/Prototypes/Entities/Clothing/Head/hats.yml b/Resources/Prototypes/Entities/Clothing/Head/hats.yml index 30907f70b5b..d59d62251cc 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hats.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hats.yml @@ -247,7 +247,7 @@ - 0,0,0,0 - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key + enum.StorageUiKey.Key: type: StorageBoundUserInterface - type: ContainerContainer containers: @@ -384,12 +384,15 @@ sprite: Clothing/Head/Hats/plaguedoctor.rsi - type: Tag tags: - - HidesHair - WhitelistChameleon - ClothMade + - type: HideLayerClothing + slots: + - Hair + - Snout - type: entity - parent: ClothingHeadBase + parent: ClothingHeadHatWizardBase id: ClothingHeadHatRedwizard name: red wizard hat description: Strange-looking red hat-wear that most certainly belongs to a real magic user. @@ -509,7 +512,7 @@ - type: entity - parent: ClothingHeadBase + parent: ClothingHeadHatWizardBase id: ClothingHeadHatVioletwizard name: violet wizard hat description: "Strange-looking violet hat-wear that most certainly belongs to a real magic user." @@ -543,15 +546,18 @@ name: witch hat description: A witch hat. components: + - type: WizardClothes #Yes this will count - type: Sprite sprite: Clothing/Head/Hats/witch.rsi - type: Clothing sprite: Clothing/Head/Hats/witch.rsi - type: Tag tags: - - HidesHair - WhitelistChameleon - ClothMade + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -565,7 +571,14 @@ sprite: Clothing/Head/Hats/wizard_fake.rsi - type: entity + abstract: true parent: ClothingHeadBase + id: ClothingHeadHatWizardBase + components: + - type: WizardClothes + +- type: entity + parent: ClothingHeadHatWizardBase id: ClothingHeadHatWizard name: wizard hat description: Strange-looking blue hat-wear that most certainly belongs to a powerful magic user. @@ -846,8 +859,8 @@ - 0,0,0,0 - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: ContainerContainer containers: storagebase: !type:Container diff --git a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml index b79b72ffb63..009c2ef784e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/helmets.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/helmets.yml @@ -110,6 +110,10 @@ Blunt: 0.95 Slash: 0.95 Piercing: 0.95 + - type: HideLayerClothing + slots: + - Hair + - Snout #Janitorial Bombsuit Helmet - type: entity @@ -157,10 +161,13 @@ sprite: Clothing/Head/Helmets/spaceninja.rsi - type: Tag tags: - - HidesHair - WhitelistChameleon - type: IngestionBlocker - type: IdentityBlocker + - type: HideLayerClothing + slots: + - Hair + - Snout #Templar Helmet - type: entity @@ -217,11 +224,16 @@ - type: IngestionBlocker - type: TemperatureProtection coefficient: 0.005 + - type: FireProtection + reduction: 0.15 # not fully sealed so less protection - type: IdentityBlocker - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair + - Snout #Atmos Fire Helmet - type: entity @@ -238,14 +250,19 @@ - type: IngestionBlocker - type: TemperatureProtection coefficient: 0.005 + - type: FireProtection + reduction: 0.2 - type: PressureProtection highPressureMultiplier: 0.25 lowPressureMultiplier: 1000 - type: IdentityBlocker - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair + - Snout #Chitinous Helmet - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml index 9ab528581af..0bca209d51e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/hoods.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/hoods.yml @@ -13,8 +13,11 @@ - type: IngestionBlocker - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair + - Snout - type: entity parent: ClothingHeadHatHoodBioGeneral @@ -94,9 +97,11 @@ sprite: Clothing/Head/Hoods/chaplain.rsi - type: Tag tags: - - HidesHair - HamsterWearable - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -110,8 +115,10 @@ sprite: Clothing/Head/Hoods/cult.rsi - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -125,9 +132,11 @@ sprite: Clothing/Head/Hoods/nun.rsi - type: Tag tags: - - HidesHair - HamsterWearable - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -145,9 +154,10 @@ Heat: 0.95 Radiation: 0.65 - type: BreathMask - - type: Tag - tags: - - HidesHair + - type: HideLayerClothing + slots: + - Hair + - Snout - type: entity parent: ClothingHeadBase @@ -161,8 +171,10 @@ sprite: Clothing/Head/Hoods/goliathcloak.rsi - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -175,9 +187,9 @@ sprite: Clothing/Head/Hoods/iansuit.rsi - type: Clothing sprite: Clothing/Head/Hoods/iansuit.rsi - - type: Tag - tags: - - HidesHair + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -190,9 +202,9 @@ sprite: Clothing/Head/Hoods/carpsuit.rsi - type: Clothing sprite: Clothing/Head/Hoods/carpsuit.rsi - - type: Tag - tags: - - HidesHair + - type: HideLayerClothing + slots: + - Hair - type: entity parent: ClothingHeadBase @@ -207,8 +219,11 @@ - type: IdentityBlocker - type: Tag tags: - - HidesHair - WhitelistChameleon + - type: HideLayerClothing + slots: + - Hair + - Snout #Winter Coat Hoods - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Head/specific.yml b/Resources/Prototypes/Entities/Clothing/Head/specific.yml index 1dd36bff949..636f922d857 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/specific.yml @@ -16,5 +16,5 @@ default: ClothingHeadHatBeret - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/Head/welding.yml b/Resources/Prototypes/Entities/Clothing/Head/welding.yml index 93d9b1e084f..c0ae440a56e 100644 --- a/Resources/Prototypes/Entities/Clothing/Head/welding.yml +++ b/Resources/Prototypes/Entities/Clothing/Head/welding.yml @@ -19,6 +19,10 @@ - type: Tag tags: - WhitelistChameleon + - WeldingMask + - type: HideLayerClothing + slots: + - Snout - type: entity parent: WeldingMaskBase @@ -34,6 +38,7 @@ tags: - HamsterWearable - WhitelistChameleon + - WeldingMask - type: entity parent: WeldingMaskBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml index 246b47b8003..f5ad2fb6c83 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/bandanas.yml @@ -25,7 +25,10 @@ - type: Tag tags: - Bandana - - HidesNose + - type: HideLayerClothing + slots: + - Snout + hideOnToggle: true - type: entity parent: ClothingMaskBandanaBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml index a20924e502e..c470605bb79 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/masks.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/masks.yml @@ -15,7 +15,10 @@ tags: - HamsterWearable - WhitelistChameleon - - HidesNose + - type: HideLayerClothing + slots: + - Snout + hideOnToggle: true - type: entity parent: ClothingMaskGas @@ -197,8 +200,10 @@ tags: - ClownMask - WhitelistChameleon - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskClownBase @@ -209,7 +214,9 @@ - ClownMask - HamsterWearable - WhitelistChameleon - - HidesNose + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskClown @@ -238,8 +245,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -257,8 +266,10 @@ tags: - HamsterWearable - WhitelistChameleon - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskPullableBase @@ -272,9 +283,12 @@ sprite: Clothing/Mask/sterile.rsi - type: IngestionBlocker - type: Item - storedRotation: -90 + size: Tiny - type: IdentityBlocker coverage: MOUTH + - type: PhysicalComposition + materialComposition: + Plastic: 25 - type: entity parent: ClothingMaskBase @@ -309,9 +323,10 @@ - type: BreathMask - type: IngestionBlocker - type: IdentityBlocker - - type: Tag - tags: - - HidesNose + - type: HideLayerClothing + slots: + - Snout + hideOnToggle: true - type: entity parent: ClothingMaskClownBase @@ -341,8 +356,11 @@ - type: Tag tags: - WhitelistChameleon - - HidesHair - - HidesNose + - type: HideLayerClothing + slots: + - Hair + - Snout + hideOnToggle: true - type: entity parent: ClothingMaskGasExplorer @@ -368,8 +386,11 @@ - type: Tag tags: - WhitelistChameleon - - HidesHair - - HidesNose + - type: HideLayerClothing + slots: + - Hair + - Snout + hideOnToggle: true - type: entity parent: ClothingMaskGasERT @@ -405,7 +426,9 @@ - IPCMaskWearable # Estacao Pirata - IPCs - HamsterWearable - WhitelistChameleon - - HidesNose + - type: HideLayerClothing + slots: + - Snout - type: IdentityBlocker - type: entity @@ -422,8 +445,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -439,8 +464,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -456,8 +483,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -473,8 +502,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -490,8 +521,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase @@ -507,8 +540,10 @@ - type: IdentityBlocker - type: Tag tags: - - HidesNose - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskBase diff --git a/Resources/Prototypes/Entities/Clothing/Masks/specific.yml b/Resources/Prototypes/Entities/Clothing/Masks/specific.yml index 3b71eb5603b..4dd9a829ee4 100644 --- a/Resources/Prototypes/Entities/Clothing/Masks/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Masks/specific.yml @@ -6,8 +6,7 @@ suffix: Chameleon components: - type: Tag - tags: # ignore "WhitelistChameleon" tag - - HidesNose + tags: [] # ignore "WhitelistChameleon" tag - type: Sprite sprite: Clothing/Mask/gas.rsi - type: Clothing @@ -19,8 +18,11 @@ - type: IdentityBlocker # need that for default ClothingMaskGas - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface + - type: HideLayerClothing + slots: + - Snout - type: entity parent: ClothingMaskGasChameleon @@ -28,7 +30,38 @@ suffix: Voice Mask, Chameleon components: - type: VoiceMasker - default: ClothingMaskGas - type: Tag tags: - - IPCMaskWearable # Estacao Pirata - IPCs + - IPCMaskWearable + - type: HideLayerClothing + slots: + - Snout + +- type: entity + parent: ClothingMaskBase + id: ClothingMaskWeldingGas + name: welding gas mask + description: A gas mask with built in welding goggles and face shield. Looks like a skull, clearly designed by a nerd. + components: + - type: Sprite + sprite: Clothing/Mask/welding-gas.rsi + state: icon + - type: Clothing + sprite: Clothing/Mask/welding-gas.rsi + - type: BreathMask + - type: IngestionBlocker + - type: IdentityBlocker + - type: FlashImmunity + - type: EyeProtection + - type: PhysicalComposition + materialComposition: + Steel: 200 + Glass: 100 + - type: StaticPrice + price: 100 + - type: Tag + tags: + - WhitelistChameleon + - type: HideLayerClothing + slots: + - Snout diff --git a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml index e76a4b3ee3b..e633c6c52d6 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/medals.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/medals.yml @@ -1,102 +1,126 @@ -- type: entity - parent: ClothingNeckBase - id: ClothingNeckMedalBase - abstract: true - name: medal - description: not given to anyone - components: - - type: Tag - tags: - - WhitelistChameleon - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckBronzeheart - name: bronzeheart medal - description: Given to crewmates for exemplary bravery in the face of danger. - components: - - type: Sprite - sprite: Clothing/Neck/Medals/bronzeheart.rsi - - type: Clothing - sprite: Clothing/Neck/Medals/bronzeheart.rsi - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckGoldmedal - name: gold medal of crewmanship - description: Given to crewmates who display excellent crewmanship. - components: - - type: Sprite - sprite: Clothing/Neck/Medals/gold.rsi - - type: Clothing - sprite: Clothing/Neck/Medals/gold.rsi - - type: StealTarget - stealGroup: ClothingNeckGoldmedal - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckCargomedal - name: logistics medal # DeltaV - Logistics Department replacing Cargo - description: Whether it's for superior accountancy, courageous salvage work, or just being a friendly technician - this medal is to be assigned only for the best work in the logistics department. # DeltaV - Logistics Department replacing Cargo. Updated description for flavour - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/cargomedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/cargomedal.rsi # DeltaV - resprite - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckEngineermedal - name: engineer medal - description: Whether it's by keeping the crew breathing, meticulous rewiring and upgrading, or just having plenty of materials on-hand - this medal is to be assigned only for the best work in the engineering department. # DeltaV - Updated description for flavour - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/engineermedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/engineermedal.rsi # DeltaV - resprite - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckMedicalmedal - name: medical medal - description: Whether it's being the first on the scene of an accident, the most caring bedside manner, or just making sure the patients don't go mad - this medal is to be assigned only for the best work in the medical department. # DeltaV - Updated description for flavour - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/medicalmedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/medicalmedal.rsi # DeltaV - resprite - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckSciencemedal - name: epistemics medal # DeltaV - Epistemics Department replacing Science - description: Whether it's pushing the edges of modern science and technology, foraying into the vast expanses of the noosphere, or just fetching the coffee - this medal is to be assigned only for the best work in the epistemics department. # DeltaV - Epistemics Department replacing Science. Updated description for flavour - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/sciencemedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/sciencemedal.rsi # DeltaV - resprite - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckSecuritymedal - name: security medal - description: Whether it's catching armed terrorists, guarding the crew from alien threats, or just having a conversation in the corridor - this medal is to be assigned only for the best work in the security department. # DeltaV - Updated description for flavour - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/securitymedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/securitymedal.rsi # DeltaV - resprite - -- type: entity - parent: ClothingNeckMedalBase - id: ClothingNeckClownmedal - name: bravado medal # DeltaV - Updated title so it's not just a joke medal. - description: Given to crewmates who laugh in the face of death, lift their peers' spirits, and uplift themselves and their friends to success. # DeltaV - Updated description for flavour and to reflect title. - components: - - type: Sprite - sprite: DeltaV/Clothing/Neck/Medals/clownmedal.rsi # DeltaV - resprite - - type: Clothing - sprite: DeltaV/Clothing/Neck/Medals/clownmedal.rsi # DeltaV - resprite - - type: StealTarget - stealGroup: ClothingNeckClownmedal +- type: entity + parent: ClothingNeckBase + id: ClothingNeckMedalBase + abstract: true + name: medal + description: not given to anyone + components: + - type: Tag + tags: + - WhitelistChameleon + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckBronzeheart + name: bronzeheart medal + description: Given to crewmates for exemplary bravery in the face of danger. + components: + - type: Sprite + sprite: Clothing/Neck/Medals/bronzeheart.rsi + - type: Clothing + sprite: Clothing/Neck/Medals/bronzeheart.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckGoldmedal + name: gold medal of crewmanship + description: Given to crewmates who display excellent crewmanship. + components: + - type: Sprite + sprite: Clothing/Neck/Medals/gold.rsi + - type: Clothing + sprite: Clothing/Neck/Medals/gold.rsi + - type: StealTarget + stealGroup: ClothingNeckGoldmedal + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckCargomedal + name: logistics medal # DeltaV - Logistics Department replacing Cargo + description: Whether it's for superior accountancy, courageous salvage work, or just being a friendly technician - this medal is to be assigned only for the best work in the logistics department. # DeltaV - Logistics Department replacing Cargo. Updated description for flavour + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/cargomedal.rsi # DeltaV - resprite + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/cargomedal.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckEngineermedal + name: engineer medal + description: Whether it's by keeping the crew breathing, meticulous rewiring and upgrading, or just having plenty of materials on-hand - this medal is to be assigned only for the best work in the engineering department. # DeltaV - Updated description for flavour + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/engineermedal.rsi # DeltaV - resprite + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/engineermedal.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckMedicalmedal + name: medical medal + description: Whether it's being the first on the scene of an accident, the most caring bedside manner, or just making sure the patients don't go mad - this medal is to be assigned only for the best work in the medical department. # DeltaV - Updated description for flavour + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/medicalmedal.rsi + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/medicalmedal.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckSciencemedal + name: epistemics medal # DeltaV - Epistemics Department replacing Science + description: Whether it's pushing the edges of modern science and technology, foraying into the vast expanses of the noosphere, or just fetching the coffee - this medal is to be assigned only for the best work in the epistemics department. # DeltaV - Epistemics Department replacing Science. Updated description for flavour + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/sciencemedal.rsi + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/sciencemedal.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckSecuritymedal + name: security medal + description: Whether it's catching armed terrorists, guarding the crew from alien threats, or just having a conversation in the corridor - this medal is to be assigned only for the best work in the security department. # DeltaV - Updated description for flavour + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/securitymedal.rsi + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/securitymedal.rsi + - type: Tag + tags: + - Medal + +- type: entity + parent: ClothingNeckMedalBase + id: ClothingNeckClownmedal + name: bravado medal # DeltaV - Updated title so it's not just a joke medal. + description: Given to crewmates who laugh in the face of death, lift their peers' spirits, and uplift themselves and their friends to success. # DeltaV - Updated description for flavour and to reflect title. + components: + - type: Sprite + sprite: DeltaV/Clothing/Neck/Medals/clownmedal.rsi # DeltaV - resprite + - type: Clothing + sprite: DeltaV/Clothing/Neck/Medals/clownmedal.rsi # DeltaV - resprite + - type: StealTarget + stealGroup: ClothingNeckClownmedal + - type: Tag + tags: + - Medal diff --git a/Resources/Prototypes/Entities/Clothing/Neck/specific.yml b/Resources/Prototypes/Entities/Clothing/Neck/specific.yml index 1f50dc1ef1c..56fddceaad6 100644 --- a/Resources/Prototypes/Entities/Clothing/Neck/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Neck/specific.yml @@ -16,5 +16,5 @@ default: ClothingNeckScarfStripedRed - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml index eb580d64996..46a431ddff2 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/armor.yml @@ -2,7 +2,7 @@ # NOTE: Half of the kind of armor you're probably thinking of is in vests.yml. These should probably be merged some day. - type: entity - parent: ClothingOuterBaseMedium + parent: [ClothingOuterBaseMedium, AllowSuitStorageClothing] id: ClothingOuterArmorBasic name: armor vest description: A standard Type I armored vest that provides decent protection against most types of damage. @@ -35,7 +35,7 @@ sprite: Clothing/OuterClothing/Armor/security_slim.rsi - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterArmorRiot name: riot suit description: A suit of semi-flexible polycarbonate body armor with heavy padding to protect against melee attacks. Perfect for fighting delinquents around the station. @@ -95,6 +95,7 @@ Heat: 0.4 # this technically means it protects against fires pretty well? -heat is just for lasers and stuff, not atmos temperature - type: Reflect reflectProb: 1 + innate: true # armor grants a passive shield that does not require concentration to maintain reflects: - Energy @@ -118,7 +119,7 @@ - type: GroupExamine - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterArmorHeavy name: heavy armor suit description: A heavily armored suit that protects against excessive damage. @@ -137,6 +138,8 @@ Radiation: 0 Caustic: 0.75 - type: GroupExamine + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -186,7 +189,7 @@ sprite: Clothing/OuterClothing/Armor/magusred.rsi - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterArmorCaptainCarapace name: "captain's carapace" description: "An armored chestpiece that provides protection whilst still offering maximum mobility and flexibility. Issued only to the station's finest." @@ -236,6 +239,8 @@ - type: ExplosionResistance damageCoefficient: 0.5 - type: GroupExamine + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -265,6 +270,8 @@ - type: Construction graph: BoneArmor node: armor + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: entity parent: ClothingOuterBaseLarge @@ -284,3 +291,5 @@ Piercing: 0.6 Heat: 0.5 - type: GroupExamine + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml index 358f91d2971..c18e5d6ab60 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/base_clothingouter.yml @@ -41,8 +41,8 @@ ents: [] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: StaticPrice price: 70 @@ -104,7 +104,7 @@ - type: entity abstract: true - parent: [ClothingOuterBase, GeigerCounterClothing] + parent: [ClothingOuterBase, GeigerCounterClothing, AllowSuitStorageClothing] id: ClothingOuterHardsuitBase name: base hardsuit components: @@ -112,7 +112,9 @@ highPressureMultiplier: 0.3 lowPressureMultiplier: 1000 - type: TemperatureProtection - coefficient: 0.001 # yes it needs to be this low, fires are fucking deadly apparently!!!! + coefficient: 0.01 + - type: FireProtection + reduction: 0.75 # almost perfectly sealed, atmos firesuit is better - type: ClothingSpeedModifier walkModifier: 0.4 sprintModifier: 0.6 @@ -147,10 +149,12 @@ localSoundOnly: true - type: StaminaDamageResistance coefficient: 0.75 # 25% + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: entity abstract: true - parent: ClothingOuterBase + parent: [ClothingOuterBase, AllowSuitStorageClothing] id: ClothingOuterEVASuitBase name: base EVA Suit components: @@ -171,6 +175,8 @@ - type: Clothing equipDelay: 1.25 # Softsuits are easier to put on and off unequipDelay: 1 + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: entity parent: ClothingOuterBase @@ -193,4 +199,4 @@ id: ClothingOuterBaseMedium components: - type: Item - size: Huge + size: Huge \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml index a47a2bbcebc..dc5454d597b 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/coats.yml @@ -10,7 +10,7 @@ sprite: Clothing/OuterClothing/Coats/bomber.rsi - type: entity - parent: ClothingOuterStorageBase + parent: [ClothingOuterStorageBase, AllowSuitStorageClothing] id: ClothingOuterCoatDetective name: detective trenchcoat description: A rugged canvas trenchcoat, designed and created by TX Fabrication Corp. Wearing it makes you feel for the plight of the Tibetans. @@ -31,6 +31,15 @@ Piercing: 0.70 Heat: 0.80 +- type: entity + parent: ClothingOuterCoatDetective + id: ClothingOuterCoatDetectiveLoadout + components: + - type: StorageFill + contents: + - id: SmokingPipeFilledTobacco + - id: FlippoLighter #Not the steal objective, only difference from normal detective trenchcoat + - type: entity parent: ClothingOuterStorageBase id: ClothingOuterCoatGentle @@ -43,7 +52,38 @@ sprite: Clothing/OuterClothing/Coats/gentlecoat.rsi - type: entity - parent: ClothingOuterStorageBase + abstract: true + parent: AllowSuitStorageClothing + id: ClothingOuterArmorHoS + components: + - type: Armor + modifiers: + coefficients: + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 + Caustic: 0.75 # not the full 90% from ss13 because of the head + - type: ExplosionResistance + damageCoefficient: 0.9 + +- type: entity + abstract: true + parent: AllowSuitStorageClothing + id: ClothingOuterArmorWarden + components: + - type: Armor + modifiers: + coefficients: + Blunt: 0.7 + Slash: 0.7 + Piercing: 0.7 + Heat: 0.7 + - type: ExplosionResistance + damageCoefficient: 0.9 + +- type: entity + parent: [ClothingOuterArmorHoS, ClothingOuterStorageBase] id: ClothingOuterCoatHoSTrench name: head of security's armored trenchcoat description: A greatcoat enhanced with a special alloy for some extra protection and style for those with a commanding presence. @@ -52,16 +92,6 @@ sprite: DeltaV/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi # DeltaV - resprite - type: Clothing sprite: DeltaV/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi # DeltaV - resprite - - type: Armor - modifiers: - coefficients: - Blunt: 0.70 - Slash: 0.70 - Piercing: 0.70 - Heat: 0.70 - Caustic: 0.75 #not the full 90% from ss13 because of the head - - type: ExplosionResistance - damageCoefficient: 0.90 - type: entity parent: ClothingOuterStorageBase @@ -197,7 +227,7 @@ parent: ClothingOuterStorageFoldableBase id: ClothingOuterCoatLabCmo name: chief medical officer's lab coat - description: Bluer than the standard model. + description: Custom made blue lab coat for the Chief Medical Officer, offers improved protection against chemical spills and minor cuts components: - type: Sprite sprite: Clothing/OuterClothing/Coats/labcoat_cmo.rsi @@ -206,7 +236,9 @@ - type: Armor modifiers: coefficients: - Caustic: 0.75 + Slash: 0.95 + Heat: 0.95 + Caustic: 0.65 - type: entity parent: [ClothingOuterStorageFoldableBaseOpened, ClothingOuterCoatLabCmo] @@ -286,7 +318,7 @@ sprite: Clothing/OuterClothing/Coats/pirate.rsi - type: entity - parent: ClothingOuterStorageBase + parent: [ClothingOuterArmorWarden, ClothingOuterStorageBase] id: ClothingOuterCoatWarden name: warden's armored jacket description: A sturdy, utilitarian jacket designed to protect a warden from any brig-bound threats. @@ -295,15 +327,6 @@ sprite: Clothing/OuterClothing/Coats/warden.rsi - type: Clothing sprite: Clothing/OuterClothing/Coats/warden.rsi - - type: Armor - modifiers: - coefficients: - Blunt: 0.70 - Slash: 0.70 - Piercing: 0.70 - Heat: 0.70 - - type: ExplosionResistance - damageCoefficient: 0.90 - type: entity parent: ClothingOuterStorageBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml index 6a0f445fc94..bb4aedcb5d7 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/hardsuits.yml @@ -52,9 +52,8 @@ Blunt: 0.9 Slash: 0.9 Piercing: 0.9 - Heat: 0.2 + Heat: 0.8 Radiation: 0.5 - Caustic: 0.5 - type: ClothingSpeedModifier walkModifier: 0.7 sprintModifier: 0.7 @@ -76,8 +75,6 @@ - type: PressureProtection highPressureMultiplier: 0.04 lowPressureMultiplier: 1000 - - type: TemperatureProtection - coefficient: 0.01 - type: ExplosionResistance damageCoefficient: 0.5 - type: Armor @@ -415,7 +412,7 @@ parent: ClothingOuterHardsuitBase id: ClothingOuterHardsuitRd name: experimental research hardsuit - description: A special suit that protects against hazardous, low pressure environments. Has an additional layer of armor. Able to be compressed to small sizes. + description: A special suit that protects against hazardous, low pressure environments. Has an additional layer of armor. components: - type: Sprite sprite: Clothing/OuterClothing/Hardsuits/rd.rsi @@ -440,7 +437,9 @@ sprintModifier: 0.75 - type: HeldSpeedModifier - type: Item - size: Normal + size: Huge + shape: + - 0,0,4,4 #5X5, can fit in a duffel bag but nothing smaller. - type: Tag tags: - WhitelistChameleon @@ -600,6 +599,8 @@ coefficient: 0.001 - type: ExplosionResistance damageCoefficient: 0.2 + - type: FireProtection + reduction: 0.8 # perfect protection like atmos firesuit for pyro tf2 ops - type: Armor modifiers: coefficients: diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml index 4b2c3c9c3ff..0b5e2c112b1 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/misc.yml @@ -166,9 +166,16 @@ - type: Clothing sprite: Clothing/OuterClothing/Misc/santa.rsi +- type: entity + abstract: true + parent: ClothingOuterBase + id: ClothingOuterWizardBase + components: + - type: WizardClothes + # Is this wizard wearing a fanny pack??? - type: entity - parent: ClothingOuterEVASuitBase # DeltaV - Make real wizard clothes space proof + parent: ClothingOuterWizardBase id: ClothingOuterWizardViolet name: violet wizard robes description: A bizarre gem-encrusted violet robe that radiates magical energies. @@ -179,7 +186,7 @@ sprite: Clothing/OuterClothing/Misc/violetwizard.rsi - type: entity - parent: ClothingOuterEVASuitBase # DeltaV - Make real wizard clothes space proof + parent: ClothingOuterWizardBase id: ClothingOuterWizard name: wizard robes description: A bizarre gem-encrusted blue robe that radiates magical energies. @@ -190,7 +197,7 @@ sprite: Clothing/OuterClothing/Misc/wizard.rsi - type: entity - parent: ClothingOuterEVASuitBase # DeltaV - Make real wizard clothes space proof + parent: ClothingOuterWizardBase id: ClothingOuterWizardRed name: red wizard robes description: Strange-looking, red, hat-wear that most certainly belongs to a real magic user. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/specific.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/specific.yml index 9be8c22a0a2..c3d9bb12242 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/specific.yml @@ -16,5 +16,5 @@ default: ClothingOuterVest - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml index 9f0a01cc481..6215fb3b45a 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/suits.yml @@ -27,6 +27,8 @@ - WhitelistChameleon - FullBodyOuter - HidesHarpyWings + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: entity parent: ClothingOuterSuitBomb @@ -52,7 +54,7 @@ - FullBodyOuter - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterSuitFire name: fire suit description: A suit that helps protect against hazardous temperatures. @@ -65,24 +67,28 @@ highPressureMultiplier: 0.04 - type: TemperatureProtection coefficient: 0.005 + - type: FireProtection + reduction: 0.65 # doesnt have a full seal so not as good - type: Armor modifiers: coefficients: Slash: 0.9 - Heat: 0.3 - Cold: 0.2 + Heat: 0.8 + Cold: 0.8 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.7 - type: HeldSpeedModifier - type: GroupExamine + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - WhitelistChameleon - HidesHarpyWings - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterSuitAtmosFire name: atmos fire suit description: An expensive firesuit that protects against even the most deadly of station fires. Designed to protect even if the wearer is set aflame. @@ -96,17 +102,21 @@ lowPressureMultiplier: 1000 - type: TemperatureProtection coefficient: 0.001 + - type: FireProtection + reduction: 0.8 # atmos firesuit offers best protection, hardsuits are a little vulnerable - type: Armor modifiers: coefficients: Slash: 0.9 - Heat: 0.3 - Cold: 0.2 + Heat: 0.8 + Cold: 0.8 - type: ClothingSpeedModifier walkModifier: 0.8 sprintModifier: 0.8 - type: HeldSpeedModifier - type: GroupExamine + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -114,7 +124,7 @@ - HidesHarpyWings - type: entity - parent: [ClothingOuterBaseLarge, GeigerCounterClothing] + parent: [ClothingOuterBaseLarge, GeigerCounterClothing, AllowSuitStorageClothing] id: ClothingOuterSuitRad name: radiation suit description: "A suit that protects against radiation. The label reads, 'Made with lead. Please do not consume insulation.'" @@ -135,6 +145,8 @@ - type: ContainerContainer containers: toggleable-clothing: !type:ContainerSlot {} + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -142,7 +154,7 @@ - HidesHarpyWings - type: entity - parent: ClothingOuterBaseLarge + parent: [ClothingOuterBaseLarge, AllowSuitStorageClothing] id: ClothingOuterSuitSpaceNinja name: space ninja suit description: This black technologically advanced, cybernetically-enhanced suit provides many abilities like invisibility or teleportation. @@ -191,6 +203,8 @@ sprite: Clothing/OuterClothing/Suits/chicken.rsi - type: Clothing sprite: Clothing/OuterClothing/Suits/chicken.rsi + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -219,6 +233,8 @@ - type: ContainerContainer containers: toggleable-clothing: !type:ContainerSlot {} + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: Tag tags: - FullBodyOuter @@ -243,6 +259,8 @@ - type: Construction graph: ClothingOuterSuitIan node: suit + - type: ClothingRequiredStepTriggerImmune + slots: WITHOUT_POCKET - type: entity parent: ClothingOuterBase diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml index 784084652c1..7dc06ff7dbe 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/vests.yml @@ -1,6 +1,6 @@ #Web vest - type: entity - parent: ClothingOuterStorageBase + parent: [ClothingOuterStorageBase, AllowSuitStorageClothing] id: ClothingOuterVestWeb name: web vest description: A synthetic armor vest. This one has added webbing and ballistic plates. @@ -21,7 +21,7 @@ #Mercenary web vest - type: entity - parent: ClothingOuterStorageBase #web vest so it should have some pockets for ammo + parent: ClothingOuterVestWeb #web vest so it should have some pockets for ammo id: ClothingOuterVestWebMerc name: merc web vest description: A high-quality armored vest made from a hard synthetic material. It's surprisingly flexible and light, despite formidable armor plating. diff --git a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml index 160c606cc41..73dc6c8c7f7 100644 --- a/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml +++ b/Resources/Prototypes/Entities/Clothing/OuterClothing/wintercoats.yml @@ -231,9 +231,23 @@ clothingPrototype: ClothingHeadHatHoodWinterHOP - type: entity - parent: ClothingOuterWinterCoatToggleable + parent: [ClothingOuterArmorHoS, ClothingOuterWinterCoatToggleable] id: ClothingOuterWinterHoS + name: head of security's armored winter coat + description: A sturdy, utilitarian winter coat designed to protect a head of security from any brig-bound threats and hypothermic events. + components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/coathosarmored.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/coathosarmored.rsi + - type: ToggleableClothing + clothingPrototype: ClothingHeadHatHoodWinterHOS + +- type: entity + parent: ClothingOuterWinterCoatToggleable + id: ClothingOuterWinterHoSUnarmored name: head of security's winter coat + description: A sturdy coat, a warm coat, but not an armored coat. components: - type: Sprite sprite: Clothing/OuterClothing/WinterCoats/coathos.rsi @@ -446,22 +460,28 @@ clothingPrototype: ClothingHeadHatHoodWinterSci - type: entity - parent: ClothingOuterWinterCoatToggleable + parent: [ClothingOuterArmorWarden, ClothingOuterWinterCoatToggleable] id: ClothingOuterWinterWarden name: warden's armored winter coat description: A sturdy, utilitarian winter coat designed to protect a warden from any brig-bound threats and hypothermic events. components: + - type: Sprite + sprite: Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi + - type: Clothing + sprite: Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi + - type: ToggleableClothing + clothingPrototype: ClothingHeadHatHoodWinterWarden + +- type: entity + parent: ClothingOuterWinterCoatToggleable + id: ClothingOuterWinterWardenUnarmored + name: warden's winter coat + description: A sturdy coat, a warm coat, but not an armored coat. + components: - type: Sprite sprite: Clothing/OuterClothing/WinterCoats/coatwarden.rsi - type: Clothing sprite: Clothing/OuterClothing/WinterCoats/coatwarden.rsi - - type: Armor - modifiers: - coefficients: - Blunt: 0.70 - Slash: 0.70 - Piercing: 0.8 #slightly less bulletproof then warden's normal coat - Heat: 0.70 - type: ToggleableClothing clothingPrototype: ClothingHeadHatHoodWinterWarden diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml index 1119d5cda74..a0f56966bb5 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/base_clothingshoes.yml @@ -23,6 +23,7 @@ tags: - ClothMade - WhitelistChameleon + - type: ClothingRequiredStepTriggerImmune - type: entity abstract: true diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml index 9381b3f2086..c4bdefd3a14 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/magboots.yml @@ -114,7 +114,7 @@ key: enum.SharedGasTankUiKey.Key - type: UserInterface interfaces: - - key: enum.SharedGasTankUiKey.Key + enum.SharedGasTankUiKey.Key: type: GasTankBoundUserInterface - type: Explosive explosionType: Default diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml index d1f6e083f40..d5a695c7c0b 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/misc.yml @@ -47,6 +47,8 @@ collection: FootstepDuck params: variation: 0.07 + - type: WaddleWhenWorn + tumbleIntensity: 10 # smaller than clown shoes - type: Construction graph: ClothingShoeSlippersDuck node: shoes diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml index 987eda582e4..4ae752345a7 100644 --- a/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Shoes/specific.yml @@ -185,7 +185,7 @@ default: ClothingShoesColorBlack - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface - type: entity diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml index cbbf78b9a17..18266dc4988 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpskirts.yml @@ -48,7 +48,7 @@ parent: ClothingUniformSkirtBase id: ClothingUniformJumpskirtChiefEngineer name: chief engineer's jumpskirt - description: It's a high visibility jumpskirt given to those engineers insane enough to achieve the rank of Chief Engineer. It has minor radiation shielding. + description: It's a high visibility jumpskirt given to those engineers insane enough to achieve the rank of Chief Engineer. components: - type: Sprite sprite: Clothing/Uniforms/Jumpskirt/ce.rsi @@ -180,7 +180,7 @@ parent: ClothingUniformSkirtBase id: ClothingUniformJumpskirtHoS name: head of security's jumpskirt - description: A standard Station Security uniform, adorned with gold emblems and commander's epaulettes. # DeltaV - improved description + description: A standard Station Security uniform, adorned with gold emblems and commander's epaulettes. components: - type: Sprite sprite: DeltaV/Clothing/Uniforms/Jumpskirt/hos.rsi # DeltaV - resprite @@ -191,7 +191,7 @@ parent: ClothingUniformSkirtBase id: ClothingUniformJumpskirtHoSAlt name: head of security's turtleneck - description: It's a turtleneck worn by those strong and disciplined enough to achieve the position of Head of Security. Its sturdy fabric provides minor protection from slash and pierce damage. + description: It's a turtleneck worn by those strong and disciplined enough to achieve the position of Head of Security. components: - type: Sprite sprite: Clothing/Uniforms/Jumpskirt/hos_alt.rsi @@ -365,7 +365,7 @@ parent: ClothingUniformSkirtBase id: ClothingUniformJumpskirtScientist name: scientist jumpskirt - description: It's made of a special fiber that provides minor protection against explosives. It has markings that denote the wearer as a scientist. + description: It's made of a special fiber that increases perceived intelligence and decreases personal ethics. It has markings that denote the wearer as a scientist. components: - type: Sprite sprite: Clothing/Uniforms/Jumpskirt/scientist.rsi @@ -828,3 +828,14 @@ - state: equipped-INNERCLOTHING-jumpskirt - state: equipped-INNERCLOTHING-shirt color: "#b30000" + +- type: entity + parent: ClothingUniformSkirtBase + id: ClothingUniformJumpskirtOldDress + name: old dress + description: A worn-looking dress from a very long time ago. + components: + - type: Sprite + sprite: Clothing/Uniforms/Jumpskirt/olddress.rsi + - type: Clothing + sprite: Clothing/Uniforms/Jumpskirt/olddress.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml index 565cc987b19..9da39893c37 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/jumpsuits.yml @@ -83,7 +83,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitChiefEngineer name: chief engineer's jumpsuit - description: It's a high visibility jumpsuit given to those engineers insane enough to achieve the rank of Chief Engineer. It has minor radiation shielding. + description: It's a high visibility jumpsuit given to those engineers insane enough to achieve the rank of Chief Engineer. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/ce.rsi @@ -518,7 +518,7 @@ parent: ClothingUniformBase id: ClothingUniformJumpsuitScientist name: scientist jumpsuit - description: It's made of a special fiber that provides minor protection against explosives. It has markings that denote the wearer as a scientist. + description: It's made of a special fiber that increases perceived intelligence and decreases personal ethics. It has markings that denote the wearer as a scientist. components: - type: Sprite sprite: Clothing/Uniforms/Jumpsuit/scientist.rsi diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/specific.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/specific.yml index ad02f4aa676..a2c903bac3b 100644 --- a/Resources/Prototypes/Entities/Clothing/Uniforms/specific.yml +++ b/Resources/Prototypes/Entities/Clothing/Uniforms/specific.yml @@ -38,5 +38,5 @@ default: ClothingUniformJumpsuitColorBlack - type: UserInterface interfaces: - - key: enum.ChameleonUiKey.Key - type: ChameleonBoundUserInterface \ No newline at end of file + enum.ChameleonUiKey.Key: + type: ChameleonBoundUserInterface diff --git a/Resources/Prototypes/Entities/Clothing/base_clothing.yml b/Resources/Prototypes/Entities/Clothing/base_clothing.yml index 16532c03e67..bc592616be9 100644 --- a/Resources/Prototypes/Entities/Clothing/base_clothing.yml +++ b/Resources/Prototypes/Entities/Clothing/base_clothing.yml @@ -22,6 +22,12 @@ - type: Geiger attachedToSuit: true +- type: entity + abstract: true + id: AllowSuitStorageClothing + components: + - type: AllowSuitStorage + # for clothing that has a single item slot to insert and alt click out. # inheritors add a whitelisted slot named item - type: entity diff --git a/Resources/Prototypes/Entities/Debugging/tippy.yml b/Resources/Prototypes/Entities/Debugging/tippy.yml new file mode 100644 index 00000000000..292cbed0f1b --- /dev/null +++ b/Resources/Prototypes/Entities/Debugging/tippy.yml @@ -0,0 +1,30 @@ +- type: entity + id: Tippy + noSpawn: true + components: + - type: Sprite + netsync: false + noRot: false + scale: 4,4 + layers: + - sprite: Tips/tippy.rsi + state: left + map: [ "revealing" ] + - sprite: Tips/tippy.rsi + state: right + map: [ "hiding" ] + - sprite: Tips/tippy.rsi + state: down + visible: false + map: [ "speaking" ] + # footstep sounds wile waddling onto the screen. + - type: FootstepModifier + footstepSoundCollection: + collection: FootstepClown + # visuals for the speech bubble. + # only supports background image. + - type: PaperVisuals + backgroundImagePath: "/Textures/Interface/Paper/paper_background_default.svg.96dpi.png" + backgroundPatchMargin: 16.0, 16.0, 16.0, 16.0 + backgroundModulate: "#ffffcc" + fontAccentColor: "#000000" diff --git a/Resources/Prototypes/Entities/Effects/puddle.yml b/Resources/Prototypes/Entities/Effects/puddle.yml index d3156c50a3f..6a29a8af456 100644 --- a/Resources/Prototypes/Entities/Effects/puddle.yml +++ b/Resources/Prototypes/Entities/Effects/puddle.yml @@ -142,8 +142,11 @@ mode: CardinalFlags - type: SolutionContainerManager solutions: - puddle: { maxVol: 1000 } + puddle: + maxVol: 1000 - type: Puddle + - type: MixableSolution + solution: puddle - type: Appearance - type: ActiveEdgeSpreader - type: EdgeSpreader diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml index ff9e5124328..f8fc2998d7f 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/drinks_glass.yml @@ -32,6 +32,7 @@ - DrinkBloodyMaryGlass - DrinkBooger - DrinkBraveBullGlass + - BudgetInsulsDrinkGlass - DrinkCarrotJuice - DrinkCoconutRum - DrinkChocolateGlass @@ -57,6 +58,7 @@ - DrinkIcedGreenTeaGlass - DrinkIcedBeerGlass - DrinkIceCreamGlass + - IrishBoolGlass - DrinkIrishCarBomb - DrinkIrishCoffeeGlass - DrinkLemonadeGlass @@ -78,6 +80,7 @@ - DrinkRewriter - DrinkRoyRogersGlass - DrinkRootBeerFloatGlass + - RubberneckGlass - DrinkRumGlass - DrinkSakeGlass - DrinkSbitenGlass @@ -91,12 +94,15 @@ - DrinkThreeMileIslandGlass - DrinkToxinsSpecialGlass - DrinkVodkaMartiniGlass + - DrinkVodkaRedBool - DrinkVodkaTonicGlass - DrinkWatermelonJuice + - DrinkWatermelonWakeup - DrinkWhiskeyColaGlass - DrinkWhiskeySodaGlass - DrinkWhiteRussianGlass - DrinkWineGlass + - XenoBasherGlass - DrinkShakeBlue - DrinkShakeWhite - DrinkTheMartinez diff --git a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_produce.yml b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_produce.yml index 6edf341e108..a889b939bde 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_produce.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/Random/Food_Drinks/food_produce.yml @@ -33,8 +33,8 @@ - FoodOnion - FoodOnionRed - FoodMushroom - - FoodChili - - FoodChilly + - FoodChiliPepper + - FoodChillyPepper - FoodAloe - FoodPoppy - FoodLingzhi diff --git a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml index 0b09e0e4c9f..4ade9a9fd45 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/ghost_roles.yml @@ -8,6 +8,8 @@ name: ghost-role-information-rat-king-name description: ghost-role-information-rat-king-description rules: ghost-role-information-rat-king-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobRatKing - type: Sprite @@ -27,6 +29,8 @@ name: ghost-role-information-remilia-name description: ghost-role-information-remilia-description rules: ghost-role-information-remilia-rules + raffle: + settings: short - type: GhostRoleMobSpawner prototype: MobBatRemilia - type: Sprite @@ -46,6 +50,8 @@ name: ghost-role-information-cerberus-name description: ghost-role-information-cerberus-description rules: ghost-role-information-cerberus-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobCorgiCerberus - type: Sprite @@ -64,6 +70,8 @@ components: - type: GhostRole rules: ghost-role-information-nukeop-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobHumanNukeOp - type: Sprite @@ -84,6 +92,8 @@ name: ghost-role-information-loneop-name description: ghost-role-information-loneop-description rules: ghost-role-information-loneop-rules + raffle: + settings: default requirements: - !type:CharacterOverallTimeRequirement min: 172800 # DeltaV - 48 hours @@ -109,6 +119,8 @@ name: ghost-role-information-space-dragon-name description: ghost-role-information-space-dragon-description rules: ghost-role-component-default-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobDragon - type: Sprite @@ -127,6 +139,8 @@ name: ghost-role-information-space-ninja-name description: ghost-role-information-space-ninja-description rules: ghost-role-information-space-ninja-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobHumanSpaceNinja - type: Sprite @@ -135,20 +149,3 @@ - state: green - sprite: Objects/Weapons/Melee/energykatana.rsi state: icon - -- type: entity - parent: MarkerBase - id: SpawnPointGhostTerminator - name: terminator spawn point - components: - - type: GhostRole - name: ghost-role-information-exterminator-name - description: ghost-role-information-exterminator-description - rules: ghost-role-information-exterminator-rules - - type: GhostRoleMobSpawner - prototype: MobHumanTerminator - - type: Sprite - layers: - - state: green - - sprite: Mobs/Species/Terminator/parts.rsi - state: full diff --git a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml index a59c7d59517..a69c974a39d 100644 --- a/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml +++ b/Resources/Prototypes/Entities/Markers/Spawners/mobs.yml @@ -849,3 +849,17 @@ - type: ConditionalSpawner prototypes: - MobLuminousEntity + +- type: entity + name: clown spider spawner + id: SpawnClownSpider + parent: MarkerBase + components: + - type: Sprite + layers: + - state: green + - state: clown + sprite: Mobs/Animals/clownspider.rsi + - type: ConditionalSpawner + prototypes: + - MobClownSpider \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml index 449f8aa2cd4..aa983583c5a 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml @@ -1160,6 +1160,13 @@ sprites: - sprite: Mobs/Customization/human_hair.rsi state: spiky2 +- type: marking + id: HumanHairSpookyLong + bodyPart: Hair + markingCategory: Hair + sprites: + - sprite: Mobs/Customization/human_hair.rsi + state: spookylong - type: marking id: HumanHairSwept bodyPart: Hair diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml index 1ad9ac98e45..cad3e779621 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/reptilian.yml @@ -63,6 +63,15 @@ - sprite: Mobs/Customization/reptilian_parts.rsi state: frills_hood_secondary +- type: marking + id: LizardFrillsNeckfull + bodyPart: HeadSide + markingCategory: HeadSide + speciesRestriction: [Reptilian] + sprites: + - sprite: Mobs/Customization/reptilian_parts.rsi + state: frills_neckfull + - type: marking id: LizardHornsAngler bodyPart: HeadTop @@ -184,6 +193,17 @@ - sprite: Mobs/Customization/reptilian_parts.rsi state: snout_sharp +- type: marking + id: LizardSnoutSplotch + bodyPart: Snout + markingCategory: Snout + speciesRestriction: [Reptilian] + sprites: + - sprite: Mobs/Customization/reptilian_parts.rsi + state: snout_splotch_primary + - sprite: Mobs/Customization/reptilian_parts.rsi + state: snout_splotch_secondary + - type: marking id: LizardChestTiger bodyPart: Chest diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_facial_hair.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_facial_hair.yml index d4cc4b00e31..6ec5f8999a1 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_facial_hair.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_facial_hair.yml @@ -1,40 +1,44 @@ - type: marking - id: VoxFacialHairColonel + id: VoxFacialHairBeard bodyPart: FacialHair markingCategory: FacialHair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_facial_hair.rsi - state: vox_colonel_s + state: beard_s + - type: marking - id: VoxFacialHairFu + id: VoxFacialHairColonel bodyPart: FacialHair markingCategory: FacialHair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_facial_hair.rsi - state: vox_fu_s + state: colonel_s + - type: marking - id: VoxFacialHairNeck + id: VoxFacialHairFu bodyPart: FacialHair markingCategory: FacialHair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_facial_hair.rsi - state: vox_neck_s + state: fu_s + - type: marking - id: VoxFacialHairBeard + id: VoxFacialHairMane bodyPart: FacialHair markingCategory: FacialHair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_facial_hair.rsi - state: vox_beard_s + state: mane_s + - type: marking - id: VoxFacialHairRuffBeard + id: VoxFacialHairNeck bodyPart: FacialHair markingCategory: FacialHair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_facial_hair.rsi - state: vox_ruff_beard_s + state: neck_s diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_hair.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_hair.yml index 975de63204d..9a847b40a99 100644 --- a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_hair.yml +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_hair.yml @@ -1,91 +1,102 @@ - type: marking - id: VoxHairShortQuills + id: VoxHairAfro bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_shortquills_s + state: afro_s + - type: marking - id: VoxHairKingly + id: VoxHairBraids bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_kingly_s + state: braid_s + - type: marking - id: VoxHairAfro + id: VoxHairCrestedQuills bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_afro_s + state: crestedquills_s + - type: marking - id: VoxHairMohawk + id: VoxHairEmperorQuills bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_mohawk_s + state: emperorquills_s + - type: marking - id: VoxHairYasuhiro + id: VoxHairFlowing bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_yasu_s + state: flowing_s + - type: marking - id: VoxHairHorns + id: VoxHairHawk bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_horns_s + state: hawk_s + - type: marking - id: VoxHairNights + id: VoxHairHorns bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_nights_s + state: horns_s + - type: marking - id: VoxHairSurf + id: VoxHairKeelQuills bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_surf_s + state: keelquills_s + - type: marking - id: VoxHairCropped + id: VoxHairKeetQuills bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_cropped_s + state: keetquills_s + - type: marking - id: VoxHairRuffhawk + id: VoxHairKingly bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_ruff_hawk_s + state: kingly_s + - type: marking - id: VoxHairRows + id: VoxHairLongBraid bodyPart: Hair markingCategory: Hair speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_rows_s + state: afro_s + - type: marking id: VoxHairMange bodyPart: Hair @@ -93,7 +104,26 @@ speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_mange_s + state: mange_s + +- type: marking + id: VoxHairMohawk + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: mohawk_s + +- type: marking + id: VoxHairNights + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: nights_s + - type: marking id: VoxHairPony bodyPart: Hair @@ -101,4 +131,67 @@ speciesRestriction: [Vox] sprites: - sprite: Mobs/Customization/vox_hair.rsi - state: vox_pony_s + state: ponytail_s + +- type: marking + id: VoxHairRazorClipped + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: razor_clipped_s + +- type: marking + id: VoxHairRazor + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: razor_s + +- type: marking + id: VoxHairSortBraid + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: short_braid_s + +- type: marking + id: VoxHairShortQuills + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: shortquills_s + +- type: marking + id: VoxHairSurf + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: surf_s + +- type: marking + id: VoxHairTielQuills + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: tielquills_s + +- type: marking + id: VoxHairYasu + bodyPart: Hair + markingCategory: Hair + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_hair.rsi + state: yasu_s \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml new file mode 100644 index 00000000000..96acd068828 --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_parts.yml @@ -0,0 +1,145 @@ +- type: marking + id: VoxBeak + bodyPart: Snout + markingCategory: Snout + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: beak + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxLArmScales + bodyPart: LArm + markingCategory: LeftArm + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: l_arm + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxLLegScales + bodyPart: LLeg + markingCategory: LeftLeg + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: l_leg + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxRArmScales + bodyPart: RArm + markingCategory: RightArm + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: r_arm + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxRLegScales + bodyPart: RLeg + markingCategory: RightLeg + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: r_leg + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxRHandScales + bodyPart: RHand + markingCategory: RightHand + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: r_hand + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxLHandScales + bodyPart: LHand + markingCategory: LeftHand + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: l_hand + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxLFootScales + bodyPart: LFoot + markingCategory: LeftFoot + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: l_foot + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxRFootScales + bodyPart: RFoot + markingCategory: RightFoot + forcedColoring: true + speciesRestriction: [Vox] + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + state: r_foot + coloring: + default: + type: + !type:SimpleColoring + color: "#937e3d" + +- type: marking + id: VoxTail + bodyPart: Tail + markingCategory: Tail + speciesRestriction: [Vox] + forcedColoring: true + sprites: + - sprite: Mobs/Customization/vox_parts.rsi + # Ideally this should use the normal tail sprite and apply an actual mask over it, not just use a butchered sprite + state: tail_stenciled diff --git a/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml new file mode 100644 index 00000000000..a802d284f3b --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Customization/Markings/vox_tattoos.yml @@ -0,0 +1,55 @@ +- type: marking + id: TattooVoxHeartLeftArm + bodyPart: LArm + markingCategory: LeftArm + speciesRestriction: [Vox] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" + sprites: + - sprite: Mobs/Customization/vox_tattoos.rsi + state: heart_l_arm + +- type: marking + id: TattooVoxHeartRightArm + bodyPart: RArm + markingCategory: RightArm + speciesRestriction: [Vox] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" + sprites: + - sprite: Mobs/Customization/vox_tattoos.rsi + state: heart_r_arm + +- type: marking + id: TattooVoxHiveChest + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" + sprites: + - sprite: Mobs/Customization/vox_tattoos.rsi + state: hive_s + +- type: marking + id: TattooVoxNightlingChest + bodyPart: Chest + markingCategory: Chest + speciesRestriction: [Vox] + coloring: + default: + type: + !type:TattooColoring + fallbackColor: "#666666" + sprites: + - sprite: Mobs/Customization/vox_tattoos.rsi + state: nightling_s diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml index 81bd0332a58..7974b06870e 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/base_borg_chassis.yml @@ -63,12 +63,12 @@ locPrefix: silicon - type: UserInterface interfaces: - - key: enum.SiliconLawsUiKey.Key - type: SiliconLawBoundUserInterface - - key: enum.BorgUiKey.Key - type: BorgBoundUserInterface - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.SiliconLawsUiKey.Key: + type: SiliconLawBoundUserInterface + enum.BorgUiKey.Key: + type: BorgBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: ActivatableUI key: enum.BorgUiKey.Key - type: SiliconLawBound @@ -129,11 +129,14 @@ proto: robot - type: Speech speechVerb: Robotic - speechSounds: Pai + speechSounds: Borg - type: Vocal sounds: Unsexed: UnisexSilicon - type: UnblockableSpeech + - type: FootstepModifier + footstepSoundCollection: + collection: FootstepBorg - type: Construction graph: Cyborg containers: @@ -205,13 +208,14 @@ - type: StandingState - type: Tag tags: - - ShoesRequiredStepTriggerImmune - DoorBumpOpener + - FootstepSound - CanPilot - type: Emoting - type: GuideHelp guides: - Cyborgs + - type: StepTriggerImmune - type: Eye visMask: - PsionicInvisibility @@ -225,9 +229,26 @@ - RobotTalk - type: PsionicInsulation +- type: entity + abstract: true + id: BaseBorgTransponder + components: + - type: BorgTransponder + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: CyborgControl + transmitFrequencyId: RoboticsConsole + # explosion does most of its damage in the center and less at the edges + - type: Explosive + explosionType: Minibomb + totalIntensity: 30 + intensitySlope: 20 + maxIntensity: 20 + canCreateVacuum: false # its for killing the borg not the station + - type: entity id: BaseBorgChassisNT - parent: BaseBorgChassis + parent: [BaseBorgChassis, BaseBorgTransponder] abstract: true components: - type: NpcFactionMember @@ -239,30 +260,36 @@ - AllAccessBorg - type: AccessReader access: [["Command"], ["Research"]] - - type: ShowSecurityIcons + - type: ShowJobIcons + - type: ShowMindShieldIcons - type: entity id: BaseBorgChassisSyndicate parent: BaseBorgChassis abstract: true components: - - type: NpcFactionMember - factions: - - Syndicate - - type: Access - tags: - - NuclearOperative - - SyndicateAgent - - type: AccessReader - access: [["SyndicateAgent"], ["NuclearOperative"]] - - type: SiliconLawProvider - laws: SyndicateStatic - - type: IntrinsicRadioTransmitter - channels: - - Binary - - Syndicate - - type: ActiveRadio - channels: - - Syndicate - - type: ShowSyndicateIcons - - type: MovementAlwaysTouching + - type: NpcFactionMember + factions: + - Syndicate + - type: Access + tags: + - NuclearOperative + - SyndicateAgent + - type: AccessReader + access: [["SyndicateAgent"], ["NuclearOperative"]] + - type: SiliconLawProvider + laws: SyndicateStatic + - type: IntrinsicRadioTransmitter + channels: + - Binary + - Syndicate + - type: ActiveRadio + channels: + - Syndicate + - type: ShowSyndicateIcons + - type: MovementAlwaysTouching + - type: Speech + speechSounds: SyndieBorg + - type: Vocal + sounds: + Unsexed: UnisexSiliconSyndicate diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml index 5056fda4c06..e0dc4a0ad43 100644 --- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml +++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml @@ -20,6 +20,11 @@ - BorgModuleGeneric hasMindState: robot_e noMindState: robot_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: robot + name: cyborg - type: Construction node: cyborg - type: Speech @@ -57,6 +62,11 @@ - BorgModuleCargo hasMindState: miner_e noMindState: miner_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: miner + name: salvage cyborg - type: Construction node: mining - type: IntrinsicRadioTransmitter @@ -100,6 +110,11 @@ - BorgModuleEngineering hasMindState: engineer_e noMindState: engineer_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: engineer + name: engineer cyborg - type: Construction node: engineer - type: IntrinsicRadioTransmitter @@ -153,6 +168,11 @@ - BorgModuleJanitor hasMindState: janitor_e noMindState: janitor_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: janitor + name: janitor cyborg - type: Construction node: janitor - type: IntrinsicRadioTransmitter @@ -206,6 +226,11 @@ - BorgModuleMedical hasMindState: medical_e noMindState: medical_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: medical + name: medical cyborg - type: Construction node: medical - type: IntrinsicRadioTransmitter @@ -224,11 +249,14 @@ access: [["Medical"], ["Command"], ["Research"]] - type: Inventory templateId: borgDutch + - type: FootstepModifier + footstepSoundCollection: + collection: FootstepHoverBorg - type: FabricateActions actions: - ActionFabricateLollipop - ActionFabricateGumball - - type: SiliconLawProvider # Delta-V - Adds custom lawset for Medical cyborg + - type: SiliconLawProvider laws: Medical - type: entity @@ -255,6 +283,11 @@ - BorgModuleService hasMindState: service_e noMindState: service_e_r + - type: BorgTransponder + sprite: + sprite: Mobs/Silicon/chassis.rsi + state: service + name: service cyborg - type: Construction node: service - type: IntrinsicRadioTransmitter diff --git a/Resources/Prototypes/Entities/Mobs/Debugging/debug_counter.yml b/Resources/Prototypes/Entities/Mobs/Debugging/debug_counter.yml new file mode 100644 index 00000000000..05707c7151c --- /dev/null +++ b/Resources/Prototypes/Entities/Mobs/Debugging/debug_counter.yml @@ -0,0 +1,53 @@ +- type: entity + parent: MobHuman + id: MobDebugCounter + name: debug counter + description: He can count + suffix: AI, DEBUG + components: + - type: HTN + rootTask: + task: DebugCounterCompound + blackboard: + MinimumIdleTime: !type:Single + 0.5 + MaximumIdleTime: !type:Single + 0.5 + Count: !type:Single + 0 + +- type: entity + parent: MobHuman + id: MobDebugRandomCounter + name: debug random counter + description: He can randomize + suffix: AI, DEBUG + components: + - type: HTN + rootTask: + task: DebugRandomCounterCompound + blackboard: + MinimumIdleTime: !type:Single + 1 + MaximumIdleTime: !type:Single + 1 + Count: !type:Single + 0 + +- type: entity + parent: MobHuman + id: MobDebugRandomLess + name: debug random less + description: He can lessing + suffix: AI, DEBUG + components: + - type: HTN + rootTask: + task: DebugRandomLessCompound + blackboard: + MinimumIdleTime: !type:Single + 1 + MaximumIdleTime: !type:Single + 1 + Count: !type:Single + 0 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 343a39ca70f..08d00c7c913 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -17,6 +17,7 @@ - type: Speech speechSounds: Squeak speechVerb: SmallMob + allowedEmotes: ['Squeak'] - type: Fixtures fixtures: fix1: @@ -457,7 +458,10 @@ - type: GhostTakeoverAvailable - type: Speech speechVerb: Moth - speechSounds: Chitter # Delta-V - Eep! + speechSounds: Chitter + allowedEmotes: ['Chitter', 'Squeak'] + - type: FaxableObject + insertingState: inserting_mothroach - type: MothAccent - type: Sprite sprite: Mobs/Animals/mothroach.rsi @@ -867,6 +871,7 @@ - type: Speech speechVerb: Arachnid speechSounds: Arachnid + allowedEmotes: ['Click', 'Chitter'] - type: DamageStateVisuals states: Alive: @@ -1143,8 +1148,8 @@ - id: FoodMeat - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -1216,6 +1221,8 @@ templateId: monkey speciesId: monkey - type: InventorySlots + - type: Deathgasp + prototype: MonkeyDeathgasp - type: Cuffable - type: RotationVisuals defaultRotation: 90 @@ -1235,8 +1242,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: Sprite drawdepth: Mobs layers: @@ -1379,6 +1386,8 @@ makeSentient: true name: ghost-role-information-monkey-name description: ghost-role-information-monkey-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Loadout prototypes: [SyndicateOperativeGearMonkey] @@ -1402,9 +1411,10 @@ - type: entity name: kobold - id: MobKobold + id: MobBaseKobold parent: MobBaseAncestor description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death. + abstract: true components: - type: NameIdentifier group: Kobold @@ -1420,9 +1430,9 @@ speechVerb: Reptilian - type: Vocal sounds: - Male: UnisexReptilian - Female: UnisexReptilian - Unsexed: UnisexReptilian + Male: MaleReptilian + Female: FemaleReptilian + Unsexed: MaleReptilian - type: TypingIndicator proto: lizard - type: InteractionPopup @@ -1502,15 +1512,6 @@ spawned: - id: FoodMeat amount: 2 - - type: Clumsy - clumsyDamage: - types: - Blunt: 2 - Piercing: 7 - groups: - Burn: 3 - clumsySound: - path: /Audio/Voice/Reptilian/reptilian_scream.ogg - type: AlwaysRevolutionaryConvertible - type: GhostTakeoverAvailable - type: SentienceTarget @@ -1523,6 +1524,55 @@ - type: RandomBark barkMultiplier: 0.65 +- type: entity + name: kobold + id: MobKobold + parent: MobBaseKobold + description: Cousins to the sentient race of lizard people, kobolds blend in with their natural habitat and are as nasty as monkeys; ready to pull out your hair and stab you to death. + components: + - type: Clumsy + clumsyDamage: + types: + Blunt: 2 + Piercing: 7 + groups: + Burn: 3 + clumsySound: + path: /Audio/Voice/Reptilian/reptilian_scream.ogg + +- type: entity + id: MobBaseSyndicateKobold + parent: MobBaseKobold + suffix: syndicate base + components: + - type: MobThresholds + thresholds: + 0: Alive + 75: Critical + 200: Dead + - type: NpcFactionMember + factions: + - Syndicate + - type: Loadout + prototypes: [SyndicateOperativeGearMonkey] + +- type: entity + id: MobKoboldSyndicateAgent + parent: MobBaseSyndicateKobold + suffix: syndicate agent + components: + # make the player a traitor once its taken + - type: AutoTraitor + giveUplink: false + giveObjectives: false + +- type: entity + id: MobKoboldSyndicateAgentNukeops # Reinforcement exclusive to nukeops uplink + parent: MobBaseSyndicateKobold + suffix: NukeOps + components: + - type: NukeOperative + - type: entity name: guidebook monkey parent: MobMonkey @@ -1550,6 +1600,7 @@ - type: Speech speechSounds: Squeak speechVerb: SmallMob + allowedEmotes: ['Squeak'] - type: Sprite drawdepth: SmallMobs sprite: Mobs/Animals/mouse.rsi @@ -1578,6 +1629,8 @@ rootTask: task: MouseCompound - type: Physics + - type: FaxableObject + insertingState: inserting_mouse - type: Fixtures fixtures: fix1: @@ -2246,6 +2299,7 @@ 0: Alive 90: Dead - type: MeleeWeapon + altDisarm: false angle: 0 animation: WeaponArcBite soundHit: @@ -2287,6 +2341,7 @@ - type: Speech speechVerb: Arachnid speechSounds: Arachnid + allowedEmotes: ['Click', 'Chitter'] - type: Vocal sounds: Male: UnisexArachnid @@ -2341,7 +2396,9 @@ makeSentient: true name: ghost-role-information-giant-spider-name description: ghost-role-information-giant-spider-description - rules: deltav-ghost-role-information-softantag-rules #DeltaV + rules: deltav-ghost-role-information-softantag-rules + raffle: + settings: short - type: GhostTakeoverAvailable - type: entity @@ -2373,6 +2430,7 @@ - type: Spider webPrototype: SpiderWebClown - type: MeleeWeapon + altDisarm: false angle: 0 animation: WeaponArcBite soundHit: @@ -2389,6 +2447,18 @@ bloodMaxVolume: 150 bloodReagent: Laughter +- type: entity + name: wizard spider + parent: MobGiantSpider + id: MobGiantSpiderWizard + description: This spider looks a little magical + suffix: Wizard + components: + - type: Accentless + removes: + - type: ReplacementAccent + accent: xeno #let this wizard speak + - type: entity name: possum parent: SimpleMobBase @@ -2421,8 +2491,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -2503,8 +2573,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -2573,8 +2643,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -2591,7 +2661,7 @@ interactFailureString: petting-failure-generic interactSuccessSpawn: EffectHearts interactSuccessSound: - path: /Audio/Animals/fox_squeak.ogg + collection: Fox - type: Grammar attributes: gender: epicene @@ -2656,8 +2726,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -2811,8 +2881,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -2839,6 +2909,11 @@ interactSuccessSound: path: /Audio/Animals/cat_meow.ogg - type: MeleeWeapon + altDisarm: false + angle: 0 + animation: WeaponArcBite + soundHit: + path: /Audio/Effects/bite.ogg damage: types: Piercing: 5 @@ -2891,16 +2966,31 @@ allowMovement: true description: ghost-role-information-SyndiCat-description rules: ghost-role-information-SyndiCat-rules + raffle: + settings: default - type: GhostTakeoverAvailable - type: AutoImplant implants: - MicroBombImplant + - type: ExplosionResistance + damageCoefficient: 0.2 - type: NpcFactionMember factions: - Syndicate + - type: MeleeWeapon + altDisarm: false + angle: 0 + animation: WeaponArcBite + soundHit: + path: /Audio/Effects/bite.ogg + damage: + types: + Slash: 6 + Piercing: 6 + Structural: 15 - type: LanguageKnowledge speaks: - - Cat + - Cat understands: - Cat - TauCetiBasic @@ -2924,7 +3014,13 @@ - type: Temperature heatDamageThreshold: 423 coldDamageThreshold: 0 + - type: Tag + tags: + - DoorBumpOpener + - type: MovementAlwaysTouching - type: PressureImmunity + - type: StepTriggerImmune + - type: Insulated - type: InteractionPopup successChance: 0.7 interactSuccessString: petting-success-space-cat @@ -3045,8 +3141,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -3112,8 +3208,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -3160,6 +3256,7 @@ - type: Speech speechVerb: SmallMob speechSounds: Squeak + allowedEmotes: ['Squeak'] - type: Sprite drawdepth: SmallMobs sprite: Mobs/Animals/hamster.rsi @@ -3176,6 +3273,8 @@ - type: Item size: Tiny - type: Physics + - type: FaxableObject + insertingState: inserting_hamster - type: Fixtures fixtures: fix1: @@ -3210,8 +3309,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -3333,8 +3432,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -3401,8 +3500,8 @@ bloodMaxVolume: 60 - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml index 8a10337c946..07ee6b1536a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/behonker.yml @@ -10,6 +10,8 @@ makeSentient: true name: ghost-role-information-behonker-name description: ghost-role-information-behonker-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: HTN rootTask: @@ -76,8 +78,8 @@ - id: BikeHorn - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: MobThresholds thresholds: 0: Alive diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml index 787f8ae5427..2778bf12788 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/carp.yml @@ -164,6 +164,8 @@ makeSentient: true name: ghost-role-information-sentient-carp-name description: ghost-role-information-sentient-carp-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: HTN rootTask: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml b/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml index 2bcd3776260..a0c19569bb2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/dogs.yml @@ -43,8 +43,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -65,7 +65,6 @@ interactFailureString: petting-failure-pibble interactSuccessSound: path: /Audio/Animals/small_dog_bark_happy.ogg - hostileOnFail: true - type: DogVision - type: NpcFactionMember factions: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml index 7103002cd7f..94ba7ec4188 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/elemental.yml @@ -44,7 +44,6 @@ - type: Tag tags: - DoorBumpOpener - - ShoesRequiredStepTriggerImmune - type: MobState allowedStates: - Alive @@ -73,6 +72,8 @@ - type: InputMover - type: MobMover - type: ZombieImmune + - type: ClothingRequiredStepTriggerImmune + slots: All - type: entity abstract: true @@ -236,6 +237,8 @@ - type: GhostRole prob: 0 description: ghost-role-information-angry-slimes-description + raffle: + settings: short - type: NpcFactionMember factions: - SimpleHostile diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/hellspawn.yml b/Resources/Prototypes/Entities/Mobs/NPCs/hellspawn.yml index 5511c40baad..74658f0a2db 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/hellspawn.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/hellspawn.yml @@ -12,6 +12,8 @@ makeSentient: true name: ghost-role-information-hellspawn-name description: ghost-role-information-hellspawn-description + raffle: + settings: default - type: RotationVisuals defaultRotation: 90 horizontalRotation: 90 @@ -53,6 +55,7 @@ - type: Perishable - type: Reflect reflectProb: 0.7 + innate: true reflects: - Energy - type: Fixtures diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml index 4ec4ee6a12f..cbf1b718b75 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/pets.yml @@ -229,8 +229,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -292,8 +292,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -397,8 +397,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: DamageStateVisuals states: Alive: @@ -559,7 +559,7 @@ interactFailureString: petting-failure-generic interactSuccessSpawn: EffectHearts interactSuccessSound: - path: /Audio/Animals/fox_squeak.ogg + collection: Fox - type: Butcherable spawned: - id: FoodMeat @@ -795,6 +795,9 @@ types: Blunt: 1 Caustic: 1 + - type: MultiHandedItem + - type: Item + size: Huge - type: SentienceTarget flavorKind: station-event-random-sentience-flavor-slime - type: MobPrice diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml index e1ea11cc2c3..f6a42dfb76b 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/regalrat.yml @@ -90,6 +90,8 @@ name: ghost-role-information-rat-king-name description: ghost-role-information-rat-king-description rules: ghost-role-information-rat-king-rules + raffle: + settings: default - type: GhostTakeoverAvailable - type: Tag tags: diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml index 47ce0f9d490..c16816b5e44 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml @@ -60,6 +60,8 @@ name: ghost-role-information-revenant-name description: ghost-role-information-revenant-description rules: ghost-role-information-revenant-rules + raffle: + settings: default - type: GhostTakeoverAvailable - type: Revenant malfunctionWhitelist: @@ -79,8 +81,8 @@ softness: 1 - type: UserInterface interfaces: - - key: enum.StoreUiKey.Key - type: StoreBoundUserInterface + enum.StoreUiKey.Key: + type: StoreBoundUserInterface - type: Visibility layer: 2 #ghost vis layer - type: Store diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index 0e279a07eb6..2fea60ea1ea 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -61,11 +61,11 @@ group: GenericNumber - type: Repairable doAfterDelay: 8 + fuelCost: 15 - type: Pullable - type: Tag tags: - DoorBumpOpener - - ShoesRequiredStepTriggerImmune - type: MobState allowedStates: - Alive @@ -106,6 +106,7 @@ - type: TypingIndicator proto: robot - type: ZombieImmune + - type: StepTriggerImmune - type: LanguageKnowledge speaks: - TauCetiBasic @@ -164,6 +165,8 @@ makeSentient: true name: ghost-role-information-honkbot-name description: ghost-role-information-honkbot-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: InteractionPopup interactSuccessString: petting-success-honkbot @@ -189,6 +192,8 @@ makeSentient: true name: ghost-role-information-jonkbot-name description: ghost-role-information-jonkbot-description + raffle: + settings: default - type: InteractionPopup interactSuccessSound: path: /Audio/Items/brokenbikehorn.ogg @@ -310,8 +315,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: Sprite layers: - map: ["enum.DamageStateVisualLayers.Base"] @@ -325,9 +330,69 @@ makeSentient: true name: ghost-role-information-mimebot-name description: ghost-role-information-mimebot-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: InteractionPopup interactSuccessString: petting-success-mimebot interactFailureString: petting-failure-mimebot - type: Inventory templateId: head + +- type: entity + parent: MobSiliconBase + id: MobSupplyBot + name: supplybot + description: Delivers cargo! + components: + - type: Sprite + sprite: Mobs/Silicon/Bots/supplybot.rsi + layers: + - state: supplybot + - type: GhostRole + makeSentient: true + name: ghost-role-information-supplybot-name + description: ghost-role-information-supplybot-description + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Construction + graph: SupplyBot + node: bot + - type: Access + tags: + - Cargo + - Maintenance + - Salvage + - type: Dumpable + - type: Storage + maxItemSize: Huge + grid: + - 0,0,9,3 + - type: UserInterface + interfaces: + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] + - type: UnpoweredFlashlight + - type: PointLight + enabled: false + radius: 3.5 + softness: 2 + mask: /Textures/Effects/LightMasks/cone.png + autoRot: true + - type: FootstepModifier + footstepSoundCollection: + collection: FootstepBorg + - type: Tag + tags: + - DoorBumpOpener + - FootstepSound + - type: ActiveRadio + channels: + - Binary + - Common + - Supply diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml index fbf133a0f1e..74bba2dec8a 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/slimes.yml @@ -1,16 +1,10 @@ - type: entity name: basic slime - id: MobAdultSlimes + id: BaseMobAdultSlimes parent: [ SimpleMobBase, MobCombat ] abstract: true description: It looks so much like jelly. I wonder what it tastes like? components: - - type: NpcFactionMember - factions: - - SimpleNeutral - - type: HTN - rootTask: - task: SimpleHostileCompound - type: Sprite drawdepth: Mobs sprite: Mobs/Aliens/slimes.rsi @@ -44,6 +38,7 @@ - type: Tag tags: - FootstepSound + - DoorBumpOpener - type: Butcherable butcheringType: Knife spawned: @@ -99,6 +94,7 @@ prototype: Slimes requiredLegs: 1 - type: MeleeWeapon + altDisarm: false soundHit: path: /Audio/Weapons/punch3.ogg angle: 0 @@ -112,6 +108,19 @@ successChance: 0.5 interactSuccessString: petting-success-slimes interactFailureString: petting-failure-generic + - type: Speech + speechVerb: Slime + speechSounds: Slime + - type: TypingIndicator + proto: slime + +- type: entity + name: basic slime + id: MobAdultSlimes + parent: BaseMobAdultSlimes + abstract: true + description: It looks so much like jelly. I wonder what it tastes like? + components: - type: LanguageKnowledge speaks: - Bubblish @@ -122,12 +131,54 @@ makeSentient: true name: ghost-role-information-slimes-name description: ghost-role-information-slimes-description - rules: deltav-ghost-role-information-softantag-rules #DeltaV + rules: deltav-ghost-role-information-softantag-rules - type: Speech speechVerb: Slime speechSounds: Slime + allowedEmotes: ['Squish'] - type: TypingIndicator proto: slime + - type: NpcFactionMember + factions: + - SimpleNeutral + - type: HTN + rootTask: + task: SimpleHostileCompound + +- type: entity + name: geras + description: A geras of a slime - the name is ironic, isn't it? + id: MobSlimesGeras + parent: BaseMobAdultSlimes + noSpawn: true + components: + # they portable... + - type: MovementSpeedModifier + baseWalkSpeed: 3 + baseSprintSpeed: 5 # +.5 from normal movement speed + - type: MobThresholds + thresholds: + 0: Alive + 80: Dead # weak af tho + - type: NpcFactionMember + factions: + - NanoTrasen + - type: MultiHandedItem + - type: Item + size: Huge + - type: Sprite + color: "#FFFFFF55" + - type: MeleeWeapon + attackRate: 2 + damage: + types: + Blunt: 4 + - type: DamageStateVisuals + states: + Alive: + Base: blue_adult_slime + Dead: + Base: blue_adult_slime_dead - type: entity name: blue slime @@ -150,8 +201,6 @@ - type: NpcFactionMember factions: - SimpleHostile -# - type: GhostRole #DeltaV - all slimes neutral when ghost role -# description: ghost-role-information-angry-slimes-description - type: entity name: green slime diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml index adf3af93eab..919441dff53 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/space.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/space.yml @@ -174,8 +174,8 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.StrippingUiKey.Key - type: StrippableBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface - type: entity id: MobKangarooSpaceSalvage @@ -269,6 +269,7 @@ - type: Speech speechVerb: Arachnid speechSounds: Arachnid + allowedEmotes: ['Click', 'Chitter'] - type: Vocal sounds: Male: UnisexArachnid diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml index 66115b46e4c..04b767b8ae2 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/xeno.yml @@ -103,14 +103,16 @@ spawned: - id: FoodMeatXeno amount: 5 - #- type: GhostRole # Delta V - Moves ghost role from parent to child - # allowMovement: true # Delta V - Moves ghost role from parent to child - # allowSpeech: true # Delta V - Moves ghost role from parent to child - # makeSentient: true # Delta V - Moves ghost role from parent to child - # name: ghost-role-information-xeno-name # Delta V - Moves ghost role from parent to child - # description: ghost-role-information-xeno-description # Delta V - Moves ghost role from parent to child - # rules: ghost-role-information-xeno-rules # Delta V - Moves ghost role from parent to child - # - type: GhostTakeoverAvailable # Delta V - Moves ghost role from parent to child + - type: GhostRole + allowMovement: true + allowSpeech: true + makeSentient: true + name: ghost-role-information-xeno-name + description: ghost-role-information-xeno-description + rules: ghost-role-information-xeno-rules + raffle: + settings: default + - type: GhostTakeoverAvailable - type: TypingIndicator proto: alien - type: Temperature diff --git a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml index e0300fa5033..c690bbb3117 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/admin_ghost.yml @@ -42,32 +42,32 @@ - CentralCommand - type: UserInterface interfaces: - - key: enum.SolarControlConsoleUiKey.Key + enum.SolarControlConsoleUiKey.Key: type: SolarControlConsoleBoundUserInterface - - key: enum.CommunicationsConsoleUiKey.Key + enum.CommunicationsConsoleUiKey.Key: type: CommunicationsConsoleBoundUserInterface - - key: enum.RadarConsoleUiKey.Key + enum.RadarConsoleUiKey.Key: type: RadarConsoleBoundUserInterface - - key: enum.CargoConsoleUiKey.Orders + enum.CargoConsoleUiKey.Orders: type: CargoOrderConsoleBoundUserInterface - - key: enum.CrewMonitoringUIKey.Key + enum.CrewMonitoringUIKey.Key: type: CrewMonitoringBoundUserInterface - - key: enum.GeneralStationRecordConsoleKey.Key - # who the fuck named this bruh + enum.GeneralStationRecordConsoleKey.Key: + # who the fuck named this bruh type: GeneralStationRecordConsoleBoundUserInterface - type: IntrinsicUI uis: - - key: enum.SolarControlConsoleUiKey.Key + enum.SolarControlConsoleUiKey.Key: toggleAction: ActionAGhostShowSolar - - key: enum.CommunicationsConsoleUiKey.Key + enum.CommunicationsConsoleUiKey.Key: toggleAction: ActionAGhostShowCommunications - - key: enum.RadarConsoleUiKey.Key + enum.RadarConsoleUiKey.Key: toggleAction: ActionAGhostShowRadar - - key: enum.CargoConsoleUiKey.Orders + enum.CargoConsoleUiKey.Orders: toggleAction: ActionAGhostShowCargo - - key: enum.CrewMonitoringUIKey.Key + enum.CrewMonitoringUIKey.Key: toggleAction: ActionAGhostShowCrewMonitoring - - key: enum.GeneralStationRecordConsoleKey.Key + enum.GeneralStationRecordConsoleKey.Key: toggleAction: ActionAGhostShowStationRecords - type: SolarControlConsole # look ma i AM the computer! - type: CommunicationsConsole diff --git a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml index 0eda8ae9d76..cb9dc1c911a 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/dragon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/dragon.yml @@ -14,6 +14,8 @@ makeSentient: true name: ghost-role-information-space-dragon-name description: ghost-role-information-space-dragon-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: HTN rootTask: @@ -89,6 +91,12 @@ speedModifierThresholds: 250: 0.7 400: 0.5 + # disable taking damage from fire, since its a fire breathing dragon + - type: Flammable + damage: + types: {} + - type: Temperature + heatDamageThreshold: 800 - type: Metabolizer solutionOnBody: false updateInterval: 0.25 @@ -139,10 +147,33 @@ spawnRiftAction: ActionSpawnRift - type: GenericAntag rule: Dragon + - type: ActionGun + action: ActionDragonsBreath + gunProto: DragonsBreathGun - type: GuideHelp guides: - MinorAntagonists +- type: entity + noSpawn: true + id: DragonsBreathGun + name: dragon's lung + description: For dragon's breathing + components: + - type: RechargeBasicEntityAmmo + rechargeCooldown: 5 + rechargeSound: + path: /Audio/Animals/space_dragon_roar.ogg + - type: BasicEntityAmmoProvider + proto: ProjectileDragonsBreath + capacity: 1 + count: 1 + - type: Gun + soundGunshot: + path: /Audio/Animals/space_dragon_roar.ogg + soundEmpty: null + projectileSpeed: 5 + - type: entity parent: BaseMobDragon id: MobDragonDungeon @@ -150,6 +181,8 @@ components: - type: GhostRole description: ghost-role-information-space-dragon-dungeon-description + raffle: + settings: default - type: SlowOnDamage speedModifierThresholds: 100: 0.7 @@ -179,6 +212,7 @@ state: icon event: !type:DragonSpawnRiftActionEvent useDelay: 1 + priority: 3 - type: entity id: ActionDevour @@ -190,3 +224,18 @@ icon: { sprite : Interface/Actions/devour.rsi, state: icon } iconOn: { sprite : Interface/Actions/devour.rsi, state: icon-on } event: !type:DevourActionEvent + priority: 1 + +- type: entity + noSpawn: true + id: ActionDragonsBreath + name: "[color=orange]Dragon's Breath[/color]" + description: Spew out flames at anyone foolish enough to attack you! + components: + - type: WorldTargetAction + # TODO: actual sprite + icon: { sprite : Objects/Weapons/Guns/Projectiles/magic.rsi, state: fireball } + event: !type:ActionGunShootEvent + priority: 2 + checkCanAccess: false + range: 0 diff --git a/Resources/Prototypes/Entities/Mobs/Player/familiars.yml b/Resources/Prototypes/Entities/Mobs/Player/familiars.yml index ab479e0332f..87166f13a3e 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/familiars.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/familiars.yml @@ -56,6 +56,8 @@ name: ghost-role-information-cerberus-name description: ghost-role-information-cerberus-description rules: ghost-role-information-cerberus-rules + raffle: + settings: default - type: GhostTakeoverAvailable - type: MeleeWeapon altDisarm: false diff --git a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml index 03253a79b32..6d90ac3ffee 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/guardian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/guardian.yml @@ -13,6 +13,8 @@ makeSentient: true name: ghost-role-information-guardian-name description: ghost-role-information-guardian-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Input context: "human" @@ -95,8 +97,8 @@ - type: MeleeSpeech - type: UserInterface interfaces: - - key: enum.MeleeSpeechUiKey.Key - type: MeleeSpeechBoundUserInterface + enum.MeleeSpeechUiKey.Key: + type: MeleeSpeechBoundUserInterface - type: Actions - type: Guardian - type: Tag @@ -116,6 +118,8 @@ makeSentient: true name: ghost-role-information-holoparasite-name description: ghost-role-information-holoparasite-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: NameIdentifier group: Holoparasite @@ -146,6 +150,8 @@ makeSentient: true name: ghost-role-information-ifrit-name description: ghost-role-information-ifrit-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: RandomSprite available: @@ -177,6 +183,8 @@ makeSentient: true name: ghost-role-information-holoclown-name description: ghost-role-information-holoclown-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: NameIdentifier group: Holoparasite diff --git a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml index 956e6f1260c..e96633dde8b 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/humanoid.yml @@ -26,6 +26,8 @@ - type: GhostRole name: ghost-role-information-Death-Squad-name description: ghost-role-information-Death-Squad-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ DeathSquadGear ] @@ -62,6 +64,8 @@ - type: GhostRole name: ghost-role-information-ert-leader-name description: ghost-role-information-ert-leader-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTLeaderGear ] @@ -92,6 +96,8 @@ - type: GhostRole name: ghost-role-information-ert-leader-name description: ghost-role-information-ert-leader-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTLeaderGearEVA ] @@ -114,6 +120,8 @@ - type: GhostRole name: ghost-role-information-ert-leader-name description: ghost-role-information-ert-leader-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTLeaderGearEVALecter ] @@ -145,6 +153,8 @@ - type: GhostRole name: ghost-role-information-ert-chaplain-name description: ghost-role-information-ert-chaplain-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -174,6 +184,8 @@ - type: GhostRole name: ghost-role-information-ert-chaplain-name description: ghost-role-information-ert-chaplain-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTChaplainGearEVA ] @@ -205,6 +217,8 @@ - type: GhostRole name: ghost-role-information-ert-janitor-name description: ghost-role-information-ert-janitor-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -234,6 +248,8 @@ - type: GhostRole name: ghost-role-information-ert-janitor-name description: ghost-role-information-ert-janitor-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTJanitorGearEVA ] @@ -265,6 +281,8 @@ - type: GhostRole name: ghost-role-information-ert-engineer-name description: ghost-role-information-ert-engineer-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -294,6 +312,8 @@ - type: GhostRole name: ghost-role-information-ert-engineer-name description: ghost-role-information-ert-engineer-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTEngineerGearEVA ] @@ -325,6 +345,8 @@ - type: GhostRole name: ghost-role-information-ert-security-name description: ghost-role-information-ert-security-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -354,6 +376,8 @@ - type: GhostRole name: ghost-role-information-ert-security-name description: ghost-role-information-ert-security-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTSecurityGearEVA ] @@ -375,6 +399,8 @@ - type: GhostRole name: ghost-role-information-ert-security-name description: ghost-role-information-ert-security-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTSecurityGearEVALecter ] @@ -406,6 +432,8 @@ - type: GhostRole name: ghost-role-information-ert-medical-name description: ghost-role-information-ert-medical-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -435,6 +463,8 @@ - type: GhostRole name: ghost-role-information-ert-medical-name description: ghost-role-information-ert-medical-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: Loadout prototypes: [ ERTMedicalGearEVA ] @@ -463,6 +493,8 @@ - type: GhostRole name: ghost-role-information-cburn-agent-name description: ghost-role-information-cburn-agent-description + raffle: + settings: short - type: GhostTakeoverAvailable - type: RandomMetadata nameSegments: @@ -489,6 +521,8 @@ - type: GhostRole name: ghost-role-information-centcom-official-name description: ghost-role-information-centcom-official-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Loadout prototypes: [ CentcomGear ] @@ -553,5 +587,311 @@ - type: GhostRole name: ghost-role-information-cluwne-name description: ghost-role-information-cluwne-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Cluwne + +## Lost Cargo technician + +- type: entity + name: lost cargo technician spawner + id: LostCargoTechnicianSpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Objects/Tools/appraisal-tool.rsi + state: icon + - type: RandomSpawner + prototypes: + - RandomHumanoidLostCargoTechnician + chance: 1 + +- type: entity + id: RandomHumanoidLostCargoTechnician + name: lost cargo technician ghost role + components: + - type: Sprite + sprite: Objects/Tools/appraisal-tool.rsi + state: icon + - type: RandomHumanoidSpawner + settings: LostCargoTechnician + +- type: randomHumanoidSettings + id: LostCargoTechnician + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-lost-cargo-technical-name + description: ghost-role-information-lost-cargo-technical-description + rules: ghost-role-information-lost-cargo-technical-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ CargoTechGear ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last + +# Clown troupe + +- type: entity + name: clown troupe spawner + id: ClownTroupeSpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Objects/Fun/bikehorn.rsi + state: icon + - type: RandomSpawner + prototypes: + - RandomHumanoidClownTroupe + rarePrototypes: + - RandomHumanoidClownTroupeBanana + rareChance: 0.3 + +- type: entity + id: RandomHumanoidClownTroupe + name: clown troupe ghost role + components: + - type: Sprite + sprite: Objects/Tools/appraisal-tool.rsi + state: icon + - type: RandomHumanoidSpawner + settings: ClownTroupe + +- type: entity + id: RandomHumanoidClownTroupeBanana + name: banana clown troupe + parent: RandomHumanoidClownTroupe + components: + - type: RandomHumanoidSpawner + settings: ClownTroupeBanana + +- type: randomHumanoidSettings + id: ClownTroupe + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-clown-troupe-name + description: ghost-role-information-clown-troupe-description + rules: ghost-role-information-clown-troupe-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ ClownGear ] + - type: RandomMetadata + nameSegments: + - names_clown + +- type: randomHumanoidSettings + id: ClownTroupeBanana + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-clown-troupe-name + description: ghost-role-information-clown-troupe-description + rules: ghost-role-information-clown-troupe-rules + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ BananaClown ] + - type: RandomMetadata + nameSegments: + - names_clown + +# Traveling exotic chef + +- type: entity + name: traveling chef spawner + id: TravelingChefSpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Objects/Weapons/Melee/kitchen_knife.rsi + state: icon + - type: RandomSpawner + prototypes: + - RandomHumanoidTravelingChef + +- type: entity + id: RandomHumanoidTravelingChef + name: traveling chef ghost role + components: + - type: Sprite + sprite: Objects/Tools/appraisal-tool.rsi + state: icon + - type: RandomHumanoidSpawner + settings: TravelingChef + +- type: randomHumanoidSettings + id: TravelingChef + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-traveling-chef-name + description: ghost-role-information-traveling-chef-description + rules: ghost-role-information-traveling-chef-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ ChefGear ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last + +# Disaster victim + +- type: entity + name: disaster victim spawner + id: DisasterVictimSpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Clothing/OuterClothing/Hardsuits/basic.rsi + state: icon + - type: RandomSpawner + prototypes: + - RandomHumanoidDisasterVictimRD + - RandomHumanoidDisasterVictimCMO + - RandomHumanoidDisasterVictimCaptain + - MobSkeletonCloset + +- type: entity + id: RandomHumanoidDisasterVictimRD + name: disaster victim RD ghost role + components: + - type: Sprite + sprite: Clothing/OuterClothing/Hardsuits/basic.rsi + state: icon + - type: RandomHumanoidSpawner + settings: DisasterVictimResearchDirector + +- type: entity + id: RandomHumanoidDisasterVictimCMO + parent: RandomHumanoidDisasterVictimRD + name: disaster victim CMO ghost role + components: + - type: RandomHumanoidSpawner + settings: DisasterVictimCMO + +- type: entity + id: RandomHumanoidDisasterVictimCaptain + parent: RandomHumanoidDisasterVictimRD + name: disaster victim Captain ghost role + components: + - type: RandomHumanoidSpawner + settings: DisasterVictimCaptain + +- type: randomHumanoidSettings + id: DisasterVictimResearchDirector + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-disaster-victim-name + description: ghost-role-information-disaster-victim-description + rules: ghost-role-information-disaster-victim-rules + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ ResearchDirectorGear ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last + +- type: randomHumanoidSettings + id: DisasterVictimCMO + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-disaster-victim-name + description: ghost-role-information-disaster-victim-description + rules: ghost-role-information-disaster-victim-rules + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ CMOGear ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last + +- type: randomHumanoidSettings + id: DisasterVictimCaptain + randomizeName: false + components: + - type: GhostRole + name: ghost-role-information-disaster-victim-name + description: ghost-role-information-disaster-victim-description + rules: ghost-role-information-disaster-victim-rules + raffle: + settings: default + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ CaptainGear ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last + +# Syndie Disaster Victim + +- type: entity + name: syndie disaster victim spawner + id: SyndieDisasterVictimSpawner + parent: MarkerBase + components: + - type: Sprite + layers: + - state: red + - sprite: Structures/Decoration/banner.rsi + state: banner_syndicate + - type: RandomSpawner + prototypes: + - RandomHumanoidSyndieDisasterVictim + +- type: entity + id: RandomHumanoidSyndieDisasterVictim + name: syndie disaster victim ghost role + components: + - type: Sprite + sprite: Structures/Decoration/banner.rsi + state: banner_syndicate + - type: RandomHumanoidSpawner + settings: SyndieDisasterVictim + +- type: randomHumanoidSettings + id: SyndieDisasterVictim + randomizeName: false + components: + - type: NpcFactionMember + factions: + - Syndicate + - type: GhostRole + name: ghost-role-information-syndie-disaster-victim-name + description: ghost-role-information-syndie-disaster-victim-description + rules: ghost-role-information-syndie-disaster-victim-rules + raffle: + settings: short + - type: GhostTakeoverAvailable + - type: Loadout + prototypes: [ SyndicateOperativeGearCivilian ] + - type: RandomMetadata + nameSegments: + - names_first + - names_last diff --git a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml index b9f265e0bcf..b332f573fb5 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/reptilian.yml @@ -1,6 +1,7 @@ - type: entity save: false - name: Urisst' Mzhand + name: Urist McScales + suffix: Urisst' Mzhand parent: BaseMobReptilian id: MobReptilian diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml index 0b122df1c84..a3879c98ce1 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon_base.yml @@ -166,7 +166,6 @@ # damage: # types: # Blunt: 0.28 #per second, scales with pressure and other constants. - atmosTemperatureTransferEfficiency: 0.4 - type: Identity # soundHit: # path: /Audio/Effects/metalbreak.ogg @@ -202,11 +201,11 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.VoiceMaskUIKey.Key + enum.VoiceMaskUIKey.Key: type: VoiceMaskBoundUserInterface - - key: enum.HumanoidMarkingModifierKey.Key + enum.HumanoidMarkingModifierKey.Key: type: HumanoidMarkingModifierBoundUserInterface - - key: enum.StrippingUiKey.Key + enum.StrippingUiKey.Key: type: StrippableBoundUserInterface - type: Emoting - type: Grammar diff --git a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml index 5c2a88c1064..bb77cefad50 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/skeleton.yml @@ -11,6 +11,8 @@ - type: GhostRole name: ghost-role-information-skeleton-pirate-name description: ghost-role-information-skeleton-pirate-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Loadout prototypes: [PirateGear] @@ -25,6 +27,8 @@ - type: GhostRole name: ghost-role-information-skeleton-biker-name description: ghost-role-information-skeleton-biker-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Loadout prototypes: [SkeletonBiker] @@ -38,6 +42,8 @@ - type: GhostRole name: ghost-role-information-closet-skeleton-name description: ghost-role-information-closet-skeleton-description + raffle: + settings: default - type: GhostTakeoverAvailable - type: Loadout prototypes: [LimitedPassengerGear] diff --git a/Resources/Prototypes/Entities/Mobs/Player/terminator.yml b/Resources/Prototypes/Entities/Mobs/Player/terminator.yml deleted file mode 100644 index 663838e01ac..00000000000 --- a/Resources/Prototypes/Entities/Mobs/Player/terminator.yml +++ /dev/null @@ -1,203 +0,0 @@ -# stuff common to flesh and endoskeleton -- type: entity - abstract: true - id: MobTerminatorBase - components: - - type: ZombieImmune # yeah no - - type: FlashImmunity # no brain to brainwash, eyes are robotic - -- type: entity - parent: [MobHuman, MobTerminatorBase] - id: MobHumanTerminator - # uses random name generator dont worry - name: exterminator - components: - - type: Terminator - - type: GenericAntag - rule: Exterminator - # reduced barotrauma damage - - type: Barotrauma - damage: - types: - Blunt: 0.1 - # 4x stamina, faster recovery - - type: Stamina - decay: 6 - cooldown: 1 - critThreshold: 400 - # immune to space drugs, pax, temporary blindness - - type: StatusEffects - allowed: - - Stun - - KnockedDown - - SlowedDown - - Stutter - - Electrocution - - Drunk - - SlurredSpeech - - RatvarianLanguage - - PressureImmunity - - Muted - - ForcedSleep - - StaminaModifier - - type: MobState - allowedStates: - - Alive - - Dead - # endoskeleton need it - - type: TransferMindOnGib - - type: MobThresholds - thresholds: - 0: Alive - # used for health display its not possible to actually fall into crit - 200: Dead - # fire!!!! - - type: Flammable - damage: - types: - Heat: 6.0 - # slightly wider thresholds - - type: Temperature - heatDamageThreshold: 390 - coldDamageThreshold: 240 - # take terminator flesh damage - - type: Damageable - damageModifierSet: CyberneticFlesh - # only organ is an endoskeleton, which is transferred when flesh dies - - type: Body - prototype: TerminatorFlesh - # endoskeleton transformation when either you would get burned to crit or killed by any damage - # you will become an endoskeleton as your last chance to kill the target - - type: Destructible - thresholds: - # the burn trigger is first incase of a bombing or nuking, it might well do over 200 damage but 100 heat is more important - - trigger: - !type:DamageTypeTrigger - damageType: Heat - damage: 100 - behaviors: - - !type:PopupBehavior - popup: terminator-endoskeleton-burn-popup - popupType: LargeCaution - - !type:GibBehavior - - trigger: - !type:DamageTrigger - damage: 200 - behaviors: - - !type:PopupBehavior - popup: terminator-endoskeleton-gib-popup - popupType: LargeCaution - - !type:GibBehavior - # faster than humans when damaged - - type: SlowOnDamage - speedModifierThresholds: - 70: 0.8 - 90: 0.6 - # arnold is very strong - - type: MeleeWeapon - damage: - types: - Blunt: 10 - Structural: 10 - - type: RandomHumanoidAppearance - - type: Tag - tags: - - CanPilot - - FootstepSound - - DoorBumpOpener - - Unimplantable # no brain to mindshield, no organic body to implant into - -- type: entity - parent: - - BaseMob - - MobCombat - - MobDamageable - - MobSiliconBase - - MobTerminatorBase - id: MobTerminatorEndoskeleton - # you are now valid - name: nt-800 "exterminator" endoskeleton - description: The inner powerhouse of Susnet's infiltrator androids. Ridiculously hard alloy on the inside, unassuming flesh on the outside. - components: - - type: HumanoidAppearance - species: Terminator - - type: MovementSpeedModifier - baseWalkSpeed: 1.5 - baseSprintSpeed: 3.0 - - type: Sprite - sprite: Mobs/Species/Terminator/parts.rsi - - type: Fixtures - fixtures: - fix1: - shape: - !type:PhysShapeCircle - radius: 0.35 - # he heavy - density: 500 - mask: - - MobMask - layer: - - MobLayer - - type: MobThresholds - thresholds: - 0: Alive - # gibbed at 200 so cant go crit - 200: Dead - # incase some weird stuff happens and the crew adopts a terminator - - type: Repairable - doAfterDelay: 15 - allowSelfRepair: false - - type: Body - prototype: TerminatorEndoskeleton - # lets it sit in the terminator flesh's brain slot - - type: Organ - - type: Brain - - type: TypingIndicator - proto: robot # beep boop borp - - type: Speech - speechSounds: Pai - - type: Damageable - damageModifierSet: Cybernetic - - type: Destructible - thresholds: - - trigger: - !type:DamageTrigger - damage: 200 - behaviors: - - !type:PlaySoundBehavior - # endoSKELETON - sound: /Audio/Effects/bone_rattle.ogg - # a keepsake or a gift for cargo - - !type:SpawnEntitiesBehavior - spawn: - HeadTerminator: - min: 1 - max: 1 - - !type:DoActsBehavior - acts: [ "Destruction" ] - # for fire spreading around, the endoskeleton cannot burn - - type: Flammable - fireSpread: true - canResistFire: true - damage: - types: - Heat: 0 - # now his only weapon, but it is stronger - - type: MeleeWeapon - damage: - types: - Blunt: 15 - Structural: 5 - - type: Puller - needsHands: false - - type: Prying - pryPowered: true - force: true - - type: Tag - tags: - - DoorBumpOpener - - ShoesRequiredStepTriggerImmune - # let mind transfer on gib work - - MindTransferTarget - # its just metal so no implants - - Unimplantable diff --git a/Resources/Prototypes/Entities/Mobs/Player/vox.yml b/Resources/Prototypes/Entities/Mobs/Player/vox.yml index de1e3da2be7..e7ad39d7316 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/vox.yml @@ -1,5 +1,5 @@ - type: entity save: false - name: Vox + name: Urist McVox parent: BaseMobVox - id: MobVox + id: MobVox \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml index 2f6437dc14e..ef129d89eae 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachne.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachne.yml @@ -104,8 +104,8 @@ - type: Tag tags: - CanPilot - - ShoesRequiredStepTriggerImmune - DoorBumpOpener + - type: StepTriggerImmune - type: Bloodstream bloodReagent: DemonsBlood - type: BloodSucker diff --git a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml index c135ac2b829..bfb7796f44a 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/arachnid.yml @@ -64,6 +64,7 @@ - type: Speech speechVerb: Arachnid speechSounds: Arachnid + allowedEmotes: ['Click', 'Chitter'] - type: Vocal sounds: Male: UnisexArachnid diff --git a/Resources/Prototypes/Entities/Mobs/Species/base.yml b/Resources/Prototypes/Entities/Mobs/Species/base.yml index 7420f168ca6..271ef0c1bda 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/base.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/base.yml @@ -191,11 +191,11 @@ - type: Strippable - type: UserInterface interfaces: - - key: enum.VoiceMaskUIKey.Key + enum.VoiceMaskUIKey.Key: type: VoiceMaskBoundUserInterface - - key: enum.HumanoidMarkingModifierKey.Key + enum.HumanoidMarkingModifierKey.Key: type: HumanoidMarkingModifierBoundUserInterface - - key: enum.StrippingUiKey.Key + enum.StrippingUiKey.Key: type: StrippableBoundUserInterface - type: Puller - type: Speech @@ -381,5 +381,5 @@ requiredLegs: 2 - type: UserInterface interfaces: - - key: enum.HumanoidMarkingModifierKey.Key # sure, this can go here too + enum.HumanoidMarkingModifierKey.Key: # sure, this can go here too type: HumanoidMarkingModifierBoundUserInterface diff --git a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml index 4b75e65ca91..069ecb3eaf3 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/dwarf.yml @@ -51,6 +51,11 @@ accent: dwarf - type: Speech speechSounds: Bass + - type: HumanoidAppearance + species: Human + hideLayersOnEquip: + - Hair + - Snout - type: LanguageKnowledge speaks: - TauCetiBasic diff --git a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml index b928a7f04dc..b3c938fca46 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/harpy.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/harpy.yml @@ -114,7 +114,6 @@ - CanPilot - FootstepSound - DoorBumpOpener - - ShoesRequiredStepTriggerImmune - type: LanguageKnowledge speaks: - TauCetiBasic diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index 121cbd3ca78..013789cd2be 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -16,6 +16,11 @@ spawned: - id: FoodMeatHuman amount: 5 + - type: HumanoidAppearance + species: Human + hideLayersOnEquip: + - Hair + - Snout - type: LanguageKnowledge speaks: - TauCetiBasic diff --git a/Resources/Prototypes/Entities/Mobs/Species/moth.yml b/Resources/Prototypes/Entities/Mobs/Species/moth.yml index 7e5716a212f..fef380d1d56 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/moth.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/moth.yml @@ -23,6 +23,7 @@ accent: zombieMoth - type: Speech speechVerb: Moth + allowedEmotes: ['Chitter', 'Squeak'] - type: LanguageKnowledge speaks: - TauCetiBasic diff --git a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml index 3dfb5cb3267..b27b4c6029d 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/reptilian.yml @@ -33,9 +33,9 @@ proto: lizard - type: Vocal sounds: - Male: UnisexReptilian - Female: UnisexReptilian - Unsexed: UnisexReptilian + Male: MaleReptilian + Female: FemaleReptilian + Unsexed: MaleReptilian - type: Damageable damageContainer: Biological damageModifierSet: Scale diff --git a/Resources/Prototypes/Entities/Mobs/Species/slime.yml b/Resources/Prototypes/Entities/Mobs/Species/slime.yml index 2982cdb5b27..76b24033530 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/slime.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/slime.yml @@ -13,11 +13,37 @@ - type: Body prototype: Slime requiredLegs: 2 + # they like eat it idk lol + - type: Storage + clickInsert: false + grid: + - 0,0,1,2 + maxItemSize: Large + storageInsertSound: + path: /Audio/Voice/Slime/slime_squish.ogg + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] + - type: UserInterface + interfaces: + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + enum.VoiceMaskUIKey.Key: + type: VoiceMaskBoundUserInterface + enum.HumanoidMarkingModifierKey.Key: + type: HumanoidMarkingModifierBoundUserInterface + enum.StrippingUiKey.Key: + type: StrippableBoundUserInterface + # to prevent bag open/honk spam + - type: UseDelay + delay: 0.5 - type: HumanoidAppearance species: SlimePerson - type: Speech speechVerb: Slime speechSounds: Slime + allowedEmotes: ['Squish'] - type: TypingIndicator proto: slime - type: Vocal @@ -28,6 +54,16 @@ - type: Damageable damageContainer: Biological damageModifierSet: Slime + - type: Geras + - type: PassiveDamage # Around 8 damage a minute healed + allowedStates: + - Alive + damageCap: 65 + damage: + types: + Heat: -0.14 + groups: + Brute: -0.14 - type: DamageVisuals damageOverlayGroups: Brute: diff --git a/Resources/Prototypes/Entities/Mobs/Species/vox.yml b/Resources/Prototypes/Entities/Mobs/Species/vox.yml index a271e9d0846..ec8035563b7 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/vox.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/vox.yml @@ -16,6 +16,16 @@ #- type: VoxAccent # Not yet coded - type: Inventory speciesId: vox + displacements: + jumpsuit: + layer: + sprite: Mobs/Species/Vox/displacement.rsi + state: jumpsuit + copyToShaderParameters: + # Value required, provide a dummy. Gets overridden when applied. + layerKey: dummy + parameterTexture: displacementMap + parameterUV: displacementUV - type: Speech speechVerb: Vox speechSounds: Vox @@ -49,6 +59,49 @@ damage: types: Slash: 5 # Reduce? + - type: Sprite # Need to redefine the whole order to draw the tail over their gas tank + layers: + - map: [ "enum.HumanoidVisualLayers.Chest" ] + - map: [ "enum.HumanoidVisualLayers.Head" ] + - map: [ "enum.HumanoidVisualLayers.Snout" ] + - map: [ "enum.HumanoidVisualLayers.Eyes" ] + - map: [ "enum.HumanoidVisualLayers.RArm" ] + - map: [ "enum.HumanoidVisualLayers.LArm" ] + - map: [ "enum.HumanoidVisualLayers.RLeg" ] + - map: [ "enum.HumanoidVisualLayers.LLeg" ] + - map: [ "jumpsuit" ] + - map: [ "enum.HumanoidVisualLayers.LFoot" ] + - map: [ "enum.HumanoidVisualLayers.RFoot" ] + - map: [ "enum.HumanoidVisualLayers.LHand" ] + - map: [ "enum.HumanoidVisualLayers.RHand" ] + - map: [ "gloves" ] + - map: [ "shoes" ] + - map: [ "ears" ] + - map: [ "outerClothing" ] + - map: [ "eyes" ] + - map: [ "belt" ] + - map: [ "id" ] + - map: [ "neck" ] + - map: [ "back" ] + - map: [ "enum.HumanoidVisualLayers.FacialHair" ] + - map: [ "enum.HumanoidVisualLayers.Hair" ] + - map: [ "enum.HumanoidVisualLayers.HeadSide" ] + - map: [ "enum.HumanoidVisualLayers.HeadTop" ] + - map: [ "suitstorage" ] # This is not in the default order + - map: [ "enum.HumanoidVisualLayers.Tail" ] + - map: [ "mask" ] + - map: [ "head" ] + - map: [ "pocket1" ] + - map: [ "pocket2" ] + - map: [ "enum.HumanoidVisualLayers.Handcuffs" ] + color: "#ffffff" + sprite: Objects/Misc/handcuffs.rsi + state: body-overlay-2 + visible: false + - map: [ "clownedon" ] + sprite: "Effects/creampie.rsi" + state: "creampie_vox" # Not default + visible: false - type: entity parent: BaseSpeciesDummy diff --git a/Resources/Prototypes/Entities/Mobs/base.yml b/Resources/Prototypes/Entities/Mobs/base.yml index 6f25841f50d..73ce97d6bec 100644 --- a/Resources/Prototypes/Entities/Mobs/base.yml +++ b/Resources/Prototypes/Entities/Mobs/base.yml @@ -197,7 +197,7 @@ canResistFire: true damage: #per second, scales with number of fire 'stacks' types: - Heat: 3 + Heat: 1.5 - type: FireVisuals sprite: Mobs/Effects/onfire.rsi normalState: Generic_mob_burning diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml index e758022710b..40684d16cfd 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks-cartons.yml @@ -15,6 +15,9 @@ solutions: drink: maxVol: 50 + - type: PressurizedSolution + solution: drink + - type: Shakeable - type: Sprite state: icon - type: Item diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml index 743d9a17925..701b8ac28ef 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks.yml @@ -10,6 +10,8 @@ solutions: drink: maxVol: 30 + - type: MixableSolution + solution: drink - type: SolutionTransfer canChangeTransferAmount: true - type: Drink @@ -31,8 +33,8 @@ solution: drink - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: EmitSoundOnPickup sound: path: /Audio/SimpleStation14/Items/Handling/drinkglass_pickup.ogg @@ -541,6 +543,22 @@ sprite: Objects/Consumable/Drinks/bravebullglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: BudgetInsulsDrinkGlass + suffix: budget insuls + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: BudgetInsulsDrink + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/budgetinsulsdrink.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkCarrotJuice @@ -573,6 +591,22 @@ sprite: Objects/Consumable/Drinks/chocolateglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: RubberneckGlass + suffix: rubberneck + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: Rubberneck + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/rubberneck.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkCoconutRum @@ -1099,6 +1133,22 @@ sprite: Objects/Consumable/Drinks/icecreamglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: IrishBoolGlass + suffix: irish bool + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: IrishBool + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/beerglass.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkIrishCarBomb @@ -2093,6 +2143,22 @@ sprite: Objects/Consumable/Drinks/martiniglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: DrinkVodkaRedBool + suffix: vodka red bool + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: VodkaRedBool + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/ginvodkaglass.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkVodkaTonicGlass @@ -2139,6 +2205,22 @@ - ReagentId: JuiceWatermelon Quantity: 30 +- type: entity + parent: DrinkGlass + id: DrinkWatermelonWakeup + suffix: watermelon wakeup + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: WatermelonWakeup + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/champagneglass.rsi + state: icon + - type: entity parent: DrinkGlass id: DrinkWhiskeyColaGlass @@ -2219,6 +2301,22 @@ sprite: Objects/Consumable/Drinks/wineglass.rsi state: icon +- type: entity + parent: DrinkGlass + id: XenoBasherGlass + suffix: xeno basher + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 30 + reagents: + - ReagentId: XenoBasher + Quantity: 30 + - type: Icon + sprite: Objects/Consumable/Drinks/xenobasher.rsi + state: icon + # TODO: MOVE - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml index b2489325e0a..7a4983b14d5 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_bottles.yml @@ -42,6 +42,9 @@ - type: PhysicalComposition materialComposition: Plastic: 100 + - type: PressurizedSolution + solution: drink + - type: Shakeable - type: entity parent: DrinkBottlePlasticBaseFull @@ -371,6 +374,7 @@ - type: Tag tags: - Wine + - DrinkBottle - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -520,6 +524,7 @@ - type: Tag tags: - Wine + - DrinkBottle # Small Bottles @@ -545,6 +550,7 @@ - type: Tag tags: - Beer + - DrinkBottle - type: entity parent: [DrinkBottleVisualsAll, DrinkBottleGlassBaseFull] @@ -568,7 +574,7 @@ - type: Tag tags: - Beer - + - DrinkBottle - type: entity parent: [DrinkBottleVisualsAll, DrinkBottlePlasticBaseFull] diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml index a9ff1c784a9..319c8a634ed 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cans.yml @@ -6,7 +6,7 @@ components: - type: Drink - type: Openable - - type: PressurizedDrink + - type: Shakeable - type: SolutionContainerManager solutions: drink: @@ -14,13 +14,15 @@ - ReagentId: Cola Quantity: 30 maxVol: 30 + - type: MixableSolution + solution: drink - type: SolutionTransfer canChangeTransferAmount: true maxTransferAmount: 15 - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Sprite state: icon layers: @@ -34,6 +36,8 @@ solution: drink - type: DrainableSolution solution: drink + - type: PressurizedSolution + solution: drink - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml index c4693c6a719..46fb4d97260 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_cups.yml @@ -10,7 +10,8 @@ solutions: drink: maxVol: 20 - canMix: true + - type: MixableSolution + solution: drink - type: FitsInDispenser solution: drink - type: DrawableSolution @@ -24,8 +25,8 @@ maxTransferAmount: 10 - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Drink - type: Sprite state: icon diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml index 2fd2331f91e..ef6208b69d4 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_fun.yml @@ -146,6 +146,9 @@ - type: RandomFillSolution solution: drink weightedRandomId: RandomFillMopwata + - type: PressurizedSolution + solution: drink + - type: Shakeable - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml index 9a523c997b9..9c87995f5ec 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/drinks_special.yml @@ -8,7 +8,10 @@ solutions: drink: maxVol: 100 + - type: MixableSolution + solution: drink - type: Drink + - type: Shakeable # Doesn't do anything, but I mean... - type: FitsInDispenser solution: drink - type: DrawableSolution @@ -26,8 +29,8 @@ state: icon - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: PhysicalComposition materialComposition: Steel: 50 @@ -107,3 +110,63 @@ - type: Drink - type: Sprite sprite: Objects/Consumable/Drinks/jar_what.rsi + +- type: entity + id: BartenderMixer + abstract: true + components: + - type: DrainableSolution + solution: drink + - type: Drink + - type: DrawableSolution + solution: drink + - type: RefillableSolution + solution: drink + - type: SolutionTransfer + canChangeTransferAmount: true + - type: Spillable + solution: drink + - type: UserInterface + interfaces: + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface + +- type: entity + parent: [BaseItem, BartenderMixer] + id: DrinkJigger + name: jigger + description: Like a shaker, but smaller. Used to control the amount of ingredients. + components: + - type: SolutionContainerManager + solutions: + drink: + maxVol: 20 + - type: MixableSolution + solution: drink + - type: FitsInDispenser + solution: drink + - type: Sprite + sprite: Objects/Consumable/Drinks/jigger.rsi + state: icon + - type: PhysicalComposition + materialComposition: + Steel: 20 + +- type: entity + parent: [BaseItem, BartenderMixer] + id: DrinkIceBucket + name: ice bucket + description: A special bucket of refreshy ice. Prohibited use for challenge with the same name! + components: + - type: SolutionContainerManager + solutions: + drink: + reagents: + - ReagentId: Ice + Quantity: 200 + - type: Sprite + sprite: Objects/Consumable/Drinks/icebucket.rsi + state: icon + - type: PhysicalComposition + materialComposition: + Steel: 75 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml index aeaa54ccf1f..b78769034b8 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Drinks/trash_drinks.yml @@ -25,6 +25,8 @@ damage: types: Blunt: 0 + - type: MixableSolution + solution: drink - type: Spillable solution: drink - type: FitsInDispenser @@ -37,8 +39,8 @@ solution: drink - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: DamageOnLand damage: types: @@ -102,6 +104,8 @@ solutions: drink: maxVol: 50 + - type: MixableSolution + solution: drink - type: SolutionTransfer canChangeTransferAmount: true maxTransferAmount: 5 @@ -118,8 +122,8 @@ solution: drink - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Damageable damageContainer: Inorganic - type: Destructible @@ -214,12 +218,12 @@ - type: entity - name: goldschlager bottle + name: gildlager bottle parent: DrinkBottleBaseEmpty - id: DrinkBottleGoldschlager + id: DrinkBottleGildlager components: - type: Sprite - sprite: Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi + sprite: Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/bread.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/bread.yml index 32a1815ac7c..e40ac40a289 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/bread.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/bread.yml @@ -810,6 +810,8 @@ allowMovement: true description: ghost-role-information-BreadDog-description rules: ghost-role-information-BreadDog-rules + raffle: + settings: short - type: GhostTakeoverAvailable - type: BarkAccent - type: Speech @@ -827,6 +829,7 @@ - type: Puller needsHands: false - type: Examiner + - type: DoAfter - type: CombatMode - type: MeleeWeapon soundHit: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml index 71b38959ce3..c939dec52c6 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Baked/cake.yml @@ -672,6 +672,8 @@ allowMovement: true description: ghost-role-information-Cak-description rules: ghost-role-information-Cak-rules + raffle: + settings: short - type: GhostTakeoverAvailable - type: OwOAccent - type: Speech @@ -689,6 +691,7 @@ - type: Puller needsHands: false - type: Examiner + - type: DoAfter - type: CombatMode - type: MeleeWeapon soundHit: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml index 45953296351..40cb141af78 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/bowl.yml @@ -19,6 +19,8 @@ - map: ["enum.SolutionContainerLayers.Fill"] state: fill-1 visible: false + - type: MixableSolution + solution: food - type: DamageOnLand damage: types: @@ -35,8 +37,8 @@ canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml index 966ae86db1e..aa9e70f3fa4 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/Containers/box.yml @@ -567,7 +567,6 @@ - type: Tag tags: - Trash - - HappyHonk - MimeHappyHonk - type: Sprite sprite: Objects/Storage/Happyhonk/mime.rsi @@ -664,6 +663,10 @@ name: woeful cluwne meal description: Nothing good can come of this. components: + - type: Tag + tags: + - Trash + - CluwneHappyHonk - type: Sprite sprite: Objects/Storage/Happyhonk/cluwne.rsi state: box diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml index 930d7fa64dc..3bf253f773b 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Food/produce.yml @@ -1136,9 +1136,9 @@ Quantity: 1 - type: entity - name: chili + name: chili pepper parent: FoodProduceBase - id: FoodChili + id: FoodChiliPepper description: Spicy, best not touch your eyes. components: - type: FlavorProfile @@ -1166,7 +1166,7 @@ - type: entity name: chilly pepper parent: FoodProduceBase - id: FoodChilly + id: FoodChillyPepper description: Icy hot. components: - type: FlavorProfile @@ -1872,3 +1872,36 @@ tags: - ClothMade - CottonBoll + +- type: entity + name: pyrotton boll + description: This will probably set you on fire. + id: PyrottonBol + parent: FoodProduceBase + components: + - type: Sprite + sprite: Objects/Specific/Hydroponics/pyrotton.rsi + - type: FlavorProfile + flavors: + - pyrotton + - type: Food + requiresSpecialDigestion: true + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: Fiber + Quantity: 5 + - ReagentId: Phlogiston + Quantity: 5 + - type: Log + spawnedPrototype: MaterialPyrotton1 + spawnCount: 2 + - type: Produce + seedId: pyrotton + - type: Tag + tags: + - ClothMade + - CottonBoll + - type: Extractable + grindableSolutionName: food diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml index e3ae06ec9f5..9a0d96e89ea 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Cigarettes/joints.yml @@ -28,6 +28,34 @@ reagents: - ReagentId: THC Quantity: 20 + +- type: entity + id: JointRainbow + parent: Joint + name: joint + suffix: Rainbow + description: A roll of dried plant matter wrapped in thin paper. Seems to be colorful inside. + components: + - type: Construction + graph: smokeableJointRainbow + node: jointRainbow + - type: SolutionContainerManager + solutions: + smokable: + maxVol: 20 + reagents: + - ReagentId: SpaceDrugs + Quantity: 4 + - ReagentId: Lipolicide + Quantity: 4 + - ReagentId: MindbreakerToxin + Quantity: 2.66 + - ReagentId: Happiness + Quantity: 2.66 +# - ReagentId: ColorfulReagent +# Quantity: 1.33 + - ReagentId: Psicodine + Quantity: 0.8 - type: entity id: Blunt @@ -59,3 +87,31 @@ reagents: - ReagentId: THC Quantity: 20 + +- type: entity + id: BluntRainbow + parent: Blunt + name: blunt + suffix: Rainbow + description: A roll of dried plant matter wrapped in a dried tobacco leaf. Seems to be colorful inside. + components: + - type: Construction + graph: smokeableBluntRainbow + node: bluntRainbow + - type: SolutionContainerManager + solutions: + smokable: + maxVol: 20 + reagents: + - ReagentId: SpaceDrugs + Quantity: 4 + - ReagentId: Lipolicide + Quantity: 4 + - ReagentId: MindbreakerToxin + Quantity: 2.66 + - ReagentId: Happiness + Quantity: 2.66 +# - ReagentId: ColorfulReagent +# Quantity: 1.33 + - ReagentId: Psicodine + Quantity: 0.8 diff --git a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Pipes/pipe.yml b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Pipes/pipe.yml index c3f13d80b75..79c568802c5 100644 --- a/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Pipes/pipe.yml +++ b/Resources/Prototypes/Entities/Objects/Consumable/Smokeables/Pipes/pipe.yml @@ -63,3 +63,26 @@ path: /Audio/Weapons/Guns/Empty/empty.ogg ejectSound: path: /Audio/Weapons/Guns/Empty/empty.ogg + +- type: entity + id: SmokingPipeFilledCannabisRainbow + parent: SmokingPipe + name: pipe + suffix: Rainbow Cannabis + description: Just like grandpappy used to smoke. + components: + - type: ContainerContainer + containers: + bowl_slot: !type:ContainerSlot + - type: ItemSlots + - type: SmokingPipe + bowl_slot: + name: smoking-pipe-slot-component-slot-name-bowl + startingItem: GroundCannabisRainbow + whitelist: + tags: + - Smokable + insertSound: + path: /Audio/Weapons/Guns/Empty/empty.ogg + ejectSound: + path: /Audio/Weapons/Guns/Empty/empty.ogg diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml index 164777284fa..360fc5ffaa3 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/base_machineboard.yml @@ -15,7 +15,7 @@ price: 100 - type: PhysicalComposition materialComposition: - Glass: 400 + Glass: 230 chemicalComposition: Silicon: 20 diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml index 891dfc1e794..a34af1c9d82 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml @@ -164,6 +164,28 @@ DefaultPrototype: Beaker ExamineName: Glass Beaker +- type: entity + parent: BaseMachineCircuitboard + id: CircuitImprinterHyperConvectionMachineCircuitboard + name: hyper convection circuit imprinter machine board + description: A machine printed circuit board for a hyper convection circuit imprinter. + components: + - type: Sprite + state: science + - type: MachineBoard + prototype: CircuitImprinterHyperConvection + requirements: + MatterBin: 2 + tagRequirements: + GlassBeaker: + Amount: 2 + DefaultPrototype: Beaker + ExamineName: Glass Beaker + Igniter: + Amount: 1 + DefaultPrototype: Igniter + ExamineName: Igniter + - type: entity id: ExosuitFabricatorMachineCircuitboard parent: BaseMachineCircuitboard @@ -281,27 +303,6 @@ recipes: - ArtifactAnalyzerMachineCircuitboard -- type: entity - id: TraversalDistorterMachineCircuitboard - parent: BaseMachineCircuitboard - name: traversal distorter machine board - description: A machine printed circuit board for a traversal distorter. - components: - - type: Sprite - state: science - - type: MachineBoard - prototype: MachineTraversalDistorter - requirements: - Manipulator: 1 - Capacitor: 2 - materialRequirements: - Steel: 5 - Cable: 1 - - type: ReverseEngineering # Nyano - difficulty: 2 - recipes: - - TraversalDistorterMachineCircuitboard - - type: entity id: ArtifactCrusherMachineCircuitboard parent: BaseMachineCircuitboard @@ -1624,3 +1625,23 @@ recipes: - JukeboxCircuitBoard +- type: entity + id: TraversalDistorterMachineCircuitboard + parent: BaseMachineCircuitboard + name: traversal distorter machine board + description: A machine printed circuit board for a traversal distorter. + components: + - type: Sprite + state: science + - type: MachineBoard + prototype: MachineTraversalDistorter + requirements: + Manipulator: 1 + Capacitor: 2 + materialRequirements: + Steel: 5 + Cable: 1 + - type: ReverseEngineering # Nyano + difficulty: 2 + recipes: + - TraversalDistorterMachineCircuitboard diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml index 35a941e759c..7681a459cb1 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/computer.yml @@ -14,7 +14,7 @@ price: 100 - type: PhysicalComposition materialComposition: - Glass: 400 + Glass: 230 chemicalComposition: Silicon: 20 @@ -427,3 +427,14 @@ state: cpu_engineering - type: ComputerBoard prototype: ComputerSensorMonitoring + +- type: entity + parent: BaseComputerCircuitboard + id: RoboticsConsoleCircuitboard + name: robotics control console board + description: A computer printed circuit board for a robotics control console. + components: + - type: Sprite + state: cpu_science + - type: ComputerBoard + prototype: ComputerRoboticsControl diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/door.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/door.yml index b761ef7996f..4d7dfed334b 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/door.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/door.yml @@ -19,10 +19,10 @@ - type: AccessReader - type: ActivatableUI key: enum.DoorElectronicsConfigurationUiKey.Key - allowedItems: + requiredItems: tags: - DoorElectronicsConfigurator - type: UserInterface interfaces: - - key: enum.DoorElectronicsConfigurationUiKey.Key - type: DoorElectronicsBoundUserInterface + enum.DoorElectronicsConfigurationUiKey.Key: + type: DoorElectronicsBoundUserInterface diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/door_access.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/door_access.yml index ec8148f7d9d..2ca77e03e91 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/door_access.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/door_access.yml @@ -1,115 +1,117 @@ - +# Command - type: entity parent: DoorElectronics - id: DoorElectronicsService - suffix: Service, Locked + id: DoorElectronicsCaptain + suffix: Captain, Locked components: - type: AccessReader - access: [["Service"]] + access: [["Captain"]] - type: entity parent: DoorElectronics - id: DoorElectronicsTheatre - suffix: Theatre, Locked + id: DoorElectronicsHeadOfPersonnel + suffix: HeadOfPersonnel, Locked components: - type: AccessReader - access: [["Theatre"]] + access: [["HeadOfPersonnel"]] - type: entity parent: DoorElectronics - id: DoorElectronicsChapel - suffix: Chapel, Locked + id: DoorElectronicsCommand + suffix: Command, Locked components: - type: AccessReader - access: [["Chapel"]] + access: [["Command"]] +# Service - type: entity parent: DoorElectronics - id: DoorElectronicsJanitor - suffix: Janitor, Locked + id: DoorElectronicsBar + suffix: Bar, Locked components: - type: AccessReader - access: [["Janitor"]] + access: [["Bar"]] - type: entity parent: DoorElectronics - id: DoorElectronicsKitchen - suffix: Kitchen, Locked + id: DoorElectronicsBarKitchen + suffix: Bar, Locked components: - type: AccessReader - access: [["Kitchen"]] + access: [["Bar"], ["Kitchen"]] - type: entity parent: DoorElectronics - id: DoorElectronicsBar - suffix: Bar, Locked + id: DoorElectronicsHydroponics + suffix: Hydroponics, Locked components: - type: AccessReader - access: [["Bar"]] + access: [["Hydroponics"]] - type: entity parent: DoorElectronics - id: DoorElectronicsHydroponics - suffix: Hydroponics, Locked + id: DoorElectronicsChapel + suffix: Chapel, Locked components: - type: AccessReader - access: [["Hydroponics"]] + access: [["Chapel"]] - type: entity parent: DoorElectronics - id: DoorElectronicsLawyer - suffix: Lawyer, Locked + id: DoorElectronicsTheatre + suffix: Theatre, Locked components: - type: AccessReader - access: [["Lawyer"]] + access: [["Theatre"]] - type: entity parent: DoorElectronics - id: DoorElectronicsCaptain - suffix: Captain, Locked + id: DoorElectronicsKitchen + suffix: Kitchen, Locked components: - type: AccessReader - access: [["Captain"]] + access: [["Kitchen"]] - type: entity parent: DoorElectronics - id: DoorElectronicsExternal - suffix: External, Locked + id: DoorElectronicsKitchenHydroponics + suffix: Kitchen/Hydroponics, Locked components: - type: AccessReader - access: [["External"]] + access: [["Kitchen"], ["Hydroponics"]] - type: entity parent: DoorElectronics - id: DoorElectronicsCargo - suffix: Cargo, Locked + id: DoorElectronicsJanitor + suffix: Janitor, Locked components: - type: AccessReader - access: [["Cargo"]] + access: [["Janitor"]] - type: entity parent: DoorElectronics - id: DoorElectronicsEngineering - suffix: Engineering, Locked + id: DoorElectronicsLawyer + suffix: Lawyer, Locked components: - type: AccessReader - access: [["Engineering"]] + access: [["Lawyer"]] - type: entity parent: DoorElectronics - id: DoorElectronicsAtmospherics - suffix: Atmospherics, Locked + id: DoorElectronicsService + suffix: Service, Locked components: - type: AccessReader - access: [["Atmospherics"]] + access: [["Service"]] +# Cargo - type: entity parent: DoorElectronics - id: DoorElectronicsFreezer - suffix: Freezer, Locked + id: DoorElectronicsQuartermaster + suffix: Quartermaster, Locked components: - type: AccessReader - access: [["Kitchen"], ["Hydroponics"]] + access: [["Quartermaster"]] - type: entity parent: DoorElectronics @@ -121,68 +123,71 @@ - type: entity parent: DoorElectronics - id: DoorElectronicsMedical - suffix: Medical, Locked + id: DoorElectronicsCargo + suffix: Cargo, Locked components: - type: AccessReader - access: [["Medical"]] + access: [["Cargo"]] +# Engineering - type: entity parent: DoorElectronics - id: DoorElectronicsChemistry - suffix: Chemistry, Locked + id: DoorElectronicsChiefEngineer + suffix: ChiefEngineer, Locked components: - type: AccessReader - access: [["Chemistry"]] + access: [["ChiefEngineer"]] - type: entity parent: DoorElectronics - id: DoorElectronicsResearch - suffix: Research, Locked + id: DoorElectronicsAtmospherics + suffix: Atmospherics, Locked components: - type: AccessReader - access: [["Research"]] + access: [["Atmospherics"]] - type: entity parent: DoorElectronics - id: DoorElectronicsScience - suffix: Science, Locked + id: DoorElectronicsEngineering + suffix: Engineering, Locked components: - type: AccessReader - access: [["Research"], ["Medical"]] + access: [["Engineering"]] +# Science - type: entity parent: DoorElectronics - id: DoorElectronicsCommand - suffix: Command, Locked + id: DoorElectronicsMorgue + suffix: Morgue, Locked components: - type: AccessReader - access: [["Command"]] + access: [["Medical"], ["Detective"], ["Chapel"]] - type: entity parent: DoorElectronics - id: DoorElectronicsCentralCommand - suffix: CentralCommand, Locked + id: DoorElectronicsResearchDirector + suffix: ResearchDirector, Locked components: - type: AccessReader - access: [["CentralCommand"]] + access: [["ResearchDirector"]] - type: entity parent: DoorElectronics - id: DoorElectronicsChiefMedicalOfficer - suffix: ChiefMedicalOfficer, Locked + id: DoorElectronicsMedicalResearch + suffix: Medical/Science, Locked components: - type: AccessReader - access: [["ChiefMedicalOfficer"]] + access: [["Research"], ["Medical"]] - type: entity parent: DoorElectronics - id: DoorElectronicsChiefEngineer - suffix: ChiefEngineer, Locked + id: DoorElectronicsResearch + suffix: Research, Locked components: - type: AccessReader - access: [["ChiefEngineer"]] + access: [["Research"]] +# Security - type: entity parent: DoorElectronics id: DoorElectronicsHeadOfSecurity @@ -193,27 +198,19 @@ - type: entity parent: DoorElectronics - id: DoorElectronicsResearchDirector - suffix: ResearchDirector, Locked - components: - - type: AccessReader - access: [["ResearchDirector"]] - -- type: entity - parent: DoorElectronics - id: DoorElectronicsHeadOfPersonnel - suffix: HeadOfPersonnel, Locked + id: DoorElectronicsArmory + suffix: Armory, Locked components: - type: AccessReader - access: [["HeadOfPersonnel"]] + access: [["Armory"]] - type: entity parent: DoorElectronics - id: DoorElectronicsQuartermaster - suffix: Quartermaster, Locked + id: DoorElectronicsDetective + suffix: Detective, Locked components: - type: AccessReader - access: [["Quartermaster"]] + access: [["Detective"]] - type: entity parent: DoorElectronics @@ -233,43 +230,45 @@ - type: entity parent: DoorElectronics - id: DoorElectronicsDetective - suffix: Detective, Locked + id: DoorElectronicsBrig + suffix: Brig, Locked components: - type: AccessReader - access: [["Detective"]] + access: [["Brig"]] -#- type: entity -# parent: DoorElectronics -# id: DoorElectronicsBrig -# suffix: Brig, Locked -# components: -# - type: AccessReader -# access: [["Brig"]] +# Medical +- type: entity + parent: DoorElectronics + id: DoorElectronicsChiefMedicalOfficer + suffix: ChiefMedicalOfficer, Locked + components: + - type: AccessReader + access: [["ChiefMedicalOfficer"]] - type: entity parent: DoorElectronics - id: DoorElectronicsArmory - suffix: Armory, Locked + id: DoorElectronicsChemistry + suffix: Chemistry, Locked components: - type: AccessReader - access: [["Armory"]] + access: [["Chemistry"]] - type: entity parent: DoorElectronics - id: DoorElectronicsVault - suffix: Vault, Locked + id: DoorElectronicsMedical + suffix: Medical, Locked components: - type: AccessReader - access: [["Security"], ["Command"]] + access: [["Medical"]] +# Syndicate - type: entity parent: DoorElectronics - id: DoorElectronicsMaintenance - suffix: Maintenance, Locked + id: DoorElectronicsNukeop + suffix: Nukeop, Locked components: - type: AccessReader - access: [["Maintenance"]] + access: [["NuclearOperative"]] - type: entity parent: DoorElectronics @@ -279,21 +278,38 @@ - type: AccessReader access: [["SyndicateAgent"]] +# Misc - type: entity parent: DoorElectronics - id: DoorElectronicsNukeop - suffix: Nukeop, Locked + id: DoorElectronicsCentralCommand + suffix: CentralCommand, Locked components: - type: AccessReader - access: [["NuclearOperative"]] + access: [["CentralCommand"]] - type: entity parent: DoorElectronics - id: DoorElectronicsRnDMed - suffix: Medical/Science, Locked + id: DoorElectronicsExternal + suffix: External, Locked components: - type: AccessReader - access: [["Research"], ["Medical"]] + access: [["External"]] + +- type: entity + parent: DoorElectronics + id: DoorElectronicsMaintenance + suffix: Maintenance, Locked + components: + - type: AccessReader + access: [["Maintenance"]] + +- type: entity + parent: DoorElectronics + id: DoorElectronicsVault + suffix: Vault, Locked + components: + - type: AccessReader + access: [["Security"], ["Command"]] - type: entity parent: DoorElectronics diff --git a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml index 43ed20c694c..2cb9b5233d0 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Electronics/triggers.yml @@ -18,6 +18,8 @@ state: timer - type: Item size: Small + - type: StaticPrice + price: 40 - type: PayloadTrigger components: - type: OnUseTimerTrigger @@ -28,8 +30,6 @@ path: /Audio/Machines/Nuke/general_beep.ogg params: volume: -2 - - type: StaticPrice - price: 40 - type: entity parent: TimerTrigger @@ -40,6 +40,11 @@ - type: Sprite sprite: Objects/Devices/signaltrigger.rsi state: signaltrigger + - type: StaticPrice + price: 40 + - type: Tag + tags: + - SignalTrigger - type: PayloadTrigger components: - type: TriggerOnSignal @@ -49,8 +54,6 @@ - type: WirelessNetworkConnection range: 200 - type: DeviceLinkSink - - type: StaticPrice - price: 40 - type: entity parent: BaseItem @@ -61,11 +64,11 @@ - type: Sprite sprite: Objects/Devices/voice.rsi state: voice - - type: PayloadTrigger - components: - - type: TriggerOnVoice - type: StaticPrice price: 40 - type: Tag tags: - VoiceTrigger + - type: PayloadTrigger + components: + - type: TriggerOnVoice diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index a8489866fc7..660a8c9e60c 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -12,6 +12,8 @@ name: ghost-role-information-syndicate-reinforcement-name description: ghost-role-information-syndicate-reinforcement-description rules: ghost-role-information-syndicate-reinforcement-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobHumanSyndicateAgent - type: EmitSoundOnUse @@ -29,24 +31,28 @@ - type: entity parent: ReinforcementRadioSyndicate - id: ReinforcementRadioSyndicateMonkey - name: syndicate monkey reinforcement radio - description: Calls in a specially trained monkey to assist you. + id: ReinforcementRadioSyndicateAncestor + name: syndicate genetic ancestor reinforcement radio + description: Calls in a specially trained ancestor of your choosing to assist you. components: - type: GhostRole name: ghost-role-information-syndicate-monkey-reinforcement-name description: ghost-role-information-syndicate-monkey-reinforcement-description rules: ghost-role-information-syndicate-monkey-reinforcement-rules + raffle: + settings: default - type: GhostRoleMobSpawner prototype: MobMonkeySyndicateAgent + selectablePrototypes: ["SyndicateMonkey", "SyndicateKobold"] - type: entity - parent: ReinforcementRadioSyndicateMonkey - id: ReinforcementRadioSyndicateMonkeyNukeops # Reinforcement radio exclusive to nukeops uplink + parent: ReinforcementRadioSyndicateAncestor + id: ReinforcementRadioSyndicateAncestorNukeops # Reinforcement radio exclusive to nukeops uplink suffix: NukeOps components: - type: GhostRoleMobSpawner prototype: MobMonkeySyndicateAgentNukeops + selectablePrototypes: ["SyndicateMonkeyNukeops", "SyndicateKoboldNukeops"] - type: entity parent: ReinforcementRadioSyndicate @@ -59,5 +65,7 @@ name: Syndicate Assault Cyborg description: Nuclear operatives needs reinforcements. You, a cold silicon killing machine, will help them. rules: Normal syndicate antagonist rules apply. Work with whoever called you in, and don't harm them. + raffle: + settings: default - type: GhostRoleMobSpawner prototype: PlayerBorgSyndicateAssaultBattery diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/war_declarator.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/war_declarator.yml index 08e96d1de2b..78009f10422 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/war_declarator.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/war_declarator.yml @@ -14,11 +14,11 @@ - type: ActivatableUI inHandsOnly: true singleUser: true - closeOnHandDeselect: false + requireActiveHand: false key: enum.WarDeclaratorUiKey.Key - type: UserInterface interfaces: - - key: enum.WarDeclaratorUiKey.Key + enum.WarDeclaratorUiKey.Key: type: WarDeclaratorBoundUserInterface - type: WarDeclarator message: war-declarator-default-message diff --git a/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml new file mode 100644 index 00000000000..e0212810210 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Devices/chameleon_projector.yml @@ -0,0 +1,71 @@ +- type: entity + parent: BaseItem + id: ChameleonProjector + name: chameleon projector + description: Holoparasite technology used to create a hard-light replica of any object around you. Disguise is destroyed when picked up or deactivated. + components: + - type: Sprite + sprite: /Textures/Objects/Devices/chameleon_projector.rsi + state: icon + - type: ChameleonProjector + whitelist: + components: + - Anchorable + - Item + blacklist: + components: + - ChameleonDisguise # no becoming kleiner + - InsideEntityStorage # no clark kent going in phone booth and becoming superman + - MindContainer # no + - Pda # PDAs currently make you invisible /!\ + polymorph: + entity: ChameleonDisguise + +- type: entity + noSpawn: true + parent: BaseMob + id: ChameleonDisguise + name: Urist McKleiner + components: + # this and the name/desc get replaced, this is just placeholder incase something goes wrong + - type: Sprite + sprite: /Textures/Mobs/Species/Human/parts.rsi + state: full + # so people can attempt to pick it up + - type: Item + # so it can take damage + # projector system sets health to be proportional to mass + - type: Damageable + - type: MobState + - type: MobThresholds + thresholds: + 0: Alive + 1: Critical + 200: Dead + - type: MovementSpeedModifier + baseWalkSpeed: 1 # precise movement for the perfect spot + baseSprintSpeed: 5 # the jig is up + - type: ChameleonDisguise + +# actions +- type: entity + noSpawn: true + id: ActionDisguiseNoRot + name: Toggle Rotation + description: Use this to prevent your disguise from rotating, making it easier to hide in some scenarios. + components: + - type: InstantAction + icon: Interface/VerbIcons/refresh.svg.192dpi.png + event: !type:DisguiseToggleNoRotEvent + +- type: entity + noSpawn: true + id: ActionDisguiseAnchor + name: Toggle Anchored + description: For many objects you will want to be anchored to not be completely obvious. + components: + - type: InstantAction + icon: + sprite: Objects/Tools/wrench.rsi + state: icon + event: !type:DisguiseToggleAnchoredEvent diff --git a/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml b/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml index 5499348bd19..2aecd132880 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/flatpack.yml @@ -110,6 +110,20 @@ - type: GuideHelp guides: [ Singularity, Power ] +- type: entity + parent: BaseFlatpack + id: EmitterFlatpack + name: emitter flatpack + description: A flatpack used for constructing an emitter. + components: + - type: Flatpack + entity: Emitter + - type: Sprite + layers: + - state: emitter + - type: GuideHelp + guides: [ Singularity, Power ] + - type: entity parent: BaseFlatpack id: TeslaGeneratorFlatpack diff --git a/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml b/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml index 7436ae7c988..170751766be 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/forensic_scanner.yml @@ -17,11 +17,11 @@ - type: ActivatableUI key: enum.ForensicScannerUiKey.Key inHandsOnly: true - closeOnHandDeselect: false + requireActiveHand: false - type: UserInterface interfaces: - - key: enum.ForensicScannerUiKey.Key - type: ForensicScannerBoundUserInterface + enum.ForensicScannerUiKey.Key: + type: ForensicScannerBoundUserInterface - type: ForensicScanner - type: GuideHelp guides: diff --git a/Resources/Prototypes/Entities/Objects/Devices/geiger.yml b/Resources/Prototypes/Entities/Objects/Devices/geiger.yml index de4178ce7fa..f8ee24c5c60 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/geiger.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/geiger.yml @@ -31,4 +31,7 @@ Med: {state: geiger_on_med} High: {state: geiger_on_high} Extreme: {state: geiger_on_ext} + - type: PhysicalComposition + materialComposition: + Plastic: 100 diff --git a/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml b/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml index a93cd545bfc..d20f3c2fb17 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/mousetrap.yml @@ -18,7 +18,7 @@ - Mousetrap - type: Mousetrap - type: TriggerOnStepTrigger - - type: ShoesRequiredStepTrigger + - type: ClothingRequiredStepTrigger - type: DamageUserOnTrigger damage: types: diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 1a388997835..8f3523426eb 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -86,19 +86,18 @@ - type: ActivatableUI key: enum.PdaUiKey.Key singleUser: true - closeOnHandDeselect: false - type: UserInterface interfaces: - - key: enum.PdaUiKey.Key - type: PdaBoundUserInterface - - key: enum.StoreUiKey.Key - type: StoreBoundUserInterface - - key: enum.RingerUiKey.Key - type: RingerBoundUserInterface - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface - - key: enum.HealthAnalyzerUiKey.Key - type: HealthAnalyzerBoundUserInterface + enum.PdaUiKey.Key: + type: PdaBoundUserInterface + enum.StoreUiKey.Key: + type: StoreBoundUserInterface + enum.RingerUiKey.Key: + type: RingerBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface + enum.HealthAnalyzerUiKey.Key: + type: HealthAnalyzerBoundUserInterface - type: Tag tags: - DoorBumpOpener diff --git a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml index f5e46bbf54e..4d36af44592 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pinpointer.yml @@ -57,6 +57,11 @@ - type: Sprite layers: - state: pinpointer-syndicate + map: ["enum.PinpointerLayers.Base"] + - state: pinonnull + map: ["enum.PinpointerLayers.Screen"] + shader: unshaded + visible: false - type: Icon state: pinpointer-syndicate - type: Pinpointer @@ -72,6 +77,11 @@ - type: Sprite layers: - state: pinpointer-way + map: ["enum.PinpointerLayers.Base"] + - state: pinonnull + map: ["enum.PinpointerLayers.Screen"] + shader: unshaded + visible: false - type: Icon state: pinpointer-way - type: Pinpointer @@ -88,8 +98,13 @@ - type: Sprite layers: - state: pinpointer-station + map: ["enum.PinpointerLayers.Base"] + - state: pinonnull + map: ["enum.PinpointerLayers.Screen"] + shader: unshaded + visible: false - type: Icon state: pinpointer-station - type: Pinpointer - component: BecomesStation + component: ResearchServer targetName: the station diff --git a/Resources/Prototypes/Entities/Objects/Devices/radio.yml b/Resources/Prototypes/Entities/Objects/Devices/radio.yml index 74c2865d07d..43f84fe404e 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/radio.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/radio.yml @@ -23,3 +23,20 @@ - type: Tag tags: - Radio + +- type: entity + name: security radio + description: A handy security radio. + parent: RadioHandheld + id: RadioHandheldSecurity + components: + - type: RadioMicrophone + broadcastChannel: Security + - type: RadioSpeaker + channels: + - Security + - type: Sprite + sprite: Objects/Devices/securityhandy.rsi + - type: Item + sprite: Objects/Devices/securityhandy.rsi + heldPrefix: walkietalkie \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml index 9afef7abc71..28d6ddea691 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/station_beacon.yml @@ -30,8 +30,8 @@ singleUser: true - type: UserInterface interfaces: - - key: enum.NavMapBeaconUiKey.Key - type: NavMapBeaconBoundUserInterface + enum.NavMapBeaconUiKey.Key: + type: NavMapBeaconBoundUserInterface - type: Item size: Small - type: SubFloorHide diff --git a/Resources/Prototypes/Entities/Objects/Devices/station_map.yml b/Resources/Prototypes/Entities/Objects/Devices/station_map.yml index c37d8935f35..0d2f890a1d3 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/station_map.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/station_map.yml @@ -28,7 +28,7 @@ acts: [ "Destruction" ] - type: UserInterface interfaces: - - key: enum.StationMapUiKey.Key + enum.StationMapUiKey.Key: type: StationMapBoundUserInterface - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml b/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml index 09b41d6e5d7..7d342eed822 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/Instruments/base_instruments.yml @@ -13,8 +13,8 @@ key: enum.InstrumentUiKey.Key - type: UserInterface interfaces: - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface - type: Item size: Normal - type: StaticPrice @@ -51,8 +51,8 @@ acts: ["Destruction"] - type: UserInterface interfaces: - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface - type: Fixtures fixtures: fix1: diff --git a/Resources/Prototypes/Entities/Objects/Fun/candy_bucket.yml b/Resources/Prototypes/Entities/Objects/Fun/candy_bucket.yml index d8f11cdea29..63175dc89aa 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/candy_bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/candy_bucket.yml @@ -36,8 +36,8 @@ ents: [] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface # to prevent bag open/honk spam - type: UseDelay delay: 0.5 diff --git a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml index cb755b161a6..4aab2efdb97 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/crayons.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/crayons.yml @@ -18,8 +18,8 @@ - type: SpaceGarbage - type: UserInterface interfaces: - - key: enum.CrayonUiKey.Key - type: CrayonBoundUserInterface + enum.CrayonUiKey.Key: + type: CrayonBoundUserInterface - type: Crayon capacity: 15 - type: Food diff --git a/Resources/Prototypes/Entities/Objects/Fun/dice.yml b/Resources/Prototypes/Entities/Objects/Fun/dice.yml index f7395ef9ca6..bca5ec7ab99 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/dice.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/dice.yml @@ -124,7 +124,7 @@ - Shard intersectRatio: 0.2 - type: TriggerOnStepTrigger - - type: ShoesRequiredStepTrigger + - type: ClothingRequiredStepTrigger - type: Slippery slipSound: path: /Audio/Effects/glass_step.ogg diff --git a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml index 7ff6c43e29b..91063a5a15c 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/immovable_rod.yml @@ -35,6 +35,7 @@ - type: entity id: ImmovableRodDespawn + suffix: Despawn parent: ImmovableRod components: - type: TimedDespawn diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 537562f4618..1b9c5303c6b 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -13,10 +13,12 @@ program: 2 - type: UserInterface interfaces: - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface - - key: enum.StationMapUiKey.Key - type: UntrackedStationMapBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface + requireInputValidation: false + enum.StationMapUiKey.Key: + type: UntrackedStationMapBoundUserInterface + requireInputValidation: false - type: Sprite sprite: Objects/Fun/pai.rsi layers: diff --git a/Resources/Prototypes/Entities/Objects/Fun/snap_pops.yml b/Resources/Prototypes/Entities/Objects/Fun/snap_pops.yml index a39c2f881a2..88f07588740 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/snap_pops.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/snap_pops.yml @@ -33,15 +33,12 @@ maxIntensity: 0.01 intensitySlope: 1 totalIntensity: 0.01 - - type: Tag - tags: - - SnapPop - type: entity parent: BaseStorageItem id: SnapPopBox name: snap pop box - description: Contains twenty snap pops for a few minutes of popping fun! + description: Contains snap pops for a few minutes of popping fun! components: - type: Item size: Normal @@ -56,6 +53,6 @@ - type: StorageFill contents: - id: SnapPop - amount: 20 + amount: 5 - type: Dumpable diff --git a/Resources/Prototypes/Entities/Objects/Fun/whistles.yml b/Resources/Prototypes/Entities/Objects/Fun/whistles.yml index 10c41efc54a..667d5da11ca 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/whistles.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/whistles.yml @@ -6,8 +6,12 @@ description: Someone forgot to turn off kettle? components: - type: Item + sprite: Objects/Fun/whistles.rsi size: Tiny + - type: Sprite + sprite: Objects/Fun/whistles.rsi - type: Clothing + sprite: Objects/Fun/whistles.rsi quickEquip: false slots: neck - type: UseDelay @@ -16,7 +20,14 @@ sound: collection: BaseWhistle - type: Whistle - distance: 5 + distance: 3 + +- type: entity + parent: BaseWhistle + id: Whistle + components: + - type: Sprite + state: whistle - type: entity parent: BaseWhistle @@ -24,10 +35,11 @@ description: Sound of it make you feel fear. components: - type: Sprite - sprite: Objects/Fun/whistle.rsi - state: securityWhistle - - type: Item - sprite: Objects/Fun/whistle.rsi + state: sec + - type: Clothing + equippedPrefix: sec + - type: Whistle + distance: 5 - type: entity parent: BaseWhistle @@ -36,13 +48,9 @@ description: A whistle used by Syndicate commanders to draw attention. Avanti! components: - type: Sprite - sprite: Clothing/Neck/Misc/whistles.rsi - state: icon + state: trench - type: Clothing - sprite: Clothing/Neck/Misc/whistles.rsi - quickEquip: False - slots: - - neck + equippedPrefix: trench - type: EmitSoundOnUse sound: collection: TrenchWhistle diff --git a/Resources/Prototypes/Entities/Objects/Magic/books.yml b/Resources/Prototypes/Entities/Objects/Magic/books.yml index 6202767ff12..7697e46b32a 100644 --- a/Resources/Prototypes/Entities/Objects/Magic/books.yml +++ b/Resources/Prototypes/Entities/Objects/Magic/books.yml @@ -9,7 +9,7 @@ layers: - state: paper_blood - state: cover_strong - color: "#645a5a" + color: "#645a5a" - state: decor_wingette_flat color: "#4d0303" - state: icon_pentagramm @@ -25,13 +25,58 @@ - type: EmitSoundOnLand sound: /Audio/SimpleStation14/Items/Handling/book_drop.ogg +# For the Wizard Antag +# Do not add discounts or price inflation +- type: entity + id: WizardsGrimoire + name: wizards grimoire + suffix: Wizard + parent: BaseItem + components: + - type: Sprite + sprite: Objects/Misc/books.rsi + layers: + - state: paper_blood + - state: cover_strong + color: "#645a5a" + - state: decor_wingette_flat + color: "#4d0303" + - state: icon_pentagramm + color: "#f7e19f" + - type: UserInterface + interfaces: + enum.StoreUiKey.Key: + type: StoreBoundUserInterface + - type: ActivatableUI + key: enum.StoreUiKey.Key + - type: Store + refundAllowed: true + ownerOnly: true # get your own tome! + preset: StorePresetSpellbook + balance: + WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are + +# Not meant for wizard antag but meant for spawning, so people can't abuse refund if they were given a tome +- type: entity + id: WizardsGrimoireNoRefund + name: wizards grimoire + suffix: Wizard, No Refund + parent: WizardsGrimoire + components: + - type: Store + refundAllowed: false + ownerOnly: true # get your own tome! + preset: StorePresetSpellbook + balance: + WizCoin: 10 # prices are balanced around this 10 point maximum and how strong the spells are + - type: entity id: SpawnSpellbook name: spawn spellbook parent: BaseSpellbook components: - type: Spellbook - spells: + spellActions: ActionSpawnMagicarpSpell: -1 - type: entity @@ -54,7 +99,7 @@ - state: detail_rivets color: gold - type: Spellbook - spells: + spellActions: ActionForceWall: -1 - type: entity @@ -75,7 +120,7 @@ - state: detail_rivets color: gold - type: Spellbook - spells: + spellActions: ActionBlink: -1 - type: entity @@ -98,7 +143,7 @@ color: red - state: overlay_blood - type: Spellbook - spells: + spellActions: ActionSmite: -1 - type: entity @@ -120,7 +165,7 @@ - state: detail_bookmark color: "#98c495" - type: Spellbook - spells: + spellActions: ActionKnock: -1 - type: entity @@ -144,7 +189,7 @@ - state: icon_magic_fireball shader: unshaded - type: Spellbook - spells: + spellActions: ActionFireball: -1 - type: entity @@ -159,7 +204,7 @@ layers: - state: spell_default - type: Spellbook - spells: + spellActions: ActionFlashRune: -1 ActionExplosionRune: -1 ActionIgniteRune: -1 diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml index 59c9a8fc46f..204cca95197 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/glass.yml @@ -93,8 +93,8 @@ Quantity: 10 - type: UserInterface interfaces: - - key: enum.ShortConstructionUiKey.Key - type: ShortConstructionMenuBUI + enum.ShortConstructionUiKey.Key: + type: ShortConstructionMenuBUI - type: ActivatableUI key: enum.ShortConstructionUiKey.Key - type: ShortConstruction @@ -193,8 +193,8 @@ acts: [ "Destruction" ] - type: UserInterface interfaces: - - key: enum.ShortConstructionUiKey.Key - type: ShortConstructionMenuBUI + enum.ShortConstructionUiKey.Key: + type: ShortConstructionMenuBUI - type: ActivatableUI key: enum.ShortConstructionUiKey.Key - type: ShortConstruction diff --git a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml index 427ae362a7a..d0f92ad8b7d 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/Sheets/metal.yml @@ -71,8 +71,8 @@ Quantity: 1 - type: UserInterface interfaces: - - key: enum.ShortConstructionUiKey.Key - type: ShortConstructionMenuBUI + enum.ShortConstructionUiKey.Key: + type: ShortConstructionMenuBUI - type: ActivatableUI key: enum.ShortConstructionUiKey.Key - type: ShortConstruction diff --git a/Resources/Prototypes/Entities/Objects/Materials/materials.yml b/Resources/Prototypes/Entities/Objects/Materials/materials.yml index e71a163b5d0..c72e503b498 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/materials.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/materials.yml @@ -419,6 +419,58 @@ - type: Stack count: 1 +- type: entity + parent: MaterialBase + id: MaterialPyrotton + name: pyrotton + suffix: Full + components: + - type: Stack + stackType: Pyrotton + baseLayer: base + layerStates: + - pyrotton + - pyrotton_2 + - pyrotton_3 + - type: Sprite + state: pyrotton_3 + layers: + - state: pyrotton_3 + map: ["base"] + - type: Appearance + - type: Food + requiresSpecialDigestion: true + - type: SolutionContainerManager + solutions: + food: + maxVol: 10 + reagents: + - ReagentId: Fiber + Quantity: 5 + - ReagentId: Phlogiston + Quantity: 5 + - type: Extractable + juiceSolution: + reagents: + - ReagentId: Fiber + Quantity: 3 + - ReagentId: Phlogiston + Quantity: 3 + - type: Tag + tags: + - ClothMade + - RawMaterial + +- type: entity + parent: MaterialPyrotton + id: MaterialPyrotton1 + suffix: Single + components: + - type: Sprite + state: pyrotton + - type: Stack + count: 1 + - type: entity parent: MaterialBase id: MaterialBananium diff --git a/Resources/Prototypes/Entities/Objects/Materials/parts.yml b/Resources/Prototypes/Entities/Objects/Materials/parts.yml index e0547b3dc48..95640dbbb5e 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/parts.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/parts.yml @@ -70,8 +70,8 @@ Quantity: 0.5 - type: UserInterface interfaces: - - key: enum.ShortConstructionUiKey.Key - type: ShortConstructionMenuBUI + enum.ShortConstructionUiKey.Key: + type: ShortConstructionMenuBUI - type: ActivatableUI key: enum.ShortConstructionUiKey.Key - type: ShortConstruction diff --git a/Resources/Prototypes/Entities/Objects/Materials/shards.yml b/Resources/Prototypes/Entities/Objects/Materials/shards.yml index 34685343145..5e0b8890ccd 100644 --- a/Resources/Prototypes/Entities/Objects/Materials/shards.yml +++ b/Resources/Prototypes/Entities/Objects/Materials/shards.yml @@ -17,7 +17,7 @@ shard2: "" shard3: "" - type: MeleeWeapon - attackRate: 1.5 + attackRate: 1 damage: types: Slash: 3.5 @@ -68,7 +68,7 @@ types: - Shard intersectRatio: 0.2 - - type: ShoesRequiredStepTrigger + - type: ClothingRequiredStepTrigger - type: Slippery slipSound: path: /Audio/Effects/glass_step.ogg @@ -96,7 +96,7 @@ - type: DamageUserOnTrigger damage: types: - Piercing: 5 + Piercing: 4.5 - type: Tag tags: - GlassShard @@ -121,6 +121,10 @@ components: - type: Sprite color: "#96cdef" + - type: MeleeWeapon + damage: + types: + Slash: 4.5 - type: WelderRefinable refineResult: - id: SheetGlass1 @@ -128,7 +132,7 @@ - type: DamageUserOnTrigger damage: types: - Piercing: 5 + Piercing: 5.5 - type: Tag tags: - ReinforcedGlassShard @@ -153,6 +157,10 @@ components: - type: Sprite color: "#FF72E7" + - type: MeleeWeapon + damage: + types: + Slash: 5.5 - type: WelderRefinable refineResult: - id: SheetGlass1 @@ -160,7 +168,7 @@ - type: DamageUserOnTrigger damage: types: - Piercing: 5 + Piercing: 6.5 - type: Tag tags: - PlasmaGlassShard @@ -187,6 +195,11 @@ components: - type: Sprite color: "#8eff7a" + - type: MeleeWeapon + damage: + types: + Slash: 4.5 + Radiation: 2 - type: WelderRefinable refineResult: - id: SheetGlass1 @@ -194,8 +207,8 @@ - type: DamageUserOnTrigger damage: types: - Piercing: 3 - Radiation: 2 + Piercing: 5 + Radiation: 2.5 - type: Tag tags: - UraniumGlassShard diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index 043ea4b0fe8..fca4b5c59dd 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -22,11 +22,10 @@ contentSize: 12000 - type: ActivatableUI key: enum.PaperUiKey.Key - closeOnHandDeselect: false - type: UserInterface interfaces: - - key: enum.PaperUiKey.Key - type: PaperBoundUserInterface + enum.PaperUiKey.Key: + type: PaperBoundUserInterface - type: Tag tags: - Book @@ -55,7 +54,7 @@ color: "#0a2a6b" - state: decor_wingette color: "#082561" - - state: icon_text + - state: icon_text color: gold - state: icon_planet color: "#42b6f5" @@ -367,7 +366,7 @@ description: Each book is unique! What is hidden in this one? components: - type: RandomMetadata - nameSegments: + nameSegments: - book_hint_appearance - book_type - type: RandomSprite @@ -416,7 +415,7 @@ icon_skull: "" icon_text: "" icon_text2: "" - icon_text3: "" + icon_text3: "" overlay: overlay_blood: "" overlay_dirt: Sixteen @@ -457,7 +456,7 @@ - book_story_element_trait - "." storySeparator: "" - + - type: entity parent: BookBase id: BookAtmosDistro @@ -536,4 +535,4 @@ - state: icon_corner color: gold - type: Paper - content: book-text-atmos-vents \ No newline at end of file + content: book-text-atmos-vents diff --git a/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml b/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml new file mode 100644 index 00000000000..ed49053f8ae --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Misc/chopsticks.yml @@ -0,0 +1,30 @@ +- type: entity + parent: BaseItem + id: ChopSticks + name: chopsticks + description: A very traditional utensil. + components: + - type: Sprite + sprite: Objects/Misc/chopstick.rsi + state: icon + - type: Item + sprite: Objects/Misc/chopstick.rsi + size: Small + - type: Utensil + types: + - Fork + +- type: entity + parent: BaseItem + name: paired chopsticks + id: PairedChopsticks + description: You should probably seperate them. + components: + - type: SpawnItemsOnUse + items: + - id: ChopSticks + sound: + path: /Audio/Effects/chopstickbreak.ogg + - type: Sprite + sprite: Objects/Misc/chopstick.rsi + state: paired diff --git a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml index 27a81a783a6..32d8ea7540a 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fire_extinguisher.yml @@ -61,6 +61,9 @@ enabled: True: { state: fire_extinguisher_closed } False: { state: fire_extinguisher_open } + - type: PhysicalComposition + materialComposition: + Steel: 100 - type: entity name: extinguisher spray diff --git a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml index a42b2fa1139..a02f94215b8 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/fluff_lights.yml @@ -212,6 +212,11 @@ enabled: false radius: 8 energy: 5 + - type: ItemSlots + slots: + cell_slot: + name: power-cell-slot-component-slot-name-default + startingItem: PowerCellMedium - type: Anchorable - type: Damageable damageContainer: Inorganic diff --git a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml index 4af517bc528..0de971e001d 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/identification_cards.yml @@ -902,9 +902,9 @@ default: PassengerIDCard - type: UserInterface interfaces: - - key: enum.AgentIDCardUiKey.Key + enum.AgentIDCardUiKey.Key: type: AgentIDCardBoundUserInterface - - key: enum.ChameleonUiKey.Key + enum.ChameleonUiKey.Key: type: ChameleonBoundUserInterface - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Misc/medalcase.yml b/Resources/Prototypes/Entities/Objects/Misc/medalcase.yml index a421c1e9e99..35000b3fba1 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/medalcase.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/medalcase.yml @@ -17,6 +17,9 @@ - type: Storage grid: - 0,0,7,1 + whitelist: + tags: + - Medal - type: StorageFill contents: - id: ClothingNeckGoldmedal diff --git a/Resources/Prototypes/Entities/Objects/Misc/paper.yml b/Resources/Prototypes/Entities/Objects/Misc/paper.yml index d1527ceff58..d3db29b4209 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/paper.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/paper.yml @@ -18,12 +18,11 @@ - type: PaperLabelType - type: ActivatableUI key: enum.PaperUiKey.Key - closeOnHandDeselect: false requireHands: false - type: UserInterface interfaces: - - key: enum.PaperUiKey.Key - type: PaperBoundUserInterface + enum.PaperUiKey.Key: + type: PaperBoundUserInterface - type: Item size: Tiny - type: Tag @@ -32,6 +31,7 @@ - Trash - Paper - type: Appearance + - type: FaxableObject - type: PaperVisuals - type: Flammable fireSpread: true @@ -270,8 +270,8 @@ key: enum.PaperUiKey.Key - type: UserInterface interfaces: - - key: enum.PaperUiKey.Key - type: PaperBoundUserInterface + enum.PaperUiKey.Key: + type: PaperBoundUserInterface - type: entity parent: Paper @@ -714,10 +714,10 @@ key: enum.CargoConsoleUiKey.Orders - type: UserInterface interfaces: - - key: enum.CargoConsoleUiKey.Orders - type: CargoOrderConsoleBoundUserInterface - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.CargoConsoleUiKey.Orders: + type: CargoOrderConsoleBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: MeleeWeapon wideAnimationRotation: 180 damage: diff --git a/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml b/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml index 84c9c7c7520..b7f296cbac7 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/pet_carrier.yml @@ -30,7 +30,7 @@ radius: 0.45 density: 25 mask: - - SmallMobMask + - ItemMask layer: - MachineLayer - type: EntityStorage diff --git a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml index 2336945f171..a0f5e254d5f 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/subdermal_implants.yml @@ -126,7 +126,7 @@ ents: [ ] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key + enum.StorageUiKey.Key: type: StorageBoundUserInterface - type: entity @@ -160,8 +160,8 @@ Telecrystal: 0 - type: UserInterface interfaces: - - key: enum.StoreUiKey.Key - type: StoreBoundUserInterface + enum.StoreUiKey.Key: + type: StoreBoundUserInterface - type: entity parent: BaseSubdermalImplant diff --git a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml index 4250669581f..86667f094fd 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/utensils.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/utensils.yml @@ -120,3 +120,28 @@ - Plastic - Trash - Knife + +- type: entity + parent: UtensilBase + id: BarSpoon + name: bar spoon + description: Your personal helper to mix drinks and changes lives. + components: + - type: Tag + tags: + - Metal + - type: Sprite + state: bar_spoon + - type: Item + heldPrefix: spoon + - type: Utensil + types: + - Spoon + - type: MeleeWeapon + wideAnimationRotation: 180 + attackRate: 2 + damage: + types: + Blunt: 2 + - type: Shovel + speedModifier: 0.05 # nah diff --git a/Resources/Prototypes/Entities/Objects/Power/portable_recharger.yml b/Resources/Prototypes/Entities/Objects/Power/portable_recharger.yml new file mode 100644 index 00000000000..e3213ac8c9e --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Power/portable_recharger.yml @@ -0,0 +1,38 @@ +- type: entity + parent: Clothing + id: PortableRecharger + name: portable recharger + description: High-tech recharger adapted for portability + components: + - type: Item + size: Huge + - type: Sprite + sprite: Objects/Power/portable_recharger.rsi + state: charging + - type: Clothing + equippedPrefix: charging + quickEquip: false + slots: + - back + - type: Charger + slotId: charger_slot + portable: true + - type: PowerChargerVisuals + - type: ApcPowerReceiver + needsPower: false + powerLoad: 0 + - type: StaticPrice + price: 500 + - type: Tag + tags: [] # ignore "WhitelistChameleon" tag + - type: ContainerContainer + containers: + charger_slot: !type:ContainerSlot + - type: ItemSlots + slots: + charger_slot: + ejectOnInteract: true + whitelist: + components: + - HitscanBatteryAmmoProvider + - ProjectileBatteryAmmoProvider diff --git a/Resources/Prototypes/Entities/Objects/Shields/shields.yml b/Resources/Prototypes/Entities/Objects/Shields/shields.yml index b794e42ff7d..e7ebb1b98d4 100644 --- a/Resources/Prototypes/Entities/Objects/Shields/shields.yml +++ b/Resources/Prototypes/Entities/Objects/Shields/shields.yml @@ -313,7 +313,7 @@ name: mirror shield parent: BaseShield id: MirrorShield - description: Eerily glows red... you hear the geometer whispering + description: Glows an eerie red. You hear the Geometer whispering... components: - type: Sprite state: mirror-icon @@ -321,6 +321,7 @@ heldPrefix: mirror - type: Reflect reflectProb: 0.95 + innate: true reflects: - Energy - type: Blocking #Mirror shield reflects heat/laser, but is relatively weak to everything else. @@ -408,6 +409,7 @@ - type: Reflect enabled: false reflectProb: 0.95 + innate: true reflects: - Energy - type: Blocking diff --git a/Resources/Prototypes/Entities/Objects/Specific/Cargo/cargo_pallet.yml b/Resources/Prototypes/Entities/Objects/Specific/Cargo/cargo_pallet.yml index c628d199a90..07bdee63cfc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Cargo/cargo_pallet.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Cargo/cargo_pallet.yml @@ -1,7 +1,7 @@ - type: entity id: CargoPallet name: cargo pallet - description: Designates valid items to sell to CentCom when a shuttle is recalled. + description: Common fixture of logistics and cargo. Subtle reminder where crates go during transport to avoid bruised shins. parent: BaseStructure components: - type: InteractionOutline @@ -58,17 +58,20 @@ - type: entity id: CargoPalletSell name: cargo selling pallet - description: Designates valid items to sell with a selling computer, or to CentCom when a shuttle is recalled. + description: Designates valid items to sell. parent: CargoPallet components: - type: CargoPallet palletType: sell - type: Sprite drawdepth: FloorTiles - layers: - - sprite: Structures/cargo_pallets.rsi - state: cargo_pallet_sell - + sprite: Structures/cargo_pallets.rsi + - type: Icon + sprite: Structures/cargo_pallets.rsi + state: cargo_pallet_sell + - type: IconSmooth + key: cargo_pallet_sell + base: cargo_pallet_sell_ - type: entity id: CargoPalletBuy @@ -80,7 +83,10 @@ palletType: buy - type: Sprite drawdepth: FloorTiles - layers: - - sprite: Structures/cargo_pallets.rsi - state: cargo_pallet_buy - + sprite: Structures/cargo_pallets.rsi + - type: Icon + sprite: Structures/cargo_pallets.rsi + state: cargo_pallet_buy + - type: IconSmooth + key: cargo_pallet_buy + base: cargo_pallet_buy_ diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml index 50bea2a8b24..9a0709e8e74 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/bibles.yml @@ -40,8 +40,8 @@ - 0,0,0,1 - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: MeleeWeapon # Nyanotrasen - Bibles do Holy damage damage: types: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Chapel/urn.yml b/Resources/Prototypes/Entities/Objects/Specific/Chapel/urn.yml index c7788600846..55a58ef18a1 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Chapel/urn.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Chapel/urn.yml @@ -9,8 +9,8 @@ - 0,0,0,1 - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: Sprite sprite: Objects/Specific/Chapel/chaplainurn.rsi state: icon diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml index b847416211d..c26ba925e0d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/leaves.yml @@ -65,7 +65,101 @@ - Smokable - type: Item size: Tiny + +- type: entity + name: rainbow cannabis leaves + parent: LeavesCannabis + id: LeavesCannabisRainbow + description: "Is it supposed to be glowing like that...?" + components: + - type: Sprite + sprite: Objects/Specific/Hydroponics/rainbow_cannabis.rsi + - type: Produce + seedId: rainbowCannabis + - type: PointLight + radius: 1.5 + energy: 2 + - type: RgbLightController + cycleRate: 0.6 + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: SpaceDrugs + Quantity: 3 + - ReagentId: Lipolicide + Quantity: 3 + - ReagentId: MindbreakerToxin + Quantity: 2 + - ReagentId: Happiness + Quantity: 2 +# - ReagentId: ColorfulReagent +# Quantity: 1 + - ReagentId: Psicodine + Quantity: 0.6 +- type: entity + name: dried rainbow cannabis leaves + parent: LeavesCannabisDried + id: LeavesCannabisRainbowDried + description: "Dried rainbow cannabis leaves, ready to be ground." + components: + - type: Stack + stackType: LeavesCannabisRainbowDried + count: 1 + - type: SolutionContainerManager + solutions: + food: + maxVol: 8.5 #fuck you saveload test fail + reagents: + - ReagentId: SpaceDrugs + Quantity: 2.4 + - ReagentId: Lipolicide + Quantity: 2.4 + - ReagentId: MindbreakerToxin + Quantity: 1.6 + - ReagentId: Happiness + Quantity: 1.6 +# - ReagentId: ColorfulReagent +# Quantity: 0.8 + - ReagentId: Psicodine + Quantity: 0.48 + - type: Sprite + sprite: Objects/Specific/Hydroponics/rainbow_cannabis.rsi + state: dried + +- type: entity + name: ground rainbow cannabis + parent: GroundCannabis + id: GroundCannabisRainbow + description: "Ground rainbow cannabis, ready to take you on a trip." + components: + - type: Stack + stackType: GroundCannabisRainbow + count: 1 + - type: SolutionContainerManager + solutions: + food: + reagents: + - ReagentId: SpaceDrugs + Quantity: 4 + - ReagentId: Lipolicide + Quantity: 4 + - ReagentId: MindbreakerToxin + Quantity: 2.66 + - ReagentId: Happiness + Quantity: 2.66 +# - ReagentId: ColorfulReagent +# Quantity: 1.33 + - ReagentId: Psicodine + Quantity: 0.8 + - type: Sprite + sprite: Objects/Specific/Hydroponics/rainbow_cannabis.rsi + state: powderpile_rainbow + color: white + - type: Construction + graph: smokeableGroundCannabisRainbow + node: groundRainbow - type: entity name: tobacco leaves diff --git a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml index 2b232d643d3..92aa22a8bae 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Hydroponics/seeds.yml @@ -285,6 +285,17 @@ - type: Sprite sprite: Objects/Specific/Hydroponics/cannabis.rsi +- type: entity + parent: SeedBase + name: packet of rainbow cannabis seeds + description: "These seeds grow into rainbow weed. Groovy... and also highly addictive." + id: RainbowCannabisSeeds + components: + - type: Seed + seedId: rainbowCannabis + - type: Sprite + sprite: Objects/Specific/Hydroponics/rainbow_cannabis.rsi + - type: entity parent: SeedBase name: packet of nettle seeds @@ -571,3 +582,13 @@ seedId: cotton - type: Sprite sprite: Objects/Specific/Hydroponics/cotton.rsi + +- type: entity + parent: SeedBase + name: packet of pyrotton seeds + id: PyrottonSeeds + components: + - type: Seed + seedId: pyrotton + - type: Sprite + sprite: Objects/Specific/Hydroponics/pyrotton.rsi diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml index f45331d5897..a3a26299bf3 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml @@ -38,6 +38,9 @@ maxVol: 100 - type: UseDelay delay: 1 + - type: PhysicalComposition + materialComposition: + Plastic: 50 - type: Tag tags: - Mop @@ -119,6 +122,9 @@ coefficients: Blunt: 0.95 Slash: 0.95 + - type: PhysicalComposition + materialComposition: + Plastic: 50 - type: Tag tags: - WetFloorSign diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml index 0e19c03deef..cddf7f6075a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/spray.yml @@ -5,6 +5,12 @@ suffix: Empty description: A spray bottle with an unscrewable top. components: + - type: Drink + solution: spray + ignoreEmpty: true + useSound: + path: /Audio/Effects/spray3.ogg + transferAmount: 10 - type: Tag tags: - Spray @@ -24,6 +30,8 @@ solution: spray - type: SolutionTransfer canChangeTransferAmount: true + - type: SolutionItemStatus + solution: spray - type: UseDelay - type: Spray transferAmount: 10 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml index f802ae1c5c3..9927d836baa 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Janitorial/trashbag.yml @@ -22,6 +22,8 @@ tags: - Cartridge - Trash + - type: UseDelay + delay: 0.5 - type: Tag tags: - TrashBag diff --git a/Resources/Prototypes/Entities/Objects/Specific/Kitchen/foodcarts.yml b/Resources/Prototypes/Entities/Objects/Specific/Kitchen/foodcarts.yml index 0894d6a7547..ca74dca8a7b 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Kitchen/foodcarts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Kitchen/foodcarts.yml @@ -44,8 +44,8 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: Storage maxItemSize: Normal grid: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml index 6e5362d9bbb..dab6f9f20fe 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Mech/mechs.yml @@ -39,8 +39,8 @@ doAfterDelay: 10 - type: UserInterface interfaces: - - key: enum.MechUiKey.Key - type: MechBoundUserInterface + enum.MechUiKey.Key: + type: MechBoundUserInterface - type: MeleeWeapon hidden: true attackRate: 0.75 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml index e2e93283425..ab338b9da95 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/handheld_crew_monitor.yml @@ -16,10 +16,9 @@ - type: ActivatableUIRequiresPowerCell - type: ActivatableUI key: enum.CrewMonitoringUIKey.Key - closeOnHandDeselect: false - type: UserInterface interfaces: - - key: enum.CrewMonitoringUIKey.Key + enum.CrewMonitoringUIKey.Key: type: CrewMonitoringBoundUserInterface - type: CrewMonitoringConsole - type: DeviceNetwork diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml index 64bd04569b5..c01aaa84a9d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/healthanalyzer.yml @@ -17,10 +17,9 @@ storedRotation: -90 - type: ActivatableUI key: enum.HealthAnalyzerUiKey.Key - closeOnHandDeselect: false - type: UserInterface interfaces: - - key: enum.HealthAnalyzerUiKey.Key + enum.HealthAnalyzerUiKey.Key: type: HealthAnalyzerBoundUserInterface - type: HealthAnalyzer scanningEndSound: diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/medkits.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/medkits.yml index 62e5ab44762..46d1efa24eb 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/medkits.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/medkits.yml @@ -15,6 +15,9 @@ size: Large sprite: Objects/Specific/Medical/firstaidkits.rsi heldPrefix: firstaid + - type: PhysicalComposition + materialComposition: + Plastic: 150 - type: Tag tags: - Medkit diff --git a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml index 74199c9f65e..113017cc84a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Research/anomaly.yml @@ -9,11 +9,11 @@ state: icon - type: ActivatableUI key: enum.AnomalyScannerUiKey.Key - closeOnHandDeselect: false + requireActiveHand: false inHandsOnly: true - type: UserInterface interfaces: - - key: enum.AnomalyScannerUiKey.Key + enum.AnomalyScannerUiKey.Key: type: AnomalyScannerBoundUserInterface - type: AnomalyScanner - type: GuideHelp diff --git a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml index a7cf7ad5c80..960e37a6ccc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Robotics/borg_modules.yml @@ -346,6 +346,7 @@ - HoloprojectorBorg - SprayBottleSpaceCleaner - Dropper + - TrashBag # medical modules - type: entity @@ -579,5 +580,19 @@ - state: icon-syndicate - type: ItemBorgModule items: - - WeaponLightMachineGunL6C - - PinpointerSyndicateNuclear + - WeaponLightMachineGunL6C + - PinpointerSyndicateNuclear + +- type: entity + id: BorgModuleMartyr + parent: [ BaseBorgModule, BaseProviderBorgModule ] + name: martyr cyborg module + description: "A module that comes with an explosive you probably don't want to handle yourself." + components: + - type: Sprite + layers: + - state: syndicateborgbomb + - state: icon-bomb + - type: ItemBorgModule + items: + - SelfDestructSeq diff --git a/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml b/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml index 4a16603541c..451230bbf1f 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Service/barber.yml @@ -14,11 +14,12 @@ changeSlotTime: 20 - type: ActivatableUI key: enum.MagicMirrorUiKey.Key - closeOnHandDeselect: true + inHandsOnly: true + requireActiveHand: true - type: UserInterface interfaces: - - key: enum.MagicMirrorUiKey.Key - type: MagicMirrorBoundUserInterface + enum.MagicMirrorUiKey.Key: + type: MagicMirrorBoundUserInterface - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1 diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml index c38868b3997..e1716f08439 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/artifact_equipment.yml @@ -36,7 +36,7 @@ radius: 0.45 density: 50 mask: - - SmallMobMask #this is so they can go under plastic flaps + - CrateMask #this is so they can go under plastic flaps layer: - MachineLayer - type: Icon diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_artifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_artifacts.yml index cb6708431a0..036b876a97a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_artifacts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/item_artifacts.yml @@ -45,14 +45,14 @@ ano01_on: Rainbow - type: UserInterface #needs to be here for certain effects interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface - - key: enum.IntercomUiKey.Key - type: IntercomBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface + enum.IntercomUiKey.Key: + type: IntercomBoundUserInterface - type: Appearance - type: Item size: Normal diff --git a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml index f098894ff79..b53a6179814 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Xenoarchaeology/structure_artifacts.yml @@ -22,14 +22,14 @@ noRot: true - type: UserInterface #needs to be here for certain effects interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface - - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface - - key: enum.IntercomUiKey.Key - type: IntercomBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface + enum.InstrumentUiKey.Key: + type: InstrumentBoundUserInterface + enum.IntercomUiKey.Key: + type: IntercomBoundUserInterface - type: Reactive groups: Acidic: [Touch] diff --git a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml index 0dc714aba0c..c67e7ff8c31 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/atmos.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/atmos.yml @@ -13,12 +13,12 @@ - type: ActivatableUI inHandsOnly: true singleUser: true - closeOnHandDeselect: false + requireActiveHand: false key: enum.GasAnalyzerUiKey.Key - type: UserInterface interfaces: - - key: enum.GasAnalyzerUiKey.Key - type: GasAnalyzerBoundUserInterface + enum.GasAnalyzerUiKey.Key: + type: GasAnalyzerBoundUserInterface - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml index 027ff206f8d..4bd71f898db 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemical-containers.yml @@ -8,7 +8,6 @@ solutions: beaker: maxVol: 200 - canMix: true - type: Sprite sprite: Objects/Specific/Chemistry/jug.rsi layers: @@ -19,6 +18,8 @@ - type: Item size: Normal sprite: Objects/Specific/Chemistry/jug.rsi + - type: MixableSolution + solution: beaker - type: RefillableSolution solution: beaker - type: DrainableSolution @@ -31,9 +32,11 @@ solution: beaker - type: SolutionTransfer canChangeTransferAmount: true + - type: SolutionItemStatus + solution: beaker - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key + enum.TransferAmountUiKey.Key: type: TransferAmountBoundUserInterface - type: Drink solution: beaker diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml index acfb65aa54f..6fdb77fe5fc 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-bottles.yml @@ -29,7 +29,8 @@ solutions: drink: # This solution name and target volume is hard-coded in ChemMasterComponent maxVol: 30 - canMix: true + - type: MixableSolution + solution: drink - type: RefillableSolution solution: drink - type: DrainableSolution @@ -41,10 +42,12 @@ - type: SolutionTransfer maxTransferAmount: 30 canChangeTransferAmount: true + - type: SolutionItemStatus + solution: drink - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Item size: Tiny sprite: Objects/Specific/Chemistry/beaker.rsi diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml index c5de88d690d..39a35dba8c6 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry-vials.yml @@ -35,7 +35,8 @@ solutions: beaker: maxVol: 30 - canMix: true + - type: MixableSolution + solution: beaker - type: RefillableSolution solution: beaker - type: DrainableSolution @@ -47,10 +48,12 @@ - type: SolutionTransfer maxTransferAmount: 30 canChangeTransferAmount: true + - type: SolutionItemStatus + solution: beaker - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Item size: Tiny sprite: Objects/Specific/Chemistry/vial.rsi diff --git a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml index fd32523d8ff..2f86604711a 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/chemistry.yml @@ -25,7 +25,8 @@ solutions: beaker: maxVol: 50 - canMix: true + - type: MixableSolution + solution: beaker - type: FitsInDispenser solution: beaker - type: RefillableSolution @@ -40,10 +41,12 @@ solution: beaker - type: SolutionTransfer canChangeTransferAmount: true + - type: SolutionItemStatus + solution: beaker - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Drink solution: beaker - type: Appearance @@ -117,7 +120,8 @@ solutions: beaker: maxVol: 50 - canMix: true + - type: MixableSolution + solution: beaker - type: FitsInDispenser solution: beaker - type: RefillableSolution @@ -132,10 +136,12 @@ solution: beaker - type: SolutionTransfer canChangeTransferAmount: true + - type: SolutionItemStatus + solution: beaker - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Drink solution: beaker - type: Appearance @@ -158,6 +164,9 @@ solution: beaker - type: StaticPrice price: 10 + - type: PhysicalComposition + materialComposition: + Glass: 50 - type: SolutionContainerVisuals maxFillLevels: 6 fillBaseName: beaker @@ -200,13 +209,15 @@ solutions: beaker: maxVol: 100 - canMix: true - type: Appearance - type: SolutionContainerVisuals maxFillLevels: 6 fillBaseName: beakerlarge inHandsMaxFillLevels: 4 inHandsFillBaseName: -fill- + - type: PhysicalComposition + materialComposition: + Glass: 100 - type: StaticPrice price: 20 @@ -248,8 +259,7 @@ solutions: beaker: maxVol: 1000 - canMix: true - - type: ReverseEngineering # Delta + - type: ReverseEngineering difficulty: 4 recipes: - BluespaceBeaker @@ -282,8 +292,8 @@ solution: dropper - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Spillable solution: injector - type: Item diff --git a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml index 883f66816de..4f760066843 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/syndicate.yml @@ -63,8 +63,8 @@ heldPrefix: radio - type: UserInterface interfaces: - - key: enum.StoreUiKey.Key - type: StoreBoundUserInterface + enum.StoreUiKey.Key: + type: StoreBoundUserInterface - type: ActivatableUI key: enum.StoreUiKey.Key - type: Store diff --git a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml index 9504ec144a8..9c8102979a1 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/access_configurator.yml @@ -75,12 +75,12 @@ doAfter: 0.5 - type: UserInterface interfaces: - - key: enum.AccessOverriderUiKey.Key + enum.AccessOverriderUiKey.Key: type: AccessOverriderBoundUserInterface - type: ActivatableUI key: enum.AccessOverriderUiKey.Key requireHands: true - closeOnHandDeselect: false + requireActiveHand: false singleUser: true - type: ItemSlots - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml b/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml index 4ec8d288573..3edf26ea78e 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/appraisal.yml @@ -17,6 +17,9 @@ quickEquip: false slots: - Belt + - type: PhysicalComposition + materialComposition: + Steel: 250 - type: Tag tags: - AppraisalTool diff --git a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml index 496fd231b82..77c5e548978 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/bucket.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/bucket.yml @@ -26,6 +26,8 @@ solutions: bucket: maxVol: 250 + - type: MixableSolution + solution: bucket - type: SolutionTransfer transferAmount: 100 maxTransferAmount: 100 @@ -33,8 +35,8 @@ canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: MeleeWeapon soundNoDamage: path: "/Audio/Effects/Fluids/splat.ogg" @@ -49,6 +51,8 @@ solution: bucket - type: DrainableSolution solution: bucket + - type: SolutionItemStatus + solution: bucket - type: Appearance - type: SolutionContainerVisuals maxFillLevels: 3 diff --git a/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml b/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml index 36a4c411634..f06539aa175 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/cable_coils.yml @@ -31,7 +31,7 @@ Steel: 15 #Same as Ointment but divided by 5 and 3 because StackPrice needs to be 1 - Estacao Pirata IPCs #1 Ointment = -50 damage of those types - #1 Cable ~= -50 (-49.8) damage of those types + #1 Cable ~= -50 (-49.8) damage of those types - type: Healing delay: 0.6 damageContainers: diff --git a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml index 977a8a931b5..87959ebef3d 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/cowtools.yml @@ -128,11 +128,6 @@ sprite: Objects/Tools/Cowtools/cowelder.rsi - type: Tool speed: 0.05 - - type: Welder - litMeleeDamageBonus: - types: # When lit, negate standard melee damage and replace with heat - Heat: 0.5 - Blunt: -5 - type: entity name: milkalyzer @@ -147,8 +142,8 @@ - type: GasAnalyzer - type: UserInterface interfaces: - - key: enum.GasAnalyzerUiKey.Key - type: GasAnalyzerBoundUserInterface + enum.GasAnalyzerUiKey.Key: + type: GasAnalyzerBoundUserInterface - type: Appearance - type: entity diff --git a/Resources/Prototypes/Entities/Objects/Tools/decoys.yml b/Resources/Prototypes/Entities/Objects/Tools/decoys.yml index 0074fe517dc..d399b77d020 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/decoys.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/decoys.yml @@ -48,6 +48,15 @@ - type: ContainerContainer containers: cell_slot: !type:ContainerSlot + - type: HandheldLight + addPrefix: false + - type: PointLight # Just like the real thing... + autoRot: true + radius: 1.5 + energy: 2.3 + offset: 0, -1 + color: green + netsync: false - type: Tag tags: - Balloon @@ -59,8 +68,6 @@ name: operative balloon description: Upon closer inspection, this Syndicate operative is actually a balloon. components: - - type: HandheldLight - addPrefix: false - type: Sprite sprite: Objects/Tools/Decoys/operative_decoy.rsi layers: @@ -69,13 +76,6 @@ - state: folded map: ["foldedLayer"] visible: false - - type: PointLight # Just like the real thing... - autoRot: true - radius: 1.5 - energy: 2.3 - offset: 0, -1 - color: green - netsync: false - type: entity parent: BaseDecoy @@ -83,8 +83,6 @@ name: agent balloon description: Upon closer inspection, this Syndicate agent is actually a balloon. components: - - type: HandheldLight - addPrefix: false - type: Sprite sprite: Objects/Tools/Decoys/agent_decoy.rsi layers: @@ -93,12 +91,6 @@ - state: folded map: ["foldedLayer"] visible: false - - type: PointLight - radius: 1.5 - energy: 2.3 - offset: 0, -1 - color: green - netsync: false - type: entity parent: BaseDecoy @@ -106,8 +98,6 @@ name: elite operative balloon description: Upon closer inspection, this Syndicate elite operative is actually a balloon. components: - - type: HandheldLight - addPrefix: false - type: Sprite sprite: Objects/Tools/Decoys/elite_decoy.rsi layers: @@ -117,11 +107,7 @@ map: ["foldedLayer"] visible: false - type: PointLight - radius: 1.5 - energy: 2.3 - offset: 0, -1 color: red - netsync: false - type: entity parent: BaseDecoy @@ -129,8 +115,6 @@ name: juggernaut balloon description: Upon closer inspection, this Syndicate juggernaut is actually a balloon. components: - - type: HandheldLight - addPrefix: false - type: Sprite sprite: Objects/Tools/Decoys/juggernaut_decoy.rsi layers: @@ -139,11 +123,6 @@ - state: folded map: ["foldedLayer"] visible: false - - type: PointLight # Inbuilt flashlight, I guess? - radius: 1.5 - energy: 2.3 - offset: 0, -1 - netsync: false - type: entity parent: BaseDecoy @@ -151,8 +130,6 @@ name: commander balloon description: Upon closer inspection, this Syndicate commander is actually a balloon. components: - - type: HandheldLight - addPrefix: false - type: Sprite sprite: Objects/Tools/Decoys/commander_decoy.rsi layers: @@ -161,9 +138,3 @@ - state: folded map: ["foldedLayer"] visible: false - - type: PointLight - radius: 1.5 - energy: 2.3 - offset: 0, -1 - color: green - netsync: false diff --git a/Resources/Prototypes/Entities/Objects/Tools/flare.yml b/Resources/Prototypes/Entities/Objects/Tools/flare.yml index dbdb935b916..fdf53148631 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/flare.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/flare.yml @@ -20,7 +20,13 @@ fadeOutBehaviourID: fade_out litSound: path: /Audio/Items/Flare/flare_on.ogg - loopedSound: /Audio/Items/Flare/flare_burn.ogg + loopedSound: + path: /Audio/Items/Flare/flare_burn.ogg + params: + loop: true + volume: -10 + maxDistance: 5 + - type: Sprite sprite: Objects/Misc/flare.rsi layers: diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index 2618666ed9a..8590a32a6a6 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity abstract: true parent: BaseItem id: GasTankBase @@ -19,8 +19,8 @@ key: enum.SharedGasTankUiKey.Key - type: UserInterface interfaces: - - key: enum.SharedGasTankUiKey.Key - type: GasTankBoundUserInterface + enum.SharedGasTankUiKey.Key: + type: GasTankBoundUserInterface - type: GasTank outputPressure: 21.3 air: @@ -245,3 +245,6 @@ outputPressure: 101.3 - type: Clothing sprite: Objects/Tanks/plasma.rsi + slots: + - Belt + - suitStorage diff --git a/Resources/Prototypes/Entities/Objects/Tools/gps.yml b/Resources/Prototypes/Entities/Objects/Tools/gps.yml index 8ae34573ffa..becbb638f4f 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gps.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gps.yml @@ -12,6 +12,10 @@ - type: Item sprite: Objects/Devices/gps.rsi - type: HandheldGPS + - type: PhysicalComposition + materialComposition: + Steel: 400 + Glass: 150 - type: Tag tags: - GPS diff --git a/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml b/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml index 7e883953363..c97caad00f7 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/hand_labeler.yml @@ -17,7 +17,7 @@ inHandsOnly: true - type: UserInterface interfaces: - - key: enum.HandLabelerUiKey.Key + enum.HandLabelerUiKey.Key: type: HandLabelerBoundUserInterface - type: HandLabeler whitelist: diff --git a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml index 131bb1960ba..38b1f7cda9f 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/handheld_mass_scanner.yml @@ -34,7 +34,7 @@ singleUser: true - type: UserInterface interfaces: - - key: enum.RadarConsoleUiKey.Key + enum.RadarConsoleUiKey.Key: type: RadarConsoleBoundUserInterface - type: StaticPrice price: 150 diff --git a/Resources/Prototypes/Entities/Objects/Tools/jammer.yml b/Resources/Prototypes/Entities/Objects/Tools/jammer.yml index beb36956275..b456a23f1f8 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jammer.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jammer.yml @@ -6,8 +6,26 @@ components: - type: Sprite sprite: Objects/Devices/jammer.rsi - state: jammer + layers: + - state: jammer + - state: jammer_high_charge + map: ["enum.RadioJammerLayers.LED"] + shader: unshaded + visible: false - type: RadioJammer + settings: + - wattage: 1 + range: 2.5 + message: radio-jammer-component-set-message-low + name: radio-jammer-component-setting-low + - wattage: 2 + range: 6 + message: radio-jammer-component-set-message-medium + name: radio-jammer-component-setting-medium + - wattage: 12 + range: 12 + message: radio-jammer-component-set-message-high + name: radio-jammer-component-setting-high - type: PowerCellSlot cellSlotId: cell_slot - type: ContainerContainer @@ -18,3 +36,15 @@ cell_slot: name: power-cell-slot-component-slot-name-default startingItem: PowerCellMedium + - type: Appearance + - type: GenericVisualizer + visuals: + enum.RadioJammerVisuals.LEDOn: + RadioJammerLayers.LED: + True: { visible: True } + False: { visible: False } + enum.RadioJammerVisuals.ChargeLevel: + RadioJammerLayers.LED: + Low: {state: jammer_low_charge} + Medium: {state: jammer_medium_charge} + High: {state: jammer_high_charge} diff --git a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml index a4c103847fe..bd05b8d0f39 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/jetpacks.yml @@ -40,7 +40,7 @@ size: Huge - type: UserInterface interfaces: - - key: enum.SharedGasTankUiKey.Key + enum.SharedGasTankUiKey.Key: type: GasTankBoundUserInterface - type: Clothing sprite: Objects/Tanks/Jetpacks/blue.rsi diff --git a/Resources/Prototypes/Entities/Objects/Tools/penlight.yml b/Resources/Prototypes/Entities/Objects/Tools/penlight.yml index 7f8a9b262c0..a7fb3a3f1c9 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/penlight.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/penlight.yml @@ -28,8 +28,8 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.PenLightUiKey.Key - type: PenLightBoundUserInterface + enum.PenLightUiKey.Key: + type: PenLightBoundUserInterface - type: ToggleableLightVisuals - type: ContainerContainer containers: diff --git a/Resources/Prototypes/Entities/Objects/Tools/spray_painter.yml b/Resources/Prototypes/Entities/Objects/Tools/spray_painter.yml index 903b8d3f906..ad31a6ec02d 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/spray_painter.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/spray_painter.yml @@ -13,8 +13,8 @@ key: enum.SprayPainterUiKey.Key - type: UserInterface interfaces: - - key: enum.SprayPainterUiKey.Key - type: SprayPainterBoundUserInterface + enum.SprayPainterUiKey.Key: + type: SprayPainterBoundUserInterface - type: SprayPainter colorPalette: red: '#FF1212FF' diff --git a/Resources/Prototypes/Entities/Objects/Tools/t-ray.yml b/Resources/Prototypes/Entities/Objects/Tools/t-ray.yml index c467974b743..8872b98c183 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/t-ray.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/t-ray.yml @@ -19,5 +19,9 @@ base: On: { state: tray-on } Off: { state: tray-off } + - type: PhysicalComposition + materialComposition: + Steel: 400 + Glass: 150 - type: StaticPrice price: 60 diff --git a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml index b242843634d..bfbb0573ca1 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/toolbox.yml @@ -181,5 +181,5 @@ key: enum.ThiefBackpackUIKey.Key - type: UserInterface interfaces: - - key: enum.ThiefBackpackUIKey.Key + enum.ThiefBackpackUIKey.Key: type: ThiefBackpackBoundUserInterface diff --git a/Resources/Prototypes/Entities/Objects/Tools/tools.yml b/Resources/Prototypes/Entities/Objects/Tools/tools.yml index 87d0c2f4003..1f1b67349f4 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/tools.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/tools.yml @@ -293,11 +293,11 @@ inHandsOnly: true - type: UserInterface interfaces: - - key: enum.NetworkConfiguratorUiKey.List + enum.NetworkConfiguratorUiKey.List: type: NetworkConfiguratorBoundUserInterface - - key: enum.NetworkConfiguratorUiKey.Configure + enum.NetworkConfiguratorUiKey.Configure: type: NetworkConfiguratorBoundUserInterface - - key: enum.NetworkConfiguratorUiKey.Link + enum.NetworkConfiguratorUiKey.Link: type: NetworkConfiguratorBoundUserInterface - type: Tag tags: @@ -349,11 +349,11 @@ - DoorElectronicsConfigurator - type: UserInterface interfaces: - - key: enum.NetworkConfiguratorUiKey.List + enum.NetworkConfiguratorUiKey.List: type: NetworkConfiguratorBoundUserInterface - - key: enum.NetworkConfiguratorUiKey.Configure + enum.NetworkConfiguratorUiKey.Configure: type: NetworkConfiguratorBoundUserInterface - - key: enum.NetworkConfiguratorUiKey.Link + enum.NetworkConfiguratorUiKey.Link: type: NetworkConfiguratorBoundUserInterface - type: StaticPrice price: 56 @@ -477,8 +477,8 @@ price: 100 - type: UserInterface interfaces: - - key: enum.RcdUiKey.Key - type: RCDMenuBoundUserInterface + enum.RcdUiKey.Key: + type: RCDMenuBoundUserInterface - type: ActivatableUI key: enum.RcdUiKey.Key - type: ReverseEngineering # Nyano diff --git a/Resources/Prototypes/Entities/Objects/Tools/welders.yml b/Resources/Prototypes/Entities/Objects/Tools/welders.yml index 9f9df6f4f19..c501237b4c8 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/welders.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/welders.yml @@ -109,7 +109,6 @@ - type: WeldingHealing # Same as Brutepack - Estacao Pirata IPCs damageContainers: - Silicon - fuelcost: 5 damage: types: Blunt: -15 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml index 22eeeff859d..edca311cb17 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/light_rifle.yml @@ -10,7 +10,7 @@ tags: - CartridgeLightRifle proto: CartridgeLightRifle - capacity: 50 + capacity: 60 - type: Item size: Small - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml index c304f0af111..3f71f93440c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/magnum.yml @@ -9,7 +9,7 @@ tags: - CartridgeMagnum proto: CartridgeMagnum - capacity: 60 + capacity: 12 - type: Item size: Small - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml index 8e6c79dfe57..03d6e337994 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/rifle.yml @@ -9,7 +9,7 @@ tags: - CartridgeRifle proto: CartridgeRifle - capacity: 60 + capacity: 50 - type: Item size: Small - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/shotgun.yml index 831c3c33525..63ad52c0320 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Boxes/shotgun.yml @@ -21,7 +21,7 @@ whitelist: tags: - ShellShotgun - capacity: 12 + capacity: 16 # Shotgun Shells - type: entity @@ -89,6 +89,19 @@ - state: boxwide - state: shellincendiary +- type: entity + name: shotgun uranium cartridges dispenser + parent: AmmoProviderShotgunShell + id: BoxShotgunUranium + description: A dispenser box full of uranium cartridges, designed for riot shotguns. + components: + - type: BallisticAmmoProvider + proto: ShellShotgunUranium + - type: Sprite + layers: + - state: boxwide + - state: shelluranium + - type: entity name: shotgun practice cartridges dispenser parent: AmmoProviderShotgunShell @@ -113,4 +126,4 @@ - type: Sprite layers: - state: boxwide - - state: shellslug \ No newline at end of file + - state: shellslug diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/light_rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/light_rifle.yml index d420a5c3d81..296af23af5a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/light_rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/light_rifle.yml @@ -68,6 +68,19 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazineLightRifleEmpty + name: "magazine (.30 rifle any)" + suffix: empty + parent: MagazineLightRifle + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - type: entity id: MagazineLightRiflePractice name: "magazine (.30 rifle practice)" @@ -110,6 +123,14 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazineLightRifleIncendiary + name: "magazine (.30 rifle incendiary)" + parent: MagazineLightRifle + components: + - type: BallisticAmmoProvider + proto: CartridgeLightRifleIncendiary + - type: entity id: MagazineLightRifleMaxim name: "pan magazine (.30 rifle)" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml index 6a1cc041ded..fc506ec594a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/magnum.yml @@ -47,6 +47,19 @@ zeroVisible: false - type: Appearance +- type: entity + id: MagazineMagnumEmpty + name: pistol magazine (.45 magnum any) + suffix: empty + parent: BaseMagazineMagnum + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - type: entity id: MagazineMagnum name: pistol magazine (.45 magnum) @@ -117,6 +130,19 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazineMagnumSubMachineGunEmpty + name: "Vector magazine (.45 magnum any)" + suffix: empty + parent: BaseMagazineMagnumSubMachineGun + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - type: entity id: MagazineMagnumSubMachineGun name: "Vector magazine (.45 magnum)" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml index 679acd299c4..bde2731937a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/pistol.yml @@ -128,6 +128,14 @@ containers: ballistic-ammo: !type:Container +- type: entity + id: MagazinePistolSubMachineGunTopMountedEmpty + name: WT550 magazine (.35 auto top-mounted any) + parent: MagazinePistolSubMachineGunTopMounted + components: + - type: BallisticAmmoProvider + proto: null + - type: entity id: MagazinePistol name: pistol magazine (.35 auto) @@ -142,6 +150,28 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazinePistolEmpty + name: pistol magazine (.35 auto any) + suffix: empty + parent: MagazinePistol + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + + +- type: entity + id: MagazinePistolIncendiary + name: pistol magazine (.35 auto incendiary) + parent: MagazinePistol + components: + - type: BallisticAmmoProvider + proto: CartridgePistolIncendiary + - type: entity id: MagazinePistolPractice name: pistol magazine (.35 auto practice) @@ -170,6 +200,33 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazinePistolUranium + name: pistol magazine (.35 auto uranium) + parent: BaseMagazinePistol + components: + - type: BallisticAmmoProvider + proto: CartridgePistolUranium + - type: Sprite + layers: + - state: uranium + map: ["enum.GunVisualLayers.Base"] + - state: mag-1 + map: ["enum.GunVisualLayers.Mag"] + +- type: entity + id: MagazinePistolHighCapacityEmpty + name: machine pistol magazine (.35 auto any) + suffix: empty + parent: BaseMagazinePistolHighCapacity + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - type: entity id: MagazinePistolHighCapacity name: machine pistol magazine (.35 auto) @@ -232,6 +289,19 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazinePistolSubMachineGunEmpty + name: SMG magazine (.35 auto any) + suffix: empty + parent: BaseMagazinePistolSubMachineGun + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + - type: entity id: MagazinePistolSubMachineGunPractice name: SMG magazine (.35 auto practice) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/rifle.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/rifle.yml index 5ba57dce4e2..7d8aeb93463 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/rifle.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/rifle.yml @@ -47,6 +47,27 @@ - state: mag-1 map: ["enum.GunVisualLayers.Mag"] +- type: entity + id: MagazineRifleEmpty + name: "magazine (.20 rifle any)" + suffix: empty + parent: MagazineRifle + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + layers: + - state: base + map: ["enum.GunVisualLayers.Base"] + +- type: entity + id: MagazineRifleIncendiary + name: "magazine (.20 rifle incendiary)" + parent: MagazineRifle + components: + - type: BallisticAmmoProvider + proto: CartridgeRifleIncendiary + - type: entity id: MagazineRiflePractice name: "magazine (.20 rifle practice)" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/shotgun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/shotgun.yml index cbe9bbfbe97..5b0b16bf4bc 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/shotgun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/Magazines/shotgun.yml @@ -33,6 +33,15 @@ zeroVisible: false - type: Appearance +- type: entity + id: MagazineShotgunEmpty + name: ammo drum (.50 shells any) + suffix: empty + parent: BaseMagazineShotgun + components: + - type: BallisticAmmoProvider + proto: null + - type: entity id: MagazineShotgun name: ammo drum (.50 pellet) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml index b06ca64d8f6..d8e2c908b6f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Ammunition/SpeedLoaders/magnum.yml @@ -39,6 +39,27 @@ zeroVisible: false - type: Appearance +- type: entity + id: SpeedLoaderMagnumEmpty + name: "speed loader (.45 magnum any)" + parent: SpeedLoaderMagnum + components: + - type: BallisticAmmoProvider + proto: null + - type: Sprite + sprite: Objects/Weapons/Guns/Ammunition/SpeedLoaders/Magnum/magnum_speed_loader.rsi + layers: + - state: base + map: [ "enum.GunVisualLayers.Base" ] + +- type: entity + id: SpeedLoaderMagnumIncendiary + name: "speed loader (.45 magnum incendiary)" + parent: SpeedLoaderMagnum + components: + - type: BallisticAmmoProvider + proto: CartridgeMagnumIncendiary + - type: entity id: SpeedLoaderMagnumPractice name: "speed loader (.45 magnum practice)" diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_wieldable.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_wieldable.yml new file mode 100644 index 00000000000..cf858e17374 --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/base_wieldable.yml @@ -0,0 +1,12 @@ +# A basic inheritable template for a gun that is wieldable and has the standard inaccuracy. +- type: entity + id: BaseGunWieldable + abstract: true + components: + - type: Wieldable + - type: GunWieldBonus + minAngle: -20 + maxAngle: -30 + - type: Gun + minAngle: 21 + maxAngle: 32 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/watergun.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/watergun.yml index e925bdab876..c96a1522d2e 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/watergun.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Basic/watergun.yml @@ -34,8 +34,8 @@ canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: DrawableSolution solution: chamber - type: RefillableSolution diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml index ec0a0a148bd..7e07a419a1c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Battery/battery_guns.yml @@ -203,7 +203,7 @@ - type: entity name: laser rifle - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, BaseGunWieldable] id: WeaponLaserCarbine description: Favoured by Nanotrasen Security for being cheap and easy to use. components: @@ -270,7 +270,7 @@ - type: entity name: pulse carbine - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, BaseGunWieldable] id: WeaponPulseCarbine description: A high tech energy carbine favoured by the NT-ERT operatives. components: @@ -301,7 +301,7 @@ - type: entity name: pulse rifle - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, BaseGunWieldable] id: WeaponPulseRifle description: A weapon that is almost as infamous as its users. components: @@ -328,7 +328,7 @@ - type: entity name: laser cannon - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, BaseGunWieldable] id: WeaponLaserCannon description: A heavy duty, high powered laser weapon. components: @@ -383,7 +383,7 @@ - type: entity name: x-ray cannon - parent: BaseWeaponBattery + parent: [BaseWeaponBattery, BaseGunWieldable] id: WeaponXrayCannon description: An experimental weapon that uses concentrated x-ray energy against its target. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml index db98c6eabe9..32b4fc6075a 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Bow/bow.yml @@ -12,7 +12,8 @@ - type: Clothing quickEquip: false slots: - - Back + - Back + - suitStorage - type: Wieldable wieldSound: path: /Audio/Items/bow_pull.ogg diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml index a721f254c89..f90cbb6e601 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/LMGs/lmgs.yml @@ -14,6 +14,7 @@ slots: - Back - type: Wieldable + unwieldOnUse: false - type: GunRequiresWield - type: GunWieldBonus minAngle: -20 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml index 594ffb4d4d9..728783fb3ea 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Launchers/launchers.yml @@ -22,7 +22,7 @@ - type: entity name: china lake - parent: BaseWeaponLauncher + parent: [BaseWeaponLauncher, BaseGunWieldable] id: WeaponLauncherChinaLake description: PLOOP components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml index 52c5dc8a9db..6f925139fb1 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: BaseItem id: BaseArrow abstract: true @@ -35,7 +35,6 @@ - type: Tag tags: - Arrow - - CannonRestrict - type: Projectile deleteOnCollide: false onlyCollideWhenShot: true diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml index 3556d1c8f8b..b3abbfdfd3f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/magic.yml @@ -30,6 +30,39 @@ - type: IgniteOnCollide fireStacks: 0.35 +- type: entity + noSpawn: true + parent: BaseBulletTrigger + id: ProjectileDragonsBreath + name: dragon's breath + description: Try not to get toasted. + components: + - type: PointLight + color: "#E25822" + radius: 3.0 + energy: 5.0 + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/magic.rsi + layers: + - state: fireball + shader: unshaded + - type: IgnitionSource + temperature: 1000 + ignited: true + - type: RepeatingTrigger + delay: 0.5 # line of fire as well as if it hits something + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + totalIntensity: 5 # low intensity, the point is to burn attackers not to break open walls, dragons can just eat them + intensitySlope: 1 + maxIntensity: 3 + canCreateVacuum: false + deleteAfterExplosion: false + repeatable: true + - type: TimedDespawn + lifetime: 5 + - type: entity id: ProjectileAnomalyFireball name: fireball diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml index 2e7265a2c77..61df2b857ea 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Rifles/rifles.yml @@ -1,6 +1,6 @@ - type: entity name: BaseWeaponRifle - parent: BaseItem + parent: [BaseItem, BaseGunWieldable] id: BaseWeaponRifle description: A rooty tooty point and shooty. abstract: true diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml index 3962f6e1f57..b2876f91fc3 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/SMGs/smgs.yml @@ -94,7 +94,13 @@ map: ["enum.GunVisualLayers.Mag"] - type: Clothing sprite: Objects/Weapons/Guns/SMGs/c20r.rsi + - type: Wieldable + - type: GunWieldBonus + minAngle: -19 + maxAngle: -16 - type: Gun + minAngle: 21 + maxAngle: 32 shotsPerBurst: 5 availableModes: - SemiAuto @@ -126,7 +132,13 @@ map: ["enum.GunVisualLayers.Mag"] - type: Clothing sprite: Objects/Weapons/Guns/SMGs/drozd.rsi + - type: Wieldable + - type: GunWieldBonus + minAngle: -19 + maxAngle: -16 - type: Gun + minAngle: 21 + maxAngle: 32 fireRate: 6 selectedMode: FullAuto soundGunshot: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml index d1635f49791..43b038b372c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Shotguns/shotguns.yml @@ -47,7 +47,7 @@ - type: entity name: Bulldog # Don't parent to BaseWeaponShotgun because it differs significantly - parent: BaseItem + parent: [BaseItem, BaseGunWieldable] id: WeaponShotgunBulldog description: It's a magazine-fed shotgun designed for close quarters combat. Uses .50 shotgun shells. components: @@ -67,6 +67,7 @@ - Back - suitStorage - type: AmmoCounter + - type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: Gun fireRate: 2 selectedMode: FullAuto @@ -78,7 +79,6 @@ path: /Audio/Weapons/Guns/Empty/empty.ogg fireOnDropChance: 0.3 - type: Wieldable - - type: GunRequiresWield - type: ItemSlots slots: gun_magazine: @@ -105,7 +105,7 @@ - type: entity name: double-barreled shotgun - parent: BaseWeaponShotgun + parent: [BaseWeaponShotgun, BaseGunWieldable] id: WeaponShotgunDoubleBarreled description: An immortal classic. Uses .50 shotgun shells. components: @@ -115,13 +115,12 @@ size: Normal shape: - 0,0,4,0 - sprite: Objects/Weapons/Guns/Shotguns/inhands_64x.rsi - heldPrefix: db + sprite: Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi + - type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: Gun fireRate: 2 fireOnDropChance: 0.5 - type: Wieldable - - type: GunRequiresWield - type: BallisticAmmoProvider capacity: 2 - type: Construction @@ -141,14 +140,16 @@ - type: entity name: Enforcer - parent: BaseWeaponShotgun + parent: [BaseWeaponShotgun, BaseGunWieldable] id: WeaponShotgunEnforcer description: A premium combat shotgun based on the Kammerer design, featuring an upgraded clip capacity. .50 shotgun shells. components: - type: Sprite - sprite: DeltaV/Objects/Weapons/Guns/Shotguns/enforcer.rsi # Delta-V + sprite: DeltaV/Objects/Weapons/Guns/Shotguns/enforcer.rsi - type: Clothing - sprite: DeltaV/Objects/Weapons/Guns/Shotguns/enforcer.rsi # Delta-V + sprite: DeltaV/Objects/Weapons/Guns/Shotguns/enforcer.rsi + - type: Item + sprite: Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi - type: BallisticAmmoProvider - type: Wieldable - type: GunRequiresWield @@ -163,7 +164,7 @@ - type: entity name: Kammerer - parent: BaseWeaponShotgun + parent: [BaseWeaponShotgun, BaseGunWieldable] id: WeaponShotgunKammerer description: When an old Remington design meets modern materials, this is the result. A favourite weapon of militia forces throughout many worlds. Uses .50 shotgun shells. components: @@ -171,19 +172,18 @@ size: Normal shape: - 0,0,4,0 - sprite: Objects/Weapons/Guns/Shotguns/inhands_64x.rsi - heldPrefix: pump + sprite: Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi - type: Sprite - sprite: DeltaV/Objects/Weapons/Guns/Shotguns/pump.rsi # Delta-V + sprite: DeltaV/Objects/Weapons/Guns/Shotguns/pump.rsi - type: Clothing - sprite: DeltaV/Objects/Weapons/Guns/Shotguns/pump.rsi # Delta-V + sprite: DeltaV/Objects/Weapons/Guns/Shotguns/pump.rsi + - type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: BallisticAmmoProvider capacity: 4 - type: Tag tags: - WeaponShotgunKammerer - type: Wieldable - - type: GunRequiresWield - type: entity name: sawn-off shotgun @@ -197,8 +197,7 @@ sprite: DeltaV/Objects/Weapons/Guns/Shotguns/sawn.rsi # Delta-V - type: Item size: Small - sprite: Objects/Weapons/Guns/Shotguns/inhands_64x.rsi - heldPrefix: sawn + sprite: Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi - type: Gun fireRate: 4 fireOnDropChance: 0.5 @@ -250,7 +249,7 @@ - type: entity name: blunderbuss - parent: BaseWeaponShotgun + parent: [BaseWeaponShotgun, BaseGunWieldable] id: WeaponShotgunBlunderbuss suffix: Pirate description: Deadly at close range. @@ -261,6 +260,7 @@ - 0,0,4,0 - type: Sprite sprite: Objects/Weapons/Guns/Shotguns/blunderbuss.rsi + - type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: Gun fireRate: 2 fireOnDropChance: 1 @@ -269,11 +269,10 @@ - type: StaticPrice price: 0 - type: Wieldable - - type: GunRequiresWield - type: entity name: improvised shotgun - parent: BaseWeaponShotgun + parent: [BaseWeaponShotgun, BaseGunWieldable] id: WeaponShotgunImprovised description: A shitty, hand-made shotgun that uses .50 shotgun shells. It can only hold one round in the chamber. components: @@ -285,8 +284,8 @@ size: Normal shape: - 0,0,4,0 - sprite: Objects/Weapons/Guns/Shotguns/inhands_64x.rsi - heldPrefix: improvised + sprite: Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi + - type: GunRequiresWield #remove when inaccuracy on spreads is fixed - type: Gun fireRate: 4 #No reason to stifle the firerate since you have to manually reload every time anyways. fireOnDropChance: 1 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml index c4f7a8cd15b..88c00bedbd5 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Snipers/snipers.yml @@ -42,7 +42,7 @@ - type: entity name: Kardashev-Mosin - parent: BaseWeaponSniper + parent: [BaseWeaponSniper, BaseGunWieldable] id: WeaponSniperMosin description: A weapon for hunting, or endless trench warfare. Uses .30 rifle ammo. components: @@ -69,7 +69,7 @@ - type: entity name: Hristov - parent: BaseWeaponSniper + parent: [BaseWeaponSniper, BaseGunWieldable] id: WeaponSniperHristov description: A portable anti-materiel rifle. Fires armor piercing 14.5mm shells. Uses .60 anti-materiel ammo. components: diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml index ae1f5df3c15..12511729460 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/pneumatic_cannon.yml @@ -22,7 +22,6 @@ selectedMode: SemiAuto availableModes: - SemiAuto - - FullAuto soundGunshot: path: /Audio/Effects/thunk.ogg soundEmpty: @@ -34,10 +33,7 @@ - type: Storage maxItemSize: Normal grid: - - 0,0,3,3 - blacklist: - tags: - - CannonRestrict + - 0,0,1,1 - type: Appearance - type: ItemMapper containerWhitelist: [gas_tank] diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/baseball_bat.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/baseball_bat.yml index 350ea94bd9f..60f599af934 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/baseball_bat.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/baseball_bat.yml @@ -43,6 +43,9 @@ node: bat - type: UseDelay delay: 1 + - type: PhysicalComposition + materialComposition: + Wood: 250 - type: Tag tags: - BaseballBat diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml new file mode 100644 index 00000000000..5c26020d72c --- /dev/null +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/cane.yml @@ -0,0 +1,98 @@ +- type: entity + parent: BaseItem + id: Cane + name: cane + description: A wooden cane. + components: + - type: Sprite + sprite: Objects/Weapons/Melee/cane.rsi + state: cane + - type: Item + size: Normal + sprite: Objects/Weapons/Melee/cane.rsi + - type: Appearance + - type: MeleeWeapon + wideAnimationRotation: 45 + damage: + types: + Blunt: 5 + - type: StaminaDamageOnHit + damage: 5 + - type: Wieldable + - type: IncreaseDamageOnWield + damage: + types: + Blunt: 3 + - type: UseDelay + delay: 1 + +- type: entity + name: cane blade + parent: BaseItem + id: CaneBlade + description: A sharp blade with a cane shaped hilt. + components: + - type: Sharp + - type: Sprite + sprite: Objects/Weapons/Melee/cane_blade.rsi + state: icon + - type: MeleeWeapon + wideAnimationRotation: 65 + attackRate: 1.5 + damage: + types: + Slash: 14 + soundHit: + path: /Audio/Weapons/bladeslice.ogg + - type: Item + size: Normal + sprite: Objects/Weapons/Melee/cane_blade.rsi + - type: Tag + tags: + - CaneBlade + - type: DisarmMalus + +- type: entity + parent: Cane + id: CaneSheath + suffix: Empty + components: + - type: Sprite + sprite: Objects/Weapons/Melee/cane.rsi + state: cane-empty + - type: ContainerContainer + containers: + storagebase: !type:Container + ents: [] + item: !type:ContainerSlot + - type: UserInterface + interfaces: + enum.StorageUiKey.Key: + type: StorageBoundUserInterface + - type: ItemSlots + slots: + item: + name: CaneBlade + insertVerbText: sheath-insert-verb + ejectVerbText: sheath-eject-verb + whitelist: + tags: + - CaneBlade + insertSound: /Audio/Items/sheath.ogg + ejectSound: /Audio/Items/unsheath.ogg + - type: ItemMapper + mapLayers: + cane: + whitelist: + tags: + - CaneBlade + +- type: entity + id: CaneSheathFilled + parent: CaneSheath + suffix: Filled + components: + - type: ContainerFill + containers: + item: + - CaneBlade diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml index 0cbc824365d..29191f8475b 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/e_sword.yml @@ -78,6 +78,8 @@ malus: 0 - type: Reflect enabled: false + reflectProb: 0.5 + minReflectProb: 0.25 - type: IgnitionSource temperature: 700 @@ -225,7 +227,7 @@ name: double-bladed energy sword parent: EnergySword id: EnergySwordDouble - description: Syndicate Command Interns thought that having one blade on the energy sword was not enough. This can be stored in pockets. + description: Syndicate Command's intern thought that having only one blade on energy swords was not cool enough. This can be stored in pockets. components: - type: EnergySword - type: ItemToggle @@ -276,7 +278,8 @@ size: Small sprite: Objects/Weapons/Melee/e_sword_double-inhands.rsi - type: Reflect - reflectProb: .80 #DeltaV: 80% Energy Reflection but no ballistics. + reflectProb: .80 + minReflectProb: .65 spread: 75 reflects: - Energy #DeltaV: 80% Energy Reflection but no ballistics. diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml index 970a00ddf8f..5502f752892 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/knife.yml @@ -275,7 +275,6 @@ tags: - CombatKnife - Knife - - CannonRestrict - type: Sprite sprite: Objects/Weapons/Melee/throwing_knife.rsi state: icon diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml index 991a5553c79..5214358ff96 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/stunprod.yml @@ -25,9 +25,9 @@ - type: ItemToggleMeleeWeapon activatedDamage: types: - Blunt: 0 + Shock: 5 - type: Stunbaton - energyPerUse: 70 + energyPerUse: 120 - type: MeleeWeapon wideAnimationRotation: -135 attackRate: 1 diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml index 5757f9c7168..046e9f76f7f 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Melee/sword.yml @@ -16,7 +16,7 @@ path: /Audio/SimpleStation14/Weapons/Melee/rapierhit.ogg damage: types: - Slash: 17 #cmon, it has to be at least BETTER than the rest. + Slash: 15 heavyRateModifier: 0.8 heavyRangeModifier: 1 heavyDamageBaseModifier: 1 @@ -25,7 +25,12 @@ angle: 80 - type: Reflect enabled: true - reflectProb: .5 + # Design intent: a robust captain or tot can sacrifice movement to make the most of this weapon, but they have to + # really restrict themselves to walking speed or less. + reflectProb: 0.5 + velocityBeforeNotMaxProb: 1.0 + velocityBeforeMinProb: 3.0 + minReflectProb: 0.1 spread: 90 - type: Item size: Normal @@ -97,6 +102,9 @@ - Back - Belt - type: Reflect + reflectProb: 0.3 + velocityBeforeNotMaxProb: 6.0 # don't punish ninjas for being ninjas + velocityBeforeMinProb: 10.0 - type: entity name: machete @@ -200,7 +208,7 @@ name: The Throngler parent: BaseItem id: Throngler - description: Why would you make this? + description: Why would someone make this? components: - type: Sharp - type: Sprite @@ -221,7 +229,10 @@ path: /Audio/Effects/explosion_small1.ogg - type: Reflect enabled: true - reflectProb: .25 + reflectProb: 0.5 # In robust hands, deflects as well as an e-sword + velocityBeforeNotMaxProb: 1.0 + velocityBeforeMinProb: 3.0 + minReflectProb: 0.1 spread: 90 - type: Item size: Ginormous diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml index f25023b4541..acbaac29222 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Throwable/grenades.yml @@ -120,6 +120,30 @@ params: volume: 12 +- type: entity + name: Self Destruct + description: Go out on your own terms! + parent: GrenadeBase + id: SelfDestructSeq + noSpawn: true + components: + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Minibomb + totalIntensity: 400 + intensitySlope: 30 + maxIntensity: 125 + canCreateVacuum: true + - type: OnUseTimerTrigger + delay: 4.5 + beepSound: + path: /Audio/Effects/Grenades/SelfDestruct/SDS_Charge2.ogg + params: + volume: 30 + initialBeepDelay: 0 + beepInterval: 16 + + - type: entity name: supermatter grenade description: Grenade that simulates delamination of the supermatter engine, pulling things in a heap and exploding after some time. diff --git a/Resources/Prototypes/Entities/Objects/Weapons/security.yml b/Resources/Prototypes/Entities/Objects/Weapons/security.yml index 2c72afa1d27..1b07eab9faf 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/security.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/security.yml @@ -80,6 +80,10 @@ explosionType: Default intensitySlope: 1.5 maxIntensity: 200 + - type: PhysicalComposition + materialComposition: + Steel: 100 + Plastic: 100 - type: GuideHelp guides: - Security @@ -107,6 +111,9 @@ heavyStaminaCost: 7.5 - type: Item size: Normal + - type: Tag + tags: + - Truncheon - type: Clothing sprite: Objects/Weapons/Melee/truncheon.rsi quickEquip: false diff --git a/Resources/Prototypes/Entities/Objects/base_item.yml b/Resources/Prototypes/Entities/Objects/base_item.yml index 84b5477f508..9c9437f46a4 100644 --- a/Resources/Prototypes/Entities/Objects/base_item.yml +++ b/Resources/Prototypes/Entities/Objects/base_item.yml @@ -50,8 +50,8 @@ - type: Storage - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: ContainerContainer containers: storagebase: !type:Container diff --git a/Resources/Prototypes/Entities/Stations/base.yml b/Resources/Prototypes/Entities/Stations/base.yml index 0bf0f7f9159..01e037c46d4 100644 --- a/Resources/Prototypes/Entities/Stations/base.yml +++ b/Resources/Prototypes/Entities/Stations/base.yml @@ -153,4 +153,4 @@ id: BaseStationAllEventsEligible abstract: true components: - - type: StationEventEligible # For when someone makes this more granular in the future. \ No newline at end of file + - type: StationEventEligible # For when someone makes this more granular in the future. diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml index 1b660c0cf07..213ad47d88f 100644 --- a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml +++ b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml @@ -30,8 +30,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.ReagentDispenserUiKey.Key - type: ReagentDispenserBoundUserInterface + enum.ReagentDispenserUiKey.Key: + type: ReagentDispenserBoundUserInterface - type: Anchorable - type: Pullable - type: Damageable diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml index f12bd2b553e..c55b9d95548 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/access.yml @@ -152,7 +152,7 @@ components: - type: ContainerFill containers: - board: [ DoorElectronicsFreezer ] + board: [ DoorElectronicsKitchenHydroponics ] - type: entity parent: AirlockFreezer @@ -243,6 +243,16 @@ containers: board: [ DoorElectronicsChemistry ] +- type: entity + parent: AirlockMedical + id: AirlockMedicalMorgueLocked + suffix: Morgue, Locked + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsMorgue ] + + - type: entity parent: AirlockScience id: AirlockScienceLocked @@ -259,7 +269,7 @@ components: - type: ContainerFill containers: - board: [ DoorElectronicsScience ] + board: [ DoorElectronicsMedicalResearch ] - type: entity parent: AirlockCentralCommand @@ -633,7 +643,7 @@ components: - type: ContainerFill containers: - board: [ DoorElectronicsScience ] + board: [ DoorElectronicsMedicalResearch ] - type: entity parent: AirlockCentralCommandGlass @@ -982,7 +992,7 @@ components: - type: ContainerFill containers: - board: [ DoorElectronicsRnDMed ] + board: [ DoorElectronicsMedicalResearch ] - type: entity parent: AirlockMaint diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml index ec1c5991555..586902bd776 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/base_structureairlocks.yml @@ -64,6 +64,7 @@ containers: board: !type:Container - type: Weldable + fuel: 5 time: 3 - type: Airlock - type: NavMapDoor @@ -103,8 +104,8 @@ - type: SpawnOnOverload - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: Airtight noAirWhenFullyAirBlocked: false - type: RadiationBlocker diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml index e9ea05a1c3f..559dca704cd 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/highsec.yml @@ -55,6 +55,7 @@ denySound: path: /Audio/Machines/airlock_deny.ogg - type: Weldable + fuel: 10 time: 10 - type: Airlock - type: NavMapDoor @@ -78,8 +79,8 @@ alwaysRandomize: true - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: Airtight - type: Occluder - type: Damageable diff --git a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml index 5d6b1088f12..43d1228a408 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Airlocks/shuttle.yml @@ -6,6 +6,11 @@ description: Necessary for connecting two space craft together. components: - type: Docking + - type: DockingSignalControl + - type: DeviceLinkSource + ports: + - DoorStatus + - DockStatus - type: Fixtures fixtures: fix1: @@ -75,7 +80,6 @@ suffix: Glass, Docking description: Necessary for connecting two space craft together. components: - - type: Docking - type: Sprite sprite: Structures/Doors/Airlocks/Glass/shuttle.rsi snapCardinals: false @@ -127,7 +131,6 @@ suffix: Glass, Docking description: Necessary for connecting two space craft together. components: - - type: Docking - type: Sprite sprite: Structures/Doors/Airlocks/Glass/shuttle_syndicate.rsi snapCardinals: false diff --git a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml index dfa00367540..074c981da25 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Firelocks/firelock.yml @@ -82,6 +82,7 @@ openingAnimationTime: 0.6 closingAnimationTime: 0.6 - type: Weldable + fuel: 5 time: 3 - type: Firelock - type: Appearance @@ -89,7 +90,7 @@ - type: WiresPanel - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: Physics canCollide: false diff --git a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml index 91d541bf5cf..3465b646b46 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Shutter/shutters.yml @@ -56,8 +56,8 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: Airtight - type: RadiationBlocker resistance: 1 diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml index bb374b11387..462632dc074 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/base_structurewindoors.yml @@ -93,10 +93,11 @@ max: 4 - !type:DoActsBehavior acts: [ "Destruction" ] - - type: AccessReader - type: ContainerFill containers: board: [ DoorElectronics ] + - type: AccessReader + containerAccessProvider: board - type: ContainerContainer containers: board: !type:Container @@ -129,8 +130,8 @@ layoutId: Airlock - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: Appearance - type: WiresVisuals - type: Airtight diff --git a/Resources/Prototypes/Entities/Structures/Doors/Windoors/windoor.yml b/Resources/Prototypes/Entities/Structures/Doors/Windoors/windoor.yml index 2b4b2c5fe07..801bd091d00 100644 --- a/Resources/Prototypes/Entities/Structures/Doors/Windoors/windoor.yml +++ b/Resources/Prototypes/Entities/Structures/Doors/Windoors/windoor.yml @@ -48,88 +48,99 @@ id: WindoorBarLocked suffix: Bar, Locked components: - - type: AccessReader - access: [["Bar"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsBar ] - type: entity parent: Windoor id: WindoorBarKitchenLocked suffix: Bar&Kitchen, Locked components: - - type: AccessReader - access: [["Bar"], ["Kitchen"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsBarKitchen ] - type: entity parent: Windoor id: WindoorCargoLocked suffix: Logistics, Locked # DeltaV - Logistics Department replacing Cargo components: - - type: AccessReader - access: [["Cargo"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCargo ] - type: entity parent: Windoor id: WindoorChapelLocked suffix: Chapel, Locked components: - - type: AccessReader - access: [["Chapel"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsChapel ] - type: entity parent: Windoor id: WindoorHydroponicsLocked suffix: Hydroponics, Locked components: - - type: AccessReader - access: [["Hydroponics"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsHydroponics ] - type: entity parent: Windoor id: WindoorJanitorLocked suffix: Janitor, Locked components: - - type: AccessReader - access: [["Janitor"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsJanitor ] - type: entity parent: WindoorPlasma id: PlasmaWindoorJanitorLocked suffix: Janitor, Locked, Plasma components: - - type: AccessReader - access: [["Janitor"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsJanitor ] - type: entity parent: Windoor id: WindoorKitchenLocked suffix: Kitchen, Locked components: - - type: AccessReader - access: [["Kitchen"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsKitchen ] - type: entity parent: Windoor id: WindoorKitchenHydroponicsLocked suffix: Kitchen&Hydroponics, Locked components: - - type: AccessReader - access: [["Kitchen"], ["Hydroponics"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsKitchenHydroponics ] - type: entity parent: Windoor id: WindoorServiceLocked suffix: Service, Locked components: - - type: AccessReader - access: [["Service"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsService ] - type: entity parent: Windoor id: WindoorTheatreLocked suffix: Theatre, Locked components: - - type: AccessReader - access: [["Theatre"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsTheatre ] # Secure @@ -138,222 +149,285 @@ id: WindoorSecureArmoryLocked suffix: Armory, Locked components: - - type: AccessReader - access: [["Armory"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsArmory ] + +- type: entity + parent: WindoorSecurePlasma + id: PlasmaWindoorSecureArmoryLocked + suffix: Armory, Locked, Plasma + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsArmory ] - type: entity parent: WindoorSecure id: WindoorSecureAtmosphericsLocked suffix: Atmospherics, Locked components: - - type: AccessReader - access: [["Atmospherics"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsAtmospherics ] + +- type: entity + parent: WindoorSecurePlasma + id: PlasmaWindoorSecureAtmosphericsLocked + suffix: Atmospherics, Locked, Plasma + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsAtmospherics ] - type: entity parent: WindoorSecure id: WindoorSecureBarLocked suffix: Bar, Locked components: - - type: AccessReader - access: [["Bar"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsBar ] -#Delta V: Removed Brig Access -#- type: entity -# parent: WindoorSecureSecurityLocked -# id: WindoorSecureBrigLocked -# suffix: Brig, Locked -# components: -# - type: AccessReader -# access: [["Brig"]] +- type: entity + parent: WindoorSecureSecurityLocked + id: WindoorSecureBrigLocked + suffix: Brig, Locked + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsBrig ] - type: entity parent: WindoorSecure id: WindoorSecureCargoLocked suffix: Logistics, Locked # DeltaV - Logistics Department replacing Cargo components: - - type: AccessReader - access: [["Cargo"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCargo ] - type: entity parent: WindoorSecure id: WindoorSecureChapelLocked suffix: Chapel, Locked components: - - type: AccessReader - access: [["Chapel"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsChapel ] - type: entity parent: WindoorSecure id: WindoorSecureChemistryLocked suffix: Chemistry, Locked components: - - type: AccessReader - access: [["Chemistry"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsChemistry ] - type: entity parent: WindoorSecurePlasma id: PlasmaWindoorSecureChemistryLocked suffix: Chemistry, Locked, Plasma components: - - type: AccessReader - access: [["Chemistry"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsChemistry ] - type: entity parent: WindoorSecure id: WindoorSecureCentralCommandLocked suffix: Central Command, Locked components: - - type: AccessReader - access: [["CentralCommand"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCentralCommand ] - type: entity parent: WindoorSecurePlasma id: PlasmaWindoorSecureCentralCommandLocked suffix: Central Command, Locked, Plasma components: - - type: AccessReader - access: [["CentralCommand"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCentralCommand ] - type: entity parent: WindoorSecureUranium id: UraniumWindoorSecureCentralCommandLocked suffix: Central Command, Locked, Uranium components: - - type: AccessReader - access: [["CentralCommand"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCentralCommand ] - type: entity parent: WindoorSecure id: WindoorSecureCommandLocked suffix: Command, Locked components: - - type: AccessReader - access: [["Command"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsCommand ] + +- type: entity + parent: WindoorSecurePlasma + id: PlasmaWindoorSecureCommandLocked + suffix: Command, Locked, Plasma + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsCommand ] - type: entity parent: WindoorSecure id: WindoorSecureDetectiveLocked suffix: Detective, Locked components: - - type: AccessReader - access: [["Detective"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsDetective ] - type: entity parent: WindoorSecure id: WindoorSecureEngineeringLocked suffix: Engineering, Locked components: - - type: AccessReader - access: [["Engineering"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsEngineering ] - type: entity parent: WindoorSecurePlasma id: PlasmaWindoorSecureEngineeringLocked suffix: Engineering, Locked, Plasma components: - - type: AccessReader - access: [["Engineering"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsEngineering ] - type: entity parent: WindoorSecureUranium id: UraniumWindoorSecureEngineeringLocked suffix: Engineering, Locked, Uranium components: - - type: AccessReader - access: [["Engineering"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsEngineering ] - type: entity parent: WindoorSecure id: WindoorSecureExternalLocked suffix: External, Locked components: - - type: AccessReader - access: [["External"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsExternal ] - type: entity parent: WindoorSecure id: WindoorSecureJanitorLocked suffix: Janitor, Locked components: - - type: AccessReader - access: [["Janitor"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsJanitor ] - type: entity parent: WindoorSecurePlasma id: PlasmaWindoorSecureJanitorLocked suffix: Janitor, Locked, Plasma components: - - type: AccessReader - access: [["Janitor"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsJanitor ] - type: entity parent: WindoorSecure id: WindoorSecureKitchenLocked suffix: Kitchen, Locked components: - - type: AccessReader - access: [["Kitchen"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsKitchen ] - type: entity parent: WindoorSecureSecurityLocked id: WindoorSecureSecurityLawyerLocked suffix: Security/Lawyer, Locked components: - - type: AccessReader - access: [["Security"], ["Lawyer"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsSecurityLawyer ] - type: entity parent: WindoorSecure id: WindoorSecureMedicalLocked suffix: Medical, Locked components: - - type: AccessReader - access: [["Medical"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsMedical ] - type: entity parent: WindoorSecure id: WindoorSecureSalvageLocked suffix: Salvage, Locked components: - - type: AccessReader - access: [["Salvage"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsSalvage ] - type: entity parent: WindoorSecure id: WindoorSecureSecurityLocked suffix: Security, Locked components: - - type: AccessReader - access: [["Security"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsSecurity ] + +- type: entity + parent: WindoorSecurePlasma + id: PlasmaWindoorSecureSecurityLocked + suffix: Security, Locked, Plasma + components: + - type: ContainerFill + containers: + board: [ DoorElectronicsSecurity ] - type: entity parent: WindoorSecure id: WindoorSecureScienceLocked suffix: Epistemics, Locked # DeltaV - Epistemics Department replacing Science components: - - type: AccessReader - access: [["Research"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsResearch ] - type: entity parent: WindoorSecurePlasma id: PlasmaWindoorSecureScienceLocked suffix: Science, Locked, Plasma components: - - type: AccessReader - access: [["Research"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsResearch ] - type: entity parent: WindoorSecure id: WindoorSecureServiceLocked suffix: Service, Locked components: - - type: AccessReader - access: [["Service"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsService ] - type: entity parent: WindoorSecure id: WindoorSecureHeadOfPersonnelLocked suffix: HeadOfPersonnel, Locked components: - - type: AccessReader - access: [["HeadOfPersonnel"]] + - type: ContainerFill + containers: + board: [ DoorElectronicsHeadOfPersonnel ] diff --git a/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml b/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml index 792f0766799..30aa793767a 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/bookshelf.yml @@ -59,8 +59,8 @@ - Spellbook - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: InteractionOutline - type: ContainerContainer containers: diff --git a/Resources/Prototypes/Entities/Structures/Furniture/dresser.yml b/Resources/Prototypes/Entities/Structures/Furniture/dresser.yml index 1d0a25ed852..6af67b239e0 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/dresser.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/dresser.yml @@ -33,8 +33,8 @@ storagebase: !type:Container - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: InteractionOutline - type: Clickable - type: Tag diff --git a/Resources/Prototypes/Entities/Structures/Furniture/shower.yml b/Resources/Prototypes/Entities/Structures/Furniture/shower.yml index 694202efdc6..a8ba4f25a99 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/shower.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/shower.yml @@ -24,11 +24,11 @@ canCollide: false - type: InteractionOutline - type: Damageable + damageContainer: Inorganic + damageModifierSet: Metallic - type: Construction graph: Shower node: shower - damageContainer: Inorganic - damageModifierSet: Metallic - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml index f02b1262489..a3124c09f6a 100644 --- a/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml +++ b/Resources/Prototypes/Entities/Structures/Furniture/toilet.yml @@ -51,6 +51,10 @@ disposals: !type:Container - type: Physics bodyType: Static + - type: Fixtures + fixtures: + fix1: + hard: false - type: Construction graph: Toilet node: toilet @@ -66,8 +70,8 @@ price: 25 - type: UserInterface interfaces: - - key: enum.DisposalUnitUiKey.Key - type: DisposalUnitBoundUserInterface + enum.DisposalUnitUiKey.Key: + type: DisposalUnitBoundUserInterface - type: RatKingRummageable - type: SolutionContainerManager solutions: @@ -104,7 +108,10 @@ components: - type: SolutionContainerManager solutions: - toilet: + drainBuffer: + maxVol: 100 + tank: + maxVol: 500 reagents: - ReagentId: Water Quantity: 180 diff --git a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml index 22bbdb7b9f9..6b301a50eed 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/base_lighting.yml @@ -43,7 +43,7 @@ - type: RCDDeconstructable cost: 4 delay: 2 - fx: EffectRCDDeconstruct2 + fx: EffectRCDDeconstruct2 - type: Destructible thresholds: - trigger: @@ -74,7 +74,7 @@ mode: SnapgridCenter snap: - Wallmount - + - type: entity name: light description: "A light fixture. Draws power and produces light when equipped with a light tube." @@ -91,7 +91,7 @@ bulb: Tube damage: types: - Heat: 5 + Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -132,7 +132,7 @@ hasLampOnSpawn: LightTube damage: types: - Heat: 5 + Heat: 2 - type: AmbientOnPowered - type: AmbientSound volume: -15 @@ -151,7 +151,7 @@ hasLampOnSpawn: LedLightTube damage: types: - Heat: 2.5 + Heat: 1 #LEDs don't get as hot - type: PointLight radius: 15 energy: 1 @@ -173,20 +173,19 @@ - type: entity id: PoweredlightExterior description: "A light fixture. Draws power and produces light when equipped with a light tube." - suffix: Blue - noSpawn: true # DeltaV - Don't map these + suffix: Exterior parent: Poweredlight components: - type: PoweredLight hasLampOnSpawn: ExteriorLightTube damage: types: - Heat: 5 + Heat: 4 #brighter light gets hotter - type: entity parent: AlwaysPoweredWallLight id: AlwaysPoweredLightExterior - suffix: Always Powered, Blue + suffix: Always Powered, Exterior components: - type: PointLight radius: 12 @@ -205,7 +204,7 @@ hasLampOnSpawn: SodiumLightTube damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 10 energy: 2.5 @@ -292,7 +291,7 @@ bulb: Bulb damage: types: - Heat: 5 + Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -331,7 +330,7 @@ hasLampOnSpawn: LedLightBulb damage: types: - Heat: 2.5 + Heat: 1 - type: entity id: PoweredSmallLight @@ -346,7 +345,7 @@ hasLampOnSpawn: LightBulb damage: types: - Heat: 5 + Heat: 2 #Emergency Lights - type: entity @@ -361,7 +360,7 @@ radius: 5 energy: 0.6 offset: "0, 0.4" - color: "#FF4020" + color: "#7CFC00" mask: /Textures/Effects/LightMasks/double_cone.png - type: ApcPowerReceiver - type: ExtensionCableReceiver @@ -378,10 +377,10 @@ map: [ "enum.EmergencyLightVisualLayers.Base" ] - state: emergency_light_off map: [ "enum.EmergencyLightVisualLayers.LightOff" ] - color: "#FF4020" + color: "#7CFC00" - state: emergency_light_on map: [ "enum.EmergencyLightVisualLayers.LightOn" ] - color: "#FF4020" + color: "#7CFC00" shader: "unshaded" visible: false - type: Appearance @@ -401,7 +400,7 @@ hasLampOnSpawn: LightTubeCrystalCyan damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 @@ -428,7 +427,7 @@ hasLampOnSpawn: LightTubeCrystalBlue damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 @@ -455,7 +454,7 @@ hasLampOnSpawn: LightTubeCrystalPink damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 @@ -482,7 +481,7 @@ hasLampOnSpawn: LightTubeCrystalOrange damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 @@ -509,7 +508,7 @@ hasLampOnSpawn: LightTubeCrystalRed damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 @@ -536,7 +535,7 @@ hasLampOnSpawn: LightTubeCrystalGreen damage: types: - Heat: 5 + Heat: 2 - type: PointLight radius: 8 energy: 3 diff --git a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml index 34a6f08294e..2afde4ef3fc 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/ground_lighting.yml @@ -79,7 +79,7 @@ bulb: Tube damage: types: - Heat: 20 + Heat: 2 - type: ContainerContainer containers: light_bulb: !type:ContainerSlot @@ -124,7 +124,7 @@ hasLampOnSpawn: LightTube damage: types: - Heat: 20 + Heat: 2 - type: StaticPrice price: 25 - type: AmbientOnPowered @@ -153,7 +153,7 @@ hasLampOnSpawn: LedLightTube damage: types: - Heat: 20 + Heat: 1 - type: StaticPrice price: 25 - type: AmbientOnPowered diff --git a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml index 8eceb76b639..72f54396469 100644 --- a/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml +++ b/Resources/Prototypes/Entities/Structures/Lighting/strobe_lighting.yml @@ -89,7 +89,7 @@ on: false damage: types: - Heat: 5 + Heat: 2 - type: ApcPowerReceiver - type: ExtensionCableReceiver - type: DeviceNetwork @@ -145,4 +145,4 @@ volume: 0 range: 10 sound: - path: "/Audio/Effects/Lightning/strobeepsilon.ogg" \ No newline at end of file + path: "/Audio/Effects/Lightning/strobeepsilon.ogg" diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml index 59690e56ebd..98c0f229ed5 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml @@ -90,9 +90,9 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.SpaceVillainArcadeUiKey.Key + enum.SpaceVillainArcadeUiKey.Key: type: SpaceVillainArcadeBoundUserInterface - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: Computer board: SpaceVillainArcadeComputerCircuitboard @@ -134,9 +134,9 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.BlockGameUiKey.Key + enum.BlockGameUiKey.Key: type: BlockGameBoundUserInterface - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: Computer board: BlockGameArcadeComputerCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml index 39fd34016b9..0021b053214 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/computers.yml @@ -24,7 +24,7 @@ False: { visible: false } computerLayerKeys: True: { visible: true, shader: unshaded } - False: { visible: true, shader: shaded } + False: { visible: true, shader: shaded } enum.AtmosAlertsComputerVisuals.ComputerLayerScreen: computerLayerScreen: 0: { state: alert-0 } @@ -38,8 +38,8 @@ key: enum.AtmosAlertsComputerUiKey.Key - type: UserInterface interfaces: - - key: enum.AtmosAlertsComputerUiKey.Key - type: AtmosAlertsComputerBoundUserInterface + enum.AtmosAlertsComputerUiKey.Key: + type: AtmosAlertsComputerBoundUserInterface - type: entity parent: BaseComputer @@ -55,8 +55,8 @@ key: enum.EmergencyConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.EmergencyConsoleUiKey.Key - type: EmergencyConsoleBoundUserInterface + enum.EmergencyConsoleUiKey.Key: + type: EmergencyConsoleBoundUserInterface - type: PointLight radius: 1.5 energy: 1.6 @@ -76,8 +76,8 @@ key: enum.ShuttleConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.ShuttleConsoleUiKey.Key - type: ShuttleConsoleBoundUserInterface + enum.ShuttleConsoleUiKey.Key: + type: ShuttleConsoleBoundUserInterface - type: RadarConsole - type: WorldLoader radius: 256 @@ -235,8 +235,8 @@ key: enum.IFFConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.IFFConsoleUiKey.Key - type: IFFConsoleBoundUserInterface + enum.IFFConsoleUiKey.Key: + type: IFFConsoleBoundUserInterface - type: Computer board: ComputerIFFCircuitboard @@ -255,8 +255,8 @@ key: enum.IFFConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.IFFConsoleUiKey.Key - type: IFFConsoleBoundUserInterface + enum.IFFConsoleUiKey.Key: + type: IFFConsoleBoundUserInterface - type: Computer board: ComputerIFFSyndicateCircuitboard @@ -295,8 +295,8 @@ key: enum.PowerMonitoringConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.PowerMonitoringConsoleUiKey.Key - type: PowerMonitoringConsoleBoundUserInterface + enum.PowerMonitoringConsoleUiKey.Key: + type: PowerMonitoringConsoleBoundUserInterface - type: entity parent: BaseComputer @@ -330,8 +330,8 @@ - type: CriminalRecordsConsole - type: UserInterface interfaces: - - key: enum.CriminalRecordsConsoleKey.Key - type: CriminalRecordsConsoleBoundUserInterface + enum.CriminalRecordsConsoleKey.Key: + type: CriminalRecordsConsoleBoundUserInterface - type: ActivatableUI key: enum.CriminalRecordsConsoleKey.Key - type: Sprite @@ -365,8 +365,8 @@ - type: GeneralStationRecordConsole - type: UserInterface interfaces: - - key: enum.GeneralStationRecordConsoleKey.Key - type: GeneralStationRecordConsoleBoundUserInterface + enum.GeneralStationRecordConsoleKey.Key: + type: GeneralStationRecordConsoleBoundUserInterface - type: ActivatableUI key: enum.GeneralStationRecordConsoleKey.Key - type: PointLight @@ -405,7 +405,7 @@ key: enum.CrewMonitoringUIKey.Key - type: UserInterface interfaces: - - key: enum.CrewMonitoringUIKey.Key + enum.CrewMonitoringUIKey.Key: type: CrewMonitoringBoundUserInterface - type: CrewMonitoringConsole - type: DeviceNetwork @@ -440,10 +440,10 @@ key: enum.ResearchConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.ResearchConsoleUiKey.Key - type: ResearchConsoleBoundUserInterface - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.ResearchConsoleUiKey.Key: + type: ResearchConsoleBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: ApcPowerReceiver powerLoad: 1000 - type: Computer @@ -488,10 +488,10 @@ key: enum.ArtifactAnalzyerUiKey.Key - type: UserInterface interfaces: - - key: enum.ArtifactAnalzyerUiKey.Key - type: AnalysisConsoleBoundUserInterface - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.ArtifactAnalzyerUiKey.Key: + type: AnalysisConsoleBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: ApcPowerReceiver powerLoad: 1000 - type: Computer @@ -533,8 +533,8 @@ key: enum.IdCardConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.IdCardConsoleUiKey.Key - type: IdCardConsoleBoundUserInterface + enum.IdCardConsoleUiKey.Key: + type: IdCardConsoleBoundUserInterface - type: CrewManifestViewer ownerKey: enum.IdCardConsoleUiKey.Key - type: Sprite @@ -604,8 +604,8 @@ key: enum.CommunicationsConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.CommunicationsConsoleUiKey.Key - type: CommunicationsConsoleBoundUserInterface + enum.CommunicationsConsoleUiKey.Key: + type: CommunicationsConsoleBoundUserInterface - type: Computer board: CommsComputerCircuitboard - type: PointLight @@ -668,8 +668,8 @@ key: enum.SolarControlConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.SolarControlConsoleUiKey.Key - type: SolarControlConsoleBoundUserInterface + enum.SolarControlConsoleUiKey.Key: + type: SolarControlConsoleBoundUserInterface - type: Computer board: SolarControlComputerCircuitboard - type: PointLight @@ -698,8 +698,8 @@ key: enum.RadarConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.RadarConsoleUiKey.Key - type: RadarConsoleBoundUserInterface + enum.RadarConsoleUiKey.Key: + type: RadarConsoleBoundUserInterface - type: Computer board: RadarConsoleCircuitboard - type: PointLight @@ -728,8 +728,8 @@ key: enum.CargoConsoleUiKey.Shuttle - type: UserInterface interfaces: - - key: enum.CargoConsoleUiKey.Shuttle - type: CargoShuttleConsoleBoundUserInterface + enum.CargoConsoleUiKey.Shuttle: + type: CargoShuttleConsoleBoundUserInterface - type: Computer board: CargoShuttleComputerCircuitboard - type: PointLight @@ -759,12 +759,15 @@ - map: ["computerLayerKeys"] state: tech_key - type: CargoOrderConsole + - type: ActiveRadio + channels: + - Supply - type: ActivatableUI key: enum.CargoConsoleUiKey.Orders - type: UserInterface interfaces: - - key: enum.CargoConsoleUiKey.Orders - type: CargoOrderConsoleBoundUserInterface + enum.CargoConsoleUiKey.Orders: + type: CargoOrderConsoleBoundUserInterface - type: Computer board: CargoRequestComputerCircuitboard - type: PointLight @@ -807,8 +810,8 @@ key: enum.CargoConsoleUiKey.Bounty - type: UserInterface interfaces: - - key: enum.CargoConsoleUiKey.Bounty - type: CargoBountyConsoleBoundUserInterface + enum.CargoConsoleUiKey.Bounty: + type: CargoBountyConsoleBoundUserInterface - type: Computer board: CargoBountyComputerCircuitboard - type: PointLight @@ -858,8 +861,8 @@ key: enum.CloningConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.CloningConsoleUiKey.Key - type: CloningConsoleBoundUserInterface + enum.CloningConsoleUiKey.Key: + type: CloningConsoleBoundUserInterface - type: Speech speechVerb: Robotic speechSounds: Pai @@ -902,7 +905,7 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.SalvageConsoleUiKey.Expedition + enum.SalvageConsoleUiKey.Expedition: type: SalvageExpeditionConsoleBoundUserInterface - type: Computer board: SalvageExpeditionsComputerCircuitboard @@ -947,8 +950,8 @@ anchored: true - type: UserInterface interfaces: - - key: enum.SurveillanceCameraMonitorUiKey.Key - type: SurveillanceCameraMonitorBoundUserInterface + enum.SurveillanceCameraMonitorUiKey.Key: + type: SurveillanceCameraMonitorBoundUserInterface - type: entity parent: BaseComputer @@ -984,8 +987,8 @@ - type: ActivatableUIRequiresVision - type: UserInterface interfaces: - - key: enum.SurveillanceCameraMonitorUiKey.Key - type: SurveillanceCameraMonitorBoundUserInterface + enum.SurveillanceCameraMonitorUiKey.Key: + type: SurveillanceCameraMonitorBoundUserInterface - type: entity id: ComputerPalletConsole @@ -1011,8 +1014,8 @@ key: enum.CargoPalletConsoleUiKey.Sale - type: UserInterface interfaces: - - key: enum.CargoPalletConsoleUiKey.Sale - type: CargoPalletConsoleBoundUserInterface + enum.CargoPalletConsoleUiKey.Sale: + type: CargoPalletConsoleBoundUserInterface - type: Computer board: CargoRequestComputerCircuitboard - type: PointLight @@ -1052,8 +1055,8 @@ anchored: true - type: UserInterface interfaces: - - key: enum.NewsWriterUiKey.Key - type: NewsWriterBoundUserInterface + enum.NewsWriterUiKey.Key: + type: NewsWriterBoundUserInterface - type: entity parent: BaseComputer @@ -1085,7 +1088,7 @@ key: enum.SensorMonitoringConsoleUiKey.Key - type: UserInterface interfaces: - - key: enum.SensorMonitoringConsoleUiKey.Key + enum.SensorMonitoringConsoleUiKey.Key: type: SensorMonitoringConsoleBoundUserInterface - type: DeviceNetwork deviceNetId: AtmosDevices @@ -1097,3 +1100,42 @@ - type: WiredNetworkConnection - type: DeviceList - type: AtmosDevice + +- type: entity + parent: BaseComputer + id: ComputerRoboticsControl + name: robotics control console + description: Used to remotely monitor, disable and destroy the station's cyborgs. + components: + - type: Sprite + layers: + - map: ["computerLayerBody"] + state: computer + - map: ["computerLayerKeyboard"] + state: generic_keyboard + - map: ["computerLayerScreen"] + state: robot + - map: ["computerLayerKeys"] + state: rd_key + - type: RoboticsConsole + - type: ActiveRadio + channels: + - Science + - type: ActivatableUI + key: enum.RoboticsConsoleUiKey.Key + - type: UserInterface + interfaces: + enum.RoboticsConsoleUiKey.Key: + type: RoboticsConsoleBoundUserInterface + - type: ApcPowerReceiver + powerLoad: 1000 + - type: DeviceNetwork + deviceNetId: Wireless + receiveFrequencyId: RoboticsConsole + transmitFrequencyId: CyborgControl + - type: Computer + board: RoboticsConsoleCircuitboard + - type: AccessReader # only used for dangerous things + access: [["ResearchDirector"]] + - type: Lock + unlockOnClick: false diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/techdiskterminal.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/techdiskterminal.yml index df989a77957..dd58b9709d3 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/techdiskterminal.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/techdiskterminal.yml @@ -19,10 +19,10 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.DiskConsoleUiKey.Key - type: DiskConsoleBoundUserInterface - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.DiskConsoleUiKey.Key: + type: DiskConsoleBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: ExtensionCableReceiver - type: Computer board: TechDiskComputerCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml index 6ac969171e0..4cb76ea4b92 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Medical/cryo_pod.yml @@ -89,9 +89,9 @@ scanDelay: 0 - type: UserInterface interfaces: - - key: enum.HealthAnalyzerUiKey.Key + enum.HealthAnalyzerUiKey.Key: type: HealthAnalyzerBoundUserInterface - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: ActivatableUI key: enum.HealthAnalyzerUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml index e6f08fe8467..09ee110054a 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/anomaly_equipment.yml @@ -27,8 +27,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: Machine board: AnomalyVesselCircuitboard - type: PointLight @@ -298,8 +298,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.AnomalyGeneratorUiKey.Key - type: AnomalyGeneratorBoundUserInterface + enum.AnomalyGeneratorUiKey.Key: + type: AnomalyGeneratorBoundUserInterface - type: Appearance - type: ActiveRadio channels: diff --git a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml index 2bea530e908..747b927e2f2 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/artifact_analyzer.yml @@ -44,6 +44,7 @@ powerLoad: 12000 needsPower: false #only turns on when scanning - type: ArtifactAnalyzer + - type: TraversalDistorter - type: ItemPlacer whitelist: components: diff --git a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml index 89cadab6b1f..88e650068eb 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/bombs.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/bombs.yml @@ -10,7 +10,7 @@ - type: InteractionOutline - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: Wires layoutId: Defusable diff --git a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml index aee12460214..4e565054b46 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/chem_master.yml @@ -50,8 +50,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.ChemMasterUiKey.Key - type: ChemMasterBoundUserInterface + enum.ChemMasterUiKey.Key: + type: ChemMasterBoundUserInterface - type: ApcPowerReceiver powerLoad: 250 - type: Appearance diff --git a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml index e8439f82131..c9b2045bac7 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/fax_machine.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity parent: BaseMachinePowered id: FaxMachineBase name: long range fax machine @@ -9,7 +9,7 @@ drawdepth: SmallObjects layers: - state: icon - map: ["base"] + map: [ "enum.FaxMachineVisuals.VisualState" ] - type: Icon sprite: Structures/Machines/fax_machine.rsi state: icon @@ -32,30 +32,34 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.FaxUiKey.Key - type: FaxBoundUi + enum.FaxUiKey.Key: + type: FaxBoundUi - type: ApcPowerReceiver powerLoad: 250 + - type: Faxecute + damage: + types: + Blunt: 100 - type: FaxMachine paperSlot: insertSound: /Audio/Machines/scanning.ogg ejectSound: /Audio/Machines/tray_eject.ogg whitelist: components: - - Paper + - FaxableObject blacklist: tags: - - PaperSlip # DeltaV - Prevent the faxing of paper slips. + - PaperSlip - type: GenericVisualizer visuals: enum.PowerDeviceVisuals.Powered: - base: + enum.FaxMachineVisuals.VisualState: True: { state: idle } False: { state: icon } enum.FaxMachineVisuals.VisualState: - base: - Inserting: { state: inserting } + enum.FaxMachineVisuals.VisualState: Printing: { state: printing } + Normal: {state: idle} - type: ItemSlots - type: ContainerContainer containers: @@ -112,4 +116,3 @@ receiveStationGoal: true - type: StealTarget stealGroup: FaxMachineCaptain - diff --git a/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml b/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml index 3244789a028..b4f05cf68a7 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/flatpacker.yml @@ -58,8 +58,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.FlatpackCreatorUIKey.Key - type: FlatpackCreatorBoundUserInterface + enum.FlatpackCreatorUIKey.Key: + type: FlatpackCreatorBoundUserInterface - type: ItemSlots slots: board_slot: diff --git a/Resources/Prototypes/Entities/Structures/Machines/gateway.yml b/Resources/Prototypes/Entities/Structures/Machines/gateway.yml index b6ad9db356f..dd01adf6d5c 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/gateway.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/gateway.yml @@ -52,6 +52,6 @@ key: enum.GatewayUiKey.Key - type: UserInterface interfaces: - - key: enum.GatewayUiKey.Key - type: GatewayBoundUserInterface + enum.GatewayUiKey.Key: + type: GatewayBoundUserInterface - type: Gateway diff --git a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml index 618538dccb7..6ee454c6a98 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/gravity_generator.yml @@ -62,8 +62,8 @@ on: "on" - type: UserInterface interfaces: - - key: enum.GravityGeneratorUiKey.Key - type: GravityGeneratorBoundUserInterface + enum.GravityGeneratorUiKey.Key: + type: GravityGeneratorBoundUserInterface - type: Appearance - type: PointLight radius: 2.5 diff --git a/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml b/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml index 3764f135915..003916ce94e 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/hotplate.yml @@ -43,7 +43,7 @@ map: ["enum.SolutionHeaterVisuals.IsOn"] shader: unshaded - type: SolutionHeater - heatPerSecond: 160 + baseHeatPerSecond: 160 - type: ItemPlacer whitelist: components: diff --git a/Resources/Prototypes/Entities/Structures/Machines/jukebox.yml b/Resources/Prototypes/Entities/Structures/Machines/jukebox.yml index 76b8ddd36ba..acd8527dbba 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/jukebox.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/jukebox.yml @@ -26,8 +26,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.JukeboxUiKey.Key - type: JukeboxBoundUserInterface + enum.JukeboxUiKey.Key: + type: JukeboxBoundUserInterface - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index 52e9096791b..ef2fe8d9abf 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -38,10 +38,10 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.LatheUiKey.Key - type: LatheBoundUserInterface - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.LatheUiKey.Key: + type: LatheBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: Transform anchored: true - type: Pullable @@ -50,11 +50,46 @@ - type: ResearchClient - type: TechnologyDatabase +# a lathe that can be sped up with space lube / slowed down with glue - type: entity - id: Autolathe + abstract: true parent: BaseLathe + id: BaseLatheLube + components: + - type: ReagentSpeed + solution: lube + modifiers: + SpaceLube: 0.25 + SpaceGlue: 5 + - type: SolutionContainerManager + solutions: + lube: + maxVol: 250 + - type: Spillable + solution: lube + - type: RefillableSolution + solution: lube + - type: ExaminableSolution + solution: lube + +- type: entity + abstract: true + id: BaseHyperlathe + components: + - type: Lathe + materialUseMultiplier: 0.5 + timeMultiplier: 1.5 + - type: LatheHeatProducing + - type: ReagentSpeed + modifiers: + SpaceLube: 0.8 # being faster means less heat so lube needs to be nerfed + SpaceGlue: 5 # no change from normal lathe, overheat!!! + +- type: entity + id: Autolathe + parent: BaseLatheLube name: autolathe - description: It produces items using metal and glass. + description: It produces basic items using metal and glass. components: - type: Sprite sprite: Structures/Machines/autolathe.rsi @@ -121,6 +156,7 @@ - DrinkGlass - DrinkShotGlass - DrinkGlassCoupeShaped + - CustomDrinkJug - FoodPlate - FoodPlateSmall - FoodPlatePlastic @@ -162,88 +198,46 @@ - ClothingHeadHatWelding - type: EmagLatheRecipes emagStaticRecipes: - - CartridgePistol - - CartridgeMagnum - - ShellShotgun - - ShellShotgunFlare - - ShellTranquilizer - - CartridgeLightRifle - - CartridgeRifle - - CombatKnife - - MagazineBoxPistol - - MagazineBoxMagnum - - MagazineBoxRifle - - MagazineBoxLightRifle - - GrenadeBlast - # DeltaV - .38 special ammo - Add .38 special lethals to emagged autolathe - - CartridgeSpecial - - MagazineBoxSpecial - # End of modified code - emagDynamicRecipes: - - CartridgePistolRubber - - CartridgeMagnumRubber - - ShellShotgunBeanbag - - CartridgeRifleRubber - - CartridgeLightRifleRubber - - MagazineBoxPistolRubber - - MagazineBoxMagnumRubber - - MagazineBoxRifleRubber - - MagazineBoxLightRifleRubber - - ShellShotgunIncendiary - - CartridgePistolIncendiary - - CartridgeMagnumIncendiary - - CartridgeLightRifleIncendiary - - CartridgeRifleIncendiary - - MagazineBoxPistolIncendiary - - MagazineBoxMagnumIncendiary - - MagazineBoxLightRifleIncendiary - - MagazineBoxRifleIncendiary - - ShellShotgunUranium - - CartridgePistolUranium - - CartridgeMagnumUranium - - CartridgeLightRifleUranium - - CartridgeRifleUranium - - MagazineBoxPistolUranium - - MagazineBoxMagnumUranium - - MagazineBoxLightRifleUranium - - MagazineBoxRifleUranium - - PowerCageSmall - - PowerCageMedium - - PowerCageHigh - - MagazineGrenadeEmpty - - GrenadeEMP - - GrenadeFlash - # DeltaV - .38 special ammo - Add various .38 special ammo to emagged autolathe - - CartridgeSpecialRubber - - CartridgeSpecialIncendiary - - CartridgeSpecialUranium - - CartridgeSpecialMindbreaker - - MagazineBoxSpecialRubber - - MagazineBoxSpecialIncendiary - - MagazineBoxSpecialUranium - - MagazineBoxSpecialMindbreaker - # End of modified code + - BoxLethalshot + - BoxShotgunFlare + - BoxShotgunSlug + - MagazineBoxLightRifle + - MagazineBoxMagnum + - MagazineBoxPistol + - MagazineBoxRifle + - MagazineLightRifle + - MagazineLightRifleEmpty + - MagazinePistol + - MagazinePistolEmpty + - MagazinePistolSubMachineGun + - MagazinePistolSubMachineGunEmpty + - MagazinePistolSubMachineGunTopMounted + - MagazinePistolSubMachineGunTopMountedEmpty + - MagazineRifle + - MagazineRifleEmpty + - MagazineShotgun + - MagazineShotgunEmpty + - MagazineShotgunSlug + - RiotShield + - SpeedLoaderMagnum + - SpeedLoaderMagnumEmpty - type: entity id: AutolatheHyperConvection - parent: Autolathe + parent: [Autolathe, BaseHyperlathe] name: hyper convection autolathe description: A highly-experimental autolathe that harnesses the power of extreme heat to slowly create objects more cost-effectively. components: - type: Sprite sprite: Structures/Machines/autolathe_hypercon.rsi - - type: Lathe - materialUseMultiplier: 0.5 - timeMultiplier: 1.5 - - type: LatheHeatProducing - type: Machine board: AutolatheHyperConvectionMachineCircuitboard - type: entity id: Protolathe - parent: BaseLathe + parent: BaseLatheLube name: protolathe - description: Converts raw materials into useful objects. + description: Converts raw materials into advanced items. components: - type: Sprite sprite: Structures/Machines/protolathe.rsi @@ -316,6 +310,7 @@ - PowerCellMicroreactor - PowerCellHigh - WeaponPistolCHIMP + - ClothingMaskWeldingGas - WeaponGauntletGorilla - SynthesizerInstrument - RPED @@ -325,11 +320,11 @@ - HolofanProjector - BluespaceBeaker - SyringeBluespace - #- WeaponForceGun + - WeaponForceGun - WeaponLaserSvalinn - WeaponProtoKineticAccelerator - #- WeaponTetherGun - #- WeaponGrapplingGun + - WeaponTetherGun + - WeaponGrapplingGun - ClothingBackpackHolding - ClothingBackpackSatchelHolding - ClothingBackpackDuffelHolding @@ -365,10 +360,44 @@ - RCD #EE - type: EmagLatheRecipes emagDynamicRecipes: + - BoxBeanbag + - BoxShotgunIncendiary + - BoxShotgunUranium - ExplosivePayload - - WeaponLaserCarbine + - GrenadeBlast + - GrenadeEMP + - GrenadeFlash + - HoloprojectorSecurity + - MagazineBoxLightRifleIncendiary + - MagazineBoxLightRifleUranium + - MagazineBoxMagnumIncendiary + - MagazineBoxMagnumUranium + - MagazineBoxPistolIncendiary + - MagazineBoxPistolUranium + - MagazineBoxRifleIncendiary + - MagazineBoxRifleUranium + - MagazineGrenadeEmpty + - MagazineLightRifleIncendiary + - MagazineLightRifleUranium + - MagazinePistolIncendiary + - MagazinePistolUranium + - MagazineRifleIncendiary + - MagazineRifleUranium + - MagazineShotgunBeanbag + - MagazineShotgunIncendiary + - MagazineShotgunIncendiary + - PortableRecharger + - PowerCageHigh + - PowerCageMedium + - PowerCageSmall + - ShellTranquilizer + - SpeedLoaderMagnumIncendiary + - SpeedLoaderMagnumUranium + - TelescopicShield + - Truncheon - WeaponAdvancedLaser - WeaponLaserCannon + - WeaponLaserCarbine - WeaponXrayCannon - WeaponEnergyGun # DeltaV - Energy Gun - WeaponEnergyGunMini # DeltaV - Miniature Energy Gun @@ -377,22 +406,18 @@ - type: entity id: ProtolatheHyperConvection - parent: Protolathe + parent: [Protolathe, BaseHyperlathe] name: hyper convection protolathe description: A highly-experimental protolathe that harnesses the power of extreme heat to slowly create objects more cost-effectively. components: - type: Sprite sprite: Structures/Machines/protolathe_hypercon.rsi - - type: Lathe - materialUseMultiplier: 0.5 - timeMultiplier: 1.5 - - type: LatheHeatProducing - type: Machine board: ProtolatheHyperConvectionMachineCircuitboard - type: entity id: CircuitImprinter - parent: BaseLathe + parent: BaseLatheLube name: circuit imprinter description: Prints circuit boards for machines. components: @@ -461,6 +486,7 @@ - PowerComputerCircuitboard - AutolatheHyperConvectionMachineCircuitboard - ProtolatheHyperConvectionMachineCircuitboard + - CircuitImprinterHyperConvectionMachineCircuitboard - FatExtractorMachineCircuitboard - FlatpackerMachineCircuitboard - SheetifierMachineCircuitboard @@ -500,12 +526,10 @@ - AnomalySynchronizerCircuitboard - APECircuitboard - ArtifactAnalyzerMachineCircuitboard - - TraversalDistorterMachineCircuitboard - ArtifactCrusherMachineCircuitboard - TelecomServerCircuitboard - MassMediaCircuitboard - ReagentGrinderIndustrialMachineCircuitboard - # Begin Nyano additions - ReverseEngineeringMachineCircuitboard - CrewMonitoringComputerCircuitboard - DoorElectronics @@ -516,8 +540,14 @@ - SalvageMagnetMachineCircuitboard - StationMapElectronics - MetempsychoticMachineCircuitboard - # End Nyano additions - - SalvageExpeditionsComputerCircuitboard # DeltaV + - SalvageExpeditionsComputerCircuitboard + - JukeboxCircuitBoard + - type: EmagLatheRecipes + emagDynamicRecipes: + - ShuttleGunDusterCircuitboard + - ShuttleGunFriendshipCircuitboard + - ShuttleGunPerforatorCircuitboard + - ShuttleGunSvalinnMachineGunCircuitboard - type: MaterialStorage whitelist: tags: @@ -526,9 +556,20 @@ - Ingot - type: RequireProjectileTarget +- type: entity + id: CircuitImprinterHyperConvection + parent: [CircuitImprinter, BaseHyperlathe] + name: hyper convection circuit imprinter + description: A highly-experimental circuit imprinter that harnesses the power of extreme heat to slowly create objects more cost-effectively. + components: + - type: Sprite + sprite: Structures/Machines/circuit_imprinter_hypercon.rsi + - type: Machine + board: CircuitImprinterHyperConvectionMachineCircuitboard + - type: entity id: ExosuitFabricator - parent: BaseLathe + parent: BaseLatheLube name: exosuit fabricator description: Creates parts for robotics and other mechanical needs components: @@ -692,7 +733,7 @@ - type: entity id: SecurityTechFab - parent: BaseLathe + parent: BaseLatheLube name: security techfab description: Prints equipment for use by security crew. components: @@ -715,49 +756,62 @@ idleState: icon runningState: icon staticRecipes: + - BoxLethalshot + - BoxShotgunFlare + - BoxShotgunPractice + - BoxShotgunSlug - ClothingEyesHudSecurity - CombatKnife - Flash - - Handcuffs - - Zipties - - Stunbaton - ForensicPad - - RiotShield + - Handcuffs - ShellShotgun - ShellShotgunSlug - ShellShotgunFlare - ShellTranquilizer + - MagazineBoxLightRifle + - MagazineBoxLightRiflePractice + - MagazineBoxMagnum + - MagazineBoxMagnumPractice + - MagazineBoxPistol + - MagazineBoxPistolPractice + - MagazineBoxRifle + - MagazineBoxRiflePractice + - MagazineLightRifle + - MagazineLightRifleEmpty - MagazinePistol + - MagazinePistolEmpty - MagazinePistolSubMachineGun + - MagazinePistolSubMachineGunEmpty - MagazinePistolSubMachineGunTopMounted + - MagazinePistolSubMachineGunTopMountedEmpty - MagazineRifle - - MagazineLightRifle - - MagazineBoxPistol - - MagazineBoxMagnum - - MagazineBoxRifle - - MagazineBoxLightRifle + - MagazineRifleEmpty + - MagazineShotgun + - MagazineShotgunEmpty + - MagazineShotgunSlug + - RiotShield - SpeedLoaderMagnum - - ClothingOuterArmorPlateCarrier # DeltaV - plate carrier body armour - - ClothingOuterArmorDuraVest # DeltaV - stabproof vest body armour + - SpeedLoaderMagnumEmpty + - Stunbaton + - TargetClown + - ClothingOuterArmorPlateCarrier + - ClothingOuterArmorDuraVest - TargetHuman - TargetSyndicate - - TargetClown - - MagazineBoxLightRiflePractice - - MagazineBoxMagnumPractice - - MagazineBoxPistolPractice - - MagazineBoxRiflePractice - - ShellShotgunPractice - - WeaponLaserCarbinePractice - WeaponDisablerPractice + - WeaponLaserCarbinePractice + - Zipties - ShockCollar - # DeltaV - .38 special ammo - Add various .38 special ammo to security techfab - MagazineBoxSpecial - MagazineBoxSpecialPractice - SpeedLoaderSpecial - MagazinePistolSpecial - # End of modified code dynamicRecipes: - - EncryptionKeySyndie # Nyano + - BoxBeanbag + - BoxShotgunIncendiary + - BoxShotgunUranium + - EncryptionKeySyndie - CartridgeLightRifleIncendiary - CartridgeMagnumIncendiary - CartridgePistolIncendiary @@ -773,34 +827,51 @@ - ClothingEyesGlassesSecurity - ExplosivePayload - FlashPayload + - GrenadeBlast + - GrenadeEMP + - GrenadeFlash - HoloprojectorSecurity - MagazineBoxLightRifleIncendiary - - MagazineBoxMagnumIncendiary - - MagazineBoxPistolIncendiary - - MagazineBoxRifleIncendiary - MagazineBoxLightRifleUranium + - MagazineBoxMagnumIncendiary - MagazineBoxMagnumUranium + - MagazineBoxPistolIncendiary - MagazineBoxPistolUranium + - MagazineBoxRifleIncendiary - MagazineBoxRifleUranium - - ShellSoulbreaker # Nyanotrasen - Shotgun shell to get rid of psionics + - ShellSoulbreaker - MagazineBoxLightRifleRubber - MagazineBoxMagnumRubber - MagazineBoxPistolRubber - MagazineBoxRifleRubber - MagazineGrenadeEmpty - - GrenadeEMP - - GrenadeFlash - - ShellShotgunBeanbag - - ShellShotgunIncendiary - - ShellShotgunUranium + - MagazineLightRifleIncendiary + - MagazineLightRifleUranium + - MagazinePistolIncendiary + - MagazinePistolUranium + - MagazineRifleIncendiary + - MagazineRifleUranium + - MagazineShotgunBeanbag + - MagazineShotgunIncendiary + - PortableRecharger + - PowerCageHigh + - PowerCageMedium + - PowerCageSmall + - ShellTranquilizer + - ShuttleGunDusterCircuitboard + - ShuttleGunFriendshipCircuitboard + - ShuttleGunPerforatorCircuitboard + - ShuttleGunSvalinnMachineGunCircuitboard - Signaller - SignalTrigger + - SpeedLoaderMagnumIncendiary + - SpeedLoaderMagnumUranium - TelescopicShield - TimerTrigger - Truncheon - VoiceTrigger - - WeaponDisablerPractice - WeaponAdvancedLaser + - WeaponDisabler - WeaponDisablerSMG - WeaponLaserCannon - WeaponLaserCarbine @@ -808,18 +879,10 @@ - ClothingHeadCage # Nyanotrasen - Insulative headgear - ShockCollar # Nyanotrasen - Shock Collar - WeaponXrayCannon - - PowerCageSmall - - PowerCageMedium - - PowerCageHigh - - ShuttleGunSvalinnMachineGunCircuitboard - - ShuttleGunPerforatorCircuitboard - - ShuttleGunFriendshipCircuitboard - - ShuttleGunDusterCircuitboard - - WeaponEnergyGun #DeltaV - Energy Gun - - WeaponEnergyGunMini #DeltaV - Energy Gun but miniature - - WeaponEnergyGunPistol #DeltaV - Energy Gun Mini but with the power of a normal energy gun - - WeaponGunLaserCarbineAutomatic #DeltaV - New Laser Projectiles with a 20 round carbine - # DeltaV - .38 special ammo - Add various .38 special ammo to security techfab + - WeaponEnergyGun + - WeaponEnergyGunMini + - WeaponEnergyGunPistol + - WeaponGunLaserCarbineAutomatic - CartridgeSpecialRubber - CartridgeSpecialIncendiary - CartridgeSpecialUranium @@ -829,7 +892,6 @@ - MagazineBoxSpecialIncendiary - MagazineBoxSpecialUranium - MagazineBoxSpecialMindbreaker - # End of modified code - type: MaterialStorage whitelist: tags: @@ -839,7 +901,7 @@ - type: entity id: AmmoTechFab - parent: BaseLathe + parent: BaseLatheLube name: ammo techfab description: Prints the bare minimum of bullets that any budget military or armory could need. Nothing fancy. components: @@ -862,22 +924,27 @@ idleState: icon runningState: icon staticRecipes: - - CartridgePistol - - CartridgeMagnum - - ShellShotgun - - ShellShotgunSlug - - ShellShotgunFlare - - ShellTranquilizer - - CartridgeLightRifle - - CartridgeRifle - - MagazineBoxPistol + - BoxLethalshot + - BoxShotgunFlare + - BoxShotgunSlug + - MagazineBoxLightRifle - MagazineBoxMagnum + - MagazineBoxPistol - MagazineBoxRifle - - MagazineBoxLightRifle - # DeltaV - .38 special ammo - Add lethal .38 special ammo to ammo techfab + - MagazineLightRifle + - MagazineLightRifleEmpty + - MagazinePistol + - MagazinePistolEmpty + - MagazineRifle + - MagazineRifleEmpty + - MagazineShotgun + - MagazineShotgunEmpty + - MagazineShotgunSlug + - ShellTranquilizer + - SpeedLoaderMagnum + - SpeedLoaderMagnumEmpty - CartridgeSpecial - MagazineBoxSpecial - # End of modified code - type: MaterialStorage whitelist: tags: @@ -887,7 +954,7 @@ - type: entity id: MedicalTechFab - parent: BaseLathe + parent: BaseLatheLube name: medical techfab description: Prints equipment for use by the medbay. components: @@ -1095,7 +1162,8 @@ - ClothingOuterWinterCE - ClothingOuterWinterCMO - ClothingOuterWinterHoP - - ClothingOuterWinterHoS + - ClothingOuterWinterHoSUnarmored + - ClothingOuterWinterWardenUnarmored - ClothingOuterWinterQM - ClothingOuterWinterRD - ClothingNeckMantleCap @@ -1299,7 +1367,6 @@ - type: LitOnPowered - type: ApcPowerReceiver powerLoad: 200 - priority: Low # - type: Advertise # pack: CuddlyCritterAds # TODO Change this - type: PointLight diff --git a/Resources/Prototypes/Entities/Structures/Machines/microwave.yml b/Resources/Prototypes/Entities/Structures/Machines/microwave.yml index 55dfe296a61..994269f71b4 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/microwave.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/microwave.yml @@ -44,8 +44,8 @@ range: 200 - type: UserInterface interfaces: - - key: enum.MicrowaveUiKey.Key - type: MicrowaveBoundUserInterface + enum.MicrowaveUiKey.Key: + type: MicrowaveBoundUserInterface - type: Physics - type: Fixtures fixtures: diff --git a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml index f37c42e4745..bc4581d7b65 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/nuke.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/nuke.yml @@ -88,8 +88,8 @@ key: enum.NukeUiKey.Key - type: UserInterface interfaces: - - key: enum.NukeUiKey.Key - type: NukeBoundUserInterface + enum.NukeUiKey.Key: + type: NukeBoundUserInterface - type: StaticPrice price: 50000 # YOU STOLE A NUCLEAR FISSION EXPLOSIVE?! - type: CargoSellBlacklist diff --git a/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml b/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml index 80bfb465fff..28aa464d210 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/reagent_grinder.yml @@ -12,8 +12,8 @@ key: enum.ReagentGrinderUiKey.Key - type: UserInterface interfaces: - - key: enum.ReagentGrinderUiKey.Key - type: ReagentGrinderBoundUserInterface + enum.ReagentGrinderUiKey.Key: + type: ReagentGrinderBoundUserInterface - type: Appearance - type: GenericVisualizer visuals: @@ -101,4 +101,4 @@ - type: DrainableSolution solution: output - type: ExaminableSolution - solution: output \ No newline at end of file + solution: output diff --git a/Resources/Prototypes/Entities/Structures/Machines/research.yml b/Resources/Prototypes/Entities/Structures/Machines/research.yml index 948b3f84b26..498759df3c9 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/research.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/research.yml @@ -83,8 +83,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.ResearchClientUiKey.Key - type: ResearchClientBoundUserInterface + enum.ResearchClientUiKey.Key: + type: ResearchClientBoundUserInterface - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/Entities/Structures/Machines/salvage.yml b/Resources/Prototypes/Entities/Structures/Machines/salvage.yml index 859dc85ff1d..6a2f6c810c2 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/salvage.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/salvage.yml @@ -28,8 +28,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.SalvageMagnetUiKey.Key - type: SalvageMagnetBoundUserInterface + enum.SalvageMagnetUiKey.Key: + type: SalvageMagnetBoundUserInterface - type: Transform noRot: false - type: Appearance diff --git a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml index e359db813f6..7b342def540 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/surveillance_camera_routers.yml @@ -13,7 +13,7 @@ - type: DeviceNetworkRequiresPower - type: UserInterface interfaces: - - key: enum.SurveillanceCameraSetupUiKey.Router + enum.SurveillanceCameraSetupUiKey.Router: type: SurveillanceCameraSetupBoundUi - type: Machine board: SurveillanceCameraRouterCircuitboard @@ -118,7 +118,7 @@ - type: DeviceNetworkRequiresPower - type: UserInterface interfaces: - - key: enum.SurveillanceCameraSetupUiKey.Router + enum.SurveillanceCameraSetupUiKey.Router: type: SurveillanceCameraSetupBoundUi - type: Machine board: SurveillanceCameraWirelessRouterCircuitboard diff --git a/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml b/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml index 2a7d827522e..13fdb7e80d4 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/telecomms.yml @@ -67,7 +67,7 @@ - type: entity parent: TelecomServer id: TelecomServerFilled - suffix: Filled + suffix: Filled All components: - type: ContainerFill containers: diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index f3f68660b2d..7a0f4660554 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -60,10 +60,10 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.VendingMachineUiKey.Key - type: VendingMachineBoundUserInterface - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.VendingMachineUiKey.Key: + type: VendingMachineBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: WiresPanel - type: Wires boardName: wires-board-name-vendingmachine diff --git a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml index 0a145177713..95079b5c858 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/wireless_surveillance_camera.yml @@ -35,7 +35,7 @@ range: 10 - type: UserInterface interfaces: - - key: enum.SurveillanceCameraSetupUiKey.Camera + enum.SurveillanceCameraSetupUiKey.Camera: type: SurveillanceCameraSetupBoundUi placement: mode: SnapgridCenter diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml index 4bea87f8175..fa5804c6452 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/binary.yml @@ -51,8 +51,8 @@ enabled: false - type: UserInterface interfaces: - - key: enum.GasPressurePumpUiKey.Key - type: GasPressurePumpBoundUserInterface + enum.GasPressurePumpUiKey.Key: + type: GasPressurePumpBoundUserInterface - type: Construction graph: GasBinary node: pressurepump @@ -92,7 +92,7 @@ enabled: false - type: UserInterface interfaces: - - key: enum.GasVolumePumpUiKey.Key + enum.GasVolumePumpUiKey.Key: type: GasVolumePumpBoundUserInterface - type: Construction graph: GasBinary diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml index e5b77095b0e..0025fc5ae1b 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/pipes.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity abstract: true id: GasPipeBase parent: BaseItem @@ -101,6 +101,20 @@ - type: Construction graph: GasPipe node: straight + - type: Item + size: Normal + storedSprite: + sprite: Structures/Piping/Atmospherics/pipe.rsi + state: storageStraight + shape: + - 0,0,0,2 + - type: MeleeWeapon + attackRate: 1 + damage: + types: + Blunt: 8 + soundHit: + collection: MetalThud # this NEEDS to changed to the metal pipe falling sound effect on april first every year - type: entity parent: GasPipeBase @@ -120,6 +134,27 @@ - type: Construction graph: GasPipe node: bend + - type: Item + size: Small + shape: + - 0,0,1,0 + - 1,1,1,1 + heldPrefix: Bend + storedSprite: + sprite: Structures/Piping/Atmospherics/pipe.rsi + state: storageBend + - type: MeleeWeapon + wideAnimationRotation: 180 + attackRate: 1 + damage: + types: + Blunt: 6 + soundHit: + collection: MetalThud + - type: DamageOtherOnHit + damage: + types: + Blunt: 3 #This should be 6 but throwing damage is doubled at the moment for some reason so for now it's 3 - type: entity parent: GasPipeBase @@ -139,6 +174,23 @@ - type: Construction graph: GasPipe node: tjunction + - type: Item + size: Normal + shape: + - 0,0,2,0 + - 1,1,1,1 + heldPrefix: TJunction + storedSprite: + sprite: Structures/Piping/Atmospherics/pipe.rsi + state: storageTJunction + - type: MeleeWeapon + wideAnimationRotation: 90 + attackRate: 0.75 + damage: + types: + Blunt: 10 + soundHit: + collection: MetalThud - type: entity parent: GasPipeBase @@ -160,6 +212,20 @@ - type: Construction graph: GasPipe node: fourway + - type: Item + size: Normal + shape: + - 1,0,1,2 + - 0,1,2,1 + heldPrefix: Fourway + - type: MeleeWeapon + wideAnimationRotation: 90 + attackRate: 0.75 + damage: + types: + Blunt: 10 + soundHit: + collection: MetalThud - type: entity id: GasPipeBroken diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/portable.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/portable.yml index 6758c413280..87e71400f73 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/portable.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/portable.yml @@ -144,8 +144,8 @@ - type: WiresVisuals - type: UserInterface interfaces: - - key: enum.SpaceHeaterUiKey.Key - type: SpaceHeaterBoundUserInterface + enum.SpaceHeaterUiKey.Key: + type: SpaceHeaterBoundUserInterface - type: ActivatableUI inHandsOnly: false key: enum.SpaceHeaterUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/trinary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/trinary.yml index d0f239b338b..e8025556aa5 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/trinary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/trinary.yml @@ -53,7 +53,7 @@ - type: PipeColorVisuals - type: UserInterface interfaces: - - key: enum.GasFilterUiKey.Key + enum.GasFilterUiKey.Key: type: GasFilterBoundUserInterface - type: GasFilter enabled: false @@ -96,6 +96,9 @@ enabled: True: { state: gasFilterFOn } False: { state: gasFilterF } + - type: Construction + node: filterflipped + - type: PipeColorVisuals - type: NodeContainer nodes: @@ -138,7 +141,7 @@ - type: PipeColorVisuals - type: UserInterface interfaces: - - key: enum.GasMixerUiKey.Key + enum.GasMixerUiKey.Key: type: GasMixerBoundUserInterface - type: GasMixer enabled: false @@ -196,6 +199,8 @@ !type:PipeNode nodeGroupID: Pipe pipeDirection: North + - type: Construction + node: mixerflipped - type: entity parent: GasPipeBase diff --git a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml index bf475d5e068..7a69f4759cd 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Atmospherics/unary.yml @@ -242,8 +242,8 @@ - type: AtmosDevice - type: UserInterface interfaces: - - key: enum.ThermomachineUiKey.Key - type: GasThermomachineBoundUserInterface + enum.ThermomachineUiKey.Key: + type: GasThermomachineBoundUserInterface - type: ActivatableUI inHandsOnly: false key: enum.ThermomachineUiKey.Key @@ -460,7 +460,8 @@ solutions: tank: maxVol: 400 - canMix: true + - type: MixableSolution + solution: tank - type: DrainableSolution solution: tank - type: ExaminableSolution diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml index 218b532efcd..7aee5896472 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/pipes.yml @@ -143,8 +143,8 @@ key: enum.DisposalTaggerUiKey.Key - type: UserInterface interfaces: - - key: enum.DisposalTaggerUiKey.Key - type: DisposalTaggerBoundUserInterface + enum.DisposalTaggerUiKey.Key: + type: DisposalTaggerBoundUserInterface - type: Construction graph: DisposalPipe node: tagger @@ -219,8 +219,8 @@ key: enum.DisposalRouterUiKey.Key - type: UserInterface interfaces: - - key: enum.DisposalRouterUiKey.Key - type: DisposalRouterBoundUserInterface + enum.DisposalRouterUiKey.Key: + type: DisposalRouterBoundUserInterface - type: Fixtures fixtures: fix1: @@ -271,6 +271,8 @@ bounds: "-0.25,-0.5,0.5,0.5" mask: - SubfloorMask + - type: Construction + node: routerflipped - type: entity id: DisposalJunction @@ -353,6 +355,8 @@ bounds: "-0.25,-0.5,0.5,0.5" mask: - SubfloorMask + - type: Construction + node: junctionflipped - type: entity id: DisposalYJunction @@ -489,3 +493,5 @@ pipe: Free: { state: signal-router-flipped-free } Anchored: { state: signal-router-flipped } + - type: Construction + node: signal_router_flipped diff --git a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml index 75ec98c402a..e7d3d3c9977 100644 --- a/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml +++ b/Resources/Prototypes/Entities/Structures/Piping/Disposal/units.yml @@ -56,8 +56,8 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.DisposalUnitUiKey.Key - type: DisposalUnitBoundUserInterface + enum.DisposalUnitUiKey.Key: + type: DisposalUnitBoundUserInterface - type: ContainerContainer containers: disposals: !type:Container @@ -77,10 +77,12 @@ graph: DisposalMachine node: disposal_unit - type: DisposalUnit + - type: ThrowInsertContainer + containerId: disposals - type: UserInterface interfaces: - - key: enum.DisposalUnitUiKey.Key - type: DisposalUnitBoundUserInterface + enum.DisposalUnitUiKey.Key: + type: DisposalUnitBoundUserInterface - type: RatKingRummageable - type: RequireProjectileTarget @@ -130,7 +132,7 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.MailingUnitUiKey.Key - type: DisposalUnitBoundUserInterface - - key: enum.ConfigurationUiKey.Key - type: ConfigurationBoundUserInterface + enum.MailingUnitUiKey.Key: + type: DisposalUnitBoundUserInterface + enum.ConfigurationUiKey.Key: + type: ConfigurationBoundUserInterface diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml index ca0cebffecd..96392ecd005 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/PA/control_box.yml @@ -17,10 +17,10 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.ParticleAcceleratorControlBoxUiKey.Key - type: ParticleAcceleratorBoundUserInterface - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.ParticleAcceleratorControlBoxUiKey.Key: + type: ParticleAcceleratorBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: WiresPanel - type: Wires boardName: wires-board-name-pa diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml index c88adca76d7..4e4ef8bdbcf 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/ame.yml @@ -65,8 +65,8 @@ key: enum.AmeControllerUiKey.Key - type: UserInterface interfaces: - - key: enum.AmeControllerUiKey.Key - type: AmeControllerBoundUserInterface + enum.AmeControllerUiKey.Key: + type: AmeControllerBoundUserInterface - type: Appearance - type: GenericVisualizer visuals: diff --git a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml index 35d65ffe87a..41f336d4052 100644 --- a/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml +++ b/Resources/Prototypes/Entities/Structures/Power/Generation/portable_generator.yml @@ -44,7 +44,7 @@ - type: WiresPanel - type: UserInterface interfaces: - - key: enum.GeneratorComponentUiKey.Key + enum.GeneratorComponentUiKey.Key: type: PortableGeneratorBoundUserInterface - type: ActivatableUI key: enum.GeneratorComponentUiKey.Key diff --git a/Resources/Prototypes/Entities/Structures/Power/apc.yml b/Resources/Prototypes/Entities/Structures/Power/apc.yml index 6504c6a1f48..01147f439f3 100644 --- a/Resources/Prototypes/Entities/Structures/Power/apc.yml +++ b/Resources/Prototypes/Entities/Structures/Power/apc.yml @@ -81,8 +81,8 @@ - type: ExtensionCableProvider - type: UserInterface interfaces: - - key: enum.ApcUiKey.Key - type: ApcBoundUserInterface + enum.ApcUiKey.Key: + type: ApcBoundUserInterface - type: ActivatableUI inHandsOnly: false singleUser: true diff --git a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml index 64e247144d4..82945860483 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml @@ -782,7 +782,6 @@ - Desoxyephedrine - Ephedrine - THC - - THCOil - SpaceDrugs - Nocturine - MuteToxin diff --git a/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml b/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml index 2591b3f3408..9fd05beaeea 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/Janitor/janicart.yml @@ -313,8 +313,8 @@ fillBaseName: cart_water- - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: Drink solution: bucket - type: ContainerContainer diff --git a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml index 1e3b9a5b7e8..3e2ed9508e3 100644 --- a/Resources/Prototypes/Entities/Structures/Specific/oracle.yml +++ b/Resources/Prototypes/Entities/Structures/Specific/oracle.yml @@ -33,7 +33,6 @@ fountain: maxVol: 200 - type: Drink - isOpen: true solution: fountain - type: DrawableSolution solution: fountain @@ -59,14 +58,6 @@ rewardEntities: - OracleRewardDisks - OracleRewardCrystals - demandBlacklist: - tags: - - Bluespace - components: - - MobState - demandWhitelist: - components: - - Item - type: LanguageSpeaker currentLanguage: TauCetiBasic - type: LanguageKnowledge diff --git a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml index 52b008c7f2c..1d184ad45eb 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Canisters/gas_canisters.yml @@ -36,7 +36,7 @@ 3: { state: can-o3, shader: "unshaded" } - type: UserInterface interfaces: - - key: enum.GasCanisterUiKey.Key + enum.GasCanisterUiKey.Key: type: GasCanisterBoundUserInterface - type: Destructible thresholds: diff --git a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base_structurelockers.yml b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base_structurelockers.yml index 783bec3ba0d..7d7bc94bb32 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base_structurelockers.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Closets/Lockers/base_structurelockers.yml @@ -45,7 +45,7 @@ min: 1 max: 2 - type: Construction - graph: ClosetSteel + graph: ClosetSteelSecure node: done containers: - entity_storage @@ -66,8 +66,3 @@ behaviors: - !type:DoActsBehavior acts: ["Destruction"] - - type: Construction - graph: ClosetSteelSecure - node: done - containers: - - entity_storage diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml index 78c8c84d4c9..01c226cb0fd 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/base_structurecrates.yml @@ -34,7 +34,7 @@ bounds: "-0.4,-0.4,0.4,0.29" density: 50 mask: - - SmallMobMask #this is so they can go under plastic flaps + - CrateMask #this is so they can go under plastic flaps layer: - MachineLayer - type: EntityStorage diff --git a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml index 1cf80836590..11c963ed228 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/Crates/crates.yml @@ -356,7 +356,7 @@ bounds: "-0.4,-0.4,0.4,0.29" density: 135 mask: - - SmallMobMask #this is so they can go under plastic flaps + - CrateMask #this is so they can go under plastic flaps layer: - LargeMobLayer - type: Construction @@ -413,7 +413,7 @@ bounds: "-0.4,-0.4,0.4,0.29" density: 80 mask: - - LargeMobMask + - CrateMask layer: - LargeMobLayer - type: StaticPrice diff --git a/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml b/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml index d6becda9cc5..cfda95fc2f9 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/filing_cabinets.yml @@ -24,8 +24,8 @@ map: ["openLayer"] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: Transform noRot: true - type: Fixtures @@ -113,8 +113,8 @@ - type: Appearance - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: Transform noRot: true - type: Fixtures diff --git a/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml b/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml index bdb02d2bc35..8177b6b6f0d 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/glass_box.yml @@ -1,97 +1,148 @@ - type: entity - id: GlassBoxLaser - name: glass box - description: A sturdy showcase for an expensive exhibit. + id: BaseGlassBox parent: BaseStructureDynamic + abstract: true placement: mode: SnapgridCenter components: - - type: Anchorable - delay: 4 - type: Transform anchored: true - - type: Damageable - damageContainer: Inorganic - damageModifierSet: Glass - - type: MeleeSound - soundGroups: - Brute: - collection: GlassSmash - type: Physics bodyType: Static - type: Clickable - type: InteractionOutline + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 1000 + mask: + - MachineMask + layer: + - MidImpassable + - LowImpassable + - type: ItemSlots + - type: ContainerContainer + containers: + ItemCabinet: !type:ContainerSlot + - type: Anchorable + delay: 4 + - type: Appearance + +- type: entity + id: GlassBox + name: glass box + description: A sturdy showcase for an expensive exhibit. + parent: BaseGlassBox + abstract: true # TODO: Temporarily abstract. Remove it after item scaling in cabinets is implemented. + components: - type: Sprite + noRot: true sprite: Structures/Storage/glassbox.rsi layers: - - state: glassbox - - state: caplaser + - state: base + - state: caplaser # TODO: Remove it after item scaling in cabinets is implemented. map: ["enum.ItemCabinetVisualLayers.ContainsItem"] visible: true - state: glass map: ["enum.ItemCabinetVisualLayers.Door"] - - type: ItemCabinet - cabinetSlot: - ejectOnInteract: true - whitelist: - tags: - - WeaponAntiqueLaser - doorSound: - path: /Audio/Machines/machine_switch.ogg - openState: glass-up - closedState: glass - - type: Lock + - state: locked + shader: unshaded + map: ["enum.LockVisualLayers.Lock"] + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeAabb + bounds: "-0.45,-0.45,0.45,0.45" + density: 1000 + mask: + - MachineMask + layer: + - LowImpassable + - MidImpassable + - BulletImpassable - type: AccessReader - access: [["Captain"]] - - type: ItemSlots - - type: ContainerContainer - containers: - ItemCabinet: !type:ContainerSlot - type: Repairable - - type: Appearance + fuelCost: 15 + doAfterDelay: 5 + - type: Lock + - type: LockVisuals - type: DamageVisuals - thresholds: [4, 8, 12] + thresholds: [4, 8, 12] # TODO: Fix damage visuals on open state. damageDivisor: 7.555 trackAllDamage: true damageOverlay: sprite: Structures/Storage/glassbox.rsi + - type: Damageable + damageContainer: Inorganic + damageModifierSet: Glass + - type: MeleeSound + soundGroups: + Brute: + collection: GlassSmash - type: Destructible thresholds: - trigger: !type:DamageTrigger damage: 150 behaviors: - - !type:EmptyAllContainersBehaviour - - !type:PlaySoundBehavior - sound: - collection: WindowShatter - - !type:SpawnEntitiesBehavior - spawn: - ShardGlassReinforced: - min: 1 - max: 1 - GlassBoxLaserBroken: - min: 1 - max: 1 - - !type:DoActsBehavior - acts: [ "Destruction" ] + - !type:EmptyAllContainersBehaviour + - !type:PlaySoundBehavior + sound: + collection: WindowShatter + - !type:PlaySoundBehavior + sound: + path: /Audio/Machines/warning_buzzer.ogg + params: + volume: 10 + - !type:SpawnEntitiesBehavior + spawn: + ShardGlassReinforced: + min: 1 + max: 2 + - !type:ChangeConstructionNodeBehavior + node: brokenGlassBox + - !type:DoActsBehavior + acts: [ "Destruction" ] - type: entity - id: GlassBoxLaserOpen - parent: GlassBoxLaser - suffix: Open + id: GlassBoxLaser + parent: GlassBox + suffix: AntiqueLaser components: + - type: AccessReader + access: [["Captain"]] + - type: Construction + graph: GlassBox + node: glassBox - type: ItemCabinet - opened: true + cabinetSlot: + ejectOnInteract: true + whitelist: + tags: + - WeaponAntiqueLaser doorSound: path: /Audio/Machines/machine_switch.ogg openState: glass-up closedState: glass +- type: entity + id: GlassBoxLaserOpen + parent: GlassBoxLaser + suffix: AntiqueLaser, Open + components: + - type: Lock + locked: false + - type: ItemCabinet + opened: true + - type: entity id: GlassBoxLaserFilled parent: GlassBoxLaser - suffix: Filled + suffix: AntiqueLaser, Filled components: - type: ItemCabinet cabinetSlot: @@ -100,40 +151,83 @@ whitelist: tags: - WeaponAntiqueLaser - doorSound: - path: /Audio/Machines/machine_switch.ogg - openState: glass-up - closedState: glass - type: entity id: GlassBoxLaserFilledOpen parent: GlassBoxLaserFilled - suffix: Filled, Open + suffix: AntiqueLaser, Filled, Open components: + - type: Lock + locked: false - type: ItemCabinet opened: true - doorSound: - path: /Audio/Machines/machine_switch.ogg - openState: glass-up - closedState: glass - type: entity - id: GlassBoxLaserBroken + id: GlassBoxFrame + name: glass box frame + description: A glassless sturdy showcase for an expensive exhibit. + parent: BaseGlassBox + suffix: Frame + components: + - type: Sprite + noRot: true + sprite: Structures/Storage/glassbox.rsi + layers: + - state: base + - type: Construction + graph: GlassBox + node: boxMissingWires + - type: Climbable + - type: Damageable + damageModifierSet: Wood + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroy + - !type:SpawnEntitiesBehavior + spawn: + MaterialWoodPlank1: + min: 2 + max: 5 + - !type:DoActsBehavior + acts: ["Destruction"] + +- type: entity + id: GlassBoxBroken name: broken glass box description: A broken showcase for a stolen expensive exhibit. - parent: BaseStructureDynamic + parent: GlassBoxFrame suffix: Broken - placement: - mode: SnapgridCenter components: - - type: Transform - anchored: true - - type: Physics - bodyType: Static - type: Sprite sprite: Structures/Storage/glassbox.rsi layers: - - state: glassbox - - state: glass-4 - - type: Clickable - - type: InteractionOutline + - state: base + - state: glass-broken + - type: Construction + graph: GlassBox + node: brokenGlassBox + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 100 + behaviors: + - !type:PlaySoundBehavior + sound: + collection: WoodDestroy + - !type:SpawnEntitiesBehavior + spawn: + ShardGlassReinforced: + min: 1 + max: 1 + MaterialWoodPlank1: + min: 2 + max: 5 + - !type:DoActsBehavior + acts: ["Destruction"] diff --git a/Resources/Prototypes/Entities/Structures/Storage/morgue.yml b/Resources/Prototypes/Entities/Structures/Storage/morgue.yml index 725f4c9b0f2..496ea416119 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/morgue.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/morgue.yml @@ -5,6 +5,8 @@ placement: mode: SnapgridCenter components: + - type: Pullable + - type: Anchorable - type: Sprite sprite: Structures/Storage/morgue.rsi layers: @@ -28,11 +30,11 @@ shape: !type:PhysShapeAabb bounds: "-0.5,-0.5,0.5,0.5" - density: 190 + density: 1000 mask: - MachineMask layer: - - WallLayer + - HalfWallLayer - type: EntityStorage isCollidableWhenOpen: true showContents: false diff --git a/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml b/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml index 961d7854c08..b26bb2c954f 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/ore_box.yml @@ -60,8 +60,8 @@ - Ore - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: ContainerContainer containers: storagebase: !type:Container diff --git a/Resources/Prototypes/Entities/Structures/Storage/storage.yml b/Resources/Prototypes/Entities/Structures/Storage/storage.yml index 79a1e357998..d0b468ca53d 100644 --- a/Resources/Prototypes/Entities/Structures/Storage/storage.yml +++ b/Resources/Prototypes/Entities/Structures/Storage/storage.yml @@ -27,9 +27,9 @@ bounds: "-0.3,-0.3,0.3,0.3" density: 140 mask: - - MachineMask + - TableMask layer: - - MachineLayer + - TableLayer - type: Damageable damageContainer: Inorganic damageModifierSet: Metallic diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml index 70e204f694e..6090aae882f 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/air_alarm.yml @@ -59,10 +59,10 @@ - type: InteractionOutline - type: UserInterface interfaces: - - key: enum.SharedAirAlarmInterfaceKey.Key - type: AirAlarmBoundUserInterface - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.SharedAirAlarmInterfaceKey.Key: + type: AirAlarmBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: WiresPanel - type: Wires boardName: wires-board-name-airalarm diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml index c39adcde3b6..c27b0ff27e9 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/fire_alarm.yml @@ -62,8 +62,8 @@ delta: fire_3 - type: UserInterface interfaces: - - key: enum.WiresUiKey.Key - type: WiresBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: WiresPanel - type: Wires boardName: wires-board-name-firealarm diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml index 6bccf14e138..e31152a5b6e 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/intercom.yml @@ -63,9 +63,9 @@ key: enum.IntercomUiKey.Key - type: UserInterface interfaces: - - key: enum.IntercomUiKey.Key + enum.IntercomUiKey.Key: type: IntercomBoundUserInterface - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: Construction graph: Intercom diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/mirror.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/mirror.yml index b524f099bfb..d02bce020da 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/mirror.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/mirror.yml @@ -16,5 +16,5 @@ key: enum.MagicMirrorUiKey.Key - type: UserInterface interfaces: - - key: enum.MagicMirrorUiKey.Key - type: MagicMirrorBoundUserInterface + enum.MagicMirrorUiKey.Key: + type: MagicMirrorBoundUserInterface diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/monitors_televisions.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/monitors_televisions.yml index 451495f58d2..408ab6b67c3 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/monitors_televisions.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/monitors_televisions.yml @@ -110,8 +110,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.SurveillanceCameraMonitorUiKey.Key - type: SurveillanceCameraMonitorBoundUserInterface + enum.SurveillanceCameraMonitorUiKey.Key: + type: SurveillanceCameraMonitorBoundUserInterface # Wall Televisions @@ -169,8 +169,8 @@ - type: ActivatableUIRequiresPower - type: UserInterface interfaces: - - key: enum.SurveillanceCameraMonitorUiKey.Key - type: SurveillanceCameraMonitorBoundUserInterface + enum.SurveillanceCameraMonitorUiKey.Key: + type: SurveillanceCameraMonitorBoundUserInterface - type: PointLight radius: 1.5 energy: 1.6 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/noticeboard.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/noticeboard.yml index 421ab93be97..f2315583e3c 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/noticeboard.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/noticeboard.yml @@ -50,8 +50,8 @@ - Write - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: ContainerContainer containers: storagebase: !type:Container diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/station_map.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/station_map.yml index d1df619b7a4..2ae5040910e 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/station_map.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/station_map.yml @@ -86,7 +86,7 @@ acts: [ "Destruction" ] - type: UserInterface interfaces: - - key: enum.StationMapUiKey.Key + enum.StationMapUiKey.Key: type: StationMapBoundUserInterface - type: entity diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml index 6e56bb855f7..3347b0e4b1c 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/surveillance_camera.yml @@ -42,9 +42,9 @@ InUse: camera_in_use - type: UserInterface interfaces: - - key: enum.SurveillanceCameraSetupUiKey.Camera + enum.SurveillanceCameraSetupUiKey.Camera: type: SurveillanceCameraSetupBoundUi - - key: enum.WiresUiKey.Key + enum.WiresUiKey.Key: type: WiresBoundUserInterface - type: StaticPrice price: 200 diff --git a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml index 0c284eec7af..dd7eb5bea82 100644 --- a/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml +++ b/Resources/Prototypes/Entities/Structures/Wallmounts/timer.yml @@ -32,8 +32,8 @@ key: enum.SignalTimerUiKey.Key - type: UserInterface interfaces: - - key: enum.SignalTimerUiKey.Key - type: SignalTimerBoundUserInterface + enum.SignalTimerUiKey.Key: + type: SignalTimerBoundUserInterface - type: ApcPowerReceiver powerLoad: 100 - type: Electrified diff --git a/Resources/Prototypes/Entities/Structures/Walls/grille.yml b/Resources/Prototypes/Entities/Structures/Walls/grille.yml index 11ada142fa5..7be721b6f9a 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/grille.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/grille.yml @@ -32,7 +32,7 @@ node: grille deconstructionTarget: start - type: Damageable - damageContainer: Inorganic + damageContainer: StructuralInorganic damageModifierSet: PerforatedMetallic - type: PowerConsumer showInMonitor: false diff --git a/Resources/Prototypes/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Entities/Structures/Walls/walls.yml index 856a5380844..675de3dab55 100644 --- a/Resources/Prototypes/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Entities/Structures/Walls/walls.yml @@ -549,8 +549,6 @@ node: girder - !type:DoActsBehavior acts: ["Destruction"] - destroySound: - collection: MetalBreak - type: IconSmooth key: walls base: reinf_over @@ -806,8 +804,6 @@ node: girder - !type:DoActsBehavior acts: ["Destruction"] - destroySound: - collection: MetalBreak - type: Construction graph: Girder node: diagonalshuttleWall @@ -1212,7 +1208,7 @@ name: force wall components: - type: TimedDespawn - lifetime: 20 + lifetime: 12 - type: Tag tags: - Wall diff --git a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml index d395235a533..9dc9f77cffc 100644 --- a/Resources/Prototypes/Entities/Structures/cargo_telepad.yml +++ b/Resources/Prototypes/Entities/Structures/cargo_telepad.yml @@ -47,3 +47,5 @@ board: CargoTelepadMachineCircuitboard - type: Appearance - type: CollideOnAnchor + - type: NameIdentifier + group: CargoTelepads diff --git a/Resources/Prototypes/Entities/Structures/cryopod.yml b/Resources/Prototypes/Entities/Structures/cryopod.yml index 9063e8b1385..bdb8862a829 100644 --- a/Resources/Prototypes/Entities/Structures/cryopod.yml +++ b/Resources/Prototypes/Entities/Structures/cryopod.yml @@ -12,8 +12,8 @@ map: ["base"] - type: UserInterface interfaces: - - key: enum.CryostorageUIKey.Key - type: CryostorageBoundUserInterface + enum.CryostorageUIKey.Key: + type: CryostorageBoundUserInterface - type: ActivatableUI key: enum.CryostorageUIKey.Key - type: AccessReader diff --git a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml index 207305d2327..5d5ff390bac 100644 --- a/Resources/Prototypes/Entities/Structures/plastic_flaps.yml +++ b/Resources/Prototypes/Entities/Structures/plastic_flaps.yml @@ -1,9 +1,7 @@ - type: entity - id: PlasticFlapsClear + id: PlasticFlapsBase parent: BaseStructureDynamic - name: plastic flaps - suffix: Clear - description: Heavy duty, plastic flaps. Definitely can't get past those. No way. + abstract: true placement: mode: SnapgridCenter components: @@ -23,7 +21,7 @@ bounds: "-0.49,-0.49,0.49,0.49" density: 100 mask: - - TabletopMachineMask + - Impassable layer: - MidImpassable - BulletImpassable @@ -41,16 +39,24 @@ - type: IconSmooth key: walls mode: NoSprite - - type: Construction - graph: PlasticFlapsGraph - node: plasticFlaps - type: StaticPrice price: 83 - type: RequireProjectileTarget +- type: entity + id: PlasticFlapsClear + parent: PlasticFlapsBase + name: plastic flaps + suffix: Clear + description: Heavy duty, plastic flaps. Definitely can't get past those. No way. + components: + - type: Construction + graph: PlasticFlapsGraph + node: plasticFlaps + - type: entity id: PlasticFlapsOpaque - parent: PlasticFlapsClear + parent: PlasticFlapsBase name: plastic flaps suffix: Opaque description: Heavy duty, plastic flaps. Definitely can't get past those. No way. @@ -63,7 +69,7 @@ bounds: "-0.49,-0.49,0.49,0.49" density: 100 mask: - - TabletopMachineMask + - Impassable layer: - Opaque - MidImpassable @@ -75,7 +81,7 @@ - type: entity id: PlasticFlapsAirtightClear - parent: PlasticFlapsClear + parent: PlasticFlapsBase name: airtight plastic flaps suffix: Airtight, Clear description: Heavy duty, slightly stronger, airtight plastic flaps. Definitely can't get past those. No way. @@ -89,15 +95,12 @@ - !type:DoActsBehavior acts: ["Destruction"] - type: Airtight - - type: Construction - graph: PlasticFlapsGraph - node: airtightFlaps - type: StaticPrice price: 100 - type: entity id: PlasticFlapsAirtightOpaque - parent: PlasticFlapsOpaque + parent: PlasticFlapsBase name: airtight plastic flaps suffix: Airtight, Opaque description: Heavy duty, slightly stronger, airtight plastic flaps. Definitely can't get past those. No way. @@ -111,8 +114,5 @@ - !type:DoActsBehavior acts: ["Destruction"] - type: Airtight - - type: Construction - graph: PlasticFlapsGraph - node: airtightopaqueFlaps - type: StaticPrice price: 100 diff --git a/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml b/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml index d93351c7e27..974a0ac3b7b 100644 --- a/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml +++ b/Resources/Prototypes/Entities/Tiles/shadow_basalt.yml @@ -1,7 +1,7 @@ - type: entity id: ShadowBasaltOne name: shadowstone - description: Cold rock + description: Glowing cracks in reality. It's probably fine. placement: mode: SnapgridCenter components: diff --git a/Resources/Prototypes/Flavors/flavors.yml b/Resources/Prototypes/Flavors/flavors.yml index 9f0f6ad6787..26190d87912 100644 --- a/Resources/Prototypes/Flavors/flavors.yml +++ b/Resources/Prototypes/Flavors/flavors.yml @@ -589,6 +589,36 @@ flavorType: Complex description: flavor-complex-irish-car-bomb +- type: flavor + id: vodkaredbool + flavorType: Complex + description: flavor-complex-vodka-red-bool + +- type: flavor + id: xenobasher + flavorType: Complex + description: flavor-complex-xeno-basher + +- type: flavor + id: irishbool + flavorType: Complex + description: flavor-complex-irish-bool + +- type: flavor + id: budgetinsulsdrink + flavorType: Complex + description: flavor-complex-budget-insuls-drink + +- type: flavor + id: watermelonwakeup + flavorType: Complex + description: flavor-complex-watermelon-wakeup + +- type: flavor + id: rubberneck + flavorType: Complex + description: flavor-complex-rubberneck + - type: flavor id: blackrussian flavorType: Complex @@ -1053,3 +1083,18 @@ id: violets flavorType: Complex description: flavor-complex-violets + +- type: flavor + id: pyrotton + flavorType: Complex + description: flavor-complex-pyrotton + +- type: flavor + id: mothballs + flavorType: Complex + description: flavor-complex-mothballs + +- type: flavor + id: paintthinner + flavorType: Complex + description: flavor-complex-paint-thinner \ No newline at end of file diff --git a/Resources/Prototypes/GameRules/cargo_gifts.yml b/Resources/Prototypes/GameRules/cargo_gifts.yml index 799805272d6..3787f4e6034 100644 --- a/Resources/Prototypes/GameRules/cargo_gifts.yml +++ b/Resources/Prototypes/GameRules/cargo_gifts.yml @@ -4,7 +4,7 @@ noSpawn: true components: - type: StationEvent - weight: 10 + weight: 5 startDelay: 10 duration: 120 earliestStart: 20 @@ -24,11 +24,10 @@ noSpawn: true components: - type: StationEvent - weight: 6 + weight: 2 startDelay: 10 duration: 240 - minimumPlayers: 50 - earliestStart: 40 + earliestStart: 20 - type: CargoGiftsRule description: cargo-gift-pizza-large sender: cargo-gift-default-sender @@ -44,7 +43,7 @@ noSpawn: true components: - type: StationEvent - weight: 4 + weight: 5 startDelay: 10 duration: 240 earliestStart: 30 @@ -90,7 +89,7 @@ noSpawn: true components: - type: StationEvent - weight: 8 + weight: 6 startDelay: 10 duration: 120 minimumPlayers: 30 @@ -132,7 +131,7 @@ noSpawn: true components: - type: StationEvent - weight: 6 + weight: 4 startDelay: 10 duration: 120 earliestStart: 10 @@ -154,7 +153,7 @@ noSpawn: true components: - type: StationEvent - weight: 3 + weight: 4 startDelay: 10 duration: 120 earliestStart: 20 @@ -174,7 +173,7 @@ noSpawn: true components: - type: StationEvent - weight: 2 + weight: 3 startDelay: 10 duration: 120 earliestStart: 20 diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index 66a8f6ada83..8dca3eb4292 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -4,9 +4,8 @@ noSpawn: true components: - type: StationEvent - weight: 12 + weight: 8 startDelay: 30 - reoccurrenceDelay: 8 duration: 35 - type: AnomalySpawnRule @@ -16,9 +15,8 @@ noSpawn: true components: - type: StationEvent - weight: 5 + weight: 8 startDelay: 30 - reoccurrenceDelay: 5 duration: 35 - type: BluespaceArtifactRule @@ -28,10 +26,9 @@ noSpawn: true components: - type: StationEvent - weight: 1 - maxOccurrences: 4 # Very annoying, makes containers unusable + weight: 2 + reoccurrenceDelay: 5 earliestStart: 1 - reoccurrenceDelay: 15 duration: 1 - type: BluespaceLockerRule @@ -41,10 +38,9 @@ noSpawn: true components: - type: StationEvent - weight: 10 + weight: 7 duration: 1 - minimumPlayers: 7 - reoccurrenceDelay: 5 + minimumPlayers: 15 - type: BreakerFlipRule - type: entity @@ -55,9 +51,8 @@ - type: StationEvent startAnnouncement: true minimumPlayers: 25 - weight: 5 + weight: 3 duration: 1 - reoccurrenceDelay: 5 - type: BureaucraticErrorRule - type: entity @@ -70,7 +65,6 @@ minimumPlayers: 15 weight: 5 duration: 1 - reoccurrenceDelay: 5 - type: ClericalErrorRule - type: entity @@ -79,10 +73,9 @@ noSpawn: true components: - type: StationEvent - weight: 10 + weight: 5 duration: 1 - minimumPlayers: 15 - reoccurrenceDelay: 25 + minimumPlayers: 10 - type: RandomEntityStorageSpawnRule prototype: MobSkeletonCloset @@ -92,10 +85,10 @@ noSpawn: true components: - type: StationEvent - weight: 2 + weight: 6.5 duration: 1 - earliestStart: 45 - reoccurrenceDelay: 60 + earliestStart: 40 + reoccurrenceDelay: 20 minimumPlayers: 20 - type: RandomSpawnRule prototype: SpawnPointGhostDragon @@ -106,14 +99,13 @@ noSpawn: true components: - type: StationEvent - weight: 3 + weight: 6 duration: 1 - earliestStart: 45 - reoccurrenceDelay: 45 - minimumPlayers: 20 + earliestStart: 30 + reoccurrenceDelay: 20 + minimumPlayers: 30 - type: NinjaSpawnRule -# TODO there's already a glimmer revenant rule. One of them might be broken. - type: entity parent: BaseGameRule id: RevenantSpawn @@ -127,16 +119,16 @@ - type: RandomSpawnRule prototype: MobRevenant -- type: entity - id: FalseAlarm - parent: BaseGameRule - noSpawn: true - components: - - type: StationEvent - weight: 10 - duration: 1 - reoccurrenceDelay: 4 # Please no 10 false alarms in a row. - - type: FalseAlarmRule +# disabled until event is rewritten to be more interesting +#- type: entity +# id: FalseAlarm +# parent: BaseGameRule +# noSpawn: true +# components: +# - type: StationEvent +# weight: 15 +# duration: 1 +# - type: FalseAlarmRule - type: entity id: GasLeak @@ -146,10 +138,7 @@ - type: StationEvent startAnnouncement: true endAnnouncement: true - earliestStart: 10 - reoccurrenceDelay: 7 - minimumPlayers: 5 - weight: 10 + weight: 8 startDelay: 20 - type: GasLeakRule @@ -160,9 +149,8 @@ components: - type: StationEvent earliestStart: 15 - reoccurrenceDelay: 10 minimumPlayers: 15 - weight: 5 + weight: 7 startDelay: 50 duration: 240 - type: KudzuGrowthRule @@ -174,9 +162,8 @@ components: - type: StationEvent earliestStart: 30 - reoccurrenceDelay: 5 weight: 7.5 - minimumPlayers: 7 #Enough to hopefully have at least one engineering guy + minimumPlayers: 10 #Enough to hopefully have at least one engineering guy startAnnouncement: true endAnnouncement: true duration: null #ending is handled by MeteorSwarmRule @@ -192,8 +179,7 @@ startAnnouncement: true startDelay: 10 earliestStart: 15 - reoccurrenceDelay: 3 - weight: 5 + weight: 6 duration: 50 - type: VentCrittersRule entries: @@ -203,6 +189,11 @@ prob: 0.02 - id: MobMouse2 prob: 0.02 + - id: MobMouseCancer + prob: 0.001 + specialEntries: + - id: SpawnPointGhostRatKing + prob: 0.001 - type: entity id: CockroachMigration @@ -212,9 +203,8 @@ - type: StationEvent startAnnouncement: true startDelay: 10 - weight: 5 + weight: 6 duration: 50 - reoccurrenceDelay: 15 # Cockroaches en masse are utmost annoying to deal with. - type: VentCrittersRule entries: - id: MobCockroach @@ -222,43 +212,18 @@ - id: MobMothroach prob: 0.008 -# TODO this is the same as mouse migration, but with different announcer. -- type: entity - id: VentCritters - parent: BaseGameRule - noSpawn: true - components: - - type: StationEvent - startAnnouncement: true - startDelay: 10 - earliestStart: 15 - reoccurrenceDelay: 3 - weight: 5 - duration: 60 - - type: VentCrittersRule - entries: - - id: MobMouse - prob: 0.02 - - id: MobMouse1 - prob: 0.02 - - id: MobMouse2 - prob: 0.02 - - id: MobPibbleVent - prob: 0.005 - - type: entity id: PowerGridCheck parent: BaseGameRule noSpawn: true components: - type: StationEvent - weight: 10 + weight: 5 startAnnouncement: true endAnnouncement: true startDelay: 24 duration: 60 maxDuration: 120 - reoccurrenceDelay: 2 # Gives a chance for multiple checks in a row, but not in parallel - type: PowerGridCheckRule - type: entity @@ -267,10 +232,9 @@ noSpawn: true components: - type: StationEvent - weight: 5 + weight: 6 duration: 1 - reoccurrenceDelay: 10 - maxOccurrences: 3 # Annoying and rarely if ever interesting + maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it - type: RandomSentienceRule - type: entity @@ -279,12 +243,11 @@ noSpawn: true components: - type: StationEvent - weight: 10 + weight: 8 startAnnouncement: true endAnnouncement: true duration: 120 maxDuration: 240 - reoccurrenceDelay: 5 - type: SolarFlareRule onlyJamHeadsets: true affectedChannels: @@ -301,19 +264,6 @@ lightBreakChancePerSecond: 0.0003 doorToggleChancePerSecond: 0.001 -# - type: entity # DeltaV - replaced terminator with paradox anomaly in midroundantag rule -# parent: BaseGameRule -# id: TerminatorSpawn -# noSpawn: true -# components: -# - type: StationEvent -# weight: 8 -# duration: 1 -# earliestStart: 30 -# minimumPlayers: 20 -# - type: RandomSpawnRule -# prototype: SpawnPointGhostTerminator - - type: entity id: VentClog parent: BaseGameRule @@ -322,7 +272,6 @@ - type: StationEvent startAnnouncement: true earliestStart: 15 - reoccurrenceDelay: 5 minimumPlayers: 15 weight: 5 startDelay: 50 @@ -338,7 +287,6 @@ startAnnouncement: true startDelay: 10 earliestStart: 20 - reoccurrenceDelay: 12 minimumPlayers: 15 weight: 5 duration: 60 @@ -360,7 +308,6 @@ startAnnouncement: true startDelay: 10 earliestStart: 20 - reoccurrenceDelay: 15 minimumPlayers: 15 weight: 5 duration: 60 @@ -369,67 +316,22 @@ - id: MobGiantSpiderAngry prob: 0.05 -# Weaker versions of the above -- type: entity - id: SlimesSpawnWeak - parent: SlimesSpawn - noSpawn: true - components: - - type: StationEvent - minimumPlayers: 1 - - type: VentCrittersRule - entries: - - id: MobAdultSlimesBlueAngry - prob: 0.005 - - id: MobAdultSlimesGreenAngry - prob: 0.005 - - id: MobAdultSlimesYellowAngry - prob: 0.005 - -- type: entity - id: SpiderSpawnWeak - parent: SpiderSpawn - noSpawn: true - components: - - type: StationEvent - minimumPlayers: 1 - - type: VentCrittersRule - entries: - - id: MobGiantSpiderAngry - prob: 0.01 - -# - type: entity # DeltaV - Prevent normal spawning of MobClownSpider -# id: SpiderClownSpawn -# parent: BaseGameRule -# noSpawn: true -# components: -# - type: StationEvent -# startAnnouncement: true -# startDelay: 10 -# earliestStart: 20 -# minimumPlayers: 15 -# weight: 1 -# duration: 60 -# - type: VentCrittersRule -# entries: -# - id: MobClownSpider -# prob: 0.05 - - type: entity - id: OneirophageSpawn + id: SpiderClownSpawn parent: BaseGameRule noSpawn: true components: - type: StationEvent - id: VentCritters - earliestStart: 15 - minimumPlayers: 15 - weight: 4 + startAnnouncement: true + startDelay: 10 + earliestStart: 20 + minimumPlayers: 20 + weight: 1.5 duration: 60 - type: VentCrittersRule entries: - - id: MobGiantSpiderVampireAngry - prob: 0.01 + - id: MobClownSpider + prob: 0.05 - type: entity id: ZombieOutbreak @@ -437,9 +339,8 @@ noSpawn: true components: - type: StationEvent - earliestStart: 60 - reoccurrenceDelay: 60 - minimumPlayers: 15 + earliestStart: 50 + minimumPlayers: 30 weight: 2 duration: 1 - type: ZombieRule @@ -472,13 +373,12 @@ noSpawn: true components: - type: StationEvent - earliestStart: 60 - weight: 3 - minimumPlayers: 15 - reoccurrenceDelay: 45 + earliestStart: 35 + weight: 5.5 + minimumPlayers: 20 duration: 1 - type: LoadMapRule - mapPath: /Maps/Shuttles/striker.yml + preloadedGrid: ShuttleStriker - type: NukeopsRule roundEndBehavior: Nothing - type: AntagSelection @@ -501,15 +401,39 @@ - type: NukeopsRole prototype: Nukeops +- type: entity + id: SleeperAgentsRule + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + earliestStart: 25 + weight: 8 + minimumPlayers: 15 + reoccurrenceDelay: 30 + startAnnouncement: true + - type: AlertLevelInterceptionRule + - type: TraitorRule + - type: AntagSelection + definitions: + - prefRoles: [ Traitor ] + min: 1 + max: 2 + playerRatio: 10 + mindComponents: + - type: TraitorRole + prototype: Traitor + - type: entity id: MassHallucinations parent: BaseGameRule noSpawn: true components: - type: StationEvent - weight: 10 + weight: 7 duration: 150 maxDuration: 300 + reoccurrenceDelay: 30 - type: MassHallucinationsRule minTimeBetweenIncidents: 0.1 maxTimeBetweenIncidents: 300 @@ -517,18 +441,18 @@ sounds: collection: Paracusia -#- type: entity # DeltaV - Why does this exist?? -# id: ImmovableRodSpawn -# parent: BaseGameRule -# noSpawn: true -# components: -# - type: StationEvent -# startAnnouncement: true -# weight: 5 -# duration: 1 -# earliestStart: 45 -# minimumPlayers: 20 -# - type: ImmovableRodRule +- type: entity + id: ImmovableRodSpawn + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 3.5 + duration: 1 + earliestStart: 30 + minimumPlayers: 20 + - type: ImmovableRodRule - type: entity noSpawn: true @@ -536,7 +460,7 @@ id: IonStorm components: - type: StationEvent - weight: 10 + weight: 8 reoccurrenceDelay: 20 duration: 1 - type: IonStormRule @@ -548,8 +472,7 @@ components: - type: StationEvent earliestStart: 0 - reoccurrenceDelay: 5 minimumPlayers: 20 + maxOccurrences: 1 # this event has diminishing returns on interesting-ness, so we cap it weight: 5 - type: MobReplacementRule - numberToReplace: 1 diff --git a/Resources/Prototypes/GameRules/midround.yml b/Resources/Prototypes/GameRules/midround.yml index bb870f6007e..db1a76adc08 100644 --- a/Resources/Prototypes/GameRules/midround.yml +++ b/Resources/Prototypes/GameRules/midround.yml @@ -12,6 +12,7 @@ - DoorjackObjective - SpiderChargeObjective - TerrorObjective + - MassArrestObjective - NinjaSurviveObjective - type: NinjaRule threats: NinjaThreats @@ -41,6 +42,7 @@ min: 1 max: 3 playerRatio: 1 + lateJoinAdditional: true allowNonHumans: true multiAntagSetting: All startingGear: ThiefGear @@ -52,13 +54,13 @@ briefing: sound: "/Audio/Misc/thief_greeting.ogg" -- type: entity - noSpawn: true - parent: BaseGameRule - id: Exterminator - components: - - type: GenericAntagRule - agentName: terminator-round-end-agent-name - objectives: - - TerminateObjective - - ShutDownObjective +#- type: entity +# noSpawn: true +# parent: BaseGameRule +# id: Exterminator +# components: +# - type: GenericAntagRule +# agentName: terminator-round-end-agent-name +# objectives: +# - TerminateObjective +# - ShutDownObjective diff --git a/Resources/Prototypes/GameRules/roundstart.yml b/Resources/Prototypes/GameRules/roundstart.yml index a9ed9a1460c..39bea004d02 100644 --- a/Resources/Prototypes/GameRules/roundstart.yml +++ b/Resources/Prototypes/GameRules/roundstart.yml @@ -147,7 +147,7 @@ - type: AntagSelection definitions: - prefRoles: [ Traitor ] - max: 12 + max: 8 playerRatio: 10 lateJoinAdditional: true mindComponents: diff --git a/Resources/Prototypes/GameRules/unknown_shuttles.yml b/Resources/Prototypes/GameRules/unknown_shuttles.yml new file mode 100644 index 00000000000..a62e61f1319 --- /dev/null +++ b/Resources/Prototypes/GameRules/unknown_shuttles.yml @@ -0,0 +1,64 @@ +- type: entity + id: UnknownShuttleCargoLost + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 5 + reoccurrenceDelay: 30 + duration: 1 + - type: LoadMapRule + preloadedGrid: ShuttleCargoLost + +- type: entity + id: UnknownShuttleTravelingCuisine + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 5 + reoccurrenceDelay: 30 + duration: 1 + - type: LoadMapRule + preloadedGrid: TravelingCuisine + +- type: entity + id: UnknownShuttleDisasterEvacPod + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 5 + reoccurrenceDelay: 30 + duration: 1 + - type: LoadMapRule + preloadedGrid: DisasterEvacPod + +- type: entity + id: UnknownShuttleHonki + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 2 + reoccurrenceDelay: 30 + duration: 1 + - type: LoadMapRule + preloadedGrid: Honki + +- type: entity + id: UnknownShuttleSyndieEvacPod + parent: BaseGameRule + noSpawn: true + components: + - type: StationEvent + startAnnouncement: true + weight: 2 + reoccurrenceDelay: 30 + duration: 1 + - type: LoadMapRule + preloadedGrid: SyndieEvacPod diff --git a/Resources/Prototypes/GameRules/variation.yml b/Resources/Prototypes/GameRules/variation.yml index 7424fc28541..2884d5f9d6f 100644 --- a/Resources/Prototypes/GameRules/variation.yml +++ b/Resources/Prototypes/GameRules/variation.yml @@ -24,8 +24,8 @@ components: - type: WallReplaceVariationPass - type: EntityReplaceVariationPass - entitiesPerReplacementAverage: 10 - entitiesPerReplacementStdDev: 2 + entitiesPerReplacementAverage: 50 + entitiesPerReplacementStdDev: 10 replacements: - id: WallSolidRust @@ -36,8 +36,8 @@ components: - type: ReinforcedWallReplaceVariationPass - type: EntityReplaceVariationPass - entitiesPerReplacementAverage: 12 - entitiesPerReplacementStdDev: 2 + entitiesPerReplacementAverage: 50 + entitiesPerReplacementStdDev: 10 replacements: - id: WallReinforcedRust diff --git a/Resources/Prototypes/GhostRoleRaffles/deciders.yml b/Resources/Prototypes/GhostRoleRaffles/deciders.yml new file mode 100644 index 00000000000..b23464cf706 --- /dev/null +++ b/Resources/Prototypes/GhostRoleRaffles/deciders.yml @@ -0,0 +1,3 @@ +- type: ghostRoleRaffleDecider + id: default + decider: !type:RngGhostRoleRaffleDecider {} diff --git a/Resources/Prototypes/GhostRoleRaffles/settings.yml b/Resources/Prototypes/GhostRoleRaffles/settings.yml new file mode 100644 index 00000000000..7ed9326ee01 --- /dev/null +++ b/Resources/Prototypes/GhostRoleRaffles/settings.yml @@ -0,0 +1,15 @@ +# for important antag roles (nukie reinforcements, ninja, etc.) +- type: ghostRoleRaffleSettings + id: default + settings: + initialDuration: 30 + joinExtendsDurationBy: 10 + maxDuration: 90 + +# for roles that don't matter too much or are available plentifully (e.g. space carp) +- type: ghostRoleRaffleSettings + id: short + settings: + initialDuration: 10 + joinExtendsDurationBy: 5 + maxDuration: 30 diff --git a/Resources/Prototypes/Guidebook/science.yml b/Resources/Prototypes/Guidebook/science.yml index e214b2867ac..a3f3f71ec3e 100644 --- a/Resources/Prototypes/Guidebook/science.yml +++ b/Resources/Prototypes/Guidebook/science.yml @@ -41,7 +41,6 @@ text: "/ServerInfo/Guidebook/Science/Xenoarchaeology.xml" children: - ArtifactReports - - TraversalDistorter - type: guideEntry id: Robotics diff --git a/Resources/Prototypes/Hydroponics/mutations.yml b/Resources/Prototypes/Hydroponics/mutations.yml index 17617f5ee32..6108278a4ac 100644 --- a/Resources/Prototypes/Hydroponics/mutations.yml +++ b/Resources/Prototypes/Hydroponics/mutations.yml @@ -6,7 +6,6 @@ reagents: - Omnizine - Nocturine - - Barozine - Lexorin - Honk - BuzzochloricBees diff --git a/Resources/Prototypes/Hydroponics/seeds.yml b/Resources/Prototypes/Hydroponics/seeds.yml index 030c89c8cf1..e134d24c26d 100644 --- a/Resources/Prototypes/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Hydroponics/seeds.yml @@ -18,11 +18,11 @@ Nutriment: Min: 1 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 Flour: Min: 5 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: oat @@ -44,11 +44,11 @@ Nutriment: Min: 1 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 Oats: Min: 5 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: banana @@ -73,11 +73,11 @@ Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Nutriment: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: mimana @@ -100,11 +100,11 @@ MuteToxin: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Nutriment: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: carrots @@ -126,15 +126,15 @@ JuiceCarrot: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Oculine: Min: 2 Max: 6 - PotencyDivisor: 20 + potencyDivisor: 20 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: laughinPea @@ -159,15 +159,15 @@ Nutriment: Min: 1 Max: 3 - PotencyDivisor: 7 + potencyDivisor: 7 Sugar: Min: 1 Max: 10 - PotencyDivisor: 5 + potencyDivisor: 5 Laughter: Min: 1 Max: 10 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: lemon @@ -191,11 +191,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: lemoon @@ -217,11 +217,11 @@ Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Milk: Min: 8 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: lime @@ -243,11 +243,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: orange @@ -269,11 +269,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: pineapple @@ -296,15 +296,15 @@ Nutriment: Min: 1 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 Water: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Vitamin: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: potato @@ -326,11 +326,11 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: sugarcane @@ -353,7 +353,7 @@ Sugar: Min: 4 Max: 5 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: towercap @@ -426,15 +426,15 @@ Nutriment: Min: 1 Max: 7 - PotencyDivisor: 14 + potencyDivisor: 14 Vitamin: Min: 1 Max: 3 - PotencyDivisor: 33 + potencyDivisor: 33 Water: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: blueTomato @@ -460,15 +460,15 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 SpaceLube: Min: 5 Max: 15 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: bloodTomato @@ -494,11 +494,11 @@ Blood: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: eggplant @@ -523,11 +523,11 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: cabbage @@ -548,11 +548,11 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: garlic @@ -573,15 +573,15 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Allicin: Min: 1 Max: 8 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: apple @@ -603,11 +603,11 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: corn @@ -631,11 +631,11 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 20 + potencyDivisor: 20 Cornmeal: Min: 5 Max: 15 - PotencyDivisor: 10 + potencyDivisor: 10 - type: seed id: onion @@ -661,15 +661,15 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Allicin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: onionred @@ -693,15 +693,15 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Allicin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: chanterelle @@ -726,7 +726,7 @@ Nutriment: Min: 1 Max: 25 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: eggy @@ -750,7 +750,7 @@ Egg: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 - type: seed id: cannabis @@ -761,6 +761,8 @@ packetPrototype: CannabisSeeds productPrototypes: - LeavesCannabis + mutationPrototypes: + - rainbowCannabis harvestRepeat: Repeat lifespan: 75 maturation: 8 @@ -775,7 +777,52 @@ THC: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 + +- type: seed + id: rainbowCannabis + name: seeds-rainbow-cannabis-name + noun: seeds-noun-seeds + displayName: seeds-rainbow-cannabis-display-name + plantRsi: Objects/Specific/Hydroponics/rainbow_cannabis.rsi + packetPrototype: RainbowCannabisSeeds + productPrototypes: + - LeavesCannabisRainbow + harvestRepeat: Repeat + lifespan: 75 + maturation: 8 + production: 12 + yield: 2 + potency: 20 + growthStages: 3 + waterConsumption: 0.40 + idealLight: 9 + idealHeat: 298 + chemicals: + SpaceDrugs: + Min: 1 + Max: 15 + potencyDivisor: 10 + Lipolicide: + Min: 1 + Max: 15 + potencyDivisor: 10 + MindbreakerToxin: + Min: 1 + Max: 5 + potencyDivisor: 20 + Happiness: + Min: 1 + Max: 5 +# potencyDivisor: 20 +# ColorfulReagent: +# Min: 0 +# Max: 5 +# potencyDivisor: 20 + Psicodine: + Min: 0 + Max: 5 + potencyDivisor: 33 - type: seed id: tobacco @@ -800,7 +847,7 @@ Nicotine: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 - type: seed id: nettle @@ -826,7 +873,7 @@ Histamine: Min: 1 Max: 25 - PotencyDivisor: 4 + potencyDivisor: 4 - type: seed id: deathNettle @@ -851,11 +898,11 @@ SulfuricAcid: Min: 1 Max: 15 - PotencyDivisor: 6 + potencyDivisor: 6 FluorosulfuricAcid: Min: 1 Max: 15 - PotencyDivisor: 6 + potencyDivisor: 6 - type: seed id: chili @@ -865,7 +912,7 @@ plantRsi: Objects/Specific/Hydroponics/chili.rsi packetPrototype: ChiliSeeds productPrototypes: - - FoodChili + - FoodChiliPepper mutationPrototypes: - chilly harvestRepeat: Repeat @@ -880,15 +927,15 @@ CapsaicinOil: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Nutriment: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: chilly @@ -898,7 +945,7 @@ plantRsi: Objects/Specific/Hydroponics/chilly.rsi packetPrototype: ChillySeeds productPrototypes: - - FoodChilly + - FoodChillyPepper harvestRepeat: Repeat lifespan: 25 maturation: 6 @@ -911,15 +958,15 @@ Frostoil: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Nutriment: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: poppy @@ -943,11 +990,11 @@ Nutriment: Min: 1 Max: 2 - Potencydivisor: 50 + potencyDivisor: 50 Bicaridine: Min: 1 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: aloe @@ -969,11 +1016,11 @@ Aloe: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Dermaline: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 - type: seed id: lily @@ -997,11 +1044,11 @@ Nutriment: Min: 1 Max: 2 - Potencydivisor: 50 + potencyDivisor: 50 Bicaridine: Min: 1 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: lingzhi @@ -1023,11 +1070,11 @@ Ultravasculine: Min: 1 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 Epinephrine: Min: 1 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: ambrosiaVulgaris @@ -1051,23 +1098,23 @@ Nutriment: Min: 1 Max: 2 - PotencyDivisor: 10 + potencyDivisor: 10 Bicaridine: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Kelotane: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Desoxyephedrine: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 2 - Potencydivisor: 50 + potencyDivisor: 50 - type: seed id: ambrosiaDeus @@ -1089,19 +1136,19 @@ Nutriment: Min: 1 Max: 2 - PotencyDivisor: 10 + potencyDivisor: 10 Omnizine: # Don't kill me Min: 1 Max: 3 - PotencyDivisor: 35 + potencyDivisor: 35 SpaceDrugs: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Desoxyephedrine: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 - type: seed id: galaxythistle @@ -1123,7 +1170,7 @@ Stellibinin: Min: 1 Max: 25 - PotencyDivisor: 4 + potencyDivisor: 4 - type: seed id: flyAmanita @@ -1146,11 +1193,11 @@ Amatoxin: Min: 1 Max: 25 - PotencyDivisor: 4 + potencyDivisor: 4 Nutriment: ## yumby :) Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: gatfruit @@ -1172,11 +1219,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Sulfur: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: rice @@ -1200,11 +1247,11 @@ Nutriment: Min: 1 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 Rice: Min: 5 Max: 20 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: soybeans @@ -1229,7 +1276,7 @@ Nutriment: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: spacemansTrumpet @@ -1251,11 +1298,11 @@ Nutriment: Min: 1 Max: 5 - Potencydivisor: 50 + potencyDivisor: 50 PolypyryliumOligomers: Min: 1 Max: 15 - PotencyDivisor: 5 + potencyDivisor: 5 - type: seed id: koibean @@ -1278,11 +1325,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 CarpoToxin: Min: 1 Max: 4 - PotencyDivisor: 30 + potencyDivisor: 30 - type: seed id: grape @@ -1303,11 +1350,11 @@ Nutriment: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 - type: seed id: watermelon @@ -1328,15 +1375,15 @@ Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Water: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 Vitamin: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: cocoa @@ -1360,11 +1407,11 @@ Vitamin: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 Nutriment: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: berries @@ -1386,11 +1433,11 @@ Nutriment: Min: 2 Max: 5 - PotencyDivisor: 30 + potencyDivisor: 30 Vitamin: Min: 1 Max: 4 - PotencyDivisor: 40 + potencyDivisor: 40 - type: seed id: bungo @@ -1415,11 +1462,11 @@ Nutriment: Min: 5 Max: 10 - PotencyDivisor: 20 + potencyDivisor: 20 Enzyme: Min: 5 Max: 10 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: pea @@ -1446,11 +1493,11 @@ Nutriment: Min: 1 Max: 3 - PotencyDivisor: 33 + potencyDivisor: 33 Vitamin: Min: 1 Max: 2 - PotencyDivisor: 50 + potencyDivisor: 50 - type: seed id: pumpkin @@ -1472,11 +1519,11 @@ PumpkinFlesh: Min: 1 Max: 20 - PotencyDivisor: 5 + potencyDivisor: 5 Vitamin: Min: 1 Max: 5 - PotencyDivisor: 20 + potencyDivisor: 20 - type: seed id: cotton @@ -1487,6 +1534,8 @@ packetPrototype: CottonSeeds productPrototypes: - CottonBol + mutationPrototypes: + - pyrotton lifespan: 25 maturation: 8 production: 3 @@ -1499,5 +1548,31 @@ Fiber: Min: 5 Max: 10 - PotencyDivisor: 20 + potencyDivisor: 20 +- type: seed + id: pyrotton + name: seeds-pyrotton-name + noun: seeds-noun-seeds + displayName: seeds-pyrotton-display-name + plantRsi: Objects/Specific/Hydroponics/pyrotton.rsi + packetPrototype: PyrottonSeeds + productPrototypes: + - PyrottonBol + lifespan: 25 + maturation: 8 + production: 3 + yield: 2 + potency: 5 + idealLight: 8 + growthStages: 3 + waterConsumption: 0.80 + chemicals: + Fiber: + Min: 5 + Max: 10 + potencyDivisor: 20 + Phlogiston: + Min: 4 + Max: 8 + potencyDivisor: 30 diff --git a/Resources/Prototypes/InventoryTemplates/aghost_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/aghost_inventory_template.yml index 6252ad8e993..84806a051a7 100644 --- a/Resources/Prototypes/InventoryTemplates/aghost_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/aghost_inventory_template.yml @@ -11,6 +11,7 @@ displayName: ID - name: id slotTexture: id + fullTextureName: template_small slotFlags: IDCARD slotGroup: SecondHotbar stripTime: 6 diff --git a/Resources/Prototypes/InventoryTemplates/arachnid_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/arachnid_inventory_template.yml index a0c62b04cb1..863d5758ff7 100644 --- a/Resources/Prototypes/InventoryTemplates/arachnid_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/arachnid_inventory_template.yml @@ -63,6 +63,7 @@ displayName: Suit Storage - name: id slotTexture: id + fullTextureName: template_small slotFlags: IDCARD slotGroup: SecondHotbar stripTime: 6 @@ -72,6 +73,7 @@ displayName: ID - name: belt slotTexture: belt + fullTextureName: template_small slotFlags: BELT slotGroup: SecondHotbar stripTime: 6 @@ -80,6 +82,7 @@ displayName: Belt - name: back slotTexture: back + fullTextureName: template_small slotFlags: BACK slotGroup: SecondHotbar stripTime: 6 @@ -89,6 +92,7 @@ - name: pocket4 slotTexture: web + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -97,6 +101,7 @@ displayName: Pocket 4 - name: pocket3 slotTexture: web + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -112,6 +117,7 @@ displayName: Suit - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -122,6 +128,7 @@ stripHidden: true - name: pocket2 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -138,4 +145,6 @@ uiWindowPos: 2,0 strippingWindowPos: 2,5 dependsOn: outerClothing + dependsOnComponents: + - type: AllowSuitStorage displayName: Suit Storage diff --git a/Resources/Prototypes/InventoryTemplates/corpse_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/corpse_inventory_template.yml index 41fa7dc375f..878ccb3d6ba 100644 --- a/Resources/Prototypes/InventoryTemplates/corpse_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/corpse_inventory_template.yml @@ -55,6 +55,7 @@ displayName: Head - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -65,6 +66,7 @@ stripHidden: true - name: pocket2 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -81,9 +83,12 @@ uiWindowPos: 2,0 strippingWindowPos: 2,5 dependsOn: outerClothing + dependsOnComponents: + - type: AllowSuitStorage displayName: Suit Storage - name: belt slotTexture: belt + fullTextureName: template_small slotFlags: BELT slotGroup: SecondHotbar stripTime: 6 diff --git a/Resources/Prototypes/InventoryTemplates/diona_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/diona_inventory_template.yml index 4bbd18b1364..619aefddc34 100644 --- a/Resources/Prototypes/InventoryTemplates/diona_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/diona_inventory_template.yml @@ -56,6 +56,7 @@ displayName: Head - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -66,6 +67,7 @@ stripHidden: true - name: pocket2 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -82,9 +84,12 @@ uiWindowPos: 2,0 strippingWindowPos: 2,5 dependsOn: outerClothing + dependsOnComponents: + - type: AllowSuitStorage displayName: Suit Storage - name: id slotTexture: id + fullTextureName: template_small slotFlags: IDCARD slotGroup: SecondHotbar stripTime: 6 @@ -94,6 +99,7 @@ displayName: ID - name: belt slotTexture: belt + fullTextureName: template_small slotFlags: BELT slotGroup: SecondHotbar stripTime: 6 @@ -102,6 +108,7 @@ displayName: Belt - name: back slotTexture: back + fullTextureName: template_small slotFlags: BACK slotGroup: SecondHotbar stripTime: 6 diff --git a/Resources/Prototypes/InventoryTemplates/holoclown_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/holoclown_inventory_template.yml index 57dce506eaf..7be9c75015b 100644 --- a/Resources/Prototypes/InventoryTemplates/holoclown_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/holoclown_inventory_template.yml @@ -3,6 +3,7 @@ slots: - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -12,6 +13,7 @@ stripHidden: true - name: pocket2 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 diff --git a/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml index 574ecca35f4..ff1447931fe 100644 --- a/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/human_inventory_template.yml @@ -62,6 +62,7 @@ displayName: Head - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -72,6 +73,7 @@ stripHidden: true - name: pocket2 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -88,9 +90,12 @@ uiWindowPos: 2,0 strippingWindowPos: 2,5 dependsOn: outerClothing + dependsOnComponents: + - type: AllowSuitStorage displayName: Suit Storage - name: id slotTexture: id + fullTextureName: template_small slotFlags: IDCARD slotGroup: SecondHotbar stripTime: 6 @@ -100,6 +105,7 @@ displayName: ID - name: belt slotTexture: belt + fullTextureName: template_small slotFlags: BELT slotGroup: SecondHotbar stripTime: 6 @@ -108,6 +114,7 @@ displayName: Belt - name: back slotTexture: back + fullTextureName: template_small slotFlags: BACK slotGroup: SecondHotbar stripTime: 6 diff --git a/Resources/Prototypes/InventoryTemplates/kangaroo_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/kangaroo_inventory_template.yml index fb7dee1ec2b..5f81cdebc6c 100644 --- a/Resources/Prototypes/InventoryTemplates/kangaroo_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/kangaroo_inventory_template.yml @@ -35,6 +35,7 @@ - name: belt slotTexture: belt + fullTextureName: template_small slotFlags: BELT slotGroup: SecondHotbar stripTime: 6 @@ -47,6 +48,7 @@ - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 @@ -60,6 +62,7 @@ slots: - name: pocket1 slotTexture: pocket + fullTextureName: template_small slotFlags: POCKET slotGroup: MainHotbar stripTime: 3 diff --git a/Resources/Prototypes/InventoryTemplates/monkey_inventory_template.yml b/Resources/Prototypes/InventoryTemplates/monkey_inventory_template.yml index 5af23dabac2..19875f7e1bf 100644 --- a/Resources/Prototypes/InventoryTemplates/monkey_inventory_template.yml +++ b/Resources/Prototypes/InventoryTemplates/monkey_inventory_template.yml @@ -29,6 +29,7 @@ displayName: Jumpsuit - name: id slotTexture: id + fullTextureName: template_small slotFlags: IDCARD slotGroup: SecondHotbar stripTime: 6 @@ -44,6 +45,8 @@ uiWindowPos: 2,0 strippingWindowPos: 2,5 dependsOn: outerClothing + dependsOnComponents: + - type: AllowSuitStorage displayName: Suit Storage - name: outerClothing slotTexture: suit diff --git a/Resources/Prototypes/Magic/event_spells.yml b/Resources/Prototypes/Magic/event_spells.yml new file mode 100644 index 00000000000..e59e1b2db88 --- /dev/null +++ b/Resources/Prototypes/Magic/event_spells.yml @@ -0,0 +1,13 @@ +- type: entity + id: ActionSummonGhosts + name: Summon Ghosts + description: Makes all current ghosts permanently invisible + noSpawn: true + components: + - type: InstantAction + useDelay: 120 + itemIconStyle: BigAction + icon: + sprite: Mobs/Ghosts/ghost_human.rsi + state: icon + event: !type:ToggleGhostVisibilityToAllEvent diff --git a/Resources/Prototypes/Magic/knock_spell.yml b/Resources/Prototypes/Magic/knock_spell.yml index f00897d32c7..e2c3dcfd4c7 100644 --- a/Resources/Prototypes/Magic/knock_spell.yml +++ b/Resources/Prototypes/Magic/knock_spell.yml @@ -7,6 +7,8 @@ - type: InstantAction useDelay: 10 itemIconStyle: BigAction + sound: !type:SoundPathSpecifier + path: /Audio/Magic/knock.ogg icon: sprite: Objects/Magic/magicactions.rsi state: knock diff --git a/Resources/Prototypes/Magic/projectile_spells.yml b/Resources/Prototypes/Magic/projectile_spells.yml index 196472fe7b2..b8db7557bba 100644 --- a/Resources/Prototypes/Magic/projectile_spells.yml +++ b/Resources/Prototypes/Magic/projectile_spells.yml @@ -4,10 +4,12 @@ description: Fires an explosive fireball towards the clicked location. noSpawn: true components: + - type: Magic - type: WorldTargetAction useDelay: 15 itemIconStyle: BigAction checkCanAccess: false + raiseOnUser: true range: 60 sound: !type:SoundPathSpecifier path: /Audio/Magic/fireball.ogg @@ -16,25 +18,25 @@ state: fireball event: !type:ProjectileSpellEvent prototype: ProjectileFireball - posData: !type:TargetCasterPos speech: action-speech-spell-fireball - type: ActionUpgrade effectedLevels: 2: ActionFireballII + 3: ActionFireballIII - type: entity id: ActionFireballII parent: ActionFireball name: Fireball II - description: Fire three explosive fireball towards the clicked location. + description: Fires a fireball, but faster! noSpawn: true components: - type: WorldTargetAction - useDelay: 5 - charges: 3 + useDelay: 10 renewCharges: true itemIconStyle: BigAction checkCanAccess: false + raiseOnUser: true range: 60 sound: !type:SoundPathSpecifier path: /Audio/Magic/fireball.ogg @@ -43,5 +45,27 @@ state: fireball event: !type:ProjectileSpellEvent prototype: ProjectileFireball - posData: !type:TargetCasterPos speech: action-speech-spell-fireball + +- type: entity + id: ActionFireballIII + parent: ActionFireball + name: Fireball III + description: The fastest fireball in the west! + noSpawn: true + components: + - type: WorldTargetAction + useDelay: 8 + renewCharges: true + itemIconStyle: BigAction + checkCanAccess: false + raiseOnUser: true + range: 60 + sound: !type:SoundPathSpecifier + path: /Audio/Magic/fireball.ogg + icon: + sprite: Objects/Magic/magicactions.rsi + state: fireball + event: !type:ProjectileSpellEvent + prototype: ProjectileFireball + speech: action-speech-spell-fireball diff --git a/Resources/Prototypes/Magic/teleport_spells.yml b/Resources/Prototypes/Magic/teleport_spells.yml index 30c83891eee..cc89cf8ee0d 100644 --- a/Resources/Prototypes/Magic/teleport_spells.yml +++ b/Resources/Prototypes/Magic/teleport_spells.yml @@ -8,9 +8,11 @@ useDelay: 10 range: 16 # default examine-range. # ^ should probably add better validation that the clicked location is on the users screen somewhere, + sound: !type:SoundPathSpecifier + path: /Audio/Magic/blink.ogg itemIconStyle: BigAction checkCanAccess: false - repeat: true + repeat: false icon: sprite: Objects/Magic/magicactions.rsi state: blink diff --git a/Resources/Prototypes/Magic/utility_spells.yml b/Resources/Prototypes/Magic/utility_spells.yml new file mode 100644 index 00000000000..dccdda37898 --- /dev/null +++ b/Resources/Prototypes/Magic/utility_spells.yml @@ -0,0 +1,15 @@ +- type: entity + id: ActionChargeSpell + name: Charge + description: Adds a charge back to your wand + noSpawn: true + components: + - type: InstantAction + useDelay: 30 + itemIconStyle: BigAction + icon: + sprite: Objects/Weapons/Guns/Basic/wands.rsi + state: nothing + event: !type:ChargeSpellEvent + charge: 1 + speech: DI'RI CEL! diff --git a/Resources/Prototypes/Maps/asterisk.yml b/Resources/Prototypes/Maps/asterisk.yml index 3ef57dd4903..cf57fa27256 100644 --- a/Resources/Prototypes/Maps/asterisk.yml +++ b/Resources/Prototypes/Maps/asterisk.yml @@ -8,6 +8,8 @@ Asterisk: stationProto: StandardNanotrasenStation components: + - type: StationBiome + biome: Snow - type: StationRandomTransform enableStationRotation: false maxStationOffset: null diff --git a/Resources/Prototypes/NPCs/Combat/melee.yml b/Resources/Prototypes/NPCs/Combat/melee.yml index 122875ed97a..b0746e56793 100644 --- a/Resources/Prototypes/NPCs/Combat/melee.yml +++ b/Resources/Prototypes/NPCs/Combat/melee.yml @@ -17,6 +17,29 @@ - !type:HTNCompoundTask task: PickupMeleeCompound + - preconditions: + - !type:BuckledPrecondition + isBuckled: true + tasks: + - !type:HTNPrimitiveTask + operator: !type:UnbuckleOperator + shutdownState: TaskFinished + + - preconditions: + - !type:InContainerPrecondition + isInContainer: true + tasks: + - !type:HTNCompoundTask + task: EscapeCompound + + - preconditions: + - !type:PulledPrecondition + isPulled: true + tasks: + - !type:HTNPrimitiveTask + operator: !type:UnPullOperator + shutdownState: TaskFinished + # Melee combat (unarmed or otherwise) - tasks: - !type:HTNPrimitiveTask @@ -101,6 +124,21 @@ proto: NearbyMeleeTargets key: Target +- type: htnCompound + id: EscapeCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:ContainerOperator + targetKey: Target + shutdownState: TaskFinished + - !type:HTNPrimitiveTask + operator: !type:EscapeOperator + targetKey: Target + preconditions: + - !type:InContainerPrecondition + isInContainer: true + - type: htnCompound id: MeleeAttackOrderedTargetCompound branches: diff --git a/Resources/Prototypes/NPCs/debug.yml b/Resources/Prototypes/NPCs/debug.yml new file mode 100644 index 00000000000..c7929be1037 --- /dev/null +++ b/Resources/Prototypes/NPCs/debug.yml @@ -0,0 +1,90 @@ +- type: htnCompound + id: DebugCounterCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:AddFloatOperator + targetKey: Count + amount: 1 + + - !type:HTNPrimitiveTask + operator: !type:SayKeyOperator + key: Count + + - !type:HTNPrimitiveTask + operator: !type:RandomOperator + targetKey: IdleTime + minKey: MinimumIdleTime + maxKey: MaximumIdleTime + + - !type:HTNPrimitiveTask + operator: !type:WaitOperator + key: IdleTime + preconditions: + - !type:KeyExistsPrecondition + key: IdleTime + +- type: htnCompound + id: DebugRandomCounterCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:SetRandomFloatOperator + targetKey: Count + minAmount: 0 + maxAmount: 100 + + - !type:HTNPrimitiveTask + operator: !type:SayKeyOperator + key: Count + + - !type:HTNPrimitiveTask + operator: !type:RandomOperator + targetKey: IdleTime + minKey: MinimumIdleTime + maxKey: MaximumIdleTime + + - !type:HTNPrimitiveTask + operator: !type:WaitOperator + key: IdleTime + preconditions: + - !type:KeyExistsPrecondition + key: IdleTime + +- type: htnCompound + id: DebugRandomLessCompound + branches: + - tasks: + - !type:HTNPrimitiveTask + operator: !type:SetRandomFloatOperator + targetKey: Count + minAmount: 0 + maxAmount: 100 + + - !type:HTNPrimitiveTask + operator: !type:SayKeyOperator + key: Count + preconditions: + - !type:KeyFloatLessPrecondition + key: Count + value: 50 + + - !type:HTNPrimitiveTask + operator: !type:RandomOperator + targetKey: IdleTime + minKey: MinimumIdleTime + maxKey: MaximumIdleTime + + - !type:HTNPrimitiveTask + operator: !type:WaitOperator + key: IdleTime + preconditions: + - !type:KeyExistsPrecondition + key: IdleTime + + - tasks: + - !type:HTNPrimitiveTask + operator: !type:SpeakOperator + speech: "fuck!" + + \ No newline at end of file diff --git a/Resources/Prototypes/Nyanotrasen/Damage/groups.yml b/Resources/Prototypes/Nyanotrasen/Damage/groups.yml index d2f9906f451..31606605718 100644 --- a/Resources/Prototypes/Nyanotrasen/Damage/groups.yml +++ b/Resources/Prototypes/Nyanotrasen/Damage/groups.yml @@ -1,4 +1,5 @@ - type: damageGroup id: Immaterial + name: damage-group-immaterial damageTypes: - Holy diff --git a/Resources/Prototypes/Nyanotrasen/Damage/types.yml b/Resources/Prototypes/Nyanotrasen/Damage/types.yml index f9aba7e2ac8..22c045e9a62 100644 --- a/Resources/Prototypes/Nyanotrasen/Damage/types.yml +++ b/Resources/Prototypes/Nyanotrasen/Damage/types.yml @@ -1,5 +1,6 @@ # Only affects magical beings. - type: damageType id: Holy + name: damage-type-holy armorCoefficientPrice: 25 armorFlatPrice: 150 diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml index 046a324e6f6..a21976fa7a5 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Markers/Spawners/ghost_roles.yml @@ -51,23 +51,23 @@ - state: prisoner # - type: MidRoundAntagSpawnLocation # When MidRoundAntag? -- type: entity - id: SpawnPointGhostVampSpider - name: ghost role spawn point - suffix: Vampire spider - parent: MarkerBase - noSpawn: true - components: - - type: GhostRoleMobSpawner - prototype: MobGiantSpiderVampireAngry - - type: GhostRole - makeSentient: true - name: ghost-role-information-giant-spider-vampire-name - description: ghost-role-information-giant-spider-vampire-description - rules: No antagonist restrictions. Just don't talk in emote; you have telepathic chat. - - type: Sprite - sprite: Markers/jobs.rsi - layers: - - state: green - - sprite: Mobs/Animals/bat.rsi - state: bat +#- type: entity +# id: SpawnPointGhostVampSpider +# name: ghost role spawn point +# suffix: Vampire spider +# parent: MarkerBase +# noSpawn: true +# components: +# - type: GhostRoleMobSpawner +# prototype: MobGiantSpiderVampireAngry +# - type: GhostRole +# makeSentient: true +# name: ghost-role-information-giant-spider-vampire-name +# description: ghost-role-information-giant-spider-vampire-description +# rules: No antagonist restrictions. Just don't talk in emote; you have telepathic chat. +# - type: Sprite +# sprite: Markers/jobs.rsi +# layers: +# - state: green +# - sprite: Mobs/Animals/bat.rsi +# state: bat diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/mutants.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/mutants.yml index 996c0d87ab1..ee75dd3c8ee 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/mutants.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/mutants.yml @@ -70,132 +70,132 @@ - type: Produce - type: NoSlip -- type: entity - name: oneirophage - parent: MobGiantSpider - id: MobGiantSpiderVampire - description: The 'dream-eater' spider, rumored to be one of the potential genetic sources for arachne. - components: - - type: Sprite - drawdepth: Mobs - layers: - - map: ["enum.DamageStateVisualLayers.Base", "movement"] - state: viper - sprite: Mobs/Animals/spider.rsi - - type: SpriteMovement - movementLayers: - movement: - state: viper-moving - noMovementLayers: - movement: - state: viper - - type: Appearance - - type: DamageStateVisuals - states: - Alive: - Base: viper - Critical: - Base: viper_dead - Dead: - Base: viper_dead - - type: ReplacementAccent - accent: xeno - - type: InteractionPopup - successChance: 0.5 - interactSuccessString: petting-success-tarantula - interactFailureString: petting-failure-generic - interactSuccessSpawn: EffectHearts - interactSuccessSound: - path: /Audio/Animals/snake_hiss.ogg - - type: Puller - needsHands: false - - type: Arachne - cocoonDelay: 8 - - type: SolutionContainerManager - solutions: - melee: - reagents: - - ReagentId: Nocturine - Quantity: 20 - - type: MeleeChemicalInjector - solution: melee - transferAmount: 3.5 - - type: SolutionRegeneration - solution: melee - generated: - reagents: - - ReagentId: Nocturine - Quantity: 0.15 - - type: BloodSucker - unitsToSucc: 35 - injectWhenSucc: true - injectReagent: Cryptobiolin - unitsToInject: 10 - webRequired: true - - type: Bloodstream - bloodReagent: DemonsBlood - - type: Body - prototype: VampiricAnimalLarge - - type: Psionic - removable: false - - type: InnatePsionicPowers - powersToAdd: - - MetapsionicPower - - PsionicInvisibilityPower - - type: AntiPsionicWeapon - punish: false - modifiers: - coefficients: - Piercing: 2.25 - - type: Damageable - damageContainer: HalfSpirit - damageModifierSet: HalfSpirit - - type: StatusEffects - allowed: - - Stun - - KnockedDown - - SlowedDown - - Stutter - - SeeingRainbows - - Electrocution - - Drunk - - SlurredSpeech - - PressureImmunity - - Muted - - ForcedSleep - - TemporaryBlindness - - Pacified - - PsionicsDisabled - - PsionicallyInsulated - - type: Tag - tags: - - Oneirophage - - type: MovementAlwaysTouching - - type: PsionicInvisibleContacts - whitelist: - tags: - - ArachneWeb +#- type: entity +# name: oneirophage +# parent: MobGiantSpider +# id: MobGiantSpiderVampire +# description: The 'dream-eater' spider, rumored to be one of the potential genetic sources for arachne. +# components: +# - type: Sprite +# drawdepth: Mobs +# layers: +# - map: ["enum.DamageStateVisualLayers.Base", "movement"] +# state: viper +# sprite: Mobs/Animals/spider.rsi +# - type: SpriteMovement +# movementLayers: +# movement: +# state: viper-moving +# noMovementLayers: +# movement: +# state: viper +# - type: Appearance +# - type: DamageStateVisuals +# states: +# Alive: +# Base: viper +# Critical: +# Base: viper_dead +# Dead: +# Base: viper_dead +# - type: ReplacementAccent +# accent: xeno +# - type: InteractionPopup +# successChance: 0.5 +# interactSuccessString: petting-success-tarantula +# interactFailureString: petting-failure-generic +# interactSuccessSpawn: EffectHearts +# interactSuccessSound: +# path: /Audio/Animals/snake_hiss.ogg +# - type: Puller +# needsHands: false +# - type: Arachne +# cocoonDelay: 8 +# - type: SolutionContainerManager +# solutions: +# melee: +# reagents: +# - ReagentId: Nocturine +# Quantity: 20 +# - type: MeleeChemicalInjector +# solution: melee +# transferAmount: 3.5 +# - type: SolutionRegeneration +# solution: melee +# generated: +# reagents: +# - ReagentId: Nocturine +# Quantity: 0.15 +# - type: BloodSucker +# unitsToSucc: 35 +# injectWhenSucc: true +# injectReagent: Cryptobiolin +# unitsToInject: 10 +# webRequired: true +# - type: Bloodstream +# bloodReagent: DemonsBlood +# - type: Body +# prototype: VampiricAnimalLarge +# - type: Psionic +# removable: false +# - type: InnatePsionicPowers +# powersToAdd: +# - MetapsionicPower +# - PsionicInvisibilityPower +# - type: AntiPsionicWeapon +# punish: false +# modifiers: +# coefficients: +# Piercing: 2.25 +# - type: Damageable +# damageContainer: HalfSpirit +# damageModifierSet: HalfSpirit +# - type: StatusEffects +# allowed: +# - Stun +# - KnockedDown +# - SlowedDown +# - Stutter +# - SeeingRainbows +# - Electrocution +# - Drunk +# - SlurredSpeech +# - PressureImmunity +# - Muted +# - ForcedSleep +# - TemporaryBlindness +# - Pacified +# - PsionicsDisabled +# - PsionicallyInsulated +# - type: Tag +# tags: +# - Oneirophage +# - type: MovementAlwaysTouching +# - type: PsionicInvisibleContacts +# whitelist: +# tags: +# - ArachneWeb -- type: entity - name: oneirophage - parent: MobGiantSpiderVampire - id: MobGiantSpiderVampireAngry - suffix: Angry - components: - - type: NpcFactionMember - factions: - - SimpleHostile - - type: InputMover - - type: MobMover - - type: HTN - rootTask: - task: SimpleHostileCompound - - type: GhostRole - makeSentient: true - name: ghost-role-information-giant-spider-vampire-name - description: ghost-role-information-giant-spider-vampire-description - rules: No antagonist restrictions. Just don't talk in emote; you have telepathic chat. - - type: GhostTakeoverAvailable +#- type: entity +# name: oneirophage +# parent: MobGiantSpiderVampire +# id: MobGiantSpiderVampireAngry +# suffix: Angry +# components: +# - type: NpcFactionMember +# factions: +# - SimpleHostile +# - type: InputMover +# - type: MobMover +# - type: HTN +# rootTask: +# task: SimpleHostileCompound +# - type: GhostRole +# makeSentient: true +# name: ghost-role-information-giant-spider-vampire-name +# description: ghost-role-information-giant-spider-vampire-description +# rules: No antagonist restrictions. Just don't talk in emote; you have telepathic chat. +# - type: GhostTakeoverAvailable - type: entity parent: SimpleMobBase @@ -298,9 +298,10 @@ - type: Puller needsHands: false - type: Vocal - # mice are gender neutral who cares - maleScream: /Audio/Animals/mouse_squeak.ogg - femaleScream: /Audio/Animals/mouse_squeak.ogg + sounds: + Male: Mouse + Female: Mouse + Unsexed: Mouse wilhelmProbability: 0.001 - type: Tag tags: @@ -335,11 +336,7 @@ proper: true gender: male - type: IntrinsicRadioReceiver - channels: - - Common - type: IntrinsicRadioTransmitter - channels: - - Common - type: ActiveRadio channels: - Common diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/xeno.yml b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/xeno.yml index 9dbe9f95f70..e12b14d4906 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/xeno.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Mobs/NPCs/xeno.yml @@ -6,6 +6,7 @@ id: MobPurpleSnakeGhost components: - type: GhostTakeoverAvailable + - type: GhostRole allowMovement: true allowSpeech: false makeSentient: true @@ -19,6 +20,7 @@ id: MobSmallPurpleSnakeGhost components: - type: GhostTakeoverAvailable + - type: GhostRole allowMovement: true allowSpeech: false makeSentient: true diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Chapel/amphorae.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Chapel/amphorae.yml index 10f5d631aa5..2ef262fd538 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Chapel/amphorae.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Chapel/amphorae.yml @@ -17,7 +17,6 @@ jar: maxVol: 120 - type: Drink - isOpen: true solution: jar - type: Spillable solution: jar @@ -35,8 +34,8 @@ canChangeTransferAmount: true - type: UserInterface interfaces: - - key: enum.TransferAmountUiKey.Key - type: TransferAmountBoundUserInterface + enum.TransferAmountUiKey.Key: + type: TransferAmountBoundUserInterface - type: Damageable damageContainer: Inorganic - type: Destructible diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml index c1ca2cd60b1..da1b1d50d03 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Objects/Specific/Mail/base_mail.yml @@ -77,7 +77,6 @@ - trigger: !type:DamageTrigger damage: 5 - triggersOnce: true behaviors: - !type:DoActsBehavior acts: [ "Breakage" ] diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/deep_fryer.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/deep_fryer.yml index fa3e0537dbb..9749a4295d2 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/deep_fryer.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/deep_fryer.yml @@ -124,15 +124,14 @@ - type: RefillableSolution solution: vat_oil - type: Drink - isOpen: true solution: vat_oil - type: Appearance - type: ActivatableUI key: enum.DeepFryerUiKey.Key - type: UserInterface interfaces: - - key: enum.DeepFryerUiKey.Key - type: DeepFryerBoundUserInterface + enum.DeepFryerUiKey.Key: + type: DeepFryerBoundUserInterface - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/laundry.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/laundry.yml index ce982d41c2f..47518c78f69 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/laundry.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/laundry.yml @@ -84,8 +84,8 @@ ents: [] - type: UserInterface interfaces: - - key: enum.StorageUiKey.Key - type: StorageBoundUserInterface + enum.StorageUiKey.Key: + type: StorageBoundUserInterface - type: UseDelay delay: 0.5 - type: Repairable diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/reverseEngineering.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/reverseEngineering.yml index c28c395261a..3c3a9908c65 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/reverseEngineering.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Machines/reverseEngineering.yml @@ -19,8 +19,8 @@ key: enum.ReverseEngineeringMachineUiKey.Key - type: UserInterface interfaces: - - key: enum.ReverseEngineeringMachineUiKey.Key - type: ReverseEngineeringMachineBoundUserInterface + enum.ReverseEngineeringMachineUiKey.Key: + type: ReverseEngineeringMachineBoundUserInterface - type: ActivatableUIRequiresPower - type: ItemSlots slots: diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml index e34aa9f4027..f92c9b07400 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Research/sophicscribe.yml @@ -16,13 +16,7 @@ - type: Speech speechSounds: Tenor - type: IntrinsicRadioReceiver - channels: - - Common - - Science - type: IntrinsicRadioTransmitter - channels: - - Common - - Science - type: ActiveRadio channels: - Common diff --git a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Walls/walls.yml b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Walls/walls.yml index 12548299910..971e292f90d 100644 --- a/Resources/Prototypes/Nyanotrasen/Entities/Structures/Walls/walls.yml +++ b/Resources/Prototypes/Nyanotrasen/Entities/Structures/Walls/walls.yml @@ -49,8 +49,6 @@ node: girder - !type:DoActsBehavior acts: ["Destruction"] - destroySound: - collection: MetalBreak - type: IconSmooth key: walls base: paperwall diff --git a/Resources/Prototypes/Nyanotrasen/Hydroponics/seeds.yml b/Resources/Prototypes/Nyanotrasen/Hydroponics/seeds.yml index 688af9fc50c..08f4482787f 100644 --- a/Resources/Prototypes/Nyanotrasen/Hydroponics/seeds.yml +++ b/Resources/Prototypes/Nyanotrasen/Hydroponics/seeds.yml @@ -17,14 +17,13 @@ nutrientConsumption: 0.25 idealLight: 8 idealHeat: 298 - juicy: true splatPrototype: PuddleSplatter chemicals: Nutriment: Min: 1 Max: 10 - PotencyDivisor: 10 + potencyDivisor: 10 DemonsBlood: Min: 1 Max: 4 - PotencyDivisor: 25 + potencyDivisor: 25 diff --git a/Resources/Prototypes/Nyanotrasen/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Nyanotrasen/Recipes/Cooking/meal_recipes.yml index 51777e2f594..b61e99ba920 100644 --- a/Resources/Prototypes/Nyanotrasen/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Nyanotrasen/Recipes/Cooking/meal_recipes.yml @@ -26,7 +26,7 @@ solids: FoodSnackBoritos: 1 FoodCheeseSlice: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodMeatMeatball: 1 # Base ingredients: Should be moved out of microwave as soon as possible. @@ -62,7 +62,7 @@ solids: FoodTofuSlice: 2 FoodOnionSlice: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodCarrot: 1 FoodCheeseCurds: 1 @@ -97,7 +97,7 @@ solids: FoodCheeseSlice: 1 FoodCabbage: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodPotato: 1 FoodOnionSlice: 2 @@ -111,7 +111,7 @@ solids: FoodCheeseSlice: 1 #Grilled cheese slice FoodMothSaladBase: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodCabbage: 1 - type: microwaveMealRecipe @@ -142,7 +142,7 @@ FoodRiceBoiled: 1 FoodPotato: 2 FoodCabbage: 1 - FoodChili: 1 + FoodChiliPepper: 1 #Herbs: 1 - type: microwaveMealRecipe @@ -307,7 +307,7 @@ solids: FoodBowlBig: 1 FoodTofuSlice: 1 - FoodChili: 1 + FoodChiliPepper: 1 #FoodYogurt: 1 #Milk and Cream placeholder - type: microwaveMealRecipe @@ -368,7 +368,7 @@ solids: FoodBowlBig: 1 FoodTomato: 1 - FoodChili: 1 + FoodChiliPepper: 1 # Salads: These should be moved out of the microwave as soon as possible @@ -421,7 +421,7 @@ solids: FoodBowlBig: 1 FoodMothSaladBase: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodOnionRed: 1 FoodAmbrosiaVulgaris: 1 #Herbs @@ -438,7 +438,7 @@ FoodDoughFlat: 1 FoodCheeseSlice: 1 FoodMothBakedCorn: 1 - FoodChili: 1 + FoodChiliPepper: 1 - type: microwaveMealRecipe id: RecipeMothFiveCheesePizza diff --git a/Resources/Prototypes/Nyanotrasen/Voice/speech_emotes.yml b/Resources/Prototypes/Nyanotrasen/Voice/speech_emotes.yml index fa471f3d705..f9bd3f60b45 100644 --- a/Resources/Prototypes/Nyanotrasen/Voice/speech_emotes.yml +++ b/Resources/Prototypes/Nyanotrasen/Voice/speech_emotes.yml @@ -1,6 +1,7 @@ # vocal emotes - type: emote id: Hiss + name: chat-emote-name-cathisses category: Vocal chatMessages: [ hisses ] chatTriggers: @@ -8,6 +9,7 @@ - type: emote id: Meow + name: chat-emote-name-catmeow category: Vocal chatMessages: [ meows ] chatTriggers: @@ -18,6 +20,7 @@ - type: emote id: Mew + name: chat-emote-name-catmew category: Vocal chatMessages: [ mews ] chatTriggers: @@ -25,6 +28,7 @@ - type: emote id: Growl + name: chat-emote-name-catgrowl category: Vocal chatMessages: [ growls ] chatTriggers: @@ -32,6 +36,7 @@ - type: emote id: Purr + name: chat-emote-name-catpurr category: Vocal chatMessages: [ purrs ] chatTriggers: diff --git a/Resources/Prototypes/Objectives/base_objectives.yml b/Resources/Prototypes/Objectives/base_objectives.yml index e24b26e6e86..2ab5149213a 100644 --- a/Resources/Prototypes/Objectives/base_objectives.yml +++ b/Resources/Prototypes/Objectives/base_objectives.yml @@ -103,3 +103,11 @@ id: BaseSurviveObjective components: - type: SurviveCondition + +# objective progress is controlled by a system and not the objective itself +- type: entity + abstract: true + parent: BaseObjective + id: BaseCodeObjective + components: + - type: CodeCondition diff --git a/Resources/Prototypes/Objectives/ninja.yml b/Resources/Prototypes/Objectives/ninja.yml index 0495be29355..fb94f2b3788 100644 --- a/Resources/Prototypes/Objectives/ninja.yml +++ b/Resources/Prototypes/Objectives/ninja.yml @@ -46,7 +46,7 @@ - type: entity noSpawn: true - parent: BaseNinjaObjective + parent: [BaseNinjaObjective, BaseCodeObjective] id: SpiderChargeObjective description: This bomb can be detonated in a specific location. Note that the bomb will not work anywhere else! components: @@ -54,7 +54,6 @@ icon: sprite: Objects/Weapons/Bombs/spidercharge.rsi state: icon - - type: SpiderChargeCondition - type: entity noSpawn: true @@ -70,7 +69,7 @@ - type: entity noSpawn: true - parent: BaseNinjaObjective + parent: [BaseNinjaObjective, BaseCodeObjective] id: TerrorObjective name: Call in a threat description: Use your gloves on a communication console in order to bring another threat to the station. @@ -79,4 +78,15 @@ icon: sprite: Objects/Fun/Instruments/otherinstruments.rsi state: red_phone - - type: TerrorCondition + +- type: entity + noSpawn: true + parent: [BaseNinjaObjective, BaseCodeObjective] + id: MassArrestObjective + name: Set everyone to wanted + description: Use your gloves to hack a criminal records console, setting the entire station to be wanted! + components: + - type: Objective + icon: + sprite: Objects/Weapons/Melee/stunbaton.rsi + state: stunbaton_on diff --git a/Resources/Prototypes/Objectives/terminator.yml b/Resources/Prototypes/Objectives/terminator.yml deleted file mode 100644 index 1b569599a7f..00000000000 --- a/Resources/Prototypes/Objectives/terminator.yml +++ /dev/null @@ -1,40 +0,0 @@ -- type: entity - abstract: true - parent: BaseObjective - id: BaseTerminatorObjective - components: - - type: Objective - difficulty: 1 - issuer: susnet - - type: RoleRequirement - roles: - components: - - TerminatorRole - -- type: entity - noSpawn: true - parent: [BaseTerminatorObjective, BaseKillObjective] - id: TerminateObjective - description: Follow your programming and terminate the target. - components: - - type: Objective - unique: false - - type: TargetObjective - title: objective-terminate-title - - type: PickRandomPerson - - type: TerminatorTargetOverride - - type: KillPersonCondition - requireDead: true - -- type: entity - noSpawn: true - parent: BaseTerminatorObjective - id: ShutDownObjective - name: Shut down - description: Once the mission is complete die to prevent our technology from being stolen. - components: - - type: Objective - icon: - sprite: Mobs/Species/Terminator/parts.rsi - state: skull_icon - - type: DieCondition diff --git a/Resources/Prototypes/Objectives/traitor.yml b/Resources/Prototypes/Objectives/traitor.yml index d9c071c30c0..554ccad2645 100644 --- a/Resources/Prototypes/Objectives/traitor.yml +++ b/Resources/Prototypes/Objectives/traitor.yml @@ -191,6 +191,9 @@ components: - type: StealCondition stealGroup: ClothingOuterHardsuitRd + - type: Objective + # This item must be worn or stored in a slowing duffelbag, very hard to hide. + difficulty: 3 - type: entity noSpawn: true diff --git a/Resources/Prototypes/Polymorphs/polymorph.yml b/Resources/Prototypes/Polymorphs/polymorph.yml index b4249f8a3ea..a1a805c74fc 100644 --- a/Resources/Prototypes/Polymorphs/polymorph.yml +++ b/Resources/Prototypes/Polymorphs/polymorph.yml @@ -75,6 +75,17 @@ inventory: Transfer revertOnDeath: true +- type: polymorph + id: SlimeMorphGeras + configuration: + entity: MobSlimesGeras + transferName: true + transferHumanoidAppearance: false + inventory: Drop + transferDamage: true + revertOnDeath: true + revertOnCrit: true + # this is a test for transferring some visual appearance stuff - type: polymorph id: TestHumanMorph @@ -164,3 +175,25 @@ revertOnDeath: true revertOnCrit: true duration: 20 + +# Polymorphs for Wizards polymorph self spell +- type: polymorph + id: WizardSpider + configuration: + entity: MobGiantSpiderWizard #Not angry so ghosts can't just take over the wizard + transferName: true + inventory: None + revertOnDeath: true + revertOnCrit: true + +- type: polymorph + id: WizardRod + configuration: + entity: ImmovableRodWizard #CLANG + transferName: true + transferDamage: false + inventory: None + duration: 1 + forced: true + revertOnCrit: false + revertOnDeath: false diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml index d9e57d5b803..211e3b83379 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/alcohol.yml @@ -39,6 +39,7 @@ metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- metamorphicChangeColor: false + fizziness: 0.6 - type: reagent id: Beer @@ -55,6 +56,7 @@ metamorphicMaxFillLevels: 6 metamorphicFillBaseName: fill- metamorphicChangeColor: true + fizziness: 0.6 - type: reagent id: BlueCuracao @@ -418,7 +420,7 @@ metamorphicSprite: sprite: Objects/Consumable/Drinks/tequillaglass.rsi state: icon_empty - metamorphicMaxFillLevels: 4 + metamorphicMaxFillLevels: 3 metamorphicFillBaseName: fill- metamorphicChangeColor: false metabolisms: @@ -546,6 +548,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.12 + fizziness: 0.8 # Mixed Alcohol @@ -811,6 +814,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.3 - type: reagent id: BlackRussian @@ -966,6 +970,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.2 - type: reagent id: DemonsBlood @@ -989,6 +994,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.10 + fizziness: 0.3 - type: reagent id: DevilsKiss @@ -1089,6 +1095,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.02 + fizziness: 0.15 - type: reagent id: GargleBlaster @@ -1135,6 +1142,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.15 + fizziness: 0.4 - type: reagent id: GinTonic @@ -1158,6 +1166,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.15 + fizziness: 0.4 - type: reagent id: Gildlager @@ -1259,6 +1268,7 @@ metamorphicMaxFillLevels: 6 metamorphicFillBaseName: fill- metamorphicChangeColor: false + fizziness: 0.6 - type: reagent id: IrishCarBomb @@ -1412,6 +1422,7 @@ metamorphicMaxFillLevels: 2 metamorphicFillBaseName: fill- metamorphicChangeColor: false + fizziness: 0.7 - type: reagent id: Margarita @@ -1465,6 +1476,7 @@ metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- metamorphicChangeColor: true + fizziness: 0.4 - type: reagent id: Mojito @@ -1488,6 +1500,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.10 + fizziness: 0.3 - type: reagent id: Moonshine @@ -1497,6 +1510,12 @@ physicalDesc: reagent-physical-desc-strong-smelling flavor: moonshine color: "#d1d7d155" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/moonshineglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 6 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false metabolisms: Drink: effects: @@ -1592,6 +1611,7 @@ metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- metamorphicChangeColor: true + fizziness: 0.4 - type: reagent id: PinaColada @@ -1753,6 +1773,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.03 + fizziness: 0.3 - type: reagent id: SuiDream @@ -1776,6 +1797,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.2 - type: reagent id: SyndicateBomb @@ -1799,6 +1821,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.095 + fizziness: 0.6 - type: reagent id: TequilaSunrise @@ -1845,6 +1868,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.2 - type: reagent id: ThreeMileIsland @@ -1940,6 +1964,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.4 - type: reagent id: WhiskeyCola @@ -1963,6 +1988,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.013 + fizziness: 0.3 - type: reagent id: WhiskeySoda @@ -1986,6 +2012,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.13 + fizziness: 0.4 - type: reagent id: WhiteGilgamesh @@ -2003,6 +2030,7 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.04 + fizziness: 0.5 - type: reagent id: WhiteRussian @@ -2026,3 +2054,165 @@ - !type:AdjustReagent reagent: Ethanol amount: 0.33 + +- type: reagent + id: VodkaRedBool + name: reagent-name-vodka-red-bool + parent: BaseAlcohol + desc: reagent-desc-vodka-red-bool + physicalDesc: reagent-physical-desc-strong-smelling + flavor: vodkaredbool + color: "#c4c27655" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/ginvodkaglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: true + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.10 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.25 + +- type: reagent + id: XenoBasher + name: reagent-name-xeno-basher + parent: BaseAlcohol + desc: reagent-desc-xeno-basher + physicalDesc: reagent-physical-desc-fizzy-and-creamy + flavor: xenobasher + color: "#4d6600" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/xenobasher.rsi + state: icon_empty + metamorphicMaxFillLevels: 2 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.15 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.15 + +- type: reagent + id: IrishBool + name: reagent-name-irish-bool + parent: BaseAlcohol + desc: reagent-desc-irish-bool + physicalDesc: reagent-physical-desc-bubbly + flavor: irishbool + color: "#71672e99" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/beerglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 6 + metamorphicFillBaseName: fill- + metamorphicChangeColor: true + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.10 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.15 + +- type: reagent + id: BudgetInsulsDrink + name: reagent-name-budget-insuls + parent: BaseAlcohol + desc: reagent-desc-budget-insuls + physicalDesc: reagent-physical-desc-strong-smelling + flavor: budgetinsulsdrink + color: "#dede73" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/budgetinsulsdrink.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.15 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.25 + +- type: reagent + id: WatermelonWakeup + name: reagent-name-watermelon-wakeup + parent: BaseAlcohol + desc: reagent-desc-watermelon-wakeup + physicalDesc: reagent-physical-desc-sweet + flavor: watermelonwakeup + color: "#d49dca" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/champagneglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: true + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.07 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.15 + +- type: reagent + id: Rubberneck + name: reagent-name-rubberneck + parent: BaseAlcohol + desc: reagent-desc-rubberneck + physicalDesc: reagent-physical-desc-strong-smelling + flavor: rubberneck + color: "#f0d74a" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/rubberneck.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false + metabolisms: + Drink: + effects: + - !type:SatiateThirst + factor: 1 + - !type:AdjustReagent + reagent: Ethanol + amount: 0.15 + - !type:AdjustReagent + reagent: Theobromine + amount: 0.05 + fizziness: 0.25 diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml b/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml index 9984b4c0cf6..19a5e1bf8f1 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/base_drink.yml @@ -40,6 +40,7 @@ collection: FootstepSticky params: volume: 6 + fizziness: 0.5 - type: reagent id: BaseAlcohol @@ -75,4 +76,4 @@ footstepSound: collection: FootstepSticky params: - volume: 6 \ No newline at end of file + volume: 6 diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml b/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml index 5c09b3c909b..52a01d973f6 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/drinks.yml @@ -15,6 +15,12 @@ - !type:AdjustReagent reagent: Theobromine amount: 0.05 + metamorphicSprite: + sprite: Objects/Consumable/Drinks/coffeeglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: HotCocoa @@ -100,9 +106,9 @@ flavor: tea color: "#7EB626" metamorphicSprite: - sprite: Objects/Consumable/Drinks/glass_green.rsi + sprite: Objects/Consumable/Drinks/greenteaglass.rsi state: icon_empty - metamorphicMaxFillLevels: 5 + metamorphicMaxFillLevels: 4 metamorphicFillBaseName: fill- metamorphicChangeColor: false @@ -149,7 +155,7 @@ flavor: icedtea color: "#5B821B" metamorphicSprite: - sprite: Objects/Consumable/Drinks/glass_green.rsi + sprite: Objects/Consumable/Drinks/icedgreenteaglass.rsi state: icon_empty metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- @@ -322,6 +328,7 @@ damage: types: Poison: 1 + fizziness: 0.5 - type: reagent id: SodaWater @@ -331,6 +338,7 @@ physicalDesc: reagent-physical-desc-fizzy flavor: fizzy color: "#619494" + fizziness: 0.8 - type: reagent id: SoyLatte @@ -364,6 +372,12 @@ - !type:AdjustReagent reagent: Theobromine amount: 0.05 + metamorphicSprite: + sprite: Objects/Consumable/Drinks/teaglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: TonicWater @@ -373,6 +387,13 @@ physicalDesc: reagent-physical-desc-fizzy flavor: tonicwater color: "#0064C8" + fizziness: 0.4 + metamorphicSprite: + sprite: Objects/Consumable/Drinks/tonicglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: Water @@ -405,6 +426,12 @@ plantMetabolism: - !type:PlantAdjustWater amount: 1 + metamorphicSprite: + sprite: Objects/Consumable/Drinks/iceglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 3 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: DryRamen @@ -467,6 +494,7 @@ effects: - !type:SatiateThirst factor: 1 + fizziness: 0.3 - type: reagent id: Posca @@ -491,6 +519,7 @@ metamorphicMaxFillLevels: 3 metamorphicFillBaseName: fill- metamorphicChangeColor: false + fizziness: 0.3 - type: reagent id: Rewriter @@ -506,6 +535,7 @@ metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- metamorphicChangeColor: true + fizziness: 0.3 - type: reagent id: Mopwata diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/juice.yml b/Resources/Prototypes/Reagents/Consumable/Drink/juice.yml index ee1492b45e2..c42791fa8fe 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/juice.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/juice.yml @@ -63,6 +63,12 @@ physicalDesc: reagent-physical-desc-citric flavor: sour color: "#fff690" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/lemonjuiceglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: JuiceLime @@ -89,6 +95,12 @@ physicalDesc: reagent-physical-desc-citric flavor: orange color: "#E78108" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/orangejuiceglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: JuicePineapple @@ -125,3 +137,9 @@ physicalDesc: reagent-physical-desc-sweet flavor: watermelon color: "#EF3520" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/watermelonglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 4 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false diff --git a/Resources/Prototypes/Reagents/Consumable/Drink/soda.yml b/Resources/Prototypes/Reagents/Consumable/Drink/soda.yml index ba5adc4f2ae..d78b0351cee 100644 --- a/Resources/Prototypes/Reagents/Consumable/Drink/soda.yml +++ b/Resources/Prototypes/Reagents/Consumable/Drink/soda.yml @@ -7,6 +7,12 @@ flavor: soda color: "#6c2828" recognizable: true + metamorphicSprite: + sprite: Objects/Consumable/Drinks/colaglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: RoyRogers @@ -42,6 +48,12 @@ physicalDesc: reagent-physical-desc-fizzy flavor: drgibb color: "#102000" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/dr_gibb_glass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: EnergyDrink @@ -58,7 +70,8 @@ factor: 2 - !type:AdjustReagent reagent: Theobromine - amount: 0.05 + amount: 0.1 + fizziness: 0.4 - type: reagent id: GrapeSoda @@ -84,6 +97,7 @@ metamorphicMaxFillLevels: 5 metamorphicFillBaseName: fill- metamorphicChangeColor: true + fizziness: 0 - type: reagent id: LemonLime @@ -102,6 +116,7 @@ physicalDesc: reagent-physical-desc-fizzy flavor: pwrgamesoda color: "#9385bf" + fizziness: 0.9 # gamers crave the fizz - type: reagent id: RootBeer @@ -132,6 +147,7 @@ metamorphicMaxFillLevels: 7 metamorphicFillBaseName: fill- metamorphicChangeColor: false + fizziness: 0.4 - type: reagent id: SolDry @@ -170,6 +186,12 @@ physicalDesc: reagent-physical-desc-fizzy flavor: sodacitrus color: "#a6fa5a" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/space_mountain_wind_glass.rsi + state: icon_empty + metamorphicMaxFillLevels: 5 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: SpaceUp @@ -179,6 +201,12 @@ physicalDesc: reagent-physical-desc-fizzy flavor: spaceup color: "#e3e3e37d" + metamorphicSprite: + sprite: Objects/Consumable/Drinks/space-up_glass.rsi + state: icon_empty + metamorphicMaxFillLevels: 6 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: Starkist diff --git a/Resources/Prototypes/Reagents/Consumable/Food/food.yml b/Resources/Prototypes/Reagents/Consumable/Food/food.yml index 03ebf7cc321..c9625c663ca 100644 --- a/Resources/Prototypes/Reagents/Consumable/Food/food.yml +++ b/Resources/Prototypes/Reagents/Consumable/Food/food.yml @@ -93,6 +93,12 @@ amount: 2 - !type:PlantAdjustPests amount: 2 + metamorphicSprite: + sprite: Objects/Consumable/Drinks/sugarglass.rsi + state: icon_empty + metamorphicMaxFillLevels: 7 + metamorphicFillBaseName: fill- + metamorphicChangeColor: false - type: reagent id: PumpkinFlesh #Just so pumpkins spill orange stuff when smashed @@ -100,4 +106,4 @@ name: reagent-name-pumpkin-flesh desc: reagent-desc-pumpkin-flesh flavor: pumpkin - color: "#fc9300" \ No newline at end of file + color: "#fc9300" diff --git a/Resources/Prototypes/Reagents/botany.yml b/Resources/Prototypes/Reagents/botany.yml index a03c3826a4d..cdd19dc308d 100644 --- a/Resources/Prototypes/Reagents/botany.yml +++ b/Resources/Prototypes/Reagents/botany.yml @@ -222,6 +222,9 @@ - !type:OrganType type: Rat shouldHave: false + - !type:OrganType + type: Vox + shouldHave: false - !type:ReagentThreshold reagent: Ammonia min: 0.8 @@ -247,6 +250,13 @@ groups: Brute: -5 Burn: -5 + types: + Bloodloss: -5 + - !type:Oxygenate # ammonia displaces nitrogen in vox blood + conditions: + - !type:OrganType + type: Vox + factor: -4 - type: reagent diff --git a/Resources/Prototypes/Reagents/gases.yml b/Resources/Prototypes/Reagents/gases.yml index 9cb73fffb85..06fb2b269b6 100644 --- a/Resources/Prototypes/Reagents/gases.yml +++ b/Resources/Prototypes/Reagents/gases.yml @@ -35,6 +35,25 @@ ratios: CarbonDioxide: 1.0 Oxygen: -1.0 + - !type:HealthChange + conditions: + - !type:OrganType + type: Vox + scaleByQuantity: true + ignoreResistances: true + damage: + types: + Poison: + 7 + - !type:AdjustAlert + alertType: Toxins + conditions: + - !type:ReagentThreshold + min: 0.5 + - !type:OrganType + type: Vox + clear: true + time: 5 - type: reagent id: Plasma @@ -142,6 +161,9 @@ - !type:OrganType type: Plant shouldHave: false + - !type:OrganType + type: Vox + shouldHave: false # Don't want people to get toxin damage from the gas they just # exhaled, right? - !type:ReagentThreshold @@ -194,7 +216,7 @@ - !type:OrganType type: Vox ratios: - CarbonDioxide: 1.0 + Ammonia: 1.0 Nitrogen: -1.0 - !type:ModifyLungGas conditions: diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index dfe96359e68..12c694e09e4 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -1120,6 +1120,27 @@ conditions: - !type:ReagentThreshold min: 12 + +- type: reagent + id: Opporozidone #Name based of an altered version of the startreck chem "Opporozine" + name: reagent-name-opporozidone + group: Medicine + desc: reagent-desc-opporozidone + physicalDesc: reagent-physical-desc-sickly + flavor: acid + color: "#b5e36d" + worksOnTheDead: true + metabolisms: + Medicine: + effects: + - !type:ReduceRotting + seconds: 20 + conditions: + #Patient must be dead and in a cryo tube (or something cold) + - !type:Temperature + max: 150.0 + - !type:MobStateCondition + mobstate: Dead - type: reagent id: Necrosol @@ -1171,3 +1192,67 @@ Heat: -3.0 Shock: -3.0 Caustic: -1.0 + +- type: reagent + id : Mannitol # currently this is just a way to create psicodine + name: reagent-name-mannitol + group: Medicine + desc: reagent-desc-mannitol + physicalDesc: reagent-physical-desc-opaque + flavor: sweet + color: "#A0A0A0" + metabolisms: + Medicine: + effects: + - !type:PopupMessage + conditions: + - !type:ReagentThreshold + min: 15 + type: Local + visualType: Medium + messages: [ "mannitol-effect-enlightened" ] + probability: 0.2 + +- type: reagent + id: Psicodine + name: reagent-name-psicodine + group: Medicine + desc: reagent-desc-psicodine + physicalDesc: reagent-physical-desc-shiny + flavor: bitter + color: "#07E79E" + metabolisms: + Medicine: + effects: + - !type:HealthChange + conditions: + - !type:ReagentThreshold + min: 30 + damage: + types: + Poison: 2 + - !type:GenericStatusEffect + conditions: + - !type:ReagentThreshold + min: 30 + key: SeeingRainbows + component: SeeingRainbows + type: Add + time: 8 + refresh: false + - !type:GenericStatusEffect + key: Jitter + time: 2.0 + type: Remove + - !type:GenericStatusEffect + key: Drunk + time: 6.0 + type: Remove + - !type:PopupMessage # we dont have sanity/mood so this will have to do + type: Local + visualType: Medium + messages: + - "psicodine-effect-fearless" + - "psicodine-effect-anxieties-wash-away" + - "psicodine-effect-at-peace" + probability: 0.2 diff --git a/Resources/Prototypes/Reagents/narcotics.yml b/Resources/Prototypes/Reagents/narcotics.yml index ca85fd15b34..b6a2597ff34 100644 --- a/Resources/Prototypes/Reagents/narcotics.yml +++ b/Resources/Prototypes/Reagents/narcotics.yml @@ -182,25 +182,6 @@ time: 16 refresh: false -- type: reagent - id: THCOil # deprecated in favor of THC, preserved here for forks - name: reagent-name-thc-oil - group: Narcotics - desc: reagent-desc-thc-oil - physicalDesc: reagent-physical-desc-skunky - flavor: bitter - flavorMinimum: 0.05 - color: "#DAA520" - metabolisms: - Narcotic: - effects: - - !type:GenericStatusEffect - key: SeeingRainbows - component: SeeingRainbows - type: Add - time: 16 - refresh: false - - type: reagent id: Nicotine name: reagent-name-nicotine @@ -417,3 +398,53 @@ conditions: - !type:ReagentThreshold min: 20 + +- type: reagent + id: Happiness + name: reagent-name-happiness + group: Narcotics + desc: reagent-desc-happiness + physicalDesc: reagent-physical-desc-soothing + flavor: paintthinner + color: "#EE35FF" + metabolisms: + Narcotic: + effects: + - !type:Emote + emote: Laugh + showInChat: true + probability: 0.1 + conditions: + - !type:ReagentThreshold + max: 20 + - !type:Emote + emote: Whistle + showInChat: true + probability: 0.1 + conditions: + - !type:ReagentThreshold + max: 20 + - !type:Emote + emote: Crying + showInChat: true + probability: 0.1 + conditions: + - !type:ReagentThreshold + min: 20 + - !type:PopupMessage # we dont have sanity/mood so this will have to do + type: Local + visualType: Medium + messages: + - "psicodine-effect-fearless" + - "psicodine-effect-anxieties-wash-away" + - "psicodine-effect-at-peace" + probability: 0.2 + conditions: + - !type:ReagentThreshold + max: 20 + - !type:GenericStatusEffect + key: SeeingRainbows + component: SeeingRainbows + type: Add + time: 5 + refresh: false diff --git a/Resources/Prototypes/Reagents/toxins.yml b/Resources/Prototypes/Reagents/toxins.yml index 661e1b7dd16..5d29f024ce8 100644 --- a/Resources/Prototypes/Reagents/toxins.yml +++ b/Resources/Prototypes/Reagents/toxins.yml @@ -486,7 +486,6 @@ - !type:OrganType type: Animal shouldHave: false - reagent: Protein type: Local visualType: MediumCaution messages: [ "generic-reagent-effect-sick" ] @@ -647,3 +646,23 @@ - !type:Electrocute probability: 0.8 +- type: reagent + id: Lipolicide + name: reagent-name-lipolicide + group: Toxins + desc: reagent-desc-lipolicide + physicalDesc: reagent-physical-desc-strong-smelling + flavor: mothballs #why does weightloss juice taste like mothballs + color: "#F0FFF0" + metabolisms: + Poison: + effects: + - !type:HealthChange + conditions: + - !type:Hunger + max: 50 + damage: + types: + Poison: 2 + - !type:SatiateHunger + factor: -6 diff --git a/Resources/Prototypes/DeltaV/Recipes/Construction/Graphs/clothing/prescription_huds.yml b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/prescriptionhuds.yml similarity index 100% rename from Resources/Prototypes/DeltaV/Recipes/Construction/Graphs/clothing/prescription_huds.yml rename to Resources/Prototypes/Recipes/Construction/Graphs/clothing/prescriptionhuds.yml diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/clothing/quiver.yml b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/quiver.yml new file mode 100644 index 00000000000..10736a5876f --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/clothing/quiver.yml @@ -0,0 +1,19 @@ +- type: constructionGraph + id: Quiver + start: start + graph: + - node: start + edges: + - to: Quiver + steps: + - material: Cable + amount: 2 + doAfter: 1 + - material: Cloth + amount: 5 + doAfter: 2 + - material: WoodPlank + amount: 1 + doAfter: 2 + - node: Quiver + entity: ClothingBeltQuiver diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/glassbox.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/glassbox.yml new file mode 100644 index 00000000000..081f22ea8dd --- /dev/null +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/glassbox.yml @@ -0,0 +1,160 @@ +- type: constructionGraph + id: GlassBox + start: start + graph: + - node: start + actions: + - !type:DeleteEntity + edges: + - to: boxMissingWires + completed: + - !type:SetAnchor + value: false + steps: + - material: WoodPlank + amount: 10 + doAfter: 5 + + - node: boxMissingWires + entity: GlassBoxFrame + edges: + - to: boxMissingTrigger + conditions: + - !type:EntityAnchored + steps: + - material: Cable + amount: 2 + doAfter: 0.5 + + - to: start + steps: + - tool: Prying + doAfter: 5 + completed: + - !type:SpawnPrototype + prototype: MaterialWoodPlank1 + amount: 10 + + - node: boxMissingTrigger + edges: + - to: boxTriggerUnsecured + conditions: + - !type:EntityAnchored + steps: + - tag: SignalTrigger + name: a Signal Trigger + icon: + sprite: Objects/Devices/signaltrigger.rsi + state: signaltrigger + doAfter: 0.5 + + - to: boxMissingWires + conditions: + - !type:EntityAnchored + steps: + - tool: Cutting + doAfter: 0.25 + completed: + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 2 + + - node: boxTriggerUnsecured + edges: + - to: boxMissingRGlass + conditions: + - !type:EntityAnchored + steps: + - tool: Screwing + doAfter: 0.5 + + - to: boxMissingTrigger + conditions: + - !type:EntityAnchored + steps: + - tool: Prying + doAfter: 0.5 + completed: + - !type:SpawnPrototype + prototype: SignalTrigger + amount: 1 + + - node: boxMissingRGlass + edges: + - to: boxRGlassUnsecured + conditions: + - !type:EntityAnchored + steps: + - material: ReinforcedGlass + amount: 5 + doAfter: 2.5 + + - to: boxTriggerUnsecured + conditions: + - !type:EntityAnchored + steps: + - tool: Screwing + doAfter: 0.5 + + - node: boxRGlassUnsecured + edges: + - to: glassBox + conditions: + - !type:EntityAnchored + steps: + - tool: Screwing + doAfter: 0.5 + + - to: boxMissingRGlass + conditions: + - !type:EntityAnchored + steps: + - tool: Prying + doAfter: 2 + completed: + - !type:SpawnPrototype + prototype: SheetRGlass1 + amount: 5 + + - node: brokenGlassBox + entity: GlassBoxBroken + edges: + - to: boxMissingWires + steps: + - tool: Prying + doAfter: 2 + completed: + - !type:SpawnPrototype + prototype: ShardGlassReinforced + amount: 1 + + - node: glassBox + entity: GlassBoxLaser + edges: + - to: boxMissingWires + steps: + - tool: Screwing + doAfter: 4 + - tool: Pulsing + doAfter: 2 + - tool: Cutting + doAfter: 2 + - tool: Screwing + doAfter: 2 + - tool: Welding + doAfter: 10 + - tool: Anchoring + doAfter: 2 + - tool: Prying + doAfter: 2 + completed: + - !type:EmptyAllContainers + - !type:SpawnPrototype + prototype: CableApcStack1 + amount: 2 + - !type:SpawnPrototype + prototype: SignalTrigger + amount: 1 + - !type:SpawnPrototype + prototype: SheetRGlass1 + amount: 5 diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml b/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml index 776c1491a63..781dd4aa871 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/structures/plastic_flaps.yml @@ -33,16 +33,6 @@ - tool: Welding doAfter: 5 - - to: airtightFlaps - completed: - - !type:SnapToGrid { } - steps: - - material: Plastic - amount: 5 - doAfter: 5 - - tool: Screwing - doAfter: 5 - - node: opaqueFlaps entity: PlasticFlapsOpaque edges: @@ -54,44 +44,3 @@ steps: - tool: Anchoring doAfter: 10 - - - to: airtightopaqueFlaps - completed: - - !type:SnapToGrid { } - steps: - - material: Plastic - amount: 5 - doAfter: 5 - - tool: Screwing - doAfter: 5 - - - node: airtightFlaps - entity: PlasticFlapsAirtightClear - edges: - - to: plasticFlaps - completed: - - !type:SpawnPrototype - prototype: SheetPlastic - amount: 5 - steps: - - tool: Screwing - doAfter: 10 - - - to: airtightopaqueFlaps #test - completed: - - !type:SnapToGrid { } - steps: - - tool: Welding - doAfter: 5 - - - node: airtightopaqueFlaps - entity: PlasticFlapsAirtightOpaque - edges: - - to: opaqueFlaps - completed: - - !type:SpawnPrototype - prototype: SheetPlastic - amount: 5 - steps: - - tool: Screwing - doAfter: 10 diff --git a/Resources/Prototypes/Recipes/Construction/clothing.yml b/Resources/Prototypes/Recipes/Construction/clothing.yml index 54218d28226..ba0c0d6c59b 100644 --- a/Resources/Prototypes/Recipes/Construction/clothing.yml +++ b/Resources/Prototypes/Recipes/Construction/clothing.yml @@ -107,3 +107,14 @@ description: A roll of treated canvas used for wrapping claws or paws. icon: { sprite: Clothing/Shoes/Misc/clothWrap.rsi, state: icon } objectType: Item + +- type: construction + name: quiver + id: ClothingBeltQuiver + graph: Quiver + startNode: start + targetNode: Quiver + category: construction-category-clothing + description: Can hold up to 15 arrows, and fits snug around your waist. + icon: { sprite: Clothing/Belt/quiver.rsi, state: icon } + objectType: Item diff --git a/Resources/Prototypes/Recipes/Construction/storage.yml b/Resources/Prototypes/Recipes/Construction/storage.yml index 41abf881b65..c8edebc5096 100644 --- a/Resources/Prototypes/Recipes/Construction/storage.yml +++ b/Resources/Prototypes/Recipes/Construction/storage.yml @@ -49,3 +49,21 @@ canBuildInImpassable: false conditions: - !type:TileNotBlocked + +# ItemCabinets +- type: construction + id: ShowCase + name: showcase + description: A sturdy showcase for an expensive exhibit. + graph: GlassBox + startNode: start + targetNode: glassBox + category: construction-category-storage + icon: + sprite: Structures/Storage/glassbox.rsi + state: icon + objectType: Structure + placementMode: SnapgridCenter + canBuildInImpassable: false + conditions: + - !type:TileNotBlocked diff --git a/Resources/Prototypes/Recipes/Construction/structures.yml b/Resources/Prototypes/Recipes/Construction/structures.yml index 52b43872561..a80ac9a3ebf 100644 --- a/Resources/Prototypes/Recipes/Construction/structures.yml +++ b/Resources/Prototypes/Recipes/Construction/structures.yml @@ -1588,23 +1588,6 @@ conditions: - !type:TileNotBlocked -- type: construction - name: airtight plastic flaps - id: PlasticFlapsAirtight - graph: PlasticFlapsGraph - startNode: start - targetNode: airtightFlaps - category: construction-category-structures - placementMode: SnapgridCenter - description: An airtight plastic flap to let items through and keep people out. - objectType: Structure - canBuildInImpassable: false - icon: - sprite: Structures/plastic_flaps.rsi - state: plasticflaps - conditions: - - !type:TileNotBlocked - - type: construction name: opaque plastic flaps id: PlasticFlapsOpaque @@ -1622,23 +1605,6 @@ conditions: - !type:TileNotBlocked -- type: construction - name: airtight opaque plastic flaps - id: PlasticFlapsAirtightOpaque - graph: PlasticFlapsGraph - startNode: start - targetNode: airtightopaqueFlaps - category: construction-category-structures - placementMode: SnapgridCenter - description: An opaque, airtight plastic flap to let items through and keep people out. - objectType: Structure - canBuildInImpassable: false - icon: - sprite: Structures/plastic_flaps.rsi - state: plasticflaps - conditions: - - !type:TileNotBlocked - - type: construction name: bananium clown statue id: BananiumClownStatue diff --git a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml index 2f280f6e46d..f3176cc5e7a 100644 --- a/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml +++ b/Resources/Prototypes/Recipes/Cooking/meal_recipes.yml @@ -135,7 +135,7 @@ FoodBreadBun: 1 FoodMeat: 2 FoodCheeseSlice: 2 - FoodChili: 1 + FoodChiliPepper: 1 FoodCabbage: 1 CrayonGreen: 1 Flare: 1 @@ -177,7 +177,7 @@ solids: FoodBreadBun: 1 FoodMeat: 1 - FoodChili: 3 + FoodChiliPepper: 3 - type: microwaveMealRecipe id: RecipeGhostBurger @@ -675,7 +675,7 @@ solids: FoodRiceBoiled: 1 FoodMeatCutlet: 3 - FoodChili: 2 + FoodChiliPepper: 2 - type: microwaveMealRecipe id: RecipeEggRice @@ -894,7 +894,7 @@ solids: FoodBowlBig: 1 FoodBungo: 2 - FoodChili: 1 + FoodChiliPepper: 1 #Pies @@ -965,7 +965,7 @@ time: 15 solids: FoodDoughPie: 1 - FoodChilly: 3 + FoodChillyPepper: 3 FoodPlateTin: 1 - type: microwaveMealRecipe @@ -1063,7 +1063,7 @@ solids: FoodDough: 1 FoodCheeseSlice: 2 - FoodChili: 1 + FoodChiliPepper: 1 FoodMeatFish: 2 - type: microwaveMealRecipe @@ -1513,7 +1513,7 @@ time: 20 solids: FoodBowlBig: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodMeatCutlet: 1 FoodOnionSlice: 1 FoodTomato: 1 @@ -1546,7 +1546,7 @@ time: 30 solids: FoodBowlBig: 1 - FoodChili: 1 + FoodChiliPepper: 1 FoodMeatCutlet: 1 FoodOnionSlice: 1 FoodTomato: 1 @@ -1561,7 +1561,7 @@ #reagents: #blackpepper: 5 solids: - FoodChili: 1 + FoodChiliPepper: 1 FoodCheeseSlice: 2 - type: microwaveMealRecipe @@ -1581,7 +1581,7 @@ result: FoodMealEnchiladas time: 20 solids: - FoodChili: 2 + FoodChiliPepper: 2 FoodMeatCutlet: 1 FoodCorn: 1 @@ -1712,6 +1712,14 @@ solids: LeavesCannabis: 1 +- type: microwaveMealRecipe + id: RecipeDriedCannabisRainbow + name: dried rainbow cannabis leaves recipe + result: LeavesCannabisRainbowDried + time: 10 + solids: + LeavesCannabisRainbow: 1 + - type: microwaveMealRecipe id: RecipeTrashBakedBananaPeel name: baked banana peel recipe @@ -1749,7 +1757,7 @@ result: FoodMeatHawaiianKebab time: 5 solids: - FoodChili: 1 + FoodChiliPepper: 1 FoodMeatCutlet: 1 FoodPineappleSlice: 1 FoodKebabSkewer: 1 @@ -1760,7 +1768,7 @@ result: FoodMeatFiestaKebab time: 5 solids: - FoodChili: 1 + FoodChiliPepper: 1 FoodCorn: 1 FoodMeatCutlet: 1 FoodTomato: 1 diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml index ff3f6d2e2a7..6806aacc241 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/honkbot.yml @@ -6,17 +6,11 @@ edges: - to: bot steps: - - tag: BoxHug - icon: - sprite: Objects/Storage/boxes.rsi - state: box_hug - name: box of hugs - - tag: ClownRubberStamp + - tag: HappyHonk icon: - sprite: Objects/Misc/stamps.rsi - state: stamp-clown - name: clown's rubber stamp - doAfter: 2 + sprite: Objects/Storage/Happyhonk/clown.rsi + state: box + name: happy honk meal - tag: BikeHorn icon: sprite: Objects/Fun/bikehorn.rsi @@ -45,21 +39,15 @@ edges: - to: bot steps: - - tag: HappyHonk + - tag: CluwneHappyHonk icon: - sprite: Objects/Storage/Happyhonk/clown.rsi + sprite: Objects/Storage/Happyhonk/cluwne.rsi state: box - name: happy honk meal - - tag: ClownRubberStamp - icon: - sprite: Objects/Misc/stamps.rsi - state: stamp-clown - name: clown's rubber stamp - doAfter: 2 + name: woeful cluwne meal - tag: CluwneHorn icon: - sprite: Objects/Fun/cluwnehorn.rsi - state: icon + sprite: Objects/Fun/cluwnehorn.rsi + state: icon name: broken bike horn doAfter: 2 - tag: ProximitySensor diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/bots/supplybot.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/supplybot.yml new file mode 100644 index 00000000000..efabb849bbc --- /dev/null +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/bots/supplybot.yml @@ -0,0 +1,23 @@ +- type: constructionGraph + id: SupplyBot + start: start + graph: + - node: start + edges: + - to: bot + steps: + - tag: ProximitySensor + icon: + sprite: Objects/Misc/proximity_sensor.rsi + state: icon + name: proximity sensor + - tag: BorgHead + icon: + sprite: Objects/Specific/Robotics/cyborg_parts.rsi + state: borg_head + name: borg head + doAfter: 1 + - material: Steel + amount: 10 + - node: bot + entity: MobSupplyBot diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/makeshiftstunprod.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/makeshiftstunprod.yml index fa006a938bd..024a7c58763 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/makeshiftstunprod.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/improvised/makeshiftstunprod.yml @@ -8,24 +8,23 @@ steps: - material: MetalRod amount: 1 - - material: Cable - amount: 15 - - tag: DrinkSpaceGlue - name: Drink Space Glue - icon: - sprite: Objects/Consumable/Drinks/glue-tube.rsi - state: icon - tag: PowerCellSmall name: Power Cell Small icon: sprite: Objects/Power/power_cells.rsi state: small - - tag: CapacitorStockPart - name: Capacitor Stock Part + - tag: Handcuffs icon: - sprite: Objects/Misc/stock_parts.rsi - state: capacitor - doAfter: 20 + sprite: Objects/Misc/cablecuffs.rsi + state: cuff + color: red + name: cuffs + - tag: Igniter + name: Igniter + icon: + sprite: Objects/Devices/igniter.rsi + state: icon + doAfter: 15 - node: msstunprod entity: Stunprod diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml index 00900a95efd..419d7bff339 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/smokeables.yml @@ -12,6 +12,21 @@ doAfter: 2 - node: joint entity: Joint + +- type: constructionGraph + id: smokeableJointRainbow + start: start + graph: + - node: start + edges: + - to: jointRainbow + steps: + - material: PaperRolling + - material: CigaretteFilter + - material: GroundCannabisRainbow + doAfter: 2 + - node: jointRainbow + entity: JointRainbow - type: constructionGraph id: smokeableBlunt @@ -27,6 +42,20 @@ - node: blunt entity: Blunt +- type: constructionGraph + id: smokeableBluntRainbow + start: start + graph: + - node: start + edges: + - to: bluntRainbow + steps: + - material: LeavesTobaccoDried + - material: GroundCannabisRainbow + doAfter: 2 + - node: bluntRainbow + entity: BluntRainbow + - type: constructionGraph id: smokeableCigarette start: start @@ -56,6 +85,20 @@ - node: ground entity: GroundCannabis +- type: constructionGraph + id: smokeableGroundCannabisRainbow + start: start + graph: + - node: start + edges: + - to: groundRainbow + steps: + - material: LeavesCannabisRainbowDried + amount: 2 + doAfter: 5 + - node: groundRainbow + entity: GroundCannabisRainbow + - type: constructionGraph id: smokeableGroundTobacco start: start diff --git a/Resources/Prototypes/Recipes/Crafting/Graphs/storage/tallbox.yml b/Resources/Prototypes/Recipes/Crafting/Graphs/storage/tallbox.yml index 7e450513afe..e72c56ff44c 100644 --- a/Resources/Prototypes/Recipes/Crafting/Graphs/storage/tallbox.yml +++ b/Resources/Prototypes/Recipes/Crafting/Graphs/storage/tallbox.yml @@ -19,8 +19,6 @@ conditions: - !type:StorageWelded welded: false - - !type:Locked - locked: false completed: - !type:SpawnPrototype prototype: SheetSteel1 diff --git a/Resources/Prototypes/Recipes/Crafting/bots.yml b/Resources/Prototypes/Recipes/Crafting/bots.yml index 9a70a19c868..3031f4a7803 100644 --- a/Resources/Prototypes/Recipes/Crafting/bots.yml +++ b/Resources/Prototypes/Recipes/Crafting/bots.yml @@ -62,3 +62,16 @@ icon: sprite: Mobs/Silicon/Bots/mimebot.rsi state: mimebot + +- type: construction + name: supplybot + id: supplybot + graph: SupplyBot + startNode: start + targetNode: bot + category: construction-category-utilities + objectType: Item + description: This bot can be loaded with cargo to make deliveries. + icon: + sprite: Mobs/Silicon/Bots/supplybot.rsi + state: supplybot diff --git a/Resources/Prototypes/Recipes/Crafting/smokeables.yml b/Resources/Prototypes/Recipes/Crafting/smokeables.yml index 6d7d4e30bc1..e4280f6d662 100644 --- a/Resources/Prototypes/Recipes/Crafting/smokeables.yml +++ b/Resources/Prototypes/Recipes/Crafting/smokeables.yml @@ -8,6 +8,17 @@ description: "A roll of dried plant matter wrapped in thin paper." icon: { sprite: Objects/Consumable/Smokeables/Cannabis/joint.rsi, state: unlit-icon } objectType: Item + +- type: construction + name: rainbow joint + id: smokeableJointRainbow + graph: smokeableJointRainbow + startNode: start + targetNode: jointRainbow + category: construction-category-misc + description: "A roll of dried plant matter wrapped in thin paper." + icon: { sprite: Objects/Consumable/Smokeables/Cannabis/joint.rsi, state: unlit-icon } + objectType: Item - type: construction name: blunt @@ -20,6 +31,17 @@ icon: { sprite: Objects/Consumable/Smokeables/Cannabis/blunt.rsi, state: unlit-icon } objectType: Item +- type: construction + name: rainbow blunt + id: smokeableBluntRainbow + graph: smokeableBluntRainbow + startNode: start + targetNode: bluntRainbow + category: construction-category-misc + description: "A roll of dried plant matter wrapped in a dried tobacco leaf." + icon: { sprite: Objects/Consumable/Smokeables/Cannabis/blunt.rsi, state: unlit-icon } + objectType: Item + - type: construction name: cigarette id: smokeableCigarette @@ -45,6 +67,17 @@ # color: darkgreen objectType: Item +- type: construction + name: ground rainbow cannabis + id: smokeableGroundCannabisRainbow + graph: smokeableGroundCannabisRainbow + startNode: start + targetNode: groundRainbow + category: construction-category-misc + description: "Ground rainbow cannabis, ready to take you on a trip." + icon: { sprite: Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: powderpile_rainbow } + objectType: Item + - type: construction name: ground tobacco id: smokeableGroundTobacco diff --git a/Resources/Prototypes/Recipes/Lathes/clothing.yml b/Resources/Prototypes/Recipes/Lathes/clothing.yml index 19b2fbb883c..729f20e9795 100644 --- a/Resources/Prototypes/Recipes/Lathes/clothing.yml +++ b/Resources/Prototypes/Recipes/Lathes/clothing.yml @@ -706,8 +706,16 @@ Durathread: 300 - type: latheRecipe - id: ClothingOuterWinterHoS - result: ClothingOuterWinterHoS + id: ClothingOuterWinterHoSUnarmored + result: ClothingOuterWinterHoSUnarmored + completetime: 3.2 + materials: + Cloth: 500 + Durathread: 300 + +- type: latheRecipe + id: ClothingOuterWinterWardenUnarmored + result: ClothingOuterWinterWardenUnarmored completetime: 3.2 materials: Cloth: 500 diff --git a/Resources/Prototypes/Recipes/Lathes/cooking.yml b/Resources/Prototypes/Recipes/Lathes/cooking.yml index a8836ff3926..577d8299dab 100644 --- a/Resources/Prototypes/Recipes/Lathes/cooking.yml +++ b/Resources/Prototypes/Recipes/Lathes/cooking.yml @@ -49,6 +49,13 @@ materials: Glass: 100 +- type: latheRecipe + id: CustomDrinkJug + result: CustomDrinkJug + completetime: 2 + materials: + Plastic: 200 + - type: latheRecipe id: FoodPlate result: FoodPlate diff --git a/Resources/Prototypes/Recipes/Lathes/devices.yml b/Resources/Prototypes/Recipes/Lathes/devices.yml index d41b5fdce87..2b0d6fa44fe 100644 --- a/Resources/Prototypes/Recipes/Lathes/devices.yml +++ b/Resources/Prototypes/Recipes/Lathes/devices.yml @@ -76,7 +76,7 @@ Steel: 100 Plastic: 200 Glass: 100 - + - type: latheRecipe id: SignallerAdvanced result: RemoteSignallerAdvanced @@ -178,15 +178,23 @@ Plasma: 1000 #DeltaV: Bluespace Exists so less plasma used, no uranium Bluespace: 200 #DeltaV: Bluespace Exists -#- type: latheRecipe #DeltaV - LRP -# id: WeaponForceGun -# result: WeaponForceGun -# category: Tools -# completetime: 5 -# materials: -# Steel: 500 -# Glass: 400 -# Silver: 200 +- type: latheRecipe + id: ClothingMaskWeldingGas + result: ClothingMaskWeldingGas + completetime: 3 + materials: + Steel: 600 + Glass: 200 + +- type: latheRecipe + id: WeaponForceGun + result: WeaponForceGun + category: Tools + completetime: 5 + materials: + Steel: 500 + Glass: 400 + Silver: 200 - type: latheRecipe id: DeviceQuantumSpinInverter @@ -207,22 +215,22 @@ Glass: 500 Silver: 100 -#- type: latheRecipe #DeltaV - LRP -# id: WeaponTetherGun -# result: WeaponTetherGun -# category: Tools -# completetime: 5 -# materials: -# Steel: 500 -# Glass: 400 -# Silver: 100 - -#- type: latheRecipe #DeltaV - LRP -# id: WeaponGrapplingGun -# result: WeaponGrapplingGun -# category: Tools -# completetime: 5 -# materials: -# Steel: 500 -# Glass: 400 -# Gold: 100 +- type: latheRecipe + id: WeaponTetherGun + result: WeaponTetherGun + category: Tools + completetime: 5 + materials: + Steel: 500 + Glass: 400 + Silver: 100 + +- type: latheRecipe + id: WeaponGrapplingGun + result: WeaponGrapplingGun + category: Tools + completetime: 5 + materials: + Steel: 500 + Glass: 400 + Gold: 100 diff --git a/Resources/Prototypes/Recipes/Lathes/electronics.yml b/Resources/Prototypes/Recipes/Lathes/electronics.yml index 12b5bedf107..af258ad31b0 100644 --- a/Resources/Prototypes/Recipes/Lathes/electronics.yml +++ b/Resources/Prototypes/Recipes/Lathes/electronics.yml @@ -114,7 +114,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -133,7 +133,7 @@ completetime: 4 materials: Steel: 150 - Glass: 900 + Glass: 500 Gold: 50 - type: latheRecipe @@ -143,7 +143,7 @@ completetime: 4 materials: Steel: 150 - Glass: 900 + Glass: 500 Gold: 50 - type: latheRecipe @@ -153,7 +153,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: PortableScrubberMachineCircuitBoard @@ -162,7 +162,7 @@ completetime: 4 materials: Steel: 150 - Glass: 900 + Glass: 500 Gold: 50 - type: latheRecipe @@ -172,7 +172,7 @@ completetime: 4 materials: Steel: 150 - Glass: 900 + Glass: 500 Gold: 50 - type: latheRecipe @@ -182,7 +182,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: CryoPodMachineCircuitboard @@ -191,7 +191,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -201,7 +201,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ChemDispenserMachineCircuitboard @@ -210,7 +210,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -220,7 +220,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -230,7 +230,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -240,7 +240,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: AutolatheMachineCircuitboard @@ -249,7 +249,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ProtolatheMachineCircuitboard @@ -258,7 +258,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: AutolatheHyperConvectionMachineCircuitboard @@ -267,7 +267,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -277,7 +277,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -286,8 +286,19 @@ category: Circuitry completetime: 4 materials: - Steel: 100 - Glass: 900 + Steel: 100 + Glass: 500 + +- type: latheRecipe + id: CircuitImprinterHyperConvectionMachineCircuitboard + result: CircuitImprinterHyperConvectionMachineCircuitboard + category: Circuitry + completetime: 4 + materials: + Steel: 100 + Glass: 900 + Gold: 100 + - type: latheRecipe id: ExosuitFabricatorMachineCircuitboard @@ -296,7 +307,7 @@ completetime: 5 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: UniformPrinterMachineCircuitboard @@ -305,7 +316,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: VaccinatorMachineCircuitboard @@ -314,7 +325,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -324,7 +335,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -334,17 +345,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 - Gold: 100 - -- type: latheRecipe - id: TraversalDistorterMachineCircuitboard - result: TraversalDistorterMachineCircuitboard - category: Circuitry - completetime: 4 - materials: - Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -354,7 +355,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -364,7 +365,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: AnomalyVesselExperimentalCircuitboard @@ -373,7 +374,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -393,7 +394,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ReagentGrinderMachineCircuitboard @@ -402,7 +403,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: HotplateMachineCircuitboard @@ -411,7 +412,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: AnalysisComputerCircuitboard @@ -420,7 +421,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -430,7 +431,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -440,7 +441,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -450,7 +451,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: DawInstrumentMachineCircuitboard @@ -459,7 +460,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: StasisBedMachineCircuitboard @@ -468,7 +469,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -478,7 +479,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: CentrifugeMachineCircuitboard @@ -487,7 +488,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: MaterialReclaimerMachineCircuitboard @@ -496,7 +497,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: OreProcessorMachineCircuitboard @@ -505,7 +506,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: OreProcessorIndustrialMachineCircuitboard @@ -514,7 +515,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -524,7 +525,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -534,7 +535,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -544,7 +545,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Bananium: 100 - type: latheRecipe @@ -554,7 +555,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Bananium: 100 - type: latheRecipe @@ -564,7 +565,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Bananium: 100 - type: latheRecipe @@ -574,7 +575,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -584,7 +585,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 # Power @@ -622,7 +623,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: PortableGeneratorPacmanMachineCircuitboard @@ -676,7 +677,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SolarTrackerElectronics @@ -694,7 +695,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: CloningConsoleComputerCircuitboard @@ -703,7 +704,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: MicrowaveMachineCircuitboard @@ -712,7 +713,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ElectricGrillMachineCircuitboard @@ -721,7 +722,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: FatExtractorMachineCircuitboard @@ -730,7 +731,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: FlatpackerMachineCircuitboard @@ -739,7 +740,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -749,7 +750,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceCameraRouterCircuitboard @@ -758,7 +759,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceCameraWirelessRouterCircuitboard @@ -767,7 +768,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceWirelessCameraAnchoredCircuitboard @@ -776,7 +777,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceWirelessCameraMovableCircuitboard @@ -785,7 +786,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceCameraMonitorCircuitboard @@ -794,7 +795,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SurveillanceWirelessCameraMonitorCircuitboard @@ -803,7 +804,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ComputerTelevisionCircuitboard @@ -812,7 +813,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: EmitterCircuitboard @@ -821,7 +822,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ThrusterMachineCircuitboard @@ -830,7 +831,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: GyroscopeMachineCircuitboard @@ -839,7 +840,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: GasRecyclerMachineCircuitboard @@ -848,7 +849,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: SeedExtractorMachineCircuitboard @@ -857,7 +858,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: BoozeDispenserMachineCircuitboard @@ -866,7 +867,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: CargoTelepadMachineCircuitboard @@ -875,7 +876,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -885,7 +886,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: TelecomServerCircuitboard @@ -894,7 +895,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: MassMediaCircuitboard @@ -903,7 +904,7 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: MiniGravityGeneratorCircuitboard @@ -912,7 +913,7 @@ completetime: 6 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -921,7 +922,7 @@ completetime: 6 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ShuttleGunSvalinnMachineGunCircuitboard @@ -929,7 +930,8 @@ completetime: 6 materials: Steel: 100 - Glass: 900 + + Glass: 500 - type: latheRecipe id: ShuttleGunPerforatorCircuitboard @@ -937,7 +939,7 @@ completetime: 10 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -946,7 +948,7 @@ completetime: 6 materials: Steel: 100 - Glass: 900 + Glass: 500 - type: latheRecipe id: ShuttleGunFriendshipCircuitboard @@ -954,7 +956,7 @@ completetime: 8 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 50 - type: latheRecipe @@ -963,7 +965,7 @@ completetime: 12 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -972,7 +974,7 @@ completetime: 5 materials: Steel: 100 - Glass: 900 + Glass: 500 Gold: 100 - type: latheRecipe @@ -981,4 +983,4 @@ completetime: 4 materials: Steel: 100 - Glass: 900 + Glass: 500 \ No newline at end of file diff --git a/Resources/Prototypes/Recipes/Lathes/janitorial.yml b/Resources/Prototypes/Recipes/Lathes/janitorial.yml index a3b968a331b..9ba7dfa1889 100644 --- a/Resources/Prototypes/Recipes/Lathes/janitorial.yml +++ b/Resources/Prototypes/Recipes/Lathes/janitorial.yml @@ -18,7 +18,7 @@ result: Bucket completetime: 2 materials: - Steel: 100 + Plastic: 100 - type: latheRecipe id: WetFloorSign diff --git a/Resources/Prototypes/Recipes/Lathes/medical.yml b/Resources/Prototypes/Recipes/Lathes/medical.yml index 631829ed53b..822945de103 100644 --- a/Resources/Prototypes/Recipes/Lathes/medical.yml +++ b/Resources/Prototypes/Recipes/Lathes/medical.yml @@ -116,7 +116,7 @@ result: ClothingMaskSterile completetime: 2 materials: - Plastic: 100 + Plastic: 50 - type: latheRecipe id: DiseaseSwab diff --git a/Resources/Prototypes/Recipes/Lathes/security.yml b/Resources/Prototypes/Recipes/Lathes/security.yml index 08e11e4ff82..04c2ad1ec1f 100644 --- a/Resources/Prototypes/Recipes/Lathes/security.yml +++ b/Resources/Prototypes/Recipes/Lathes/security.yml @@ -38,7 +38,7 @@ materials: Steel: 250 Plastic: 100 - + - type: latheRecipe id: WeaponLaserCarbine result: WeaponLaserCarbine @@ -146,15 +146,6 @@ Plastic: 200 Steel: 100 -- type: latheRecipe - id: ShellShotgunBeanbag - result: ShellShotgunBeanbag - category: Ammo - completetime: 2 - materials: - Plastic: 15 - Steel: 10 - - type: latheRecipe id: CartridgePistolRubber result: CartridgePistolRubber @@ -173,14 +164,6 @@ Plastic: 5 Steel: 5 -- type: latheRecipe - id: CartridgeRifle - result: CartridgeRifle - category: Ammo - completetime: 2 - materials: - Steel: 15 - - type: latheRecipe id: CartridgeLightRifleRubber result: CartridgeLightRifleRubber @@ -199,54 +182,6 @@ Plastic: 10 Steel: 5 -- type: latheRecipe - id: CartridgePistol - result: CartridgePistol - category: Ammo - completetime: 2 - materials: - Steel: 10 - -- type: latheRecipe - id: ShellShotgun - result: ShellShotgun - category: Ammo - completetime: 2 - materials: - Steel: 20 - -- type: latheRecipe - id: ShellShotgunSlug - result: ShellShotgunSlug - completetime: 2 - materials: - Steel: 25 - -- type: latheRecipe - id: CartridgeMagnum - result: CartridgeMagnum - category: Ammo - completetime: 2 - materials: - Steel: 20 - -- type: latheRecipe - id: CartridgeLightRifle - result: CartridgeLightRifle - category: Ammo - completetime: 2 - materials: - Steel: 30 - -- type: latheRecipe - id: ShellShotgunFlare - result: ShellShotgunFlare - category: Ammo - completetime: 2 - materials: - Plastic: 20 - Steel: 5 - - type: latheRecipe id: ShellTranquilizer result: ShellTranquilizer @@ -283,13 +218,56 @@ materials: Steel: 500 +- type: latheRecipe + id: MagazinePistolEmpty + result: MagazinePistolEmpty + category: Ammo + completetime: 5 + materials: + Steel: 25 + - type: latheRecipe id: MagazinePistol result: MagazinePistol category: Ammo completetime: 5 materials: - Steel: 100 + Steel: 145 + +- type: latheRecipe + id: MagazinePistolPractice + result: MagazinePistolPractice + category: Ammo + completetime: 5 + materials: + Steel: 85 + +- type: latheRecipe + id: MagazinePistolUranium + result: MagazinePistolUranium + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 65 + Uranium: 120 + +- type: latheRecipe + id: MagazinePistolIncendiary + result: MagazinePistolIncendiary + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 120 + +- type: latheRecipe + id: MagazinePistolSubMachineGunEmpty + result: MagazinePistolSubMachineGunEmpty + category: Ammo + completetime: 5 + materials: + Steel: 30 - type: latheRecipe id: MagazinePistolSubMachineGun @@ -299,6 +277,14 @@ materials: Steel: 300 +- type: latheRecipe + id: MagazinePistolSubMachineGunTopMountedEmpty + result: MagazinePistolSubMachineGunTopMountedEmpty + category: Ammo + completetime: 5 + materials: + Steel: 30 + - type: latheRecipe id: MagazinePistolSubMachineGunTopMounted result: MagazinePistolSubMachineGunTopMounted @@ -313,7 +299,7 @@ category: Ammo completetime: 5 materials: - Steel: 650 + Steel: 600 - type: latheRecipe id: MagazineBoxPistolRubber @@ -330,7 +316,15 @@ category: Ammo completetime: 5 materials: - Steel: 1250 + Steel: 240 + +- type: latheRecipe + id: MagazineRifleEmpty + result: MagazineRifleEmpty + category: Ammo + completetime: 5 + materials: + Steel: 25 - type: latheRecipe id: MagazineBoxMagnumRubber @@ -347,7 +341,43 @@ category: Ammo completetime: 5 materials: - Steel: 375 + Steel: 475 + + +- type: latheRecipe + id: MagazineRiflePractice + result: MagazineRiflePractice + category: Ammo + completetime: 5 + materials: + Steel: 175 + +- type: latheRecipe + id: MagazineRifleUranium + result: MagazineRifleUranium + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 300 + Uranium: 300 + +- type: latheRecipe + id: MagazineRifleIncendiary + result: MagazineRifleIncendiary + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 450 + +- type: latheRecipe + id: MagazineLightRifleEmpty + result: MagazineLightRifleEmpty + category: Ammo + completetime: 5 + materials: + Steel: 25 - type: latheRecipe id: MagazineLightRifle @@ -355,7 +385,35 @@ category: Ammo completetime: 5 materials: - Steel: 375 + Steel: 565 + +- type: latheRecipe + id: MagazineLightRiflePractice + result: MagazineLightRiflePractice + category: Ammo + completetime: 5 + materials: + Steel: 205 + + +- type: latheRecipe + id: MagazineLightRifleUranium + result: MagazineLightRifleUranium + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 360 + Uranium: 360 + +- type: latheRecipe + id: MagazineLightRifleIncendiary + result: MagazineLightRifleIncendiary + category: Ammo + completetime: 5 + materials: + Steel: 25 + Plastic: 540 - type: latheRecipe id: MagazineBoxRifle @@ -363,7 +421,7 @@ category: Ammo completetime: 5 materials: - Steel: 950 + Steel: 750 - type: latheRecipe id: MagazineBoxRifleRubber @@ -380,7 +438,41 @@ category: Ammo completetime: 5 materials: - Steel: 1800 + Steel: 900 + +- type: latheRecipe + id: BoxLethalshot + result: BoxLethalshot + category: Ammo + completetime: 5 + materials: + Steel: 320 + +- type: latheRecipe + id: BoxBeanbag + result: BoxBeanbag + category: Ammo + completetime: 5 + materials: + Steel: 160 + Plastic: 240 + +- type: latheRecipe + id: BoxShotgunSlug + result: BoxShotgunSlug + category: Ammo + completetime: 5 + materials: + Steel: 240 + Plastic: 160 + +- type: latheRecipe + id: SpeedLoaderMagnumEmpty + result: SpeedLoaderMagnumEmpty + category: Ammo + completetime: 5 + materials: + Steel: 50 - type: latheRecipe id: MagazineBoxLightRifleRubber @@ -397,47 +489,77 @@ category: Ammo completetime: 5 materials: - Steel: 200 + Steel: 190 - type: latheRecipe - id: ShellShotgunIncendiary - result: ShellShotgunIncendiary + id: SpeedLoaderMagnumPractice + result: SpeedLoaderMagnumPractice category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 20 + Steel: 90 - type: latheRecipe - id: CartridgePistolIncendiary - result: CartridgePistolIncendiary + id: SpeedLoaderMagnumUranium + result: SpeedLoaderMagnumUranium category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 10 + Steel: 50 + Plastic: 150 + Uranium: 110 - type: latheRecipe - id: CartridgeMagnumIncendiary - result: CartridgeMagnumIncendiary + id: SpeedLoaderMagnumIncendiary + result: SpeedLoaderMagnumIncendiary category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 20 + Steel: 50 + Plastic: 150 - type: latheRecipe - id: CartridgeLightRifleIncendiary - result: CartridgeLightRifleIncendiary + id: MagazineShotgunEmpty + result: MagazineShotgunEmpty category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 20 + Steel: 50 - type: latheRecipe - id: CartridgeRifleIncendiary - result: CartridgeRifleIncendiary + id: MagazineShotgun + result: MagazineShotgun category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 15 + Steel: 240 + +- type: latheRecipe + id: MagazineShotgunBeanbag + result: MagazineShotgunBeanbag + category: Ammo + completetime: 5 + materials: + Steel: 150 + Plastic: 140 + +- type: latheRecipe + id: MagazineShotgunSlug + result: MagazineShotgunSlug + category: Ammo + completetime: 5 + materials: + Steel: 190 + Plastic: 100 + +- type: latheRecipe + id: MagazineShotgunIncendiary + result: MagazineShotgunIncendiary + category: Ammo + completetime: 5 + materials: + Steel: 100 + Plastic: 190 - type: latheRecipe id: MagazineBoxPistolIncendiary @@ -445,7 +567,7 @@ category: Ammo completetime: 5 materials: - Plastic: 650 + Plastic: 600 - type: latheRecipe id: MagazineBoxMagnumIncendiary @@ -453,7 +575,7 @@ category: Ammo completetime: 5 materials: - Plastic: 1250 + Plastic: 240 - type: latheRecipe id: MagazineBoxLightRifleIncendiary @@ -461,7 +583,7 @@ category: Ammo completetime: 5 materials: - Plastic: 1800 + Plastic: 900 - type: latheRecipe id: MagazineBoxRifleIncendiary @@ -469,15 +591,25 @@ category: Ammo completetime: 5 materials: - Plastic: 950 + Plastic: 750 - type: latheRecipe - id: ShellShotgunPractice - result: ShellShotgunPractice + id: BoxShotgunFlare + result: BoxShotgunFlare category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 20 + Steel: 80 + Plastic: 80 + +- type: latheRecipe + id: BoxShotgunIncendiary + result: BoxShotgunIncendiary + category: Ammo + completetime: 5 + materials: + Steel: 80 + Plastic: 320 - type: latheRecipe id: MagazineBoxPistolPractice @@ -485,7 +617,7 @@ category: Ammo completetime: 5 materials: - Plastic: 600 + Steel: 300 - type: latheRecipe id: MagazineBoxMagnumPractice @@ -493,7 +625,7 @@ category: Ammo completetime: 5 materials: - Plastic: 1200 + Steel: 60 - type: latheRecipe id: MagazineBoxLightRiflePractice @@ -501,7 +633,7 @@ category: Ammo completetime: 5 materials: - Plastic: 1000 + Steel: 300 - type: latheRecipe id: MagazineBoxRiflePractice @@ -509,7 +641,7 @@ category: Ammo completetime: 5 materials: - Plastic: 900 + Steel: 250 - type: latheRecipe id: WeaponLaserCarbinePractice @@ -532,49 +664,12 @@ Plastic: 200 - type: latheRecipe - id: ShellShotgunUranium - result: ShellShotgunUranium - category: Ammo - completetime: 2 - materials: - Plastic: 15 - Uranium: 10 - -- type: latheRecipe - id: CartridgePistolUranium - result: CartridgePistolUranium - category: Ammo - completetime: 2 - materials: - Plastic: 5 - Uranium: 10 - -- type: latheRecipe - id: CartridgeMagnumUranium - result: CartridgeMagnumUranium - category: Ammo - completetime: 2 - materials: - Plastic: 20 - Uranium: 10 - -- type: latheRecipe - id: CartridgeLightRifleUranium - result: CartridgeLightRifleUranium - category: Ammo - completetime: 2 - materials: - Plastic: 20 - Uranium: 10 - -- type: latheRecipe - id: CartridgeRifleUranium - result: CartridgeRifleUranium + id: BoxShotgunPractice + result: BoxShotgunPractice category: Ammo - completetime: 2 + completetime: 5 materials: - Plastic: 15 - Uranium: 10 + Steel: 80 - type: latheRecipe id: MagazineBoxPistolUranium @@ -582,8 +677,8 @@ category: Ammo completetime: 5 materials: - Plastic: 650 - Uranium: 65 + Plastic: 300 + Uranium: 600 - type: latheRecipe id: MagazineBoxMagnumUranium @@ -591,8 +686,8 @@ category: Ammo completetime: 5 materials: - Plastic: 1250 - Uranium: 125 + Plastic: 240 + Uranium: 180 - type: latheRecipe id: MagazineBoxLightRifleUranium @@ -600,8 +695,8 @@ category: Ammo completetime: 5 materials: - Plastic: 1800 - Uranium: 180 + Plastic: 600 + Uranium: 600 - type: latheRecipe id: MagazineBoxRifleUranium @@ -609,8 +704,27 @@ category: Ammo completetime: 5 materials: - Plastic: 950 - Uranium: 95 + Plastic: 500 + Uranium: 500 + +- type: latheRecipe + id: BoxShotgunUranium + result: BoxShotgunUranium + category: Ammo + completetime: 5 + materials: + Plastic: 320 + Uranium: 240 + +- type: latheRecipe + id: WeaponDisabler + result: WeaponDisabler + category: Weapons + completetime: 6 + materials: + Steel: 300 + Glass: 200 + Plastic: 200 - type: latheRecipe id: WeaponDisablerSMG @@ -621,7 +735,7 @@ Steel: 1000 Glass: 500 Plastic: 500 - + - type: latheRecipe id: MagazineGrenadeEmpty result: MagazineGrenadeEmpty @@ -629,7 +743,7 @@ materials: Steel: 150 Plastic: 50 - + - type: latheRecipe id: GrenadeEMP result: GrenadeEMP @@ -638,16 +752,15 @@ Steel: 150 Plastic: 100 Glass: 20 - + - type: latheRecipe id: GrenadeBlast result: GrenadeBlast completetime: 3 materials: - Steel: 150 - Plastic: 100 - Gold: 50 - + Steel: 450 + Plastic: 300 + Gold: 150 - type: latheRecipe id: GrenadeFlash result: GrenadeFlash @@ -656,4 +769,106 @@ Steel: 150 Plastic: 100 Glass: 20 - \ No newline at end of file + +- type: latheRecipe + id: PortableRecharger + result: PortableRecharger + completetime: 15 + materials: + Steel: 2000 + Uranium: 2000 + Plastic: 1000 + Plasma: 500 + Glass: 500 + +- type: latheRecipe + id: ShellShotgun + result: ShellShotgun + category: Ammo + completetime: 2 + materials: + Steel: 20 + +- type: latheRecipe + id: ShellShotgunSlug + result: ShellShotgunSlug + completetime: 2 + materials: + Steel: 25 + +- type: latheRecipe + id: ShellShotgunFlare + result: ShellShotgunFlare + category: Ammo + completetime: 2 + materials: + Plastic: 20 + Steel: 5 + +- type: latheRecipe + id: CartridgeLightRifleIncendiary + result: CartridgeLightRifleIncendiary + category: Ammo + completetime: 2 + materials: + Plastic: 20 + +- type: latheRecipe + id: CartridgeMagnumIncendiary + result: CartridgeMagnumIncendiary + category: Ammo + completetime: 2 + materials: + Plastic: 20 + +- type: latheRecipe + id: CartridgePistolIncendiary + result: CartridgePistolIncendiary + category: Ammo + completetime: 2 + materials: + Plastic: 10 + +- type: latheRecipe + id: CartridgeRifleIncendiary + result: CartridgeRifleIncendiary + category: Ammo + completetime: 2 + materials: + Plastic: 15 + +- type: latheRecipe + id: CartridgePistolUranium + result: CartridgePistolUranium + category: Ammo + completetime: 2 + materials: + Plastic: 5 + Uranium: 10 + +- type: latheRecipe + id: CartridgeMagnumUranium + result: CartridgeMagnumUranium + category: Ammo + completetime: 2 + materials: + Plastic: 20 + Uranium: 10 + +- type: latheRecipe + id: CartridgeLightRifleUranium + result: CartridgeLightRifleUranium + category: Ammo + completetime: 2 + materials: + Plastic: 20 + Uranium: 10 + +- type: latheRecipe + id: CartridgeRifleUranium + result: CartridgeRifleUranium + category: Ammo + completetime: 2 + materials: + Plastic: 15 + Uranium: 10 diff --git a/Resources/Prototypes/Recipes/Reactions/drinks.yml b/Resources/Prototypes/Recipes/Reactions/drinks.yml index 812cded972f..afb315c09d9 100644 --- a/Resources/Prototypes/Recipes/Reactions/drinks.yml +++ b/Resources/Prototypes/Recipes/Reactions/drinks.yml @@ -86,6 +86,16 @@ products: B52: 3 +- type: reaction + id: BudgetInsulsDrink + reactants: + Tequila: + amount: 1 + VodkaRedBool: + amount: 2 + products: + BudgetInsulsDrink: 3 + - type: reaction id: BlueHawaiian reactants: @@ -516,6 +526,16 @@ products: IcedTea: 3 +- type: reaction + id: IrishBool + reactants: + EnergyDrink: + amount: 1 + IrishCarBomb: + amount: 1 + products: + IrishBool: 2 + - type: reaction id: IrishCarBomb reactants: @@ -794,6 +814,18 @@ products: RoyRogers: 3 +- type: reaction + id: Rubberneck + reactants: + EnergyDrink: + amount: 2 + Moonshine: + amount: 1 + Sugar: + amount: 1 + products: + Rubberneck: 4 + - type: reaction id: Sbiten reactants: @@ -943,6 +975,16 @@ products: VodkaMartini: 3 +- type: reaction + id: VodkaRedBool + reactants: + Vodka: + amount: 1 + EnergyDrink: + amount: 2 + products: + VodkaRedBool: 3 + - type: reaction id: VodkaTonic reactants: @@ -963,6 +1005,18 @@ products: WhiskeyCola: 3 +- type: reaction + id: WatermelonWakeup + reactants: + JuiceWatermelon: + amount: 1 + Whiskey: + amount: 1 + EnergyDrink: + amount: 1 + products: + WatermelonWakeup: 3 + - type: reaction id: WhiteRussian reactants: @@ -983,6 +1037,16 @@ products: WhiskeySoda: 3 +- type: reaction + id: XenoBasher + reactants: + ManlyDorf: + amount: 2 + EnergyDrink: + amount: 1 + products: + XenoBasher: 3 + - type: reaction id: HotRamen minTemp: 323.15 diff --git a/Resources/Prototypes/Recipes/Reactions/medicine.yml b/Resources/Prototypes/Recipes/Reactions/medicine.yml index a1ca3ea38e2..2e9b1d4f854 100644 --- a/Resources/Prototypes/Recipes/Reactions/medicine.yml +++ b/Resources/Prototypes/Recipes/Reactions/medicine.yml @@ -298,6 +298,18 @@ products: Lipozine: 3 +- type: reaction + id: Mannitol + reactants: + Hydrogen: + amount: 1 + Water: + amount: 1 + Sugar: + amount: 1 + products: + Mannitol: 3 + - type: reaction id: MindbreakerToxin minTemp: 370 @@ -542,11 +554,21 @@ amount: 1 Silicon: amount: 1 - Benzene: - amount: 1 products: Insuzine: 3 - Ash: 1 + +- type: reaction + id: Opporozidone + minTemp: 400 #Maybe if a method of reducing reagent temp exists one day, this could be -50 + reactants: + Cognizine: + amount: 1 + Plasma: + amount: 2 + Doxarubixadone: + amount: 1 + products: + Opporozidone: 3 - type: reaction id: Necrosol @@ -574,3 +596,43 @@ amount: 2 products: Aloxadone: 4 + +- type: reaction + id: Psicodine + impact: Medium + reactants: + Mannitol: + amount: 2 + Impedrezene: + amount: 1 + Water: + amount: 2 + products: + Psicodine: 4 + +- type: reaction + id: Lipolicide + reactants: + Ephedrine: + amount: 1 + Diethylamine: + amount: 1 + Mercury: + amount: 1 + products: + Lipolicide: 3 + +- type: reaction + id: Happiness + reactants: + Laughter: + amount: 2 + Epinephrine: + amount: 1 + Ethanol: + amount: 1 + Plasma: + amount: 5 + catalyst: true + products: + Happiness: 4 diff --git a/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml b/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml index 318490931f8..3591ce70086 100644 --- a/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml +++ b/Resources/Prototypes/Recipes/Reactions/pyrotechnic.yml @@ -31,6 +31,7 @@ - type: reaction id: ChlorineTrifluoride + minTemp: 370 priority: 20 reactants: Chlorine: @@ -38,7 +39,6 @@ Fluorine: amount: 3 effects: - # TODO solution temperature!! - !type:ExplosionReactionEffect explosionType: Default # 15 damage per intensity. maxIntensity: 200 diff --git a/Resources/Prototypes/Research/arsenal.yml b/Resources/Prototypes/Research/arsenal.yml index 7432d4225f2..b519d0b3514 100644 --- a/Resources/Prototypes/Research/arsenal.yml +++ b/Resources/Prototypes/Research/arsenal.yml @@ -24,11 +24,12 @@ tier: 1 cost: 10000 recipeUnlocks: - - ShellShotgunIncendiary - - CartridgePistolIncendiary - - CartridgeMagnumIncendiary - - CartridgeLightRifleIncendiary - - CartridgeRifleIncendiary + - BoxShotgunIncendiary + - MagazineRifleIncendiary + - MagazinePistolIncendiary + - MagazineLightRifleIncendiary + - SpeedLoaderMagnumIncendiary + - MagazineShotgunIncendiary - MagazineBoxPistolIncendiary - MagazineBoxMagnumIncendiary - MagazineBoxLightRifleIncendiary @@ -60,7 +61,9 @@ tier: 1 cost: 5000 recipeUnlocks: - - ShellShotgunBeanbag + - MagazineShotgunBeanbag + - ShellTranquilizer + - BoxBeanbag - CartridgePistolRubber - CartridgeMagnumRubber - CartridgeLightRifleRubber @@ -69,10 +72,9 @@ - MagazineBoxMagnumRubber - MagazineBoxLightRifleRubber - MagazineBoxRifleRubber - # DeltaV - .38 special rubber ammo - Adds .38 special rubber ammo to the research tree - CartridgeSpecialRubber - MagazineBoxSpecialRubber - # End of modified code + - WeaponDisabler - type: technology id: UraniumMunitions @@ -84,19 +86,17 @@ tier: 1 cost: 7500 recipeUnlocks: - - ShellShotgunUranium - - CartridgePistolUranium - - CartridgeMagnumUranium - - CartridgeLightRifleUranium - - CartridgeRifleUranium + - MagazineRifleUranium + - MagazinePistolUranium + - MagazineLightRifleUranium + - SpeedLoaderMagnumUranium - MagazineBoxPistolUranium - MagazineBoxMagnumUranium - MagazineBoxLightRifleUranium - MagazineBoxRifleUranium - # DeltaV - .38 special uranium ammo - Adds .38 special uranium ammo to the research tree + - BoxShotgunUranium - CartridgeSpecialUranium - MagazineBoxSpecialUranium - # End of modified code - type: technology id: AdvancedRiotControl @@ -173,6 +173,7 @@ - PowerCageMedium - MagazineGrenadeEmpty - GrenadeFlash + - GrenadeBlast - ShuttleGunSvalinnMachineGunCircuitboard - ShuttleGunPerforatorCircuitboard - ShuttleGunFriendshipCircuitboard @@ -192,6 +193,7 @@ cost: 15000 recipeUnlocks: - WeaponAdvancedLaser + - PortableRecharger - type: technology id: ExperimentalBatteryAmmo diff --git a/Resources/Prototypes/Research/civilianservices.yml b/Resources/Prototypes/Research/civilianservices.yml index 0a9f74b86d6..26b519e1efa 100644 --- a/Resources/Prototypes/Research/civilianservices.yml +++ b/Resources/Prototypes/Research/civilianservices.yml @@ -191,8 +191,6 @@ - WeaponSprayNozzle - ClothingBackpackWaterTank -# Tier 3 - - type: technology id: BluespaceCargoTransport name: research-technology-bluespace-cargo-transport @@ -200,11 +198,13 @@ sprite: Structures/cargo_telepad.rsi state: display discipline: CivilianServices - tier: 3 + tier: 2 cost: 15000 recipeUnlocks: - CargoTelepadMachineCircuitboard +# Tier 3 + - type: technology id: QuantumFiberWeaving name: research-technology-quantum-fiber-weaving diff --git a/Resources/Prototypes/Research/experimental.yml b/Resources/Prototypes/Research/experimental.yml index 85523033f86..ab353489d63 100644 --- a/Resources/Prototypes/Research/experimental.yml +++ b/Resources/Prototypes/Research/experimental.yml @@ -102,13 +102,12 @@ id: AbnormalArtifactManipulation name: research-technology-abnormal-artifact-manipulation icon: - sprite: Structures/Machines/traversal_distorter.rsi - state: display + sprite: Structures/Machines/artifact_crusher.rsi + state: icon discipline: Experimental tier: 2 cost: 5000 recipeUnlocks: - - TraversalDistorterMachineCircuitboard - ArtifactCrusherMachineCircuitboard - type: technology diff --git a/Resources/Prototypes/Research/industrial.yml b/Resources/Prototypes/Research/industrial.yml index 33377f52520..748e9f32445 100644 --- a/Resources/Prototypes/Research/industrial.yml +++ b/Resources/Prototypes/Research/industrial.yml @@ -14,7 +14,8 @@ - BorgModuleMining - OreProcessorIndustrialMachineCircuitboard - OreBagOfHolding - - SalvageExpeditionsComputerCircuitboard # DeltaV + - ClothingMaskWeldingGas + - SalvageExpeditionsComputerCircuitboard - type: technology id: AdvancedPowercells @@ -53,6 +54,7 @@ recipeUnlocks: - AutolatheHyperConvectionMachineCircuitboard - ProtolatheHyperConvectionMachineCircuitboard + - CircuitImprinterHyperConvectionMachineCircuitboard - SheetifierMachineCircuitboard - type: technology diff --git a/Resources/Prototypes/Roles/Antags/nukeops.yml b/Resources/Prototypes/Roles/Antags/nukeops.yml index b02ebe67539..7b2d9893b60 100644 --- a/Resources/Prototypes/Roles/Antags/nukeops.yml +++ b/Resources/Prototypes/Roles/Antags/nukeops.yml @@ -19,10 +19,10 @@ objective: roles-antag-nuclear-operative-agent-objective requirements: - !type:CharacterOverallTimeRequirement - min: 108000 # DeltaV - 30 hours - - !type:CharacterDepartmentTimeRequirement # DeltaV - Medical dept time requirement + min: 108000 # 30 hours + - !type:CharacterDepartmentTimeRequirement department: Medical - min: 36000 # DeltaV - 10 hours + min: 36000 # 10 hours - type: antag id: NukeopsCommander diff --git a/Resources/Prototypes/Roles/Antags/terminator.yml b/Resources/Prototypes/Roles/Antags/terminator.yml deleted file mode 100644 index ef1f176b8de..00000000000 --- a/Resources/Prototypes/Roles/Antags/terminator.yml +++ /dev/null @@ -1,6 +0,0 @@ -- type: antag - id: Terminator - name: roles-antag-terminator-name - antagonist: true - setPreference: false - objective: roles-antag-terminator-objective diff --git a/Resources/Prototypes/Roles/Ghostroles/syndicate.yml b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml new file mode 100644 index 00000000000..24c0d8b3e3b --- /dev/null +++ b/Resources/Prototypes/Roles/Ghostroles/syndicate.yml @@ -0,0 +1,27 @@ +- type: ghostRole + id: SyndicateKobold + name: ghost-role-information-syndicate-kobold-reinforcement-name + description: ghost-role-information-syndicate-kobold-reinforcement-description + rules: ghost-role-information-syndicate-kobold-reinforcement-rules + entityPrototype: MobKoboldSyndicateAgent + +- type: ghostRole + id: SyndicateKoboldNukeops + name: ghost-role-information-syndicate-kobold-reinforcement-name + description: ghost-role-information-syndicate-kobold-reinforcement-description + rules: ghost-role-information-syndicate-kobold-reinforcement-rules + entityPrototype: MobKoboldSyndicateAgentNukeops + +- type: ghostRole + id: SyndicateMonkey + name: ghost-role-information-syndicate-monkey-reinforcement-name + description: ghost-role-information-syndicate-monkey-reinforcement-description + rules: ghost-role-information-syndicate-monkey-reinforcement-name + entityPrototype: MobMonkeySyndicateAgent + +- type: ghostRole + id: SyndicateMonkeyNukeops + name: ghost-role-information-syndicate-monkey-reinforcement-name + description: ghost-role-information-syndicate-monkey-reinforcement-description + rules: ghost-role-information-syndicate-monkey-reinforcement-name + entityPrototype: MobMonkeySyndicateAgentNukeops \ No newline at end of file diff --git a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml index b2bcd8bcb49..7dd3e6823ae 100644 --- a/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml +++ b/Resources/Prototypes/Roles/Jobs/Fun/misc_startinggear.yml @@ -79,6 +79,15 @@ satchel: ClothingBackpackDuffelSyndicateOperative duffelbag: ClothingBackpackDuffelSyndicateOperative +# Syndicate Operative Outfit - Civilian +- type: startingGear + id: SyndicateOperativeGearCivilian + equipment: + jumpsuit: ClothingUniformJumpsuitSyndieFormal + back: ClothingBackpackDuffelSyndicate + shoes: ClothingShoesBootsCombat + gloves: ClothingHandsGlovesColorBlack + #Syndicate Operative Outfit - Basic - type: startingGear id: SyndicateOperativeGearBasic @@ -144,7 +153,7 @@ jumpsuit: ClothingUniformJumpsuitOperative back: ClothingBackpackDuffelSyndicateOperativeMedic mask: ClothingMaskGasSyndicate - eyes: ClothingEyesHudSyndicateMed # - Delta-V + eyes: ClothingEyesHudSyndicateAgent ears: ClothingHeadsetAltSyndicate gloves: ClothingHandsGlovesCombat outerClothing: ClothingOuterHardsuitSyndieMedic diff --git a/Resources/Prototypes/Shaders/displacement.yml b/Resources/Prototypes/Shaders/displacement.yml new file mode 100644 index 00000000000..5c907380083 --- /dev/null +++ b/Resources/Prototypes/Shaders/displacement.yml @@ -0,0 +1,10 @@ +- type: shader + id: DisplacedStencilDraw + kind: source + path: "/Textures/Shaders/displacement.swsl" + stencil: + ref: 1 + op: Keep + func: NotEqual + params: + displacementSize: 127 diff --git a/Resources/Prototypes/Shuttles/shuttle_incoming_event.yml b/Resources/Prototypes/Shuttles/shuttle_incoming_event.yml new file mode 100644 index 00000000000..5819a934bf2 --- /dev/null +++ b/Resources/Prototypes/Shuttles/shuttle_incoming_event.yml @@ -0,0 +1,29 @@ +- type: preloadedGrid + id: ShuttleStriker + path: /Maps/Shuttles/ShuttleEvent/striker.yml + copies: 2 + +- type: preloadedGrid + id: ShuttleCargoLost + path: /Maps/Shuttles/ShuttleEvent/lost_cargo.yml + copies: 2 + +- type: preloadedGrid + id: TravelingCuisine + path: /Maps/Shuttles/ShuttleEvent/traveling_china_cuisine.yml + copies: 2 + +- type: preloadedGrid + id: DisasterEvacPod + path: /Maps/Shuttles/ShuttleEvent/disaster_evacpod.yml + copies: 3 + +- type: preloadedGrid + id: Honki + path: /Maps/Shuttles/ShuttleEvent/honki.yml + copies: 1 + +- type: preloadedGrid + id: SyndieEvacPod + path: /Maps/Shuttles/ShuttleEvent/syndie_evacpod.yml + copies: 2 diff --git a/Resources/Prototypes/SimpleStation14/Traits/disabilities.yml b/Resources/Prototypes/SimpleStation14/Traits/disabilities.yml deleted file mode 100644 index b7aa00353c8..00000000000 --- a/Resources/Prototypes/SimpleStation14/Traits/disabilities.yml +++ /dev/null @@ -1,12 +0,0 @@ -- type: trait - id: Nearsighted - category: Visual - points: 1 - requirements: - - !type:CharacterJobRequirement - inverted: true - jobs: - - Borg - - MedicalBorg - components: - - type: Nearsighted diff --git a/Resources/Prototypes/SimpleStation14/tags.yml b/Resources/Prototypes/SimpleStation14/tags.yml deleted file mode 100644 index 3b885a58016..00000000000 --- a/Resources/Prototypes/SimpleStation14/tags.yml +++ /dev/null @@ -1,2 +0,0 @@ -- type: Tag - id: GlassesNearsight diff --git a/Resources/Prototypes/SoundCollections/expeditions.yml b/Resources/Prototypes/SoundCollections/expeditions.yml new file mode 100644 index 00000000000..526a16f3c2c --- /dev/null +++ b/Resources/Prototypes/SoundCollections/expeditions.yml @@ -0,0 +1,5 @@ +- type: soundCollection + id: ExpeditionEnd + files: + - /Audio/Expedition/tension_session.ogg + - /Audio/Expedition/deadline.ogg diff --git a/Resources/Prototypes/SoundCollections/footsteps.yml b/Resources/Prototypes/SoundCollections/footsteps.yml index bd51e6b4458..e179584f6fb 100644 --- a/Resources/Prototypes/SoundCollections/footsteps.yml +++ b/Resources/Prototypes/SoundCollections/footsteps.yml @@ -201,3 +201,13 @@ - /Audio/Effects/Footsteps/spurs1.ogg - /Audio/Effects/Footsteps/spurs2.ogg - /Audio/Effects/Footsteps/spurs3.ogg + +- type: soundCollection + id: FootstepBorg + files: + - /Audio/Effects/Footsteps/borgwalk1.ogg + +- type: soundCollection + id: FootstepHoverBorg + files: + - /Audio/Effects/Footsteps/borgwalk2.ogg diff --git a/Resources/Prototypes/SoundCollections/fox.yml b/Resources/Prototypes/SoundCollections/fox.yml new file mode 100644 index 00000000000..912ae24e9a4 --- /dev/null +++ b/Resources/Prototypes/SoundCollections/fox.yml @@ -0,0 +1,18 @@ +- type: soundCollection + id: Fox + files: + - /Audio/Animals/fox_squeak.ogg + - /Audio/Animals/fox1.ogg + - /Audio/Animals/fox2.ogg + - /Audio/Animals/fox3.ogg + - /Audio/Animals/fox4.ogg + - /Audio/Animals/fox5.ogg + - /Audio/Animals/fox6.ogg + - /Audio/Animals/fox7.ogg + - /Audio/Animals/fox8.ogg + - /Audio/Animals/fox9.ogg + - /Audio/Animals/fox10.ogg + - /Audio/Animals/fox11.ogg + - /Audio/Animals/fox12.ogg + - /Audio/Animals/fox13.ogg + - /Audio/Animals/fox14.ogg diff --git a/Resources/Prototypes/Species/terminator.yml b/Resources/Prototypes/Species/terminator.yml deleted file mode 100644 index cfc5a7107ce..00000000000 --- a/Resources/Prototypes/Species/terminator.yml +++ /dev/null @@ -1,110 +0,0 @@ -- type: species - id: Terminator - name: Terminator - roundStart: false - prototype: MobTerminatorEndoskeleton - sprites: MobTerminatorSprites - defaultSkinTone: "#fff9e2" - markingLimits: MobHumanMarkingLimits - maleFirstNames: skeletonNamesFirst - femaleFirstNames: skeletonNamesFirst - dollPrototype: MobSkeletonPersonDummy - skinColoration: TintedHues - -- type: speciesBaseSprites - id: MobTerminatorSprites - sprites: - Head: MobTerminatorHead - Chest: MobTerminatorTorso - LArm: MobTerminatorLArm - RArm: MobTerminatorRArm - LHand: MobTerminatorLHand - RHand: MobTerminatorRHand - LLeg: MobTerminatorLLeg - RLeg: MobTerminatorRLeg - LFoot: MobTerminatorLFoot - RFoot: MobTerminatorRFoot - -- type: humanoidBaseSprite - id: MobTerminatorHead - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: head_m - -- type: humanoidBaseSprite - id: MobTerminatorHeadMale - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: head_m - -- type: humanoidBaseSprite - id: MobTerminatorHeadFemale - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: head_f - -- type: humanoidBaseSprite - id: MobTerminatorTorso - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: torso_m - -- type: humanoidBaseSprite - id: MobTerminatorTorsoMale - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: torso_m - -- type: humanoidBaseSprite - id: MobTerminatorTorsoFemale - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: torso_f - -- type: humanoidBaseSprite - id: MobTerminatorLLeg - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: l_leg - -- type: humanoidBaseSprite - id: MobTerminatorLArm - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: l_arm - -- type: humanoidBaseSprite - id: MobTerminatorLHand - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: l_hand - -- type: humanoidBaseSprite - id: MobTerminatorLFoot - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: l_foot - -- type: humanoidBaseSprite - id: MobTerminatorRLeg - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: r_leg - -- type: humanoidBaseSprite - id: MobTerminatorRArm - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: r_arm - -- type: humanoidBaseSprite - id: MobTerminatorRHand - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: r_hand - -- type: humanoidBaseSprite - id: MobTerminatorRFoot - baseSprite: - sprite: Mobs/Species/Terminator/parts.rsi - state: r_foot diff --git a/Resources/Prototypes/Species/vox.yml b/Resources/Prototypes/Species/vox.yml index 5d9724826d6..b6cba51322e 100644 --- a/Resources/Prototypes/Species/vox.yml +++ b/Resources/Prototypes/Species/vox.yml @@ -6,18 +6,19 @@ sprites: MobVoxSprites markingLimits: MobVoxMarkingLimits dollPrototype: MobVoxDummy - skinColoration: Hues + skinColoration: VoxFeathers + defaultSkinTone: "#6c741d" maleFirstNames: names_vox femaleFirstNames: names_vox naming: First sexes: - - Unsexed - + - Unsexed - type: speciesBaseSprites id: MobVoxSprites sprites: Head: MobVoxHead + Snout: MobHumanoidAnyMarking Hair: MobHumanoidAnyMarking FacialHair: MobHumanoidAnyMarking Chest: MobVoxTorso @@ -30,6 +31,7 @@ RLeg: MobVoxRLeg LFoot: MobVoxLFoot RFoot: MobVoxRFoot + Tail: MobHumanoidAnyMarking - type: markingPoints id: MobVoxMarkingLimits @@ -41,75 +43,94 @@ FacialHair: points: 1 required: false - Chest: + Head: points: 1 - required: false - RightLeg: - points: 2 - required: false - RightFoot: - points: 2 - required: false - LeftLeg: - points: 2 - required: false - LeftFoot: - points: 2 - required: false + required: true + Snout: + points: 1 + required: true + defaultMarkings: [ VoxBeak ] RightArm: - points: 2 - required: false + points: 1 + required: true + defaultMarkings: [ VoxRArmScales ] RightHand: - points: 2 - required: false + points: 1 + required: true + defaultMarkings: [ VoxRHandScales ] LeftArm: - points: 2 - required: false + points: 1 + required: true + defaultMarkings: [ VoxLArmScales ] LeftHand: - points: 2 + points: 1 + required: true + defaultMarkings: [ VoxLHandScales ] + RightLeg: + points: 1 + required: true + defaultMarkings: [ VoxRLegScales ] + LeftLeg: + points: 1 + required: true + defaultMarkings: [ VoxLLegScales ] + RightFoot: + points: 1 + required: true + defaultMarkings: [ VoxRFootScales ] + LeftFoot: + points: 1 + required: true + defaultMarkings: [ VoxLFootScales ] + Chest: + points: 1 required: false + Tail: + points: 1 + required: true + defaultMarkings: [ VoxTail ] - type: humanoidBaseSprite id: MobVoxEyes baseSprite: - sprite: Mobs/Customization/eyes.rsi - state: vox_eyes_s + sprite: Mobs/Species/Vox/parts.rsi + state: eyes - type: humanoidBaseSprite id: MobVoxHead baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: head_m + state: head - type: humanoidBaseSprite id: MobVoxHeadMale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: head_m + state: head - type: humanoidBaseSprite id: MobVoxHeadFemale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: head_f + state: head - type: humanoidBaseSprite id: MobVoxTorso baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso_m + state: torso - type: humanoidBaseSprite id: MobVoxTorsoMale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso_m + state: torso - type: humanoidBaseSprite id: MobVoxTorsoFemale baseSprite: sprite: Mobs/Species/Vox/parts.rsi - state: torso_f + state: torso - type: humanoidBaseSprite id: MobVoxLLeg @@ -158,5 +179,3 @@ baseSprite: sprite: Mobs/Species/Vox/parts.rsi state: r_foot - -# diff --git a/Resources/Prototypes/Stacks/Materials/materials.yml b/Resources/Prototypes/Stacks/Materials/materials.yml index 00153ef23c0..0a05a899648 100644 --- a/Resources/Prototypes/Stacks/Materials/materials.yml +++ b/Resources/Prototypes/Stacks/Materials/materials.yml @@ -54,6 +54,14 @@ maxCount: 30 itemSize: 1 +- type: stack + id: Pyrotton + name: pyrotton + icon: { sprite: /Textures/Objects/Materials/materials.rsi, state: pyrotton } + spawn: MaterialPyrotton1 + maxCount: 30 + itemSize: 1 + - type: stack id: Bananium name: bananium diff --git a/Resources/Prototypes/Stacks/consumable_stacks.yml b/Resources/Prototypes/Stacks/consumable_stacks.yml index e9f0cab7e4b..2936772f080 100644 --- a/Resources/Prototypes/Stacks/consumable_stacks.yml +++ b/Resources/Prototypes/Stacks/consumable_stacks.yml @@ -51,6 +51,14 @@ maxCount: itemSize: 1 +- type: stack + id: GroundCannabisRainbow + name: ground rainbow cannabis + icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: powderpile_rainbow } + spawn: GroundCannabisRainbow + maxCount: + itemSize: 1 + - type: stack id: LeavesTobaccoDried name: dried tobacco leaves @@ -66,3 +74,11 @@ spawn: LeavesCannabisDried maxCount: 5 itemSize: 5 + +- type: stack + id: LeavesCannabisRainbowDried + name: dried rainbow cannabis leaves + icon: { sprite: /Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi, state: dried } + spawn: LeavesCannabisRainbowDried + maxCount: 5 + itemSize: 5 diff --git a/Resources/Prototypes/StatusEffects/health.yml b/Resources/Prototypes/StatusEffects/health.yml index 562dbb336d8..073b03a2aeb 100644 --- a/Resources/Prototypes/StatusEffects/health.yml +++ b/Resources/Prototypes/StatusEffects/health.yml @@ -1,8 +1,8 @@ - type: statusIcon id: HealthIcon abstract: true - priority: 1 - locationPreference: Right + priority: 3 + locationPreference: Left isShaded: true - type: statusIcon diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml index 11f8d509af3..1b377902e43 100644 --- a/Resources/Prototypes/Store/categories.yml +++ b/Resources/Prototypes/Store/categories.yml @@ -7,6 +7,32 @@ id: Debug2 name: store-category-debug2 +#WIZARD +- type: storeCategory + id: SpellbookOffensive + name: store-caregory-spellbook-offensive + priority: 0 + +- type: storeCategory + id: SpellbookDefensive + name: store-caregory-spellbook-defensive + priority: 1 + +- type: storeCategory + id: SpellbookUtility + name: store-caregory-spellbook-utility + priority: 2 + +- type: storeCategory + id: SpellbookEquipment + name: store-caregory-spellbook-equipment + priority: 3 + +- type: storeCategory + id: SpellbookEvents + name: store-caregory-spellbook-events + priority: 4 + #uplink categoires - type: storeCategory id: UplinkWeapons @@ -68,6 +94,16 @@ name: store-category-deception priority: 10 +- type: storeCategory + id: UplinkChemicals + name: store-category-chemicals + priority: 11 + +- type: storeCategory + id: UplinkDisruption + name: store-category-disruption + priority: 12 + #revenant - type: storeCategory id: RevenantAbilities diff --git a/Resources/Prototypes/Store/currency.yml b/Resources/Prototypes/Store/currency.yml index 91039a75e6a..b1cff06be2d 100644 --- a/Resources/Prototypes/Store/currency.yml +++ b/Resources/Prototypes/Store/currency.yml @@ -1,7 +1,7 @@ - type: currency id: Telecrystal displayName: store-currency-display-telecrystal - cash: + cash: 1: Telecrystal1 canWithdraw: true @@ -10,7 +10,12 @@ displayName: store-currency-display-stolen-essence canWithdraw: false +- type: currency + id: WizCoin + displayName: store-currency-display-wizcoin + canWithdraw: false + #debug - type: currency id: DebugDollar - displayName: store-currency-display-debugdollar \ No newline at end of file + displayName: store-currency-display-debugdollar diff --git a/Resources/Prototypes/Store/presets.yml b/Resources/Prototypes/Store/presets.yml index bbf96997956..47768b68ec3 100644 --- a/Resources/Prototypes/Store/presets.yml +++ b/Resources/Prototypes/Store/presets.yml @@ -23,3 +23,15 @@ minItems: 3 maxItems: 8 salesCategory: UplinkSales + +- type: storePreset + id: StorePresetSpellbook + storeName: Spellbook + categories: + - SpellbookOffensive #Fireball, Rod Form + - SpellbookDefensive #Magic Missile, Wall of Force + - SpellbookUtility #Body Swap, Lich, Teleport, Knock, Polymorph + - SpellbookEquipment #Battlemage Robes, Staff of Locker + - SpellbookEvents #Summon Weapons, Summon Ghosts + currencyWhitelist: + - WizCoin diff --git a/Resources/Prototypes/Traits/Misc/singer_types.yml b/Resources/Prototypes/Traits/Misc/singer_types.yml index 28e4712ee99..605f3be9130 100644 --- a/Resources/Prototypes/Traits/Misc/singer_types.yml +++ b/Resources/Prototypes/Traits/Misc/singer_types.yml @@ -10,9 +10,7 @@ "Flute": {73: 0} "Sax": {66: 0} defaultInstrument: "Voice" - midiUi: - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface + midiUi: Key midiActionId: ActionHarpyPlayMidi - type: SingerInstrument @@ -20,7 +18,5 @@ instrumentList: "Voice": {52: 0} defaultInstrument: "Voice" - midiUi: - key: enum.InstrumentUiKey.Key - type: InstrumentBoundUserInterface + midiUi: Key midiActionId: ActionHarpyPlayMidi # TODO: custom action maybe? diff --git a/Resources/Prototypes/Traits/disabilities.yml b/Resources/Prototypes/Traits/disabilities.yml index 2b37aadb9a9..9961c849487 100644 --- a/Resources/Prototypes/Traits/disabilities.yml +++ b/Resources/Prototypes/Traits/disabilities.yml @@ -11,6 +11,20 @@ components: - type: PermanentBlindness +- type: trait + id: Nearsighted + category: Visual + points: 1 + requirements: + - !type:CharacterJobRequirement + inverted: true + jobs: + - Borg + - MedicalBorg + components: + - type: PermanentBlindness + blindness: 4 + - type: trait id: Narcolepsy category: Mental diff --git a/Resources/Prototypes/Traits/neutral.yml b/Resources/Prototypes/Traits/neutral.yml index 6186c3382b7..3b63c930e8e 100644 --- a/Resources/Prototypes/Traits/neutral.yml +++ b/Resources/Prototypes/Traits/neutral.yml @@ -97,4 +97,12 @@ species: - IPC moodEffects: - - NicotineWithdrawal \ No newline at end of file + - NicotineWithdrawal + +- type: trait + id: Liar + category: Mental + components: + - type: ReplacementAccent + replacementChance: 0.15 + accent: liar diff --git a/Resources/Prototypes/Voice/disease_emotes.yml b/Resources/Prototypes/Voice/disease_emotes.yml index 7845fd3e6d2..6b9914ad454 100644 --- a/Resources/Prototypes/Voice/disease_emotes.yml +++ b/Resources/Prototypes/Voice/disease_emotes.yml @@ -1,43 +1,65 @@ - type: emote id: Sneeze + name: chat-emote-name-sneeze category: Vocal - chatMessages: [ sneezes ] + chatMessages: [ "chat-emote-msg-sneeze" ] - type: emote id: Cough + name: chat-emote-name-cough + icon: Interface/Emotes/cough.png category: Vocal - chatMessages: [ coughs ] + chatMessages: [ "chat-emote-msg-cough" ] + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassischatMessages chatTriggers: - coughs - type: emote id: CatMeow + name: chat-emote-name-catmeow category: Vocal - chatMessages: [ meows ] + chatMessages: [ "chat-emote-msg-catmeow" ] - type: emote id: CatHisses + name: chat-emote-name-cathisses category: Vocal - chatMessages: [ hisses ] + chatMessages: [ "chat-emote-msg-cathisses" ] - type: emote id: MonkeyScreeches + name: chat-emote-name-monkeyscreeches category: Vocal - chatMessages: [ screeches ] + chatMessages: [ "chat-emote-msg-monkeyscreeches" ] - type: emote id: RobotBeep + name: chat-emote-name-robotbeep category: Vocal - chatMessages: [ beeps ] + chatMessages: [ "chat-emote-msg-beep" ] - type: emote id: Yawn + name: chat-emote-name-yawn + icon: Interface/Emotes/yawn.png category: Vocal - chatMessages: [ yawns ] + chatMessages: [ "chat-emote-msg-yawn" ] + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassischatMessages chatTriggers: - yawns - type: emote id: Snore + name: chat-emote-name-snore category: Vocal - chatMessages: [ snores ] + chatMessages: [ "chat-emote-msg-snore" ] diff --git a/Resources/Prototypes/Voice/speech_emote_sounds.yml b/Resources/Prototypes/Voice/speech_emote_sounds.yml index 2ec71110766..a5d05e24b71 100644 --- a/Resources/Prototypes/Voice/speech_emote_sounds.yml +++ b/Resources/Prototypes/Voice/speech_emote_sounds.yml @@ -72,7 +72,7 @@ collection: Weh - type: emoteSounds - id: UnisexReptilian + id: MaleReptilian params: variation: 0.125 sounds: @@ -89,6 +89,24 @@ Weh: collection: Weh +- type: emoteSounds + id: FemaleReptilian + params: + variation: 0.125 + sounds: + Scream: + path: /Audio/Voice/Reptilian/reptilian_scream.ogg + Laugh: + path: /Audio/Animals/lizard_happy.ogg + Honk: + collection: BikeHorn + Whistle: + collection: Whistles + Crying: + collection: FemaleCry + Weh: + collection: Weh + - type: emoteSounds id: MaleSlime sounds: @@ -316,6 +334,26 @@ Ping: path: /Audio/Effects/Cargo/ping.ogg +- type: emoteSounds + id: UnisexSiliconSyndicate + params: + variation: 0.05 + sounds: + Laugh: + path: /Audio/Voice/Silicon/syndieborg_laugh.ogg + Beep: + path: /Audio/Machines/twobeep.ogg + Chime: + path: /Audio/Machines/chime.ogg + Buzz: + path: /Audio/Machines/buzz-sigh.ogg + Buzz-Two: + path: /Audio/Machines/buzz-two.ogg + Honk: + path: /Audio/Items/bikehorn.ogg + Ping: + path: /Audio/Effects/Cargo/ping.ogg + # body emotes - type: emoteSounds id: GeneralBodyEmotes diff --git a/Resources/Prototypes/Voice/speech_emotes.yml b/Resources/Prototypes/Voice/speech_emotes.yml index 130e5e3d80b..ca4aa17229e 100644 --- a/Resources/Prototypes/Voice/speech_emotes.yml +++ b/Resources/Prototypes/Voice/speech_emotes.yml @@ -1,8 +1,16 @@ # vocal emotes - type: emote id: Scream + name: chat-emote-name-scream category: Vocal - chatMessages: [ screams ] + icon: Interface/Actions/scream.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-scream"] chatTriggers: - screams - shrieks @@ -11,8 +19,16 @@ - type: emote id: Laugh + name: chat-emote-name-laugh category: Vocal - chatMessages: [ laughs ] + icon: Interface/Emotes/laugh.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassischatMessages + chatMessages: ["chat-emote-msg-laugh"] chatTriggers: - laughs - chuckles @@ -21,73 +37,156 @@ - type: emote id: Honk + name: chat-emote-name-honk category: Vocal - chatMessages: [ honks ] + icon: Interface/Emotes/honk.png + chatMessages: ["chat-emote-msg-honk"] + whitelist: + requireAll: true + components: + - Vocal + - BorgChassischatMessages chatTriggers: - honks - type: emote id: Sigh + name: chat-emote-name-sigh category: Vocal - chatMessages: [ sighs ] + icon: Interface/Emotes/sigh.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassischatMessages + chatMessages: ["chat-emote-msg-sigh"] chatTriggers: - sighs - type: emote id: Whistle + name: chat-emote-name-whistle category: Vocal - chatMessages: [ whistles ] + icon: Interface/Emotes/whistle.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-whistle"] chatTriggers: - whistles - type: emote id: Crying + name: chat-emote-name-crying category: Vocal - chatMessages: [ cries ] + icon: Interface/Emotes/cry.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-crying"] chatTriggers: - cries - sobs - type: emote id: Squish + name: chat-emote-name-squish category: Vocal - chatMessages: [ squishes ] + available: false + icon: Interface/Emotes/squish.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-squish"] chatTriggers: - squishes - type: emote id: Chitter + name: chat-emote-name-chitter category: Vocal - chatMessages: [ chitters ] + available: false + icon: Interface/Emotes/chitter.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-chitter"] chatTriggers: - chitters - type: emote id: Squeak + name: chat-emote-name-squeak category: Vocal - chatMessages: [ squeaks ] + available: false + icon: Interface/Emotes/squeak.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-squeak"] chatTriggers: - squeaks - type: emote id: Click + name: chat-emote-name-click category: Vocal - chatMessages: [ clicks ] + available: false + icon: Interface/Emotes/click.png + whitelist: + components: + - Vocal + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-click"] chatTriggers: - clicks # hand emotes - type: emote id: Clap + name: chat-emote-name-clap category: Hands - chatMessages: [ claps ] + icon: Interface/Emotes/clap.png + whitelist: + components: + - Hands + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-clap"] chatTriggers: - claps - type: emote id: Snap + name: chat-emote-name-snap category: Hands - chatMessages: [ snaps ] # snaps <{THEIR($ent)}> fingers? + icon: Interface/Emotes/snap.png + whitelist: + components: + - Hands + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-snap"] # snaps <{THEIR($ent)}> fingers? chatTriggers: - snaps - snaps fingers @@ -99,52 +198,95 @@ - type: emote id: Salute + name: chat-emote-name-salute category: Hands - chatMessages: [ salutes ] + icon: Interface/Emotes/salute.png + whitelist: + components: + - Hands + blacklist: + components: + - BorgChassis + chatMessages: ["chat-emote-msg-salute"] chatTriggers: - salutes - type: emote id: DefaultDeathgasp - chatMessages: ["emote-deathgasp"] + name: chat-emote-name-deathgasp + icon: Interface/Emotes/deathgasp.png + whitelist: + components: + - MobState + chatMessages: ["chat-emote-msg-deathgasp"] chatTriggers: - deathgasp +- type: emote + id: MonkeyDeathgasp + name: chat-emote-name-deathgasp + icon: Interface/Emotes/deathgasp.png + chatMessages: ["chat-emote-msg-deathgasp-monkey"] + - type: emote id: SiliconDeathgasp + name: chat-emote-name-deathgasp chatMessages: ["chat-emote-msg-deathgasp-silicon"] chatTriggers: - sdeathgasp - type: emote id: Buzz + name: chat-emote-name-buzz category: Vocal - chatMessages: [ buzzes ] + icon: Interface/Emotes/buzz.png + whitelist: + requireAll: true + components: + - BorgChassis + - Vocal + chatMessages: ["chat-emote-msg-buzz"] chatTriggers: - buzzes - type: emote id: Weh + name: chat-emote-name-weh category: Vocal + icon: Interface/Emotes/weh.png chatMessages: [ wehs ] - type: emote id: Chirp + name: chat-emote-name-chirp category: Vocal - chatMessages: [ chirps ] + icon: Interface/Emotes/chirp.png + whitelist: + requireAll: true + components: + - Nymph + chatMessages: ["chat-emote-msg-chirp"] chatTriggers: - chirps # Machine Emotes - type: emote id: Beep + name: chat-emote-name-beep category: Vocal - chatMessages: [ beeps ] + icon: Interface/Emotes/beep.png + whitelist: + requireAll: true + components: + - BorgChassis + - Vocal + chatMessages: ["chat-emote-msg-beep"] chatTriggers: - beeps - type: emote id: Boop + name: chat-emote-name-boop category: Vocal chatMessages: [ boops ] chatTriggers: @@ -152,27 +294,49 @@ - type: emote id: Chime + name: chat-emote-name-chime category: Vocal - chatMessages: [ chimes ] + icon: Interface/Emotes/chime.png + whitelist: + requireAll: true + components: + - BorgChassis + - Vocal + chatMessages: ["chat-emote-msg-chime"] chatTriggers: - chimes - type: emote id: Buzz-Two + name: chat-emote-name-buzztwo category: Vocal - chatMessages: [ "buzzes twice" ] + icon: Interface/Emotes/buzztwo.png + whitelist: + requireAll: true + components: + - BorgChassis + - Vocal + chatMessages: ["chat-emote-msg-buzzestwo"] chatTriggers: - buzzes twice - type: emote id: Ping + name: chat-emote-name-ping category: Vocal - chatMessages: [ pings ] + icon: Interface/Emotes/ping.png + whitelist: + requireAll: true + components: + - BorgChassis + - Vocal + chatMessages: ["chat-emote-msg-ping"] chatTriggers: - pings - type: emote - id: Whirr # uncategorized as it is generic + id: Whirr + name: chat-emote-name-whirr chatMessages: [ whirrs ] chatTriggers: - whirrs diff --git a/Resources/Prototypes/Voice/speech_sounds.yml b/Resources/Prototypes/Voice/speech_sounds.yml index 2e7e7bf989a..a490c734d3d 100644 --- a/Resources/Prototypes/Voice/speech_sounds.yml +++ b/Resources/Prototypes/Voice/speech_sounds.yml @@ -52,6 +52,24 @@ exclaimSound: path: /Audio/Machines/vending_jingle.ogg +- type: speechSounds + id: Borg + saySound: + path: /Audio/Voice/Talk/Silicon/borg.ogg + askSound: + path: /Audio/Voice/Talk/Silicon/borg_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/Silicon/borg_exclaim.ogg + +- type: speechSounds + id: SyndieBorg + saySound: + path: /Audio/Voice/Talk/Silicon/syndieborg.ogg + askSound: + path: /Audio/Voice/Talk/Silicon/syndieborg_ask.ogg + exclaimSound: + path: /Audio/Voice/Talk/Silicon/syndieborg_exclaim.ogg + - type: speechSounds id: Pai saySound: diff --git a/Resources/Prototypes/Voice/tail_emotes.yml b/Resources/Prototypes/Voice/tail_emotes.yml index be6064b652a..965b7da8d9f 100644 --- a/Resources/Prototypes/Voice/tail_emotes.yml +++ b/Resources/Prototypes/Voice/tail_emotes.yml @@ -1,6 +1,7 @@ - type: emote id: WagTail - chatMessages: [wags tail] + name: chat-emote-name-tailwag + chatMessages: [wags their tail] chatTriggers: - wags tail - wags his tail diff --git a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml index 0a0b9bcbcc3..4dcdd78435b 100644 --- a/Resources/Prototypes/XenoArch/Effects/normal_effects.yml +++ b/Resources/Prototypes/XenoArch/Effects/normal_effects.yml @@ -109,7 +109,7 @@ components: - type: PointLight radius: 8 - energy: 25 + energy: 10 color: "#daa3fd" - type: TriggerArtifact - type: FlashOnTrigger diff --git a/Resources/Prototypes/XenoArch/Effects/utility_effects.yml b/Resources/Prototypes/XenoArch/Effects/utility_effects.yml index 911c1c2e88e..84df09af33d 100644 --- a/Resources/Prototypes/XenoArch/Effects/utility_effects.yml +++ b/Resources/Prototypes/XenoArch/Effects/utility_effects.yml @@ -214,8 +214,8 @@ permanentComponents: - type: UserInterface interfaces: - - key: enum.SignalLinkerUiKey.Key - type: SignalPortSelectorBoundUserInterface + enum.SignalLinkerUiKey.Key: + type: SignalPortSelectorBoundUserInterface - type: ToolTileCompatible - type: Tool qualities: diff --git a/Resources/Prototypes/floor_trap.yml b/Resources/Prototypes/floor_trap.yml new file mode 100644 index 00000000000..217dd9fca2d --- /dev/null +++ b/Resources/Prototypes/floor_trap.yml @@ -0,0 +1,116 @@ +- type: entity + id: CollideFloorTrap + abstract: true + placement: + mode: SnapgridCenter + components: + - type: Sprite + sprite: Tiles/Misc/floortrap.rsi + state: floortrap + - type: Fixtures + fixtures: + floortrap: + shape: + !type:PhysShapeAabb + bounds: "-0.4,-0.4,0.4,0.4" + hard: false + mask: + - ItemMask + layer: + - SlipLayer + - type: Physics + - type: Tag + tags: + - HideContextMenu + +- type: entity + parent: CollideFloorTrap + id: CollideFloorTrapSpawn + name: floor trap spawn + abstract: true + components: + - type: Sprite + sprite: Tiles/Misc/floortrap.rsi + state: floortrapspawn + +- type: entity + parent: CollideFloorTrap + id: FloorTrapExplosion + name: explosion floor trap + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: ExplodeOnTrigger + - type: Explosive + explosionType: Default + totalIntensity: 20.0 + intensitySlope: 5 + maxIntensity: 4 + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrap + id: FloorTrapEMP + name: EMP floor trap + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: EmpOnTrigger + range: 2 + energyConsumption: 5000 + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrapSpawn + id: SpawnFloorTrapCarp + suffix: Carp + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: SpawnOnTrigger + proto: MobCarp + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrapSpawn + id: SpawnFloorTrapBear + suffix: Bear + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: SpawnOnTrigger + proto: MobBearSpace + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrapSpawn + id: SpawnFloorTrapKangaroo + suffix: Kangaroo + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: SpawnOnTrigger + proto: MobKangarooSpace + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrapSpawn + id: SpawnFloorTrapXenoDrone + suffix: Xeno. Drone + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: SpawnOnTrigger + proto: MobXenoDrone + - type: DeleteOnTrigger + +- type: entity + parent: CollideFloorTrapSpawn + id: SpawnFloorTrapXenoBurrower + suffix: Xeno. Burrower + components: + - type: TriggerOnCollide + fixtureID: floortrap + - type: SpawnOnTrigger + proto: MobXeno + - type: DeleteOnTrigger diff --git a/Resources/Prototypes/lobbyscreens.yml b/Resources/Prototypes/lobbyscreens.yml index 773af9a1437..d8c5d283794 100644 --- a/Resources/Prototypes/lobbyscreens.yml +++ b/Resources/Prototypes/lobbyscreens.yml @@ -37,3 +37,7 @@ - type: lobbyBackground id: TerminalStation background: /Textures/LobbyScreens/terminalstation.webp + +- type: lobbyBackground + id: JustAWeekAway + background: /Textures/LobbyScreens/justaweekaway.webp \ No newline at end of file diff --git a/Resources/Prototypes/name_identifier_groups.yml b/Resources/Prototypes/name_identifier_groups.yml index 82c2f3bce9a..4823e31f55d 100644 --- a/Resources/Prototypes/name_identifier_groups.yml +++ b/Resources/Prototypes/name_identifier_groups.yml @@ -37,3 +37,9 @@ id: Bounty minValue: 0 maxValue: 999 + +- type: nameIdentifierGroup + id: CargoTelepads + prefix: TELE + minValue: 0 + maxValue: 999 diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index cc81a2ed64b..c8745eb8490 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -259,6 +259,9 @@ - type: Tag id: CableCoil +- type: Tag + id: CaneBlade + - type: Tag id: CapacitorStockPart @@ -401,6 +404,9 @@ - type: Tag id: ClownSuit +- type: Tag + id: CluwneHappyHonk + - type: Tag id: CluwneHorn @@ -877,6 +883,9 @@ - type: Tag id: Meat +- type: Tag + id: Medal + - type: Tag id: Medkit @@ -1112,15 +1121,15 @@ - type: Tag id: Shiv -- type: Tag - id: ShoesRequiredStepTriggerImmune - - type: Tag id: Shovel - type: Tag id: Sidearm +- type: Tag + id: SignalTrigger + - type: Tag id: SkeletonMotorcycleKeys @@ -1136,9 +1145,6 @@ - type: Tag id: Smokable -- type: Tag - id: SnapPop - - type: Tag id: SnowyLabs @@ -1247,6 +1253,9 @@ - type: Tag id: TrashBag +- type: Tag + id: Truncheon + - type: Tag id: Unimplantable @@ -1286,6 +1295,9 @@ - type: Tag id: WeaponShotgunKammerer +- type: Tag + id: WeldingMask + - type: Tag id: WetFloorSign @@ -1327,5 +1339,3 @@ - type: Tag id: WriteIgnoreStamps - -# PUT YOUR TAGS IN ALPHABETICAL ORDER diff --git a/Resources/Prototypes/themes.yml b/Resources/Prototypes/themes.yml index edd2681a624..3952687255a 100644 --- a/Resources/Prototypes/themes.yml +++ b/Resources/Prototypes/themes.yml @@ -12,6 +12,8 @@ concerningOrangeFore: "#A5762F" dangerousRedFore: "#BB3232" disabledFore: "#5A5A5A" + _itemstatus_content_margin_right: "#06060404" + _itemstatus_content_margin_left: "#04060604" - type: uiTheme id: SS14PlasmafireTheme path: /Textures/Interface/Plasmafire/ @@ -26,6 +28,8 @@ concerningOrangeFore: "#FFF5EE" dangerousRedFore: "#FFF5EE" disabledFore: "#FFF5EE" + _itemstatus_content_margin_right: "#06060404" + _itemstatus_content_margin_left: "#04060604" - type: uiTheme id: SS14SlimecoreTheme path: /Textures/Interface/Slimecore/ @@ -40,6 +44,8 @@ concerningOrangeFore: "#FFF5EE" dangerousRedFore: "#FFF5EE" disabledFore: "#FFF5EE" + _itemstatus_content_margin_right: "#06060404" + _itemstatus_content_margin_left: "#04060604" - type: uiTheme id: SS14ClockworkTheme path: /Textures/Interface/Clockwork/ @@ -54,6 +60,8 @@ concerningOrangeFore: "#FFF5EE" dangerousRedFore: "#FFF5EE" disabledFore: "#FFF5EE" + _itemstatus_content_margin_right: "#06060404" + _itemstatus_content_margin_left: "#04060604" - type: uiTheme id: SS14RetroTheme path: /Textures/Interface/Retro/ @@ -68,6 +76,8 @@ concerningOrangeFore: "#FFF5EE" dangerousRedFore: "#FFF5EE" disabledFore: "#FFF5EE" + _itemstatus_content_margin_right: "#06060404" + _itemstatus_content_margin_left: "#04060604" - type: uiTheme id: SS14MinimalistTheme path: /Textures/Interface/Minimalist/ @@ -82,6 +92,8 @@ concerningOrangeFore: "#A5762F" dangerousRedFore: "#BB3232" disabledFore: "#5A5A5A" + _itemstatus_content_margin_right: "#06060604" + _itemstatus_content_margin_left: "#06060604" - type: uiTheme id: SS14AshenTheme path: /Textures/Interface/Ashen/ @@ -96,3 +108,5 @@ concerningOrangeFore: "#FFF5EE" dangerousRedFore: "#FFF5EE" disabledFore: "#FFF5EE" + _itemstatus_content_margin_right: "#06060604" + _itemstatus_content_margin_left: "#06060604" diff --git a/Resources/ServerInfo/Guidebook/Antagonist/Antagonists.xml b/Resources/ServerInfo/Guidebook/Antagonist/Antagonists.xml index a0e434dc772..927a56a5054 100644 --- a/Resources/ServerInfo/Guidebook/Antagonist/Antagonists.xml +++ b/Resources/ServerInfo/Guidebook/Antagonist/Antagonists.xml @@ -8,5 +8,6 @@ Antagonists can take many forms, like: - Nuclear operatives, with the goal of infiltrating and destroying the station. - Traitors infiltrating the crew who can assassinate targets and steal high value items. + - Space Ninjas, masters of espionage and sabotage, who are equipped with special gear. - Several non-humanoid creatures, who usually just try to bring down as many crewmembers as they can. diff --git a/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml b/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml index 8ee9ec090eb..e69220fc2a0 100644 --- a/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml +++ b/Resources/ServerInfo/Guidebook/Antagonist/Revolutionaries.xml @@ -10,7 +10,7 @@ - [color=#5e9cff]Head Revolutionaries[/color] are chosen at the start of the shift and are tasked with taking over the station by killing or exiling all of the Command staff. Head Revolutionaries will be given a [color=#a4885c]Flash[/color] and a pair of [color=#a4885c]Sunglasses[/color] to aid them. + [color=#5e9cff]Head Revolutionaries[/color] are chosen at the start of the shift and are tasked with taking over the station by killing, exiling or cuffing all of the Command staff. Head Revolutionaries will be given a [color=#a4885c]Flash[/color] and a pair of [color=#a4885c]Sunglasses[/color] to aid them. ## Conversion @@ -41,7 +41,7 @@ ## Objectives - You must eliminate or exile all of the following Command staff on station in no particular order. + You must eliminate, exile or arrest all of the following Command staff on station in no particular order. - Captain - Head of Personnel - Chief Engineer diff --git a/Resources/ServerInfo/Guidebook/Antagonist/SpaceNinja.xml b/Resources/ServerInfo/Guidebook/Antagonist/SpaceNinja.xml index 7fed84da73e..f088b9f27b1 100644 --- a/Resources/ServerInfo/Guidebook/Antagonist/SpaceNinja.xml +++ b/Resources/ServerInfo/Guidebook/Antagonist/SpaceNinja.xml @@ -1,74 +1,80 @@ -# Space Ninja + # Space Ninja -The Space Ninja is a ghost role randomly available mid-late game. If you pick it you will be given your gear, your objectives and the greeting. + The [color=#66FF00]Space Ninja[/color] is a ghost role randomly available mid-late game. If you pick it you will be given your gear, your objectives and the greeting. -You are a ninja, but in space. The Spider Clan has sent you to the station to wreak all kinds of havoc, from bolting the armory open and killing the entire station to engaging in a slipping war with the clown and fighting in rage cages. + You are a ninja, but in space. [color=#66FF00]The Spider Clan[/color] has sent you to the station to wreak all kinds of havoc, and you are equipped to keep it silent-but-deadly. -# Equipment + Whether you mercilessly pick off the station's crew one by one, or assassinate the clown over and over, your discipline has taught you that [color=#66FF00]your objectives must be at least attempted[/color]. For honor! -You start with a microbomb implant, so if you get KIA or seppuku you will leave behind a nice crater and all your precious equipment is kept out of enemy hands. + # Equipment -Your bag is full of tools for more subtle sabotage, along with a survival box if you need a snack. + You begin implanted with a [color=#a4885c]death acidifier[/color], so if you are KIA or decide to commit seppuku you will leave behind one final gift to the janitor and all your precious equipment is kept out of enemy hands. -You have a jetpack and pinpointer that will let you find the station. + Your bag is full of tools for more subtle sabotage, along with a survival box if you need a snack. - + You have a [color=#a4885c]jetpack[/color] and [color=#a4885c]pinpointer[/color] that will let you find the station. -## Ninja Suit + - + ## Ninja Suit -Your single most important item is your suit, without it none of your abilities would work. -Your suit requires power to function, its internal battery can be replaced by clicking on it **with a better one**. -You can see the current charge by examining the suit or in a sweet battery alert at the top right of your screen. + -If you run out of power and need to recharge your battery, just use your gloves to drain an APC, substation or a SMES. + Your single most important item is [color=#66FF00]your suit[/color], without it none of your abilities would work. + Your suit requires power to function. Its [color=#a4885c]internal battery[/color] can be replaced by clicking on it with another one, and [color=#a4885c]higher capacity batteries[/color] mean a [color=#a4885c]highly effective ninja[/color]. + You can see the current charge by examining the suit or in a sweet battery alert at the top right of your screen. -## Ninja Gloves + If you run out of power and need to recharge your battery, just use your gloves to drain an APC, substation or a SMES. - + ## Ninja Gloves -These bad boys are your bread and butter. + -They are insulated so you can nom on wires in peace. Obviously they block your fingerprints from being left on things you touch. + [color=#66FF00]These bad boys are your bread and butter.[/color] -You have an action to toggle gloves. When the gloves are turned on, they allow you to use special abilities, which are triggered by interacting with things with an empty hand and with combat mode disabled. + They are made from [color=#a4885c]insulated nanomachines[/color] to assist you in gracefully breaking and entering into your destination without leaving behind fingerprints. -Your glove abilities include: -- Emagging an unlimited number of doors. -- Draining power from transformers such as APCs, substations or SMESes. The higher the voltage, the more efficient the draining is. -- You can shock any mob, stunning and slightly damaging them. -- You can download technologies from a R&D server for one of your objectives. -- You can hack a communications console to call in a threat. + You have an action to toggle gloves. When the gloves are turned on, they allow you to use [color=#a4885c]special abilities[/color], which are triggered by interacting with things with an empty hand and with combat mode disabled. -## Energy Katana + Your glove abilities include: + - Emagging an unlimited number of doors. + - Draining power from transformers such as APCs, substations or SMESes. The higher the voltage, the more efficient the draining is. + - You can shock any mob, stunning and slightly damaging them. + - You can download technologies from a R&D server for one of your objectives. + - You can hack a communications console to call in a threat. - + ## Energy Katana -Deals a lot of damage and can be recalled at will, costing suit power proportional to the distance teleported. -While in hand you can teleport to anywhere that you can see, meaning most doors and windows, but not past solid walls. -This has a limited number of charges which regenerate slowly, so keep a charge or two spare incase you need a quick getaway. + -## Spider Clan Charge + You have sworn yourself to the [color=#66FF00]sword[/color] and refuse to use firearms. + Deals a lot of damage and can be recalled at will, costing suit power proportional to the distance teleported. + + While in hand you can [color=#a4885c]teleport[/color] to anywhere that you can see, meaning most doors and windows, but not past solid walls. + This has a limited number of charges which regenerate slowly, so keep a charge or two spare incase you need a quick getaway. - + ## Spider Clan Charge -A modified C-4 explosive, you start with this in your pocket. Creates a large explosion but must be armed in your target area. -A random area on the map is selected for you to blow up, which is one of your objectives. It can't be activated manually, simply plant it on a wall or something. -Can't be unstuck once planted. + -## Ninja Shoes + [color=#66FF00]A modified C-4 explosive[/color], you start with this in your pocket. Creates a large explosion but must be armed in your target area. + A random area on the map is selected for you to blow up, which is one of your [color=#a4885c]objectives[/color]. -Special noslips that make you go really fast. -Energy not required. + It can't be activated manually, simply plant it on a wall or a particularly ugly piece of furniture. + Can't be unstuck once planted. -# Objectives + ## Ninja Shoes -- Download X research nodes: Use your gloves on an R&D server with a number of unlocked technologies -- Doorjack X doors on the station: Use your gloves to emag a number of doors. -- Detonate the spider clan charge: Plant your spider clan charge at a random location and watch it go boom. -- Call in a threat: Use your gloves on a communications console. -- Survive: Don't die. + Special [color=#a4885c]noslips[/color] that keep you agile, swift and upright. + Energy not required. + + # Objectives + + - Download X research nodes: Use your gloves on an R&D server with a number of unlocked technologies + - Doorjack X doors on the station: Use your gloves to emag a number of doors. + - Detonate the spider clan charge: Plant your spider clan charge at a random location and watch it go boom. + - Call in a threat: Use your gloves on a communications console. + - Survive: Don't die. diff --git a/Resources/ServerInfo/Guidebook/Engineering/AME.xml b/Resources/ServerInfo/Guidebook/Engineering/AME.xml index ae0217c4b0c..0a969072033 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/AME.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/AME.xml @@ -1,26 +1,25 @@ -# Antimatter Engine (AME) + # Antimatter Engine (AME) -The AME is one of the simplest engines available. You put together the multi-tile structure, stick some fuel into it, and you're all set. This doesn't mean it isn't potentially dangerous with overheating though. + The AME is one of the simplest engines available. You put together the multi-tile structure, stick some fuel into it, and you're all set. This doesn't mean it is perfectly safe though; you may need to deal with the AME overheating. -## Construction -Required parts: - - - - - + ## Construction + Required parts: + + + + + -To assemble an AME, start by wrenching down the controller on the far end of a HV wire. On most stations, there's catwalks to assist with this. From there, start putting down a 3x3 or larger square of AME parts in preparation for construction, making sure to maximize the number of "center" pieces that are surrounded on all 8 sides. + To assemble an AME, start by wrenching down the controller on the near end of a HV wire. On most stations, there's catwalks to assist with this. From there, start putting down a 3x3 or larger square of AME parts in preparation for construction, making sure to maximize the number of "center" pieces that are surrounded on all 8 sides. -Once this is done, you can use a multitool to convert each AME part into shielding, which should form a finished AME configuration. From there, insert a fuel jar, set the fuel rate to [color=#a4885c]twice the core count or less[/color], and turn on injection. + Once this is done, you can use a multitool to convert each AME part into shielding, which should form a finished AME configuration. From there, insert a fuel jar, set the fuel rate to [color=#a4885c]twice the core count or less[/color], and turn on injection. Any more than this ratio will eventually result in the engine [color=#ff0000]overheating and[/color], shortly afterwards, [color=#ff0000]exploding[/color]. -## Fuel Economy -The closer you are to the perfect ratio of [color=#a4885c]1:2[/color] (1 AME core to 2 fuel rate) the more efficient you'll be. You're cutting fuel efficiency to [color=#a4885c]50% and less[/color] if you're using more cores, but less fuel injection rate. -For an example [color=#76db91]3 core and 6 fuel rate[/color] will generate [color=#76db91]240kW[/color], while [color=#f0684d]8 core 8 fuel rate[/color] will generate [color=#f0684d]160kW[/color]. Generating 80kW less while spending 2 more fuel each injection. + ## Fuel Economy + The closer you are to the perfect ratio of [color=#a4885c]1:2[/color] AME cores to fuel injection rate, the more efficient you'll be. You're cutting fuel efficiency to [color=#a4885c]50% and less[/color] if you're using more cores, but a lower fuel injection rate. + For an example, [color=#76db91]3 cores and 6 fuel injected[/color] will generate [color=#76db91]240kW[/color], while [color=#f0684d]8 cores and 8 fuel injected[/color] will generate [color=#f0684d]160kW[/color]; you'd be generating 80kW less while spending 2 more fuel per injection. -## Upgrading the AME - -You can generally only upgrade the AME by getting more cores, which can be done by ordering more AME packages from [color=#a4885c]logistics[/color]. + ## Upgrading the AME + You can generally only upgrade the AME by installing more cores, which can be done by ordering more AME flatpacks from [color=#a4885c]Logistics[/color]. diff --git a/Resources/ServerInfo/Guidebook/Engineering/AccessConfigurator.xml b/Resources/ServerInfo/Guidebook/Engineering/AccessConfigurator.xml index e54f45345d6..490cbf09c35 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/AccessConfigurator.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/AccessConfigurator.xml @@ -1,32 +1,34 @@ -# Access Configurator -The access configurator is a tool used to specify what type of personnel may use certain devices. + # Access Configurator + The access configurator is a tool used to specify what type of personnel may use certain devices. - - - + + + -Configurable devices can include airlocks, secure crates and lockers, as well as access restricted machines. + Configurable devices can include airlocks, secure crates and lockers, as well as access restricted machines. + Note: Airlocks can have their accesses configured by the [color=#a4885c]Network Configurator[/color] (or multitool), for convenience. -## Where to find access configurators -Each station is equipped with up to two access configurators. The first is in the possession of the Chief Engineer, while the second can be found with the Head of Personnel. + ## Where to find Access Configurators + Each station is equipped with up to two access configurators. The first is in the possession of the Chief Engineer, while the second can be found with the Head of Personnel. -## How to use the access configurator -To modify a device using the access configurator -- First, use the access configurator on the chosen device to link them together. This will automatically open the configurator UI. -- Next, insert an ID card into the access configurator. -- Set the access requirements of the connected device. What requirements can be added or removed will depend upon the access privileges of the inserted ID card. -- Any changes made will be applied immediately - simply eject the ID card from the access configurator and close the UI when you are done. + ## How to use the access configurator + To modify a device using the access configurator: + - First, use the access configurator on the chosen device to link them together. This will automatically open the configurator UI. + - Next, insert an ID card into the access configurator. + - Set the access requirements of the connected device. What requirements can be added or removed will depend upon the access privileges of the inserted ID card. + - Any changes made will be applied [color=#a4885c]immediately[/color] - simply eject the ID card from the access configurator and close the UI when you are done. -## Restrictions on changing access -As a safety precaution, the inserted ID must possess *all* of the access requirements that are currently active on the connected device in order to modify it. + ## Restrictions on changing access + As a safety precaution, the inserted ID must possess [bold]all[/bold] of the access requirements that are currently active on the connected device in order to modify it. -For example, a device which can be access by both 'Epistemics' and 'Medical' personnel can only by modified using an ID card that has access to both of these departments. The access configurator will warn the user if the inserted ID card does not have sufficient privileges to modify a device. + For example, a device which can be access by both 'Epistemics' and 'Medical' personnel can only by modified using an ID card that has access to [color=#a4885c]both[/color] of these departments. + The access configurator will warn the user if the inserted ID card does not have sufficient privileges to modify a device. -A device with no access requirements set, like a public access airlock, can be modified using any valid station ID card. + A device with no access requirements set, like a public access airlock, can be modified using any valid station ID card. -## Repairing damaged ID card readers -Syndicate agents may attempt to hack access restricted devices through the use of a Cryptographic Sequencer (EMAG). This nefarious tool will completely short out any ID card readers that are attached to the device. + ## Repairing damaged ID card readers + Syndicate agents may attempt to hack access restricted devices through the use of a [color=#a4885c]Cryptographic Sequencer (EMAG)[/color]. This nefarious tool will completely short out any ID card readers that are attached to the device. -Crew members will need to partially de/reconstruct affected devices, and then set appropriate access permissions afterwards using the access configurator, to re-establish access restrictions. + Engineers will need to partially de/reconstruct affected devices, and then set appropriate access permissions afterwards using the access configurator (or network configurator, for airlocks), to re-establish access restrictions. diff --git a/Resources/ServerInfo/Guidebook/Engineering/AirlockSecurity.xml b/Resources/ServerInfo/Guidebook/Engineering/AirlockSecurity.xml index 125833a0a18..8bfd3902cc2 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/AirlockSecurity.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/AirlockSecurity.xml @@ -1,76 +1,76 @@ -# Airlock Upgrades -It is not uncommon for plucky individuals to try and bypass an airlock by meddling with its internal wiring. + # Airlock Upgrades + It is not uncommon for plucky individuals to try and bypass an airlock by meddling with its internal wiring. -Fortunately, certain countermeasures can installed into airlocks to inconvenience any would be trespassers. + Fortunately, certain countermeasures can installed into airlocks to inconvenience any would-be trespassers. -## Medium security airlocks -The most basic form of intrusion deterrence is to install internal steel plating that will prevent access to internal wiring of the airlock. + ## Medium security airlocks + The most basic form of intrusion deterrence is to install a secured steel plating that will prevent access to internal wiring of the airlock. -To upgrade a basic airlock to a medium security airlock, you will require the following materials - - - - - - - - - - - + To upgrade a basic airlock to a medium security airlock, you will require the following materials: + + + + + + + + + + + -To upgrade the basic airlock, -- Use the screwdriver to open the airlock maintenance panel. -- Add the steel sheets to the airlock. -- Weld the steel sheets into place. -- Close the maintenance panel using the screwdriver. + To upgrade a basic airlock: + - Use the screwdriver to open the airlock maintenance panel. + - Add the steel sheets to the airlock. + - Weld the steel sheets into place. + - Close the maintenance panel using the screwdriver. -## High security airlocks -For airlocks leading to the more sensitive areas of the space station, the use of stronger deterrents are advised. High security airlocks have improved armor plating to protect its internal wiring, along with an electrified security grille. + ## High security airlocks + For airlocks leading to the more sensitive areas of the space station, the use of stronger deterrents are advised. High security airlocks have improved armor plating to protect its internal wiring, along with an electrified security grille. -To upgrade a basic airlock to a high security airlock, you will require the following materials - - - - - - - - - - - - - - + To upgrade a medium security airlock to a high security airlock, you will require the following materials: + + + + + + + + + + + + + + -To upgrade the basic airlock, -- Use the screwdriver to open the airlock maintenance panel. -- Add the plasteel sheets to the airlock. -- Weld the plasteel sheets into place. -- Add the metal rods to the airlock. -- Close the maintenance panel using the screwdriver. + To upgrade a medium security airlock: + - Use the screwdriver to open the airlock maintenance panel. + - Add the plasteel sheets to the airlock. + - Weld the plasteel sheets into place. + - Add the metal rods to the airlock. + - Close the maintenance panel using the screwdriver. -## Maximum security airlocks -You can optionally upgrade a high security airlock to a maximum security airlock. Maximum security airlocks possess an additional layer of plasteel plating on top of its other protections. + ## Maximum security airlocks + You can optionally upgrade a high security airlock to a maximum security airlock. Maximum security airlocks possess an additional layer of plasteel plating on top of its other protections. -To upgrade a high security airlock to a maximum security airlock, you will require the following materials - - - - - - - - - - - + To upgrade a high security airlock to a maximum security airlock, you will require the following materials: + + + + + + + + + + + -To upgrade the high security airlock, -- Use the screwdriver to open the airlock maintenance panel. -- Add the plasteel sheets to the airlock. -- Weld the plasteel sheets into place. -- Close the maintenance panel using the screwdriver. - \ No newline at end of file + To upgrade a high security airlock: + - Use the screwdriver to open the airlock maintenance panel. + - Add the plasteel sheets to the airlock. + - Weld the plasteel sheets into place. + - Close the maintenance panel using the screwdriver. + diff --git a/Resources/ServerInfo/Guidebook/Engineering/Atmospherics.xml b/Resources/ServerInfo/Guidebook/Engineering/Atmospherics.xml index 693e3a02098..48d0d9415e2 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Atmospherics.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Atmospherics.xml @@ -1,61 +1,67 @@ - -# Atmospherics - -Atmospherics setups are a necessity for your long-term comfort but are generally undocumented, resulting in them being a bit tricky to set up. The following attempts to cover the basics. - -## Standard Mix -Breathing pure O2 or pure N2 is generally bad for the health of your crew, and it is recommended to instead aim for a mix of [color=#a4885c]78% N2 and 22% O2 at 101.24kPa.[/color] It's recommended that your gas mixer setup be set to output at least 1000kPa for faster re-pressurization of rooms. - - - - - -Variations on this mix may be necessary for the long-term comfort of atypical crew, for example crew who require a plasma gas mix to survive. For atypical crew, it is recommended to try and give them their own personal space, isolated by either airlock or disposals section. Keep in mind both methods are leaky and you will need scrubbers on both sides of the lock to clean up any leaked gasses. - - - - -## Vents and Scrubbers -Vents and scrubbers are core atmospherics devices that fill and cleanse rooms, respectively. By default, they are configured for filling rooms to standard pressure (101.24kPa) and to remove all non-O2/N2 gasses from a room. They can be reconfigured from their default settings, allowing you to configure how they respond to various types of gasses or pressure levels. This can be done by interacting with an existing air alarm nearby, or installing and connecting them to a new one. - - - - - -During standard operation, if a vent detects that the outside environment is space, it will automatically cease operation until a minimum pressure is reached to avoid destruction of necessary gasses. This can be fixed by pressurizing the room up to that minimum pressure by refilling it with gas canister (potentially multiple, if the room is of significant size). - -Should you encounter a situation where scrubbers aren't cleaning a room fast enough, employ portable scrubbers by dragging them to the affected location and wrenching them down. They work much faster than typical scrubbers and can clean up a room quite quickly. Large spills may require you to employ multiple. - - - -# Gas mixes and Burn chambers -In the event you finish all the tasks at hand, you can make some extra power or money by creating new chemical gasses. - -##Tritium -Tritium is a clear, green gas that is highly flammable, radioactive, and combusts when in contact with oxygen making it very helpful when running the [color=#a4885c]TEG.[/color] -It can be made by burning 1% Plasma and 96% or more Oxygen in the Burn Chamber. You can extract this gas through scrubbers. - - - - - - - - -##Frezon -Frezon is a bluish-green gas that is very complex and very dangerous. To obtain frezon, you must mix Tritium, Oxygen, and Nitrogen in a 70K room to start the reaction, as well as prevent the Tritium from combusting with the oxygen. - - - - - - - - -It is critical to understand that a frezon leak can devastate the station, causing a wintery hell filled with itchy sweaters and cold burns. Frezon is very cold, and can freeze the station to death if even a few moles get out, so make sure that you lock your canisters or just move your Frezon straight into a storage room. - -## Reference Sheet -- Standard atmospheric mix is [color=#a4885c]78% N2 and 22% O2 at 101.24kPa.[/color] -- Gas obeys real math. You can use the equation PV = nRT (Pressure kPa * Volume L = Moles * R * Temperature K) to derive information you might need to know about a gas. R is approximately 8.31446 + + # Atmospherics + + Atmospherics setups are a necessity for your long-term comfort, but are generally underdocumented, resulting in them being a bit tricky to set up. The following attempts to cover the basics. + + ## Standard Mix + Breathing pure O2 or pure N2 is generally bad for the health of your crew, and it is recommended to instead aim for a mix of [color=#a4885c]78% N2 and 22% O2 at 101.24kPa.[/color] It's recommended that your gas mixer setup be set to output at least 300kPA for faster re-pressurization of rooms, without posing too much of an overpressurization risk, should traitors sabotage the distro. + + + + + + Variations on this mix may be necessary for the long-term comfort of atypical crew, (for example, Voxes, who are poisoned by Oxygen and breathe Nitrogen). For atypical crew (to be implemented), it is recommended to try and give them their own personal space, isolated by either an airlock or disposals section. Keep in mind that both methods are leaky and you will need scrubbers on both sides of the lock to clean up any leaked gasses. + + + + + ## Vents and Scrubbers + Vents and scrubbers are core atmospherics devices that fill and cleanse rooms, respectively. By default, they are configured for filling rooms to standard pressure (101.24kPa) and to remove all non-O2/N2 gasses from a room. They can be reconfigured from their default settings by linking them to an Air Alarm, allowing you to configure how they respond to various types of gasses or pressure levels. + + + + + + During standard operation, if a normal vent detects that the outside environment is space, it will automatically cease operation until a minimum pressure is reached to avoid destruction of useful gasses. This can be fixed by pressurizing the room up to that minimum pressure by refilling it with gas canister (potentially multiple, if the room is of significant size). + + Should you encounter a situation where scrubbers aren't cleaning a room fast enough (and the "Siphon" functionality still cannot keep up), employ portable scrubbers by dragging them to the affected location and wrenching them down. They work much faster than typical scrubbers and can clean up a room quite quickly. Large spills may require you to employ multiple. + + + + # Gas mixes and Burn chambers + In the event you finish all the tasks at hand, you can make some extra money by creating new chemical gasses. + + ##Tritium + Tritium is a clear, green gas that is highly flammable, radioactive, and combusts when in contact with oxygen, making it very helpful when running the [color=#a4885c]TEG[/color]. + It can be made by burning 1% Plasma and 96% or more Oxygen in the Burn Chamber (Ideal ratio is 3% Plasma to 97% Oxygen). You can extract this gas through scrubbers. + + + + + + + + + ##Frezon + Frezon is a bluish-green gas that is very complex and very dangerous. To obtain frezon, you must mix Tritium, Oxygen, and Nitrogen in a 70K room to start the reaction, and prevent the Tritium from combusting with the oxygen. + + + + + + + + + It is critical to understand that a frezon leak can devastate the station, causing a wintery hell filled with itchy sweaters and cold burns. Frezon is very cold, and can freeze the station to death if even a few moles get out, so make sure that you lock your canisters or just move your Frezon straight into a storage room. + + ## Reference Sheet + - Standard atmospheric mix is [color=#a4885c]78% N2 and 22% O2 at 101.24kPa.[/color] + - Gas obeys real math. You can use the equation: + + [color=cyan]PV = nRT[/color] + + + ([color=#a4885c]Pressure kPa * Volume L = Moles * R * Temperature K[/color]) + to derive information you might need to know about a gas. R is approximately 8.31446. diff --git a/Resources/ServerInfo/Guidebook/Engineering/Construction.xml b/Resources/ServerInfo/Guidebook/Engineering/Construction.xml index 832b831d8e4..15f2f155394 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Construction.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Construction.xml @@ -1,11 +1,11 @@ - -# Construction + + # Construction -By pressing [color=#a4885c]G[/color], one can open the construction menu, which allows you to craft and build a variety of objects. + By pressing [color=#a4885c][keybind="OpenCraftingMenu"][/color], one can open the construction menu, which allows you to craft and build a variety of objects. -When placing objects that "snap" to the grid, you can hold [color=#a4885c]shift[/color] to place an entire line at a time, and [color=#a4885c]ctrl[/color] to place an entire square at a time. + When placing objects that "snap" to the grid, you can hold [color=#a4885c]Shift[/color] to place an entire line at a time, and [color=#a4885c]Ctrl[/color] to place an entire grid at a time. -When crafting objects with a lot of ingredients, keep in mind you don't have to hold everything at once, you can simply place the ingredients on the floor or on a table near you and they'll be used up during crafting like normal. + When crafting objects with a lot of ingredients, keep in mind you don't have to hold everything at once; you can simply place the ingredients on the floor, in your backpack or on a table near you, and they'll be used up during crafting like normal. -When placing a "building ghost" somewhere in the world press [color=#a4885c]Middle Mouse Button[/color] to rotate the ghost clockwise. + When placing a "building ghost" somewhere in the world, press [color=#a4885c][keybind="EditorRotateObject"][/color] to rotate the ghost clockwise. If you are building a mirrorable component (think: Gas Mixers/Filters), you can press [color=#a4885c][keybind="EditorFlipObject"][/color] to flip the ghost. diff --git a/Resources/ServerInfo/Guidebook/Engineering/Engineering.xml b/Resources/ServerInfo/Guidebook/Engineering/Engineering.xml index 0f53ea30424..ab48ed1d827 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Engineering.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Engineering.xml @@ -1,22 +1,21 @@ -# Engineering + # Engineering -Engineering is a combination of construction work, repair work, maintaining a death machine that happens to produce power, and making sure the station contains breathable air. + Engineering is a combination of construction work, repair work, maintaining a death machine that happens to produce power, and making sure the station contains breathable air. -## Tools - - - - - - - - - - - -Your core toolset is a small variety of tools. If you're an engineer, then you should have a belt on your waist containing one of each, if not you can likely find them in maintenance and tool storage within assorted toolboxes and vending machines. - -Most tasks will have explainers for how to perform them on examination, for example if you're constructing a wall, it'll tell you the next step if you look at it a bit closer. + ## Tools + + + + + + + + + + + + Your core toolset is a small variety of tools. If you're an engineer, then you should have a belt on your waist containing one of each; if not, you can likely find them in maintenance shafts and in tool storage within assorted toolboxes and vending machines. + Most tasks will have explainers for how to perform them on examination; for example, if you're constructing a wall, it'll tell you the next step if you look at it a bit closer. diff --git a/Resources/ServerInfo/Guidebook/Engineering/Fires.xml b/Resources/ServerInfo/Guidebook/Engineering/Fires.xml index a1c54059b78..e2c83956cc6 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Fires.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Fires.xml @@ -1,15 +1,15 @@ - -# Fires & Space + + # Fires & Space -Fires and spacings are an inevitability due to the highly flammable plasma gas and endless vacuum of space present in and around the station, so it's important to know how to manage them. + Fires and spacings are an inevitability due to the highly flammable plasma gas and the endless vacuum of space present in and around the station, so it's important to know how to manage them. -## Spacing -Space is arguably the easier of the two to handle. -While it does render an area uninhabitable, it can be trivially solved by simply sealing the hole that resulted in the vacuum. After that, assuming distro vents and pipes have not been destroyed in some unfortunate accident, the room will slowly begin to repressurize. -Be aware, that active spacings will slowly siphon the air out of the station's air reserves. If you find it impossible to fix structural damage due to some other hazard - make sure to limit the airflow to that room. + ## Spacing + Space is arguably the easier of the two to handle. + While it does render an area uninhabitable, it can be trivially solved by simply sealing the hole that resulted in the vacuum. After that, assuming distro vents and pipes have not been destroyed in some unfortunate accident, the room will slowly begin to repressurize. + Be aware; active spacings will slowly siphon the air out of the station's air reserves. If you find it impossible to fix structural damage due to some other hazard, make sure to limit the airflow to that room. (Currently only half-valid due to the Gas Miners infinitely replenishing most of the useful gases) -## Fires -Fires can be dealt with through a multitude of ways, but some of the most effective methods include: - - Spacing the enflamed area if possible. This will destroy all of the gasses in the room, which may be a problem if you're already straining life support. - - Dumping a Frezon canister into the enflamed area. This will ice over the flames and halt any ongoing reaction, provided you use enough Frezon. Additionally does not result in destruction of material, so you can simply scrub the room afterwards. + ## Fires + Fires can be dealt with through a multitude of ways, but some of the most effective methods include: + - Spacing the enflamed area if possible. This will destroy all of the gasses in the room, which may be a problem if you're already straining life support. + - Dumping a Frezon canister into the enflamed area. This will ice over the flames and halt any ongoing reaction, provided you use enough Frezon. Additionally, this does not result in destruction of material, so you can simply scrub the room afterwards. diff --git a/Resources/ServerInfo/Guidebook/Engineering/NetworkConfigurator.xml b/Resources/ServerInfo/Guidebook/Engineering/NetworkConfigurator.xml index 445d182ab84..ab95dd2e29b 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/NetworkConfigurator.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/NetworkConfigurator.xml @@ -1,39 +1,40 @@ -# Network Configurator -The network configurator allows you to manipulate device lists and link devices together. - - - -The configurator has two modes: List and Link. You can press [color=gray]Alt+Z[/color] or [color=gray]Alt+Y[/color] to switch between them. + # Network Configurator + The network configurator allows you to manipulate device lists, link devices together and configure accesses for airlocks through door electronics. + + + + The configurator has two modes: List and Link. You can press [color=gray]Alt+Z[/color] or [color=gray]Alt+Y[/color] to switch between them. -## List Mode -In list mode you can click on network devices to save them on the configurator and then on a network device that has a device list like the [color=#a4885c]Air Alarm[/color]. + ## List Mode + In list mode you can click on network devices to save them on the configurator and then on a network device that has a device list like the [color=#a4885c]Air Alarm[/color]. -When clicking on a device like the Air Alarm, a UI will open displaying the list currently saved on the device and buttons to manipulate that list. + When clicking on a device like the Air Alarm, a UI will open displaying the list currently saved on the device and buttons to manipulate that list. -You can: -- Replace the current list with the one saved on the configurator -- Add the list on the configurator to the current one -- Clear the current list -- Copy the current list to the configurator -- Visualize the connections to the devices on the current list + You can: + - Replace the current list with the one saved on the configurator + - Add the list on the configurator to the current one + - Clear the current list + - Copy the current list to the configurator + - Visualize the connections to the devices on the current list -Pressing [color=gray]z[/color] or [color=gray]y[/color] opens the list saved on the configurator where you can remove saved devices. + Pressing [color=gray][keybind="ActivateItemInHand"][/color] opens the list saved on the configurator where you can remove saved devices. -## Link Mode -With link mode you can click on a device that is capable of device linking and click on any other device that is either -a sink or source. + ## Link Mode + With link mode, you can click on a device that is capable of device linking and then click on any other device that is either a sink or source. -For example, first clicking on a source like a [color=#a4885c]signal button[/color] and then on sink like a -[color=#a4885c]small light[/color] opens a UI that displays the source ports on the left side and the sink ports on the right. + For example, first clicking on a source, like a [color=#a4885c]signal button[/color], and then on sink, like a [color=#a4885c]small light[/color], opens a UI that displays the source ports on the left side and the sink ports on the right. -Now you can eiter click [color=gray]link defaults[/color] to link the default ports for a source + sink combination or press on a source and then a sink port to connect them. + Now, you can either click [color=gray]Link Defaults[/color] to link the default ports for a source + sink combination, or press on a source port and then a sink port to connect them. -An example of a default link for the aformentioned combinaton of devices would be: - - [color=cyan]Pressed 🠒 Toggle[/color] - -When you're done connecting the ports you want you can click on [color=gray]ok[/color] to close the UI. + An example of a default link for the aformentioned combinaton of devices would be: + + [color=cyan]Pressed 🠒 Toggle[/color] + + When you're done connecting the ports you want you can click on [color=gray]OK[/color] to close the UI. -You can quickly link multiple devices to their default port by first clicking on a device that can be linked and then using [color=gray]alt+left mouse button[/color] on the devices you want to link together. + You can quickly link multiple devices to their default port by first clicking on a device that can be linked and then using [color=gray]Alt+Left Mouse button[/color] on the devices you want to link together. + + ## Airlock Access + To configure an airlock's access, simply take the airlock's door electronics and interact with it using a network configurator (or multitool). Select the accesses you want, insert the door electronics into an airlock frame, and construct to finish! diff --git a/Resources/ServerInfo/Guidebook/Engineering/Networking.xml b/Resources/ServerInfo/Guidebook/Engineering/Networking.xml index 03576c789ac..90d1f0891b4 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Networking.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Networking.xml @@ -1,25 +1,24 @@ -# Networking -Some devices on the station need to communicate with each other, and they do this by utilizing device networking. -With networking machines and devices can send arbitrary data between each other. -There are multiple networks that get used, such as the wireless and wired network. -Each network device has a frequency it receives on. PDAs for example, use the frequency: [color=green]220.2[/color] + # Networking + Some devices on the station need to communicate with each other, and they do this by utilizing device networking. + With networking, machines and devices can send arbitrary data between each other. + There are multiple networks that get used, such as the wireless and wired network. + Each network device has a frequency it receives on. PDAs for example, use the frequency: [color=green]220.2[/color] -## Device Lists -Some devices need to know what other devices to communicate with specifically. - - - -Air alarms for example require you to tell it which vents, scrubbers, sensors, and firelocks to interact with. -You do that by using the Network Configurator. + Note: The following operations will require use of the Network Configurator to be performed: -## Linking -If devices basic or still more advanced but need finer control of how and what connects to each other they will generally use device linking. + ## Device Lists + Some devices need to know which other devices to communicate with specifically. - - + -With linking you can connect the outputs of a device like [color=gray]On[/color] or [color=gray]Off[/color] with the inputs of a device like the airlocks -[color=gray]Open[/color] or [color=gray]Close[/color] inputs. -The Network Configurator is also used for linking devices together. + Air alarms, for example, require you to tell it which vents, scrubbers, sensors, and firelocks to interact with. + + ## Linking + If a device, basic or advanced, needs finer controls of how and which devices it connects to, it will generally use device linking. + + + + + With linking, you can connect the outputs of a device, like [color=gray]On[/color] or [color=gray]Off[/color], with the inputs of a device, like the airlocks [color=gray]Open[/color] or [color=gray]Close[/color] inputs. diff --git a/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml b/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml index 2cf1fa44ea1..b946bf041cb 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/PortableGenerator.xml @@ -1,7 +1,7 @@ - + # Portable Generators - Need power? No engine running? The "P.A.C.M.A.N." line of portable generators has you covered. + Need power? No engines running? The "P.A.C.M.A.N." line of portable generators has you covered. @@ -16,10 +16,10 @@ - The J.R.P.A.C.M.A.N. can be found across the station in maintenance areas, and is ideal for crew to set up themselves whenever there are power issues. + The J.R.P.A.C.M.A.N. can be found across the station in maintenance shafts, and is ideal for crew to set up themselves whenever there are power issues. Setup is incredibly easy: wrench it down above an [color=green]LV[/color] power cable, give it some welding fuel, and start it up. - Welding fuel should be plentiful to find around the station. In a pinch, you can even transfer some from the big tanks with a soda can. Just remember to empty the soda can first, I don't think it likes soda as fuel. + Welding fuel should be plentiful to find around the station. In a pinch, you can even transfer some from the big tanks with a soda can or water bottle. Just remember to empty the soda can first, I don't think it likes soda as fuel. # The Big Ones @@ -33,10 +33,11 @@ - The (S.U.P.E.R.)P.A.C.M.A.N. is intended for usage by engineering for advanced power scenarios. Bootstrapping the engine, powering departments, and so on. + The (S.U.P.E.R.)P.A.C.M.A.N. is intended for usage by engineering for advanced power scenarios. Bootstrapping larger engines, powering departments, and so on. - The S.U.P.E.R.P.A.C.M.A.N. boasts larger power output and longer runtime at maximum output, but scales down to lower outputs less efficiently. + The S.U.P.E.R.P.A.C.M.A.N. boasts a larger power output and longer runtime at maximum output, but scales down to lower outputs less efficiently. - They connect directly to [color=yellow]MV[/color] or [color=orange]HV[/color] power cables, able to switch between them for flexibility. + They connect directly to [color=yellow]MV[/color] or [color=orange]HV[/color] power cables, and are able to switch between them for flexibility. + The S.U.P.E.R.P.A.C.M.A.N and P.A.C.M.A.N require uranium sheets and plasma sheets as fuel, respectively. diff --git a/Resources/ServerInfo/Guidebook/Engineering/Power.xml b/Resources/ServerInfo/Guidebook/Engineering/Power.xml index 62b38e397dd..7dd227ee9b9 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Power.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Power.xml @@ -1,53 +1,53 @@ -# Power - -SS14 has a fairly in-depth power system through which all devices on the station receive electricity. It's divided into three main powernets; HV, LV, and MV. - - - - - - -## Cabling -The three major cable types (HV, MV, and LV) can be used to form independent powernets. Examine them for a description of their uses. - - - - - - -## Power storage -Each power storage device presented functions as the transformer for its respective power level (HV, MV, and LV) and also provides a fairly sizable backup battery to help flatten out spikes and dips in power usage. - - - - - - -## Ramping -Contrary to what one might expect from a video game electrical simulation, power is not instantly provided upon request. Generators and batteries take time to ramp up to match the draw imposed on them, which leads to brownouts when there are large changes in current draw all at once, for example when batteries run out. - -## Installing power storage -Substations are the most self-explanatory. Simply install the machine on top of an MV and HV cable, it will draw power from the HV cable to provide to MV. - -Installing APCs is similarly simple, except APCs are exclusively wallmounted machinery and cannot be installed on the floor. Make sure it has both MV and LV connections. - -Installing a SMES requires you construct a cable terminal to use as the input. The SMES will draw power from the terminal and send power out from underneath. The terminal will ensure that the HV input and HV output do not connect. Avoid connecting a SMES to itself, this will result in a short circuit which can result in power flickering or outages depending on severity. - -## APC breaking -Currently the only power storage device that has a limit to its power network is APC. As soon as all connected devices and machinery demand more than [color=#a4885c]24kW[/color] it's breaker will pop and everything will turn off. - - - - -## Checking power grid -1. Use the [color=#a4885c]t-ray scanner[/color] in order to locate cables that are hidden under tiles. (skip this step if cables aren't hidden) -2. Pry open the tile that is blocking your access to the cable with a [color=#a4885c]crowbar[/color]. (skip this step if cables aren't hidden) -3. Equip your trusty [color=#a4885c]Multitool[/color] and click on any cable to see powergrid stats. - - - - - + # Power + + SS14 has a fairly in-depth power system through which all devices on the station receive electricity. It's divided into three main powernets; High Voltage, Medium Voltage, and Low Voltage. + + + + + + + ## Cabling + The three major cable types (HV, MV, and LV) can be used to form independent powernets. Examine them for a description of their uses. + + + + + + + ## Power storage + Each power storage device presented functions as the transformer for its respective power level (HV, MV, and LV), and also provides a fairly sizable backup battery to help flatten out spikes and dips in power usage. + + + + + + + ## Ramping + Contrary to what one might expect from a video game electrical simulation, power is not instantly provided upon request. Generators and batteries take time to ramp up to match the draw imposed on them, which leads to brownouts when there are large changes in current draw all at once; for example, when batteries run out. + + ## Installing power storage + Substations are the most self-explanatory. Simply install the machine on top of an MV and HV cable; it will draw power from the HV cable to provide to MV. + + Installing APCs is similarly simple, except APCs are exclusively wallmounted machinery and cannot be installed on the floor. Make sure it has both MV and LV connections. + + Installing a SMES requires you construct a cable terminal to use as the input. The SMES will draw power from the terminal and send power out from underneath. The terminal will ensure that the HV input and HV output do not connect. Avoid connecting a SMES to itself; this will result in a short circuit, which can result in power flickering or outages depending on severity. + + ## APC breaking + Currently the only power storage device that has a limit to its power to the network is the APC. As soon as all connected devices and machinery demand more than [color=#a4885c]24kW[/color] of power, its breaker will pop and everything will turn off. In the case that you are not an engineer, call an engineer (or cyborg) to re-enable it, after reducing the load back down to [color=#a4885c]below[/color] 24kW. + + + + + ## Checking the power grid + 1. Use the [color=#a4885c]t-ray scanner[/color] in order to locate cables that are hidden under tiles. (skip this step if cables aren't hidden) + 2. Pry open the tile that is blocking your access to the cable with a [color=#a4885c]crowbar[/color]. (skip this step if cables aren't hidden) + 3. Equip your trusty [color=#a4885c]Multitool[/color] and click on any cable to see the power-grid stats. + + + + + diff --git a/Resources/ServerInfo/Guidebook/Engineering/RTG.xml b/Resources/ServerInfo/Guidebook/Engineering/RTG.xml index 1d71ee9144b..6149b580494 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/RTG.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/RTG.xml @@ -1,17 +1,20 @@ -# Radioisotope Thermoelectric Generator (RTG) + # Radioisotope Thermoelectric Generator (RTG) - - - - + + + -Making power using a Radioisotope Thermoelectric Generator (RTG) is similar to making power using solar. -RTGs only provide 10 kW of power, but they provide it for free and for the entire round. -Basically, if you connect an RTG to your power grid, it'll give you free power. + Making power using a Radioisotope Thermoelectric Generator (RTG) is similar to making power using solars. + RTGs only provide [color=#a4885c]10kW[/color] of power, but they provide it for free and for the entire round. + Basically, if you connect an RTG to your power grid, it'll give you [color=#a4885c]free power[/color]. + However, they're only accessible through salvage finding one on an expedition. Should they bring some in, make sure to thank them! -Sometimes, RTGs are damaged. -Damaged RTGs behave just like regular ones, but they're radioactive. -That means they're more dangerous, but on the bright side, you can put radiation collectors next to them to turn that radiation into more power. - - \ No newline at end of file + + + + Sometimes, RTGs appear damaged. + Damaged RTGs behave just like regular ones, but they're [color=yellow]radioactive[/color]. + That means they're more dangerous, but on the bright side, you can put radiation collectors next to them to turn that radiation into more power. + This is usually more worthwhile, considering the power is still free, so long as you can find a safe spot to put the RTG(s) in. + diff --git a/Resources/ServerInfo/Guidebook/Engineering/Shuttlecraft.xml b/Resources/ServerInfo/Guidebook/Engineering/Shuttlecraft.xml index 7e743ddd685..21956d600cb 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Shuttlecraft.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Shuttlecraft.xml @@ -1,40 +1,39 @@ -# Shuttle-craft + # Shuttle-craft -Shuttle construction is simple and easy, albeit rather expensive and hard to pull off within an hour. It's a good activity if you have a significant amount of spare time on your hands and want a bit of a challenge. + Shuttle construction is simple and easy, albeit rather expensive and hard to pull off within an hour. It's a good activity if you have a significant amount of spare time on your hands and want a bit of a challenge. -## Getting started -Required parts: - - - - - - - - - - - - - + ## Getting started + Required parts: + + + + + + + + + + + + + -Optional parts: - - - - - - - - - - + Optional parts: + + + + + + + + + + -Head out into space with steel sheets and metal rods in hand, and once you're three or more meters away from the station, click near or under you with the rods in hand. This will place some lattice, which can then be turned into plating with the steel sheets. Expand your lattice platform by clicking just off the edge with rods in hand. + Head out into space with steel sheets and metal rods in hand, and once you're three or more tiles away from the station, click near or under you with the rods in hand. This will place some lattice, which can then be turned into plating with steel sheets or floor tiles. Expand your lattice platform by clicking just off the edge with some rods in hand. -From there, once you have the shape you want, bring out and install thrusters at the edges. They must be pointing outward into space to function and will not fire if there's a tile in the way of the nozzle. Install a gyroscope where convenient, and use your substation and generator to set up power. Construct a wall on top of an MV cable and then install an APC on that to power the devices onboard. - -Finally, install the shuttle computer wherever is convenient and ensure all your thrusters and gyroscopes are receiving power. If they are, congratulations, you should have a functional shuttle! Making it livable and good looking is left as an exercise to the reader. + From there, once you have the shape you want, bring out and install thrusters at the edges. They must be pointing outward into space to function and will not fire if there's a tile in the way of the nozzle. Install a gyroscope where convenient, and use your substation and generator to set up power. Construct a wall on top of an MV cable and then install an APC on that to power the devices onboard. + Finally, install the shuttle computer wherever is convenient and ensure all your thrusters and gyroscopes are receiving power (remember to wire the MV and LV networks!). If they are; congratulations, you should have a functional shuttle! Making it livable and good looking is left as an exercise to the reader. diff --git a/Resources/ServerInfo/Guidebook/Engineering/Singularity.xml b/Resources/ServerInfo/Guidebook/Engineering/Singularity.xml index 3553d43e6fc..3c0dd665e25 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/Singularity.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/Singularity.xml @@ -1,109 +1,141 @@ -# Gravitational Singularity Engine - -The Gravitational Singularity Engine can yield infinite power, with no fueling required. It can also destroy the whole station with equal ease. It uses a Particle Accelerator to fire high energy particles at a Singularity Generator to form a singularity. The singularity then pulses radiation which is absorbed by Radiation Collectors. - -## Setting it up - -The Gravitational Singularity Engine requires 4 subsystems to work properly: - -## Gravitational singularity generator - - - -The generator should be anchored at the center of the containment area since this is where the singularity will appear at. - -## Containment field generators and emitters - - - - - -The emitters connect to MV cables and fire lasers as long as they have power and are turned on. -Fire emitters at containment field generators to activate them. -If two containment field generators are active, in range and in the same cardinal axis, a containment field will appear. -The containment field will repell the singularity, keeping it from escaping, and yield a little bit of power every time anything bounces off of them. -Emitter lasers and containment field can cause damage, avoid touching them when active. - -## Radiation collectors - - - - -They connect to HV cables and generate power from nearby radiation sources when turned on. -Radiation collectors require a tank full of gaseous plasma in order to operate. -Continous radiation exposure will gradually consume the stored plasma, so replace depleted tanks with fresh ones to maintain a high power output. - -## Particle accelerator - - - - - - - - - - - - - - - - - - - - - -The Particle Accelerator (PA) is a multi-tile structure that launches accelerated particles from its emitters. Its emitters should always face the gravitational singularity generator. -Some stations already have an unfinished PA. To complete, first ensure there is MV cable beneath the PA power box, anchor all parts, then add LV cable to each part. - - - -Then use a screwdriver to screw back the panels. -Scan parts using the PA control computer to check if it's operational. If it shows up as incomplete, examine for what's missing. - - - - -## Turing on the Gravitational Singularity Engine - -[color=#a4885c]Do not[/color] turn the PA on unless all other subsystems are working properly. - -Turn power on using the PA control computer. Set strength to an appropiate level. Currently the only appropriate level is [color=#f0684d]1[/color], anything above that will ensure that singularity grows too strong to handle. -The higher the output stength is set on PA control computer, the bigger the singularity will be. - -The PA will now draw power from the power net and start firing particles at the Gravitational singularity generator. - - - - - - - -A singularity will soon appear at the position of the Gravitational singularity generator. - - - - -If no particle is hitting the singularity generator, the singularity will start to slowly decay until it disappear. - -## Safety -Singularity emits radiation around it, so always keep a distance. Consider getting radiation shielding gear beforehand. Seek medical attention if experiencing health issues. - - - - - - - - - - - -A singularity might move around, but the containment field will repel it. -If a singularity escapes its containment field, often referred to as a "singuloose," it will attract and then consume everything in its way. - -In such circumstances, there is little to be done other than running in the opposite direction. + # Singularity / Tesla Engine + + The Singularity Engine / Tesla Engine can yield [color=#a4885c]infinite power[/color], with no fueling required. It can also [color=red]destroy the whole station[/color] with equal ease. It uses a Particle Accelerator to fire high energy particles at a Singularity Generator to form a singularity or ball lightning. + The singularity then pulses radiation which is absorbed by Radiation Collectors, or the ball lightning then zaps nearby tesla coils and grounding rods to provide power. + + # Setting it up + + Both engines requires 4 subsystems to work properly; two are shared between both engines: + + ## Containment field generators and Emitters + + + + + + The emitters connect to MV cables and fire lasers as long as they have power and are turned on. + Fire the emitters at enabled containment field generators to activate them. + If two containment field generators are active, in range and are in the same cardinal axis, a containment field will appear. + The containment field will repel the singularity or tesla, keeping it from escaping, and yield a little bit of power every time anything bounces off of them. + + The emitter lasers and the containment fields can also cause damage and/or cause you to be sent flying into deep space; [color=#a4885c]avoid touching them[/color] when active. + It is recommended to [color=#a4885c]lock the emitters[/color] with [keybind="AltActivateItemInWorld"/], to prevent any break-in no-gooders from loosing the singularity or tesla by simply switching off the field. + + Teslas can have significantly smaller containment fields than singularity containment fields; adjusting field size is recommended, as the tesla becomes easier to keep watch on in a simply 3x3 field setup. + + ## Particle accelerator + + + + + + + + + + + + + + + + + + + + + + The Particle Accelerator (PA) is a multi-tile structure that launches accelerated particles from its emitters. Its emitters should always face the generator. + Some stations already have an unfinished PA. To complete it, first ensure there is a MV cable beneath the PA power box, anchor all the parts, and then add an LV cable to each part. + + + + Then use a screwdriver to screw back the panels. + [color=#a4885c]Scan parts[/color] using the PA control computer to check if it's operational (the PA will not function if you do not scan it!). If it shows up as incomplete, examine what's missing. + + + + + The other two subsystems are unique to each other: + + ## Gravitational singularity generator or Ball lightning generator + + + + + The generator should be anchored at the center of the containment area, since this is where the singularity/tesla should appear at. + + ## Radiation collectors or Tesla coils + + + + + The radition collectors connect to HV cables and generate power from nearby radiation sources when turned on. + Radiation collectors require a tank full of gaseous plasma in order to operate. + Continous radiation exposure will gradually convert the stored plasma into tritium, so replace depleted plasma tanks with fresh ones regularly to maintain a high power output. + + + + + + The tesla coils connect to HV cables and provide a stream of power after being zapped by the ball lightning. + However, tesla coils usually do not fully absorb the lightning strike, and the grounding rods are required to prevent lighting from arcing to and obliterating nearby machines. + Do note that one grounding rod is not a foolproof solution; get [color=#a4885c]atleast 4 rods[/color] around the containment field to make it mathematically unlikely for the tesla to escape. + As the ball lightning zaps tesla coils, they will degrade from wear; make sure to [color=#a4885c]weld them[/color] every now and then to keep generating power. + + ## Turing on the Engines + + [color=red]Do not[/color] turn the PA on unless all the other subsystems are working properly and there is enough power to start the engine. + + Turn power on using the PA control computer. Set the strength to an appropiate level. Currently the only appropriate level is [color=#f0684d]1[/color]; anything above that will ensure that singularity grows too strong to handle. + The higher the output stength is set on PA control computer, the bigger the singularity will be. + + Currently, the output power does not affect the ball lightning, beyond giving the ball lightning extra orbs around it. + + The PA will now draw power from the power net and start firing particles at the generators. + + + + + + + + A singularity or ball lightning will soon appear at the position of the Gravitational singularity generator. + + + or + + + + If no particles are hitting the singularity, the singularity will start to slowly decay until it disappears. + This is not the case for the tesla; feel free to disconnect the PA after the tesla has been set up. + + ## Safety + The singularity emits a large amount of radiation around it, so always keep a distance from it. Consider getting [color=yellow]radiation shielding gear[/color] beforehand. Seek medical attention if you are experiencing health issues. + + + + + + + + + + + + The singularity might move around, but the containment field will repel it. + + The tesla creates large bolts of lightning around it, so make sure to wear insuls before approaching it. If you aren't, and it zaps you, pray that the ball lightning doesn't stunlock you and eventually send you into crit. + + + + If a singularity or tesla escapes its containment field, often referred to as a "singuloose" or "tesloose" respectively, it will attract and then consume everything in its way, growing larger as it does so, or it will begin to obliterate every machine in its path, and shock all crew personnel. + + In such circumstances, there is little to be done other than running in the opposite direction. + + + + However, if science has happened to research [color=#D381C9]Portable Particle Decelerators[/color], or if cargo can order them in time, you may be able to stop the singularity from eating the whole station. + Good luck on the tesla, though; it is merely too powerful to recontain after breaching. diff --git a/Resources/ServerInfo/Guidebook/Engineering/TEG.xml b/Resources/ServerInfo/Guidebook/Engineering/TEG.xml index 9e8697a9e13..63a62fecf80 100644 --- a/Resources/ServerInfo/Guidebook/Engineering/TEG.xml +++ b/Resources/ServerInfo/Guidebook/Engineering/TEG.xml @@ -19,25 +19,25 @@ Note that the circulators are [color=#a4885c]directional[/color]: they will only let gas through one way. You can see this direction in-game by examining the circulator itself. A pressure difference is required across the input and output, so pumps are generally provided and must be turned on. - There is no preference for which side must be hot or cold, there need only be a difference in temperature between them. The gases in the two "loops" are never mixed, only energy is exchanged between them. The hot side will cool down, the cold side will heat up. + There is no preference for which side must be hot or cold, there need only be a difference in temperature between them. The gases in the two "loops" are never mixed, [color=#a4885c]only energy is exchanged between them[/color]. The hot side will cool down, the cold side will heat up. ## The Pipes - There are 2 major pipenets to worry about here: The Hot Loop (where gas will be burnt for heat), and The Cold Loop (where circulated, heated waste gas will either be removed into space or cooled back down). Make sure that [bold]both pipenets do NOT mix[/bold], as only heat should be transferred between the two through the TEG. + There are 2 major pipenets to worry about here: [color=red]The Hot Loop[/color] (where gas will be burnt for heat), and [color=cyan]The Cold Loop[/color] (where circulated, heated waste gas will either be removed into space or cooled back down). Make sure that [color=#a4885c][bold]both pipenets do NOT mix[/bold][/color], as only heat should be transferred between the two through the TEG. # The Hot Loop As I'm sure a wise person once said: the best way to make something hot is to light it on fire. Well, depending on context, that may not be very wise, but luckily your engineering department has just what's needed to do it wisely after all. - As stated above, there are many different layouts one can follow to heat up (or cool down) gases; this part of the guide will cover 2 common methods one will often see for the hot loop when the TEG is setup: The Pipe Burn, and the Burn chamber. + As stated above, there are many different layouts one can follow to heat up (or cool down) gases; this part of the guide will cover 2 common methods one will often see for the hot loop when the TEG is setup: [color=#a4885c]The Pipe Burn[/color], and [color=red]the Burn Chamber[/color]. - Side note: Plasma fires burn relatively cool compared to, for example, Tritium fires. It may be viable to extract Tritium from an extraction setup (using a 97/3 ratio of O2/Plasma) and react it with Oxygen to get truly hellish temperatures for power. Although, this is just a recommendation; I'm not ya mum. + Side note: Plasma fires burn relatively cool compared to, for example, Tritium fires. It may be viable to extract Tritium from an extraction setup (using a 96/4 ratio of O2/Plasma) and react it with Oxygen to get truly hellish temperatures for power. Although, this is just a recommendation; I'm not ya mum. ## The Pipe Burn Also known as the naive method, this is generally discouraged when working for efficiency. However, if all you need is a smidge of power to run the station, and you don't feel like setting up the burn chamber, this method will do. - TODO: Remove this section when atmos pipes are updated to have pressure/temperature limits in a future atmos refactor. + [color=#444444]TODO: Remove this section when atmos pipes are updated to have pressure/temperature limits in a future atmos refactor.[/color] Most (if not all) pipe burns follow this general layout: @@ -55,8 +55,8 @@ - The Gas input is pretty self-explanatory; this is where you will input the O2-Plasma mix to be burnt. A 2:1 (67/33) ratio of Oxygen to Plasma is recommended for the hottest burn. - The High-pressure pump serves 2 purposes; first, it prevents the burn from backwashing into the supply pipe, which would be.. bad, for many reasons. Second, it maintains a positive pressure in the following pipe segment, which is important to allow the burn to continue, especially since hot gases expand. - - The Pipe segment is where the burn actually occurs; to start it off, one can use a heater to increase the temperature up to the ignition temperature of Plasma. Afterwards, the reaction should be self-sustaining, so long as the Pressure and Moles supplied remains high enough. Be warned; if you wish to remove the heater, it will carry some of this superheated gas with it, transferring it to the next pipenet you connect it to. Best to space the gas through a space vent, if you must. - - The Low-pressure pump (whose pressure should be [italics]slightly lower[/italics] than the input pump) prevents [italics]all[/italics] the gas from passing through the circulator, which could result in the loss of the Moles required to sustain a burn. + - The Pipe segment is where the burn actually occurs; to start it off, one can use a heater to increase the temperature up to the ignition temperature of Plasma. Afterwards, the reaction should be self-sustaining, so long as the Pressure and Moles supplied remains high enough. [color=#a4885c]Be warned[/color]; if you wish to remove the heater, it will carry some of this superheated gas with it, transferring it to the next pipenet you connect it to. Best to space the gas through a space vent, if you must. + - The Low-pressure pump (whose pressure should be [italic]slightly lower[/italic] than the input pump) prevents [italic]all[/italic] the gas from passing through the circulator, which could result in the loss of the Moles required to sustain a burn. - The Circulator is where this generated heat will flow to the cold loop; afterwards, feel free to space the waste gases. Note: Pressure pumps are used here as, while they pump on pressure (not flow-rate, which is comparatively faster), they are a bit easier to control when it comes to the limited Plasma supply on-station. However, the steps shown can be followed with volumetric pumps too. @@ -68,25 +68,53 @@ Most (if not all) stations have the burn chamber separated from the main atmospherics block by a 1-wide spaced grid, presumably to prevent conduction. The chambers consist of 3(+1) important parts: - The Air Injector/Passive Vent - The Space Vent - - The Radiator Loop + - The Scrubber Array + + Here is one layer of an example setup: (pipes can and do need to be layered under the scrubbers below to connect them!) + + + + + + + + + + + + + + + + + + + + + + + + + + + + - Most normal burn chambers don't come with Heat-Exchangers; instead, they have air scrubbers (and optionally, an air alarm) to help filter for Tritium, which is a highly reactive, hot-burning gas that can also be used to heat the TEG efficiently. - However, this is a slightly more advanced setup than just burning plasma, as it needs 2 burn chambers instead of 1 (one for tritium production, one for burning said tritium), so remove the scrubbers and retrofit the burn chamber with a parallel array of heat-exchangers instead. - The air injector (or Passive Vent) injects air (or allows air to flow) into the burn chamber. Either should be supplemented with a pump before it, to keep pressures high. - There is a notable difference between the passive vent and the air injector; the air injector can only keep injecting air up to 9MPa, which can be reached very easily with a good burn. Ideally, switch out the air injector for a passive vent connected to a volume pump. + There is a notable difference between the passive vent and the air injector; the air injector can only keep injecting air up to [color=#a4885c]9MPa[/color], which can be reached very easily with a good burn. Ideally, switch out the air injector for a passive vent connected to a volume pump. + + The space vent (designated as a blast door to space on one side of the burn chamber) allows waste gases to be expelled and destroyed. Open this every now and then to keep the pressure under control, or to space excess input gas. - The space vent (designated as a blast door to space on one side of the burn chamber) allows waste gases to be expelled and destroyed. Open this to keep the pressure under control. + The scrubber array filters out all the burnt gasses and sends them through the TEG. Note that using default settings on the scrubbers is a bad idea, as valuable plasma will be filtered out too. + Instead, use a network configurator to connect all the scrubbers to a nearby air alarm, and set the air alarm's scrubber settings to scrub everything except Oxygen and Plasma, and to siphon air aswell. This ensures that as much heat as available can be collected and sent to the TEG. - The radiator loop collects heat from the burnt gases and brings it to the TEG. To maximize efficiency, hook up the heat-exchangers [italics]in parallel to each other[/italics], with a pressure pump at max pressure after the array and a volumetric pump before the array. - The pressure of the volumetric pump should be set to ( 200 / number of heat-exchangers ) L/s. For example, having 2 heat-exchangers would mean you should set the pressure to 100 L/s. - Finally, fill the whole loop with (ideally) a high heat capacity gas, like Frezon or Plasma. (Yes, Frezon =/= Cold. Frezon has one of the highest heat capacities in the game; so long as it isn't reacting with Nitrogen, it can actually be heated and can store heat really well!) + Note that these are just two of many ways you can setup the hot loop; [color=#a4885c]feel free to mix and match setups as needed![/color] Volume pumps in replacement of pressure pumps, radiator loops for heat collection, or even a Pyroclastic anomaly to provide said heat! The stars are the limit! # The Cold Loop As with the Hot Loop, the Cold Loop must also be setup in order to operate the TEG. However, the Cold Loop is usually a lot more low-tech than the Hot Loop; in reality, the Cold Loop only has to be "relatively" cooler -- hey, room temperature is technically cooler than the surface of the sun, right? - There are 3 main methods you will see used for the Cold Loop: The Water Cooler (see: Liltenhead's video on the TEG), the Coolant Array and the Freezer Loop. + There are 3 main methods you will see used for the Cold Loop: [color=#a4885c]The Water Cooler[/color] (see: Liltenhead's video on the TEG), [color=cyan]the Coolant Array[/color] and [color=#a4885c]the Freezer Loop[/color]. ## The Water Cooler @@ -103,14 +131,17 @@ - TODO: Remove this section when gas miners are removed in a future atmos refactor. + [color=#444444]TODO: Remove this section when gas miners are removed in a future atmos refactor.[/color] ## Coolant Array - This is the default method for the Cold Loop you will see on a variety of stations. Being of moderate complexity and having no losses of any resource, this [italics]should[/italics] be the main method of cooling down the TEG. However, every station at the moment somehow has their heat exchangers hooked up wrong, reducing efficiency greatly. (Thanks a bunch, NT!) + This is the default method for the Cold Loop you will see on a variety of stations. Being of moderate complexity and having no losses of any resource, this [color=#a4885c]should[/color] be the main method of cooling down the TEG. However, most stations at the moment somehow have their heat exchangers hooked up wrong (or suggest incorrect piping), reducing efficiency greatly. [color=#444444](Thanks a bunch, NT!)[/color] - To use heat-exchangers properly, they must be setup in [italics]parallel[/italics], not in series (like what you see on most stations). A gas pump at max pressure should be placed after, and a volumetric pump before the heat-exchangers. - The flow-rate of the volumetric pump should be set to ( 200 / number of heat-exchangers ) L/s. + To use heat-exchangers properly, they must be setup in [color=#a4885c]parallel[/color], not in series (like what you see on most stations). A gas pump at max pressure should be placed after, and a volumetric pump before the heat-exchangers. + The flow-rate of the volumetric pump should be set using the following formula: + + [color=cyan]( 200 / number of heat-exchangers )[/color] L/s. + Simply speaking, the Coolant Array consists of 3 major parts: An input connector port, a few pumps and the heat-exchanger array out in space. It can be setup like so: @@ -161,7 +192,7 @@ - Connector Port: Use this to input a gas with high heat capacity; most of the time, Plasma or Frezon is used to do so, as they both have very high specific heat capacities (although most any gas will do). (Yes, Plasma =/= Hot. You can cool it down, and it acts as a really good heat exchange medium.) - Input/Output Pumps: Used to make sure gas keeps flowing through both the Circulator and the Heat-Exchanger array. As the gas cools down and heats up (and as it flows through the Exchanger), pressure must be applied for it to keep flowing. - - Heat-Exchanger: Basically, just a bunch of heat-exchanger pipes in space. Not much to say, besides the fact that it cools down the gas inside it. Make sure the heat-exchangers are placed on lattice, not plating! Otherwise, the heat-exchange efficiency will be greatly reduced, as the heat-exchangers aren't directly exposed to space below them. + - Heat-Exchanger: Basically, just a bunch of heat-exchanger pipes in space. Not much to say, besides the fact that it cools down the gas inside it. Make sure the heat-exchangers are [color=#a4885c]placed on lattice, not plating[/color]! Otherwise, the heat-exchange efficiency will be greatly reduced, as the heat-exchangers aren't directly exposed to space below them. ## The Freezer Loop diff --git a/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml b/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml index ef6e1a49e87..f70f43c8a8b 100644 --- a/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml +++ b/Resources/ServerInfo/Guidebook/Medical/Cryogenics.xml @@ -12,7 +12,7 @@ Cryogenics can be a bit daunting to understand, but hopefully, quick run through - + diff --git a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml index fc72c60dbf4..0374d4cb958 100644 --- a/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml +++ b/Resources/ServerInfo/Guidebook/Mobs/SlimePerson.xml @@ -10,7 +10,21 @@ They exhale nitrous oxide and are unaffected by it. Their body can process 6 reagents at the same time instead of just 2. - Their Slime "blood" can not be regenerated from Iron. Slime Blood is technically a source of + Slimepeople can morph into a [bold]"geras"[/bold] (an archaic slimefolk term), which is a smaller slime form that can [bold]pass through grilles[/bold], + but forces them to drop their inventory and held items. It's handy for a quick getaway. A geras is small enough to pick up (with two hands) + and fits in a duffelbag. + + + + + + Slimepeople have an [bold]internal 2x2 storage inventory[/bold] inside of their slime membrane. Anyone can see what's inside and take it out of you without asking, + so be careful. They [bold]don't drop their internal storage when they morph into a geras, however![/bold] + + Slimepeople have slight accelerated regeneration compared to other humanoids. They're also capable of hardening their fists, and as such have stronger punches, + although they punch a little slower. + + Their slime "blood" can not be regenerated from Iron. Slime Blood is technically a source of moderately filling food for other species, although drinking the blood of your coworkers is usually frowned upon. They suffocate 80% slower, but take pressure damage 9% faster. This makes them by far the species most capable to survive in hard vacuum. For a while. diff --git a/Resources/ServerInfo/Guidebook/Science/ArtifactReports.xml b/Resources/ServerInfo/Guidebook/Science/ArtifactReports.xml index a377c980e55..5aaa9ba34ac 100644 --- a/Resources/ServerInfo/Guidebook/Science/ArtifactReports.xml +++ b/Resources/ServerInfo/Guidebook/Science/ArtifactReports.xml @@ -1,25 +1,24 @@ -# Artifact Reports -A large portion of Xenoarchaeology gameplay revolves around the interpretation of artifact reports, which are created at the [color=#a4885c]analysis console[/color] after an artifact is scanned. Reports contain the following information: + # Artifact Reports + A large portion of Xenoarchaeology gameplay revolves around the interpretation of artifact reports, which are created at the [color=#a4885c]analysis console[/color] after an artifact is scanned. Reports contain the following information: -- [color=#a4885c]Node ID:[/color] a unique numeric ID corresponding to this artifact's node. Useful in conjunction with a [color=#a4885c]node scanner[/color] for quickly identifying recurring nodes. + - [color=#a4885c]Node ID:[/color] a unique numeric ID corresponding to this artifact's node. Useful in conjunction with a [color=#a4885c]node scanner[/color] for quickly identifying recurring nodes. -- [color=#a4885c]Depth:[/color] a distance from the starting node (depth 0). This is a good shorthand for the value and danger of a node. + - [color=#a4885c]Depth:[/color] a distance from the starting node (depth 0). This is a good shorthand for the value and danger of a node. -- [color=#a4885c]Activation status:[/color] whether or not a node has been activated in the past. + - [color=#a4885c]Activation status:[/color] whether or not a node has been activated in the past. -- [color=#a4885c]Stimulus:[/color] the stimulus for that particular node. + - [color=#a4885c]Stimulus:[/color] the stimulus for that particular node. -- [color=#a4885c]Reaction:[/color] the reaction the stimulus induces. This is often vague, so caution is advised. + - [color=#a4885c]Reaction:[/color] the reaction the stimulus induces. This is often vague, so caution is advised. -- [color=#a4885c]Edges:[/color] the amount of nodes that are connected to the current node. Using this, you can calculate the total number of nodes as well as organize a map of their connections. + - [color=#a4885c]Edges:[/color] the amount of nodes that are connected to the current node. Using this, you can calculate the total number of nodes as well as organize a map of their connections. -- [color=#a4885c]Current value:[/color] the amount of research points an artifact is currently worth. Extracting will set this to zero and traversing new nodes will increase it. - -Reports are a helpful tool in manipulating an artifact, especially in the later stages where you are traversing nodes that have already been activated. - - - -To help with this process, consider printing out reports, writing down details uncovered during activation, or storing them in a folder nearby. + - [color=#a4885c]Current value:[/color] the amount of research points an artifact is currently worth. Extracting will set this to zero and traversing new nodes will increase it. + Reports are a helpful tool in manipulating an artifact, especially in the later stages where you are traversing nodes that have already been activated. + + + + To help with this process, consider printing out reports, writing down details uncovered during activation, or storing them in a folder nearby. diff --git a/Resources/ServerInfo/Guidebook/Science/Xenoarchaeology.xml b/Resources/ServerInfo/Guidebook/Science/Xenoarchaeology.xml index 8cd94e8526d..b42b8de5306 100644 --- a/Resources/ServerInfo/Guidebook/Science/Xenoarchaeology.xml +++ b/Resources/ServerInfo/Guidebook/Science/Xenoarchaeology.xml @@ -2,18 +2,28 @@ # Xenoarchaeology Xenoarchaeology is a epistemics subdepartment focused on researching and experimenting on alien artifacts. -## Artifacts +At the start of each shift, the Science department will usually have access to at least two artifacts to experiment on. You can buy more by talking to the Cargo department. + +By researching the unique things each artifact can do, you gain Research Points, increase the artifact's sale value, and potentially discover a useful ability or two that can help your department or the whole station! + +## Artifact Nodes -Artifacts consist of a randomly-generated graph structure. They consist of nodes connected to each other by edges, the traversal of which is the main goal of the scientists working on them. +Artifacts consist of a randomly-generated tree of nodes. These nodes have a "[color=#a4885c]depth[/color]", representing how dangerous the node is, and the number of other nodes connected to it, called "[color=#a4885c]edges[/color]", + +Artifacts always start at depth zero, the root of the tree. Travelling the tree to find as many nodes as possible is the main goal of the scientists working on them. Knowledge is extracted from nodes to gain Research Points and increase the artifact's sale value. + +Each node has two components: its [color=#a4885c]stimulus[/color] and a [color=#a4885c]reaction[/color]. + +A stimulus is the external behavior that triggers the reaction. There's a variety of these, and higher depth nodes have more difficult to accomplish stimuli. Some stimuli will need improvisation to trigger, and you may need to talk to other departments to get everything you need. -Each node has two main components: a [color=#a4885c]stimulus[/color] and a [color=#a4885c]reaction[/color]. A stimulus is the external behavior that triggers the reaction. Some reactions are instantaneous effects while others are permanent changes. Triggering the reaction causes the artifact to move to one of the node's edges. +Some reactions are instantaneous effects while others are permanent changes. Once an artifact is triggered, the reaction causes the artifact to randomly move to another node it is linked to. -With these basic principles, you can begin to grasp how the different nodes of an artifact are interconnected, and how one can move between them by repeatedly activating nodes. +With some experimental science, you can begin to grasp how the different nodes of an artifact are connected, and how to move between them by repeatedly activating nodes. -While it might seem random to an untrained eye, a skilled scientist can learn to understand the internal structure of any artifact. +All non-zero-depth nodes will have exactly one edge that leads up to its parent node. All other edges a node has lead down to the next depth. ## Artifact Analyzer and Analysis Console @@ -22,13 +32,26 @@ While it might seem random to an untrained eye, a skilled scientist can learn to The main equipment that you'll be using for Xenoarchaeology is the [color=#a4885c]artifact analyzer[/color] and the [color=#a4885c]analysis console[/color]. You can use these to create reports that contain valuable information about an artifact. -To set them up, simply link them with a network configurator, set an artifact on top of the analyzer, and press the [color=#a4885c]Scan[/color] button. +To set them up, simply link them with a network configurator and set an artifact on top of the analyzer. Every station has at least one of these machines already set up. -Using the console, you can extract points from the artifact using the [color=#a4885c]Extract[/color] button. The amount of points you extract is based on how many new nodes have been activated, since last extracting. You can extract multiple times, there is no reason not to!!! +Use the console's [color=#a4885c]scan[/color] button to discover what stimulus the artifact needs and what its reaction will do. Scanning takes thirty seconds. + +Use the [color=#a4885c]print[/color] button to save the scan result, so you can refer to it later. + +Once you've discovered a new node, you can extract points from the artifact using the [color=#a4885c]Extract[/color] button. ## Assembling Artifacts -It is possible to gather multiple artifact fragments and assemble them into a working artifact. You can ask for these from Salvage, they usually find these while mining asteroids or on Expeditions. +It is possible to gather multiple artifact fragments and assemble them into a working artifact. You can ask for these from Salvage, who usually find these while mining asteroids or on Expeditions. + +## Traversal Bias + + + +Artifacts placed on top of a powered artifact analyzer are subjected to a bias which affects which node they will move to after being activated. The bias can be set in the artifact console. +There are two types of biases: +- [color=#a4885c]Up:[/color] favors nodes closer to the origin. Results in a decrease of depth. +- [color=#a4885c]Down:[/color] favors nodes farther away from the origin. Results in an increase of depth. diff --git a/Resources/ServerInfo/Guidebook/Security/Forensics.xml b/Resources/ServerInfo/Guidebook/Security/Forensics.xml index 2189488c6b2..3eb53b1e9ac 100644 --- a/Resources/ServerInfo/Guidebook/Security/Forensics.xml +++ b/Resources/ServerInfo/Guidebook/Security/Forensics.xml @@ -1,4 +1,4 @@ - + # Forensics There are a lot of tools to help you gather and examine the evidence at your disposal @@ -40,7 +40,7 @@ ## Fibers Whenenever people wearing gloves touch anything on the station, they are bound to leave behind some fibers. This complicates things, but nothing is unsolvable for a real detective. - There are up to [color=red]16[/color] different types of fibers possible. Can that stop you from solving the case? + There are up to [color=red]25[/color] different types of fibers possible. Can that stop you from solving the case? diff --git a/Resources/ServerInfo/Guidebook/Service/Bartender.xml b/Resources/ServerInfo/Guidebook/Service/Bartender.xml index 060c39fca31..b7599fc0d1c 100644 --- a/Resources/ServerInfo/Guidebook/Service/Bartender.xml +++ b/Resources/ServerInfo/Guidebook/Service/Bartender.xml @@ -18,6 +18,7 @@ Don't forget containers to serve them in! + ## Drinks diff --git a/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/equipped-EYES.png b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/equipped-EYES.png new file mode 100644 index 00000000000..84979d10972 Binary files /dev/null and b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/equipped-EYES.png differ diff --git a/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/icon.png b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/icon.png new file mode 100644 index 00000000000..900b438c7e2 Binary files /dev/null and b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-left.png b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-left.png new file mode 100644 index 00000000000..b888ce227ab Binary files /dev/null and b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-right.png b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-right.png new file mode 100644 index 00000000000..0e248905fbf Binary files /dev/null and b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/meta.json b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/meta.json new file mode 100644 index 00000000000..f3acabcc544 --- /dev/null +++ b/Resources/Textures/Clothing/Eyes/Hud/syndagent.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by IntegerTempest, edited by Golinth", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-EYES", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/equipped-HAND.png b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/equipped-HAND.png new file mode 100644 index 00000000000..7ca224617c0 Binary files /dev/null and b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/equipped-HAND.png differ diff --git a/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/icon.png b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/icon.png new file mode 100644 index 00000000000..eedef5290db Binary files /dev/null and b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-left.png b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-left.png new file mode 100644 index 00000000000..2e6ce0b9b9f Binary files /dev/null and b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-right.png b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-right.png new file mode 100644 index 00000000000..41ca0dddfb5 Binary files /dev/null and b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/meta.json b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/meta.json new file mode 100644 index 00000000000..1ad417f8f1b --- /dev/null +++ b/Resources/Textures/Clothing/Hands/Gloves/combat.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by OnsenCapy (NamelessName on Discord)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HAND", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..b74049130c7 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..a3def50f88e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/black.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/meta.json index a5553690327..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/black.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/black.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..72664323727 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..6bc5266367f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/meta.json index a5553690327..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/blue.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-hamster.png b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-hamster.png deleted file mode 100644 index 3b89ea8bdfd..00000000000 Binary files a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-hamster.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..c576b30f47c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..378a1a3c19f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/meta.json index a9b3b1556d9..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/botany.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -18,13 +18,17 @@ "directions": 4 }, { - "name": "equipped-HELMET-hamster", + "name": "equipped-HELMET-vox", "directions": 4 }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..5189f62e251 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..616bb8eeb3c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/meta.json index a5553690327..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/gold.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..ed4c08a3257 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..958bcdf0ea5 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/green.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/meta.json index a5553690327..ef97b40b361 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/green.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/green.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -21,6 +21,14 @@ "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..92f305f183a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..5d2af65f4b2 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/meta.json index a5553690327..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/grey.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..22df7888e7c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..7cea36d5393 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/red.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/meta.json index a5553690327..a39a46ac810 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/red.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/red.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..99ed4f9cc2f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..a5fdbe4aac0 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/meta.json b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/meta.json index a5553690327..96c7993dd35 100644 --- a/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Bandanas/skull.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-MASK-vox & equipped-HELMET-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi and modified by Flareguy", "size": { "x": 32, "y": 32 @@ -17,10 +17,18 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json index fe9f38cad4d..bcd0d726dcf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10 inhands by peptide", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..e24011cc920 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-left.png deleted file mode 100644 index 8617b5a239b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-right.png deleted file mode 100644 index d205602ccf7..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..5ad3f9c79a9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-left.png deleted file mode 100644 index 22a6c42d8f4..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-right.png deleted file mode 100644 index a204bb0a787..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertengineer.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json index fe9f38cad4d..bcd0d726dcf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10 inhands by peptide", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..34d61a07cac Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-left.png deleted file mode 100644 index 8de04490735..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-right.png deleted file mode 100644 index 7a96aed7319..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..99955187a8e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-left.png deleted file mode 100644 index 030472239bb..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-right.png deleted file mode 100644 index 270a9249dba..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertjanitor.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json index fe9f38cad4d..bcd0d726dcf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10 inhands by peptide", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..f79fe95b573 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-left.png deleted file mode 100644 index b53973feec2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-right.png deleted file mode 100644 index 0f534f88b1f..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..f94eecb4113 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-left.png deleted file mode 100644 index 819ca15f448..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-right.png deleted file mode 100644 index 848bfcfe88b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertleader.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json index fe9f38cad4d..bcd0d726dcf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10 inhands by peptide", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..17790bee542 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-left.png deleted file mode 100644 index 7d3ce261575..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-right.png deleted file mode 100644 index 67f7494249b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..d25030e13a8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET.png index 8f01538a7a6..486ae099690 100644 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET.png and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-left.png deleted file mode 100644 index 4eaae604cde..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-right.png deleted file mode 100644 index f5f2f5c6f70..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertmedical.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json index fe9f38cad4d..bcd0d726dcf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10 inhands by peptide", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/f09526480788c2e18fff8c16c4318fd6b4272c10. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..d300533c208 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-left.png deleted file mode 100644 index c7b53126d48..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-right.png deleted file mode 100644 index b6be1feebb6..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..a9b18438721 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-left.png deleted file mode 100644 index 946a56c89a7..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-right.png deleted file mode 100644 index e490de88da1..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/ERThelmets/ertsecurity.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-vox.png new file mode 100644 index 00000000000..879ce40a74a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-light-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-vox.png new file mode 100644 index 00000000000..40f2eca45a1 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-unshaded-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-vox.png new file mode 100644 index 00000000000..f61a157050a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/equipped-head-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-light.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-light.png deleted file mode 100644 index 9ee768d5ee0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-light.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-unshaded.png deleted file mode 100644 index 8a7835b20d4..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left.png deleted file mode 100644 index e9ba55de1e0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-light.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-light.png deleted file mode 100644 index 29906052373..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-light.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-unshaded.png deleted file mode 100644 index 6c80725c0a7..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right.png deleted file mode 100644 index 45d73f73dfc..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json index 93d9fece1d0..8236090f7a1 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/atmospherics.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", "size": { "x": 32, "y": 32 @@ -32,27 +32,11 @@ "directions": 4 }, { - "name": "inhand-left", + "name": "equipped-head-vox", "directions": 4 }, { - "name": "inhand-left-unshaded", - "directions": 4 - }, - { - "name": "inhand-left-light", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "inhand-right-unshaded", - "directions": 4 - }, - { - "name": "inhand-right-light", + "name": "equipped-head-light-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json index cc8edd38197..1ccf847b3ed 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by Emisse for SS14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by Emisse for SS14. Vox states by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -18,11 +18,7 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { @@ -30,11 +26,7 @@ "directions": 4 }, { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..f02e33c6584 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-left.png deleted file mode 100644 index 5216ba5dd92..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-right.png deleted file mode 100644 index 2ffe013c121..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..9a0101f09a2 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-left.png deleted file mode 100644 index 6a5d075d808..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-right.png deleted file mode 100644 index 25796fc014d..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/capspace.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-unshaded-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-unshaded-vox.png new file mode 100644 index 00000000000..40d1f9a0c62 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-unshaded-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-vox.png new file mode 100644 index 00000000000..cc2fa16917f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/equipped-head-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left-unshaded.png deleted file mode 100644 index 60ca0efa13b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left.png deleted file mode 100644 index 43f27a890f2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right-unshaded.png deleted file mode 100644 index 118914c8d3f..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right.png deleted file mode 100644 index 602020b2769..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json index 16f509fa99f..1df9c2ddbf6 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/cburn.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by EmoGarbage404", + "copyright": "Made by EmoGarbage404. Vox states by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -28,19 +28,11 @@ "directions": 4 }, { - "name": "inhand-left", + "name": "equipped-head-vox", "directions": 4 }, { - "name": "inhand-left-unshaded", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "inhand-right-unshaded", + "name": "equipped-head-unshaded-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json index 5a77b01e501..5956a9b0f4f 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github)", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github). Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -20,6 +20,14 @@ { "name": "on-equipped-HELMET", "directions": 4 + }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..a974f19a2bd Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..88ee1fbad61 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/clown.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..02363a7faac Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-left.png deleted file mode 100644 index ee1c8d1c4b6..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-right.png deleted file mode 100644 index fa19eea1f7b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/meta.json index f6b86138919..0c1323d3f01 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/cybersun.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from Paradise SS13 at commit https://github.com/ParadiseSS13/Paradise/commit/a67c929b7394f78e7787114457ba42f4df6cc3a1", + "copyright": "Taken from Paradise SS13 at commit https://github.com/ParadiseSS13/Paradise/commit/a67c929b7394f78e7787114457ba42f4df6cc3a1. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -15,16 +15,12 @@ "directions": 4 }, { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", + "name": "equipped-HELMET-harpy", "directions": 4 }, { - "name": "equipped-HELMET-harpy", - "directions": 4 + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..1a7ed3b8666 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-left.png deleted file mode 100644 index 6be2c34d768..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-right.png deleted file mode 100644 index e3c056ada0e..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/meta.json index 83e8e1a7881..782ce631af8 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/deathsquad.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers | Vox state by Flareguy", "size": { "x": 32, "y": 32 @@ -15,15 +15,11 @@ "directions": 4 }, { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", + "name": "equipped-HELMET-vulpkanin", "directions": 4 }, { - "name": "equipped-HELMET-vulpkanin", + "name": "equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json index 1ac1729cd2d..7dbf66ad67c 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,34 +18,26 @@ "directions": 4 }, { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", - "directions": 4 - }, - { - "name": "on-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vulpkanin", "directions": 4 }, { - "name": "on-equipped-HELMET-vulpkanin", + "name": "off-equipped-HELMET-vulpkanin", "directions": 4 }, { - "name": "off-equipped-HELMET-vulpkanin", + "name": "on-equipped-HELMET-vox", "directions": 4 - }, - { + }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, + { "name": "on-equipped-HELMET-harpy", "directions": 4 }, diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..683d6ce97d6 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-left.png deleted file mode 100644 index f7375fd6002..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-right.png deleted file mode 100644 index c2adc46cdb1..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..574b3d985b7 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-left.png deleted file mode 100644 index 7c6e7831c89..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-right.png deleted file mode 100644 index 5ee7bc104c3..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering-white.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/meta.json index 4dae2c687da..f20b167c368 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,25 +18,17 @@ "directions": 4 }, { - "name": "off-inhand-left", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 + "name": "on-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET", "directions": 4 }, - { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", - "directions": 4 - }, { "name": "on-equipped-HELMET-vulpkanin", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..900ed95dc03 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-left.png deleted file mode 100644 index cafca9a938e..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-right.png deleted file mode 100644 index 9645b59e2d1..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..1a40bc3a266 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-left.png deleted file mode 100644 index bff16d72c49..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-right.png deleted file mode 100644 index 355977d540b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/engineering.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json index d431123de2b..d80c50a1c44 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -17,24 +17,16 @@ "name": "off-equipped-HELMET", "directions": 4 }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, { "name": "on-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..efacfba7411 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-left.png deleted file mode 100644 index b26ae9a31f0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-right.png deleted file mode 100644 index fc0edd4a972..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..09d835e9b9f Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-left.png deleted file mode 100644 index 3f5034da6c0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-right.png deleted file mode 100644 index 45776a03b8e..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/luxury.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..11de602a6e9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-left.png deleted file mode 100644 index 81e8a07fdd2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-right.png deleted file mode 100644 index e10648fd9b2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json index 2d5aaae8c75..2a085063a47 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/maxim.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d. Vox state by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -15,11 +15,7 @@ "directions": 4 }, { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", + "name": "equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/meta.json index d168108fdf3..7954c0611e6 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 - }, + "name": "on-equipped-HELMET", + "directions": 4 + }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..1952c3152d8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-left.png deleted file mode 100644 index 8fbfbbf6c6a..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-right.png deleted file mode 100644 index 035c6fc0619..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..3011afac41d Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-left.png deleted file mode 100644 index 85cbfb321a0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-right.png deleted file mode 100644 index c876fefb6c2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/medical.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..8d0cd093f3b Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json index 2244815b787..48f0cbb6153 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/piratecaptainhelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183 (github) for ss14", + "copyright": "Made by brainfood1183 (github) for ss14. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -13,6 +13,10 @@ { "name": "equipped-HELMET", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..663733cfe82 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/meta.json index 2244815b787..5bb20fd0fb3 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/pirateeva.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183 (github) for ss14", + "copyright": "Made by brainfood1183 (github) for ss14. Vox state by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -13,6 +13,10 @@ { "name": "equipped-HELMET", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json index a2c357d43ff..db7f740811d 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states made by Flareguy for SS14 | vulpkanin versions taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..9f2f5c41df3 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-left.png deleted file mode 100644 index dc16b147b84..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-right.png deleted file mode 100644 index e289c62a841..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..b577d32feb2 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-left.png deleted file mode 100644 index b107272ddae..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-right.png deleted file mode 100644 index 59a3181afb1..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/rd.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json index d168108fdf3..051b7e25eaf 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..c3f24c8b34a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-left.png deleted file mode 100644 index b11a533c26b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-right.png deleted file mode 100644 index b9c9df2350a..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..007852fc102 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-left.png deleted file mode 100644 index 12d13f0e189..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-right.png deleted file mode 100644 index 141dc492a4e..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/salvage.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..025e7026679 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-left.png deleted file mode 100644 index c0c5863a3bc..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-right.png deleted file mode 100644 index f29877bf5a8..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/meta.json index c53de839011..afc9f219ac6 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/santahelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Edited by StanTheCarpenter. Originally taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Edited by StanTheCarpenter. Originally taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -15,11 +15,7 @@ "directions": 4 }, { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", + "name": "equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json index 40c5c72b114..f7be4bb5d47 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..6954a4e1a85 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-left.png deleted file mode 100644 index c81cf30dc9c..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-right.png deleted file mode 100644 index f5b449d7b99..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..b48bb710d9b Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-left.png deleted file mode 100644 index 32f699cb473..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-right.png deleted file mode 100644 index 71d2a093251..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security-red.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/meta.json index 14121523ca0..3d94d382c31 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "sprite made by Gtheglorious based on the sprite made by Alekshhh for SS14 | vulpkanin versions made by Floofers", + "copyright": "sprite made by Gtheglorious based on the sprite made by Alekshhh for SS14 | vulpkanin versions made by Floofers. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -28,6 +28,14 @@ { "name": "off-equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..2a3619db8e9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..5b9e2b19ad1 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security-warden.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json index a2e10d43001..24f2a06e376 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", + "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin versions taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 and edited by Floofers", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..439b6c6ebc0 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-left.png deleted file mode 100644 index 68329b89c1a..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-right.png deleted file mode 100644 index 38cc8ca8a67..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..56bca1c618e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-left.png deleted file mode 100644 index 742af4cd003..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-right.png deleted file mode 100644 index 79f70ac1217..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/security.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-light-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-light-vox.png new file mode 100644 index 00000000000..d0124f743be Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-light-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-unshaded-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-unshaded-vox.png new file mode 100644 index 00000000000..4486bff5622 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-unshaded-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-vox.png new file mode 100644 index 00000000000..80a31d544fa Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/equipped-head-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-light.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-light.png deleted file mode 100644 index 7f1657d9e5c..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-light.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-unshaded.png deleted file mode 100644 index fe450b8df19..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left.png deleted file mode 100644 index 81cecd01c2f..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-light.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-light.png deleted file mode 100644 index 7749494c565..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-light.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-unshaded.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-unshaded.png deleted file mode 100644 index be08f2c2576..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right-unshaded.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right.png deleted file mode 100644 index 2bbec0f04c7..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/meta.json index 35a6a87bfdc..29335fd904e 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/spatiohelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Original by Emisse, modified by EmoGarbage404 | vulpkanin version made by Floofers", + "copyright": "Original by Emisse, modified by EmoGarbage404 | vulpkanin version made by Floofers. Vox states by Flareguy for SS14", "size": { "x": 32, @@ -33,27 +33,11 @@ "directions": 4 }, { - "name": "inhand-left", + "name": "equipped-head-vox", "directions": 4 }, { - "name": "inhand-left-unshaded", - "directions": 4 - }, - { - "name": "inhand-left-light", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "inhand-right-unshaded", - "directions": 4 - }, - { - "name": "inhand-right-light", + "name": "equipped-head-light-vox", "directions": 4 }, { @@ -61,4 +45,4 @@ "directions": 4 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/meta.json index e9de1ae57b6..9b960ec32b1 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -21,24 +21,16 @@ "name": "off-equipped-HELMET", "directions": 4 }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, { "name": "on-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..eb2027c5fa6 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-left.png deleted file mode 100644 index 1b108753b35..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-right.png deleted file mode 100644 index dc0500af778..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..8804afa3d86 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-left.png deleted file mode 100644 index c1350c82422..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-right.png deleted file mode 100644 index db67f97b6f4..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndicate.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json index 038aabe6050..6999f12991b 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd. Vox states by Flareguy for Space Station 14", "size": { "x": 32, @@ -18,25 +18,17 @@ "name": "off-equipped-HELMET", "directions": 4 }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, { "name": "on-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 } ] -} \ No newline at end of file +} diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..5276e3f681e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-left.png deleted file mode 100644 index 79a96cd7111..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-right.png deleted file mode 100644 index 0c7b0caddfa..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..65069f91c71 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-left.png deleted file mode 100644 index 505808fc9d0..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-right.png deleted file mode 100644 index 862f6294fbc..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiecommander.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/meta.json index 038aabe6050..5c7932bb286 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/meta.json @@ -1,42 +1,33 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd. Vox states by Flareguy for Space Station 14", + "size": { + "x": 32, + "y": 32 }, - { - "name": "icon-flash" - }, - { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", - "directions": 4 - }, - { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", - "directions": 4 - } - ] + "states": [ + { + "name": "icon" + }, + { + "name": "icon-flash" + }, + { + "name": "off-equipped-HELMET", + "directions": 4 + }, + { + "name": "on-equipped-HELMET", + "directions": 4 + }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-vox", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..4f4b2f0f771 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-left.png deleted file mode 100644 index 22a8dd14b15..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-right.png deleted file mode 100644 index 71572c0ffdc..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..bf7243ed32c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-left.png deleted file mode 100644 index 5a40993d72e..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-right.png deleted file mode 100644 index 27a27d1e8e2..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndieelite.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json index b69addc4760..9adc3b7cef9 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github)", + "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github). Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -17,24 +17,16 @@ "name": "off-equipped-HELMET", "directions": 4 }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, { "name": "on-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "off-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", + "name": "on-equipped-HELMET-vox", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..4d5f2cf4b72 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-left.png deleted file mode 100644 index 97f21fd350b..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-right.png deleted file mode 100644 index 0e950a6674a..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..8c072609c94 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-left.png deleted file mode 100644 index 0e174c04c33..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-right.png deleted file mode 100644 index b0494003486..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/syndiemedic.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/meta.json b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/meta.json index d168108fdf3..b72a96092e7 100644 --- a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox states by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", "size": { "x": 32, "y": 32 @@ -14,28 +14,20 @@ "name": "icon-flash" }, { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 + "name": "on-equipped-HELMET", + "directions": 4 }, { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", + "name": "off-equipped-HELMET", "directions": 4 }, { - "name": "on-inhand-left", + "name": "on-equipped-HELMET-vox", "directions": 4 }, { - "name": "on-inhand-right", - "directions": 4 + "name": "off-equipped-HELMET-vox", + "directions": 4 }, { "name": "on-equipped-HELMET-vulpkanin", diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..647d0e76c1b Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-left.png deleted file mode 100644 index 90b7c2574ad..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-right.png deleted file mode 100644 index de647331f93..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/off-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..a0345048e84 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-left.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-left.png deleted file mode 100644 index fc11467e8f9..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-left.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-right.png b/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-right.png deleted file mode 100644 index 131989b5928..00000000000 Binary files a/Resources/Textures/Clothing/Head/Hardsuits/wizard.rsi/on-inhand-right.png and /dev/null differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..b432655c5ac Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json index bbb0aac6648..057d0b0ab24 100644 --- a/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hats/gladiator.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -20,7 +20,11 @@ }, { "name": "inhand-right", - "direction": 4 + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hats/paper.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hats/paper.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..5f5c3376d7e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/paper.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/paper.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/paper.rsi/meta.json index a470e009443..057d0b0ab24 100644 --- a/Resources/Textures/Clothing/Head/Hats/paper.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hats/paper.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..a51c2680417 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/meta.json index ade65863af2..e099085bde1 100644 --- a/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hats/surgcap_blue.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -25,6 +25,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..81601c6c2bb Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/meta.json index a470e009443..057d0b0ab24 100644 --- a/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hats/surgcap_green.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..24ea1365cd8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/meta.json b/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/meta.json index a470e009443..057d0b0ab24 100644 --- a/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hats/surgcap_purple.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/meta.json index 26d3341e24e..f2d8747c039 100644 --- a/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/meta.json @@ -1,41 +1,49 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation https://github.com/tgstation/tgstation/blob/master/icons/mob/clothing/head.dmi", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "icon-flash" - }, - { - "name": "off-equipped-HELMET", - "directions": 4 - }, - { - "name": "off-inhand-left", - "directions": 4 - }, - { - "name": "off-inhand-right", - "directions": 4 - }, - { - "name": "on-equipped-HELMET", - "directions": 4 - }, - { - "name": "on-inhand-left", - "directions": 4 - }, - { - "name": "on-inhand-right", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation https://github.com/tgstation/tgstation/blob/master/icons/mob/clothing/head.dmi. Vox states taken from paradise at https://github.com/ParadiseSS13/Paradise/blob/765461f14aa4dd4f1edc33242c667843134678b5/icons/mob/clothing/species/vox/head.dmi", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "icon-flash" + }, + { + "name": "off-equipped-HELMET", + "directions": 4 + }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "off-inhand-left", + "directions": 4 + }, + { + "name": "off-inhand-right", + "directions": 4 + }, + { + "name": "on-equipped-HELMET", + "directions": 4 + }, + { + "name": "on-equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "on-inhand-left", + "directions": 4 + }, + { + "name": "on-inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..ea6e7edce8e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..301ff00e341 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/atmos_firehelmet.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..58e8aa9e709 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/meta.json index e0ee93d642c..e55d1eb4691 100644 --- a/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/bombsuit.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/a75dee2e6d236612dbd403dd5f8687ca930c01f1", + "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/a75dee2e6d236612dbd403dd5f8687ca930c01f1. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..50d4ec39d54 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json index 3c406ff57cd..c7a2236b61b 100644 --- a/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/eva.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..b5f224b98ad Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET.png b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET.png index c64f69b0d84..f6f0e58c6b9 100644 Binary files a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET.png and b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/meta.json index 3c406ff57cd..c7a2236b61b 100644 --- a/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/eva_large.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..62ff233af14 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json index 3c406ff57cd..c7a2236b61b 100644 --- a/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/eva_syndicate.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/meta.json index 9530d0f7aa4..014284471a4 100644 --- a/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradise station and modified by Peptide90 https://github.com/ParadiseSS13/Paradise/commit/46bb8d448f52278a8f027b3f5bdf061e39d06140", + "copyright": "Taken from paradise station and modified by Peptide90 https://github.com/ParadiseSS13/Paradise/commit/46bb8d448f52278a8f027b3f5bdf061e39d06140. Vox states by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -17,6 +17,10 @@ "name": "off-equipped-HELMET", "directions": 4 }, + { + "name": "off-equipped-HELMET-vox", + "directions": 4 + }, { "name": "off-inhand-left", "directions": 4 @@ -29,6 +33,10 @@ "name": "on-equipped-HELMET", "directions": 4 }, + { + "name": "on-equipped-HELMET-vox", + "directions": 4 + }, { "name": "on-inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/off-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/off-equipped-HELMET-vox.png new file mode 100644 index 00000000000..ad7bbad4477 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/off-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/on-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/on-equipped-HELMET-vox.png new file mode 100644 index 00000000000..2ebb820f60c Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/firehelmet.rsi/on-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..522a2eb9237 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/meta.json index 4427c7fb519..69b03ad731d 100644 --- a/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/ihvoid.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state by Flareguy for Space Station 14 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..952b32f3a1a Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/meta.json index 5048ec6bb0d..abfed0635af 100644 --- a/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/light_riot.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/fed2ddeb54d0fb8bb97cb0a899a088b7d7423bbb", + "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/fed2ddeb54d0fb8bb97cb0a899a088b7d7423bbb. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/security.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/security.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..703d927ecfe Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/security.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/security.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/security.rsi/meta.json index db2bbfafd4c..a0653e5c65f 100644 --- a/Resources/Textures/Clothing/Head/Helmets/security.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "light-equipped-HELMET", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..59f1e3263b1 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/meta.json index 61c8ce163c2..dae510390fe 100644 --- a/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/spaceninja.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradise https://github.com/ParadiseSS13/Paradise/tree/master/icons (unknown commit) | vulpkanin version made by Floofers", + "copyright": "Taken from paradise https://github.com/ParadiseSS13/Paradise/tree/master/icons (unknown commit) | vulpkanin version made by Floofers. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/swat.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/swat.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..1ed974c2062 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/swat.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/swat.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/swat.rsi/meta.json index 8836c0b646c..f505b4e75e8 100644 --- a/Resources/Textures/Clothing/Head/Helmets/swat.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/swat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, inhand sprites by Flareguy", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, inhand sprites & vox state by Flareguy", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..e228a8a33aa Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/meta.json index 8bedbfb78e0..a0bf9545853 100644 --- a/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/swat_syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, inhand sprites by Flareguy, icon edited by Flareguy", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, inhand sprites by Flareguy, icon edited by Flareguy. Vox state taken from from Paradise at https://github.com/ParadiseSS13/Paradise/blob/b1658390731745adf5cc9fb039bb0f17ad3c11a7/icons/mob/clothing/species/vox/helmet.dmi ", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Helmets/templar.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/templar.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..3572a5de9f0 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/templar.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/templar.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/templar.rsi/meta.json index 7bd2e3e22a7..5c8b454ea69 100644 --- a/Resources/Textures/Clothing/Head/Helmets/templar.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/templar.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -13,6 +13,10 @@ { "name": "equipped-HELMET", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..0cabbe106c7 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/meta.json b/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/meta.json index a470e009443..8e639d26bcd 100644 --- a/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Helmets/wizardhelm.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 and modified to remove duplicate states", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..35cfa8ddc0e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/meta.json index 4427c7fb519..fd2c470dc4b 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/bio.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -25,6 +25,10 @@ { "name": "equipped-HELMET-vulpkanin", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..90ad846f9b8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/meta.json index 4427c7fb519..d95bcad823c 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/cmo.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..35cfa8ddc0e Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/meta.json index 4427c7fb519..d95bcad823c 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/general.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..2a8f1b0cdb3 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/meta.json index 4427c7fb519..d95bcad823c 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/janitor.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..4b90b700a8d Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/meta.json index 4427c7fb519..d95bcad823c 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/scientist.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..402d6bf76a9 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/meta.json index e830cae2823..6d404a14b82 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/security.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..d4a1f0848eb Binary files /dev/null and b/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/meta.json b/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/meta.json index 4427c7fb519..d95bcad823c 100644 --- a/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Hoods/Bio/virology.rsi/meta.json @@ -1,30 +1,34 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-HELMET", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-HELMET-vulpkanin", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-HELMET", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-HELMET-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..65a8cb83c17 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/meta.json b/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/meta.json index a470e009443..8e639d26bcd 100644 --- a/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Misc/chickenhead.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-HELMET-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 and modified to remove duplicate states", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-HELMET-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..5b2c2550498 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/meta.json b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/meta.json index 39eb54f44c8..22039e8e306 100644 --- a/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, icon by лазік#7305 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79, icon by лазік#7305. equipped-HELMET-vox state modified by Flareguy from vox welding helmet state | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", "size": { "x": 32, "y": 32 @@ -21,6 +21,14 @@ "name": "up-equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "up-equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/up-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/up-equipped-HELMET-vox.png new file mode 100644 index 00000000000..14129a80cb6 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/blue_flame_welding_mask.rsi/up-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..64014962527 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/meta.json b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/meta.json index 39eb54f44c8..d0931b9be1a 100644 --- a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, icon by лазік#7305 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 and up-equipped-HELMET modified by Flareguy, icon by лазік#7305. equipped-HELMET-vox state modified by Flareguy from vox welding helmet state | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", "size": { "x": 32, "y": 32 @@ -21,6 +21,14 @@ "name": "up-equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "up-equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET-vox.png new file mode 100644 index 00000000000..d011e47c2d8 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET.png b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET.png index b60219beccd..e7ef24dceef 100644 Binary files a/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET.png and b/Resources/Textures/Clothing/Head/Welding/flame_welding_mask.rsi/up-equipped-HELMET.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..0b9342b2362 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/meta.json b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/meta.json index 39eb54f44c8..825fa48b804 100644 --- a/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, icon by лазік#7305 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from CEV-Eris at https://github.com/discordia-space/CEV-Eris/blob/2a0d963d5bf68bd8ddf6fba6f60479bec172b51d/icons/inventory/head/mob.dmi, icon by лазік#7305. equipped-HELMET-vox state modified by Flareguy from 'welding' state in /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", "size": { "x": 32, "y": 32 @@ -21,6 +21,14 @@ "name": "up-equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "up-equipped-HELMET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/up-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/up-equipped-HELMET-vox.png new file mode 100644 index 00000000000..6ecdfda3ea0 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/paintedwelding.rsi/up-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/welding.rsi/equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/welding.rsi/equipped-HELMET-vox.png new file mode 100644 index 00000000000..6b19f42a821 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/welding.rsi/equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Head/Welding/welding.rsi/meta.json b/Resources/Textures/Clothing/Head/Welding/welding.rsi/meta.json index 3a84e3148e0..569555b8695 100644 --- a/Resources/Textures/Clothing/Head/Welding/welding.rsi/meta.json +++ b/Resources/Textures/Clothing/Head/Welding/welding.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", "size": { "x": 32, "y": 32 @@ -21,6 +21,14 @@ "name": "up-equipped-HELMET", "directions": 4 }, + { + "name": "equipped-HELMET-vox", + "directions": 4 + }, + { + "name": "up-equipped-HELMET-vox", + "directions": 4 + }, { "name": "equipped-HELMET-hamster", "directions": 4 diff --git a/Resources/Textures/Clothing/Head/Welding/welding.rsi/up-equipped-HELMET-vox.png b/Resources/Textures/Clothing/Head/Welding/welding.rsi/up-equipped-HELMET-vox.png new file mode 100644 index 00000000000..b13423cd8b1 Binary files /dev/null and b/Resources/Textures/Clothing/Head/Welding/welding.rsi/up-equipped-HELMET-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/bee.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/bee.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..05af835e9d9 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/bee.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/bee.rsi/meta.json b/Resources/Textures/Clothing/Mask/bee.rsi/meta.json index cc214ea433b..628b5d1ffcf 100644 --- a/Resources/Textures/Clothing/Mask/bee.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/bee.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/dannno/-tg-station/blob/a51c5a85d327f562004cef2f36c081ad0d95fd9a/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github)", + "copyright": "Taken from tgstation at commit https://github.com/dannno/-tg-station/blob/a51c5a85d327f562004cef2f36c081ad0d95fd9a/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github). equipped-MASK-vox state taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -17,6 +17,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/breath.rsi/meta.json b/Resources/Textures/Clothing/Mask/breath.rsi/meta.json index bed9ae64b0b..f0ec0118d81 100644 --- a/Resources/Textures/Clothing/Mask/breath.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/breath.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) equipped-MASK-secdog modified from equipped-MASK-dog by TJohnson. | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) equipped-MASK-secdog modified from equipped-MASK-dog by TJohnson. | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox & up-equipped-MASK-vox state in /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -18,6 +18,14 @@ "name": "up-equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, + { + "name": "up-equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -54,10 +62,6 @@ "name": "equipped-MASK-possum", "directions": 4 }, - { - "name": "equipped-MASK-vox", - "directions": 4 - }, { "name": "equipped-MASK-pig", "directions": 4 diff --git a/Resources/Textures/Clothing/Mask/breath.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/breath.rsi/up-equipped-MASK-vox.png new file mode 100644 index 00000000000..770ad70cf5e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/breath.rsi/up-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/clown.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/clown.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..0a7c6fc3279 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/clown.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/clown.rsi/meta.json b/Resources/Textures/Clothing/Mask/clown.rsi/meta.json index b3709bcd83c..6671a11d694 100644 --- a/Resources/Textures/Clothing/Mask/clown.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/clown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e and slightly modified by Flareguy", "size": { "x": 32, "y": 32 @@ -33,6 +33,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/gas.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gas.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..7170d7ebdf5 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gas.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gas.rsi/meta.json b/Resources/Textures/Clothing/Mask/gas.rsi/meta.json index 07a0c908b10..7d52a23d9c4 100644 --- a/Resources/Textures/Clothing/Mask/gas.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gas.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e and modified by Flareguy", "size": { "x": 32, "y": 32 @@ -33,6 +33,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/gasatmos.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gasatmos.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..8975b1eb04e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gasatmos.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gasatmos.rsi/meta.json b/Resources/Textures/Clothing/Mask/gasatmos.rsi/meta.json index 63476f222be..6e2e5245473 100644 --- a/Resources/Textures/Clothing/Mask/gasatmos.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gasatmos.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state modified by Flareguy from 'gas-alt' state in /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -29,6 +29,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/gascaptain.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gascaptain.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..bc0f5e90119 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gascaptain.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gascaptain.rsi/meta.json b/Resources/Textures/Clothing/Mask/gascaptain.rsi/meta.json index 4b2d043352d..332a8fed816 100644 --- a/Resources/Textures/Clothing/Mask/gascaptain.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gascaptain.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, edited by Emisse for ss14. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, edited by Emisse for ss14. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from 'gas-alt' state in /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e, and modified by Flareguy", "size": { "x": 32, "y": 32 @@ -29,6 +29,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..f504228f7df Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json index 600054012ea..42e2775ecae 100644 --- a/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gasexplorer.rsi/meta.json @@ -1,38 +1,42 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version edited by Floofers", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version edited by Floofers. Vox state by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-MASK", - "directions": 4 - }, - { - "name": "up-equipped-MASK", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-MASK-vulpkanin", - "directions": 4 - }, - { - "name": "equipped-MASK-reptilian", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-MASK", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, + { + "name": "up-equipped-MASK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-MASK-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-MASK-reptilian", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Mask/gassecurity.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gassecurity.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..ff33f309443 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gassecurity.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gassecurity.rsi/meta.json b/Resources/Textures/Clothing/Mask/gassecurity.rsi/meta.json index 9ed76c4839d..a92fcef8bf8 100644 --- a/Resources/Textures/Clothing/Mask/gassecurity.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gassecurity.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox & up-equipped-MASK-vox states taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -14,24 +14,32 @@ "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-reptilian", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "up-equipped-MASK", "directions": 4 }, { - "name": "inhand-left", + "name": "up-equipped-MASK-vox", "directions": 4 }, { - "name": "inhand-right", + "name": "inhand-left", "directions": 4 }, { - "name": "equipped-MASK-vulpkanin", + "name": "inhand-right", "directions": 4 }, { - "name": "equipped-MASK-reptilian", + "name": "equipped-MASK-vulpkanin", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Mask/gassecurity.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gassecurity.rsi/up-equipped-MASK-vox.png new file mode 100644 index 00000000000..e701323f55a Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gassecurity.rsi/up-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gassyndicate.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/gassyndicate.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..59a80479f7f Binary files /dev/null and b/Resources/Textures/Clothing/Mask/gassyndicate.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/gassyndicate.rsi/meta.json b/Resources/Textures/Clothing/Mask/gassyndicate.rsi/meta.json index 1e01e88dc45..b2871a27974 100644 --- a/Resources/Textures/Clothing/Mask/gassyndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/gassyndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e and slightly modified to fix an error", "size": { "x": 32, "y": 32 @@ -47,6 +47,16 @@ [ 0.5, 0.5, 0.5 ], [ 0.5, 0.5, 0.5 ] ] + }, + { + "name": "equipped-MASK-vox", + "directions": 4, + "delays": [ + [ 0.5, 0.5, 0.5 ], + [ 0.5, 0.5, 0.5 ], + [ 0.5, 0.5, 0.5 ], + [ 0.5, 0.5, 0.5 ] + ] } ] } diff --git a/Resources/Textures/Clothing/Mask/italian_moustache.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..9bd2b35d778 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json index 9621b18fe9e..af0873d23a7 100644 --- a/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/italian_moustache.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6665eec76c98a4f3f89bebcd10b34b47dcc0b8ae | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6665eec76c98a4f3f89bebcd10b34b47dcc0b8ae | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Mask/medical.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/medical.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..c3fa7f5917d Binary files /dev/null and b/Resources/Textures/Clothing/Mask/medical.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/medical.rsi/meta.json b/Resources/Textures/Clothing/Mask/medical.rsi/meta.json index 59e292cbd4b..ba8e8da405c 100644 --- a/Resources/Textures/Clothing/Mask/medical.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/medical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox & up-equipped-MASK-vox states taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -75,6 +75,14 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, + { + "name": "up-equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/medical.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/medical.rsi/up-equipped-MASK-vox.png new file mode 100644 index 00000000000..770ad70cf5e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/medical.rsi/up-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/mime.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/mime.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..cab47297f0a Binary files /dev/null and b/Resources/Textures/Clothing/Mask/mime.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/mime.rsi/meta.json b/Resources/Textures/Clothing/Mask/mime.rsi/meta.json index 34248cb9b95..e1a387cdd35 100644 --- a/Resources/Textures/Clothing/Mask/mime.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/mime.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -25,6 +25,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/muzzle.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/muzzle.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..529c87878ed Binary files /dev/null and b/Resources/Textures/Clothing/Mask/muzzle.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/muzzle.rsi/meta.json b/Resources/Textures/Clothing/Mask/muzzle.rsi/meta.json index 33176d73e7b..d5fd7a68ee2 100644 --- a/Resources/Textures/Clothing/Mask/muzzle.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/muzzle.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -29,6 +29,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/ninja.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/ninja.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..924742fa945 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/ninja.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/ninja.rsi/meta.json b/Resources/Textures/Clothing/Mask/ninja.rsi/meta.json index da51268a11b..26fff924c11 100644 --- a/Resources/Textures/Clothing/Mask/ninja.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/ninja.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradise at commit https://github.com/ParadiseSS13/Paradise/commit/33f7c1ef477fa67db5dda48078b469ab59aa7997 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from paradise at commit https://github.com/ParadiseSS13/Paradise/commit/33f7c1ef477fa67db5dda48078b469ab59aa7997 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..67d3c25cac4 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/meta.json b/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/meta.json index 0f2358a55ff..4536363585b 100644 --- a/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/plaguedoctormask.rsi/meta.json @@ -1,30 +1,34 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/e89db4dd4f42377b0adafb06806a763314a89034 , edited by Alekshhh | vulpkanin version taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-MASK", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-MASK-vulpkanin", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/e89db4dd4f42377b0adafb06806a763314a89034 , edited by Alekshhh | vulpkanin version taken from https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13/commit/091d9ec00f186052b87bd65125e896f78faefe38 | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-MASK", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-MASK-vulpkanin", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Mask/sexyclown.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/sexyclown.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..b1cb32a1573 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/sexyclown.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/sexyclown.rsi/meta.json b/Resources/Textures/Clothing/Mask/sexyclown.rsi/meta.json index da5fdbe7cd2..9e577533fcc 100644 --- a/Resources/Textures/Clothing/Mask/sexyclown.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/sexyclown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/ed466a4c67828b44ddb9d9550366be5c2d745955/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/ed466a4c67828b44ddb9d9550366be5c2d745955/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/sexymime.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/sexymime.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..4ceaf59677b Binary files /dev/null and b/Resources/Textures/Clothing/Mask/sexymime.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/sexymime.rsi/meta.json b/Resources/Textures/Clothing/Mask/sexymime.rsi/meta.json index 8c0842d68ad..747190632bf 100644 --- a/Resources/Textures/Clothing/Mask/sexymime.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/sexymime.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/ed466a4c67828b44ddb9d9550366be5c2d745955/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/blob/ed466a4c67828b44ddb9d9550366be5c2d745955/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d edited by Floofers | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "equipped-MASK-reptilian", "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/sterile.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/sterile.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..18c64e1048e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/sterile.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/sterile.rsi/meta.json b/Resources/Textures/Clothing/Mask/sterile.rsi/meta.json index f61bba1a326..4115a8de19f 100644 --- a/Resources/Textures/Clothing/Mask/sterile.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/sterile.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -14,10 +14,22 @@ "name": "equipped-MASK", "directions": 4 }, + { + "name": "equipped-MASK-reptilian", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, { "name": "up-equipped-MASK", "directions": 4 }, + { + "name": "up-equipped-MASK-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -33,10 +45,6 @@ { "name": "up-equipped-MASK-vulpkanin", "directions": 4 - }, - { - "name": "equipped-MASK-reptilian", - "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/Mask/sterile.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/sterile.rsi/up-equipped-MASK-vox.png new file mode 100644 index 00000000000..770ad70cf5e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/sterile.rsi/up-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/swat.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/swat.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..d654e3493c9 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/swat.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/swat.rsi/meta.json b/Resources/Textures/Clothing/Mask/swat.rsi/meta.json index fb3b9e8f4a5..9b8c7ad0809 100644 --- a/Resources/Textures/Clothing/Mask/swat.rsi/meta.json +++ b/Resources/Textures/Clothing/Mask/swat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/RemieRichards/-tg-station/blob/f8c05e21694cd3cb703e40edc5cfc375017944b1/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/RemieRichards/-tg-station/blob/f8c05e21694cd3cb703e40edc5cfc375017944b1/icons/obj/clothing/masks.dmi. Reptilian edit by Nairod(Github) | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | equipped-MASK-vox state taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/bc095ad398790a2b718b2bab4f2157cdd80a51da/icons/mob/clothing/species/vox/mask.dmi", "size": { "x": 32, "y": 32 @@ -15,19 +15,23 @@ "directions": 4 }, { - "name": "inhand-left", + "name": "equipped-MASK-reptilian", "directions": 4 }, { - "name": "inhand-right", + "name": "equipped-MASK-vox", "directions": 4 }, { - "name": "equipped-MASK-vulpkanin", + "name": "inhand-left", "directions": 4 }, { - "name": "equipped-MASK-reptilian", + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-MASK-vulpkanin", "directions": 4 } ] diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK-vox.png new file mode 100644 index 00000000000..e6028f3a4c1 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK.png new file mode 100644 index 00000000000..5d0a7ea70d1 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/equipped-MASK.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon-up.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon-up.png new file mode 100644 index 00000000000..352e536ca91 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon-up.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon.png new file mode 100644 index 00000000000..cdb8d4b7c7e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-left.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-left.png new file mode 100644 index 00000000000..c5111a66a9b Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-right.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-right.png new file mode 100644 index 00000000000..5841f0b8460 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/meta.json b/Resources/Textures/Clothing/Mask/welding-gas.rsi/meta.json new file mode 100644 index 00000000000..8e9b8573250 --- /dev/null +++ b/Resources/Textures/Clothing/Mask/welding-gas.rsi/meta.json @@ -0,0 +1,49 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6f5ca45e3ac06b30fb1957042214a888d8c01722. Inhands, worn sprites, and vox sprites created by EmoGarbage404 (github)", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "icon-up" + }, + { + "name": "equipped-MASK", + "directions": 4 + }, + { + "name": "up-equipped-MASK", + "directions": 4 + }, + { + "name": "equipped-MASK-vox", + "directions": 4 + }, + { + "name": "up-equipped-MASK-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "up-inhand-left", + "directions": 4 + }, + { + "name": "up-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK-vox.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK-vox.png new file mode 100644 index 00000000000..90871d7d006 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK.png new file mode 100644 index 00000000000..449c8624c9a Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-equipped-MASK.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-left.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-left.png new file mode 100644 index 00000000000..2868ab8317e Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-left.png differ diff --git a/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-right.png b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-right.png new file mode 100644 index 00000000000..1362d990110 Binary files /dev/null and b/Resources/Textures/Clothing/Mask/welding-gas.rsi/up-inhand-right.png differ diff --git a/Resources/Textures/Clothing/Neck/Misc/whistles.rsi/meta.json b/Resources/Textures/Clothing/Neck/Misc/whistles.rsi/meta.json deleted file mode 100644 index 31cda14261e..00000000000 --- a/Resources/Textures/Clothing/Neck/Misc/whistles.rsi/meta.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Drawn by Firewatchin on Discord.", - "size": { - "x": 32, - "y": 32 - }, - - "states": [ - { - "name": "equipped-NECK", - "directions": 4 - }, - { - "name": "icon" - } - ] -} diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..9d92b21329d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/meta.json index c7a0afcae33..5f95573206c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/armor_reflec.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/dbc2435fa562f4ef130a7112d2a4cc9c80099894", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/dbc2435fa562f4ef130a7112d2a4cc9c80099894. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..cffb51e5e56 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/meta.json index 9ae7fc3f93a..8b7a929fcde 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/bulletproof.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/ParadiseSS13/Paradise", + "copyright": "Taken from https://github.com/ParadiseSS13/Paradise. Vox states by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e0bfdfbc389 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/meta.json index b979f8bfb8a..a9366f0bc1d 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/captain_carapace.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/69842/commits/d8138946b0ed06fced522729ac8eaa0596864329 edited by Skarletto (github), edited by Emisse for ss14", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/69842/commits/d8138946b0ed06fced522729ac8eaa0596864329 edited by Skarletto (github), edited by Emisse for ss14. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..599e73c76f1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/meta.json index e482264df5f..5c326232e4f 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/cult_armour.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/fce54deb01d465957691ba2907218d4af4830db2/icons/mob/clothing/species/vox/suit.dmi and north sprite modified", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f37eba33599 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/heavygreen.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..164f5e4592d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/heavyred.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f0e99ee3c33 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/meta.json index afdd4120b55..26631d02819 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/riot.rsi/meta.json @@ -1,26 +1,30 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/ParadiseSS13/Paradise", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/ParadiseSS13/Paradise. Vox state by Flareguy for Space Station 14", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..1d9b1d14596 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/meta.json index afdd4120b55..00bef7108a3 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/ParadiseSS13/Paradise", + "copyright": "Taken from https://github.com/ParadiseSS13/Paradise. Vox state by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..ea3c78dfbe7 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/meta.json index afdd4120b55..26631d02819 100644 --- a/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Armor/security_slim.rsi/meta.json @@ -1,26 +1,30 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/ParadiseSS13/Paradise", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/ParadiseSS13/Paradise. Vox state by Flareguy for Space Station 14", + "size": { + "x": 32, + "y": 32 }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e62fa89ab54 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/cmo.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..0a224c92b96 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/general.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..82b0ea9f364 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/janitor.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..044d87e2f63 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/scientist.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e426556e7db Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f6b5c43d2bf Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Bio/virology.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..1fd6c3828d3 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/meta.json index 20e876460d2..cc68d97d378 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/expensive_coat.rsi/meta.json @@ -11,6 +11,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "icon" } diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..31e6f31708e Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/meta.json index 55e082d620d..fa20ea7d596 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/hos_trenchcoat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e , edited by Alekshhh", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e , edited by Alekshhh. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..59bf1f287b2 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/jensencoat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..fa32996aa89 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/meta.json index 442bfb29202..2311851853a 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..ce7c029026c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..6d96d0a0379 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/meta.json index 442bfb29202..2311851853a 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f83538ee601 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_chem.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..58b84263ac0 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/meta.json index 02abb078069..c2b48b1d762 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..547839061b6 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_cmo.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..fa9a53d3735 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/meta.json index 442bfb29202..2311851853a 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..9cba3e8ef3f Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_gene.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e432bb2d017 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/meta.json index 6cb239d8c85..4d788f71eed 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..2363b4118d0 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/labcoat_viro.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..1679773c734 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/pirate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..89369f8794c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/meta.json index 442bfb29202..2311851853a 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/meta.json @@ -21,6 +21,14 @@ "name": "open-equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "open-equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/open-equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/open-equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..973451e5f5b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/rndcoat.rsi/open-equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..a56db4fd532 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Coats/warden.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..be85f19ea64 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/meta.json index 4fbd43a08b5..b7b0719efa4 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertengineer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6. Vox state by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e5f648a31f1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/meta.json index 4fbd43a08b5..6de2d485b82 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertjanitor.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6. Vox sprite by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..cb2c6308015 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/meta.json index 4fbd43a08b5..6de2d485b82 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertleader.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6. Vox sprite by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..284954aabcc Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/meta.json index 4fbd43a08b5..daa64b2f5c6 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertmedical.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6. Vox sprite made by Flareguy", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..29130c57f07 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/meta.json index 4fbd43a08b5..6de2d485b82 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/ERTSuits/ertsecurity.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6", + "copyright": "Taken from paradisestation at commit https://github.com/ParadiseSS13/Paradise/commit/12c21ced8432015485484b17e311dcceb7c458f6. Vox sprite by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..b896fbef73d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/meta.json index ef5e62cca40..2da9e2ad1d5 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/atmospherics.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..644c67846b1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/meta.json index 7f50fdcf083..3271d26a2cf 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/capspace.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by Emisse for SS14", + "copyright": "Made by Emisse for SS14. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..52c1cea7cf3 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/meta.json index 2de954bbf90..458fb144f73 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cburn.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by EmoGarbage404, harpy by VMSolidus", + "copyright": "Made by EmoGarbage404, harpy by VMSolidus. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..bf6028dfdb9 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/meta.json index 090140fa8cd..60c53e9cc28 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/clown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github), harpy by VMSolidus", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by brainfood1183 (github), harpy by VMSolidus. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-OUTERCLOTHING-harpy", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..631815d06b6 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/meta.json index 1cfa2a9cfe4..5a3fd99c11f 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/cybersun.rsi/meta.json @@ -1,30 +1,34 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Sprite made by Gtheglorious based on the sprite made by emisse for ss14, harpy variant by VMSolidus", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-OUTERCLOTHING-harpy", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprite made by Gtheglorious based on the sprite made by emisse for ss14, harpy variant by VMSolidus, vox state made by Flareguy for SS14.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-harpy", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..cbf92dffde4 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/meta.json index f6910b12aa0..5054eea8f45 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/deathsquad.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, edited by Emisse for SS14, harpy edit by VMSolidus", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, edited by Emisse for SS14. Vox state made by Flareguy for SS14, harpy edit by VMSolidus", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-OUTERCLOTHING-harpy", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..a6066c595b2 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/meta.json index ef5e62cca40..0a78966c1d5 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering-white.rsi/meta.json @@ -1,11 +1,11 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", - "size": { - "x": 32, - "y": 32 - }, + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, "states": [ { "name": "icon" @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -27,4 +31,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..7e4e050f9d2 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/meta.json index cbf3391af71..13f389a778c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/engineering.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy version by VMSolidus", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy version by VMSolidus. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..c082fd23404 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/meta.json index 0261a0564f1..76e3264cbce 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/luxury.rsi/meta.json @@ -1,11 +1,11 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", - "size": { - "x": 32, - "y": 32 - }, + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Texture edit from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, "states": [ { "name": "icon" @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -27,4 +31,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..2085dc1c838 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/meta.json index 3641da6f505..9acde9a4dea 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/maxim.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/6b3f58d7de4d4e374282819a7001eaa9bde1676d. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..6b6a36e0e7f Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/meta.json index ef5e62cca40..0a78966c1d5 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/medical.rsi/meta.json @@ -1,11 +1,11 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", - "size": { - "x": 32, - "y": 32 - }, + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, "states": [ { "name": "icon" @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -27,4 +31,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e8149c9cd9b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/meta.json index 64b98f1e798..403cfec384c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/paramed.rsi/meta.json @@ -1,30 +1,34 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from paradise station git at commit https://github.com/ParadiseSS13/Paradise/commit/e5e584804b4b0b373a6a69d23afb73fd3c094365, redrawn by Ubaser", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-OUTERCLOTHING-harpy", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from paradise station git at commit https://github.com/ParadiseSS13/Paradise/commit/e5e584804b4b0b373a6a69d23afb73fd3c094365, redrawn by Ubaser. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-harpy", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f0638fc80d7 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/meta.json index 8840689d9ed..8663673f5c6 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/piratecaptain.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183 (Github) for ss14", + "copyright": "Made by brainfood1183 (Github) for ss14. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..ce3d20cc203 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/meta.json index 8840689d9ed..8663673f5c6 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/pirateeva.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183 (Github) for ss14", + "copyright": "Made by brainfood1183 (Github) for ss14. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..629584e995b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/meta.json index def2d42704e..c3caac82252 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/rd.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-OUTERCLOTHING-harpy", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..b8c26d6f41c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/meta.json index ef5e62cca40..0a78966c1d5 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/salvage.rsi/meta.json @@ -1,11 +1,11 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", - "size": { - "x": 32, - "y": 32 - }, + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, "states": [ { "name": "icon" @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -27,4 +31,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..0d8f373dc1b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/meta.json index 13748622fee..eb28d4c8a1f 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/santahardsuit.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Edited by StanTheCarpenter. Originally taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Edited by StanTheCarpenter. Originally taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..8c301cbe55c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-red.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..30cf54325e5 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/meta.json index 54a0ed85fa2..180439fbcce 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security-warden.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite made by Gtheglorious based on the sprite made by Alekshhh for SS14", + "copyright": "Sprite made by Gtheglorious based on the sprite made by Alekshhh for SS14. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..c06d8fae90d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/meta.json index 32d6d8901a7..8acf2ddc611 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Sprite made by Gtheglorious based on the sprite taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..999761e150b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/meta.json index f6a942a8956..c04f7d758c0 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/spatio.rsi/meta.json @@ -1,32 +1,34 @@ - -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Original by Emisse, modified by EmoGarbage404", - - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-OUTERCLOTHING-harpy", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Original by Emisse, modified by EmoGarbage404. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-harpy", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..df2abbbf030 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json index b9b739337be..30830125099 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, equipped-OUTERCLOTHING-monkey made by Dutch-VanDerLinde", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/fb2d71495bfe81446159ef528534193d09dd8d34, equipped-OUTERCLOTHING-monkey made by Dutch-VanDerLinde, vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "equipped-OUTERCLOTHING-monkey", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..24c1aa2a870 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/meta.json index 4aa4d60ccb8..3744e040b68 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiecommander.rsi/meta.json @@ -1,30 +1,34 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-OUTERCLOTHING-harpy", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-harpy", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..869cf41ce2a Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/meta.json index b85c75656c4..226372c9d38 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndieelite.rsi/meta.json @@ -1,30 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd, harpy by VMSolidus", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "equipped-OUTERCLOTHING-harpy", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd, harpy by VMSolidus. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-harpy", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..9417c5547b3 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json index 88d91565d77..2026bba8931 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/syndiemedic.rsi/meta.json @@ -1,11 +1,11 @@ { - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github), harpy by VMSolidus", - "size": { - "x": 32, - "y": 32 - }, + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Based on tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, modified by EmoGarbage404 (github), harpy by VMSolidus. Vox state made by Flareguy for SS14", + "size": { + "x": 32, + "y": 32 + }, "states": [ { "name": "icon" @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 @@ -27,4 +31,4 @@ "directions": 4 } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..d4e4ab0f53c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Hardsuits/wizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..091fe54d8b6 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/apronbotanist.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e0fd17d98a2 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/apronchef.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e4ea5d5fa4a Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/cardborg.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..a159e887771 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/meta.json index e482264df5f..232bec9c0a2 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/chef.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..94835833ccb Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/meta.json index e482264df5f..21cd9257fdf 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/classicponcho.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/fce54deb01d465957691ba2907218d4af4830db2/icons/mob/clothing/species/vox/suit.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..df08ef1986f Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/meta.json index 5de1afef0f3..ccfd0c03038 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/ghostsheet.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/pull/38809", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/pull/38809. Vox state by Flareguy for SS1", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..6423bd5c734 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/meta.json index 442bfb29202..b5f8619d65a 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/grey_hoodie.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -17,6 +17,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "open-equipped-OUTERCLOTHING", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..36e53e4396e Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/meta.json index 217a3f95112..3fa2c7657cb 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/nunrobe.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/a20589c401fc9b0f23c1dea08c56d4a1697adcd6", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} \ No newline at end of file +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from TGstation github https://github.com/tgstation/tgstation/commit/a20589c401fc9b0f23c1dea08c56d4a1697adcd6. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..ff43b16105d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/meta.json index b20ea0277f7..cd0053daea8 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/red_racoon.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Created by netwy(583844759429316618)", + "copyright": "Created by netwy(583844759429316618). Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..d5efb0d4b2b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/redwizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..b50aa58c48c Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/meta.json index 9a00c5741a8..ed75ee470b7 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/skubbody.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "EOBGames from tgstation", + "copyright": "EOBGames from tgstation. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -13,6 +13,10 @@ { "name": "equipped-OUTERCLOTHING", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/body-overlay-2-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/body-overlay-2-vox.png new file mode 100644 index 00000000000..0a23447f94e Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/body-overlay-2-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/meta.json index b41f0209d72..2eda10ef510 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/straight_jacket.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "body-overlay-2", "directions": 4 }, + { + "name": "body-overlay-2-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e39761b3608 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/violetwizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..a586ec3fe39 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/meta.json index e482264df5f..15aef26a56c 100644 --- a/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Misc/wizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..36cea26549a Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/meta.json index e9a9a4453d8..669e1d98574 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/bombsuit.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/760f0be7af33a31f5a08a3291864e91539d0ebb7", + "copyright": "Taken from cev-eris at commit https://github.com/discordia-space/CEV-Eris/commit/760f0be7af33a31f5a08a3291864e91539d0ebb7. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -18,6 +18,10 @@ "name": "equipped-OUTERCLOTHING-harpy", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..d9ccc1dd962 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/meta.json index e482264df5f..ca1146d007e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/chicken.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 } ] } diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..2fb7750843d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/meta.json index 4dcd7b13b58..136d76ea97e 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/eva.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "equipped-OUTERCLOTHING-monkey", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..99b555f7ac5 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/eva_emergency.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..9601695dacb Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/meta.json index 0482d086421..510a3431afe 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/eva_prisoner.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "equipped-OUTERCLOTHING-monkey", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..7f71b04f1cd Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/meta.json index 0482d086421..510a3431afe 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/eva_syndicate.rsi/meta.json @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "equipped-OUTERCLOTHING-monkey", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..920cc9e05f8 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/meta.json index 0a8c670a890..9f4fd0c0634 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/fire.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy edit by VMSolidus", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy edit by VMSolidus. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..c585862bb1d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/meta.json index e482264df5f..920eab55204 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/monkey.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..13f9dacef35 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/meta.json index 0a8c670a890..8c3ddde70a1 100644 --- a/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Suits/rad.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy edit by VMSolidus", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e, harpy edit by VMSolidus. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..50e6d79c20f Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/meta.json index e482264df5f..920eab55204 100644 --- a/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Vests/detvest.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..6d9f6dbead9 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/meta.json index 05ec90135ea..4c56c355a49 100644 --- a/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Vests/hazard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..ee35c40fbd7 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/meta.json index e482264df5f..920eab55204 100644 --- a/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Vests/vest.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state made by Flareguy for Space Station 14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..17d75d29b36 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/meta.json index e482264df5f..0e30ab4d3f1 100644 --- a/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/Vests/webvest.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/4f6190e2895e09116663ef282d3ce1d8b35c032e. Vox state by Flareguy for SS14", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-OUTERCLOTHING", "directions": 4 }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..440fc3375fa Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/meta.json index 7752722477b..19f610cdfe9 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coat.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} \ No newline at end of file +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..1d755313177 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatatmos.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..092d66ea3ef Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/meta.json index 7863947d1cc..19fcc6a9352 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatbar.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..0fca4396ea0 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/meta.json index 46b3e631a07..7ddd460a3bd 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcap.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62 , edited by Skarletto (github)", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62, edited by Skarletto (github). equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 and repaletted to match with the default state", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f4427249ec8 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatcargo.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..29002eaf6b1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatce.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..781df9000be Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/meta.json index 7863947d1cc..19fcc6a9352 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatclown.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..015e3250235 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatengi.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 00000000000..d279e92da28 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/equipped-OUTERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/icon.png new file mode 100644 index 00000000000..6f7573420d0 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-left.png new file mode 100644 index 00000000000..85a0b83457b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-right.png new file mode 100644 index 00000000000..70ade34a8d1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/meta.json new file mode 100644 index 00000000000..4010520850d --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathosarmored.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd, recolored by Github user PursuitinAshes", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..334e1e8fe8b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coathydro.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..7b1b9d883c1 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmed.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..f713d3c8464 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/meta.json index 7863947d1cc..19fcc6a9352 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatmime.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..438eced1b5e Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatminer.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..a7ff1040664 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatparamed.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..1634304d137 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsci.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..e67c55f114d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/meta.json index 7752722477b..5d9e9636f78 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatsec.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62. equipped-OUTERCLOTHING-vox state taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] } \ No newline at end of file diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING-vox.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING-vox.png new file mode 100644 index 00000000000..b4f8cacea5b Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING-vox.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING.png index 28cf03f49cc..baeeca8781a 100644 Binary files a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING.png and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/equipped-OUTERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/icon.png index eaf984f4378..854ea543e96 100644 Binary files a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/icon.png and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-left.png index df033631e9d..464c4bfc5e3 100644 Binary files a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-left.png and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-right.png index 77baaca885f..d537128b824 100644 Binary files a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-right.png and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/meta.json index 7863947d1cc..ade0905fb8b 100644 --- a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/meta.json +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwarden.rsi/meta.json @@ -1,26 +1,30 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "equipped-OUTERCLOTHING", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - } - ] -} \ No newline at end of file +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/31d6576ba8102135d058ef49c3cb6ecbe8db8a79 / https://github.com/tgstation/tgstation/commit/77cff42b6c514e73881a885036be4b4dd2949f62, recolored by Github user Dutch-VanDerLinde.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "equipped-OUTERCLOTHING-vox", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/equipped-OUTERCLOTHING.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/equipped-OUTERCLOTHING.png new file mode 100644 index 00000000000..28cf03f49cc Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/equipped-OUTERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/icon.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/icon.png new file mode 100644 index 00000000000..eaf984f4378 Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-left.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-left.png new file mode 100644 index 00000000000..df033631e9d Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-right.png b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-right.png new file mode 100644 index 00000000000..77baaca885f Binary files /dev/null and b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/meta.json b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/meta.json new file mode 100644 index 00000000000..c9f0d90ea13 --- /dev/null +++ b/Resources/Textures/Clothing/OuterClothing/WinterCoats/coatwardenarmored.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from vg at commit https://github.com/vgstation-coders/vgstation13/commit/a16e41020a93479e9a7e2af343b1b74f7f2a61bd", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-OUTERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..73ab1326b83 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/jackboots.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..0d3d83cbad4 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/meta.json index 8d56bf0c2bb..5b3afdcd749 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/tgstation/tgstation/commit/3d319f6157acc1c1cd9ebcb0f6f12641e051cf91", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/3d319f6157acc1c1cd9ebcb0f6f12641e051cf91. equipped-FEET-vox & on-equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi, and equipped-FEET-vox state modified to fix inconsistencies", "size": { "x": 32, "y": 32 @@ -15,6 +15,14 @@ "name": "on-equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, + { + "name": "on-equipped-FEET-vox", + "directions": 4 + }, { "name": "icon" }, diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/on-equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/on-equipped-FEET-vox.png new file mode 100644 index 00000000000..9c1af7f0619 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots-advanced.rsi/on-equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..ff7074dbe3d Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/meta.json index ead74d88966..ae71606af37 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/debf90acfcafa4fb8d6723a37e0b8ac556c0702b", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/debf90acfcafa4fb8d6723a37e0b8ac556c0702b. equipped-FEET-vox & on-equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi, and equipped-FEET-vox state modified to fix inconsistencies", "size": { "x": 32, "y": 32 @@ -15,6 +15,14 @@ "name": "on-equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, + { + "name": "on-equipped-FEET-vox", + "directions": 4 + }, { "name": "icon" }, diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/on-equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/on-equipped-FEET-vox.png new file mode 100644 index 00000000000..c14f7078345 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots-syndicate.rsi/on-equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..66083b253d4 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/meta.json index 96b3f4109e6..f2aa6dbc5b1 100644 --- a/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox & on-equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi, and equipped-FEET-vox state modified to fix inconsistencies", "size": { "x": 32, "y": 32 @@ -15,6 +15,14 @@ "name": "on-equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, + { + "name": "on-equipped-FEET-vox", + "directions": 4 + }, { "name": "icon" }, diff --git a/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/on-equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/on-equipped-FEET-vox.png new file mode 100644 index 00000000000..e9d3dffc764 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Boots/magboots.rsi/on-equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..02a752334bf Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Misc/slippers.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..a7383072977 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Misc/tourist.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..2dc1885cd37 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Specific/clown.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..73ab1326b83 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Specific/swat.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/equipped-FEET-vox.png b/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/equipped-FEET-vox.png new file mode 100644 index 00000000000..838d02bb453 Binary files /dev/null and b/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/equipped-FEET-vox.png differ diff --git a/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/meta.json b/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/meta.json index 54b1191d425..1abf6951f1e 100644 --- a/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/meta.json +++ b/Resources/Textures/Clothing/Shoes/Specific/wizard.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/7e4e9d432d88981fb9bb463970c5b98ce85c0abe. equipped-FEET-vox state taken from vgstation13 at https://github.com/vgstation-coders/vgstation13/blob/31d6576ba8102135d058ef49c3cb6ecbe8db8a79/icons/mob/species/vox/shoes.dmi", "size": { "x": 32, "y": 32 @@ -14,6 +14,10 @@ "name": "equipped-FEET", "directions": 4 }, + { + "name": "equipped-FEET-vox", + "directions": 4 + }, { "name": "inhand-left", "directions": 4 diff --git a/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png b/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png index 0fea6220634..4bb67f166d5 100644 Binary files a/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png and b/Resources/Textures/Clothing/Under/Socks/coder.rsi/equipped-FEET.png differ diff --git a/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json b/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json index 194b8c4f0f5..1bb04ab6eb6 100644 --- a/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json +++ b/Resources/Textures/Clothing/Under/Socks/coder.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039, equipped-FEET modified by Psychpsyo", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/equipped-INNERCLOTHING.png new file mode 100644 index 00000000000..145cf97b2e5 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/icon.png new file mode 100644 index 00000000000..28b2de16927 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-left.png new file mode 100644 index 00000000000..a85d0a11e9b Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-right.png new file mode 100644 index 00000000000..4d6da567de5 Binary files /dev/null and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/meta.json new file mode 100644 index 00000000000..d4ea50d555c --- /dev/null +++ b/Resources/Textures/Clothing/Uniforms/Jumpskirt/olddress.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "fujiwaranao", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-INNERCLOTHING", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png index 8ffa6e2e94c..8781d46b5f8 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/security.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/equipped-INNERCLOTHING.png index b3ecbd97129..8d2ae436492 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/equipped-INNERCLOTHING.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/icon.png index 18ab875179f..b08cd213dee 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/icon.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_officer.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png index 4e98c89cc93..830f482ab86 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING.png index 311e0aecb97..c92abfde99c 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/icon.png index aaee2537daa..65ef81a2529 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/icon.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-left.png index e0b2d4759be..4381a0172be 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-left.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-right.png index a2ecc2b551d..3855dc44e1b 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-right.png and b/Resources/Textures/Clothing/Uniforms/Jumpskirt/senior_physician.rsi/inhand-right.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/equipped-INNERCLOTHING.png index b3977c97489..2fb771d84c3 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/equipped-INNERCLOTHING.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/meta.json index 3f72fb44600..c11c48fe747 100644 --- a/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/meta.json +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/security.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039. In hand sprite scaled down by potato1234_x, monkey made by brainfood1183 (github) for ss14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c838ba21dae97db345e0113f99596decd1d66039. In hand sprite scaled down by potato1234_x, monkey made by brainfood1183 (github) for ss14. equipped-INNERCLOTHING edited by Dutch-VanDerLinde (github).", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_officer.rsi/meta.json b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_officer.rsi/meta.json index 913d9408814..bfad46e1841 100644 --- a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_officer.rsi/meta.json +++ b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_officer.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Edit by Nairodian (github) of secred_s taken from tgstation at pull request https://github.com/tgstation/tgstation/pull/2984", + "copyright": "Edit by Nairodian (github) of secred_s taken from tgstation at pull request https://github.com/tgstation/tgstation/pull/2984, jumpskirt sprite made by Flareguy and edited by Dutch-VanDerLinde.", "size": { "x": 32, "y": 32 diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png index 5248c1b09f2..1c5fc823ebd 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING-monkey.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING.png index f67f3c67bf0..3e68439c786 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/equipped-INNERCLOTHING.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/icon.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/icon.png index d5d956c4e51..7a4e5b493fd 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/icon.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/icon.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-left.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-left.png index e0b2d4759be..4381a0172be 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-left.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-left.png differ diff --git a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-right.png b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-right.png index a2ecc2b551d..3855dc44e1b 100644 Binary files a/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-right.png and b/Resources/Textures/Clothing/Uniforms/Jumpsuit/senior_physician.rsi/inhand-right.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/creampie_vox.png b/Resources/Textures/Effects/creampie.rsi/creampie_vox.png new file mode 100644 index 00000000000..dfe199b0c86 Binary files /dev/null and b/Resources/Textures/Effects/creampie.rsi/creampie_vox.png differ diff --git a/Resources/Textures/Effects/creampie.rsi/meta.json b/Resources/Textures/Effects/creampie.rsi/meta.json index 54e0cc73c2b..8db8a77945c 100644 --- a/Resources/Textures/Effects/creampie.rsi/meta.json +++ b/Resources/Textures/Effects/creampie.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0. creampie_moth by MilenVolf, creampie_arachnid by PixelTheKermit (Github)", + "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0. creampie_moth by MilenVolf, creampie_arachnid by PixelTheKermit (Github), creampie_vox by Errant", "size": { "x": 32, "y": 32 @@ -66,6 +66,10 @@ "name": "creampie_standborg", "directions": 4 }, + { + "name": "creampie_vox", + "directions": 4 + }, { "name": "creampie_xeno_crit" }, diff --git a/Resources/Textures/Interface/Alerts/deflecting.rsi/deflecting0.png b/Resources/Textures/Interface/Alerts/deflecting.rsi/deflecting0.png new file mode 100644 index 00000000000..37404e77f76 Binary files /dev/null and b/Resources/Textures/Interface/Alerts/deflecting.rsi/deflecting0.png differ diff --git a/Resources/Textures/Interface/Alerts/deflecting.rsi/meta.json b/Resources/Textures/Interface/Alerts/deflecting.rsi/meta.json new file mode 100644 index 00000000000..f5d94c891a7 --- /dev/null +++ b/Resources/Textures/Interface/Alerts/deflecting.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Deflecting icon by Ubaser", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "deflecting0" + } + ] +} diff --git a/Resources/Textures/Interface/Ashen/item_status_left.png b/Resources/Textures/Interface/Ashen/item_status_left.png new file mode 100644 index 00000000000..fb2bf2b9b4a Binary files /dev/null and b/Resources/Textures/Interface/Ashen/item_status_left.png differ diff --git a/Resources/Textures/Interface/Ashen/item_status_left_highlight.png b/Resources/Textures/Interface/Ashen/item_status_left_highlight.png new file mode 100644 index 00000000000..91cd15dd4cf Binary files /dev/null and b/Resources/Textures/Interface/Ashen/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Ashen/item_status_right.png b/Resources/Textures/Interface/Ashen/item_status_right.png new file mode 100644 index 00000000000..53f4f362d0a Binary files /dev/null and b/Resources/Textures/Interface/Ashen/item_status_right.png differ diff --git a/Resources/Textures/Interface/Ashen/item_status_right_highlight.png b/Resources/Textures/Interface/Ashen/item_status_right_highlight.png new file mode 100644 index 00000000000..ad16bab6d10 Binary files /dev/null and b/Resources/Textures/Interface/Ashen/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Ashen/template_small.png b/Resources/Textures/Interface/Ashen/template_small.png new file mode 100644 index 00000000000..f3a4379f76c Binary files /dev/null and b/Resources/Textures/Interface/Ashen/template_small.png differ diff --git a/Resources/Textures/Interface/Clockwork/item_status_left.png b/Resources/Textures/Interface/Clockwork/item_status_left.png new file mode 100644 index 00000000000..1ce950362d2 Binary files /dev/null and b/Resources/Textures/Interface/Clockwork/item_status_left.png differ diff --git a/Resources/Textures/Interface/Clockwork/item_status_left_highlight.png b/Resources/Textures/Interface/Clockwork/item_status_left_highlight.png new file mode 100644 index 00000000000..f715e062765 Binary files /dev/null and b/Resources/Textures/Interface/Clockwork/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Clockwork/item_status_right.png b/Resources/Textures/Interface/Clockwork/item_status_right.png new file mode 100644 index 00000000000..5ea5ffcffad Binary files /dev/null and b/Resources/Textures/Interface/Clockwork/item_status_right.png differ diff --git a/Resources/Textures/Interface/Clockwork/item_status_right_highlight.png b/Resources/Textures/Interface/Clockwork/item_status_right_highlight.png new file mode 100644 index 00000000000..315d595c925 Binary files /dev/null and b/Resources/Textures/Interface/Clockwork/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Default/item_status_left.png b/Resources/Textures/Interface/Default/item_status_left.png new file mode 100644 index 00000000000..6c980f226ec Binary files /dev/null and b/Resources/Textures/Interface/Default/item_status_left.png differ diff --git a/Resources/Textures/Interface/Default/item_status_left_highlight.png b/Resources/Textures/Interface/Default/item_status_left_highlight.png new file mode 100644 index 00000000000..87dea5cf100 Binary files /dev/null and b/Resources/Textures/Interface/Default/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Default/item_status_right.png b/Resources/Textures/Interface/Default/item_status_right.png new file mode 100644 index 00000000000..82ad44b48c1 Binary files /dev/null and b/Resources/Textures/Interface/Default/item_status_right.png differ diff --git a/Resources/Textures/Interface/Default/item_status_right_highlight.png b/Resources/Textures/Interface/Default/item_status_right_highlight.png new file mode 100644 index 00000000000..0c1c3448486 Binary files /dev/null and b/Resources/Textures/Interface/Default/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Emotes/attributions.yml b/Resources/Textures/Interface/Emotes/attributions.yml new file mode 100644 index 00000000000..125651e4194 --- /dev/null +++ b/Resources/Textures/Interface/Emotes/attributions.yml @@ -0,0 +1,117 @@ +# Attempted to keep the files in alphabetical order so its easier to audit. +# Finding individual authors is an unfeasible task. If you can reference the author please do so. + +- files: ["beep.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from borg_chest.png and borg_head.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["buzz.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing bee texture (0.png) by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["buzztwo.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing bee texture (0.png) by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["chime.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing desk bell texture (normal.png) by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["chirp.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing nymph texture (icon.png) by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["chitter.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from mothroach.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["clap.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["click.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing crab.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["cough.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["cry.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from scream.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["deathgasp.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from scream.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["honk.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from existing bikehorn texture (icon.png) by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["laugh.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from scream.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["ping.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["salute.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from scream.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["sigh.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["snap.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["squeak.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from mouse-0.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["squish.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from blue_adult_slime.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["vocal.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" + +- files: ["weh.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from plushie_lizard.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["whistle.png"] + license: "CC-BY-SA-3.0" + copyright: "Modified from scream.png by TyAshley (AllenTheGreat)" + source: "https://github.com/TyAshley" + +- files: ["yawn.png"] + license: "CC-BY-SA-3.0" + copyright: "Created by TyAshley (AllenTheGreat) at commit 7f6c7cd82943dbc9a1fe8a79d6a924ac600b3fdb" + source: "https://github.com/TyAshley" diff --git a/Resources/Textures/Interface/Emotes/beep.png b/Resources/Textures/Interface/Emotes/beep.png new file mode 100644 index 00000000000..f59b0925ab5 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/beep.png differ diff --git a/Resources/Textures/Interface/Emotes/buzz.png b/Resources/Textures/Interface/Emotes/buzz.png new file mode 100644 index 00000000000..da7ac363a47 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/buzz.png differ diff --git a/Resources/Textures/Interface/Emotes/buzztwo.png b/Resources/Textures/Interface/Emotes/buzztwo.png new file mode 100644 index 00000000000..460a8868a52 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/buzztwo.png differ diff --git a/Resources/Textures/Interface/Emotes/chime.png b/Resources/Textures/Interface/Emotes/chime.png new file mode 100644 index 00000000000..ca595be5d3b Binary files /dev/null and b/Resources/Textures/Interface/Emotes/chime.png differ diff --git a/Resources/Textures/Interface/Emotes/chirp.png b/Resources/Textures/Interface/Emotes/chirp.png new file mode 100644 index 00000000000..57e8b671439 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/chirp.png differ diff --git a/Resources/Textures/Interface/Emotes/chitter.png b/Resources/Textures/Interface/Emotes/chitter.png new file mode 100644 index 00000000000..f6e11012237 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/chitter.png differ diff --git a/Resources/Textures/Interface/Emotes/clap.png b/Resources/Textures/Interface/Emotes/clap.png new file mode 100644 index 00000000000..a0ef9e1316a Binary files /dev/null and b/Resources/Textures/Interface/Emotes/clap.png differ diff --git a/Resources/Textures/Interface/Emotes/click.png b/Resources/Textures/Interface/Emotes/click.png new file mode 100644 index 00000000000..539aea7b928 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/click.png differ diff --git a/Resources/Textures/Interface/Emotes/cough.png b/Resources/Textures/Interface/Emotes/cough.png new file mode 100644 index 00000000000..cb1c2832acc Binary files /dev/null and b/Resources/Textures/Interface/Emotes/cough.png differ diff --git a/Resources/Textures/Interface/Emotes/cry.png b/Resources/Textures/Interface/Emotes/cry.png new file mode 100644 index 00000000000..2793a11b9dc Binary files /dev/null and b/Resources/Textures/Interface/Emotes/cry.png differ diff --git a/Resources/Textures/Interface/Emotes/deathgasp.png b/Resources/Textures/Interface/Emotes/deathgasp.png new file mode 100644 index 00000000000..e27d0bb5734 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/deathgasp.png differ diff --git a/Resources/Textures/Interface/Emotes/honk.png b/Resources/Textures/Interface/Emotes/honk.png new file mode 100644 index 00000000000..19441e4a0ee Binary files /dev/null and b/Resources/Textures/Interface/Emotes/honk.png differ diff --git a/Resources/Textures/Interface/Emotes/laugh.png b/Resources/Textures/Interface/Emotes/laugh.png new file mode 100644 index 00000000000..a688fdb4432 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/laugh.png differ diff --git a/Resources/Textures/Interface/Emotes/ping.png b/Resources/Textures/Interface/Emotes/ping.png new file mode 100644 index 00000000000..7408eb1f28f Binary files /dev/null and b/Resources/Textures/Interface/Emotes/ping.png differ diff --git a/Resources/Textures/Interface/Emotes/salute.png b/Resources/Textures/Interface/Emotes/salute.png new file mode 100644 index 00000000000..5727d8fd854 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/salute.png differ diff --git a/Resources/Textures/Interface/Emotes/sigh.png b/Resources/Textures/Interface/Emotes/sigh.png new file mode 100644 index 00000000000..ff49a56360f Binary files /dev/null and b/Resources/Textures/Interface/Emotes/sigh.png differ diff --git a/Resources/Textures/Interface/Emotes/snap.png b/Resources/Textures/Interface/Emotes/snap.png new file mode 100644 index 00000000000..ae6d81c19d8 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/snap.png differ diff --git a/Resources/Textures/Interface/Emotes/squeak.png b/Resources/Textures/Interface/Emotes/squeak.png new file mode 100644 index 00000000000..e32a89f5989 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/squeak.png differ diff --git a/Resources/Textures/Interface/Emotes/squish.png b/Resources/Textures/Interface/Emotes/squish.png new file mode 100644 index 00000000000..efa1ce6c5ea Binary files /dev/null and b/Resources/Textures/Interface/Emotes/squish.png differ diff --git a/Resources/Textures/Interface/Emotes/vocal.png b/Resources/Textures/Interface/Emotes/vocal.png new file mode 100644 index 00000000000..9b129ec4669 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/vocal.png differ diff --git a/Resources/Textures/Interface/Emotes/weh.png b/Resources/Textures/Interface/Emotes/weh.png new file mode 100644 index 00000000000..fea5ad3b731 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/weh.png differ diff --git a/Resources/Textures/Interface/Emotes/whistle.png b/Resources/Textures/Interface/Emotes/whistle.png new file mode 100644 index 00000000000..029a52af231 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/whistle.png differ diff --git a/Resources/Textures/Interface/Emotes/yawn.png b/Resources/Textures/Interface/Emotes/yawn.png new file mode 100644 index 00000000000..8130fc9ab44 Binary files /dev/null and b/Resources/Textures/Interface/Emotes/yawn.png differ diff --git a/Resources/Textures/Interface/Minimalist/SlotBackground.png b/Resources/Textures/Interface/Minimalist/SlotBackground.png index eb0ee037fd5..85c944357ef 100644 Binary files a/Resources/Textures/Interface/Minimalist/SlotBackground.png and b/Resources/Textures/Interface/Minimalist/SlotBackground.png differ diff --git a/Resources/Textures/Interface/Minimalist/item_status_left.png b/Resources/Textures/Interface/Minimalist/item_status_left.png new file mode 100644 index 00000000000..d70eca2fe92 Binary files /dev/null and b/Resources/Textures/Interface/Minimalist/item_status_left.png differ diff --git a/Resources/Textures/Interface/Minimalist/item_status_left_highlight.png b/Resources/Textures/Interface/Minimalist/item_status_left_highlight.png new file mode 100644 index 00000000000..b69872cd89c Binary files /dev/null and b/Resources/Textures/Interface/Minimalist/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Minimalist/item_status_right.png b/Resources/Textures/Interface/Minimalist/item_status_right.png new file mode 100644 index 00000000000..89171b9b478 Binary files /dev/null and b/Resources/Textures/Interface/Minimalist/item_status_right.png differ diff --git a/Resources/Textures/Interface/Minimalist/item_status_right_highlight.png b/Resources/Textures/Interface/Minimalist/item_status_right_highlight.png new file mode 100644 index 00000000000..d1474cee120 Binary files /dev/null and b/Resources/Textures/Interface/Minimalist/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Minimalist/template_small.png b/Resources/Textures/Interface/Minimalist/template_small.png new file mode 100644 index 00000000000..85c944357ef Binary files /dev/null and b/Resources/Textures/Interface/Minimalist/template_small.png differ diff --git a/Resources/Textures/Interface/Nano/help.png b/Resources/Textures/Interface/Nano/help.png new file mode 100644 index 00000000000..17f52833341 Binary files /dev/null and b/Resources/Textures/Interface/Nano/help.png differ diff --git a/Resources/Textures/Interface/Nano/item_status_left.svg b/Resources/Textures/Interface/Nano/item_status_left.svg deleted file mode 100644 index c97f8de0167..00000000000 --- a/Resources/Textures/Interface/Nano/item_status_left.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/Resources/Textures/Interface/Nano/item_status_left.svg.96dpi.png b/Resources/Textures/Interface/Nano/item_status_left.svg.96dpi.png deleted file mode 100644 index e058fa73747..00000000000 Binary files a/Resources/Textures/Interface/Nano/item_status_left.svg.96dpi.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/item_status_middle.svg b/Resources/Textures/Interface/Nano/item_status_middle.svg deleted file mode 100644 index a913981db11..00000000000 --- a/Resources/Textures/Interface/Nano/item_status_middle.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/Resources/Textures/Interface/Nano/item_status_middle.svg.96dpi.png b/Resources/Textures/Interface/Nano/item_status_middle.svg.96dpi.png deleted file mode 100644 index ce41106b20c..00000000000 Binary files a/Resources/Textures/Interface/Nano/item_status_middle.svg.96dpi.png and /dev/null differ diff --git a/Resources/Textures/Interface/Nano/item_status_right.svg b/Resources/Textures/Interface/Nano/item_status_right.svg deleted file mode 100644 index d898bb2ce09..00000000000 --- a/Resources/Textures/Interface/Nano/item_status_right.svg +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - diff --git a/Resources/Textures/Interface/Nano/item_status_right.svg.96dpi.png b/Resources/Textures/Interface/Nano/item_status_right.svg.96dpi.png deleted file mode 100644 index fb7c4a9e6e6..00000000000 Binary files a/Resources/Textures/Interface/Nano/item_status_right.svg.96dpi.png and /dev/null differ diff --git a/Resources/Textures/Interface/Plasmafire/item_status_left.png b/Resources/Textures/Interface/Plasmafire/item_status_left.png new file mode 100644 index 00000000000..d5d25c98091 Binary files /dev/null and b/Resources/Textures/Interface/Plasmafire/item_status_left.png differ diff --git a/Resources/Textures/Interface/Plasmafire/item_status_left_highlight.png b/Resources/Textures/Interface/Plasmafire/item_status_left_highlight.png new file mode 100644 index 00000000000..afe37513fd5 Binary files /dev/null and b/Resources/Textures/Interface/Plasmafire/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Plasmafire/item_status_right.png b/Resources/Textures/Interface/Plasmafire/item_status_right.png new file mode 100644 index 00000000000..ca97f81c8f5 Binary files /dev/null and b/Resources/Textures/Interface/Plasmafire/item_status_right.png differ diff --git a/Resources/Textures/Interface/Plasmafire/item_status_right_highlight.png b/Resources/Textures/Interface/Plasmafire/item_status_right_highlight.png new file mode 100644 index 00000000000..b95822b7373 Binary files /dev/null and b/Resources/Textures/Interface/Plasmafire/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Retro/item_status_left.png b/Resources/Textures/Interface/Retro/item_status_left.png new file mode 100644 index 00000000000..21b107b84df Binary files /dev/null and b/Resources/Textures/Interface/Retro/item_status_left.png differ diff --git a/Resources/Textures/Interface/Retro/item_status_left_highlight.png b/Resources/Textures/Interface/Retro/item_status_left_highlight.png new file mode 100644 index 00000000000..fdd5a4fe7d6 Binary files /dev/null and b/Resources/Textures/Interface/Retro/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Retro/item_status_right.png b/Resources/Textures/Interface/Retro/item_status_right.png new file mode 100644 index 00000000000..5e7d54618d2 Binary files /dev/null and b/Resources/Textures/Interface/Retro/item_status_right.png differ diff --git a/Resources/Textures/Interface/Retro/item_status_right_highlight.png b/Resources/Textures/Interface/Retro/item_status_right_highlight.png new file mode 100644 index 00000000000..c6e12c41e69 Binary files /dev/null and b/Resources/Textures/Interface/Retro/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/Retro/template_small.png b/Resources/Textures/Interface/Retro/template_small.png new file mode 100644 index 00000000000..7244b37f5c7 Binary files /dev/null and b/Resources/Textures/Interface/Retro/template_small.png differ diff --git a/Resources/Textures/Interface/Slimecore/item_status_left.png b/Resources/Textures/Interface/Slimecore/item_status_left.png new file mode 100644 index 00000000000..a7d940f401f Binary files /dev/null and b/Resources/Textures/Interface/Slimecore/item_status_left.png differ diff --git a/Resources/Textures/Interface/Slimecore/item_status_left_highlight.png b/Resources/Textures/Interface/Slimecore/item_status_left_highlight.png new file mode 100644 index 00000000000..322355b1358 Binary files /dev/null and b/Resources/Textures/Interface/Slimecore/item_status_left_highlight.png differ diff --git a/Resources/Textures/Interface/Slimecore/item_status_right.png b/Resources/Textures/Interface/Slimecore/item_status_right.png new file mode 100644 index 00000000000..77b53340a63 Binary files /dev/null and b/Resources/Textures/Interface/Slimecore/item_status_right.png differ diff --git a/Resources/Textures/Interface/Slimecore/item_status_right_highlight.png b/Resources/Textures/Interface/Slimecore/item_status_right_highlight.png new file mode 100644 index 00000000000..1e1a631db4b Binary files /dev/null and b/Resources/Textures/Interface/Slimecore/item_status_right_highlight.png differ diff --git a/Resources/Textures/Interface/emotes.svg b/Resources/Textures/Interface/emotes.svg new file mode 100644 index 00000000000..352f7ed2941 --- /dev/null +++ b/Resources/Textures/Interface/emotes.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Resources/Textures/Interface/emotes.svg.192dpi.png b/Resources/Textures/Interface/emotes.svg.192dpi.png new file mode 100644 index 00000000000..4e1f3c4f481 Binary files /dev/null and b/Resources/Textures/Interface/emotes.svg.192dpi.png differ diff --git a/Resources/Textures/Interface/emotes.svg.192dpi.png.yml b/Resources/Textures/Interface/emotes.svg.192dpi.png.yml new file mode 100644 index 00000000000..dabd6601f78 --- /dev/null +++ b/Resources/Textures/Interface/emotes.svg.192dpi.png.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/LobbyScreens/attributions.yml b/Resources/Textures/LobbyScreens/attributions.yml index afe4af7bf29..4dd3dc945bf 100644 --- a/Resources/Textures/LobbyScreens/attributions.yml +++ b/Resources/Textures/LobbyScreens/attributions.yml @@ -37,3 +37,8 @@ license: "CC-BY-SA-3.0" copyright: "aserovich on discord" source: "https://github.com/space-wizards/space-station-14" + +- files: ["justaweekaway.webp"] + license: "CC-BY-SA-3.0" + copyright: "plantyfern on discord" + source: "https://github.com/space-wizards/space-station-14" \ No newline at end of file diff --git a/Resources/Textures/LobbyScreens/justaweekaway.webp b/Resources/Textures/LobbyScreens/justaweekaway.webp new file mode 100644 index 00000000000..6e8205043c9 Binary files /dev/null and b/Resources/Textures/LobbyScreens/justaweekaway.webp differ diff --git a/Resources/Textures/LobbyScreens/justaweekaway.yml b/Resources/Textures/LobbyScreens/justaweekaway.yml new file mode 100644 index 00000000000..5c43e233050 --- /dev/null +++ b/Resources/Textures/LobbyScreens/justaweekaway.yml @@ -0,0 +1,2 @@ +sample: + filter: true diff --git a/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json b/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json index cb94dfab3e1..78339d7b76d 100644 --- a/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/eyes.rsi/meta.json @@ -1 +1 @@ -{"version": 1, "license": "CC-BY-SA-3.0","copyright": "Vox_eyes Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb and human_eyes taken from https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf", "size": {"x": 32, "y": 32}, "states": [{"name": "diona", "directions": 4}, {"name": "eyes", "directions": 4}, {"name":"no_eyes"},{"name": "vox_eyes_s", "directions": 4}]} +{"version": 1, "license": "CC-BY-SA-3.0","copyright": "human_eyes taken from https://github.com/tgstation/tgstation/blob/8024397cc81c5f47f74cf4279e35728487d0a1a7/icons/mob/human_parts_greyscale.dmi and modified by DrSmugleaf", "size": {"x": 32, "y": 32}, "states": [{"name": "diona", "directions": 4}, {"name": "eyes", "directions": 4}, {"name":"no_eyes"}]} diff --git a/Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png b/Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png deleted file mode 100644 index 807e9374c45..00000000000 Binary files a/Resources/Textures/Mobs/Customization/eyes.rsi/vox_eyes_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json index 5cb41c258b8..8fd4f5e1b91 100644 --- a/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/human_hair.rsi/meta.json @@ -667,6 +667,10 @@ "name": "spikyponytail", "directions": 4 }, + { + "name": "spookylong", + "directions": 4 + }, { "name": "stail", "directions": 4 diff --git a/Resources/Textures/Mobs/Customization/human_hair.rsi/spookylong.png b/Resources/Textures/Mobs/Customization/human_hair.rsi/spookylong.png new file mode 100644 index 00000000000..4e79da275bc Binary files /dev/null and b/Resources/Textures/Mobs/Customization/human_hair.rsi/spookylong.png differ diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_axolotl.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_axolotl.png index f7f54acdaed..d61b60824c9 100644 Binary files a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_axolotl.png and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_axolotl.png differ diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png new file mode 100644 index 00000000000..dfbe573096b Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/frills_neckfull.png differ diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json index 8eaac10cd94..3770a771d8e 100644 --- a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large drawn by Ubaser. Wagging tail by SonicDC.", + "copyright": "https://github.com/Skyrat-SS13/Skyrat-tg/tree/40e3cdbb15b8bc0d5ef2fb46133adf805bda5297, while Argali, Ayrshire, Myrsore and Bighorn are drawn by Ubaser, and Kobold Ears are drawn by Pigeonpeas. Body_underbelly made by Nairod(github) for SS14. Large drawn by Ubaser. Wagging tail by SonicDC. Splotch modified from Sharp by KittenColony(github). Frills neckfull come from: https://github.com/Bubberstation/Bubberstation/commit/8bc6b83404803466a560b694bf22ef3c0ac266a2", "size": { "x": 32, "y": 32 @@ -87,391 +87,391 @@ "name": "tail_smooth_wagging_primary", "directions": 4, "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] ] }, { "name": "tail_smooth_wagging_secondary", "directions": 4, "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] ] }, { - "name": "tail_dtiger_wagging", - "directions": 4, - "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] + "name": "tail_dtiger_wagging", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 ] + ] }, { - "name": "tail_ltiger_wagging", - "directions": 4, - "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] + "name": "tail_ltiger_wagging", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 ] + ] }, { - "name": "tail_spikes_wagging", - "directions": 4, - "delays": [ - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ], - [ - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1, - 0.1 - ] + "name": "tail_spikes_wagging", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 ] + ] }, { "name": "snout_round", @@ -525,19 +525,19 @@ "name": "frills_divinity", "directions": 4 }, - { + { "name": "horns_double", "directions": 4 }, - { + { "name": "frills_axolotl", "directions": 4 }, - { + { "name": "frills_hood_primary", "directions": 4 }, - { + { "name": "frills_hood_secondary", "directions": 4 }, @@ -548,58 +548,70 @@ { "name": "body_tiger", "directions": 4 - }, - { - "name": "head_tiger", - "directions": 4 - }, - { - "name": "l_arm_tiger", - "directions": 4 - }, - { - "name": "l_leg_tiger", - "directions": 4 - }, - { - "name": "r_arm_tiger", - "directions": 4 - }, - { - "name": "horns_argali", - "directions": 4 - }, - { - "name": "horns_ayrshire", - "directions": 4 - }, - { - "name": "horns_myrsore", - "directions": 4 - }, - { - "name": "horns_bighorn", - "directions": 4 - }, - { - "name": "horns_kobold_ears", - "directions": 4 - }, - { - "name": "r_leg_tiger", - "directions": 4 - }, - { - "name": "horns_floppy_kobold_ears", - "directions": 4 - }, + }, + { + "name": "head_tiger", + "directions": 4 + }, + { + "name": "l_arm_tiger", + "directions": 4 + }, + { + "name": "l_leg_tiger", + "directions": 4 + }, + { + "name": "r_arm_tiger", + "directions": 4 + }, + { + "name": "horns_argali", + "directions": 4 + }, + { + "name": "horns_ayrshire", + "directions": 4 + }, + { + "name": "horns_myrsore", + "directions": 4 + }, + { + "name": "horns_bighorn", + "directions": 4 + }, + { + "name": "horns_kobold_ears", + "directions": 4 + }, + { + "name": "r_leg_tiger", + "directions": 4 + }, + { + "name": "horns_floppy_kobold_ears", + "directions": 4 + }, { "name": "body_underbelly", "directions": 4 - }, - { - "name": "body_backspikes", - "directions": 4 - } + }, + { + "name": "body_backspikes", + "directions": 4 + }, + { + "name": "snout_splotch_primary", + "directions": 4 + }, + { + "name": "snout_splotch_secondary", + "directions": 4 + }, + { + "name": "frills_neckfull", + "directions": 4 + } ] -} +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png new file mode 100644 index 00000000000..850b985e5dc Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_primary.png differ diff --git a/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_secondary.png b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_secondary.png new file mode 100644 index 00000000000..5a982ed3546 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/reptilian_parts.rsi/snout_splotch_secondary.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/beard_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/beard_s.png new file mode 100644 index 00000000000..92aeea8f360 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/beard_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/colonel_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/colonel_s.png new file mode 100644 index 00000000000..2e657d675af Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/colonel_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/fu_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/fu_s.png new file mode 100644 index 00000000000..87f97eeaeeb Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/fu_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/mane_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/mane_s.png new file mode 100644 index 00000000000..08b120f500e Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/mane_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json index c52ad8a2a2e..64eebb88830 100644 --- a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/meta.json @@ -1 +1,31 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/vgstation-coders/vgstation13/blob/02ff588d59b3c560c685d9ca75e882d32a72d8cb/icons/mob/human_face.dmi", "states": [{"name": "vox_beard_s", "directions": 4}, {"name": "vox_colonel_s", "directions": 4}, {"name": "vox_fu_s", "directions": 4}, {"name": "vox_neck_s", "directions": 4}, {"name": "vox_ruff_beard_s", "directions": 4}, {"name": "vox_ruff_beard_s2", "directions": 4}]} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/0f9ef5962f4422836c0a42f289fb24d018918cbc/icons/mob/sprite_accessories/vox/vox_facial_hair.dmi and greyscaled", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "colonel_s", + "directions": 4 + }, + { + "name": "fu_s", + "directions": 4 + }, + { + "name": "neck_s", + "directions": 4 + }, + { + "name": "beard_s", + "directions": 4 + }, + { + "name": "mane_s", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/neck_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/neck_s.png new file mode 100644 index 00000000000..f630e8ce8bc Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/neck_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png deleted file mode 100644 index 8e922e58dea..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_beard_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png deleted file mode 100644 index 8de4dd68030..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_colonel_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_fu_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_fu_s.png deleted file mode 100644 index e49e84baf0d..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_fu_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png deleted file mode 100644 index 9009717cee3..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_neck_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png deleted file mode 100644 index 365f134c44f..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png b/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_facial_hair.rsi/vox_ruff_beard_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/afro_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/afro_s.png new file mode 100644 index 00000000000..74b09a0635a Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/afro_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/braid_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/braid_s.png new file mode 100644 index 00000000000..ff2aa4acbc7 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/braid_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/crestedquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/crestedquills_s.png new file mode 100644 index 00000000000..f089905438f Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/crestedquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/emperorquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/emperorquills_s.png new file mode 100644 index 00000000000..899918e694c Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/emperorquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/flowing_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/flowing_s.png new file mode 100644 index 00000000000..98139350d4e Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/flowing_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/hawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/hawk_s.png new file mode 100644 index 00000000000..c262fc1d918 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/hawk_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/horns_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/horns_s.png new file mode 100644 index 00000000000..8891151c9fd Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/horns_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/keelquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/keelquills_s.png new file mode 100644 index 00000000000..c3c947bcce9 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/keelquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/keetquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/keetquills_s.png new file mode 100644 index 00000000000..910542dde13 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/keetquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/kingly_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/kingly_s.png new file mode 100644 index 00000000000..1d0a1d8d894 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/kingly_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/long_braid_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/long_braid_s.png new file mode 100644 index 00000000000..3df31052dbe Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/long_braid_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/mange_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/mange_s.png new file mode 100644 index 00000000000..afa934e8807 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/mange_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json index 2f141784244..9b08260bd64 100644 --- a/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json +++ b/Resources/Textures/Mobs/Customization/vox_hair.rsi/meta.json @@ -1 +1,99 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/vgstation-coders/vgstation13/blob/02ff588d59b3c560c685d9ca75e882d32a72d8cb/icons/mob/human_face.dmi", "states": [{"name": "vox_afro_s", "directions": 4}, {"name": "vox_afro_s2", "directions": 4}, {"name": "vox_bald_s", "directions": 4}, {"name": "vox_cropped_s", "directions": 4}, {"name": "vox_cropped_s2", "directions": 4}, {"name": "vox_horns_s", "directions": 4}, {"name": "vox_horns_s2", "directions": 4}, {"name": "vox_kingly_s", "directions": 4}, {"name": "vox_kingly_s2", "directions": 4}, {"name": "vox_mange_s", "directions": 4}, {"name": "vox_mange_s2", "directions": 4}, {"name": "vox_mohawk_s", "directions": 4}, {"name": "vox_mohawk_s2", "directions": 4}, {"name": "vox_nights_s", "directions": 4}, {"name": "vox_nights_s2", "directions": 4}, {"name": "vox_pony_s", "directions": 4}, {"name": "vox_pony_s2", "directions": 4}, {"name": "vox_rows_s", "directions": 4}, {"name": "vox_rows_s2", "directions": 4}, {"name": "vox_ruff_hawk_s", "directions": 4}, {"name": "vox_ruff_hawk_s2", "directions": 4}, {"name": "vox_shortquills_s", "directions": 4}, {"name": "vox_shortquills_s2", "directions": 4}, {"name": "vox_surf_s", "directions": 4}, {"name": "vox_surf_s2", "directions": 4}, {"name": "vox_yasu_s", "directions": 4}, {"name": "vox_yasu_s2", "directions": 4}]} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/dcd1f5d88a8c5ba9634fc3fce67a76ada45f71dc/icons/mob/sprite_accessories/vox/vox_hair.dmi and greyscaled", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "crestedquills_s", + "directions": 4 + }, + { + "name": "emperorquills_s", + "directions": 4 + }, + { + "name": "keelquills_s", + "directions": 4 + }, + { + "name": "keetquills_s", + "directions": 4 + }, + { + "name": "shortquills_s", + "directions": 4 + }, + { + "name": "tielquills_s", + "directions": 4 + }, + { + "name": "kingly_s", + "directions": 4 + }, + { + "name": "afro_s", + "directions": 4 + }, + { + "name": "yasu_s", + "directions": 4 + }, + { + "name": "razor_s", + "directions": 4 + }, + { + "name": "razor_clipped_s", + "directions": 4 + }, + { + "name": "mohawk_s", + "directions": 4 + }, + { + "name": "horns_s", + "directions": 4 + }, + { + "name": "nights_s", + "directions": 4 + }, + { + "name": "hawk_s", + "directions": 4 + }, + { + "name": "long_braid_s", + "directions": 4 + }, + { + "name": "short_braid_s", + "directions": 4 + }, + { + "name": "mange_s", + "directions": 4 + }, + { + "name": "ponytail_s", + "directions": 4 + }, + { + "name": "braid_s", + "directions": 4 + }, + { + "name": "surf_s", + "directions": 4 + }, + { + "name": "flowing_s", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/mohawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/mohawk_s.png new file mode 100644 index 00000000000..b8466620b8d Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/mohawk_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/nights_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/nights_s.png new file mode 100644 index 00000000000..68d2654dcd1 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/nights_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/ponytail_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/ponytail_s.png new file mode 100644 index 00000000000..316f08fe9a5 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/ponytail_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_clipped_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_clipped_s.png new file mode 100644 index 00000000000..e5ffe57daa0 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_clipped_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_s.png new file mode 100644 index 00000000000..0b57cec2c12 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/razor_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/short_braid_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/short_braid_s.png new file mode 100644 index 00000000000..6f7a1e86ca3 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/short_braid_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/shortquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/shortquills_s.png new file mode 100644 index 00000000000..a0d496aeed8 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/shortquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/surf_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/surf_s.png new file mode 100644 index 00000000000..712ccb542f3 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/surf_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/tielquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/tielquills_s.png new file mode 100644 index 00000000000..aa121bd3313 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/tielquills_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png deleted file mode 100644 index 60b9b18c21e..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_afro_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_bald_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png deleted file mode 100644 index 67574355ee4..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_cropped_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png deleted file mode 100644 index dbb4ae8f28e..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_horns_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png deleted file mode 100644 index 3f35429e14f..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_kingly_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png deleted file mode 100644 index 138c58e690a..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mange_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png deleted file mode 100644 index 0a5589b0bae..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_mohawk_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png deleted file mode 100644 index 0a587eafceb..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_nights_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png deleted file mode 100644 index a9ff211389f..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_pony_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png deleted file mode 100644 index cee8b9a1030..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_rows_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png deleted file mode 100644 index 41c3cb6decc..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_ruff_hawk_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png deleted file mode 100644 index c83ef673a54..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_shortquills_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png deleted file mode 100644 index df2191cacd2..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_surf_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png deleted file mode 100644 index 6461305e85e..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png deleted file mode 100644 index 0858c19f052..00000000000 Binary files a/Resources/Textures/Mobs/Customization/vox_hair.rsi/vox_yasu_s2.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Customization/vox_hair.rsi/yasu_s.png b/Resources/Textures/Mobs/Customization/vox_hair.rsi/yasu_s.png new file mode 100644 index 00000000000..6ee3de1dad2 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_hair.rsi/yasu_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/beak.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/beak.png new file mode 100644 index 00000000000..23744679b68 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/beak.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_arm.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_arm.png new file mode 100644 index 00000000000..e35fb3c6bfb Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_arm.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_foot.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_foot.png new file mode 100644 index 00000000000..5ab81e36168 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_foot.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_hand.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_hand.png new file mode 100644 index 00000000000..660da8a5d11 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_hand.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_leg.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_leg.png new file mode 100644 index 00000000000..1a81369838c Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/l_leg.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json new file mode 100644 index 00000000000..fd5c14b6a35 --- /dev/null +++ b/Resources/Textures/Mobs/Customization/vox_parts.rsi/meta.json @@ -0,0 +1,55 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, modified by Bhijn, Errant and Flareguy", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "beak", + "directions": 4 + }, + { + "name": "l_arm", + "directions": 4 + }, + { + "name": "l_foot", + "directions": 4 + }, + { + "name": "l_hand", + "directions": 4 + }, + { + "name": "l_leg", + "directions": 4 + }, + { + "name": "r_arm", + "directions": 4 + }, + { + "name": "r_foot", + "directions": 4 + }, + { + "name": "r_hand", + "directions": 4 + }, + { + "name": "r_leg", + "directions": 4 + }, + { + "name": "tail", + "directions": 4 + }, + { + "name": "tail_stenciled", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_arm.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_arm.png new file mode 100644 index 00000000000..c8c70752f44 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_arm.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_foot.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_foot.png new file mode 100644 index 00000000000..58dbe90b090 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_foot.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_hand.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_hand.png new file mode 100644 index 00000000000..e433456bf22 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_hand.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_leg.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_leg.png new file mode 100644 index 00000000000..d6167531291 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/r_leg.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail.png new file mode 100644 index 00000000000..0e63d3327bd Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_stenciled.png b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_stenciled.png new file mode 100644 index 00000000000..50627ac5220 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_parts.rsi/tail_stenciled.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_l_arm.png b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_l_arm.png new file mode 100644 index 00000000000..0ff82bbaf26 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_l_arm.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_r_arm.png b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_r_arm.png new file mode 100644 index 00000000000..774c96692c1 Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/heart_r_arm.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/hive_s.png b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/hive_s.png new file mode 100644 index 00000000000..8361f55864b Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/hive_s.png differ diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json new file mode 100644 index 00000000000..725fbb6a0db --- /dev/null +++ b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/ef7a4d962915cb36b138eeb59663f0053d4906fe/icons/mob/sprite_accessories/vox/vox_body_markings.dmi and modified by Flareguy", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "heart_l_arm", + "directions": 4 + }, + { + "name": "heart_r_arm", + "directions": 4 + }, + { + "name": "hive_s", + "directions": 4 + }, + { + "name": "nightling_s", + "directions": 4 + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/nightling_s.png b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/nightling_s.png new file mode 100644 index 00000000000..72b0b30fd5f Binary files /dev/null and b/Resources/Textures/Mobs/Customization/vox_tattoos.rsi/nightling_s.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/jumpsuit.png b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/jumpsuit.png new file mode 100644 index 00000000000..2c938634eb6 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/jumpsuit.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/displacement.rsi/meta.json b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/meta.json new file mode 100644 index 00000000000..6ea6c552b97 --- /dev/null +++ b/Resources/Textures/Mobs/Species/Vox/displacement.rsi/meta.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by PJB3005", + "size": { + "x": 32, + "y": 32 + }, + "load": { + "srgb": false + }, + "states": [ + { + "name": "jumpsuit", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/eyes.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/eyes.png new file mode 100644 index 00000000000..5069e90b535 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/eyes.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/full.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/full.png new file mode 100644 index 00000000000..6338e4d1128 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/full.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png new file mode 100644 index 00000000000..ec0dd8402e5 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png deleted file mode 100644 index 15c0ed8d66f..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_m.png deleted file mode 100644 index 15c0ed8d66f..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/groin_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/head.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/head.png new file mode 100644 index 00000000000..955e6c7b2aa Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/head.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_f.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_f.png deleted file mode 100644 index 6d92de1b903..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_m.png deleted file mode 100644 index 6d92de1b903..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/head_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_arm.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_arm.png index bdd61871c5f..258127dbae2 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_arm.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_foot.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_foot.png index d12c19cf0cb..3b81ae70595 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_foot.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png index 0d1048e090b..d321880c7b8 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_leg.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_leg.png index 20eebad8606..918b343f98c 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_leg.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/l_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json index 1070da1203d..4704e093b40 100644 --- a/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json +++ b/Resources/Textures/Mobs/Species/Vox/parts.rsi/meta.json @@ -1,26 +1,25 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 02ff588d59b3c560c685d9ca75e882d32a72d8cb, and modified by Bhijn, Errant and Flareguy", "size": { "x": 32, "y": 32 }, "states": [ { - "name": "groin_f", + "name": "eyes", "directions": 4 }, { - "name": "groin_m", - "directions": 4 + "name": "full" }, { - "name": "head_f", + "name": "groin", "directions": 4 }, { - "name": "head_m", + "name": "head", "directions": 4 }, { @@ -60,11 +59,7 @@ "directions": 4 }, { - "name": "torso_f", - "directions": 4 - }, - { - "name": "torso_m", + "name": "torso", "directions": 4 }, { diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png index 0c1f703efdf..766cd378ea8 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_arm.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_foot.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_foot.png index 80d3a787598..2511bc5252c 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_foot.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_foot.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png index d794c608bda..98f8b376a81 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_hand.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png index 37417e28157..45b1ae82e78 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/r_leg.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png new file mode 100644 index 00000000000..841d4097351 Binary files /dev/null and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso.png differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_f.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_f.png deleted file mode 100644 index 75bb51ed378..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_f.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png deleted file mode 100644 index 75bb51ed378..00000000000 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/torso_m.png and /dev/null differ diff --git a/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png b/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png index 31f75a79964..8eead3c97b7 100644 Binary files a/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png and b/Resources/Textures/Mobs/Species/Vox/parts.rsi/vox_m.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-1.png new file mode 100644 index 00000000000..aca8f4931d8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-2.png new file mode 100644 index 00000000000..4715162ebe2 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-3.png new file mode 100644 index 00000000000..04bfd58d03a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon.png new file mode 100644 index 00000000000..04bfd58d03a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon_empty.png new file mode 100644 index 00000000000..4d446abc54e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/meta.json new file mode 100644 index 00000000000..14c43f186f3 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/budgetinsulsdrink.rsi/meta.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Glass and fillstates by Hanzdegloker on Github.", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-1.png new file mode 100644 index 00000000000..e4e832ce8db Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-2.png new file mode 100644 index 00000000000..c778f3c428e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-3.png new file mode 100644 index 00000000000..480528bc96a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-4.png new file mode 100644 index 00000000000..da13e681397 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon.png new file mode 100644 index 00000000000..08de3090393 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon_empty.png new file mode 100644 index 00000000000..d46a00edd04 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/meta.json new file mode 100644 index 00000000000..32c5e0342d1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/coffeeglass.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by borkroman. Fill levels by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-1.png new file mode 100644 index 00000000000..a36d304a4dd Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-2.png new file mode 100644 index 00000000000..6351e9f3dd4 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-3.png new file mode 100644 index 00000000000..bb7bee49d05 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-4.png new file mode 100644 index 00000000000..1808bdbd041 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-5.png new file mode 100644 index 00000000000..734126d8668 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon.png new file mode 100644 index 00000000000..2894625a2e5 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon_empty.png new file mode 100644 index 00000000000..b20279f8f1b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/meta.json new file mode 100644 index 00000000000..ec55ebfa1f1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/colaglass.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-1.png new file mode 100644 index 00000000000..68731e8fcb0 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-2.png new file mode 100644 index 00000000000..716aebbb83a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-3.png new file mode 100644 index 00000000000..74f54a4c832 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-4.png new file mode 100644 index 00000000000..da440839643 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-5.png new file mode 100644 index 00000000000..db2b9315bfa Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon.png index 620cf5ea01e..6a68486662a 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon_empty.png new file mode 100644 index 00000000000..af2dcb404ce Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/meta.json index db0ac608ed0..ec55ebfa1f1 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/dr_gibb_glass.rsi/meta.json @@ -1 +1,32 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", "states": [{"name": "icon"}]} \ No newline at end of file +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon.png index 7a577d477ca..e9e2aea7168 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon_open.png b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon_open.png index b26d37e3779..44688ef3e92 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon_open.png and b/Resources/Textures/Objects/Consumable/Drinks/energy_drink.rsi/icon_open.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-1.png new file mode 100644 index 00000000000..613efd11712 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-2.png new file mode 100644 index 00000000000..785703f4df7 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-3.png new file mode 100644 index 00000000000..1f482c8df9b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-4.png new file mode 100644 index 00000000000..99c7dffa36f Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon.png new file mode 100644 index 00000000000..9c77c673ffb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon_empty.png new file mode 100644 index 00000000000..71eb4351836 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/meta.json new file mode 100644 index 00000000000..32c5e0342d1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/greenteaglass.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by borkroman. Fill levels by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/icon.png new file mode 100644 index 00000000000..228d098060c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/meta.json new file mode 100644 index 00000000000..f55a85dc265 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/icebucket.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Dezzzix; Discord: dezzzix", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] + } diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-1.png new file mode 100644 index 00000000000..2d217ef1477 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-2.png new file mode 100644 index 00000000000..d8ca5b63af8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-3.png new file mode 100644 index 00000000000..a65df2aaed0 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-4.png new file mode 100644 index 00000000000..3ae28ff68fe Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-5.png new file mode 100644 index 00000000000..72c2f4cecf0 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon.png new file mode 100644 index 00000000000..999834b1421 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon_empty.png new file mode 100644 index 00000000000..e10df8d1724 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/meta.json new file mode 100644 index 00000000000..ec55ebfa1f1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/icedgreenteaglass.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-1.png new file mode 100644 index 00000000000..04c8198fc97 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-2.png new file mode 100644 index 00000000000..367a9e178bd Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-3.png new file mode 100644 index 00000000000..02022cd03b9 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon.png index 61f63fd057b..96807c9a5d8 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon_empty.png new file mode 100644 index 00000000000..5d1f677b89b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/meta.json index db0ac608ed0..bdfdb18a0d0 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/iceglass.rsi/meta.json @@ -1 +1,26 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", "states": [{"name": "icon"}]} \ No newline at end of file +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by borkroman. Fill levels by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/icon.png new file mode 100644 index 00000000000..6c65ca02025 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/meta.json new file mode 100644 index 00000000000..f55a85dc265 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/jigger.rsi/meta.json @@ -0,0 +1,14 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Dezzzix; Discord: dezzzix", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + } + ] + } diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-1.png new file mode 100644 index 00000000000..48881271871 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-2.png new file mode 100644 index 00000000000..081ad92014b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-3.png new file mode 100644 index 00000000000..97a8f2c29b6 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-4.png new file mode 100644 index 00000000000..5b8af69ec86 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-5.png new file mode 100644 index 00000000000..9b2bc6a3f7a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon.png new file mode 100644 index 00000000000..9ee1bdd5176 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon_empty.png new file mode 100644 index 00000000000..abbdd77b271 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/meta.json new file mode 100644 index 00000000000..ec55ebfa1f1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/lemonjuiceglass.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-1.png new file mode 100644 index 00000000000..824ffcf3d65 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-2.png new file mode 100644 index 00000000000..5159ff36712 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-3.png new file mode 100644 index 00000000000..6d2115a95af Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-4.png new file mode 100644 index 00000000000..90ca019493a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-5.png new file mode 100644 index 00000000000..c50860e4d03 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-6.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-6.png new file mode 100644 index 00000000000..1488e2b6297 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/fill-6.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon.png new file mode 100644 index 00000000000..5fa26544fda Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon_empty.png new file mode 100644 index 00000000000..673679cb4ab Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/meta.json new file mode 100644 index 00000000000..5fe156daaae --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/moonshineglass.rsi/meta.json @@ -0,0 +1,35 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + }, + { + "name": "fill-6" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-1.png new file mode 100644 index 00000000000..6a56b31eeed Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-2.png new file mode 100644 index 00000000000..0a853551c53 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-3.png new file mode 100644 index 00000000000..92293d8cf22 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-4.png new file mode 100644 index 00000000000..85f6dea9b6a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-5.png new file mode 100644 index 00000000000..598d0be5b6d Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon.png new file mode 100644 index 00000000000..64e185065a5 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon_empty.png new file mode 100644 index 00000000000..fc940737b24 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/meta.json new file mode 100644 index 00000000000..ec55ebfa1f1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/orangejuiceglass.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-1.png new file mode 100644 index 00000000000..f5afa0bed8a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-2.png new file mode 100644 index 00000000000..79bcdcfb8cb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-3.png new file mode 100644 index 00000000000..772aa80d6a7 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon.png new file mode 100644 index 00000000000..772aa80d6a7 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon_empty.png new file mode 100644 index 00000000000..416d1f77176 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/meta.json new file mode 100644 index 00000000000..a26c7355aeb --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/rubberneck.rsi/meta.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "size": + { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "https://tgstation13.org/wiki/images/archive/4/4e/20220514022531%21Rubberneck.png. Fill levels by Hanzdegloker on GitHub.", + "states": + [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-1.png new file mode 100644 index 00000000000..077d84804eb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-2.png new file mode 100644 index 00000000000..763d02e7b8b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-3.png new file mode 100644 index 00000000000..ba76b0c22ba Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-4.png new file mode 100644 index 00000000000..ce9f636dbc5 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-5.png new file mode 100644 index 00000000000..b79be483635 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-6.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-6.png new file mode 100644 index 00000000000..9abb7c672bc Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/fill-6.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon.png index 5930cd7536c..e5eeaba2642 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon_empty.png new file mode 100644 index 00000000000..9e12bbbe4d7 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/meta.json index db0ac608ed0..5fe156daaae 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/space-up_glass.rsi/meta.json @@ -1 +1,35 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", "states": [{"name": "icon"}]} \ No newline at end of file +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + }, + { + "name": "fill-6" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-1.png new file mode 100644 index 00000000000..53db03fd96b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-2.png new file mode 100644 index 00000000000..601efddc0d9 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-3.png new file mode 100644 index 00000000000..4c50ee9fd7a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-4.png new file mode 100644 index 00000000000..38cf3fdbfc8 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-5.png new file mode 100644 index 00000000000..06be04566cd Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon.png index 812d7fd4887..6303745c500 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon_empty.png new file mode 100644 index 00000000000..d576502499c Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/meta.json index db0ac608ed0..ec55ebfa1f1 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/space_mountain_wind_glass.rsi/meta.json @@ -1 +1,32 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", "states": [{"name": "icon"}]} \ No newline at end of file +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-1.png new file mode 100644 index 00000000000..6dce3834eee Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-2.png new file mode 100644 index 00000000000..64dfddb473a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-3.png new file mode 100644 index 00000000000..2d281d5189a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-4.png new file mode 100644 index 00000000000..18ee0e42802 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-5.png new file mode 100644 index 00000000000..fe4fdead762 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-6.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-6.png new file mode 100644 index 00000000000..9a023cdb01e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-6.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-7.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-7.png new file mode 100644 index 00000000000..d7cd6ca7be5 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/fill-7.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon.png new file mode 100644 index 00000000000..cf2066eb378 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon_empty.png new file mode 100644 index 00000000000..5f3bc4f4c7f Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/meta.json new file mode 100644 index 00000000000..55fdf441638 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/sugarglass.rsi/meta.json @@ -0,0 +1,38 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + }, + { + "name": "fill-6" + }, + { + "name": "fill-7" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-1.png new file mode 100644 index 00000000000..05e6af71a78 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-2.png new file mode 100644 index 00000000000..cdf98da4a6b Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-3.png new file mode 100644 index 00000000000..1f514088a29 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-4.png new file mode 100644 index 00000000000..1a8ed41fde2 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon.png index 727bc3f2fbd..b31ed22db53 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon_empty.png new file mode 100644 index 00000000000..abad93afb35 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/meta.json index db0ac608ed0..019c918be99 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/teaglass.rsi/meta.json @@ -1 +1,29 @@ -{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA-3.0", "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi", "states": [{"name": "icon"}]} \ No newline at end of file +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-1.png index 202cfe304cf..30399627af6 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-1.png and b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-2.png index 8cb7a51424e..ed17e566935 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-2.png and b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-3.png index b17d5ec6b6f..a240f84f261 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-3.png and b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-4.png deleted file mode 100644 index 642c08ff685..00000000000 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/fill-4.png and /dev/null differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon.png index 4cac2a3aa48..b1510211cfe 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon.png and b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon_empty.png index 72476b77c00..dd4fd594d57 100644 Binary files a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon_empty.png and b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/meta.json index 20e933bb577..a2e79dfea11 100644 --- a/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Drinks/tequillaglass.rsi/meta.json @@ -1,31 +1,26 @@ { - "version": 1, - "size": + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ { - "x": 32, - "y": 32 + "name": "icon" }, - "license": "CC-BY-SA-3.0", - "copyright": "https://github.com/discordia-space/CEV-Eris/raw/f7aa28fd4b4d0386c3393d829681ebca526f1d2d/icons/obj/drinks.dmi. Fill levels by Tayrtahn on GitHub.", - "states": - [ - { - "name": "icon" - }, - { - "name": "icon_empty" - }, - { - "name": "fill-1" - }, - { - "name": "fill-2" - }, - { - "name": "fill-3" - }, - { - "name": "fill-4" - } - ] + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + } + ] } diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-1.png new file mode 100644 index 00000000000..0082f2b8143 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-2.png new file mode 100644 index 00000000000..cd667bfb334 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-3.png new file mode 100644 index 00000000000..0edd69b4dbd Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-4.png new file mode 100644 index 00000000000..f3cf6be999d Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-5.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-5.png new file mode 100644 index 00000000000..3e1c0d68c12 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/fill-5.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon.png new file mode 100644 index 00000000000..438ed21e517 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon_empty.png new file mode 100644 index 00000000000..1a306745d94 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/meta.json new file mode 100644 index 00000000000..ec55ebfa1f1 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/tonicglass.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + }, + { + "name": "fill-5" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-1.png new file mode 100644 index 00000000000..533f3b81770 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-2.png new file mode 100644 index 00000000000..7563af563a7 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-3.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-3.png new file mode 100644 index 00000000000..38c729ef387 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-3.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-4.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-4.png new file mode 100644 index 00000000000..010224c48eb Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/fill-4.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon.png new file mode 100644 index 00000000000..e551fdb07ba Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon_empty.png new file mode 100644 index 00000000000..ab9ba53863e Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/meta.json new file mode 100644 index 00000000000..019c918be99 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/watermelonglass.rsi/meta.json @@ -0,0 +1,29 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Made by RumiTiger", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + }, + { + "name": "fill-3" + }, + { + "name": "fill-4" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-1.png b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-1.png new file mode 100644 index 00000000000..3aef3bd8abd Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-1.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-2.png b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-2.png new file mode 100644 index 00000000000..ce4411ee1ef Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/fill-2.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon.png b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon.png new file mode 100644 index 00000000000..ce4411ee1ef Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon_empty.png b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon_empty.png new file mode 100644 index 00000000000..85097b80cca Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/icon_empty.png differ diff --git a/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/meta.json b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/meta.json new file mode 100644 index 00000000000..9743bd909e0 --- /dev/null +++ b/Resources/Textures/Objects/Consumable/Drinks/xenobasher.rsi/meta.json @@ -0,0 +1,23 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "Created by Hanzdegloker on github", + "states": [ + { + "name": "icon" + }, + { + "name": "icon_empty" + }, + { + "name": "fill-1" + }, + { + "name": "fill-2" + } + ] +} diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/lit-equipped-MASK-vox.png b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/lit-equipped-MASK-vox.png new file mode 100644 index 00000000000..c0723dcde67 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/lit-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/meta.json b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/meta.json index 6b6687d88c1..17b46355b69 100644 --- a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | lit-equipped-MASK-vox & unlit-equipped-MASK-vox states taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -57,6 +57,56 @@ ] ] }, + { + "name": "unlit-equipped-MASK-vox", + "directions": 4 + }, + { + "name": "lit-equipped-MASK-vox", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, { "name": "burnt-icon" }, diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/unlit-equipped-MASK-vox.png b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/unlit-equipped-MASK-vox.png new file mode 100644 index 00000000000..3cbf873967a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar-gold.rsi/unlit-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/lit-equipped-MASK-vox.png b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/lit-equipped-MASK-vox.png new file mode 100644 index 00000000000..c0723dcde67 Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/lit-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/meta.json b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/meta.json index 6b6687d88c1..17b46355b69 100644 --- a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/meta.json +++ b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bfc9c6ba8126ee8c41564d68c4bfb9ce37faa8f8 | vulpkanin version taken from Paradise station at https://github.com/ParadiseSS13/Paradise/commit/f0fa4e1fd809482fbc104a310aa34cebf7df157d | lit-equipped-MASK-vox & unlit-equipped-MASK-vox states taken from /vg/station at commit https://github.com/vgstation-coders/vgstation13/commit/4638130fab5ff0e9faa220688811349d3297a33e", "size": { "x": 32, "y": 32 @@ -57,6 +57,56 @@ ] ] }, + { + "name": "unlit-equipped-MASK-vox", + "directions": 4 + }, + { + "name": "lit-equipped-MASK-vox", + "directions": 4, + "delays": [ + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ], + [ + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1, + 0.1 + ] + ] + }, { "name": "burnt-icon" }, diff --git a/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/unlit-equipped-MASK-vox.png b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/unlit-equipped-MASK-vox.png new file mode 100644 index 00000000000..3cbf873967a Binary files /dev/null and b/Resources/Textures/Objects/Consumable/Smokeables/Cigars/cigar.rsi/unlit-equipped-MASK-vox.png differ diff --git a/Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/icon.png b/Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/icon.png similarity index 100% rename from Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/icon.png rename to Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/icon.png diff --git a/Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/meta.json b/Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/meta.json similarity index 100% rename from Resources/Textures/Objects/Consumable/TrashDrinks/goldschlagerbottle_empty.rsi/meta.json rename to Resources/Textures/Objects/Consumable/TrashDrinks/gildlagerbottle_empty.rsi/meta.json diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png new file mode 100644 index 00000000000..ce20b5eeeed Binary files /dev/null and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-left.png b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-left.png new file mode 100644 index 00000000000..2d3863145b9 Binary files /dev/null and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-right.png b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-right.png new file mode 100644 index 00000000000..1704b9c3c11 Binary files /dev/null and b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Devices/chameleon_projector.rsi/meta.json b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/meta.json new file mode 100644 index 00000000000..3eb42e9e6fa --- /dev/null +++ b/Resources/Textures/Objects/Devices/chameleon_projector.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at ", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Devices/flatpack.rsi/emitter.png b/Resources/Textures/Objects/Devices/flatpack.rsi/emitter.png new file mode 100644 index 00000000000..c663886f9cc Binary files /dev/null and b/Resources/Textures/Objects/Devices/flatpack.rsi/emitter.png differ diff --git a/Resources/Textures/Objects/Devices/flatpack.rsi/meta.json b/Resources/Textures/Objects/Devices/flatpack.rsi/meta.json index 2d1ca371418..8f46a0ca53b 100644 --- a/Resources/Textures/Objects/Devices/flatpack.rsi/meta.json +++ b/Resources/Textures/Objects/Devices/flatpack.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC0-1.0", - "copyright": "Created by EmoGarbage404 (github) for SS14, solar-assembly-part taken from tgstation and modified at https://tgstation13.org/wiki/Guide_to_construction#Solar_Panels_and_Trackers, ame-part taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1b7952787c06c21ef1623e494dcfe7cb1f46e041; singularity-generator, tesla-generator, radiation-collector, containment-field-generator, tesla-coil, grounding-rod inner icons made by lzk228", + "copyright": "Created by EmoGarbage404 (github) for SS14, solar-assembly-part taken from tgstation and modified at https://tgstation13.org/wiki/Guide_to_construction#Solar_Panels_and_Trackers, ame-part taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1b7952787c06c21ef1623e494dcfe7cb1f46e041; singularity-generator, tesla-generator, radiation-collector, containment-field-generator, tesla-coil, grounding-rod inner icons made by lzk228; emitter made by pigeonpeas", "size": { "x": 32, "y": 32 @@ -39,6 +39,9 @@ }, { "name": "containment-field-generator" + }, + { + "name": "emitter" } ] } diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/jammer-on.png b/Resources/Textures/Objects/Devices/jammer.rsi/jammer-on.png deleted file mode 100644 index 987e571b263..00000000000 Binary files a/Resources/Textures/Objects/Devices/jammer.rsi/jammer-on.png and /dev/null differ diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/jammer_high_charge.png b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_high_charge.png new file mode 100644 index 00000000000..e288427e717 Binary files /dev/null and b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_high_charge.png differ diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/jammer_low_charge.png b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_low_charge.png new file mode 100644 index 00000000000..0950a95df7e Binary files /dev/null and b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_low_charge.png differ diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/jammer_medium_charge.png b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_medium_charge.png new file mode 100644 index 00000000000..7c12da8606c Binary files /dev/null and b/Resources/Textures/Objects/Devices/jammer.rsi/jammer_medium_charge.png differ diff --git a/Resources/Textures/Objects/Devices/jammer.rsi/meta.json b/Resources/Textures/Objects/Devices/jammer.rsi/meta.json index c5cc9f56d24..d837374a87f 100644 --- a/Resources/Textures/Objects/Devices/jammer.rsi/meta.json +++ b/Resources/Textures/Objects/Devices/jammer.rsi/meta.json @@ -1,23 +1,33 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from Paradise at https://github.com/ParadiseSS13/Paradise/blob/93d9c70530c7299ef0af96fe2178096b2a62e036/icons/obj/device.dmi", + "copyright": "Taken from https://github.com/tgstation/tgstation/commit/c65da5a49477413310c81c460ea4b243a9f864dd with minor edits.", "size": { "x": 32, "y": 32 }, "states": [ { - "name": "jammer" + "name": "jammer", + "directions": 1 }, { - "name": "jammer-on", - "delays": [ - [ - 0.8, - 0.2 - ] + "name": "jammer_high_charge", + "directions": 1 + }, + { + "name": "jammer_medium_charge", + "directions": 1 + }, + { + "name": "jammer_low_charge", + "directions": 1, + "delays": [ + [ + 0.3, + 0.3 ] + ] } ] } diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/meta.json b/Resources/Textures/Objects/Devices/securityhandy.rsi/meta.json new file mode 100644 index 00000000000..18a2d932724 --- /dev/null +++ b/Resources/Textures/Objects/Devices/securityhandy.rsi/meta.json @@ -0,0 +1,28 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from cev-eris and modified by Swept at https://github.com/discordia-space/CEV-Eris/commit/efce5b6c3be75458ce238dcc01510e8f8a653ca6", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "walkietalkie" + }, + { + "name": "walkietalkie-inhand-left", + "directions": 4 + }, + { + "name": "walkietalkie-inhand-right", + "directions": 4 + }, + { + "name": "walkietalkie-off" + }, + { + "name": "walkietalkie-on" + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-left.png b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-left.png new file mode 100644 index 00000000000..5815169abfb Binary files /dev/null and b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-left.png differ diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-right.png b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-right.png new file mode 100644 index 00000000000..ed1e606cfb7 Binary files /dev/null and b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-inhand-right.png differ diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-off.png b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-off.png new file mode 100644 index 00000000000..2afdf8d962f Binary files /dev/null and b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-off.png differ diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-on.png b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-on.png new file mode 100644 index 00000000000..dfd79a64416 Binary files /dev/null and b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie-on.png differ diff --git a/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie.png b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie.png new file mode 100644 index 00000000000..12aaa3f2f09 Binary files /dev/null and b/Resources/Textures/Objects/Devices/securityhandy.rsi/walkietalkie.png differ diff --git a/Resources/Textures/Objects/Fun/whistle.rsi/meta.json b/Resources/Textures/Objects/Fun/whistle.rsi/meta.json deleted file mode 100644 index 59159ff6170..00000000000 --- a/Resources/Textures/Objects/Fun/whistle.rsi/meta.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "Made by Foleps (discord)", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "securityWhistle" - } - ] -} diff --git a/Resources/Textures/Objects/Fun/whistles.rsi/equipped-NECK.png b/Resources/Textures/Objects/Fun/whistles.rsi/equipped-NECK.png new file mode 100644 index 00000000000..89fdd599b2b Binary files /dev/null and b/Resources/Textures/Objects/Fun/whistles.rsi/equipped-NECK.png differ diff --git a/Resources/Textures/Objects/Fun/whistles.rsi/meta.json b/Resources/Textures/Objects/Fun/whistles.rsi/meta.json new file mode 100644 index 00000000000..4f59ad60e0f --- /dev/null +++ b/Resources/Textures/Objects/Fun/whistles.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "sec and whistle made by Foleps (discord), trench by Firewatchin (discord)", + "size": { + "x": 32, + "y": 32 + }, + + "states": [ + { + "name": "equipped-NECK", + "directions": 4 + }, + { + "name": "whistle" + }, + { + "name": "sec-equipped-NECK", + "directions": 4 + }, + { + "name": "sec" + }, + { + "name": "trench-equipped-NECK", + "directions": 4 + }, + { + "name": "trench" + } + ] +} diff --git a/Resources/Textures/Objects/Fun/whistles.rsi/sec-equipped-NECK.png b/Resources/Textures/Objects/Fun/whistles.rsi/sec-equipped-NECK.png new file mode 100644 index 00000000000..053c457f03c Binary files /dev/null and b/Resources/Textures/Objects/Fun/whistles.rsi/sec-equipped-NECK.png differ diff --git a/Resources/Textures/Objects/Fun/whistle.rsi/securityWhistle.png b/Resources/Textures/Objects/Fun/whistles.rsi/sec.png similarity index 100% rename from Resources/Textures/Objects/Fun/whistle.rsi/securityWhistle.png rename to Resources/Textures/Objects/Fun/whistles.rsi/sec.png diff --git a/Resources/Textures/Clothing/Neck/Misc/whistles.rsi/equipped-NECK.png b/Resources/Textures/Objects/Fun/whistles.rsi/trench-equipped-NECK.png similarity index 100% rename from Resources/Textures/Clothing/Neck/Misc/whistles.rsi/equipped-NECK.png rename to Resources/Textures/Objects/Fun/whistles.rsi/trench-equipped-NECK.png diff --git a/Resources/Textures/Clothing/Neck/Misc/whistles.rsi/icon.png b/Resources/Textures/Objects/Fun/whistles.rsi/trench.png similarity index 100% rename from Resources/Textures/Clothing/Neck/Misc/whistles.rsi/icon.png rename to Resources/Textures/Objects/Fun/whistles.rsi/trench.png diff --git a/Resources/Textures/Objects/Fun/whistles.rsi/whistle.png b/Resources/Textures/Objects/Fun/whistles.rsi/whistle.png new file mode 100644 index 00000000000..35db0ffca4b Binary files /dev/null and b/Resources/Textures/Objects/Fun/whistles.rsi/whistle.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/meta.json b/Resources/Textures/Objects/Materials/materials.rsi/meta.json index f0307208e92..78f497c0cda 100644 --- a/Resources/Textures/Objects/Materials/materials.rsi/meta.json +++ b/Resources/Textures/Objects/Materials/materials.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 , bear pelt remade by Alekshhh, wood sprite modified by MisterMecky, wood_2 and wood_3 made by MisterMecky based on wood sprite, cardboard sprites made by MisterMecky, bananium, bananium_1 and peel made by brainfood1183 (github) for ss14", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/c6e3401f2e7e1e55c57060cdf956a98ef1fefc24 , bear pelt remade by Alekshhh, wood sprite modified by MisterMecky, wood_2 and wood_3 made by MisterMecky based on wood sprite, cardboard sprites made by MisterMecky, bananium, bananium_1 and peel made by brainfood1183 (github) for ss14. Pyrotton sprites are drawn by Ubaser, using the cotton material sprites as a base.", "size": { "x": 32, "y": 32 @@ -66,6 +66,15 @@ { "name": "cotton_3" }, + { + "name": "pyrotton" + }, + { + "name": "pyrotton_2" + }, + { + "name": "pyrotton_3" + }, { "name": "diamond" }, diff --git a/Resources/Textures/Objects/Materials/materials.rsi/pyrotton.png b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton.png new file mode 100644 index 00000000000..daa6701c39d Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_2.png b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_2.png new file mode 100644 index 00000000000..fcd26895575 Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_2.png differ diff --git a/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_3.png b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_3.png new file mode 100644 index 00000000000..072ba2c6d14 Binary files /dev/null and b/Resources/Textures/Objects/Materials/materials.rsi/pyrotton_3.png differ diff --git a/Resources/Textures/Objects/Misc/chopstick.rsi/icon.png b/Resources/Textures/Objects/Misc/chopstick.rsi/icon.png new file mode 100644 index 00000000000..95acfb53cd1 Binary files /dev/null and b/Resources/Textures/Objects/Misc/chopstick.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-left.png b/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-left.png new file mode 100644 index 00000000000..48fa05ce347 Binary files /dev/null and b/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-right.png b/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-right.png new file mode 100644 index 00000000000..51dc3961d5f Binary files /dev/null and b/Resources/Textures/Objects/Misc/chopstick.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Misc/chopstick.rsi/meta.json b/Resources/Textures/Objects/Misc/chopstick.rsi/meta.json new file mode 100644 index 00000000000..78e9149225e --- /dev/null +++ b/Resources/Textures/Objects/Misc/chopstick.rsi/meta.json @@ -0,0 +1,25 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from goonstation at https://github.com/goonstation/goonstation/pull/1179", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "paired" + } + ] + } \ No newline at end of file diff --git a/Resources/Textures/Objects/Misc/chopstick.rsi/paired.png b/Resources/Textures/Objects/Misc/chopstick.rsi/paired.png new file mode 100644 index 00000000000..220dc31ecba Binary files /dev/null and b/Resources/Textures/Objects/Misc/chopstick.rsi/paired.png differ diff --git a/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-left.png b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-left.png new file mode 100644 index 00000000000..fba15fa255f Binary files /dev/null and b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-left.png differ diff --git a/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-right.png b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-right.png new file mode 100644 index 00000000000..d2b32fd8b8a Binary files /dev/null and b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon-inhand-right.png differ diff --git a/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon.png b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon.png new file mode 100644 index 00000000000..f24ded7e6b8 Binary files /dev/null and b/Resources/Textures/Objects/Misc/utensils.rsi/bar_spoon.png differ diff --git a/Resources/Textures/Objects/Misc/utensils.rsi/meta.json b/Resources/Textures/Objects/Misc/utensils.rsi/meta.json index 30dd4e85643..77aeb5e3c13 100644 --- a/Resources/Textures/Objects/Misc/utensils.rsi/meta.json +++ b/Resources/Textures/Objects/Misc/utensils.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432 and modified by Swept", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/e1142f20f5e4661cb6845cfcf2dd69f864d67432 and modified by Swept; Bar spoon by Dezzzix", "size": { "x": 32, "y": 32 @@ -40,6 +40,17 @@ }, { "name": "plastic_knife" + }, + { + "name": "bar_spoon" + }, + { + "name": "bar_spoon-inhand-left", + "directions": 4 + }, + { + "name": "bar_spoon-inhand-right", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-equipped-BACKPACK.png b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-equipped-BACKPACK.png new file mode 100644 index 00000000000..500ad05704c Binary files /dev/null and b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-equipped-BACKPACK.png differ diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-unlit.png b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-unlit.png new file mode 100644 index 00000000000..6c902b7d7ef Binary files /dev/null and b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging-unlit.png differ diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/charging.png b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging.png new file mode 100644 index 00000000000..6105bb4ad3b Binary files /dev/null and b/Resources/Textures/Objects/Power/portable_recharger.rsi/charging.png differ diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-left.png b/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-left.png new file mode 100644 index 00000000000..e3bc6d82993 Binary files /dev/null and b/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-right.png b/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-right.png new file mode 100644 index 00000000000..8c651922317 Binary files /dev/null and b/Resources/Textures/Objects/Power/portable_recharger.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Power/portable_recharger.rsi/meta.json b/Resources/Textures/Objects/Power/portable_recharger.rsi/meta.json new file mode 100644 index 00000000000..794f491bdb9 --- /dev/null +++ b/Resources/Textures/Objects/Power/portable_recharger.rsi/meta.json @@ -0,0 +1,92 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by Lomovar", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "charging", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "charging-equipped-BACKPACK", + "directions": 4, + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ], + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "charging-unlit", + "delays": [ + [ + 0.3, + 0.3, + 0.3, + 0.3, + 0.3, + 0.3 + ] + ] + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} + diff --git a/Resources/Textures/Objects/Specific/Chapel/quran.rsi/icon.png b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/icon.png new file mode 100644 index 00000000000..0c710e8850c Binary files /dev/null and b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-left.png b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-left.png new file mode 100644 index 00000000000..f5c0eca3159 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-right.png b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-right.png new file mode 100644 index 00000000000..bc8b034185e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Specific/Chapel/quran.rsi/meta.json b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/meta.json new file mode 100644 index 00000000000..64d37670f1c --- /dev/null +++ b/Resources/Textures/Objects/Specific/Chapel/quran.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a, modified by Terraspark4941", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/chili.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/chili.rsi/produce.png index 5033cdecc75..873f89e1811 100644 Binary files a/Resources/Textures/Objects/Specific/Hydroponics/chili.rsi/produce.png and b/Resources/Textures/Objects/Specific/Hydroponics/chili.rsi/produce.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/chilly.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/chilly.rsi/produce.png index 45ea8a32f5b..b2c59dc31a1 100644 Binary files a/Resources/Textures/Objects/Specific/Hydroponics/chilly.rsi/produce.png and b/Resources/Textures/Objects/Specific/Hydroponics/chilly.rsi/produce.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/dead.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/dead.png new file mode 100644 index 00000000000..39d4b40f4c2 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/dead.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/harvest.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/harvest.png new file mode 100644 index 00000000000..1012ccfe03b Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/harvest.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/meta.json new file mode 100644 index 00000000000..4a6e3c94fca --- /dev/null +++ b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/meta.json @@ -0,0 +1,32 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Drawn by Ubaser, using the cotton sprites as a base.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "dead" + }, + { + "name": "harvest" + }, + { + "name": "produce" + }, + { + "name": "seed" + }, + { + "name": "stage-1" + }, + { + "name": "stage-2" + }, + { + "name": "stage-3" + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/produce.png new file mode 100644 index 00000000000..72a98653c8f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/produce.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/seed.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/seed.png new file mode 100644 index 00000000000..6528f4f326a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/seed.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-1.png new file mode 100644 index 00000000000..c86f85f0d25 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-1.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-2.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-2.png new file mode 100644 index 00000000000..7bc634ce83a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-2.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-3.png new file mode 100644 index 00000000000..31aa7399f58 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/pyrotton.rsi/stage-3.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dead.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dead.png new file mode 100644 index 00000000000..2eb3c64ca9e Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dead.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dried.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dried.png new file mode 100644 index 00000000000..77f23e938c5 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/dried.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/harvest.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/harvest.png new file mode 100644 index 00000000000..9702e5b4881 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/harvest.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/meta.json b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/meta.json new file mode 100644 index 00000000000..e5bfeb99ef8 --- /dev/null +++ b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/meta.json @@ -0,0 +1,173 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from https://github.com/vgstation-coders/vgstation13 at 1dbcf389b0ec6b2c51b002df5fef8dd1519f8068 and modified by potato1234_x", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "dead" + }, + { + "name": "harvest", + "delays": + [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + }, + { + "name": "powderpile_rainbow" + }, + { + "name": "produce", + "delays": + [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + }, + { + "name": "dried" + }, + { + "name": "seed" + }, + { + "name": "stage-1", + "delays": + [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + }, + { + "name": "stage-2", + "delays": + [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + }, + { + "name": "stage-3", + "delays": + [ + [ + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08, + 0.08 + ] + ] + } + ] +} diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/powderpile_rainbow.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/powderpile_rainbow.png new file mode 100644 index 00000000000..15057f8785f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/powderpile_rainbow.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/produce.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/produce.png new file mode 100644 index 00000000000..400fed1b21d Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/produce.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/seed.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/seed.png new file mode 100644 index 00000000000..fa194148f3a Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/seed.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-1.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-1.png new file mode 100644 index 00000000000..8a3e17b098f Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-1.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-2.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-2.png new file mode 100644 index 00000000000..d30ed1ed264 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-2.png differ diff --git a/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-3.png b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-3.png new file mode 100644 index 00000000000..f4880b69e05 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Hydroponics/rainbow_cannabis.rsi/stage-3.png differ diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-bomb.png b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-bomb.png new file mode 100644 index 00000000000..5f876573f38 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/icon-bomb.png differ diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json index ce8f8187b7d..1b3eba668d1 100644 --- a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json +++ b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC0-1.0", - "copyright": "Created by EmoGarbage404 (github) for Space Station 14. icon-construction.png created by deltanedas (github).", + "copyright": "Created by EmoGarbage404 (github) for Space Station 14. icon-construction.png created by deltanedas (github). syndicateborgbomb.png created by Mangohydra (github).", "size": { "x": 32, "y": 32 @@ -112,6 +112,9 @@ { "name": "janitor" }, + { + "name": "icon-bomb" + }, { "name": "medical" }, @@ -124,6 +127,9 @@ { "name": "service" }, + { + "name": "syndicateborgbomb" + }, { "name": "syndicate" } diff --git a/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/syndicateborgbomb.png b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/syndicateborgbomb.png new file mode 100644 index 00000000000..c5238b96fc3 Binary files /dev/null and b/Resources/Textures/Objects/Specific/Robotics/borgmodule.rsi/syndicateborgbomb.png differ diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json index b30927da33c..0cba2f59d93 100644 --- a/Resources/Textures/Objects/Storage/boxes.rsi/meta.json +++ b/Resources/Textures/Objects/Storage/boxes.rsi/meta.json @@ -197,6 +197,9 @@ { "name": "shellslug" }, + { + "name": "shelluranium" + }, { "name": "shelltoy" }, diff --git a/Resources/Textures/Objects/Storage/boxes.rsi/shelluranium.png b/Resources/Textures/Objects/Storage/boxes.rsi/shelluranium.png new file mode 100644 index 00000000000..2a4e1dee152 Binary files /dev/null and b/Resources/Textures/Objects/Storage/boxes.rsi/shelluranium.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..a37261e3f7b Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json index b4d4730957e..c71ae8955eb 100644 --- a/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency.rsi/meta.json @@ -71,6 +71,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_clown.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_clown.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..dd19aa56804 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_clown.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_clown.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_clown.rsi/meta.json index 489cf3072ae..21d23712e98 100644 --- a/Resources/Textures/Objects/Tanks/emergency_clown.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_clown.rsi/meta.json @@ -66,6 +66,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_double.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..f139bc6db21 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_double.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json index 6b3765d794d..b3ab67fad65 100644 --- a/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_double.rsi/meta.json @@ -71,6 +71,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..7e2f947d343 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/meta.json index ce287bf2779..74fc108c09c 100644 --- a/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_double_red.rsi/meta.json @@ -66,6 +66,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_extended.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_extended.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..0470c6895f3 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_extended.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_extended.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_extended.rsi/meta.json index a1661aee78c..fe19dcec1cf 100644 --- a/Resources/Textures/Objects/Tanks/emergency_extended.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_extended.rsi/meta.json @@ -66,6 +66,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..db800b2a3bf Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/meta.json index ce287bf2779..74fc108c09c 100644 --- a/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_extended_red.rsi/meta.json @@ -66,6 +66,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_red.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_red.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..db800b2a3bf Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_red.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_red.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_red.rsi/meta.json index ce3d401ca2f..d71cdae541c 100644 --- a/Resources/Textures/Objects/Tanks/emergency_red.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_red.rsi/meta.json @@ -66,6 +66,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..0470c6895f3 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json index 6b3765d794d..b3ab67fad65 100644 --- a/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/emergency_yellow.rsi/meta.json @@ -71,6 +71,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Tanks/plasma.rsi/equipped-SUITSTORAGE.png b/Resources/Textures/Objects/Tanks/plasma.rsi/equipped-SUITSTORAGE.png new file mode 100644 index 00000000000..e282da2e6d2 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/plasma.rsi/equipped-SUITSTORAGE.png differ diff --git a/Resources/Textures/Objects/Tanks/plasma.rsi/meta.json b/Resources/Textures/Objects/Tanks/plasma.rsi/meta.json index a88e367a852..2d3199f75cd 100644 --- a/Resources/Textures/Objects/Tanks/plasma.rsi/meta.json +++ b/Resources/Textures/Objects/Tanks/plasma.rsi/meta.json @@ -21,6 +21,10 @@ { "name": "inhand-right", "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/base.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/base.png index d6da03ed28d..003858cf9d9 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/base.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/base.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/icon.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/icon.png index d2e461be282..88be89b3780 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/icon.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-0.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-0.png index 32fba189df8..042d52f5d74 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-0.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-0.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-1.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-1.png index b0fa62d39f2..5e64562bdc3 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-1.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-1.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-2.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-2.png index 4ad441aa0b0..df4767bff9f 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-2.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-2.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-3.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-3.png index 1678a31534f..fcbbc48af1a 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-3.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-3.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-4.png b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-4.png index 5300c65d31a..40e557d736c 100644 Binary files a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-4.png and b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/mag-unshaded-4.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/meta.json index 04e2ac93099..86ecf2bff1a 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/antiquelasergun.rsi/meta.json @@ -1,80 +1,80 @@ -{ - "version": 1, - "license": "CC-BY-SA-3.0", - "copyright": "taken from tg station at commit https://github.com/tgstation/tgstation/commit/8b7f8ba6a3327c7381967c550f185dffafd11a57", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-0" - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left-0", - "directions": 4 - }, - { - "name": "inhand-right-0", - "directions": 4 - }, - { - "name": "inhand-left-1", - "directions": 4 - }, - { - "name": "inhand-right-1", - "directions": 4 - }, - { - "name": "inhand-left-2", - "directions": 4 - }, - { - "name": "inhand-right-2", - "directions": 4 - }, - { - "name": "inhand-left-3", - "directions": 4 - }, - { - "name": "inhand-right-3", - "directions": 4 - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BELT", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } - ] -} +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "icon by RiceMar1244 based on icon taken from tg station at commit https://github.com/tgstation/tgstation/commit/8b7f8ba6a3327c7381967c550f185dffafd11a57", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-0" + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left-0", + "directions": 4 + }, + { + "name": "inhand-right-0", + "directions": 4 + }, + { + "name": "inhand-left-1", + "directions": 4 + }, + { + "name": "inhand-right-1", + "directions": 4 + }, + { + "name": "inhand-left-2", + "directions": 4 + }, + { + "name": "inhand-right-2", + "directions": 4 + }, + { + "name": "inhand-left-3", + "directions": 4 + }, + { + "name": "inhand-right-3", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/meta.json index 6657216b76b..acbd06c2708 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/meta.json @@ -1,77 +1,85 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/125c975f1b3bf9826b37029e9ab5a5f89e975a7e, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/125c975f1b3bf9826b37029e9ab5a5f89e975a7e, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, - "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "0-inhand-left", - "directions": 4 - }, - { - "name": "0-inhand-right", - "directions": 4 - }, - { - "name": "25-inhand-left", - "directions": 4 - }, - { - "name": "25-inhand-right", - "directions": 4 - }, - { - "name": "50-inhand-left", - "directions": 4 - }, - { - "name": "50-inhand-right", - "directions": 4 - }, - { - "name": "75-inhand-left", - "directions": 4 - }, - { - "name": "75-inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } - ] + "states": [ + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "0-inhand-left", + "directions": 4 + }, + { + "name": "0-inhand-right", + "directions": 4 + }, + { + "name": "25-inhand-left", + "directions": 4 + }, + { + "name": "25-inhand-right", + "directions": 4 + }, + { + "name": "50-inhand-left", + "directions": 4 + }, + { + "name": "50-inhand-right", + "directions": 4 + }, + { + "name": "75-inhand-left", + "directions": 4 + }, + { + "name": "75-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..38327d97081 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..4e0a357b844 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_cannon.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/meta.json index 7ec48da4fec..2b374ec4dd8 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/meta.json @@ -1,45 +1,53 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from Polaris at https://github.com/PolarisSS13/Polaris/commit/9ded73fb85b9106d6bbf1c9a34d1d2fa27ee0e2e, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from Polaris at https://github.com/PolarisSS13/Polaris/commit/9ded73fb85b9106d6bbf1c9a34d1d2fa27ee0e2e, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..126915fd270 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..93a9303c5ea Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/laser_gun.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/meta.json index 3b48bfc87c3..434d66fcfd8 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/meta.json @@ -1,45 +1,53 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/27386/commits/4814da0f8e0d88f430c8b335e541e0a7734755a2 backpack sprite by Peptide (copy of pulse rifle), backpack sling sprite edited by Boaz1111", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/27386/commits/4814da0f8e0d88f430c8b335e541e0a7734755a2 backpack sprite by Peptide (copy of pulse rifle), backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..b9df7a2cb2d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..644db232d2e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_carbine.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/meta.json index 1a906ef965d..023ad90cfae 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/meta.json @@ -1,45 +1,53 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/27386/commits/4814da0f8e0d88f430c8b335e541e0a7734755a2, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/27386/commits/4814da0f8e0d88f430c8b335e541e0a7734755a2, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..b9df7a2cb2d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..644db232d2e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/pulse_rifle.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/meta.json index 990ba511859..8766242121a 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/meta.json @@ -1,54 +1,62 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/raw/167a810bc8534a56c74ffa8f1373acd3b1ac70ee/icons/obj/guns/energy/xray.dmi, backpack sprite by peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from cev-eris at https://github.com/discordia-space/CEV-Eris/raw/167a810bc8534a56c74ffa8f1373acd3b1ac70ee/icons/obj/guns/energy/xray.dmi, backpack sprite by peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, - "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "mag-unshaded-0", - "delays": [ - [ - 0.3, - 0.3 - ] - ] - }, - { - "name": "mag-unshaded-1" - }, - { - "name": "mag-unshaded-2" - }, - { - "name": "mag-unshaded-3" - }, - { - "name": "mag-unshaded-4" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } - ] + "states": [ + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "mag-unshaded-0", + "delays": [ + [ + 0.3, + 0.3 + ] + ] + }, + { + "name": "mag-unshaded-1" + }, + { + "name": "mag-unshaded-2" + }, + { + "name": "mag-unshaded-3" + }, + { + "name": "mag-unshaded-4" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } + ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..9fa2fafdff6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..63615e2df1f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Battery/xray.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/meta.json index a5e32a3b395..d3b991783f4 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-4.0", - "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/pull/6042/commits/64916c98f4847acc4adf3a2416bf78c005fd7dd7, https://github.com/discordia-space/CEV-Eris/blob/master/icons/obj/guns/launcher/grenadelauncher.dmi, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/pull/6042/commits/64916c98f4847acc4adf3a2416bf78c005fd7dd7, https://github.com/discordia-space/CEV-Eris/blob/master/icons/obj/guns/launcher/grenadelauncher.dmi, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -21,11 +21,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..a1d40617d2f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..146fe9b1c2a Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Launchers/china_lake.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/meta.json index 919d0f87ac0..0257e70364f 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/pull/6042/commits/64916c98f4847acc4adf3a2416bf78c005fd7dd7, https://github.com/discordia-space/CEV-Eris/raw/e1a3cbe9ba2e6e29b7f1cad1bb456b390aac936d/icons/obj/guns/projectile.dmi, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/pull/6042/commits/64916c98f4847acc4adf3a2416bf78c005fd7dd7, https://github.com/discordia-space/CEV-Eris/raw/e1a3cbe9ba2e6e29b7f1cad1bb456b390aac936d/icons/obj/guns/projectile.dmi, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -27,13 +27,21 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..2fa1f7811dc Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..c358af57c32 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Rifles/ak.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/meta.json index 2f30ef18a87..c45db54aff5 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken/modified from tgstation at https://github.com/tgstation/tgstation/pull/41393/commits/1e56473177d0994d163c9edca3d13d6e5b640cc4, https://github.com/tgstation/tgstation/tree/master/icons/obj/weapons/guns backpack sprite by Peptide (copy of carbine), backpack sling sprite edited by Boaz1111", + "copyright": "Taken/modified from tgstation at https://github.com/tgstation/tgstation/pull/41393/commits/1e56473177d0994d163c9edca3d13d6e5b640cc4, https://github.com/tgstation/tgstation/tree/master/icons/obj/weapons/guns backpack sprite by Peptide (copy of carbine), backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -27,11 +27,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..42926b00f47 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..fd58fca837b Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Rifles/lecter.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/meta.json index 8b1af3c5049..2ff87fa2917 100644 --- a/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/meta.json @@ -45,11 +45,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..50b0e2a1d4f Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..eaf5e92574d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/SMGs/c20r.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/meta.json index 25feebd92c2..bd66b2c9685 100644 --- a/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/meta.json @@ -1,42 +1,50 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/raw/56cbafd6ad8c013ccd5472d6c4a0db790f7f872a/icons/obj/guns/projectile/drozd.dmi, sprite modification by Jaсkal 298/TaralGit, backpack sling sprite edited by Boaz1111", + "copyright": "Taken/modified from cev-eris at https://github.com/discordia-space/CEV-Eris/raw/56cbafd6ad8c013ccd5472d6c4a0db790f7f872a/icons/obj/guns/projectile/drozd.dmi, sprite modification by Jaсkal 298/TaralGit, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 }, - "states": [ - { - "name": "icon" - }, - { - "name": "base" - }, - { - "name": "bolt-open" - }, - { - "name": "mag-0" - }, - { - "name": "suppressor" - }, - { - "name": "inhand-left", - "directions": 4 - }, - { - "name": "inhand-right", - "directions": 4 - }, - { - "name": "equipped-BACKPACK", - "directions": 4 - }, - { - "name": "equipped-SUITSTORAGE", - "directions": 4 - } + "states": [ + { + "name": "icon" + }, + { + "name": "base" + }, + { + "name": "bolt-open" + }, + { + "name": "mag-0" + }, + { + "name": "suppressor" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, + { + "name": "equipped-BACKPACK", + "directions": 4 + }, + { + "name": "equipped-SUITSTORAGE", + "directions": 4 + } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..ee66cf3df9b Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..c5d66956051 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/SMGs/drozd.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/meta.json index f55fd2db207..b3ab88b772f 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Made by brainfood1183(Github) inspired by an image created by rezierré#5003 (Discord)", + "copyright": "Made by brainfood1183(Github) inspired by an image created by rezierré#5003 (Discord), wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -20,6 +20,14 @@ { "name": "inhand-left", "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 } ] } diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..da4a7f4f922 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..ac02c47a844 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/blunderbuss.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/meta.json index 5ef981dec9e..8699d00b7df 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1b6831dab1e1a74c0d91f2229adb87abbb089d31, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/commit/1b6831dab1e1a74c0d91f2229adb87abbb089d31, backpack sprite by Peptide, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -27,11 +27,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..9a45848ec52 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..7252681abaf Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/bulldog.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun.rsi/meta.json index 27d7ebd6653..3add3a471b6 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun.rsi/meta.json @@ -17,7 +17,7 @@ "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/db-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/db-inhand-left.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/db-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/db-inhand-right.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/meta.json new file mode 100644 index 00000000000..6c1d1581e8a --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-NC-4.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, wield sprites by RiceMar1244", + "size": { + "x": 64, + "y": 64 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..27c2e923590 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..78165792c70 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/db_shotgun_inhands_64x.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer.rsi/meta.json index f3a7f48582c..42b8d94d6d0 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer.rsi/meta.json @@ -17,7 +17,7 @@ "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/enforcer-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/enforcer-inhand-left.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/enforcer-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/enforcer-inhand-right.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/meta.json new file mode 100644 index 00000000000..6c1d1581e8a --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-NC-4.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, wield sprites by RiceMar1244", + "size": { + "x": 64, + "y": 64 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..5f5b50d715d Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..4810c9c3755 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/enforcer_inhands_64x.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/improvised-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/improvised-inhand-left.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/improvised-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/improvised-inhand-right.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/meta.json new file mode 100644 index 00000000000..6c1d1581e8a --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-NC-4.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, wield sprites by RiceMar1244", + "size": { + "x": 64, + "y": 64 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..26a569bfc22 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..e2380308b43 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/improvised_shotgun_inhands_64x.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/meta.json deleted file mode 100644 index fefe1f6eb75..00000000000 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/meta.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "version": 1, - "license": "CC-BY-NC-4.0", - "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, sawn-inhand states modified from db-inhand by Flareguy", - "size": { - "x": 64, - "y": 64 - }, - "states": [ - { - "name": "pump-inhand-left", - "directions": 4 - }, - { - "name": "pump-inhand-right", - "directions": 4 - }, - { - "name": "enforcer-inhand-left", - "directions": 4 - }, - { - "name": "enforcer-inhand-right", - "directions": 4 - }, - { - "name": "db-inhand-left", - "directions": 4 - }, - { - "name": "db-inhand-right", - "directions": 4 - }, - { - "name": "sawn-inhand-left", - "directions": 4 - }, - { - "name": "sawn-inhand-right", - "directions": 4 - }, - { - "name": "improvised-inhand-left", - "directions": 4 - }, - { - "name": "improvised-inhand-right", - "directions": 4 - } - ] -} diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump.rsi/meta.json index 27d7ebd6653..3add3a471b6 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump.rsi/meta.json @@ -17,7 +17,7 @@ "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/pump-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/pump-inhand-left.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/pump-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/pump-inhand-right.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/meta.json new file mode 100644 index 00000000000..6c1d1581e8a --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "license": "CC-BY-NC-4.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, wield sprites by RiceMar1244", + "size": { + "x": 64, + "y": 64 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..09fbaae551e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..00b475f6b45 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Shotguns/pump_inhands_64x.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/sawn-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/inhand-left.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/sawn-inhand-left.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/inhand-left.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/sawn-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/inhand-right.png similarity index 100% rename from Resources/Textures/Objects/Weapons/Guns/Shotguns/inhands_64x.rsi/sawn-inhand-right.png rename to Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/inhand-right.png diff --git a/Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/meta.json new file mode 100644 index 00000000000..852268d1874 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Guns/Shotguns/sawn_inhands_64x.rsi/meta.json @@ -0,0 +1,19 @@ +{ + "version": 1, + "license": "CC-BY-NC-4.0", + "copyright": "Taken from https://github.com/tgstation/tgstation/ at commit fb2d71495bfe81446159ef528534193d09dd8d34, sawn-inhand states modified from db-inhand by Flareguy", + "size": { + "x": 64, + "y": 64 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/meta.json index 4f7fc5d6f55..e4f1ef8dd85 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from InterBay13 at https://github.com/AndySok/InterBay13/commit/84824582fe1381d9ea6282b9da407994ab8ab509, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from InterBay13 at https://github.com/AndySok/InterBay13/commit/84824582fe1381d9ea6282b9da407994ab8ab509, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -21,11 +21,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..dc8f5727641 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..7a478a39768 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Snipers/bolt_gun_wood.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/meta.json b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/meta.json index da8881c7c58..818c56417d4 100644 --- a/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/meta.json +++ b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/13612/commits/c1cf3c42b0cd00023937e46845a7c32d6beefa0e, backpack sling sprite edited by Boaz1111", + "copyright": "Taken from tgstation at https://github.com/tgstation/tgstation/pull/13612/commits/c1cf3c42b0cd00023937e46845a7c32d6beefa0e, backpack sling sprite edited by Boaz1111, wield sprites by RiceMar1244", "size": { "x": 32, "y": 32 @@ -21,11 +21,19 @@ "name": "inhand-right", "directions": 4 }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + }, { "name": "equipped-BACKPACK", "directions": 4 }, - { + { "name": "equipped-SUITSTORAGE", "directions": 4 } diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..d373352b9f5 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..03625930c82 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Guns/Snipers/heavy_sniper.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane-empty.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane-empty.png new file mode 100644 index 00000000000..64cb9ef3aa2 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane-empty.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane.png new file mode 100644 index 00000000000..721847ff284 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/cane.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-left.png new file mode 100644 index 00000000000..caa2f232703 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-right.png new file mode 100644 index 00000000000..8f12a08afd6 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/meta.json new file mode 100644 index 00000000000..913fcb524bf --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/meta.json @@ -0,0 +1,33 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by ps3moira#9488 on discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "cane-empty" + }, + { + "name": "cane" + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "wielded-inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "wielded-inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-left.png new file mode 100644 index 00000000000..f6f87a4a90e Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-right.png new file mode 100644 index 00000000000..e1f0449b4c2 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane.rsi/wielded-inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/icon.png b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/icon.png new file mode 100644 index 00000000000..6581dc96e8c Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-left.png b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-left.png new file mode 100644 index 00000000000..f8e57880cb1 Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-right.png b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-right.png new file mode 100644 index 00000000000..5fa04f7f87c Binary files /dev/null and b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/meta.json b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/meta.json new file mode 100644 index 00000000000..a48335cc0d7 --- /dev/null +++ b/Resources/Textures/Objects/Weapons/Melee/cane_blade.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Sprited by ps3moira#9488 on discord", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "icon" + } + ] +} diff --git a/Resources/Textures/Shaders/displacement.swsl b/Resources/Textures/Shaders/displacement.swsl new file mode 100644 index 00000000000..ba5ca57852e --- /dev/null +++ b/Resources/Textures/Shaders/displacement.swsl @@ -0,0 +1,18 @@ +uniform sampler2D displacementMap; +uniform highp float displacementSize; +uniform highp vec4 displacementUV; + +varying highp vec2 displacementUVOut; + +void vertex() { + displacementUVOut = mix(displacementUV.xy, displacementUV.zw, tCoord2); +} + +void fragment() { + highp vec4 displacementSample = texture2D(displacementMap, displacementUVOut); + highp vec2 displacementValue = (displacementSample.xy - vec2(128.0 / 255.0)) / (1.0 - 128.0 / 255.0); + COLOR = zTexture(UV + displacementValue * TEXTURE_PIXEL_SIZE * displacementSize * vec2(1.0, -1.0)); + COLOR.a *= displacementSample.a; +} + + diff --git a/Resources/Textures/Structures/Machines/artifact_crusher.rsi/icon.png b/Resources/Textures/Structures/Machines/artifact_crusher.rsi/icon.png new file mode 100644 index 00000000000..af5f78e3683 Binary files /dev/null and b/Resources/Textures/Structures/Machines/artifact_crusher.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Machines/artifact_crusher.rsi/meta.json b/Resources/Textures/Structures/Machines/artifact_crusher.rsi/meta.json index dc0d23c539e..279bc73ec72 100644 --- a/Resources/Textures/Structures/Machines/artifact_crusher.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/artifact_crusher.rsi/meta.json @@ -7,6 +7,9 @@ "y": 64 }, "states": [ + { + "name": "icon" + }, { "name": "glass" }, diff --git a/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/building.png b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/building.png new file mode 100644 index 00000000000..7987532f393 Binary files /dev/null and b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/building.png differ diff --git a/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/icon.png b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/icon.png new file mode 100644 index 00000000000..e56878a7adc Binary files /dev/null and b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/meta.json b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/meta.json new file mode 100644 index 00000000000..faa9a362b4a --- /dev/null +++ b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/meta.json @@ -0,0 +1,52 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Piksqu for ss14, based on the circuit imprinter sprite taken from tgstation at https://github.com/tgstation/tgstation/commit/40d89d11ea4a5cb81d61dc1018b46f4e7d32c62a", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "panel" + }, + { + "name": "unlit" + }, + { + "name": "building", + "delays": [ + [ + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.16, + 0.18 + ] + ] + } + ] +} diff --git a/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/panel.png b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/panel.png new file mode 100644 index 00000000000..e9c369c734f Binary files /dev/null and b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/panel.png differ diff --git a/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/unlit.png b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/unlit.png new file mode 100644 index 00000000000..9a9e240fbc1 Binary files /dev/null and b/Resources/Textures/Structures/Machines/circuit_imprinter_hypercon.rsi/unlit.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png new file mode 100644 index 00000000000..5f14e3013fe Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_hamster.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png new file mode 100644 index 00000000000..d034322697e Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mothroach.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png new file mode 100644 index 00000000000..7fb87053f3f Binary files /dev/null and b/Resources/Textures/Structures/Machines/fax_machine.rsi/inserting_mouse.png differ diff --git a/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json b/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json index 1a8856301d5..00681ca6da1 100644 --- a/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json +++ b/Resources/Textures/Structures/Machines/fax_machine.rsi/meta.json @@ -40,6 +40,63 @@ ] ] }, + { + "name": "inserting_hamster", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "inserting_mothroach", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, + { + "name": "inserting_mouse", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] + }, { "name": "printing", "delays": [ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-left.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-left.png new file mode 100644 index 00000000000..f4f60cdd179 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-left.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-right.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-right.png new file mode 100644 index 00000000000..dfd245221f8 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Bend-inhand-right.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-left.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-left.png new file mode 100644 index 00000000000..4da2f458e8e Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-left.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-right.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-right.png new file mode 100644 index 00000000000..a59a7971659 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/Fourway-inhand-right.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-left.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-left.png new file mode 100644 index 00000000000..8b14c9117a5 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-left.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-right.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-right.png new file mode 100644 index 00000000000..828920b4002 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/TJunction-inhand-right.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-left.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-left.png new file mode 100644 index 00000000000..7ca777a2e94 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-left.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-right.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-right.png new file mode 100644 index 00000000000..6c8c55a515c Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/inhand-right.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/meta.json b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/meta.json index ae4ff9b12d0..aecb62aee52 100644 --- a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/meta.json +++ b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/meta.json @@ -5,8 +5,40 @@ "y":32 }, "license":"CC-BY-SA-3.0", - "copyright":"pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da", + "copyright":"Inhand sprites by alzore_(discord) for SS14. pipeTrinaryConnectors made by Menshin for SS14 based on pipeTJunction, the rest is taken from https://github.com/tgstation/tgstation at commit 57cd1d59ca019dd0e7811ac451f295f818e573da.", "states":[ + { + "name": "inhand-left", + "directions":4 + }, + { + "name":"inhand-right", + "directions":4 + }, + { + "name": "Bend-inhand-left", + "directions":4 + }, + { + "name":"Bend-inhand-right", + "directions":4 + }, + { + "name": "TJunction-inhand-left", + "directions":4 + }, + { + "name":"TJunction-inhand-right", + "directions":4 + }, + { + "name": "Fourway-inhand-left", + "directions":4 + }, + { + "name":"Fourway-inhand-right", + "directions":4 + }, { "name":"pipeBroken", "directions":1 @@ -38,6 +70,18 @@ { "name":"pipeTrinaryConnectors", "directions":4 + }, + { + "name":"storageStraight", + "directions":4 + }, + { + "name":"storageBend", + "directions":4 + }, + { + "name":"storageTJunction", + "directions":4 } ] } diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBend.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBend.png index b6408718eba..cda379a65b9 100644 Binary files a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBend.png and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/pipeBend.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png new file mode 100644 index 00000000000..39ffe213efb Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageBend.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png new file mode 100644 index 00000000000..715aeb58249 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageStraight.png differ diff --git a/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png new file mode 100644 index 00000000000..af8376a1527 Binary files /dev/null and b/Resources/Textures/Structures/Piping/Atmospherics/pipe.rsi/storageTJunction.png differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_12.png b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_12.png index cce6fe0ba3c..a82bb8b2338 100644 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_12.png and b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_12.png differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_4.png b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_4.png index 08b6f664490..054f1f520c9 100644 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_4.png and b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_4.png differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_8.png b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_8.png index 6d980d1c67c..e1c22974684 100644 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_8.png and b/Resources/Textures/Structures/Storage/glassbox.rsi/DamageOverlay_8.png differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-empty-open.png b/Resources/Textures/Structures/Storage/glassbox.rsi/base.png similarity index 100% rename from Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-empty-open.png rename to Resources/Textures/Structures/Storage/glassbox.rsi/base.png diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/glass-4.png b/Resources/Textures/Structures/Storage/glassbox.rsi/glass-broken.png similarity index 100% rename from Resources/Textures/Structures/Storage/glassbox.rsi/glass-4.png rename to Resources/Textures/Structures/Storage/glassbox.rsi/glass-broken.png diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-closed.png b/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-closed.png deleted file mode 100644 index b558cf5212c..00000000000 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-closed.png and /dev/null differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-open.png b/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-open.png deleted file mode 100644 index 48db8e88e59..00000000000 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox-filled-open.png and /dev/null differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox.png b/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox.png deleted file mode 100644 index 3a3bf591ca5..00000000000 Binary files a/Resources/Textures/Structures/Storage/glassbox.rsi/glassbox.png and /dev/null differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/icon.png b/Resources/Textures/Structures/Storage/glassbox.rsi/icon.png new file mode 100644 index 00000000000..9d1c8c8685e Binary files /dev/null and b/Resources/Textures/Structures/Storage/glassbox.rsi/icon.png differ diff --git a/Resources/Textures/Structures/Storage/glassbox.rsi/meta.json b/Resources/Textures/Structures/Storage/glassbox.rsi/meta.json index 5ce653f37b1..33decc40092 100644 --- a/Resources/Textures/Structures/Storage/glassbox.rsi/meta.json +++ b/Resources/Textures/Structures/Storage/glassbox.rsi/meta.json @@ -1,50 +1,44 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from tgstation https://github.com/tgstation/tgstation/commit/0129a094635aac51e00fdc7aa3b4248affc1f49d Sprite modified and updated by Nimfar11 (Github), Shatter resprite by KREKS", + "copyright": "Taken from tgstation https://github.com/tgstation/tgstation/commit/0129a094635aac51e00fdc7aa3b4248affc1f49d Sprite modified and updated by Nimfar11 (Github), Shatter resprite by KREKS and modified by MilenVolf (GitHub)", "size": { "x": 32, "y": 32 }, "states": [ { - "name": "glass" - }, - { - "name": "DamageOverlay_4" + "name": "base" }, { - "name": "DamageOverlay_8" + "name": "glass" }, { - "name": "DamageOverlay_12" + "name": "glass-up" }, { - "name": "glass-4" + "name": "glass-broken" }, { - "name": "glass-up" + "name": "caplaser" }, { "name": "locked" }, - { - "name": "caplaser" - }, { "name": "unlocked" }, { - "name": "glassbox" + "name": "icon" }, { - "name": "glassbox-empty-open" + "name": "DamageOverlay_4" }, { - "name": "glassbox-filled-closed" + "name": "DamageOverlay_8" }, { - "name": "glassbox-filled-open" + "name": "DamageOverlay_12" } ] } \ No newline at end of file diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_0.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_0.png new file mode 100644 index 00000000000..1505c892b8e Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_0.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_1.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_1.png new file mode 100644 index 00000000000..e0d5a4d39ea Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_1.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_2.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_2.png new file mode 100644 index 00000000000..1505c892b8e Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_2.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_3.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_3.png new file mode 100644 index 00000000000..e0d5a4d39ea Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_3.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_4.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_4.png new file mode 100644 index 00000000000..38cb4115083 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_4.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_5.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_5.png new file mode 100644 index 00000000000..b863e36b8ce Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_5.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_6.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_6.png new file mode 100644 index 00000000000..38cb4115083 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_6.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_7.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_7.png new file mode 100644 index 00000000000..88ffa378d2a Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_buy_7.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_0.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_0.png new file mode 100644 index 00000000000..136a48087b5 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_0.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_1.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_1.png new file mode 100644 index 00000000000..06fb688c5bd Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_1.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_2.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_2.png new file mode 100644 index 00000000000..136a48087b5 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_2.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_3.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_3.png new file mode 100644 index 00000000000..06fb688c5bd Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_3.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_4.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_4.png new file mode 100644 index 00000000000..80a85ef2383 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_4.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_5.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_5.png new file mode 100644 index 00000000000..4a194d7fb1f Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_5.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_6.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_6.png new file mode 100644 index 00000000000..80a85ef2383 Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_6.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_7.png b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_7.png new file mode 100644 index 00000000000..88ffa378d2a Binary files /dev/null and b/Resources/Textures/Structures/cargo_pallets.rsi/cargo_pallet_sell_7.png differ diff --git a/Resources/Textures/Structures/cargo_pallets.rsi/meta.json b/Resources/Textures/Structures/cargo_pallets.rsi/meta.json index 4751d95b9b5..c32fcfefd05 100644 --- a/Resources/Textures/Structures/cargo_pallets.rsi/meta.json +++ b/Resources/Textures/Structures/cargo_pallets.rsi/meta.json @@ -10,8 +10,72 @@ { "name": "cargo_pallet_buy" }, + { + "name": "cargo_pallet_buy_0", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_1", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_2", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_3", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_4", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_5", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_6", + "directions": 4 + }, + { + "name": "cargo_pallet_buy_7", + "directions": 4 + }, { "name": "cargo_pallet_sell" + }, + { + "name": "cargo_pallet_sell_0", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_1", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_2", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_3", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_4", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_5", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_6", + "directions": 4 + }, + { + "name": "cargo_pallet_sell_7", + "directions": 4 } ] } diff --git a/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrap.png b/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrap.png new file mode 100644 index 00000000000..391437064e5 Binary files /dev/null and b/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrap.png differ diff --git a/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrapspawn.png b/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrapspawn.png new file mode 100644 index 00000000000..764a0fed152 Binary files /dev/null and b/Resources/Textures/Tiles/Misc/floortrap.rsi/floortrapspawn.png differ diff --git a/Resources/Textures/Tiles/Misc/floortrap.rsi/meta.json b/Resources/Textures/Tiles/Misc/floortrap.rsi/meta.json new file mode 100644 index 00000000000..586fad6d231 --- /dev/null +++ b/Resources/Textures/Tiles/Misc/floortrap.rsi/meta.json @@ -0,0 +1,17 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by Nimfar11 (github) for ss14", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "floortrap" + }, + { + "name": "floortrapspawn" + } + ] +} diff --git a/Resources/Textures/Tips/tippy.rsi/down.png b/Resources/Textures/Tips/tippy.rsi/down.png new file mode 100644 index 00000000000..bdfcf315b6c Binary files /dev/null and b/Resources/Textures/Tips/tippy.rsi/down.png differ diff --git a/Resources/Textures/Tips/tippy.rsi/left.png b/Resources/Textures/Tips/tippy.rsi/left.png new file mode 100644 index 00000000000..f2293c6111d Binary files /dev/null and b/Resources/Textures/Tips/tippy.rsi/left.png differ diff --git a/Resources/Textures/Tips/tippy.rsi/meta.json b/Resources/Textures/Tips/tippy.rsi/meta.json new file mode 100644 index 00000000000..68942d731c9 --- /dev/null +++ b/Resources/Textures/Tips/tippy.rsi/meta.json @@ -0,0 +1,20 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "down" + }, + { + "name": "left" + }, + { + "name": "right" + } + ] +} diff --git a/Resources/Textures/Tips/tippy.rsi/right.png b/Resources/Textures/Tips/tippy.rsi/right.png new file mode 100644 index 00000000000..900262932da Binary files /dev/null and b/Resources/Textures/Tips/tippy.rsi/right.png differ diff --git a/Resources/engineCommandPerms.yml b/Resources/engineCommandPerms.yml index 51743c6e822..42cc4668a93 100644 --- a/Resources/engineCommandPerms.yml +++ b/Resources/engineCommandPerms.yml @@ -96,6 +96,8 @@ - tp - tpto - respawn + - tippy + - tip - Flags: SERVER Commands: diff --git a/Resources/keybinds.yml b/Resources/keybinds.yml index 33b4166161a..39e4971fdb4 100644 --- a/Resources/keybinds.yml +++ b/Resources/keybinds.yml @@ -187,6 +187,9 @@ binds: - function: OpenCharacterMenu type: State key: C +- function: OpenEmotesMenu + type: State + key: Y - function: OpenLanguageMenu type: State key: L @@ -461,6 +464,9 @@ binds: - function: OpenDecalSpawnWindow type: State key: F8 +- function: OpenScoreboardWindow + type: State + key: F9 - function: OpenSandboxWindow type: State key: B diff --git a/RobustToolbox b/RobustToolbox index eb638099999..970da5f717c 160000 --- a/RobustToolbox +++ b/RobustToolbox @@ -1 +1 @@ -Subproject commit eb638099999dce3a43d90772ca976ae010d649c0 +Subproject commit 970da5f717c921bfa110aa5dc31e74edb96dcf99 diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 620de422532..15424a68ec7 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -34,6 +34,7 @@ WARNING WARNING WARNING + SUGGESTION Required Required Required @@ -55,6 +56,7 @@ AL BB CC + FTL GC GD GL diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua b/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua new file mode 100644 index 00000000000..3291685071d --- /dev/null +++ b/Tools/SS14 Aseprite Plugins/Displacement Map Flip.lua @@ -0,0 +1,78 @@ +local sprite = app.editor.sprite +local cel = app.cel + +if sprite.selection.isEmpty then + print("You need to select something sorry") + return +end + +local diag = Dialog{ + title = "Flip Displacement Map" +} + +diag:check{ + id = "horizontal", + label = "flip horizontal?" +} + +diag:check{ + id = "vertical", + label = "flip vertical?" +} + +diag:button{ + text = "ok", + focus = true, + onclick = function(ev) + local horizontal = diag.data["horizontal"] + local vertical = diag.data["vertical"] + + local selection = sprite.selection + local image = cel.image:clone() + + for x = 0, selection.bounds.width do + for y = 0, selection.bounds.height do + local xSel = x + selection.origin.x + local ySel = y + selection.origin.y + + local xImg = xSel - cel.position.x + local yImg = ySel - cel.position.y + + if xImg < 0 or xImg >= image.width or yImg < 0 or yImg >= image.height then + goto continue + end + + local imgValue = image:getPixel(xImg, yImg) + local color = Color(imgValue) + + if horizontal then + color.red = 128 + -(color.red - 128) + end + + if vertical then + color.green = 128 + -(color.green - 128) + end + + image:drawPixel( + xImg, + yImg, + app.pixelColor.rgba(color.red, color.green, color.blue, color.alpha)) + + ::continue:: + end + end + + cel.image = image + + diag:close() + end +} + +diag:button{ + text = "cancel", + onclick = function(ev) + diag:close() + end +} + +diag:show() diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua b/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua new file mode 100644 index 00000000000..468636c07d8 --- /dev/null +++ b/Tools/SS14 Aseprite Plugins/Displacement Map Visualizer.lua @@ -0,0 +1,171 @@ +-- Displacement Map Visualizer +-- +-- This script will create a little preview window that will test a displacement map. +-- +-- TODO: Handling of sizes != 127 doesn't work properly and rounds differently from the real shader. Ah well. + +local scale = 4 + +-- This script requires UI +if not app.isUIAvailable then + return +end + +local getOffsetPixel = function(x, y, image, rect) + local posX = x - rect.x + local posY = y - rect.y + + if posX < 0 or posX >= image.width or posY < 0 or posY >= image.height then + return image.spec.transparentColor + end + + return image:getPixel(posX, posY) +end + +local pixelValueToColor = function(sprite, value) + return Color(value) +end + +local applyDisplacementMap = function(width, height, size, displacement, displacementRect, target, targetRect) + -- print(Color(displacement:getPixel(17, 15)).red) + local image = target:clone() + image:resize(width, height) + image:clear() + + for x = 0, width - 1 do + for y = 0, height - 1 do + local value = getOffsetPixel(x, y, displacement, displacementRect) + local color = pixelValueToColor(sprite, value) + + if color.alpha ~= 0 then + local offset_x = (color.red - 128) / 127 * size + local offset_y = (color.green - 128) / 127 * size + + local colorValue = getOffsetPixel(x + offset_x, y + offset_y, target, targetRect) + image:drawPixel(x, y, colorValue) + end + end + end + + return image +end + +local dialog = nil + +local sprite = app.editor.sprite +local spriteChanged = sprite.events:on("change", + function(ev) + dialog:repaint() + end) + +local layers = {} +for i,layer in ipairs(sprite.layers) do + table.insert(layers, 1, layer.name) +end + +local findLayer = function(sprite, name) + for i, layer in ipairs(sprite.layers) do + if layer.name == name then + return layer + end + end + + return nil +end + +dialog = Dialog{ + title = "Displacement map preview", + onclose = function(ev) + sprite.events:off(spriteChanged) + end} + +dialog:canvas{ + id = "canvas", + width = sprite.width * scale, + height = sprite.height * scale, + onpaint = function(ev) + local context = ev.context + + local layerDisplacement = findLayer(sprite, dialog.data["displacement-select"]) + local layerTarget = findLayer(sprite, dialog.data["reference-select"]) + local layerBackground = findLayer(sprite, dialog.data["background-select"]) + -- print(layerDisplacement.name) + -- print(layerTarget.name) + + local celDisplacement = layerDisplacement:cel(1) + local celTarget = layerTarget:cel(1) + local celBackground = layerBackground:cel(1) + + -- Draw background + context:drawImage( + -- srcImage + celBackground.image, + -- srcPos + 0, 0, + -- srcSize + celBackground.image.width, celBackground.image.height, + -- dstPos + celBackground.position.x * scale, celBackground.position.y * scale, + -- dstSize + celBackground.image.width * scale, celBackground.image.height * scale) + + -- Apply displacement map and draw + local image = applyDisplacementMap( + sprite.width, sprite.height, + dialog.data["size"], + celDisplacement.image, celDisplacement.bounds, + celTarget.image, celTarget.bounds) + + context:drawImage( + -- srcImage + image, + -- srcPos + 0, 0, + -- srcSize + image.width, image.height, + -- dstPos + 0, 0, + -- dstSize + image.width * scale, image.height * scale) + end +} + +dialog:combobox{ + id = "displacement-select", + label = "displacement layer", + options = layers, + onchange = function(ev) + dialog:repaint() + end +} + +dialog:combobox{ + id = "reference-select", + label = "reference layer", + options = layers, + onchange = function(ev) + dialog:repaint() + end +} + +dialog:combobox{ + id = "background-select", + label = "background layer", + options = layers, + onchange = function(ev) + dialog:repaint() + end +} + +dialog:slider{ + id = "size", + label = "displacement size", + min = 1, + max = 127, + value = 127, + onchange = function(ev) + dialog:repaint() + end +} + +dialog:show{wait = false} diff --git a/Tools/SS14 Aseprite Plugins/Displacement Map.png b/Tools/SS14 Aseprite Plugins/Displacement Map.png new file mode 100644 index 00000000000..50744cef601 Binary files /dev/null and b/Tools/SS14 Aseprite Plugins/Displacement Map.png differ