Merge remote-tracking branch 'wizards/master' into upstream-sync

# Conflicts:
#	Content.Packaging/ClientPackaging.cs
#	Content.Server/Administration/Systems/AdminSystem.cs
#	Content.Server/GameTicking/GameTicker.StatusShell.cs
#	Content.Shared/Preferences/HumanoidCharacterProfile.cs
#	Resources/Prototypes/Entities/Stations/base.yml
#	Resources/Prototypes/Entities/Structures/Machines/lathe.yml
#	Resources/Textures/Interface/Misc/job_icons.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_1.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_2.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_3.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_4.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_5.rsi/meta.json
#	Resources/Textures/Structures/Power/Generation/Singularity/singularity_6.rsi/meta.json
This commit is contained in:
Morb0
2025-01-16 13:37:26 +03:00
162 changed files with 203839 additions and 13727 deletions

View File

@@ -88,8 +88,9 @@ namespace Content.Client.Access.UI
button.Disabled = !interfaceEnabled;
if (interfaceEnabled)
{
button.Pressed = state.TargetAccessReaderIdAccessList?.Contains(accessName) ?? false;
button.Disabled = (!state.AllowedModifyAccessList?.Contains(accessName)) ?? true;
// Explicit cast because Rider gives a false error otherwise.
button.Pressed = state.TargetAccessReaderIdAccessList?.Contains((ProtoId<AccessLevelPrototype>) accessName) ?? false;
button.Disabled = (!state.AllowedModifyAccessList?.Contains((ProtoId<AccessLevelPrototype>) accessName)) ?? true;
}
}
}

View File

@@ -6,8 +6,7 @@
xmlns:tabs="clr-namespace:Content.Client.Administration.UI.Tabs"
xmlns:playerTab="clr-namespace:Content.Client.Administration.UI.Tabs.PlayerTab"
xmlns:objectsTab="clr-namespace:Content.Client.Administration.UI.Tabs.ObjectsTab"
xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab"
xmlns:baby="clr-namespace:Content.Client.Administration.UI.Tabs.BabyJailTab">
xmlns:panic="clr-namespace:Content.Client.Administration.UI.Tabs.PanicBunkerTab">
<TabContainer Name="MasterTabContainer">
<adminTab:AdminTab />
<adminbusTab:AdminbusTab />
@@ -15,7 +14,6 @@
<tabs:RoundTab />
<tabs:ServerTab />
<panic:PanicBunkerTab Name="PanicBunkerControl" Access="Public" />
<baby:BabyJailTab Name="BabyJailControl" Access="Public" />
<playerTab:PlayerTab Name="PlayerTabControl" Access="Public" />
<objectsTab:ObjectsTab Name="ObjectsTabControl" Access="Public" />
</TabContainer>

View File

@@ -21,10 +21,6 @@ public sealed partial class AdminMenuWindow : DefaultWindow
MasterTabContainer.SetTabTitle((int) TabIndex.Round, Loc.GetString("admin-menu-round-tab"));
MasterTabContainer.SetTabTitle((int) TabIndex.Server, Loc.GetString("admin-menu-server-tab"));
MasterTabContainer.SetTabTitle((int) TabIndex.PanicBunker, Loc.GetString("admin-menu-panic-bunker-tab"));
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
MasterTabContainer.SetTabTitle((int) TabIndex.BabyJail, Loc.GetString("admin-menu-baby-jail-tab"));
MasterTabContainer.SetTabTitle((int) TabIndex.Players, Loc.GetString("admin-menu-players-tab"));
MasterTabContainer.SetTabTitle((int) TabIndex.Objects, Loc.GetString("admin-menu-objects-tab"));
MasterTabContainer.OnTabChanged += OnTabChanged;
@@ -52,7 +48,6 @@ public sealed partial class AdminMenuWindow : DefaultWindow
Round,
Server,
PanicBunker,
BabyJail,
Players,
Objects,
}

View File

@@ -130,6 +130,7 @@ namespace Content.Client.Administration.UI
}
var title = string.IsNullOrWhiteSpace(popup.TitleEdit.Text) ? null : popup.TitleEdit.Text;
var suspended = popup.SuspendedCheckbox.Pressed;
if (popup.SourceData is { } src)
{
@@ -139,7 +140,8 @@ namespace Content.Client.Administration.UI
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
RankId = rank,
Suspended = suspended,
});
}
else
@@ -152,7 +154,8 @@ namespace Content.Client.Administration.UI
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
RankId = rank,
Suspended = suspended,
});
}
@@ -171,7 +174,7 @@ namespace Content.Client.Administration.UI
{
Id = src,
Flags = flags,
Name = name
Name = name,
});
}
else
@@ -351,6 +354,7 @@ namespace Content.Client.Administration.UI
public readonly OptionButton RankButton;
public readonly Button SaveButton;
public readonly Button? RemoveButton;
public readonly CheckBox SuspendedCheckbox;
public readonly Dictionary<AdminFlags, (Button inherit, Button sub, Button plus)> FlagButtons
= new();
@@ -381,6 +385,12 @@ namespace Content.Client.Administration.UI
RankButton = new OptionButton();
SaveButton = new Button { Text = Loc.GetString("permissions-eui-edit-admin-window-save-button"), HorizontalAlignment = HAlignment.Right };
SuspendedCheckbox = new CheckBox
{
Text = Loc.GetString("permissions-eui-edit-admin-window-suspended"),
Pressed = data?.Suspended ?? false,
};
RankButton.AddItem(Loc.GetString("permissions-eui-edit-admin-window-no-rank-button"), NoRank);
foreach (var (rId, rank) in ui._ranks)
{
@@ -488,7 +498,8 @@ namespace Content.Client.Administration.UI
{
nameControl,
TitleEdit,
RankButton
RankButton,
SuspendedCheckbox,
}
},
permGrid

View File

@@ -1,6 +0,0 @@
<controls:BabyJailStatusWindow
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.Administration.UI.Tabs.BabyJailTab"
Title="{Loc admin-ui-baby-jail-window-title}">
<RichTextLabel Name="MessageLabel" Access="Public" />
</controls:BabyJailStatusWindow>

View File

@@ -1,21 +0,0 @@
using Content.Client.Message;
using Content.Client.UserInterface.Controls;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Administration.UI.Tabs.BabyJailTab;
/*
* TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
[GenerateTypedNameReferences]
public sealed partial class BabyJailStatusWindow : FancyWindow
{
public BabyJailStatusWindow()
{
RobustXamlLoader.Load(this);
MessageLabel.SetMarkup(Loc.GetString("admin-ui-baby-jail-is-enabled"));
}
}

View File

@@ -1,26 +0,0 @@
<controls:BabyJailTab
xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.Administration.UI.Tabs.BabyJailTab"
xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls"
Margin="4">
<BoxContainer Orientation="Vertical">
<cc:CommandButton Name="EnabledButton" Command="babyjail" ToggleMode="True"
Text="{Loc admin-ui-baby-jail-disabled}"
ToolTip="{Loc admin-ui-baby-jail-tooltip}" />
<cc:CommandButton Name="ShowReasonButton" Command="babyjail_show_reason"
ToggleMode="True" Text="{Loc admin-ui-baby-jail-show-reason}"
ToolTip="{Loc admin-ui-baby-jail-show-reason-tooltip}" />
<BoxContainer Orientation="Vertical" Margin="0 10 0 0">
<BoxContainer Orientation="Horizontal" Margin="2">
<Label Text="{Loc admin-ui-baby-jail-max-account-age}" MinWidth="175" />
<LineEdit Name="MaxAccountAge" MinWidth="50" Margin="0 0 5 0" />
<Label Text="{Loc generic-minutes}" />
</BoxContainer>
<BoxContainer Orientation="Horizontal" Margin="2">
<Label Text="{Loc admin-ui-baby-jail-max-overall-minutes}" MinWidth="175" />
<LineEdit Name="MaxOverallMinutes" MinWidth="50" Margin="0 0 5 0" />
<Label Text="{Loc generic-minutes}" />
</BoxContainer>
</BoxContainer>
</BoxContainer>
</controls:BabyJailTab>

View File

@@ -1,75 +0,0 @@
using Content.Shared.Administration.Events;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Console;
/*
* TODO: Remove me once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
namespace Content.Client.Administration.UI.Tabs.BabyJailTab;
[GenerateTypedNameReferences]
public sealed partial class BabyJailTab : Control
{
[Dependency] private readonly IConsoleHost _console = default!;
private string _maxAccountAge;
private string _maxOverallMinutes;
public BabyJailTab()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
MaxAccountAge.OnTextEntered += args => SendMaxAccountAge(args.Text);
MaxAccountAge.OnFocusExit += args => SendMaxAccountAge(args.Text);
_maxAccountAge = MaxAccountAge.Text;
MaxOverallMinutes.OnTextEntered += args => SendMaxOverallMinutes(args.Text);
MaxOverallMinutes.OnFocusExit += args => SendMaxOverallMinutes(args.Text);
_maxOverallMinutes = MaxOverallMinutes.Text;
}
private void SendMaxAccountAge(string text)
{
if (string.IsNullOrWhiteSpace(text) ||
text == _maxAccountAge ||
!int.TryParse(text, out var minutes))
{
return;
}
_console.ExecuteCommand($"babyjail_max_account_age {minutes}");
}
private void SendMaxOverallMinutes(string text)
{
if (string.IsNullOrWhiteSpace(text) ||
text == _maxOverallMinutes ||
!int.TryParse(text, out var minutes))
{
return;
}
_console.ExecuteCommand($"babyjail_max_overall_minutes {minutes}");
}
public void UpdateStatus(BabyJailStatus status)
{
EnabledButton.Pressed = status.Enabled;
EnabledButton.Text = Loc.GetString(status.Enabled
? "admin-ui-baby-jail-enabled"
: "admin-ui-baby-jail-disabled"
);
EnabledButton.ModulateSelfOverride = status.Enabled ? Color.Red : null;
ShowReasonButton.Pressed = status.ShowReason;
MaxAccountAge.Text = status.MaxAccountAgeMinutes.ToString();
_maxAccountAge = MaxAccountAge.Text;
MaxOverallMinutes.Text = status.MaxOverallMinutes.ToString();
_maxOverallMinutes = MaxOverallMinutes.Text;
}
}

View File

@@ -4,6 +4,7 @@ namespace Content.Client
{
internal static class Program
{
[STAThread]
public static void Main(string[] args)
{
ContentStart.Start(args);

View File

@@ -3,7 +3,6 @@ using Content.Client.Administration.Systems;
using Content.Client.Administration.UI;
using Content.Client.Administration.UI.Tabs.ObjectsTab;
using Content.Client.Administration.UI.Tabs.PanicBunkerTab;
using Content.Client.Administration.UI.Tabs.BabyJailTab;
using Content.Client.Administration.UI.Tabs.PlayerTab;
using Content.Client.Gameplay;
using Content.Client.Lobby;
@@ -38,13 +37,11 @@ public sealed class AdminUIController : UIController,
private AdminMenuWindow? _window;
private MenuButton? AdminButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.AdminButton;
private PanicBunkerStatus? _panicBunker;
private BabyJailStatus? _babyJail;
public override void Initialize()
{
base.Initialize();
SubscribeNetworkEvent<PanicBunkerChangedEvent>(OnPanicBunkerUpdated);
SubscribeNetworkEvent<BabyJailChangedEvent>(OnBabyJailUpdated);
}
private void OnPanicBunkerUpdated(PanicBunkerChangedEvent msg, EntitySessionEventArgs args)
@@ -59,18 +56,6 @@ public sealed class AdminUIController : UIController,
}
}
private void OnBabyJailUpdated(BabyJailChangedEvent msg, EntitySessionEventArgs args)
{
var showDialog = _babyJail == null && msg.Status.Enabled;
_babyJail = msg.Status;
_window?.BabyJailControl.UpdateStatus(msg.Status);
if (showDialog)
{
UIManager.CreateWindow<BabyJailStatusWindow>().OpenCentered();
}
}
public void OnStateEntered(GameplayState state)
{
EnsureWindow();
@@ -116,13 +101,6 @@ public sealed class AdminUIController : UIController,
if (_panicBunker != null)
_window.PanicBunkerControl.UpdateStatus(_panicBunker);
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
if (_babyJail != null)
_window.BabyJailControl.UpdateStatus(_babyJail);
_window.PlayerTabControl.OnEntryKeyBindDown += PlayerTabEntryKeyBindDown;
_window.ObjectsTabControl.OnEntryKeyBindDown += ObjectsTabEntryKeyBindDown;
_window.OnOpen += OnWindowOpen;

View File

@@ -84,9 +84,8 @@ namespace Content.IntegrationTests.Tests
"Gate",
"Amber",
"Loop",
"Plasma",
"Elkridge"
};
/// <summary>

View File

@@ -80,7 +80,13 @@ public static class ClientPackaging
var graph = new RobustClientAssetGraph();
pass.Dependencies.Add(new AssetPassDependency(graph.Output.Name));
AssetGraph.CalculateGraph(graph.AllPasses.Append(pass).ToArray(), logger);
var dropSvgPass = new AssetPassFilterDrop(f => f.Path.EndsWith(".svg"))
{
Name = "DropSvgPass",
};
dropSvgPass.AddDependency(graph.Input).AddBefore(graph.PresetPasses);
AssetGraph.CalculateGraph([pass, dropSvgPass, ..graph.AllPasses], logger);
var inputPass = graph.Input;
@@ -97,7 +103,7 @@ public static class ClientPackaging
assemblies, // Corvax-Secrets
cancel: cancel);
await WriteClientResources(contentDir, pass, cancel); // Corvax-Secrets: Support content resource ignore to ignore server-only prototypes
await WriteClientResources(contentDir, inputPass, cancel); // Corvax-Secrets: Support content resource ignore to ignore server-only prototypes
inputPass.InjectFinished();
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Postgres
{
/// <inheritdoc />
public partial class AdminStatus : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "deadminned",
table: "admin",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "suspended",
table: "admin",
type: "boolean",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "deadminned",
table: "admin");
migrationBuilder.DropColumn(
name: "suspended",
table: "admin");
}
}
}

View File

@@ -36,6 +36,14 @@ namespace Content.Server.Database.Migrations.Postgres
.HasColumnType("integer")
.HasColumnName("admin_rank_id");
b.Property<bool>("Deadminned")
.HasColumnType("boolean")
.HasColumnName("deadminned");
b.Property<bool>("Suspended")
.HasColumnType("boolean")
.HasColumnName("suspended");
b.Property<string>("Title")
.HasColumnType("text")
.HasColumnName("title");

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,40 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Content.Server.Database.Migrations.Sqlite
{
/// <inheritdoc />
public partial class AdminStatus : Migration
{
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "deadminned",
table: "admin",
type: "INTEGER",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "suspended",
table: "admin",
type: "INTEGER",
nullable: false,
defaultValue: false);
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "deadminned",
table: "admin");
migrationBuilder.DropColumn(
name: "suspended",
table: "admin");
}
}
}

View File

@@ -28,6 +28,14 @@ namespace Content.Server.Database.Migrations.Sqlite
.HasColumnType("INTEGER")
.HasColumnName("admin_rank_id");
b.Property<bool>("Deadminned")
.HasColumnType("INTEGER")
.HasColumnName("deadminned");
b.Property<bool>("Suspended")
.HasColumnType("INTEGER")
.HasColumnName("suspended");
b.Property<string>("Title")
.HasColumnType("TEXT")
.HasColumnName("title");

View File

@@ -611,6 +611,16 @@ namespace Content.Server.Database
[Key] public Guid UserId { get; set; }
public string? Title { get; set; }
/// <summary>
/// If true, the admin is voluntarily deadminned. They can re-admin at any time.
/// </summary>
public bool Deadminned { get; set; }
/// <summary>
/// If true, the admin is suspended by an admin with <c>PERMISSIONS</c>. They will not have in-game permissions.
/// </summary>
public bool Suspended { get; set; }
public int? AdminRankId { get; set; }
public AdminRank? AdminRank { get; set; }
public List<AdminFlag> Flags { get; set; } = default!;
@@ -964,10 +974,10 @@ namespace Content.Server.Database
Full = 2,
Panic = 3,
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*
* If baby jail is removed, please reserve this value for as long as can reasonably be done to prevent causing ambiguity in connection denial reasons.
* Reservation by commenting out the value is likely sufficient for this purpose, but may impact projects which depend on SS14 like SS14.Admin.
*
* Edit: It has
*/
BabyJail = 4,
/// Results from rejected connections with external API checking tools

View File

@@ -1,139 +0,0 @@
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Robust.Shared.Configuration;
using Robust.Shared.Console;
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
namespace Content.Server.Administration.Commands;
[AdminCommand(AdminFlags.Server)]
public sealed class BabyJailCommand : LocalizedCommands
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override string Command => "babyjail";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var toggle = Toggle(CCVars.BabyJailEnabled, shell, args, _cfg);
if (toggle == null)
return;
shell.WriteLine(Loc.GetString(toggle.Value ? "babyjail-command-enabled" : "babyjail-command-disabled"));
}
public static bool? Toggle(CVarDef<bool> cvar, IConsoleShell shell, string[] args, IConfigurationManager config)
{
if (args.Length > 1)
{
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
return null;
}
var enabled = config.GetCVar(cvar);
switch (args.Length)
{
case 0:
enabled = !enabled;
break;
case 1 when !bool.TryParse(args[0], out enabled):
shell.WriteError(Loc.GetString("shell-argument-must-be-boolean"));
return null;
}
config.SetCVar(cvar, enabled);
return enabled;
}
}
[AdminCommand(AdminFlags.Server)]
public sealed class BabyJailShowReasonCommand : LocalizedCommands
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override string Command => "babyjail_show_reason";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var toggle = BabyJailCommand.Toggle(CCVars.BabyJailShowReason, shell, args, _cfg);
if (toggle == null)
return;
shell.WriteLine(Loc.GetString(toggle.Value
? "babyjail-command-show-reason-enabled"
: "babyjail-command-show-reason-disabled"
));
}
}
[AdminCommand(AdminFlags.Server)]
public sealed class BabyJailMinAccountAgeCommand : LocalizedCommands
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override string Command => "babyjail_max_account_age";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
switch (args.Length)
{
case 0:
{
var current = _cfg.GetCVar(CCVars.BabyJailMaxAccountAge);
shell.WriteLine(Loc.GetString("babyjail-command-max-account-age-is", ("minutes", current)));
break;
}
case > 1:
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
return;
}
if (!int.TryParse(args[0], out var minutes))
{
shell.WriteError(Loc.GetString("shell-argument-must-be-number"));
return;
}
_cfg.SetCVar(CCVars.BabyJailMaxAccountAge, minutes);
shell.WriteLine(Loc.GetString("babyjail-command-max-account-age-set", ("minutes", minutes)));
}
}
[AdminCommand(AdminFlags.Server)]
public sealed class BabyJailMinOverallHoursCommand : LocalizedCommands
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override string Command => "babyjail_max_overall_minutes";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
switch (args.Length)
{
case 0:
{
var current = _cfg.GetCVar(CCVars.BabyJailMaxOverallMinutes);
shell.WriteLine(Loc.GetString("babyjail-command-max-overall-minutes-is", ("minutes", current)));
break;
}
case > 1:
shell.WriteError(Loc.GetString("shell-need-between-arguments",("lower", 0), ("upper", 1)));
return;
}
if (!int.TryParse(args[0], out var hours))
{
shell.WriteError(Loc.GetString("shell-argument-must-be-number"));
return;
}
_cfg.SetCVar(CCVars.BabyJailMaxOverallMinutes, hours);
shell.WriteLine(Loc.GetString("babyjail-command-overall-minutes-set", ("hours", hours)));
}
}

View File

@@ -91,14 +91,29 @@ namespace Content.Server.Administration.Managers
_chat.SendAdminAnnouncement(Loc.GetString("admin-manager-self-de-admin-message", ("exAdminName", session.Name)));
_chat.DispatchServerMessage(session, Loc.GetString("admin-manager-became-normal-player-message"));
var plyData = session.ContentData()!;
plyData.ExplicitlyDeadminned = true;
UpdateDatabaseDeadminnedState(session, true);
reg.Data.Active = false;
SendPermsChangedEvent(session);
UpdateAdminStatus(session);
}
private async void UpdateDatabaseDeadminnedState(ICommonSession player, bool newState)
{
try
{
// NOTE: This function gets called if you deadmin/readmin from a transient admin status.
// (e.g. loginlocal)
// In which case there may not be a database record.
// The DB function handles this scenario fine, but it's worth noting.
await _dbManager.UpdateAdminDeadminnedAsync(player.UserId, newState);
}
catch (Exception e)
{
_sawmill.Error("Failed to save deadmin state to database for {Admin}", player.UserId);
}
}
public void Stealth(ICommonSession session)
{
if (!_admins.TryGetValue(session, out var reg))
@@ -151,8 +166,7 @@ namespace Content.Server.Administration.Managers
_chat.DispatchServerMessage(session, Loc.GetString("admin-manager-became-admin-message"));
var plyData = session.ContentData()!;
plyData.ExplicitlyDeadminned = false;
UpdateDatabaseDeadminnedState(session, false);
reg.Data.Active = true;
if (!reg.Data.Stealth)
@@ -208,13 +222,13 @@ namespace Content.Server.Administration.Managers
curAdmin.IsSpecialLogin = special;
curAdmin.RankId = rankId;
curAdmin.Data = aData;
}
if (!player.ContentData()!.ExplicitlyDeadminned)
{
aData.Active = true;
if (curAdmin.Data.Active)
{
aData.Active = true;
_chat.DispatchServerMessage(player, Loc.GetString("admin-manager-admin-permissions-updated-message"));
_chat.DispatchServerMessage(player, Loc.GetString("admin-manager-admin-permissions-updated-message"));
}
}
if (player.ContentData()!.Stealthed)
@@ -381,10 +395,8 @@ namespace Content.Server.Administration.Managers
if (session.ContentData()!.Stealthed)
reg.Data.Stealth = true;
if (!session.ContentData()!.ExplicitlyDeadminned)
if (reg.Data.Active)
{
reg.Data.Active = true;
if (_cfg.GetCVar(CCVars.AdminAnnounceLogin))
{
if (reg.Data.Stealth)
@@ -430,6 +442,7 @@ namespace Content.Server.Administration.Managers
{
Title = Loc.GetString("admin-manager-admin-data-host-title"),
Flags = AdminFlagsHelper.Everything,
Active = true,
};
return (data, null, true);
@@ -444,6 +457,12 @@ namespace Content.Server.Administration.Managers
return null;
}
if (dbData.Suspended)
{
// Suspended admins don't count.
return null;
}
var flags = AdminFlags.None;
if (dbData.AdminRank != null)
@@ -466,7 +485,8 @@ namespace Content.Server.Administration.Managers
var data = new AdminData
{
Flags = flags
Flags = flags,
Active = !dbData.Deadminned,
};
if (dbData.Title != null && _cfg.GetCVar(CCVars.AdminUseCustomNamesAdminRank))

View File

@@ -0,0 +1,23 @@
using Content.Server.Administration.Notes;
using Content.Server.Database;
using Content.Server.Discord;
using Content.Shared.CCVar;
using Robust.Server;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using System.Linq;
namespace Content.Server.Administration.Managers;
/// <summary>
/// This manager sends a webhook notification whenever a player with an active
/// watchlist joins the server.
/// </summary>
public interface IWatchlistWebhookManager
{
void Initialize();
void Update();
}

View File

@@ -0,0 +1,143 @@
using Content.Server.Administration.Notes;
using Content.Server.Database;
using Content.Server.Discord;
using Content.Shared.CCVar;
using Robust.Server;
using Robust.Server.Player;
using Robust.Shared.Enums;
using Robust.Shared.Configuration;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Timing;
using System.Linq;
using System.Text;
namespace Content.Server.Administration.Managers;
/// <summary>
/// This manager sends a Discord webhook notification whenever a player with an active
/// watchlist joins the server.
/// </summary>
public sealed class WatchlistWebhookManager : IWatchlistWebhookManager
{
[Dependency] private readonly IAdminNotesManager _adminNotes = default!;
[Dependency] private readonly IBaseServer _baseServer = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly DiscordWebhook _discord = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IPlayerManager _playerManager = default!;
private ISawmill _sawmill = default!;
private string _webhookUrl = default!;
private TimeSpan _bufferTime;
private List<WatchlistConnection> watchlistConnections = new();
private TimeSpan? _bufferStartTime;
public void Initialize()
{
_sawmill = Logger.GetSawmill("discord");
_cfg.OnValueChanged(CCVars.DiscordWatchlistConnectionBufferTime, SetBufferTime, true);
_cfg.OnValueChanged(CCVars.DiscordWatchlistConnectionWebhook, SetWebhookUrl, true);
_playerManager.PlayerStatusChanged += OnPlayerStatusChanged;
}
private void SetBufferTime(float bufferTimeSeconds)
{
_bufferTime = TimeSpan.FromSeconds(bufferTimeSeconds);
}
private void SetWebhookUrl(string webhookUrl)
{
_webhookUrl = webhookUrl;
}
private async void OnPlayerStatusChanged(object? sender, SessionStatusEventArgs e)
{
if (e.NewStatus != SessionStatus.Connected)
return;
var watchlists = await _adminNotes.GetActiveWatchlists(e.Session.UserId);
if (watchlists.Count == 0)
return;
watchlistConnections.Add(new WatchlistConnection(e.Session.Name, watchlists));
if (_bufferTime > TimeSpan.Zero)
{
if (_bufferStartTime == null)
_bufferStartTime = _gameTiming.RealTime;
}
else
{
SendDiscordMessage();
}
}
public void Update()
{
if (_bufferStartTime != null && _gameTiming.RealTime > (_bufferStartTime + _bufferTime))
{
SendDiscordMessage();
_bufferStartTime = null;
}
}
private async void SendDiscordMessage()
{
try
{
if (string.IsNullOrWhiteSpace(_webhookUrl))
return;
var webhookData = await _discord.GetWebhook(_webhookUrl);
if (webhookData == null)
return;
var webhookIdentifier = webhookData.Value.ToIdentifier();
var messageBuilder = new StringBuilder(Loc.GetString("discord-watchlist-connection-header",
("players", watchlistConnections.Count),
("serverName", _baseServer.ServerName)));
foreach (var connection in watchlistConnections)
{
messageBuilder.Append('\n');
var watchlist = connection.Watchlists.First();
var expiry = watchlist.ExpirationTime?.ToUnixTimeSeconds();
messageBuilder.Append(Loc.GetString("discord-watchlist-connection-entry",
("playerName", connection.PlayerName),
("message", watchlist.Message),
("expiry", expiry ?? 0),
("otherWatchlists", connection.Watchlists.Count - 1)));
}
var payload = new WebhookPayload { Content = messageBuilder.ToString() };
await _discord.CreateMessage(webhookIdentifier, payload);
}
catch (Exception e)
{
_sawmill.Error($"Error while sending discord watchlist connection message:\n{e}");
}
// Clear the buffered list regardless of whether the message is sent successfully
// This prevents infinitely buffering connections if we fail to send a message
watchlistConnections.Clear();
}
private sealed class WatchlistConnection
{
public string PlayerName;
public List<AdminWatchlistRecord> Watchlists;
public WatchlistConnection(string playerName, List<AdminWatchlistRecord> watchlists)
{
PlayerName = playerName;
Watchlists = watchlists;
}
}
}

View File

@@ -65,7 +65,6 @@ public sealed class AdminSystem : EntitySystem
private readonly HashSet<NetUserId> _roundActivePlayers = new();
public readonly PanicBunkerStatus PanicBunker = new();
public readonly BabyJailStatus BabyJail = new();
public override void Initialize()
{
@@ -85,16 +84,6 @@ public sealed class AdminSystem : EntitySystem
Subs.CVar(_config, CCVars.PanicBunkerMinOverallMinutes, OnPanicBunkerMinOverallMinutesChanged, true);
Subs.CVar(_config, CCCVars.PanicBunkerDenyVPN, OnPanicBunkerDenyVpnChanged, true); // Corvax-VPNGuard
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
// Baby Jail Settings
Subs.CVar(_config, CCVars.BabyJailEnabled, OnBabyJailChanged, true);
Subs.CVar(_config, CCVars.BabyJailShowReason, OnBabyJailShowReasonChanged, true);
Subs.CVar(_config, CCVars.BabyJailMaxAccountAge, OnBabyJailMaxAccountAgeChanged, true);
Subs.CVar(_config, CCVars.BabyJailMaxOverallMinutes, OnBabyJailMaxOverallMinutesChanged, true);
SubscribeLocalEvent<IdentityChangedEvent>(OnIdentityChanged);
SubscribeLocalEvent<PlayerAttachedEvent>(OnPlayerAttached);
SubscribeLocalEvent<PlayerDetachedEvent>(OnPlayerDetached);
@@ -281,17 +270,6 @@ public sealed class AdminSystem : EntitySystem
SendPanicBunkerStatusAll();
}
private void OnBabyJailChanged(bool enabled)
{
BabyJail.Enabled = enabled;
_chat.SendAdminAlert(Loc.GetString(enabled
? "admin-ui-baby-jail-enabled-admin-alert"
: "admin-ui-baby-jail-disabled-admin-alert"
));
SendBabyJailStatusAll();
}
private void OnPanicBunkerDisableWithAdminsChanged(bool enabled)
{
PanicBunker.DisableWithAdmins = enabled;
@@ -316,36 +294,18 @@ public sealed class AdminSystem : EntitySystem
SendPanicBunkerStatusAll();
}
private void OnBabyJailShowReasonChanged(bool enabled)
{
BabyJail.ShowReason = enabled;
SendBabyJailStatusAll();
}
private void OnPanicBunkerMinAccountAgeChanged(int minutes)
{
PanicBunker.MinAccountAgeMinutes = minutes;
SendPanicBunkerStatusAll();
}
private void OnBabyJailMaxAccountAgeChanged(int minutes)
{
BabyJail.MaxAccountAgeMinutes = minutes;
SendBabyJailStatusAll();
}
private void OnPanicBunkerMinOverallMinutesChanged(int minutes)
{
PanicBunker.MinOverallMinutes = minutes;
SendPanicBunkerStatusAll();
}
private void OnBabyJailMaxOverallMinutesChanged(int minutes)
{
BabyJail.MaxOverallMinutes = minutes;
SendBabyJailStatusAll();
}
// Corvax-VPNGuard-Start
private void OnPanicBunkerDenyVpnChanged(bool deny)
{
@@ -400,15 +360,6 @@ public sealed class AdminSystem : EntitySystem
}
}
private void SendBabyJailStatusAll()
{
var ev = new BabyJailChangedEvent(BabyJail);
foreach (var admin in _adminManager.AllAdmins)
{
RaiseNetworkEvent(ev, admin);
}
}
/// <summary>
/// Erases a player from the round.
/// This removes them and any trace of them from the round, deleting their

View File

@@ -76,7 +76,8 @@ namespace Content.Server.Administration.UI
Title = p.a.Title,
RankId = p.a.AdminRankId,
UserId = new NetUserId(p.a.UserId),
UserName = p.lastUserName
UserName = p.lastUserName,
Suspended = p.a.Suspended,
}).ToArray(),
AdminRanks = _adminRanks.ToDictionary(a => a.Id, a => new PermissionsEuiState.AdminRankData
@@ -255,6 +256,7 @@ namespace Content.Server.Administration.UI
admin.Title = ua.Title;
admin.AdminRankId = ua.RankId;
admin.Flags = GenAdminFlagList(ua.PosFlags, ua.NegFlags);
admin.Suspended = ua.Suspended;
await _db.UpdateAdminAsync(admin);
@@ -335,7 +337,8 @@ namespace Content.Server.Administration.UI
Flags = GenAdminFlagList(ca.PosFlags, ca.NegFlags),
AdminRankId = ca.RankId,
UserId = userId.UserId,
Title = ca.Title
Title = ca.Title,
Suspended = ca.Suspended,
};
await _db.AddAdminAsync(admin);

View File

@@ -101,9 +101,16 @@ namespace Content.Server.Connection
time = newTime;
}
public void Update()
public async void Update()
{
_ipintel.Update();
try
{
await _ipintel.Update();
}
catch (Exception e)
{
_sawmill.Error("IPIntel update failed:" + e);
}
}
/*
@@ -303,14 +310,6 @@ namespace Content.Server.Connection
}
}
if (_cfg.GetCVar(CCVars.BabyJailEnabled) && adminData == null)
{
var result = await IsInvalidConnectionDueToBabyJail(userId, e);
if (result.IsInvalid)
return (ConnectionDenyReason.BabyJail, result.Reason, null);
}
var wasInGame = EntitySystem.TryGet<GameTicker>(out var ticker) &&
ticker.PlayerGameStatuses.TryGetValue(userId, out var status) &&
status == PlayerGameStatus.JoinedGame;
@@ -372,72 +371,6 @@ namespace Content.Server.Connection
return null;
}
private async Task<(bool IsInvalid, string Reason)> IsInvalidConnectionDueToBabyJail(NetUserId userId, NetConnectingArgs e)
{
// If you're whitelisted then bypass this whole thing
if (await _db.GetWhitelistStatusAsync(userId))
return (false, "");
// Initial cvar retrieval
var showReason = _cfg.GetCVar(CCVars.BabyJailShowReason);
var reason = _cfg.GetCVar(CCVars.BabyJailCustomReason);
var maxAccountAgeMinutes = _cfg.GetCVar(CCVars.BabyJailMaxAccountAge);
var maxPlaytimeMinutes = _cfg.GetCVar(CCVars.BabyJailMaxOverallMinutes);
// Wait some time to lookup data
var record = await _db.GetPlayerRecordByUserId(userId);
// No player record = new account or the DB is having a skill issue
if (record == null)
return (false, "");
var isAccountAgeInvalid = record.FirstSeenTime.CompareTo(DateTimeOffset.UtcNow - TimeSpan.FromMinutes(maxAccountAgeMinutes)) <= 0;
if (isAccountAgeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for account age {record.FirstSeenTime}"); // Remove on or after 2024-09
}
if (isAccountAgeInvalid && showReason)
{
var locAccountReason = reason != string.Empty
? reason
: Loc.GetString("baby-jail-account-denied-reason",
("reason",
Loc.GetString(
"baby-jail-account-reason-account",
("minutes", maxAccountAgeMinutes))));
return (true, locAccountReason);
}
var overallTime = ( await _db.GetPlayTimes(e.UserId)).Find(p => p.Tracker == PlayTimeTrackingShared.TrackerOverall);
var isTotalPlaytimeInvalid = overallTime != null && overallTime.TimeSpent.TotalMinutes >= maxPlaytimeMinutes;
if (isTotalPlaytimeInvalid)
{
_sawmill.Debug($"Baby jail will deny {userId} for playtime {overallTime!.TimeSpent}"); // Remove on or after 2024-09
}
if (isTotalPlaytimeInvalid && showReason)
{
var locPlaytimeReason = reason != string.Empty
? reason
: Loc.GetString("baby-jail-account-denied-reason",
("reason",
Loc.GetString(
"baby-jail-account-reason-overall",
("minutes", maxPlaytimeMinutes))));
return (true, locPlaytimeReason);
}
if (!showReason && isTotalPlaytimeInvalid || isAccountAgeInvalid)
return (true, Loc.GetString("baby-jail-account-denied"));
return (false, "");
}
private bool HasTemporaryBypass(NetUserId user)
{
return _temporaryBypasses.TryGetValue(user, out var time) && time > _gameTiming.RealTime;

View File

@@ -38,6 +38,7 @@ public sealed class IPIntel
_sawmill = logManager.GetSawmill("ipintel");
cfg.OnValueChanged(CCVars.GameIPIntelEmail, b => _contactEmail = b, true);
cfg.OnValueChanged(CCVars.GameIPIntelEnabled, b => _enabled = b, true);
cfg.OnValueChanged(CCVars.GameIPIntelRejectUnknown, b => _rejectUnknown = b, true);
cfg.OnValueChanged(CCVars.GameIPIntelRejectBad, b => _rejectBad = b, true);
cfg.OnValueChanged(CCVars.GameIPIntelRejectRateLimited, b => _rejectLimited = b, true);
@@ -74,6 +75,7 @@ public sealed class IPIntel
// CCVars
private string? _contactEmail;
private bool _enabled;
private bool _rejectUnknown;
private bool _rejectBad;
private bool _rejectLimited;
@@ -273,12 +275,12 @@ public sealed class IPIntel
return _rejectBad ? (true, Loc.GetString("ipintel-suspicious")) : (false, string.Empty);
}
public void Update()
public async Task Update()
{
if (_gameTiming.RealTime >= _nextClean)
if (_enabled && _gameTiming.RealTime >= _nextClean)
{
_nextClean = _gameTiming.RealTime + TimeSpan.FromMinutes(_cleanupMins);
_db.CleanIPIntelCache(_cacheDays);
await _db.CleanIPIntelCache(_cacheDays);
}
}

View File

@@ -759,6 +759,20 @@ namespace Content.Server.Database
existing.Flags = admin.Flags;
existing.Title = admin.Title;
existing.AdminRankId = admin.AdminRankId;
existing.Deadminned = admin.Deadminned;
existing.Suspended = admin.Suspended;
await db.DbContext.SaveChangesAsync(cancel);
}
public async Task UpdateAdminDeadminnedAsync(NetUserId userId, bool deadminned, CancellationToken cancel)
{
await using var db = await GetDb(cancel);
var adminRecord = db.DbContext.Admin.Where(a => a.UserId == userId);
await adminRecord.ExecuteUpdateAsync(
set => set.SetProperty(p => p.Deadminned, deadminned),
cancellationToken: cancel);
await db.DbContext.SaveChangesAsync(cancel);
}
@@ -1782,8 +1796,11 @@ INSERT INTO player_round (players_id, rounds_id) VALUES ({players[player]}, {id}
{
await using var db = await GetDb();
// Calculating this here cause otherwise sqlite whines.
var cutoffTime = DateTime.UtcNow.Subtract(range);
await db.DbContext.IPIntelCache
.Where(w => DateTime.UtcNow - w.Time >= range)
.Where(w => w.Time <= cutoffTime)
.ExecuteDeleteAsync();
await db.DbContext.SaveChangesAsync();

View File

@@ -217,6 +217,16 @@ namespace Content.Server.Database
Task AddAdminAsync(Admin admin, CancellationToken cancel = default);
Task UpdateAdminAsync(Admin admin, CancellationToken cancel = default);
/// <summary>
/// Update whether an admin has voluntarily deadminned.
/// </summary>
/// <remarks>
/// This does nothing if the player is not an admin.
/// </remarks>
/// <param name="userId">The user ID of the admin.</param>
/// <param name="deadminned">Whether the admin is deadminned or not.</param>
Task UpdateAdminDeadminnedAsync(NetUserId userId, bool deadminned, CancellationToken cancel = default);
Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default);
Task AddAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
Task UpdateAdminRankAsync(AdminRank rank, CancellationToken cancel = default);
@@ -674,6 +684,12 @@ namespace Content.Server.Database
return RunDbCommand(() => _db.UpdateAdminAsync(admin, cancel));
}
public Task UpdateAdminDeadminnedAsync(NetUserId userId, bool deadminned, CancellationToken cancel = default)
{
DbWriteOpsMetric.Inc();
return RunDbCommand(() => _db.UpdateAdminDeadminnedAsync(userId, deadminned, cancel));
}
public Task RemoveAdminRankAsync(int rankId, CancellationToken cancel = default)
{
DbWriteOpsMetric.Inc();

View File

@@ -49,6 +49,7 @@ namespace Content.Server.Entry
private PlayTimeTrackingManager? _playTimeTracking;
private IEntitySystemManager? _sysMan;
private IServerDbManager? _dbManager;
private IWatchlistWebhookManager _watchlistWebhookManager = default!;
private IConnectionManager? _connectionManager;
/// <inheritdoc />
@@ -97,6 +98,7 @@ namespace Content.Server.Entry
_connectionManager = IoCManager.Resolve<IConnectionManager>();
_sysMan = IoCManager.Resolve<IEntitySystemManager>();
_dbManager = IoCManager.Resolve<IServerDbManager>();
_watchlistWebhookManager = IoCManager.Resolve<IWatchlistWebhookManager>();
logManager.GetSawmill("Storage").Level = LogLevel.Info;
logManager.GetSawmill("db.ef").Level = LogLevel.Info;
@@ -115,6 +117,7 @@ namespace Content.Server.Entry
_voteManager.Initialize();
_updateManager.Initialize();
_playTimeTracking.Initialize();
_watchlistWebhookManager.Initialize();
IoCManager.Resolve<JobWhitelistManager>().Initialize();
IoCManager.Resolve<PlayerRateLimitManager>().Initialize();
}
@@ -182,6 +185,7 @@ namespace Content.Server.Entry
case ModUpdateLevel.FramePostEngine:
_updateManager.Update();
_playTimeTracking?.Update();
_watchlistWebhookManager.Update();
_connectionManager?.Update();
break;
}

View File

@@ -55,6 +55,8 @@ public sealed partial class PuddleSystem
Spawn("PuddleSparkle", xformQuery.GetComponent(uid).Coordinates);
QueueDel(uid);
}
_solutionContainerSystem.UpdateChemicals(puddle.Solution.Value);
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using System.Text.Json.Nodes;
using Content.Corvax.Interfaces.Server;
using Content.Shared.CCVar;
@@ -45,6 +46,10 @@ namespace Content.Server.GameTicking
var players = IoCManager.Instance?.TryResolveType<IServerJoinQueueManager>(out var joinQueueManager) ?? false
? joinQueueManager.ActualPlayersCount
: _playerManager.PlayerCount;
players = _cfg.GetCVar(CCVars.AdminsCountInReportedPlayerCount)
? players
: players - _adminManager.ActiveAdmins.Count();
// Corvax-Queue-End
jObject["name"] = _baseServer.ServerName;
@@ -53,12 +58,6 @@ namespace Content.Server.GameTicking
jObject["players"] = players; // Corvax-Queue
jObject["soft_max_players"] = _cfg.GetCVar(CCVars.SoftMaxPlayers);
jObject["panic_bunker"] = _cfg.GetCVar(CCVars.PanicBunkerEnabled);
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
jObject["baby_jail"] = _cfg.GetCVar(CCVars.BabyJailEnabled);
jObject["run_level"] = (int) _runLevel;
if (preset != null)
jObject["preset"] = Loc.GetString(preset.ModeTitle);

View File

@@ -21,6 +21,7 @@ using Robust.Shared.Random;
using System.Numerics;
using Content.Shared.Movement.Pulling.Components;
using Content.Shared.Movement.Pulling.Systems;
using Content.Server.IdentityManagement;
using Content.Shared.Store.Components;
using Robust.Shared.Collections;
using Robust.Shared.Map.Components;
@@ -41,6 +42,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
[Dependency] private readonly PullingSystem _pullingSystem = default!;
[Dependency] private readonly EntityLookupSystem _lookupSystem = default!;
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
[Dependency] private readonly IdentitySystem _identity = default!;
private EntityQuery<PhysicsComponent> _physicsQuery;
private HashSet<Entity<MapGridComponent>> _targetGrids = [];
@@ -211,7 +213,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
{
var newProfile = HumanoidCharacterProfile.RandomWithSpecies(humanoid.Species);
_humanoidAppearance.LoadProfile(ent, newProfile, humanoid);
_metaData.SetEntityName(ent, newProfile.Name);
_metaData.SetEntityName(ent, newProfile.Name, raiseEvents: false); // raising events would update ID card, station record, etc.
if (TryComp<DnaComponent>(ent, out var dna))
{
dna.DNA = _forensicsSystem.GenerateDNA();
@@ -223,6 +225,7 @@ public sealed class SubdermalImplantSystem : SharedSubdermalImplantSystem
{
fingerprint.Fingerprint = _forensicsSystem.GenerateFingerprint();
}
_identity.QueueIdentityUpdate(ent); // manually queue identity update since we don't raise the event
_popup.PopupEntity(Loc.GetString("scramble-implant-activated-popup"), ent, ent);
}

View File

@@ -75,6 +75,7 @@ namespace Content.Server.IoC
IoCManager.Register<PlayerRateLimitManager>();
IoCManager.Register<SharedPlayerRateLimitManager, PlayerRateLimitManager>();
IoCManager.Register<MappingManager>();
IoCManager.Register<IWatchlistWebhookManager, WatchlistWebhookManager>();
IoCManager.Register<ConnectionManager>();
}
}

View File

@@ -0,0 +1,7 @@
namespace Content.Server.Speech.Components;
[RegisterComponent]
public sealed partial class MumbleAccentComponent : Component
{
}

View File

@@ -0,0 +1,25 @@
using Content.Server.Speech.Components;
namespace Content.Server.Speech.EntitySystems;
public sealed class MumbleAccentSystem : EntitySystem
{
[Dependency] private readonly ReplacementAccentSystem _replacement = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MumbleAccentComponent, AccentGetEvent>(OnAccentGet);
}
public string Accentuate(string message, MumbleAccentComponent component)
{
return _replacement.ApplyReplacements(message, "mumble");
}
private void OnAccentGet(EntityUid uid, MumbleAccentComponent component, AccentGetEvent args)
{
args.Message = Accentuate(args.Message, component);
}
}

View File

@@ -1,22 +0,0 @@
using Robust.Shared.Serialization;
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
namespace Content.Shared.Administration.Events;
[Serializable, NetSerializable]
public sealed class BabyJailStatus
{
public bool Enabled;
public bool ShowReason;
public int MaxAccountAgeMinutes;
public int MaxOverallMinutes;
}
[Serializable, NetSerializable]
public sealed class BabyJailChangedEvent(BabyJailStatus status) : EntityEventArgs
{
public BabyJailStatus Status = status;
}

View File

@@ -18,6 +18,7 @@ namespace Content.Shared.Administration
public NetUserId UserId;
public string? UserName;
public string? Title;
public bool Suspended;
public AdminFlags PosFlags;
public AdminFlags NegFlags;
public int? RankId;
@@ -41,6 +42,7 @@ namespace Content.Shared.Administration
public AdminFlags PosFlags;
public AdminFlags NegFlags;
public int? RankId;
public bool Suspended;
}
[Serializable, NetSerializable]
@@ -57,6 +59,7 @@ namespace Content.Shared.Administration
public AdminFlags PosFlags;
public AdminFlags NegFlags;
public int? RankId;
public bool Suspended;
}

View File

@@ -158,6 +158,13 @@ public sealed partial class CCVars
public static readonly CVarDef<bool> AdminsCountForMaxPlayers =
CVarDef.Create("admin.admins_count_for_max_players", false, CVar.SERVERONLY);
/// <summary>
/// Should admins be hidden from the player count reported to the launcher/via api?
/// This is hub advert safe, in case that's a worry.
/// </summary>
public static readonly CVarDef<bool> AdminsCountInReportedPlayerCount =
CVarDef.Create("admin.admins_count_in_playercount", false, CVar.SERVERONLY);
/// <summary>
/// Determine if custom rank names are used.
/// If it is false, it'd use the actual rank name regardless of the individual's title.

View File

@@ -1,4 +1,4 @@
using Robust.Shared.Configuration;
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
@@ -58,4 +58,18 @@ public sealed partial class CCVars
/// </summary>
public static readonly CVarDef<string> DiscordRoundEndRoleWebhook =
CVarDef.Create("discord.round_end_role", string.Empty, CVar.SERVERONLY);
/// <summary>
/// URL of the Discord webhook which will relay watchlist connection notifications. If left empty, disables the webhook.
/// </summary>
public static readonly CVarDef<string> DiscordWatchlistConnectionWebhook =
CVarDef.Create("discord.watchlist_connection_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// How long to buffer watchlist connections for, in seconds.
/// All connections within this amount of time from the first one will be batched and sent as a single
/// Discord notification. If zero, always sends a separate notification for each connection (not recommended).
/// </summary>
public static readonly CVarDef<float> DiscordWatchlistConnectionBufferTime =
CVarDef.Create("discord.watchlist_connection_buffer_time", 5f, CVar.SERVERONLY);
}

View File

@@ -198,48 +198,6 @@ public sealed partial class CCVars
public static readonly CVarDef<bool> BypassBunkerWhitelist =
CVarDef.Create("game.panic_bunker.whitelisted_can_bypass", true, CVar.SERVERONLY);
/*
* TODO: Remove baby jail code once a more mature gateway process is established. This code is only being issued as a stopgap to help with potential tiding in the immediate future.
*/
/// <summary>
/// Whether the baby jail is currently enabled.
/// </summary>
public static readonly CVarDef<bool> BabyJailEnabled =
CVarDef.Create("game.baby_jail.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Show reason of disconnect for user or not.
/// </summary>
public static readonly CVarDef<bool> BabyJailShowReason =
CVarDef.Create("game.baby_jail.show_reason", false, CVar.SERVERONLY);
/// <summary>
/// Maximum age of the account (from server's PoV, so from first-seen date) in minutes that can access baby
/// jailed servers.
/// </summary>
public static readonly CVarDef<int> BabyJailMaxAccountAge =
CVarDef.Create("game.baby_jail.max_account_age", 1440, CVar.SERVERONLY);
/// <summary>
/// Maximum overall played time allowed to access baby jailed servers.
/// </summary>
public static readonly CVarDef<int> BabyJailMaxOverallMinutes =
CVarDef.Create("game.baby_jail.max_overall_minutes", 120, CVar.SERVERONLY);
/// <summary>
/// A custom message that will be used for connections denied due to the baby jail.
/// If not empty, then will overwrite <see cref="BabyJailShowReason"/>
/// </summary>
public static readonly CVarDef<string> BabyJailCustomReason =
CVarDef.Create("game.baby_jail.custom_reason", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Allow bypassing the baby jail if the user is whitelisted.
/// </summary>
public static readonly CVarDef<bool> BypassBabyJailWhitelist =
CVarDef.Create("game.baby_jail.whitelisted_can_bypass", true, CVar.SERVERONLY);
/// <summary>
/// Enable IPIntel for blocking VPN connections from new players.
/// </summary>

View File

@@ -75,10 +75,10 @@ namespace Content.Shared.Containers.ItemSlots
public EntityWhitelist? Blacklist;
[DataField]
public SoundSpecifier InsertSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/revolver_magin.ogg");
public SoundSpecifier? InsertSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/revolver_magin.ogg");
[DataField]
public SoundSpecifier EjectSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagOut/revolver_magout.ogg");
public SoundSpecifier? EjectSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagOut/revolver_magout.ogg");
/// <summary>
/// The name of this item slot. This will be shown to the user in the verb menu.

View File

@@ -589,8 +589,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassAirlockLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.TableLayer)
continue;
//If the colliding entity is a slippable item ignore it by the airlock
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.SlipLayer && otherPhysics.Comp.CollisionMask == (int) CollisionGroup.ItemMask)
// Ignore low-passable entities.
if ((otherPhysics.Comp.CollisionMask & (int)CollisionGroup.LowImpassable) == 0)
continue;
//For when doors need to close over conveyor belts

View File

@@ -32,12 +32,6 @@ public sealed class ContentPlayerData
[ViewVariables, Access(typeof(SharedMindSystem), typeof(SharedGameTicker))]
public EntityUid? Mind { get; set; }
/// <summary>
/// If true, the player is an admin and they explicitly de-adminned mid-game,
/// so they should not regain admin if they reconnect.
/// </summary>
public bool ExplicitlyDeadminned { get; set; }
/// <summary>
/// If true, the admin will not show up in adminwho except to admins with the <see cref="AdminFlags.Stealth"/> flag.
/// </summary>

View File

@@ -695,5 +695,31 @@ Entries:
id: 86
time: '2025-01-12T19:41:26.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33339
- author: PJB3005
changes:
- message: Deadmin status is now synchronized to database, making it persistent
across server restarts and between multiple game servers.
type: Tweak
- message: Admins can now be suspended via the permissions panel. This effectively
removes their admin status without completely deleting their record.
type: Add
id: 87
time: '2025-01-14T23:46:45.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34048
- author: Palladinium
changes:
- message: Added Discord relay notifications when a watchlisted player connects.
type: Add
id: 88
time: '2025-01-15T00:32:24.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33483
- author: Myra
changes:
- message: Admins are by default now hidden from the reported player count on the
launcher.
type: Add
id: 89
time: '2025-01-15T21:10:54.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34406
Name: Admin
Order: 1

View File

@@ -1,144 +1,4 @@
Entries:
- author: EmoGarbage404
changes:
- message: Firesuits are now worse at keeping in heat and winter clothes make you
get warmer quicker.
type: Tweak
id: 7302
time: '2024-09-07T05:37:17.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30662
- author: Boaz1111
changes:
- message: The maple wing marking for moths now have a secondary color palette.
type: Tweak
id: 7303
time: '2024-09-07T05:48:40.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31691
- author: lzk228
changes:
- message: Bottle and syringe names are remade into labels.
type: Tweak
id: 7304
time: '2024-09-07T05:51:36.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29956
- author: Ian321
changes:
- message: The AgriChem kit now links to the botanical chemicals guidebook.
type: Tweak
- message: The botanical chemicals guidebook has been expanded.
type: Tweak
id: 7305
time: '2024-09-07T06:23:01.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31896
- author: Lank
changes:
- message: The Antimov and Overseer law boards are no longer available roundstart.
type: Remove
id: 7306
time: '2024-09-07T08:45:51.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31908
- author: lzk228
changes:
- message: Books cannot longer be inserted in crates as paper labels
type: Fix
id: 7307
time: '2024-09-07T13:22:11.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31919
- author: qwerltaz
changes:
- message: Reduced wall closet range. It's now much easier to not close yourself
inside by accident.
type: Tweak
id: 7308
time: '2024-09-07T23:44:29.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31933
- author: Ilya246
changes:
- message: Reagents that make you flammable no longer extinguish you.
type: Fix
id: 7309
time: '2024-09-07T23:44:58.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31930
- author: LucasTheDrgn
changes:
- message: Restored functionality to the Industrial Reagent Grinder
type: Fix
id: 7310
time: '2024-09-07T23:47:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31903
- author: EmoGarbage404
changes:
- message: Added the biogenerator! Botany can use this machine to create various
materials, chemicals, and food items out of the
type: Add
id: 7311
time: '2024-09-08T05:34:22.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30694
- author: TheShuEd
changes:
- message: Returned Taco microwave recipes (people were sad)
type: Add
- message: added an alternative method of crafting some burgers, through the correct
assembly sequence of modular food.
type: Add
- message: severely cut back on the number of items you can put on burgers, tacos,
or kebabs. This had poor design, and things need to be separately resprited
by adding them on modular food.
type: Tweak
id: 7312
time: '2024-09-08T06:22:27.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31012
- author: metalgearsloth
changes:
- message: Fix the FTL bubbles sometimes persisting.
type: Fix
- message: Fix AI eye being able to FTL.
type: Fix
- message: Fix the AI eye being able to be FTL smashed.
type: Fix
id: 7313
time: '2024-09-08T08:12:24.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31952
- author: PopGamer46
changes:
- message: Fixed being able to craft the justice helmet with a justice helmet
type: Fix
id: 7314
time: '2024-09-08T10:21:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31957
- author: Killerqu00
changes:
- message: Seclite is now restricted to security.
type: Tweak
- message: Handcuffs are now restricted to security and command.
type: Tweak
- message: Trench whistle is now minor contraband.
type: Tweak
id: 7315
time: '2024-09-08T12:06:01.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31956
- author: Psychpsyo
changes:
- message: The random sentience event should now actually happen again.
type: Fix
id: 7316
time: '2024-09-08T12:10:50.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31953
- author: Beck Thompson
changes:
- message: Gold and silver rings now give a small amount of materials when scrapped.
type: Tweak
id: 7317
time: '2024-09-08T16:10:05.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31847
- author: K-Dynamic
changes:
- message: added missing missing resistance values for directional plasma and uranium
windows
type: Fix
id: 7318
time: '2024-09-08T18:08:06.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/31975
- author: qwerltaz
changes:
- message: Power cables on the ground are now offset and do not obscure each other
@@ -3937,3 +3797,130 @@
id: 7801
time: '2025-01-12T16:38:41.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34394
- author: SlimSlam
changes:
- message: News Room
type: Add
id: 7802
time: '2025-01-12T23:32:51.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34408
- author: Deerstop
changes:
- message: Improved the readability of the manual valve sprite.
type: Tweak
id: 7803
time: '2025-01-13T07:07:30.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34378
- author: JustinWinningham
changes:
- message: Anomalies no longer block players or APES (or other objects) from passing
through them
type: Tweak
- message: Players can no longer move anomalies with unanchored furniture, closets,
etc.
type: Fix
id: 7804
time: '2025-01-13T10:06:57.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34280
- author: zHonys
changes:
- message: Items with collisions (like mousetraps) won't kept doors form opening
type: Fix
id: 7805
time: '2025-01-13T10:07:18.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34045
- author: Coolsurf6
changes:
- message: The "Jazz" style for the Electric Guitar now uses the correct soundfont.
type: Tweak
id: 7806
time: '2025-01-13T10:07:33.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33363
- author: southbridge-fur
changes:
- message: The Pride-O-Mat vending machine has been ported to upstream.
type: Add
id: 7807
time: '2025-01-13T18:49:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34412
- author: Killerqu00
changes:
- message: Pet carriers can now be crafted.
type: Add
id: 7808
time: '2025-01-14T22:34:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34431
- author: themias
changes:
- message: Fixed muzzles not working on some characters (e.g. dwarves)
type: Fix
id: 7809
time: '2025-01-15T00:10:39.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34419
- author: ArtisticRoomba
changes:
- message: The station anchor machine board can no longer be printed at the circuit
imprinter.
type: Remove
id: 7810
time: '2025-01-15T16:26:19.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34358
- author: ArtisticRoomba
changes:
- message: Mime PDA item interactions (insertions/ejections of IDs, pens, etc.)
are now silent.
type: Tweak
id: 7811
time: '2025-01-15T18:03:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34426
- author: Alpaccalypse
changes:
- message: Smite soda vending machines have been added to the game.
type: Add
id: 7812
time: '2025-01-15T18:20:01.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34420
- author: kosticia
changes:
- message: Bedsheets now can be printed on uniform printer
type: Add
id: 7813
time: '2025-01-15T19:35:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34034
- author: TheShuEd
changes:
- message: Christmas anomaly removed
type: Remove
id: 7814
time: '2025-01-15T20:22:32.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34053
- author: Kickguy223
changes:
- message: Puddles will now correctly evaporate
type: Fix
id: 7815
time: '2025-01-15T21:21:20.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34303
- author: themias
changes:
- message: The DNA scrambler implant no longer updates your ID card or station record
type: Fix
id: 7816
time: '2025-01-15T22:49:51.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34091
- author: jbox144
changes:
- message: Added Plasma Station
type: Add
id: 7817
time: '2025-01-16T07:02:14.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/33991
- author: jbox144
changes:
- message: Reduced Plasma's minimum population to 20, maximum population to 60
type: Tweak
- message: Reduced Plasma's clown jobs from 2 to 1
type: Tweak
id: 7818
time: '2025-01-16T08:51:17.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/34462

View File

@@ -12,6 +12,10 @@ panic_bunker.enable_without_admins = true
panic_bunker.show_reason = true
panic_bunker.custom_reason = "You have not played on a Wizard's Den server long enough to connect to this server. Please play on Wizard's Den Lizard until you have more playtime."
# IPIntel stuff
ipintel_enabled = true
ipintel_contact_email = "telecommunications@spacestation14.com"
[infolinks]
bug_report = "https://github.com/space-wizards/space-station-14/issues/new/choose"
discord = "https://discord.spacestation14.io"
@@ -44,6 +48,6 @@ alert.min_players_sharing_connection = 2
max_explosion_range = 5
[status]
privacy_policy_link = "https://account.spacestation14.com/Home/Privacy"
privacy_policy_link = "https://spacestation14.com/about/privacy/#game-server-privacy-policy"
privacy_policy_identifier = "wizden"
privacy_policy_version = "2024-12-22"
privacy_policy_version = "2025-01-19"

View File

@@ -11,12 +11,6 @@ panic_bunker.enabled = false
panic_bunker.disable_with_admins = false
panic_bunker.enable_without_admins = false
panic_bunker.custom_reason = ""
baby_jail.enabled = true
baby_jail.show_reason = true
baby_jail.max_account_age = 5256000 # 10 years. Disabling this check specifically isn't currently supported
baby_jail.max_overall_minutes = 3000 # 50 hours
baby_jail.custom_reason = "Sorry! Only new and whitelisted players can join this server. Apply to be whitelisted in our Discord server (discord.ss14.io) or try joining another server instead!"
baby_jail.whitelisted_can_bypass = true
[hub]
tags = "lang:en,region:am_n_e,rp:low"

View File

@@ -1,19 +0,0 @@
cmd-babyjail-desc = Toggles the baby jail, which enables stricter restrictions on who's allowed to join the server.
cmd-babyjail-help = Usage: babyjail
babyjail-command-enabled = Baby jail has been enabled.
babyjail-command-disabled = Baby jail has been disabled.
cmd-babyjail_show_reason-desc = Toggles whether or not to show connecting clients the reason why the baby jail blocked them from joining.
cmd-babyjail_show_reason-help = Usage: babyjail_show_reason
babyjail-command-show-reason-enabled = The baby jail will now show a reason to users it blocks from connecting.
babyjail-command-show-reason-disabled = The baby jail will no longer show a reason to users it blocks from connecting.
cmd-babyjail_max_account_age-desc = Gets or sets the maximum account age in minutes that an account can have to be allowed to connect with the baby jail enabled.
cmd-babyjail_max_account_age-help = Usage: babyjail_max_account_age <minutes>
babyjail-command-max-account-age-is = The maximum account age for the baby jail is {$minutes} minutes.
babyjail-command-max-account-age-set = Set the maximum account age for the baby jail to {$minutes} minutes.
cmd-babyjail_max_overall_minutes-desc = Gets or sets the maximum overall playtime in minutes that an account can have to be allowed to connect with the baby jail enabled.
cmd-babyjail_max_overall_minutes-help = Usage: babyjail_max_overall_minutes <minutes>
babyjail-command-max-overall-minutes-is = The maximum overall playtime for the baby jail is {$minutes} minutes.
babyjail-command-max-overall-minutes-set = Set the maximum overall playtime for the baby jail to {$minutes} minutes.

View File

@@ -14,6 +14,7 @@ permissions-eui-edit-admin-window-title-edit-placeholder = Custom title, leave b
permissions-eui-edit-admin-window-no-rank-button = No rank
permissions-eui-edit-admin-rank-window-name-edit-placeholder = Rank name
permissions-eui-edit-admin-title-control-text = none
permissions-eui-edit-admin-window-suspended = Suspended?
permissions-eui-edit-no-rank-text = none
permissions-eui-edit-title-button = Edit
permissions-eui-edit-admin-rank-button = Edit

View File

@@ -0,0 +1,7 @@
advertisement-pride-1 = Be gay do crime!
advertisement-pride-2 = Full of colors!
advertisement-pride-3 = You are valid!
advertisement-pride-4 = The first pride was a riot!
thankyou-pride-1 = Slay!
thankyou-pride-2 = Knock 'em dead!
thankyou-pride-3 = What a glow up!

View File

@@ -0,0 +1,12 @@
advertisement-smite-1 = SMITE! Ban your thirst!
advertisement-smite-2 = An eldritch blast of lemon and lime!
advertisement-smite-3 = Over 1 million drinks sold!
advertisement-smite-4 = SMITE! Roll 2d8 for FLAVOR.
advertisement-smite-5 = SMITE! Let's get that paperwork done!
advertisement-smite-6 = The janitor has it in for you!
advertisement-smite-7 = SMITE! It won't get you hammered.
advertisement-smite-8 = It's lemon-lime time!
thankyou-smite-1 = Smite makes right!
thankyou-smite-2 = You DEFINITELY wanted lemon-lime!
thankyou-smite-3 = The office won't know what hit them.
thankyou-smite-4 = Banish your thirst.

View File

@@ -0,0 +1,14 @@
discord-watchlist-connection-header =
{ $players ->
[one] {$players} player on a watchlist has
*[other] {$players} players on a watchlist have
} connected to {$serverName}
discord-watchlist-connection-entry = - {$playerName} with message "{$message}"{ $expiry ->
[0] {""}
*[other] {" "}(expires <t:{$expiry}:R>)
}{ $otherWatchlists ->
[0] {""}
[one] {" "}and {$otherWatchlists} other watchlist
*[other] {" "}and {$otherWatchlists} other watchlists
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@ entities:
name: NT Evac Log
- type: Transform
pos: -0.42093527,-0.86894274
parent: invalid
parent: 637
- type: MapGrid
chunks:
0,0:
@@ -804,6 +804,18 @@ entities:
chunkSize: 4
- type: GasTileOverlay
- type: RadiationGridResistance
- uid: 637
components:
- type: MetaData
name: Map Entity
- type: Transform
- type: Map
mapPaused: True
- type: PhysicsMap
- type: GridTree
- type: MovedGrids
- type: Broadphase
- type: OccluderTree
- proto: AirAlarm
entities:
- uid: 577
@@ -1130,6 +1142,56 @@ entities:
- type: Transform
pos: 1.5,-6.5
parent: 1
- proto: AtmosDeviceFanDirectional
entities:
- uid: 638
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -4.5,5.5
parent: 1
- uid: 639
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -4.5,3.5
parent: 1
- uid: 640
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -4.5,-2.5
parent: 1
- uid: 641
components:
- type: Transform
rot: -1.5707963267948966 rad
pos: -4.5,-4.5
parent: 1
- uid: 642
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 5.5,-4.5
parent: 1
- uid: 643
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 5.5,-2.5
parent: 1
- uid: 644
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 5.5,3.5
parent: 1
- uid: 645
components:
- type: Transform
rot: 1.5707963267948966 rad
pos: 5.5,5.5
parent: 1
- proto: AtmosFixBlockerMarker
entities:
- uid: 615

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

167820
Resources/Maps/plasma.yml Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -150,7 +150,7 @@
- type: entity
id: CrateAirlockKit
parent: CrateGenericSteel
parent: CrateEngineering
name: airlock kit
description: A kit for building 6 airlocks, doesn't include tools.
components:
@@ -215,3 +215,31 @@
- type: StorageFill
contents:
- id: SpaceHeaterFlatpack
- type: entityTable
id: RandomTechBoardTable
table: !type:GroupSelector
children:
- id: AirAlarmElectronics
- id: FireAlarmElectronics
- id: DoorElectronics
- id: FirelockElectronics
- id: APCElectronics
- id: SignalTimerElectronics
- id: SMESMachineCircuitboard
- id: SubstationMachineCircuitboard
- id: SpaceVillainArcadeComputerCircuitboard
- id: BlockGameArcadeComputerCircuitboard
- type: entity
id: CrateTechBoardRandom
parent: CrateEngineering
name: surplus boards
description: Surplus boards from somewhere.
components:
- type: EntityTableContainerFill
containers:
entity_storage: !type:NestedSelector
tableId: RandomTechBoardTable
rolls: !type:RangeNumberSelector
range: 3, 7

View File

@@ -107,6 +107,52 @@
- id: SheetPaper
amount: 3
- type: entityTable
id: RandomMaterialCrateTable
table: !type:GroupSelector
children:
- !type:GroupSelector # regular materials, 10
weight: 35
children:
- id: SheetGlass10
- id: SheetSteel10
- id: SheetPlastic10
- !type:GroupSelector # regular materials, stack
weight: 30
children:
- id: SheetGlass
- id: SheetSteel
- id: SheetPlastic
- !type:GroupSelector # secondary materials, stack
weight: 30
children:
- id: MaterialCloth
- id: SheetPlasteel
- id: MaterialWoodPlank
- id: PartRodMetal
- !type:GroupSelector # tertiary materials, singles
weight: 5
children:
- id: SheetPlasma1
- id: SheetUranium1
- id: IngotGold1
- id: IngotSilver1
- type: entity
id: CrateMaterialRandom
parent: CrateGenericSteel
name: surplus materials
description: Surplus materials from somewhere.
components:
- type: EntityTableContainerFill
containers:
entity_storage: !type:NestedSelector
tableId: RandomMaterialCrateTable
rolls: !type:RangeNumberSelector
range: 1, 3
# for some reason, the selector here adds 1 to whatever value it generates,
# so this is actually 2-4
#- type: entity
# id: CrateMaterialHFuelTank
# name: fueltank crate

View File

@@ -159,6 +159,9 @@
- !type:NestedSelector
tableId: SyndieMaintLoot
prob: 0.05
# Recursive
- id: ClosetMaintenanceFilledRandom
prob: 0.01
- type: entity
id: ClosetMaintenanceFilledRandom

View File

@@ -0,0 +1,35 @@
- type: vendingMachineInventory
id: PrideDrobeInventory
startingInventory:
ClothingNeckLGBTPin: 3
ClothingNeckAromanticPin: 3
ClothingNeckAsexualPin: 3
ClothingNeckBisexualPin: 3
ClothingNeckGayPin: 3
ClothingNeckIntersexPin: 3
ClothingNeckLesbianPin: 3
ClothingNeckNonBinaryPin: 3
ClothingNeckPansexualPin: 3
ClothingNeckOmnisexualPin: 3
ClothingNeckTransPin: 3
ClothingNeckAutismPin: 3
ClothingNeckGoldAutismPin: 3
PlushieSharkBlue: 2
PlushieSharkPink: 2
PlushieSharkGrey: 2
ClothingNeckCloakAce: 2
ClothingNeckCloakAro: 2
ClothingNeckCloakBi: 2
ClothingNeckCloakEnby: 2
ClothingNeckCloakGay: 2
ClothingNeckCloakIntersex: 2
ClothingNeckCloakLesbian: 2
ClothingNeckCloakPan: 2
ClothingNeckCloakTrans: 2
ClothingHeadHatXmasCrown: 2
BedsheetRainbow: 2
ClothingNeckHeadphones: 2
ClothingHeadHatFlowerWreath: 2
ClothingUniformColorRainbow: 2
ClothingUnderSocksCoder: 2
ClothingUnderSocksBee: 2

View File

@@ -0,0 +1,13 @@
- type: vendingMachineInventory
id: SmiteInventory
startingInventory:
DrinkLemonLimeCan: 4
DrinkLemonLimeCranberryCan: 2
DrinkColaCan: 2
DrinkSolDryCan: 2
contrabandInventory:
ToyHammer: 1
DrinkStarkistCan: 2
emaggedInventory:
DrinkNukieCan: 2
DrinkChangelingStingCan: 2

View File

@@ -88,6 +88,12 @@
prefix: advertisement-gibb-
count: 8
- type: localizedDataset
id: SmiteAds
values:
prefix: advertisement-smite-
count: 8
- type: localizedDataset
id: CondimentVendAds
values:
@@ -279,3 +285,9 @@
values:
prefix: advertisement-medibot-
count: 17
- type: localizedDataset
id: PrideDrobeAds
values:
prefix: advertisement-pride-
count: 4

View File

@@ -46,6 +46,12 @@
prefix: thankyou-gibb-
count: 4
- type: localizedDataset
id: SmiteGoodbyes
values:
prefix: thankyou-smite-
count: 4
- type: localizedDataset
id: DiscountDansGoodbyes
values:
@@ -111,3 +117,9 @@
values:
prefix: thankyou-syndiedrobe-
count: 5
- type: localizedDataset
id: PrideDrobeGoodbyes
values:
prefix: thankyou-pride-
count: 3

View File

@@ -319,8 +319,7 @@
unequipDelay: 3
- type: IngestionBlocker
- type: AddAccentClothing
accent: ReplacementAccent
replacement: mumble
accent: MumbleAccent
- type: Construction
graph: Muzzle
node: muzzle

View File

@@ -111,6 +111,17 @@
- type: Clothing
equippedPrefix: pan
- type: entity
parent: ClothingNeckPinBase
id: ClothingNeckOmnisexualPin
name: omnisexual pin
description: Be omni do crime.
components:
- type: Sprite
state: omni
- type: Clothing
equippedPrefix: omni
- type: entity
parent: ClothingNeckPinBase
id: ClothingNeckTransPin
@@ -121,7 +132,7 @@
state: trans
- type: Clothing
equippedPrefix: trans
- type: entity
parent: ClothingNeckPinBase
id: ClothingNeckAutismPin

View File

@@ -22,7 +22,7 @@
- AnomalyFlora
- AnomalyShadow
- AnomalyTech
- AnomalySanta #Remove in 2025
#- AnomalySanta
rareChance: 0.3
rarePrototypes:
- RandomAnomalyInjectorSpawner
@@ -67,6 +67,6 @@
- AnomalyTrapGravity
- AnomalyTrapTech
- AnomalyTrapRock
- AnomalyTrapSanta # Remove in 2025
#- AnomalyTrapSanta
chance: 1

View File

@@ -3,26 +3,26 @@
id: CrateEmptySpawner
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/generic.rsi
state: icon
- type: RandomSpawner
prototypes:
- CrateGenericSteel
- CratePlastic
- CrateFreezer
- CrateHydroponics
- CrateMedical
- CrateRadiation
- CrateInternals
- CrateElectrical
- CrateEngineering
- CrateScience
- CrateSurgery
chance: 0.7
offset: 0.0
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/generic.rsi
state: icon
- type: RandomSpawner
prototypes:
- CrateGenericSteel
- CratePlastic
- CrateFreezer
- CrateHydroponics
- CrateMedical
- CrateRadiation
- CrateInternals
- CrateElectrical
- CrateEngineering
- CrateScience
- CrateSurgery
chance: 0.7
offset: 0.0
- type: entity
name: Filled Crate Spawner
@@ -30,109 +30,112 @@
suffix: Low Value
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/o2.rsi
state: icon
- type: RandomSpawner
prototypes:
- CrateServiceReplacementLights
- CrateServiceBureaucracy
- CrateChemistrySupplies
- CrateMaterialGlass
- CrateMaterialSteel
- CrateMaterialPlastic
- CrateMaterialWood
- CrateMaterialPlasteel
- CrateFunArtSupplies
- CrateEngineeringCableLV
- CrateEngineeringCableMV
- CrateEngineeringCableHV
- CrateEngineeringCableBulk
- CrateEmergencyFire
- CrateEmergencyInternals
- CrateEmergencyInflatablewall
- CrateHydroponicsTools
- CrateHydroponicsSeeds
chance: 0.7
rarePrototypes:
- CrateMaterialPlasma
- CrateHydroponicsSeedsExotic
rareChance: 0.1
offset: 0.0
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/o2.rsi
state: icon
- type: RandomSpawner
prototypes:
- CrateServiceReplacementLights
- CrateServiceBureaucracy
- CrateChemistrySupplies
- CrateMaterialGlass
- CrateMaterialSteel
- CrateMaterialPlastic
- CrateMaterialWood
- CrateMaterialPlasteel
- CrateMaterialRandom
- CrateFunArtSupplies
- CrateEngineeringCableLV
- CrateEngineeringCableMV
- CrateEngineeringCableHV
- CrateEngineeringCableBulk
- CrateTechBoardRandom
- CrateEmergencyFire
- CrateEmergencyInternals
- CrateEmergencyInflatablewall
- CrateHydroponicsTools
- CrateHydroponicsSeeds
- PetCarrier
chance: 0.7
rarePrototypes:
- CrateMaterialPlasma
- CrateHydroponicsSeedsExotic
rareChance: 0.1
offset: 0.0
- type: entity
name: random engineering crate spawner
id: LootSpawnerRandomCrateEngineering
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/engineering.rsi
state: icon
- type: RandomSpawner
rarePrototypes:
- CrateEngineeringSingularityGenerator
- CrateEngineeringTeslaGenerator
- CrateEngineeringTeslaGroundingRod
- CrateEngineeringParticleAccelerator
- CrateRCD
- CrateEngineeringGear
rareChance: 0.2
prototypes:
- CrateEngineering
- CrateElectrical
- CrateEngineeringElectricalSupplies
- CrateRCDAmmo
- CrateEngineeringCableLV
- CrateEngineeringCableMV
- CrateEngineeringCableHV
- CrateEngineeringCableBulk
- CrateEngineeringSingularityContainment
- CrateEngineeringSingularityCollector
- CrateEngineeringTeslaCoil
- CrateEngineeringSingularityEmitter
- CrateEngineeringGyroscope
- CrateEngineeringThruster
- CrateEngineeringToolbox
- CrateEngineeringShuttle
- CrateEngineeringSolar
- CrateEngineeringJetpack
- CrateEmergencyRadiation
- CrateRadiation
chance: 0.9
offset: 0.0
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/engineering.rsi
state: icon
- type: RandomSpawner
rarePrototypes:
- CrateEngineeringSingularityGenerator
- CrateEngineeringTeslaGenerator
- CrateEngineeringTeslaGroundingRod
- CrateEngineeringParticleAccelerator
- CrateRCD
- CrateEngineeringGear
rareChance: 0.2
prototypes:
- CrateEngineering
- CrateElectrical
- CrateEngineeringElectricalSupplies
- CrateRCDAmmo
- CrateEngineeringCableLV
- CrateEngineeringCableMV
- CrateEngineeringCableHV
- CrateEngineeringCableBulk
- CrateEngineeringSingularityContainment
- CrateEngineeringSingularityCollector
- CrateEngineeringTeslaCoil
- CrateEngineeringSingularityEmitter
- CrateEngineeringGyroscope
- CrateEngineeringThruster
- CrateEngineeringToolbox
- CrateEngineeringShuttle
- CrateEngineeringSolar
- CrateEngineeringJetpack
- CrateEmergencyRadiation
- CrateRadiation
chance: 0.9
offset: 0.0
- type: entity
name: random security crate spawner
id: LootSpawnerRandomCrateSecurity
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/sec_gear.rsi
state: icon
- type: RandomSpawner
rarePrototypes: #Very useful stuff we probably don't want random people getting on space ruins often, even if there are hurdles to open it
- CrateArmoryShotgun
- CrateArmorySMG
- CrateSecurityRiot
- CrateSecurityNonlethal
rareChance: 0.1
prototypes:
- CrateWeaponSecure
- CrateArmoryLaser
- CrateArmoryPistols
- CrateTrainingBombs
- CrateTrackingImplants
- CrateSecurityTrackingMindshieldImplants
- CrateSecurityHelmet
- CrateSecurityArmor
- CrateRestraints
- CrateEmergencyExplosive
- CrateSecurityBiosuit
chance: 0.9
offset: 0.0
- type: Sprite
layers:
- state: red
- sprite: Structures/Storage/Crates/sec_gear.rsi
state: icon
- type: RandomSpawner
rarePrototypes: #Very useful stuff we probably don't want random people getting on space ruins often, even if there are hurdles to open it
- CrateArmoryShotgun
- CrateArmorySMG
- CrateSecurityRiot
- CrateSecurityNonlethal
rareChance: 0.1
prototypes:
- CrateWeaponSecure
- CrateArmoryLaser
- CrateArmoryPistols
- CrateTrainingBombs
- CrateTrackingImplants
- CrateSecurityTrackingMindshieldImplants
- CrateSecurityHelmet
- CrateSecurityArmor
- CrateRestraints
- CrateEmergencyExplosive
- CrateSecurityBiosuit
chance: 0.9
offset: 0.0

View File

@@ -149,6 +149,7 @@
- id: ClothingNeckLesbianPin
- id: ClothingNeckNonBinaryPin
- id: ClothingNeckPansexualPin
- id: ClothingNeckOmnisexualPin
- id: ClothingNeckTransPin
- id: ClothingNeckAutismPin
- id: ClothingNeckGoldAutismPin
@@ -393,3 +394,32 @@
- Spaceshroom
chance: 0.6
offset: 0.0
- type: entityTable
id: InsulsTable
table: !type:GroupSelector
children:
- id: ClothingHandsGlovesColorYellowBudget # budget insuls
weight: 85
- id: ClothingHandsGlovesColorYellow # true insuls
weight: 10
- id: ClothingHandsGlovesFingerlessInsulated # fingerless
weight: 4
- id: ClothingHandsGlovesConducting # conducting
weight: 1
- type: entity
name: Maint Loot Spawner
id: MaintenanceInsulsSpawner
suffix: Insuls, safe
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Clothing/Hands/Gloves/Color/yellow.rsi
state: icon
- type: EntityTableSpawner
table: !type:NestedSelector
tableId: InsulsTable

View File

@@ -6,29 +6,59 @@
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Machines/VendingMachines/random.rsi
state: any
- state: red
- sprite: Structures/Machines/VendingMachines/random.rsi
state: any
- type: RandomSpawner
prototypes:
- VendingMachineCigs
- VendingMachineCoffee
- VendingMachineCola
- VendingMachineColaRed
- VendingMachineColaBlack
- VendingMachineDiscount
- VendingMachineSnack
- VendingMachineSnackBlue
- VendingMachineSnackGreen
- VendingMachineSnackOrange
- VendingMachineSnackTeal
- VendingMachineSovietSoda
- VendingMachineChang
- VendingMachineDonut
- VendingMachineShamblersJuice
- VendingMachinePwrGame
- VendingMachineDrGibb
- VendingMachineSoda
- VendingMachineStarkist
- VendingMachineSpaceUp
- VendingMachineChang
- VendingMachineCigs
- VendingMachineCoffee
- VendingMachineCola #Robust Sofdrinks
- VendingMachineColaBlack #Robust Sofdrinks [Black]
- VendingMachineColaRed #Space Cola
- VendingMachineDiscount
- VendingMachineDonut
- VendingMachineDrGibb
- VendingMachinePwrGame
- VendingMachineShamblersJuice
- VendingMachineSmite
- VendingMachineSnack
- VendingMachineSnackBlue
- VendingMachineSnackGreen
- VendingMachineSnackOrange
- VendingMachineSnackTeal
- VendingMachineSoda #Robust Sofdrinks [Soda]
- VendingMachineSovietSoda #Boda
- VendingMachineSpaceUp
- VendingMachineStarkist
chance: 1
- type: entityTable
id: ClothingVendorTable
table: !type:GroupSelector
children:
- id: VendingMachineClothing
weight: 40
- id: VendingMachineWinter
weight: 40
- id: VendingMachinePride
weight: 10
- id: VendingMachineTheater
weight: 10
- type: entity
id: RandomVendingClothing
name: random vending machine spawner
suffix: Clothing
parent: MarkerBase
components:
- type: Sprite
layers:
- state: red
- sprite: Structures/Machines/VendingMachines/random.rsi
state: clothing
- type: EntityTableSpawner
table: !type:NestedSelector
tableId: ClothingVendorTable

View File

@@ -12,14 +12,15 @@
- type: RandomSpawner
prototypes:
- VendingMachineCoffee
- VendingMachineCola
- VendingMachineColaRed
- VendingMachineColaBlack
- VendingMachineSovietSoda
- VendingMachineShamblersJuice
- VendingMachinePwrGame
- VendingMachineCola #Robust Sofdrinks
- VendingMachineColaBlack #Robust Sofdrinks [Black]
- VendingMachineColaRed #Space Cola
- VendingMachineDrGibb
- VendingMachineSoda
- VendingMachineStarkist
- VendingMachinePwrGame
- VendingMachineShamblersJuice
- VendingMachineSmite
- VendingMachineSoda #Robust Sofdrinks [Soda]
- VendingMachineSovietSoda #Boda
- VendingMachineSpaceUp
- VendingMachineStarkist
chance: 1

View File

@@ -1567,7 +1567,7 @@
- type: MobThresholds
thresholds:
0: Alive
75: Critical
100: Critical
200: Dead
- type: NpcFactionMember
factions:

View File

@@ -362,11 +362,35 @@
components:
- type: Pda
id: MimeIDCard
idSlot: # rewrite without sound because mime
name: ID Card
paiSlot:
priority: -2
ejectSound: null
insertSound: null
whitelist:
components:
- PAI
idSlot:
name: access-id-card-component-default
ejectSound: null # mime is silent
insertSound: null
whitelist:
components:
- IdCard
penSlot:
startingItem: Pen
priority: -1
whitelist:
tags:
- Write
ejectSound: null
insertSound: null
- type: CartridgeLoader
cartridgeSlot:
ejectSound: null
insertSound: null
whitelist:
components:
- Cartridge
- type: Appearance
appearanceDataInit:
enum.PdaVisuals.PdaType:

View File

@@ -9,7 +9,7 @@
- type: SwappableInstrument
instrumentList:
"Clean": {27: 0}
"Jazz": {25: 0}
"Jazz": {26: 0}
"Muted": {28: 0}
- type: Sprite
sprite: Objects/Fun/Instruments/eguitar.rsi

View File

@@ -63,4 +63,9 @@
- type: ItemSlots
- type: Item
size: Ginormous
sprite: Objects/Storage/petcarrier.rsi
sprite: Objects/Storage/petcarrier.rsi
- type: Construction
graph: PetCarrier
node: petCarrier
containers:
- entity_storage

View File

@@ -77,6 +77,7 @@
- /Maps/Corvax/Ruins/corvax_ussp_debris.yml
- /Maps/Corvax/Ruins/corvax_ussp_asteroid.yml
# Corvax-Mapping-End
- /Maps/Ruins/wrecklaimer.yml
vgroid: !type:DungeonSpawnGroup
minimumDistance: 300
maximumDistance: 350

View File

@@ -452,7 +452,6 @@
- SodaDispenserMachineCircuitboard
- SpaceHeaterMachineCircuitBoard
- CutterMachineCircuitboard
- StationAnchorCircuitboard
- SalvageMagnetMachineCircuitboard
dynamicRecipes:
- ThermomachineFreezerMachineCircuitBoard
@@ -1086,6 +1085,25 @@
- CarpetPurple
- CarpetCyan
- CarpetWhite
# Bedsheets
- BedsheetBlack
- BedsheetBlue
- BedsheetBrown
- BedsheetGreen
- BedsheetGrey
- BedsheetOrange
- BedsheetPurple
- BedsheetRed
- BedsheetWhite
- BedsheetYellow
- BedsheetClown
- BedsheetCosmos
- BedsheetIan
- BedsheetMedical
- BedsheetMime
- BedsheetNT
- BedsheetRainbow
- BedsheetBrigmedic
# Corvax-Clothing-Start
- ClothingHeadHatCapHoS
- ClothingHeadHatBeretSecurityMedic
@@ -1101,6 +1119,7 @@
# Corvax-Clothing-End
- type: EmagLatheRecipes
emagStaticRecipes:
# Clothing
- ClothingHeadHatCentcomcap
- ClothingHeadHatCentcom
- ClothingUniformJumpsuitCentcomAgent
@@ -1123,6 +1142,8 @@
- ClothingOuterWinterCentcom
- ClothingOuterWinterSyndie
- ClothingOuterWinterSyndieCap
# Bedsheets
- BedsheetSyndie
- type: MaterialStorage
whitelist:
tags:

View File

@@ -137,7 +137,6 @@
pack: CondimentVendAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Transform
noRot: false
@@ -156,7 +155,6 @@
pack: AmmoVendAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Corvax/Structures/Machines/VendingMachines/ammo.rsi
layers:
@@ -185,7 +183,6 @@
pack: BoozeOMatAds
- type: SpeakOnUIClosed
pack: BoozeOMatGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/boozeomat.rsi
layers:
@@ -220,7 +217,6 @@
pack: BruiseOMatAds
- type: SpeakOnUIClosed
pack: BruiseOMatGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/bruiseomat.rsi
layers:
@@ -320,7 +316,6 @@
pack: CigaretteMachineAds
- type: SpeakOnUIClosed
pack: CigaretteMachineGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/cigs.rsi
layers:
@@ -348,7 +343,6 @@
pack: ClothesMateAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/clothing.rsi
layers:
@@ -380,7 +374,6 @@
pack: ClothesMateAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/winterdrobe.rsi
layers:
@@ -419,7 +412,6 @@
pack: HotDrinksMachineAds
- type: SpeakOnUIClosed
pack: HotDrinksMachineGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/coffee.rsi
layers:
@@ -459,7 +451,6 @@
pack: RobustSoftdrinksAds
- type: SpeakOnUIClosed
pack: RobustSoftdrinksGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/cola.rsi
layers:
@@ -603,7 +594,6 @@
initialStockQuality: 0.33
- type: Advertise
pack: RobustSoftdrinksAds
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/shamblersjuice.rsi
layers:
@@ -640,7 +630,6 @@
pack: RobustSoftdrinksAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/pwrgame.rsi
layers:
@@ -677,7 +666,6 @@
pack: DrGibbAds
- type: SpeakOnUIClosed
pack: DrGibbGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/gib.rsi
layers:
@@ -693,6 +681,42 @@
energy: 1.6
color: "#D82929"
- type: entity
parent: VendingMachine
id: VendingMachineSmite
name: Smite Vendor
description: Popular with the administration.
components:
- type: Sprite
sprite: Structures/Machines/VendingMachines/smite.rsi
layers:
- state: "off"
map: [ "enum.VendingMachineVisualLayers.Base" ]
- state: "off"
map: [ "enum.VendingMachineVisualLayers.BaseUnshaded" ]
shader: unshaded
- state: panel
map: [ "enum.WiresVisualLayers.MaintenancePanel" ]
- type: VendingMachine
pack: SmiteInventory
dispenseOnHitChance: 0.25
dispenseOnHitThreshold: 2
offState: off
brokenState: broken
normalState: normal-unshaded
ejectState: eject-unshaded
denyState: deny-unshaded
ejectDelay: 1.9
initialStockQuality: 0.33
- type: Advertise
pack: SmiteAds
- type: SpeakOnUIClosed
pack: SmiteGoodbyes
- type: PointLight
radius: 1.5
energy: 1.6
color: "#00E645"
- type: entity
parent: VendingMachine
id: VendingMachineDinnerware
@@ -774,7 +798,6 @@
pack: DiscountDansAds
- type: SpeakOnUIClosed
pack: DiscountDansGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/discount.rsi
layers:
@@ -991,7 +1014,6 @@
pack: GetmoreChocolateCorpAds
- type: SpeakOnUIClosed
pack: GetmoreChocolateCorpGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/snack.rsi
layers:
@@ -1137,7 +1159,6 @@
pack: BodaAds
- type: SpeakOnUIClosed
pack: BodaGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/sovietsoda.rsi
layers:
@@ -1171,7 +1192,6 @@
pack: AutoDrobeAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/theater.rsi
layers:
@@ -1207,7 +1227,6 @@
pack: VendomatAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/vendomat.rsi
layers:
@@ -1240,7 +1259,6 @@
pack: VendomatAds
- type: SpeakOnUIClosed
pack: GenericVendGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/robotics.rsi
layers:
@@ -1339,7 +1357,6 @@
pack: ChangAds
- type: SpeakOnUIClosed
pack: ChangGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/changs.rsi
layers:
@@ -1405,7 +1422,6 @@
pack: DonutAds
- type: SpeakOnUIClosed
pack: DonutGoodbyes
- type: Speech
- type: Sprite
sprite: Structures/Machines/VendingMachines/donut.rsi
layers:
@@ -2102,6 +2118,39 @@
- type: AccessReader
access: [["Kitchen"], ["Theatre"]]
# Pride Vending Machine
- type: entity
parent: VendingMachine
id: VendingMachinePride
name: Pride-O-Mat
description: A vending machine containing pride.
components:
- type: VendingMachine
pack: PrideDrobeInventory
offState: off
brokenState: broken
normalState: normal-unshaded
- type: Advertise
pack: PrideDrobeAds
- type: SpeakOnUIClosed
pack: PrideDrobeGoodbyes
- type: Speech
- type: PointLight
radius: 1.5
energy: 1.3 # reduced energy since the color is pure white
color: "#FFFFFF"
- type: Sprite
sprite: Structures/Machines/VendingMachines/pride.rsi
layers:
- state: "off"
map: ["enum.VendingMachineVisualLayers.Base"]
- state: "off"
map: ["enum.VendingMachineVisualLayers.BaseUnshaded"]
shader: unshaded
- state: panel
map: ["enum.WiresVisualLayers.MaintenancePanel"]
# Gas Tank Dispenser
- type: entity

View File

@@ -28,9 +28,9 @@
radius: 0.35
density: 50
mask:
- MobMask
- FlyingMobMask
layer:
- MobLayer
- FlyingMobLayer
- type: Sprite
noRot: true
drawdepth: Effects #it needs to draw over stuff.

View File

@@ -154,6 +154,12 @@
back:
- ClothingNeckPansexualPin
- type: loadout
id: ClothingNeckOmnisexualPin
storage:
back:
- ClothingNeckOmnisexualPin
- type: loadout
id: ClothingNeckTransPin
storage:

View File

@@ -28,6 +28,7 @@
- ClothingNeckLesbianPin
- ClothingNeckNonBinaryPin
- ClothingNeckPansexualPin
- ClothingNeckOmnisexualPin
- ClothingNeckTransPin
- ClothingNeckAutismPin
- ClothingNeckGoldAutismPin

View File

@@ -15,5 +15,6 @@
- Oasis
- Omega
- Packed
- Plasma
- Reach
#- Train

View File

@@ -29,6 +29,7 @@
Chaplain: [ 1, 1 ]
Librarian: [ 1, 1 ]
ServiceWorker: [ 2, 2 ]
Reporter: [ 1, 1 ]
#engineering
ChiefEngineer: [ 1, 1 ]
AtmosphericTechnician: [ 3, 3 ]

View File

@@ -0,0 +1,66 @@
- type: gameMap
id: Plasma
mapName: 'Plasma'
mapPath: /Maps/plasma.yml
minPlayers: 20
maxPlayers: 60
stations:
Plasma:
stationProto: StandardNanotrasenStation
components:
- type: StationNameSetup
mapNameTemplate: '{0} Plasma {1}'
nameGenerator:
!type:NanotrasenNameGenerator
prefixCreator: '14'
- type: StationEmergencyShuttle
emergencyShuttlePath: /Maps/Shuttles/emergency_plasma.yml
- type: StationCargoShuttle
path: /Maps/Shuttles/cargo_plasma.yml
- type: StationJobs
availableJobs:
#service
Captain: [ 1, 1 ]
HeadOfPersonnel: [ 1, 1 ]
Bartender: [ 2, 2 ]
Botanist: [ 2, 3 ]
Chef: [ 2, 2 ]
Janitor: [ 3, 3 ]
Chaplain: [ 1, 1 ]
Librarian: [ 1, 1 ]
ServiceWorker: [ 2, 2 ]
Reporter: [ 2, 3 ]
#engineering
ChiefEngineer: [ 1, 1 ]
AtmosphericTechnician: [ 4, 4 ]
StationEngineer: [ 4, 4 ]
TechnicalAssistant: [ 4, 4 ]
#medical
ChiefMedicalOfficer: [ 1, 1 ]
Chemist: [ 2, 2 ]
MedicalDoctor: [ 4, 4 ]
Paramedic: [ 2, 2 ]
MedicalIntern: [ 4, 4 ]
Psychologist: [ 1, 1 ]
#science
ResearchDirector: [ 1, 1 ]
Scientist: [ 4, 4 ]
ResearchAssistant: [ 4, 4 ]
StationAi: [ 1, 1 ]
Borg: [ 2, 4 ]
#security
HeadOfSecurity: [ 1, 1 ]
Warden: [ 1, 1 ]
SecurityOfficer: [ 6, 8 ]
Detective: [ 1, 2 ]
SecurityCadet: [ 4, 4 ]
Lawyer: [ 1, 2 ]
#supply
Quartermaster: [ 1, 1 ]
SalvageSpecialist: [ 4, 4 ]
CargoTechnician: [ 4, 6 ]
#civilian
Passenger: [ -1, -1 ]
Clown: [ 1, 1 ]
Mime: [ 1, 1 ]
Musician: [ 1, 1 ]

View File

@@ -0,0 +1,16 @@
- type: constructionGraph
id: PetCarrier
start: start
graph:
- node: start
edges:
- to: petCarrier
steps:
- material: Plastic
amount: 5
doAfter: 7
- material: MetalRod
amount: 4
doAfter: 3
- node: petCarrier
entity: PetCarrier

View File

@@ -227,3 +227,16 @@
icon:
sprite: Objects/Tools/rolling_pin.rsi
state: icon
- type: construction
name: pet carrier
id: PetCarrier
graph: PetCarrier
startNode: start
targetNode: petCarrier
category: construction-category-misc
objectType: Item
description: Allows large animals to be carried comfortably.
icon:
sprite: Objects/Storage/petcarrier.rsi
state: icon

View File

@@ -0,0 +1,113 @@
- type: latheRecipe
abstract: true
id: BaseBedsheetRecipe
completetime: 2
materials:
Cloth: 150
- type: latheRecipe
abstract: true
parent: BaseBedsheetRecipe
id: BaseSpecifiedBedsheetRecipe
materials:
Cloth: 150
Durathread: 50
#Base bedsheets
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetBlack
result: BedsheetBlack
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetBlue
result: BedsheetBlue
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetBrown
result: BedsheetBrown
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetGreen
result: BedsheetGreen
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetGrey
result: BedsheetGrey
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetOrange
result: BedsheetOrange
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetPurple
result: BedsheetPurple
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetRed
result: BedsheetRed
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetWhite
result: BedsheetWhite
- type: latheRecipe
parent: BaseBedsheetRecipe
id: BedsheetYellow
result: BedsheetYellow
#Specified bedsheets
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetClown
result: BedsheetClown
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetCosmos
result: BedsheetCosmos
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetIan #I'm not sure that that should be here
result: BedsheetIan
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetMedical
result: BedsheetMedical
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetMime
result: BedsheetMime
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetNT
result: BedsheetNT
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetRainbow
result: BedsheetRainbow
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetBrigmedic
result: BedsheetBrigmedic
- type: latheRecipe
parent: BaseSpecifiedBedsheetRecipe
id: BedsheetSyndie
result: BedsheetSyndie

View File

@@ -0,0 +1,51 @@
- type: latheRecipe
abstract: true
id: BaseCarpetRecipe
completetime: 1
materials:
Cloth: 100
- type: latheRecipe
parent: BaseCarpetRecipe
id: Carpet
result: FloorCarpetItemRed
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetBlack
result: FloorCarpetItemBlack
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetPink
result: FloorCarpetItemPink
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetBlue
result: FloorCarpetItemBlue
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetGreen
result: FloorCarpetItemGreen
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetOrange
result: FloorCarpetItemOrange
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetPurple
result: FloorCarpetItemPurple
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetCyan
result: FloorCarpetItemCyan
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetWhite
result: FloorCarpetItemWhite

View File

@@ -38,13 +38,6 @@
materials:
Cloth: 100
- type: latheRecipe
abstract: true
id: BaseCarpetRecipe
completetime: 1
materials:
Cloth: 100
- type: latheRecipe
abstract: true
parent: BaseHatRecipe
@@ -916,49 +909,3 @@
parent: BaseNeckClothingRecipe
id: ClothingNeckScarfStripedPurple
result: ClothingNeckScarfStripedPurple
# Carpets
- type: latheRecipe
parent: BaseCarpetRecipe
id: Carpet
result: FloorCarpetItemRed
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetBlack
result: FloorCarpetItemBlack
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetPink
result: FloorCarpetItemPink
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetBlue
result: FloorCarpetItemBlue
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetGreen
result: FloorCarpetItemGreen
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetOrange
result: FloorCarpetItemOrange
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetPurple
result: FloorCarpetItemPurple
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetCyan
result: FloorCarpetItemCyan
- type: latheRecipe
parent: BaseCarpetRecipe
id: CarpetWhite
result: FloorCarpetItemWhite

View File

@@ -584,12 +584,6 @@
result: ShuttleGunDusterCircuitboard
completetime: 12
- type: latheRecipe
parent: BaseGoldCircuitboardRecipe
id: StationAnchorCircuitboard
result: StationAnchorCircuitboard
completetime: 8
- type: latheRecipe
parent: BaseGoldCircuitboardRecipe
id: ReagentGrinderIndustrialMachineCircuitboard

View File

@@ -13,6 +13,6 @@
id: ThiefGear
storage:
back:
- ThiefBeacon
- ToolboxThief
- ClothingHandsChameleonThief
- ThiefBeacon

View File

@@ -368,7 +368,8 @@
storage:
back:
- Hypospray
- MedkitAdvancedFilled
- MedkitCombatFilled
- MedkitCombatFilled
- CrowbarRed
- OmnizineChemistryBottle
- EpinephrineChemistryBottle
@@ -391,7 +392,8 @@
storage:
back:
- Hypospray
- MedkitAdvancedFilled
- MedkitCombatFilled
- MedkitCombatFilled
- CrowbarRed
- OmnizineChemistryBottle
- EpinephrineChemistryBottle

View File

@@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "PixelTK leaves his mark on upstream, BackeTako made the gay, autism pins by Terraspark",
"copyright": "PixelTK leaves his mark on upstream, BackeTako made the gay, autism pins by Terraspark, omnisexual pin by juliangiebel",
"size": {
"x": 32,
"y": 32
@@ -90,6 +90,13 @@
{
"name": "trans-equipped-NECK",
"directions": 4
},
{
"name": "omni"
},
{
"name": "omni-equipped-NECK",
"directions": 4
}
]
}

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