Merge pull request #595 from crystallpunk-14/ed-20-11-2024-upstream-sync

Upstream sync
This commit is contained in:
Ed
2024-11-23 13:44:10 +03:00
committed by GitHub
661 changed files with 33165 additions and 12823 deletions

View File

@@ -25,7 +25,7 @@ public static class BanPanelEuiStateMsg
{
public string? Player { get; set; }
public string? IpAddress { get; set; }
public byte[]? Hwid { get; set; }
public ImmutableTypedHwid? Hwid { get; set; }
public uint Minutes { get; set; }
public string Reason { get; set; }
public NoteSeverity Severity { get; set; }
@@ -34,7 +34,7 @@ public static class BanPanelEuiStateMsg
public bool UseLastHwid { get; set; }
public bool Erase { get; set; }
public CreateBanRequest(string? player, (IPAddress, int)? ipAddress, bool useLastIp, byte[]? hwid, bool useLastHwid, uint minutes, string reason, NoteSeverity severity, string[]? roles, bool erase)
public CreateBanRequest(string? player, (IPAddress, int)? ipAddress, bool useLastIp, ImmutableTypedHwid? hwid, bool useLastHwid, uint minutes, string reason, NoteSeverity severity, string[]? roles, bool erase)
{
Player = player;
IpAddress = ipAddress == null ? null : $"{ipAddress.Value.Item1}/{ipAddress.Value.Item2}";

View File

@@ -1,4 +1,5 @@
using Robust.Shared.GameStates;
using Robust.Shared.Serialization;
namespace Content.Shared.Alert;
@@ -6,12 +7,23 @@ namespace Content.Shared.Alert;
/// Handles the icons on the right side of the screen.
/// Should only be used for player-controlled entities.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
// Component is not AutoNetworked due to supporting clientside-only alerts.
// Component state is handled manually to avoid the server overwriting the client list.
[RegisterComponent, NetworkedComponent]
public sealed partial class AlertsComponent : Component
{
[ViewVariables]
[AutoNetworkedField]
public Dictionary<AlertKey, AlertState> Alerts = new();
public override bool SendOnlyToOwner => true;
}
[Serializable, NetSerializable]
public sealed class AlertComponentState : ComponentState
{
public Dictionary<AlertKey, AlertState> Alerts { get; }
public AlertComponentState(Dictionary<AlertKey, AlertState> alerts)
{
Alerts = alerts;
}
}

View File

@@ -0,0 +1,41 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Chat window opacity slider, controlling the alpha of the chat window background.
/// Goes from to 0 (completely transparent) to 1 (completely opaque)
/// </summary>
public static readonly CVarDef<float> ChatWindowOpacity =
CVarDef.Create("accessibility.chat_window_transparency", 0.85f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Toggle for visual effects that may potentially cause motion sickness.
/// Where reasonable, effects affected by this CVar should use an alternate effect.
/// Please do not use this CVar as a bandaid for effects that could otherwise be made accessible without issue.
/// </summary>
public static readonly CVarDef<bool> ReducedMotion =
CVarDef.Create("accessibility.reduced_motion", false, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<bool> ChatEnableColorName =
CVarDef.Create("accessibility.enable_color_name",
true,
CVar.CLIENTONLY | CVar.ARCHIVE,
"Toggles displaying names with individual colors.");
/// <summary>
/// Screen shake intensity slider, controlling the intensity of the CameraRecoilSystem.
/// Goes from 0 (no recoil at all) to 1 (regular amounts of recoil)
/// </summary>
public static readonly CVarDef<float> ScreenShakeIntensity =
CVarDef.Create("accessibility.screen_shake_intensity", 1f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// A generic toggle for various visual effects that are color sensitive.
/// As of 2/16/24, only applies to progress bar colors.
/// </summary>
public static readonly CVarDef<bool> AccessibilityColorblindFriendly =
CVarDef.Create("accessibility.colorblind_friendly", false, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -0,0 +1,39 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Ahelp rate limit values are accounted in periods of this size (seconds).
/// After the period has passed, the count resets.
/// </summary>
/// <seealso cref="AhelpRateLimitCount"/>
public static readonly CVarDef<float> AhelpRateLimitPeriod =
CVarDef.Create("ahelp.rate_limit_period", 2f, CVar.SERVERONLY);
/// <summary>
/// How many ahelp messages are allowed in a single rate limit period.
/// </summary>
/// <seealso cref="AhelpRateLimitPeriod"/>
public static readonly CVarDef<int> AhelpRateLimitCount =
CVarDef.Create("ahelp.rate_limit_count", 10, CVar.SERVERONLY);
/// <summary>
/// Should the administrator's position be displayed in ahelp.
/// If it is is false, only the admin's ckey will be displayed in the ahelp.
/// </summary>
/// <seealso cref="AdminUseCustomNamesAdminRank"/>
/// <seealso cref="AhelpAdminPrefixWebhook"/>
public static readonly CVarDef<bool> AhelpAdminPrefix =
CVarDef.Create("ahelp.admin_prefix", false, CVar.SERVERONLY);
/// <summary>
/// Should the administrator's position be displayed in the webhook.
/// If it is is false, only the admin's ckey will be displayed in webhook.
/// </summary>
/// <seealso cref="AdminUseCustomNamesAdminRank"/>
/// <seealso cref="AhelpAdminPrefix"/>
public static readonly CVarDef<bool> AhelpAdminPrefixWebhook =
CVarDef.Create("ahelp.admin_prefix_webhook", false, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,42 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Controls if admin logs are enabled. Highly recommended to shut this off for development.
/// </summary>
public static readonly CVarDef<bool> AdminLogsEnabled =
CVarDef.Create("adminlogs.enabled", true, CVar.SERVERONLY);
public static readonly CVarDef<float> AdminLogsQueueSendDelay =
CVarDef.Create("adminlogs.queue_send_delay_seconds", 5f, CVar.SERVERONLY);
/// <summary>
/// When to skip the waiting time to save in-round admin logs, if no admin logs are currently being saved
/// </summary>
public static readonly CVarDef<int> AdminLogsQueueMax =
CVarDef.Create("adminlogs.queue_max", 5000, CVar.SERVERONLY);
/// <summary>
/// When to skip the waiting time to save pre-round admin logs, if no admin logs are currently being saved
/// </summary>
public static readonly CVarDef<int> AdminLogsPreRoundQueueMax =
CVarDef.Create("adminlogs.pre_round_queue_max", 5000, CVar.SERVERONLY);
/// <summary>
/// When to start dropping logs
/// </summary>
public static readonly CVarDef<int> AdminLogsDropThreshold =
CVarDef.Create("adminlogs.drop_threshold", 20000, CVar.SERVERONLY);
/// <summary>
/// How many logs to send to the client at once
/// </summary>
public static readonly CVarDef<int> AdminLogsClientBatchSize =
CVarDef.Create("adminlogs.client_batch_size", 1000, CVar.SERVERONLY);
public static readonly CVarDef<string> AdminLogsServerName =
CVarDef.Create("adminlogs.server_name", "unknown", CVar.SERVERONLY);
}

View File

@@ -0,0 +1,18 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Time that players have to wait before rules can be accepted.
/// </summary>
public static readonly CVarDef<float> RulesWaitTime =
CVarDef.Create("rules.time", 45f, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Don't show rules to localhost/loopback interface.
/// </summary>
public static readonly CVarDef<bool> RulesExemptLocal =
CVarDef.Create("rules.exempt_local", true, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,163 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> AdminAnnounceLogin =
CVarDef.Create("admin.announce_login", true, CVar.SERVERONLY);
public static readonly CVarDef<bool> AdminAnnounceLogout =
CVarDef.Create("admin.announce_logout", true, CVar.SERVERONLY);
/// <summary>
/// The token used to authenticate with the admin API. Leave empty to disable the admin API. This is a secret! Do not share!
/// </summary>
public static readonly CVarDef<string> AdminApiToken =
CVarDef.Create("admin.api_token", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// Should users be able to see their own notes? Admins will be able to see and set notes regardless
/// </summary>
public static readonly CVarDef<bool> SeeOwnNotes =
CVarDef.Create("admin.see_own_notes", false, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Should the server play a quick sound to the active admins whenever a new player joins?
/// </summary>
public static readonly CVarDef<bool> AdminNewPlayerJoinSound =
CVarDef.Create("admin.new_player_join_sound", false, CVar.SERVERONLY);
/// <summary>
/// The amount of days before the note starts fading. It will slowly lose opacity until it reaches stale. Set to 0 to disable.
/// </summary>
public static readonly CVarDef<double> NoteFreshDays =
CVarDef.Create("admin.note_fresh_days", 91.31055, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// The amount of days before the note completely fades, and can only be seen by admins if they press "see more notes". Set to 0
/// if you want the note to immediately disappear without fading.
/// </summary>
public static readonly CVarDef<double> NoteStaleDays =
CVarDef.Create("admin.note_stale_days", 365.2422, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// How much time does the user have to wait in seconds before confirming that they saw an admin message?
/// </summary>
public static readonly CVarDef<float> MessageWaitTime =
CVarDef.Create("admin.message_wait_time", 3f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Default severity for role bans
/// </summary>
public static readonly CVarDef<string> RoleBanDefaultSeverity =
CVarDef.Create("admin.role_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Default severity for department bans
/// </summary>
public static readonly CVarDef<string> DepartmentBanDefaultSeverity =
CVarDef.Create("admin.department_ban_default_severity", "medium", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Default severity for server bans
/// </summary>
public static readonly CVarDef<string> ServerBanDefaultSeverity =
CVarDef.Create("admin.server_ban_default_severity", "High", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether a server ban will ban the player's ip by default.
/// </summary>
public static readonly CVarDef<bool> ServerBanIpBanDefault =
CVarDef.Create("admin.server_ban_ip_ban_default", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether a server ban will ban the player's hardware id by default.
/// </summary>
public static readonly CVarDef<bool> ServerBanHwidBanDefault =
CVarDef.Create("admin.server_ban_hwid_ban_default", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether to use details from last connection for ip/hwid in the BanPanel.
/// </summary>
public static readonly CVarDef<bool> ServerBanUseLastDetails =
CVarDef.Create("admin.server_ban_use_last_details", true, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether to erase a player's chat messages and their entity from the game when banned.
/// </summary>
public static readonly CVarDef<bool> ServerBanErasePlayer =
CVarDef.Create("admin.server_ban_erase_player", false, CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Minimum players sharing a connection required to create an alert. -1 to disable the alert.
/// </summary>
/// <remarks>
/// If you set this to 0 or 1 then it will alert on every connection, so probably don't do that.
/// </remarks>
public static readonly CVarDef<int> AdminAlertMinPlayersSharingConnection =
CVarDef.Create("admin.alert.min_players_sharing_connection", -1, CVar.SERVERONLY);
/// <summary>
/// Minimum explosion intensity to create an admin alert message. -1 to disable the alert.
/// </summary>
public static readonly CVarDef<int> AdminAlertExplosionMinIntensity =
CVarDef.Create("admin.alert.explosion_min_intensity", 60, CVar.SERVERONLY);
/// <summary>
/// Minimum particle accelerator strength to create an admin alert message.
/// </summary>
public static readonly CVarDef<int> AdminAlertParticleAcceleratorMinPowerState =
CVarDef.Create("admin.alert.particle_accelerator_min_power_state", 5, CVar.SERVERONLY); // strength 4
/// <summary>
/// Should the ban details in admin channel include PII? (IP, HWID, etc)
/// </summary>
public static readonly CVarDef<bool> AdminShowPIIOnBan =
CVarDef.Create("admin.show_pii_onban", false, CVar.SERVERONLY);
/// <summary>
/// If an admin joins a round by reading up or using the late join button, automatically
/// de-admin them.
/// </summary>
public static readonly CVarDef<bool> AdminDeadminOnJoin =
CVarDef.Create("admin.deadmin_on_join", false, CVar.SERVERONLY);
/// <summary>
/// Overrides the name the client sees in ahelps. Set empty to disable.
/// </summary>
public static readonly CVarDef<string> AdminAhelpOverrideClientName =
CVarDef.Create("admin.override_adminname_in_client_ahelp", string.Empty, CVar.SERVERONLY);
/// <summary>
/// The threshold of minutes to appear as a "new player" in the ahelp menu
/// If 0, appearing as a new player is disabled.
/// </summary>
public static readonly CVarDef<int> NewPlayerThreshold =
CVarDef.Create("admin.new_player_threshold", 0, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// How long an admin client can go without any input before being considered AFK.
/// </summary>
public static readonly CVarDef<float> AdminAfkTime =
CVarDef.Create("admin.afk_time", 600f, CVar.SERVERONLY);
/// <summary>
/// If true, admins are able to connect even if
/// <see cref="SoftMaxPlayers"/> would otherwise block regular players.
/// </summary>
public static readonly CVarDef<bool> AdminBypassMaxPlayers =
CVarDef.Create("admin.bypass_max_players", true, 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.
/// </summary>
/// <seealso cref="AhelpAdminPrefix"/>
/// <seealso cref="AhelpAdminPrefixWebhook"/>
public static readonly CVarDef<bool> AdminUseCustomNamesAdminRank =
CVarDef.Create("admin.use_custom_names_admin_rank", true, CVar.SERVERONLY);
public static readonly CVarDef<bool> BanHardwareIds =
CVarDef.Create("ban.hardware_ids", true, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,153 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Whether gas differences will move entities.
/// </summary>
public static readonly CVarDef<bool> SpaceWind =
CVarDef.Create("atmos.space_wind", false, CVar.SERVERONLY);
/// <summary>
/// Divisor from maxForce (pressureDifference * 2.25f) to force applied on objects.
/// </summary>
public static readonly CVarDef<float> SpaceWindPressureForceDivisorThrow =
CVarDef.Create("atmos.space_wind_pressure_force_divisor_throw", 15f, CVar.SERVERONLY);
/// <summary>
/// Divisor from maxForce (pressureDifference * 2.25f) to force applied on objects.
/// </summary>
public static readonly CVarDef<float> SpaceWindPressureForceDivisorPush =
CVarDef.Create("atmos.space_wind_pressure_force_divisor_push", 2500f, CVar.SERVERONLY);
/// <summary>
/// The maximum velocity (not force) that may be applied to an object by atmospheric pressure differences.
/// Useful to prevent clipping through objects.
/// </summary>
public static readonly CVarDef<float> SpaceWindMaxVelocity =
CVarDef.Create("atmos.space_wind_max_velocity", 30f, CVar.SERVERONLY);
/// <summary>
/// The maximum force that may be applied to an object by pushing (i.e. not throwing) atmospheric pressure differences.
/// A "throwing" atmospheric pressure difference ignores this limit, but not the max. velocity limit.
/// </summary>
public static readonly CVarDef<float> SpaceWindMaxPushForce =
CVarDef.Create("atmos.space_wind_max_push_force", 20f, CVar.SERVERONLY);
/// <summary>
/// Whether monstermos tile equalization is enabled.
/// </summary>
public static readonly CVarDef<bool> MonstermosEqualization =
CVarDef.Create("atmos.monstermos_equalization", true, CVar.SERVERONLY);
/// <summary>
/// Whether monstermos explosive depressurization is enabled.
/// Needs <see cref="MonstermosEqualization"/> to be enabled to work.
/// </summary>
public static readonly CVarDef<bool> MonstermosDepressurization =
CVarDef.Create("atmos.monstermos_depressurization", true, CVar.SERVERONLY);
/// <summary>
/// Whether monstermos explosive depressurization will rip tiles..
/// Needs <see cref="MonstermosEqualization"/> and <see cref="MonstermosDepressurization"/> to be enabled to work.
/// WARNING: This cvar causes MAJOR contrast issues, and usually tends to make any spaced scene look very cluttered.
/// This not only usually looks strange, but can also reduce playability for people with impaired vision. Please think twice before enabling this on your server.
/// Also looks weird on slow spacing for unrelated reasons. If you do want to enable this, you should probably turn on instaspacing.
/// </summary>
public static readonly CVarDef<bool> MonstermosRipTiles =
CVarDef.Create("atmos.monstermos_rip_tiles", false, CVar.SERVERONLY);
/// <summary>
/// Whether explosive depressurization will cause the grid to gain an impulse.
/// Needs <see cref="MonstermosEqualization"/> and <see cref="MonstermosDepressurization"/> to be enabled to work.
/// </summary>
public static readonly CVarDef<bool> AtmosGridImpulse =
CVarDef.Create("atmos.grid_impulse", false, CVar.SERVERONLY);
/// <summary>
/// What fraction of air from a spaced tile escapes every tick.
/// 1.0 for instant spacing, 0.2 means 20% of remaining air lost each time
/// </summary>
public static readonly CVarDef<float> AtmosSpacingEscapeRatio =
CVarDef.Create("atmos.mmos_spacing_speed", 0.15f, CVar.SERVERONLY);
/// <summary>
/// Minimum amount of air allowed on a spaced tile before it is reset to 0 immediately in kPa
/// Since the decay due to SpacingEscapeRatio follows a curve, it would never reach 0.0 exactly
/// unless we truncate it somewhere.
/// </summary>
public static readonly CVarDef<float> AtmosSpacingMinGas =
CVarDef.Create("atmos.mmos_min_gas", 2.0f, CVar.SERVERONLY);
/// <summary>
/// How much wind can go through a single tile before that tile doesn't depressurize itself
/// (I.e spacing is limited in large rooms heading into smaller spaces)
/// </summary>
public static readonly CVarDef<float> AtmosSpacingMaxWind =
CVarDef.Create("atmos.mmos_max_wind", 500f, CVar.SERVERONLY);
/// <summary>
/// Whether atmos superconduction is enabled.
/// </summary>
/// <remarks> Disabled by default, superconduction is awful. </remarks>
public static readonly CVarDef<bool> Superconduction =
CVarDef.Create("atmos.superconduction", false, CVar.SERVERONLY);
/// <summary>
/// Heat loss per tile due to radiation at 20 degC, in W.
/// </summary>
public static readonly CVarDef<float> SuperconductionTileLoss =
CVarDef.Create("atmos.superconduction_tile_loss", 30f, CVar.SERVERONLY);
/// <summary>
/// Whether excited groups will be processed and created.
/// </summary>
public static readonly CVarDef<bool> ExcitedGroups =
CVarDef.Create("atmos.excited_groups", true, CVar.SERVERONLY);
/// <summary>
/// Whether all tiles in an excited group will clear themselves once being exposed to space.
/// Similar to <see cref="MonstermosDepressurization"/>, without none of the tile ripping or
/// things being thrown around very violently.
/// Needs <see cref="ExcitedGroups"/> to be enabled to work.
/// </summary>
public static readonly CVarDef<bool> ExcitedGroupsSpaceIsAllConsuming =
CVarDef.Create("atmos.excited_groups_space_is_all_consuming", false, CVar.SERVERONLY);
/// <summary>
/// Maximum time in milliseconds that atmos can take processing.
/// </summary>
public static readonly CVarDef<float> AtmosMaxProcessTime =
CVarDef.Create("atmos.max_process_time", 3f, CVar.SERVERONLY);
/// <summary>
/// Atmos tickrate in TPS. Atmos processing will happen every 1/TPS seconds.
/// </summary>
public static readonly CVarDef<float> AtmosTickRate =
CVarDef.Create("atmos.tickrate", 15f, CVar.SERVERONLY);
/// <summary>
/// Scale factor for how fast things happen in our atmosphere
/// simulation compared to real life. 1x means pumps run at 1x
/// speed. Players typically expect things to happen faster
/// in-game.
/// </summary>
public static readonly CVarDef<float> AtmosSpeedup =
CVarDef.Create("atmos.speedup", 8f, CVar.SERVERONLY);
/// <summary>
/// Like atmos.speedup, but only for gas and reaction heat values. 64x means
/// gases heat up and cool down 64x faster than real life.
/// </summary>
public static readonly CVarDef<float> AtmosHeatScale =
CVarDef.Create("atmos.heat_scale", 8f, CVar.SERVERONLY);
/// <summary>
/// Maximum explosion radius for explosions caused by bursting a gas tank ("max caps").
/// Setting this to zero disables the explosion but still allows the tank to burst and leak.
/// </summary>
public static readonly CVarDef<float> AtmosTankFragment =
CVarDef.Create("atmos.max_explosion_range", 26f, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,61 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// How long we'll wait until re-sampling nearby objects for ambience. Should be pretty fast, but doesn't have to match the tick rate.
/// </summary>
public static readonly CVarDef<float> AmbientCooldown =
CVarDef.Create("ambience.cooldown", 0.1f, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// How large of a range to sample for ambience.
/// </summary>
public static readonly CVarDef<float> AmbientRange =
CVarDef.Create("ambience.range", 8f, CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Maximum simultaneous ambient sounds.
/// </summary>
public static readonly CVarDef<int> MaxAmbientSources =
CVarDef.Create("ambience.max_sounds", 16, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// The minimum value the user can set for ambience.max_sounds
/// </summary>
public static readonly CVarDef<int> MinMaxAmbientSourcesConfigured =
CVarDef.Create("ambience.min_max_sounds_configured", 16, CVar.REPLICATED | CVar.SERVER | CVar.CHEAT);
/// <summary>
/// The maximum value the user can set for ambience.max_sounds
/// </summary>
public static readonly CVarDef<int> MaxMaxAmbientSourcesConfigured =
CVarDef.Create("ambience.max_max_sounds_configured", 64, CVar.REPLICATED | CVar.SERVER | CVar.CHEAT);
/// <summary>
/// Ambience volume.
/// </summary>
public static readonly CVarDef<float> AmbienceVolume =
CVarDef.Create("ambience.volume", 1.5f, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// Ambience music volume.
/// </summary>
public static readonly CVarDef<float> AmbientMusicVolume =
CVarDef.Create("ambience.music_volume", 1.5f, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// Lobby / round end music volume.
/// </summary>
public static readonly CVarDef<float> LobbyMusicVolume =
CVarDef.Create("ambience.lobby_music_volume", 0.50f, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// UI volume.
/// </summary>
public static readonly CVarDef<float> InterfaceVolume =
CVarDef.Create("audio.interface_volume", 0.50f, CVar.ARCHIVE | CVar.CLIENTONLY);
}

View File

@@ -0,0 +1,26 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> LoocEnabled =
CVarDef.Create("looc.enabled", true, CVar.NOTIFY | CVar.REPLICATED);
public static readonly CVarDef<bool> AdminLoocEnabled =
CVarDef.Create("looc.enabled_admin", true, CVar.NOTIFY);
/// <summary>
/// True: Dead players can use LOOC
/// False: Dead player LOOC gets redirected to dead chat
/// </summary>
public static readonly CVarDef<bool> DeadLoocEnabled =
CVarDef.Create("looc.enabled_dead", false, CVar.NOTIFY | CVar.REPLICATED);
/// <summary>
/// True: Crit players can use LOOC
/// False: Crit player LOOC gets redirected to dead chat
/// </summary>
public static readonly CVarDef<bool> CritLoocEnabled =
CVarDef.Create("looc.enabled_crit", false, CVar.NOTIFY | CVar.REPLICATED);
}

View File

@@ -0,0 +1,27 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool>
OocEnabled = CVarDef.Create("ooc.enabled", true, CVar.NOTIFY | CVar.REPLICATED);
public static readonly CVarDef<bool> AdminOocEnabled =
CVarDef.Create("ooc.enabled_admin", true, CVar.NOTIFY);
/// <summary>
/// If true, whenever OOC is disabled the Discord OOC relay will also be disabled.
/// </summary>
public static readonly CVarDef<bool> DisablingOOCDisablesRelay =
CVarDef.Create("ooc.disabling_ooc_disables_relay", true, CVar.SERVERONLY);
/// <summary>
/// Whether or not OOC chat should be enabled during a round.
/// </summary>
public static readonly CVarDef<bool> OocEnableDuringRound =
CVarDef.Create("ooc.enable_during_round", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<bool> ShowOocPatronColor =
CVarDef.Create("ooc.show_ooc_patron_color", true, CVar.ARCHIVE | CVar.REPLICATED | CVar.CLIENT);
}

View File

@@ -0,0 +1,68 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Chat rate limit values are accounted in periods of this size (seconds).
/// After the period has passed, the count resets.
/// </summary>
/// <seealso cref="ChatRateLimitCount"/>
public static readonly CVarDef<float> ChatRateLimitPeriod =
CVarDef.Create("chat.rate_limit_period", 2f, CVar.SERVERONLY);
/// <summary>
/// How many chat messages are allowed in a single rate limit period.
/// </summary>
/// <remarks>
/// The total rate limit throughput per second is effectively
/// <see cref="ChatRateLimitCount"/> divided by <see cref="ChatRateLimitCount"/>.
/// </remarks>
/// <seealso cref="ChatRateLimitPeriod"/>
public static readonly CVarDef<int> ChatRateLimitCount =
CVarDef.Create("chat.rate_limit_count", 10, CVar.SERVERONLY);
/// <summary>
/// Minimum delay (in seconds) between notifying admins about chat message rate limit violations.
/// A negative value disables admin announcements.
/// </summary>
public static readonly CVarDef<int> ChatRateLimitAnnounceAdminsDelay =
CVarDef.Create("chat.rate_limit_announce_admins_delay", 15, CVar.SERVERONLY);
public static readonly CVarDef<int> ChatMaxMessageLength =
CVarDef.Create("chat.max_message_length", 1000, CVar.SERVER | CVar.REPLICATED);
public static readonly CVarDef<int> ChatMaxAnnouncementLength =
CVarDef.Create("chat.max_announcement_length", 256, CVar.SERVER | CVar.REPLICATED);
public static readonly CVarDef<bool> ChatSanitizerEnabled =
CVarDef.Create("chat.chat_sanitizer_enabled", true, CVar.SERVERONLY);
public static readonly CVarDef<bool> ChatShowTypingIndicator =
CVarDef.Create("chat.show_typing_indicator", true, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<bool> ChatEnableFancyBubbles =
CVarDef.Create("chat.enable_fancy_bubbles",
true,
CVar.CLIENTONLY | CVar.ARCHIVE,
"Toggles displaying fancy speech bubbles, which display the speaking character's name.");
public static readonly CVarDef<bool> ChatFancyNameBackground =
CVarDef.Create("chat.fancy_name_background",
false,
CVar.CLIENTONLY | CVar.ARCHIVE,
"Toggles displaying a background under the speaking character's name.");
/// <summary>
/// A message broadcast to each player that joins the lobby.
/// May be changed by admins ingame through use of the "set-motd" command.
/// In this case the new value, if not empty, is broadcast to all connected players and saved between rounds.
/// May be requested by any player through use of the "get-motd" command.
/// </summary>
public static readonly CVarDef<string> MOTD =
CVarDef.Create("chat.motd",
"",
CVar.SERVER | CVar.SERVERONLY | CVar.ARCHIVE,
"A message broadcast to each player that joins the lobby.");
}

View File

@@ -0,0 +1,35 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
// These are server-only for now since I don't foresee a client use yet,
// and I don't wanna have to start coming up with like .client suffixes and stuff like that.
/// <summary>
/// Configuration presets to load during startup.
/// Multiple presets can be separated by comma and are loaded in order.
/// </summary>
/// <remarks>
/// Loaded presets must be located under the <c>ConfigPresets/</c> resource directory and end with the <c>.toml</c> extension.
/// Only the file name (without extension) must be given for this variable.
/// </remarks>
public static readonly CVarDef<string> ConfigPresets =
CVarDef.Create("config.presets", "", CVar.SERVERONLY);
/// <summary>
/// Whether to load the preset development CVars.
/// This disables some things like lobby to make development easier.
/// Even when true, these are only loaded if the game is compiled with <c>DEVELOPMENT</c> set.
/// </summary>
public static readonly CVarDef<bool> ConfigPresetDevelopment =
CVarDef.Create("config.preset_development", true, CVar.SERVERONLY);
/// <summary>
/// Whether to load the preset debug CVars.
/// Even when true, these are only loaded if the game is compiled with <c>DEBUG</c> set.
/// </summary>
public static readonly CVarDef<bool> ConfigPresetDebug =
CVarDef.Create("config.preset_debug", true, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,15 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> ConsoleLoginLocal =
CVarDef.Create("console.loginlocal", true, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Automatically log in the given user as host, equivalent to the <c>promotehost</c> command.
/// </summary>
public static readonly CVarDef<string> ConsoleLoginHostUser =
CVarDef.Create("console.login_host_user", "", CVar.ARCHIVE | CVar.SERVERONLY);
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Setting this allows a crew manifest to be opened from any window
/// that has a crew manifest button, and sends the correct message.
/// If this is false, only in-game entities will allow you to see
/// the crew manifest, if the functionality is coded in.
/// Having administrator priveledge ignores this, but will still
/// hide the button in UI windows.
/// </summary>
public static readonly CVarDef<bool> CrewManifestWithoutEntity =
CVarDef.Create("crewmanifest.no_entity", true, CVar.REPLICATED);
/// <summary>
/// Setting this allows the crew manifest to be viewed from 'unsecure'
/// entities, such as the PDA.
/// </summary>
public static readonly CVarDef<bool> CrewManifestUnsecure =
CVarDef.Create("crewmanifest.unsecure", true, CVar.REPLICATED);
}

View File

@@ -0,0 +1,77 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
#if DEBUG
private const int DefaultSqliteDelay = 1;
#else
private const int DefaultSqliteDelay = 0;
#endif
public static readonly CVarDef<string> DatabaseEngine =
CVarDef.Create("database.engine", "sqlite", CVar.SERVERONLY);
public static readonly CVarDef<string> DatabaseSqliteDbPath =
CVarDef.Create("database.sqlite_dbpath", "preferences.db", CVar.SERVERONLY);
/// <summary>
/// Milliseconds to asynchronously delay all SQLite database acquisitions with.
/// </summary>
/// <remarks>
/// Defaults to 1 on DEBUG, 0 on RELEASE.
/// This is intended to help catch .Result deadlock bugs that only happen on postgres
/// (because SQLite is not actually asynchronous normally)
/// </remarks>
public static readonly CVarDef<int> DatabaseSqliteDelay =
CVarDef.Create("database.sqlite_delay", DefaultSqliteDelay, CVar.SERVERONLY);
/// <summary>
/// Amount of concurrent SQLite database operations.
/// </summary>
/// <remarks>
/// Note that SQLite is not a properly asynchronous database and also has limited read/write concurrency.
/// Increasing this number may allow more concurrent reads, but it probably won't matter much.
/// SQLite operations are normally ran on the thread pool, which may cause thread pool starvation if the concurrency is too high.
/// </remarks>
public static readonly CVarDef<int> DatabaseSqliteConcurrency =
CVarDef.Create("database.sqlite_concurrency", 3, CVar.SERVERONLY);
public static readonly CVarDef<string> DatabasePgHost =
CVarDef.Create("database.pg_host", "localhost", CVar.SERVERONLY);
public static readonly CVarDef<int> DatabasePgPort =
CVarDef.Create("database.pg_port", 5432, CVar.SERVERONLY);
public static readonly CVarDef<string> DatabasePgDatabase =
CVarDef.Create("database.pg_database", "ss14", CVar.SERVERONLY);
public static readonly CVarDef<string> DatabasePgUsername =
CVarDef.Create("database.pg_username", "postgres", CVar.SERVERONLY);
public static readonly CVarDef<string> DatabasePgPassword =
CVarDef.Create("database.pg_password", "", CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// Max amount of concurrent Postgres database operations.
/// </summary>
public static readonly CVarDef<int> DatabasePgConcurrency =
CVarDef.Create("database.pg_concurrency", 8, CVar.SERVERONLY);
/// <summary>
/// Milliseconds to asynchronously delay all PostgreSQL database operations with.
/// </summary>
/// <remarks>
/// This is intended for performance testing. It works different from <see cref="DatabaseSqliteDelay"/>,
/// as the lag is applied after acquiring the database lock.
/// </remarks>
public static readonly CVarDef<int> DatabasePgFakeLag =
CVarDef.Create("database.pg_fake_lag", 0, CVar.SERVERONLY);
/// <summary>
/// Basically only exists for integration tests to avoid race conditions.
/// </summary>
public static readonly CVarDef<bool> DatabaseSynchronous =
CVarDef.Create("database.sync", false, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,61 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// The role that will get mentioned if a new SOS ahelp comes in.
/// </summary>
public static readonly CVarDef<string> DiscordAhelpMention =
CVarDef.Create("discord.on_call_ping", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// URL of the discord webhook to relay unanswered ahelp messages.
/// </summary>
public static readonly CVarDef<string> DiscordOnCallWebhook =
CVarDef.Create("discord.on_call_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// URL of the Discord webhook which will relay all ahelp messages.
/// </summary>
public static readonly CVarDef<string> DiscordAHelpWebhook =
CVarDef.Create("discord.ahelp_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// The server icon to use in the Discord ahelp embed footer.
/// Valid values are specified at https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure.
/// </summary>
public static readonly CVarDef<string> DiscordAHelpFooterIcon =
CVarDef.Create("discord.ahelp_footer_icon", string.Empty, CVar.SERVERONLY);
/// <summary>
/// The avatar to use for the webhook. Should be an URL.
/// </summary>
public static readonly CVarDef<string> DiscordAHelpAvatar =
CVarDef.Create("discord.ahelp_avatar", string.Empty, CVar.SERVERONLY);
/// <summary>
/// URL of the Discord webhook which will relay all custom votes. If left empty, disables the webhook.
/// </summary>
public static readonly CVarDef<string> DiscordVoteWebhook =
CVarDef.Create("discord.vote_webhook", string.Empty, CVar.SERVERONLY);
/// <summary>
/// URL of the Discord webhook which will relay all votekick votes. If left empty, disables the webhook.
/// </summary>
public static readonly CVarDef<string> DiscordVotekickWebhook =
CVarDef.Create("discord.votekick_webhook", string.Empty, CVar.SERVERONLY);
/// <summary>
/// URL of the Discord webhook which will relay round restart messages.
/// </summary>
public static readonly CVarDef<string> DiscordRoundUpdateWebhook =
CVarDef.Create("discord.round_update_webhook", string.Empty, CVar.SERVERONLY | CVar.CONFIDENTIAL);
/// <summary>
/// Role id for the Discord webhook to ping when the round ends.
/// </summary>
public static readonly CVarDef<string> DiscordRoundEndRoleWebhook =
CVarDef.Create("discord.round_end_role", string.Empty, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,12 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Controls if the game should run station events
/// </summary>
public static readonly CVarDef<bool>
EventsEnabled = CVarDef.Create("events.enabled", true, CVar.ARCHIVE | CVar.SERVERONLY);
}

View File

@@ -0,0 +1,108 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// How many tiles the explosion system will process per tick
/// </summary>
/// <remarks>
/// Setting this too high will put a large load on a single tick. Setting this too low will lead to
/// unnaturally "slow" explosions.
/// </remarks>
public static readonly CVarDef<int> ExplosionTilesPerTick =
CVarDef.Create("explosion.tiles_per_tick", 100, CVar.SERVERONLY);
/// <summary>
/// Upper limit on the size of an explosion before physics-throwing is disabled.
/// </summary>
/// <remarks>
/// Large nukes tend to generate a lot of shrapnel that flies through space. This can functionally cripple
/// the server TPS for a while after an explosion (or even during, if the explosion is processed
/// incrementally.
/// </remarks>
public static readonly CVarDef<int> ExplosionThrowLimit =
CVarDef.Create("explosion.throw_limit", 400, CVar.SERVERONLY);
/// <summary>
/// If this is true, explosion processing will pause the NodeGroupSystem to pause updating.
/// </summary>
/// <remarks>
/// This only takes effect if an explosion needs more than one tick to process (i.e., covers more than <see
/// cref="ExplosionTilesPerTick"/> tiles). If this is not enabled, the node-system will rebuild its graph
/// every tick as the explosion shreds the station, causing significant slowdown.
/// </remarks>
public static readonly CVarDef<bool> ExplosionSleepNodeSys =
CVarDef.Create("explosion.node_sleep", true, CVar.SERVERONLY);
/// <summary>
/// Upper limit on the total area that an explosion can affect before the neighbor-finding algorithm just
/// stops. Defaults to a 60-rile radius explosion.
/// </summary>
/// <remarks>
/// Actual area may be larger, as it currently doesn't terminate mid neighbor finding. I.e., area may be that of a ~51 tile radius circle instead.
/// </remarks>
public static readonly CVarDef<int> ExplosionMaxArea =
CVarDef.Create("explosion.max_area", (int)3.14f * 256 * 256, CVar.SERVERONLY);
/// <summary>
/// Upper limit on the number of neighbor finding steps for the explosion system neighbor-finding algorithm.
/// </summary>
/// <remarks>
/// Effectively places an upper limit on the range that any explosion can have. In the vast majority of
/// instances, <see cref="ExplosionMaxArea"/> will likely be hit before this becomes a limiting factor.
/// </remarks>
public static readonly CVarDef<int> ExplosionMaxIterations =
CVarDef.Create("explosion.max_iterations", 500, CVar.SERVERONLY);
/// <summary>
/// Max Time in milliseconds to spend processing explosions every tick.
/// </summary>
/// <remarks>
/// This time limiting is not perfectly implemented. Firstly, a significant chunk of processing time happens
/// due to queued entity deletions, which happen outside of the system update code. Secondly, explosion
/// spawning cannot currently be interrupted & resumed, and may lead to exceeding this time limit.
/// </remarks>
public static readonly CVarDef<float> ExplosionMaxProcessingTime =
CVarDef.Create("explosion.max_tick_time", 7f, CVar.SERVERONLY);
/// <summary>
/// If the explosion is being processed incrementally over several ticks, this variable determines whether
/// updating the grid tiles should be done incrementally at the end of every tick, or only once the explosion has finished processing.
/// </summary>
/// <remarks>
/// The most notable consequence of this change is that explosions will only punch a hole in the station &
/// create a vacumm once they have finished exploding. So airlocks will no longer slam shut as the explosion
/// expands, just suddenly at the end.
/// </remarks>
public static readonly CVarDef<bool> ExplosionIncrementalTileBreaking =
CVarDef.Create("explosion.incremental_tile", false, CVar.SERVERONLY);
/// <summary>
/// This determines for how many seconds an explosion should stay visible once it has finished expanding.
/// </summary>
public static readonly CVarDef<float> ExplosionPersistence =
CVarDef.Create("explosion.persistence", 1.0f, CVar.SERVERONLY);
/// <summary>
/// If an explosion covers a larger area than this number, the damaging/processing will always start during
/// the next tick, instead of during the same tick that the explosion was generated in.
/// </summary>
/// <remarks>
/// This value can be used to ensure that for large explosions the area/tile calculation and the explosion
/// processing/damaging occurs in separate ticks. This helps reduce the single-tick lag if both <see
/// cref="ExplosionMaxProcessingTime"/> and <see cref="ExplosionTilesPerTick"/> are large. I.e., instead of
/// a single tick explosion, this cvar allows for a configuration that results in a two-tick explosion,
/// though most of the computational cost is still in the second tick.
/// </remarks>
public static readonly CVarDef<int> ExplosionSingleTickAreaLimit =
CVarDef.Create("explosion.single_tick_area_limit", 400, CVar.SERVERONLY);
/// <summary>
/// Whether or not explosions are allowed to create tiles that have
/// <see cref="ContentTileDefinition.MapAtmosphere"/> set to true.
/// </summary>
public static readonly CVarDef<bool> ExplosionCanCreateVacuum =
CVarDef.Create("explosion.can_create_vacuum", true, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,60 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Link to Discord server to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksDiscord =
CVarDef.Create("infolinks.discord", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to website to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksForum =
CVarDef.Create("infolinks.forum", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to GitHub page to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksGithub =
CVarDef.Create("infolinks.github", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to website to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksWebsite =
CVarDef.Create("infolinks.website", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to wiki to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksWiki =
CVarDef.Create("infolinks.wiki", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to Patreon. Not shown in the launcher currently.
/// </summary>
public static readonly CVarDef<string> InfoLinksPatreon =
CVarDef.Create("infolinks.patreon", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to the bug report form.
/// </summary>
public static readonly CVarDef<string> InfoLinksBugReport =
CVarDef.Create("infolinks.bug_report", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to site handling ban appeals. Shown in ban disconnect messages.
/// </summary>
public static readonly CVarDef<string> InfoLinksAppeal =
CVarDef.Create("infolinks.appeal", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Link to Telegram channel to show in the launcher.
/// </summary>
public static readonly CVarDef<string> InfoLinksTelegram =
CVarDef.Create("infolinks.telegram", "", CVar.SERVER | CVar.REPLICATED);
}

View File

@@ -0,0 +1,336 @@
using Content.Shared.Roles;
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Disables most functionality in the GameTicker.
/// </summary>
public static readonly CVarDef<bool>
GameDummyTicker = CVarDef.Create("game.dummyticker", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls if the lobby is enabled. If it is not, and there are no available jobs, you may get stuck on a black screen.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnabled = CVarDef.Create("game.lobbyenabled", true, CVar.ARCHIVE);
/// <summary>
/// Controls the duration of the lobby timer in seconds. Defaults to 2 minutes and 30 seconds.
/// </summary>
public static readonly CVarDef<int>
GameLobbyDuration = CVarDef.Create("game.lobbyduration", 150, CVar.ARCHIVE);
/// <summary>
/// Controls if players can latejoin at all.
/// </summary>
public static readonly CVarDef<bool>
GameDisallowLateJoins = CVarDef.Create("game.disallowlatejoins", false, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls the default game preset.
/// </summary>
public static readonly CVarDef<string>
GameLobbyDefaultPreset = CVarDef.Create("game.defaultpreset", "secret", CVar.ARCHIVE);
/// <summary>
/// Controls if the game can force a different preset if the current preset's criteria are not met.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyFallbackEnabled = CVarDef.Create("game.fallbackenabled", true, CVar.ARCHIVE);
/// <summary>
/// The preset for the game to fall back to if the selected preset could not be used, and fallback is enabled.
/// </summary>
public static readonly CVarDef<string>
GameLobbyFallbackPreset = CVarDef.Create("game.fallbackpreset", "Traitor,Extended", CVar.ARCHIVE);
/// <summary>
/// Controls if people can win the game in Suspicion or Deathmatch.
/// </summary>
public static readonly CVarDef<bool>
GameLobbyEnableWin = CVarDef.Create("game.enablewin", true, CVar.ARCHIVE);
/// <summary>
/// Controls the maximum number of character slots a player is allowed to have.
/// </summary>
public static readonly CVarDef<int>
GameMaxCharacterSlots = CVarDef.Create("game.maxcharacterslots", 30, CVar.ARCHIVE | CVar.SERVERONLY);
/// <summary>
/// Controls the game map prototype to load. SS14 stores these prototypes in Prototypes/Maps.
/// </summary>
public static readonly CVarDef<string>
GameMap = CVarDef.Create("game.map", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Controls whether to use world persistence or not.
/// </summary>
public static readonly CVarDef<bool>
UsePersistence = CVarDef.Create("game.usepersistence", false, CVar.ARCHIVE);
/// <summary>
/// If world persistence is used, what map prototype should be initially loaded.
/// If the save file exists, it replaces MapPath but everything else stays the same (station name and such).
/// </summary>
public static readonly CVarDef<string>
PersistenceMap = CVarDef.Create("game.persistencemap", "Empty", CVar.ARCHIVE);
/// <summary>
/// Prototype to use for map pool.
/// </summary>
public static readonly CVarDef<string>
GameMapPool = CVarDef.Create("game.map_pool", "DefaultMapPool", CVar.SERVERONLY);
/// <summary>
/// The depth of the queue used to calculate which map is next in rotation.
/// This is how long the game "remembers" that some map was put in play. Default is 16 rounds.
/// </summary>
public static readonly CVarDef<int>
GameMapMemoryDepth = CVarDef.Create("game.map_memory_depth", 16, CVar.SERVERONLY);
/// <summary>
/// Is map rotation enabled?
/// </summary>
public static readonly CVarDef<bool>
GameMapRotation = CVarDef.Create("game.map_rotation", true, CVar.SERVERONLY);
/// <summary>
/// If roles should be restricted based on time.
/// </summary>
public static readonly CVarDef<bool>
GameRoleTimers = CVarDef.Create("game.role_timers", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Override default role requirements using a <see cref="JobRequirementOverridePrototype"/>
/// </summary>
public static readonly CVarDef<string>
GameRoleTimerOverride = CVarDef.Create("game.role_timer_override", "", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// If roles should be restricted based on whether or not they are whitelisted.
/// </summary>
public static readonly CVarDef<bool>
GameRoleWhitelist = CVarDef.Create("game.role_whitelist", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not disconnecting inside of a cryopod should remove the character or just store them until they reconnect.
/// </summary>
public static readonly CVarDef<bool>
GameCryoSleepRejoining = CVarDef.Create("game.cryo_sleep_rejoining", false, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// When enabled, guests will be assigned permanent UIDs and will have their preferences stored.
/// </summary>
public static readonly CVarDef<bool> GamePersistGuests =
CVarDef.Create("game.persistguests", true, CVar.ARCHIVE | CVar.SERVERONLY);
public static readonly CVarDef<bool> GameDiagonalMovement =
CVarDef.Create("game.diagonalmovement", true, CVar.ARCHIVE);
public static readonly CVarDef<int> SoftMaxPlayers =
CVarDef.Create("game.soft_max_players", 30, CVar.SERVERONLY | CVar.ARCHIVE);
/// <summary>
/// If a player gets denied connection to the server,
/// how long they are forced to wait before attempting to reconnect.
/// </summary>
public static readonly CVarDef<int> GameServerFullReconnectDelay =
CVarDef.Create("game.server_full_reconnect_delay", 30, CVar.SERVERONLY);
/// <summary>
/// Whether or not panic bunker is currently enabled.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnabled =
CVarDef.Create("game.panic_bunker.enabled", false, CVar.NOTIFY | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Whether or not the panic bunker will disable when an admin comes online.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerDisableWithAdmins =
CVarDef.Create("game.panic_bunker.disable_with_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will enable when no admins are online.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerEnableWithoutAdmins =
CVarDef.Create("game.panic_bunker.enable_without_admins", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not the panic bunker will count deadminned admins for
/// <see cref="PanicBunkerDisableWithAdmins"/> and
/// <see cref="PanicBunkerEnableWithoutAdmins"/>
/// </summary>
public static readonly CVarDef<bool> PanicBunkerCountDeadminnedAdmins =
CVarDef.Create("game.panic_bunker.count_deadminned_admins", false, CVar.SERVERONLY);
/// <summary>
/// Show reason of disconnect for user or not.
/// </summary>
public static readonly CVarDef<bool> PanicBunkerShowReason =
CVarDef.Create("game.panic_bunker.show_reason", false, CVar.SERVERONLY);
/// <summary>
/// Minimum age of the account (from server's PoV, so from first-seen date) in minutes.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinAccountAge =
CVarDef.Create("game.panic_bunker.min_account_age", 1440, CVar.SERVERONLY);
/// <summary>
/// Minimal overall played time.
/// </summary>
public static readonly CVarDef<int> PanicBunkerMinOverallMinutes =
CVarDef.Create("game.panic_bunker.min_overall_minutes", 600, CVar.SERVERONLY);
/// <summary>
/// A custom message that will be used for connections denied to the panic bunker
/// If not empty, then will overwrite <see cref="PanicBunkerShowReason"/>
/// </summary>
public static readonly CVarDef<string> PanicBunkerCustomReason =
CVarDef.Create("game.panic_bunker.custom_reason", string.Empty, CVar.SERVERONLY);
/// <summary>
/// Allow bypassing the panic bunker if the user is whitelisted.
/// </summary>
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>
/// Make people bonk when trying to climb certain objects like tables.
/// </summary>
public static readonly CVarDef<bool> GameTableBonk =
CVarDef.Create("game.table_bonk", false, CVar.REPLICATED);
/// <summary>
/// Whether or not status icons are rendered for everyone.
/// </summary>
public static readonly CVarDef<bool> GlobalStatusIconsEnabled =
CVarDef.Create("game.global_status_icons_enabled", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not status icons are rendered on this specific client.
/// </summary>
public static readonly CVarDef<bool> LocalStatusIconsEnabled =
CVarDef.Create("game.local_status_icons_enabled", true, CVar.CLIENTONLY);
/// <summary>
/// Whether or not coordinates on the Debug overlay should only be available to admins.
/// </summary>
public static readonly CVarDef<bool> DebugCoordinatesAdminOnly =
CVarDef.Create("game.debug_coordinates_admin_only", true, CVar.SERVER | CVar.REPLICATED);
#if EXCEPTION_TOLERANCE
/// <summary>
/// Amount of times round start must fail before the server is shut down.
/// Set to 0 or a negative number to disable.
/// </summary>
public static readonly CVarDef<int> RoundStartFailShutdownCount =
CVarDef.Create("game.round_start_fail_shutdown_count", 5, CVar.SERVERONLY | CVar.SERVER);
#endif
/// <summary>
/// Delay between station alert level changes.
/// </summary>
public static readonly CVarDef<int> GameAlertLevelChangeDelay =
CVarDef.Create("game.alert_level_change_delay", 30, CVar.SERVERONLY);
/// <summary>
/// The time in seconds that the server should wait before restarting the round.
/// Defaults to 2 minutes.
/// </summary>
public static readonly CVarDef<float> RoundRestartTime =
CVarDef.Create("game.round_restart_time", 120f, CVar.SERVERONLY);
/// <summary>
/// The prototype to use for secret weights.
/// </summary>
public static readonly CVarDef<string> SecretWeightPrototype =
CVarDef.Create("game.secret_weight_prototype", "Secret", CVar.SERVERONLY);
/// <summary>
/// The id of the sound collection to randomly choose a sound from and play when the round ends.
/// </summary>
public static readonly CVarDef<string> RoundEndSoundCollection =
CVarDef.Create("game.round_end_sound_collection", "RoundEnd", CVar.SERVERONLY);
/// <summary>
/// Whether or not to add every player as a global override to PVS at round end.
/// This will allow all players to see their clothing in the round screen player list screen,
/// but may cause lag during round end with very high player counts.
/// </summary>
public static readonly CVarDef<bool> RoundEndPVSOverrides =
CVarDef.Create("game.round_end_pvs_overrides", true, CVar.SERVERONLY);
/// <summary>
/// If true, players can place objects onto tabletop games like chess boards.
/// </summary>
/// <remarks>
/// This feature is currently highly abusable and can easily be used to crash the server,
/// so it's off by default.
/// </remarks>
public static readonly CVarDef<bool> GameTabletopPlace =
CVarDef.Create("game.tabletop_place", false, CVar.SERVERONLY);
/// <summary>
/// If true, contraband severity can be viewed in the examine menu
/// </summary>
public static readonly CVarDef<bool> ContrabandExamine =
CVarDef.Create("game.contraband_examine", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Size of the lookup area for adding entities to the context menu
/// </summary>
public static readonly CVarDef<float> GameEntityMenuLookup =
CVarDef.Create("game.entity_menu_lookup", 0.25f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Should the clients window show the server hostname in the title?
/// </summary>
public static readonly CVarDef<bool> GameHostnameInTitlebar =
CVarDef.Create("game.hostname_in_titlebar", true, CVar.SERVER | CVar.REPLICATED);
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// The time you must spend reading the rules, before the "Request" button is enabled
/// </summary>
public static readonly CVarDef<float> GhostRoleTime =
CVarDef.Create("ghost.role_time", 3f, CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// If ghost role lotteries should be made near-instanteous.
/// </summary>
public static readonly CVarDef<bool> GhostQuickLottery =
CVarDef.Create("ghost.quick_lottery", false, CVar.SERVERONLY);
/// <summary>
/// Whether or not to kill the player's mob on ghosting, when it is in a critical health state.
/// </summary>
public static readonly CVarDef<bool> GhostKillCrit =
CVarDef.Create("ghost.kill_crit", true, CVar.REPLICATED | CVar.SERVER);
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<int> HudTheme =
CVarDef.Create("hud.theme", 0, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> HudHeldItemShow =
CVarDef.Create("hud.held_item_show", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> CombatModeIndicatorsPointShow =
CVarDef.Create("hud.combat_mode_indicators_point_show", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> LoocAboveHeadShow =
CVarDef.Create("hud.show_looc_above_head", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<float> HudHeldItemOffset =
CVarDef.Create("hud.held_item_offset", 28f, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> HudFpsCounterVisible =
CVarDef.Create("hud.fps_counter_visible", false, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -0,0 +1,48 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Restricts IC character names to alphanumeric chars.
/// </summary>
public static readonly CVarDef<bool> RestrictedNames =
CVarDef.Create("ic.restricted_names", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Allows flavor text (character descriptions)
/// </summary>
public static readonly CVarDef<bool> FlavorText =
CVarDef.Create("ic.flavor_text", false, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Adds a period at the end of a sentence if the sentence ends in a letter.
/// </summary>
public static readonly CVarDef<bool> ChatPunctuation =
CVarDef.Create("ic.punctuation", false, CVar.SERVER);
/// <summary>
/// Enables automatically forcing IC name rules. Uppercases the first letter of the first and last words of the name
/// </summary>
public static readonly CVarDef<bool> ICNameCase =
CVarDef.Create("ic.name_case", true, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Whether or not players' characters are randomly generated rather than using their selected characters in the creator.
/// </summary>
public static readonly CVarDef<bool> ICRandomCharacters =
CVarDef.Create("ic.random_characters", false, CVar.SERVER);
/// <summary>
/// A weighted random prototype used to determine the species selected for random characters.
/// </summary>
public static readonly CVarDef<string> ICRandomSpeciesWeights =
CVarDef.Create("ic.random_species_weights", "SpeciesWeights", CVar.SERVER);
/// <summary>
/// Control displaying SSD indicators near players
/// </summary>
public static readonly CVarDef<bool> ICShowSSDIndicator =
CVarDef.Create("ic.show_ssd_indicator", true, CVar.CLIENTONLY);
}

View File

@@ -0,0 +1,54 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Deadzone for drag-drop interactions.
/// </summary>
public static readonly CVarDef<float> DragDropDeadZone =
CVarDef.Create("control.drag_dead_zone", 12f, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Toggles whether the walking key is a toggle or a held key.
/// </summary>
public static readonly CVarDef<bool> ToggleWalk =
CVarDef.Create("control.toggle_walk", false, CVar.CLIENTONLY | CVar.ARCHIVE);
// The rationale behind the default limit is simply that I can easily get to 7 interactions per second by just
// trying to spam toggle a light switch or lever (though the UseDelay component limits the actual effect of the
// interaction). I don't want to accidentally spam admins with alerts just because somebody is spamming a
// key manually, nor do we want to alert them just because the player is having network issues and the server
// receives multiple interactions at once. But we also want to try catch people with modified clients that spam
// many interactions on the same tick. Hence, a very short period, with a relatively high count.
/// <summary>
/// Maximum number of interactions that a player can perform within <see cref="InteractionRateLimitCount"/> seconds
/// </summary>
public static readonly CVarDef<int> InteractionRateLimitCount =
CVarDef.Create("interaction.rate_limit_count", 5, CVar.SERVER | CVar.REPLICATED);
/// <seealso cref="InteractionRateLimitCount"/>
public static readonly CVarDef<float> InteractionRateLimitPeriod =
CVarDef.Create("interaction.rate_limit_period", 0.5f, CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Minimum delay (in seconds) between notifying admins about interaction rate limit violations. A negative
/// value disables admin announcements.
/// </summary>
public static readonly CVarDef<int> InteractionRateLimitAnnounceAdminsDelay =
CVarDef.Create("interaction.rate_limit_announce_admins_delay", 120, CVar.SERVERONLY);
/// <summary>
/// Whether or not the storage UI is static and bound to the hotbar, or unbound and allowed to be dragged anywhere.
/// </summary>
public static readonly CVarDef<bool> StaticStorageUI =
CVarDef.Create("control.static_storage_ui", true, CVar.CLIENTONLY | CVar.ARCHIVE);
/// <summary>
/// Whether or not the storage window uses a transparent or opaque sprite.
/// </summary>
public static readonly CVarDef<bool> OpaqueStorageWindow =
CVarDef.Create("control.opaque_storage_background", false, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<string> UIClickSound =
CVarDef.Create("interface.click_sound", "/Audio/UserInterface/click.ogg", CVar.REPLICATED);
public static readonly CVarDef<string> UIHoverSound =
CVarDef.Create("interface.hover_sound", "/Audio/UserInterface/hover.ogg", CVar.REPLICATED);
public static readonly CVarDef<string> UILayout =
CVarDef.Create("ui.layout", "Default", CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<string> DefaultScreenChatSize =
CVarDef.Create("ui.default_chat_size", "", CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<string> SeparatedScreenChatSize =
CVarDef.Create("ui.separated_chat_size", "0.6,0", CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<bool> OutlineEnabled =
CVarDef.Create("outline.enabled", true, CVar.CLIENTONLY);
}

View File

@@ -0,0 +1,24 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Will mapping mode enable autosaves when it's activated?
/// </summary>
public static readonly CVarDef<bool>
AutosaveEnabled = CVarDef.Create("mapping.autosave", true, CVar.SERVERONLY);
/// <summary>
/// Autosave interval in seconds.
/// </summary>
public static readonly CVarDef<float>
AutosaveInterval = CVarDef.Create("mapping.autosave_interval", 600f, CVar.SERVERONLY);
/// <summary>
/// Directory in server user data to save to. Saves will be inside folders in this directory.
/// </summary>
public static readonly CVarDef<string>
AutosaveDirectory = CVarDef.Create("mapping.autosave_dir", "Autosaves", CVar.SERVERONLY);
}

View File

@@ -0,0 +1,18 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<int> MaxMidiEventsPerSecond =
CVarDef.Create("midi.max_events_per_second", 1000, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<int> MaxMidiEventsPerBatch =
CVarDef.Create("midi.max_events_per_batch", 60, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<int> MaxMidiBatchesDropped =
CVarDef.Create("midi.max_batches_dropped", 1, CVar.SERVERONLY);
public static readonly CVarDef<int> MaxMidiLaggedBatches =
CVarDef.Create("midi.max_lagged_batches", 8, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,97 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> HolidaysEnabled = CVarDef.Create("holidays.enabled", true, CVar.SERVERONLY);
public static readonly CVarDef<bool> BrandingSteam = CVarDef.Create("branding.steam", false, CVar.CLIENTONLY);
public static readonly CVarDef<int> EntityMenuGroupingType = CVarDef.Create("entity_menu", 0, CVar.CLIENTONLY);
/// <summary>
/// Should we pre-load all of the procgen atlasses.
/// </summary>
public static readonly CVarDef<bool> ProcgenPreload =
CVarDef.Create("procgen.preload", true, CVar.SERVERONLY);
/// <summary>
/// Enabled: Cloning has 70% cost and reclaimer will refuse to reclaim corpses with souls. (For LRP).
/// Disabled: Cloning has full biomass cost and reclaimer can reclaim corpses with souls. (Playtested and balanced for MRP+).
/// </summary>
public static readonly CVarDef<bool> BiomassEasyMode =
CVarDef.Create("biomass.easy_mode", true, CVar.SERVERONLY);
/// <summary>
/// A scale factor applied to a grid's bounds when trying to find a spot to randomly generate an anomaly.
/// </summary>
public static readonly CVarDef<float> AnomalyGenerationGridBoundsScale =
CVarDef.Create("anomaly.generation_grid_bounds_scale", 0.6f, CVar.SERVERONLY);
/// <summary>
/// How long a client can go without any input before being considered AFK.
/// </summary>
public static readonly CVarDef<float> AfkTime =
CVarDef.Create("afk.time", 60f, CVar.SERVERONLY);
/// <summary>
/// Flavor limit. This is to ensure that having a large mass of flavors in
/// some food object won't spam a user with flavors.
/// </summary>
public static readonly CVarDef<int>
FlavorLimit = CVarDef.Create("flavor.limit", 10, CVar.SERVERONLY);
public static readonly CVarDef<string> DestinationFile =
CVarDef.Create("autogen.destination_file", "", CVar.SERVER | CVar.SERVERONLY);
/// <summary>
/// Whether uploaded files will be stored in the server's database.
/// This is useful to keep "logs" on what files admins have uploaded in the past.
/// </summary>
public static readonly CVarDef<bool> ResourceUploadingStoreEnabled =
CVarDef.Create("netres.store_enabled", true, CVar.SERVER | CVar.SERVERONLY);
/// <summary>
/// Numbers of days before stored uploaded files are deleted. Set to zero or negative to disable auto-delete.
/// This is useful to free some space automatically. Auto-deletion runs only on server boot.
/// </summary>
public static readonly CVarDef<int> ResourceUploadingStoreDeletionDays =
CVarDef.Create("netres.store_deletion_days", 30, CVar.SERVER | CVar.SERVERONLY);
/// <summary>
/// If a server update restart is pending, the delay after the last player leaves before we actually restart. In seconds.
/// </summary>
public static readonly CVarDef<float> UpdateRestartDelay =
CVarDef.Create("update.restart_delay", 20f, CVar.SERVERONLY);
/// <summary>
/// If fire alarms should have all access, or if activating/resetting these
/// should be restricted to what is dictated on a player's access card.
/// Defaults to true.
/// </summary>
public static readonly CVarDef<bool> FireAlarmAllAccess =
CVarDef.Create("firealarm.allaccess", true, CVar.SERVERONLY);
/// <summary>
/// Time between play time autosaves, in seconds.
/// </summary>
public static readonly CVarDef<float>
PlayTimeSaveInterval = CVarDef.Create("playtime.save_interval", 900f, CVar.SERVERONLY);
/// <summary>
/// The maximum amount of time the entity GC can process, in ms.
/// </summary>
public static readonly CVarDef<int> GCMaximumTimeMs =
CVarDef.Create("entgc.maximum_time_ms", 5, CVar.SERVERONLY);
public static readonly CVarDef<bool> GatewayGeneratorEnabled =
CVarDef.Create("gateway.generator_enabled", true);
public static readonly CVarDef<string> TippyEntity =
CVarDef.Create("tippy.entity", "Tippy", CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// The number of seconds that must pass for a single entity to be able to point at something again.
/// </summary>
public static readonly CVarDef<float> PointingCooldownSeconds =
CVarDef.Create("pointing.cooldown_seconds", 0.5f, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,16 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<int> NPCMaxUpdates =
CVarDef.Create("npc.max_updates", 128);
public static readonly CVarDef<bool> NPCEnabled = CVarDef.Create("npc.enabled", true);
/// <summary>
/// Should NPCs pathfind when steering. For debug purposes.
/// </summary>
public static readonly CVarDef<bool> NPCPathfinding = CVarDef.Create("npc.pathfinding", true);
}

View File

@@ -0,0 +1,15 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<float> NetAtmosDebugOverlayTickRate =
CVarDef.Create("net.atmosdbgoverlaytickrate", 3.0f);
public static readonly CVarDef<float> NetGasOverlayTickRate =
CVarDef.Create("net.gasoverlaytickrate", 3.0f);
public static readonly CVarDef<int> GasOverlayThresholds =
CVarDef.Create("net.gasoverlaythresholds", 20);
}

View File

@@ -0,0 +1,15 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> ParallaxEnabled =
CVarDef.Create("parallax.enabled", true, CVar.CLIENTONLY);
public static readonly CVarDef<bool> ParallaxDebug =
CVarDef.Create("parallax.debug", false, CVar.CLIENTONLY);
public static readonly CVarDef<bool> ParallaxLowQuality =
CVarDef.Create("parallax.low_quality", false, CVar.ARCHIVE | CVar.CLIENTONLY);
}

View File

@@ -0,0 +1,27 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// When a mob is walking should its X / Y movement be relative to its parent (true) or the map (false).
/// </summary>
public static readonly CVarDef<bool> RelativeMovement =
CVarDef.Create("physics.relative_movement", true, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<float> TileFrictionModifier =
CVarDef.Create("physics.tile_friction", 40.0f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<float> StopSpeed =
CVarDef.Create("physics.stop_speed", 0.1f, CVar.ARCHIVE | CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Whether mobs can push objects like lockers.
/// </summary>
/// <remarks>
/// Technically client doesn't need to know about it but this may prevent a bug in the distant future so it stays.
/// </remarks>
public static readonly CVarDef<bool> MobPushing =
CVarDef.Create("physics.mob_pushing", false, CVar.REPLICATED | CVar.SERVER);
}

View File

@@ -0,0 +1,32 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// What is the smallest radiation dose in rads that can be received by object.
/// Extremely small values may impact performance.
/// </summary>
public static readonly CVarDef<float> RadiationMinIntensity =
CVarDef.Create("radiation.min_intensity", 0.1f, CVar.SERVERONLY);
/// <summary>
/// Rate of radiation system update in seconds.
/// </summary>
public static readonly CVarDef<float> RadiationGridcastUpdateRate =
CVarDef.Create("radiation.gridcast.update_rate", 1.0f, CVar.SERVERONLY);
/// <summary>
/// If both radiation source and receiver are placed on same grid, ignore grids between them.
/// May get inaccurate result in some cases, but greatly boost performance in general.
/// </summary>
public static readonly CVarDef<bool> RadiationGridcastSimplifiedSameGrid =
CVarDef.Create("radiation.gridcast.simplified_same_grid", true, CVar.SERVERONLY);
/// <summary>
/// Max distance that radiation ray can travel in meters.
/// </summary>
public static readonly CVarDef<float> RadiationGridcastMaxDistance =
CVarDef.Create("radiation.gridcast.max_distance", 50f, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,43 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Whether or not to record admin chat. If replays are being publicly distributes, this should probably be
/// false.
/// </summary>
public static readonly CVarDef<bool> ReplayRecordAdminChat =
CVarDef.Create("replay.record_admin_chat", false, CVar.ARCHIVE);
/// <summary>
/// Automatically record full rounds as replays.
/// </summary>
public static readonly CVarDef<bool> ReplayAutoRecord =
CVarDef.Create("replay.auto_record", false, CVar.SERVERONLY);
/// <summary>
/// The file name to record automatic replays to. The path is relative to <see cref="CVars.ReplayDirectory"/>.
/// </summary>
/// <remarks>
/// <para>
/// If the path includes slashes, directories will be automatically created if necessary.
/// </para>
/// <para>
/// A number of substitutions can be used to automatically fill in the file name: <c>{year}</c>, <c>{month}</c>, <c>{day}</c>, <c>{hour}</c>, <c>{minute}</c>, <c>{round}</c>.
/// </para>
/// </remarks>
public static readonly CVarDef<string> ReplayAutoRecordName =
CVarDef.Create("replay.auto_record_name",
"{year}_{month}_{day}-{hour}_{minute}-round_{round}.zip",
CVar.SERVERONLY);
/// <summary>
/// Path that, if provided, automatic replays are initially recorded in.
/// When the recording is done, the file is moved into its final destination.
/// Unless this path is rooted, it will be relative to <see cref="CVars.ReplayDirectory"/>.
/// </summary>
public static readonly CVarDef<string> ReplayAutoRecordTempDir =
CVarDef.Create("replay.auto_record_temp_dir", "", CVar.SERVERONLY);
}

View File

@@ -0,0 +1,18 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Duration for missions
/// </summary>
public static readonly CVarDef<float>
SalvageExpeditionDuration = CVarDef.Create("salvage.expedition_duration", 660f, CVar.REPLICATED);
/// <summary>
/// Cooldown for missions.
/// </summary>
public static readonly CVarDef<float>
SalvageExpeditionCooldown = CVarDef.Create("salvage.expedition_cooldown", 780f, CVar.REPLICATED);
}

View File

@@ -0,0 +1,43 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/*
* Server
*/
/// <summary>
/// Change this to have the changelog and rules "last seen" date stored separately.
/// </summary>
public static readonly CVarDef<string> ServerId =
CVarDef.Create("server.id", "unknown_server_id", CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Guide Entry Prototype ID to be displayed as the server rules.
/// </summary>
public static readonly CVarDef<string> RulesFile =
CVarDef.Create("server.rules_file", "DefaultRuleset", CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// Guide entry that is displayed by default when a guide is opened.
/// </summary>
public static readonly CVarDef<string> DefaultGuide =
CVarDef.Create("server.default_guide", "NewPlayer", CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// If greater than 0, automatically restart the server after this many minutes of uptime.
/// </summary>
/// <remarks>
/// <para>
/// This is intended to work around various bugs and performance issues caused by long continuous server uptime.
/// </para>
/// <para>
/// This uses the same non-disruptive logic as update restarts,
/// i.e. the game will only restart at round end or when there is nobody connected.
/// </para>
/// </remarks>
public static readonly CVarDef<int> ServerUptimeRestartMinutes =
CVarDef.Create("server.uptime_restart_minutes", 0, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,176 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// If true then the camera will match the grid / map and is unchangeable.
/// - When traversing grids it will snap to 0 degrees rotation.
/// False means the player has control over the camera rotation.
/// - When traversing grids it will snap to the nearest cardinal which will generally be imperceptible.
/// </summary>
public static readonly CVarDef<bool> CameraRotationLocked =
CVarDef.Create("shuttle.camera_rotation_locked", false, CVar.REPLICATED);
/// <summary>
/// Whether the arrivals terminal should be on a planet map.
/// </summary>
public static readonly CVarDef<bool> ArrivalsPlanet =
CVarDef.Create("shuttle.arrivals_planet", true, CVar.SERVERONLY);
/// <summary>
/// Whether the arrivals shuttle is enabled.
/// </summary>
public static readonly CVarDef<bool> ArrivalsShuttles =
CVarDef.Create("shuttle.arrivals", false, CVar.SERVERONLY); //CP14 arrivals disabled
/// <summary>
/// The map to use for the arrivals station.
/// </summary>
public static readonly CVarDef<string> ArrivalsMap =
CVarDef.Create("shuttle.arrivals_map", "/Maps/Misc/terminal.yml", CVar.SERVERONLY);
/// <summary>
/// Cooldown between arrivals departures. This should be longer than the FTL time or it will double cycle.
/// </summary>
public static readonly CVarDef<float> ArrivalsCooldown =
CVarDef.Create("shuttle.arrivals_cooldown", 50f, CVar.SERVERONLY);
/// <summary>
/// Are players allowed to return on the arrivals shuttle.
/// </summary>
public static readonly CVarDef<bool> ArrivalsReturns =
CVarDef.Create("shuttle.arrivals_returns", false, CVar.SERVERONLY);
/// <summary>
/// Should all players who spawn at arrivals have godmode until they leave the map?
/// </summary>
public static readonly CVarDef<bool> GodmodeArrivals =
CVarDef.Create("shuttle.godmode_arrivals", false, CVar.SERVERONLY);
/// <summary>
/// If a grid is split then hide any smaller ones under this mass (kg) from the map.
/// This is useful to avoid split grids spamming out labels.
/// </summary>
public static readonly CVarDef<int> HideSplitGridsUnder =
CVarDef.Create("shuttle.hide_split_grids_under", 30, CVar.SERVERONLY);
/// <summary>
/// Whether to automatically spawn escape shuttles.
/// </summary>
public static readonly CVarDef<bool> GridFill =
CVarDef.Create("shuttle.grid_fill", true, CVar.SERVERONLY);
/// <summary>
/// Whether to automatically preloading grids by GridPreloaderSystem
/// </summary>
public static readonly CVarDef<bool> PreloadGrids =
CVarDef.Create("shuttle.preload_grids", true, CVar.SERVERONLY);
/// <summary>
/// How long the warmup time before FTL start should be.
/// </summary>
public static readonly CVarDef<float> FTLStartupTime =
CVarDef.Create("shuttle.startup_time", 5.5f, CVar.SERVERONLY);
/// <summary>
/// How long a shuttle spends in FTL.
/// </summary>
public static readonly CVarDef<float> FTLTravelTime =
CVarDef.Create("shuttle.travel_time", 20f, CVar.SERVERONLY);
/// <summary>
/// How long the final stage of FTL before arrival should be.
/// </summary>
public static readonly CVarDef<float> FTLArrivalTime =
CVarDef.Create("shuttle.arrival_time", 5f, CVar.SERVERONLY);
/// <summary>
/// How much time needs to pass before a shuttle can FTL again.
/// </summary>
public static readonly CVarDef<float> FTLCooldown =
CVarDef.Create("shuttle.cooldown", 10f, CVar.SERVERONLY);
/// <summary>
/// The maximum <see cref="PhysicsComponent.Mass"/> a grid can have before it becomes unable to FTL.
/// Any value equal to or less than zero will disable this check.
/// </summary>
public static readonly CVarDef<float> FTLMassLimit =
CVarDef.Create("shuttle.mass_limit", 300f, CVar.SERVERONLY);
/// <summary>
/// How long to knock down entities for if they aren't buckled when FTL starts and stops.
/// </summary>
public static readonly CVarDef<float> HyperspaceKnockdownTime =
CVarDef.Create("shuttle.hyperspace_knockdown_time", 5f, CVar.SERVERONLY);
/// <summary>
/// Is the emergency shuttle allowed to be early launched.
/// </summary>
public static readonly CVarDef<bool> EmergencyEarlyLaunchAllowed =
CVarDef.Create("shuttle.emergency_early_launch_allowed", false, CVar.SERVERONLY);
/// <summary>
/// How long the emergency shuttle remains docked with the station, in seconds.
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleDockTime =
CVarDef.Create("shuttle.emergency_dock_time", 180f, CVar.SERVERONLY);
/// <summary>
/// If the emergency shuttle can't dock at a priority port, the dock time will be multiplied with this value.
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleDockTimeMultiplierOtherDock =
CVarDef.Create("shuttle.emergency_dock_time_multiplier_other_dock", 1.6667f, CVar.SERVERONLY);
/// <summary>
/// If the emergency shuttle can't dock at all, the dock time will be multiplied with this value.
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleDockTimeMultiplierNoDock =
CVarDef.Create("shuttle.emergency_dock_time_multiplier_no_dock", 2f, CVar.SERVERONLY);
/// <summary>
/// How long after the console is authorized for the shuttle to early launch.
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleAuthorizeTime =
CVarDef.Create("shuttle.emergency_authorize_time", 10f, CVar.SERVERONLY);
/// <summary>
/// The minimum time for the emergency shuttle to arrive at centcomm.
/// Actual minimum travel time cannot be less than <see cref="ShuttleSystem.DefaultArrivalTime"/>
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleMinTransitTime =
CVarDef.Create("shuttle.emergency_transit_time_min", 60f, CVar.SERVERONLY);
/// <summary>
/// The maximum time for the emergency shuttle to arrive at centcomm.
/// </summary>
public static readonly CVarDef<float> EmergencyShuttleMaxTransitTime =
CVarDef.Create("shuttle.emergency_transit_time_max", 180f, CVar.SERVERONLY);
/// <summary>
/// Whether the emergency shuttle is enabled or should the round just end.
/// </summary>
public static readonly CVarDef<bool> EmergencyShuttleEnabled =
CVarDef.Create("shuttle.emergency", false, CVar.SERVERONLY); //CP14 Emergency disabled
/// <summary>
/// The percentage of time passed from the initial call to when the shuttle can no longer be recalled.
/// ex. a call time of 10min and turning point of 0.5 means the shuttle cannot be recalled after 5 minutes.
/// </summary>
public static readonly CVarDef<float> EmergencyRecallTurningPoint =
CVarDef.Create("shuttle.recall_turning_point", 0.5f, CVar.SERVERONLY);
/// <summary>
/// Time in minutes after round start to auto-call the shuttle. Set to zero to disable.
/// </summary>
public static readonly CVarDef<int> EmergencyShuttleAutoCallTime =
CVarDef.Create("shuttle.auto_call_time", 90, CVar.SERVERONLY);
/// <summary>
/// Time in minutes after the round was extended (by recalling the shuttle) to call
/// the shuttle again.
/// </summary>
public static readonly CVarDef<int> EmergencyShuttleAutoCallExtensionTime =
CVarDef.Create("shuttle.auto_call_extension_time", 45, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,34 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> LobbyMusicEnabled =
CVarDef.Create("ambience.lobby_music_enabled", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> EventMusicEnabled =
CVarDef.Create("ambience.event_music_enabled", true, CVar.ARCHIVE | CVar.CLIENTONLY);
/// <summary>
/// Round end sound (APC Destroyed)
/// </summary>
public static readonly CVarDef<bool> RestartSoundsEnabled =
CVarDef.Create("ambience.restart_sounds_enabled", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<bool> AdminSoundsEnabled =
CVarDef.Create("audio.admin_sounds_enabled", true, CVar.ARCHIVE | CVar.CLIENTONLY);
public static readonly CVarDef<string> AdminChatSoundPath =
CVarDef.Create("audio.admin_chat_sound_path",
"/Audio/Items/pop.ogg",
CVar.ARCHIVE | CVar.CLIENT | CVar.REPLICATED);
public static readonly CVarDef<float> AdminChatSoundVolume =
CVarDef.Create("audio.admin_chat_sound_volume", -5f, CVar.ARCHIVE | CVar.CLIENT | CVar.REPLICATED);
public static readonly CVarDef<string> AHelpSound =
CVarDef.Create("audio.ahelp_sound", "/Audio/Effects/adminhelp.ogg", CVar.ARCHIVE | CVar.CLIENTONLY);
}

View File

@@ -0,0 +1,13 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<string> StatusMoMMIUrl =
CVarDef.Create("status.mommiurl", "", CVar.SERVERONLY);
public static readonly CVarDef<string> StatusMoMMIPassword =
CVarDef.Create("status.mommipassword", "", CVar.SERVERONLY | CVar.CONFIDENTIAL);
}

View File

@@ -0,0 +1,40 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Whether tips being shown is enabled at all.
/// </summary>
public static readonly CVarDef<bool> TipsEnabled =
CVarDef.Create("tips.enabled", true);
/// <summary>
/// The dataset prototype to use when selecting a random tip.
/// </summary>
public static readonly CVarDef<string> TipsDataset =
CVarDef.Create("tips.dataset", "CP14Tips");
/// <summary>
/// The number of seconds between each tip being displayed when the round is not actively going
/// (i.e. postround or lobby)
/// </summary>
public static readonly CVarDef<float> TipFrequencyOutOfRound =
CVarDef.Create("tips.out_of_game_frequency", 60f * 1.5f);
/// <summary>
/// The number of seconds between each tip being displayed when the round is actively going
/// </summary>
public static readonly CVarDef<float> TipFrequencyInRound =
CVarDef.Create("tips.in_game_frequency", 60f * 60);
public static readonly CVarDef<string> LoginTipsDataset =
CVarDef.Create("tips.login_dataset", "Tips");
/// <summary>
/// The chance for Tippy to replace a normal tip message.
/// </summary>
public static readonly CVarDef<float> TipsTippyChance =
CVarDef.Create("tips.tippy_chance", 0.01f);
}

View File

@@ -0,0 +1,33 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
public static readonly CVarDef<bool> ViewportStretch =
CVarDef.Create("viewport.stretch", true, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<int> ViewportFixedScaleFactor =
CVarDef.Create("viewport.fixed_scale_factor", 2, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<int> ViewportSnapToleranceMargin =
CVarDef.Create("viewport.snap_tolerance_margin", 64, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<int> ViewportSnapToleranceClip =
CVarDef.Create("viewport.snap_tolerance_clip", 32, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<bool> ViewportScaleRender =
CVarDef.Create("viewport.scale_render", true, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<int> ViewportMinimumWidth =
CVarDef.Create("viewport.minimum_width", 15, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<int> ViewportMaximumWidth =
CVarDef.Create("viewport.maximum_width", 21, CVar.REPLICATED | CVar.SERVER);
public static readonly CVarDef<int> ViewportWidth =
CVarDef.Create("viewport.width", 21, CVar.CLIENTONLY | CVar.ARCHIVE);
public static readonly CVarDef<bool> ViewportVerticalFit =
CVarDef.Create("viewport.vertical_fit", true, CVar.CLIENTONLY | CVar.ARCHIVE);
}

View File

@@ -0,0 +1,180 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Allows enabling/disabling player-started votes for ultimate authority
/// </summary>
public static readonly CVarDef<bool> VoteEnabled =
CVarDef.Create("vote.enabled", true, CVar.SERVERONLY);
/// <summary>
/// See vote.enabled, but specific to restart votes
/// </summary>
public static readonly CVarDef<bool> VoteRestartEnabled =
CVarDef.Create("vote.restart_enabled", true, CVar.SERVERONLY);
/// <summary>
/// Config for when the restart vote should be allowed to be called regardless with less than this amount of players.
/// </summary>
public static readonly CVarDef<int> VoteRestartMaxPlayers =
CVarDef.Create("vote.restart_max_players", 20, CVar.SERVERONLY);
/// <summary>
/// Config for when the restart vote should be allowed to be called based on percentage of ghosts.
/// </summary>
public static readonly CVarDef<int> VoteRestartGhostPercentage =
CVarDef.Create("vote.restart_ghost_percentage", 55, CVar.SERVERONLY);
/// <summary>
/// See vote.enabled, but specific to preset votes
/// </summary>
public static readonly CVarDef<bool> VotePresetEnabled =
CVarDef.Create("vote.preset_enabled", true, CVar.SERVERONLY);
/// <summary>
/// See vote.enabled, but specific to map votes
/// </summary>
public static readonly CVarDef<bool> VoteMapEnabled =
CVarDef.Create("vote.map_enabled", false, CVar.SERVERONLY);
/// <summary>
/// The required ratio of the server that must agree for a restart round vote to go through.
/// </summary>
public static readonly CVarDef<float> VoteRestartRequiredRatio =
CVarDef.Create("vote.restart_required_ratio", 0.85f, CVar.SERVERONLY);
/// <summary>
/// Whether or not to prevent the restart vote from having any effect when there is an online admin
/// </summary>
public static readonly CVarDef<bool> VoteRestartNotAllowedWhenAdminOnline =
CVarDef.Create("vote.restart_not_allowed_when_admin_online", true, CVar.SERVERONLY);
/// <summary>
/// The delay which two votes of the same type are allowed to be made by separate people, in seconds.
/// </summary>
public static readonly CVarDef<float> VoteSameTypeTimeout =
CVarDef.Create("vote.same_type_timeout", 240f, CVar.SERVERONLY);
/// <summary>
/// Sets the duration of the map vote timer.
/// </summary>
public static readonly CVarDef<int>
VoteTimerMap = CVarDef.Create("vote.timermap", 90, CVar.SERVERONLY);
/// <summary>
/// Sets the duration of the restart vote timer.
/// </summary>
public static readonly CVarDef<int>
VoteTimerRestart = CVarDef.Create("vote.timerrestart", 60, CVar.SERVERONLY);
/// <summary>
/// Sets the duration of the gamemode/preset vote timer.
/// </summary>
public static readonly CVarDef<int>
VoteTimerPreset = CVarDef.Create("vote.timerpreset", 30, CVar.SERVERONLY);
/// <summary>
/// Sets the duration of the map vote timer when ALONE.
/// </summary>
public static readonly CVarDef<int>
VoteTimerAlone = CVarDef.Create("vote.timeralone", 10, CVar.SERVERONLY);
/// <summary>
/// Allows enabling/disabling player-started votekick for ultimate authority
/// </summary>
public static readonly CVarDef<bool> VotekickEnabled =
CVarDef.Create("votekick.enabled", true, CVar.SERVERONLY);
/// <summary>
/// Config for when the votekick should be allowed to be called based on number of eligible voters.
/// </summary>
public static readonly CVarDef<int> VotekickEligibleNumberRequirement =
CVarDef.Create("votekick.eligible_number", 5, CVar.SERVERONLY);
/// <summary>
/// Whether a votekick initiator must be a ghost or not.
/// </summary>
public static readonly CVarDef<bool> VotekickInitiatorGhostRequirement =
CVarDef.Create("votekick.initiator_ghost_requirement", true, CVar.SERVERONLY);
/// <summary>
/// Should the initiator be whitelisted to initiate a votekick?
/// </summary>
public static readonly CVarDef<bool> VotekickInitiatorWhitelistedRequirement =
CVarDef.Create("votekick.initiator_whitelist_requirement", true, CVar.SERVERONLY);
/// <summary>
/// Should the initiator be able to start a votekick if they are bellow the votekick.voter_playtime requirement?
/// </summary>
public static readonly CVarDef<bool> VotekickInitiatorTimeRequirement =
CVarDef.Create("votekick.initiator_time_requirement", false, CVar.SERVERONLY);
/// <summary>
/// Whether a votekick voter must be a ghost or not.
/// </summary>
public static readonly CVarDef<bool> VotekickVoterGhostRequirement =
CVarDef.Create("votekick.voter_ghost_requirement", true, CVar.SERVERONLY);
/// <summary>
/// Config for how many hours playtime a player must have to be able to vote on a votekick.
/// </summary>
public static readonly CVarDef<int> VotekickEligibleVoterPlaytime =
CVarDef.Create("votekick.voter_playtime", 100, CVar.SERVERONLY);
/// <summary>
/// Config for how many seconds a player must have been dead to initiate a votekick / be able to vote on a votekick.
/// </summary>
public static readonly CVarDef<int> VotekickEligibleVoterDeathtime =
CVarDef.Create("votekick.voter_deathtime", 30, CVar.REPLICATED | CVar.SERVER);
/// <summary>
/// The required ratio of eligible voters that must agree for a votekick to go through.
/// </summary>
public static readonly CVarDef<float> VotekickRequiredRatio =
CVarDef.Create("votekick.required_ratio", 0.6f, CVar.SERVERONLY);
/// <summary>
/// Whether or not to prevent the votekick from having any effect when there is an online admin.
/// </summary>
public static readonly CVarDef<bool> VotekickNotAllowedWhenAdminOnline =
CVarDef.Create("votekick.not_allowed_when_admin_online", true, CVar.SERVERONLY);
/// <summary>
/// The delay for which two votekicks are allowed to be made by separate people, in seconds.
/// </summary>
public static readonly CVarDef<float> VotekickTimeout =
CVarDef.Create("votekick.timeout", 120f, CVar.SERVERONLY);
/// <summary>
/// Sets the duration of the votekick vote timer.
/// </summary>
public static readonly CVarDef<int>
VotekickTimer = CVarDef.Create("votekick.timer", 60, CVar.SERVERONLY);
/// <summary>
/// Config for how many hours playtime a player must have to get protection from the Raider votekick type when playing as an antag.
/// </summary>
public static readonly CVarDef<int> VotekickAntagRaiderProtection =
CVarDef.Create("votekick.antag_raider_protection", 10, CVar.SERVERONLY);
/// <summary>
/// Default severity for votekick bans
/// </summary>
public static readonly CVarDef<string> VotekickBanDefaultSeverity =
CVarDef.Create("votekick.ban_default_severity", "High", CVar.ARCHIVE | CVar.SERVER | CVar.REPLICATED);
/// <summary>
/// Duration of a ban caused by a votekick (in minutes).
/// </summary>
public static readonly CVarDef<int> VotekickBanDuration =
CVarDef.Create("votekick.ban_duration", 180, CVar.SERVERONLY);
/// <summary>
/// Whether the ghost requirement settings for votekicks should be ignored for the lobby.
/// </summary>
public static readonly CVarDef<bool> VotekickIgnoreGhostReqInLobby =
CVarDef.Create("votekick.ignore_ghost_req_in_lobby", true, CVar.SERVERONLY);
}

View File

@@ -0,0 +1,19 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Controls whether the server will deny any players that are not whitelisted in the DB.
/// </summary>
public static readonly CVarDef<bool> WhitelistEnabled =
CVarDef.Create("whitelist.enabled", false, CVar.SERVERONLY);
/// <summary>
/// Specifies the whitelist prototypes to be used by the server. This should be a comma-separated list of prototypes.
/// If a whitelists conditions to be active fail (for example player count), the next whitelist will be used instead. If no whitelist is valid, the player will be allowed to connect.
/// </summary>
public static readonly CVarDef<string> WhitelistPrototypeList =
CVarDef.Create("whitelist.prototype_list", "basicWhitelist", CVar.SERVERONLY);
}

View File

@@ -0,0 +1,18 @@
using Robust.Shared.Configuration;
namespace Content.Shared.CCVar;
public sealed partial class CCVars
{
/// <summary>
/// Whether or not world generation is enabled.
/// </summary>
public static readonly CVarDef<bool> WorldgenEnabled =
CVarDef.Create("worldgen.enabled", false, CVar.SERVERONLY);
/// <summary>
/// The worldgen config to use.
/// </summary>
public static readonly CVarDef<string> WorldgenConfig =
CVarDef.Create("worldgen.worldgen_config", "Default", CVar.SERVERONLY);
}

File diff suppressed because it is too large Load Diff

View File

@@ -17,4 +17,7 @@ public sealed class CartridgeUiMessage : BoundUserInterfaceMessage
public abstract class CartridgeMessageEvent : EntityEventArgs
{
public NetEntity LoaderUid;
[NonSerialized]
public EntityUid Actor;
}

View File

@@ -11,11 +11,6 @@ public sealed partial class HyposprayComponent : Component
[DataField]
public string SolutionName = "hypospray";
// TODO: This should be on clumsycomponent.
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public float ClumsyFailChance = 0.5f;
[DataField]
[ViewVariables(VVAccess.ReadWrite)]
public FixedPoint2 TransferAmount = FixedPoint2.New(5);

View File

@@ -45,6 +45,15 @@ public sealed partial class InjectorComponent : Component
[DataField]
public bool IgnoreMobs;
/// <summary>
/// Whether or not the injector is able to draw from or inject into containers that are closed/sealed
/// </summary>
/// <remarks>
/// for example: droppers can not inject into cans, but syringes can
/// </remarks>
[DataField]
public bool IgnoreClosed = true;
/// <summary>
/// The minimum amount of solution that can be transferred at once from this solution.
/// </summary>

View File

@@ -0,0 +1,38 @@
using Content.Shared.Inventory;
namespace Content.Shared.Chemistry.Hypospray.Events;
public abstract partial class BeforeHyposprayInjectsTargetEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public EntityUid EntityUsingHypospray;
public readonly EntityUid Hypospray;
public EntityUid TargetGettingInjected;
public string? InjectMessageOverride;
public BeforeHyposprayInjectsTargetEvent(EntityUid user, EntityUid hypospray, EntityUid target)
{
EntityUsingHypospray = user;
Hypospray = hypospray;
TargetGettingInjected = target;
InjectMessageOverride = null;
}
}
/// <summary>
/// This event is raised on the user using the hypospray before the hypospray is injected.
/// The event is triggered on the user and all their clothing.
/// </summary>
public sealed class SelfBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
{
public SelfBeforeHyposprayInjectsEvent(EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
}
/// <summary>
/// This event is raised on the target before the hypospray is injected.
/// The event is triggered on the target itself and all its clothing.
/// </summary>
public sealed class TargetBeforeHyposprayInjectsEvent : BeforeHyposprayInjectsTargetEvent
{
public TargetBeforeHyposprayInjectsEvent (EntityUid user, EntityUid hypospray, EntityUid target) : base(user, hypospray, target) { }
}

View File

@@ -1,5 +1,4 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Climbing.Components;
@@ -8,39 +7,18 @@ namespace Content.Shared.Climbing.Components;
/// Makes entity do damage and stun entities with ClumsyComponent
/// upon DragDrop or Climb interactions.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(Systems.BonkSystem))]
[RegisterComponent, NetworkedComponent]
public sealed partial class BonkableComponent : Component
{
/// <summary>
/// Chance of bonk triggering if the user is clumsy.
/// How long to stun players on bonk, in seconds.
/// </summary>
[DataField("bonkClumsyChance")]
public float BonkClumsyChance = 0.5f;
[DataField]
public TimeSpan BonkTime = TimeSpan.FromSeconds(2);
/// <summary>
/// Sound to play when bonking.
/// How much damage to apply on bonk.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkSound")]
public SoundSpecifier? BonkSound;
/// <summary>
/// How long to stun players on bonk, in seconds.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkTime")]
public float BonkTime = 2;
/// <summary>
/// How much damage to apply on bonk.
/// </summary>
/// <seealso cref="Bonk"/>
[DataField("bonkDamage")]
[DataField]
public DamageSpecifier? BonkDamage;
/// <summary>
/// How long it takes to bonk.
/// </summary>
[DataField("bonkDelay")]
public float BonkDelay = 1.5f;
}

View File

@@ -0,0 +1,36 @@
using Content.Shared.Inventory;
using Content.Shared.Climbing.Components;
namespace Content.Shared.Climbing.Events;
public abstract partial class BeforeClimbEvent : CancellableEntityEventArgs
{
public readonly EntityUid GettingPutOnTable;
public readonly EntityUid PuttingOnTable;
public readonly Entity<ClimbableComponent> BeingClimbedOn;
public BeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn)
{
GettingPutOnTable = gettingPutOntable;
PuttingOnTable = puttingOnTable;
BeingClimbedOn = beingClimbedOn;
}
}
/// <summary>
/// This event is raised on the the person either getting put on or going on the table.
/// The event is also called on their clothing as well.
/// </summary>
public sealed class SelfBeforeClimbEvent : BeforeClimbEvent, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public SelfBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
}
/// <summary>
/// This event is raised on the thing being climbed on.
/// </summary>
public sealed class TargetBeforeClimbEvent : BeforeClimbEvent
{
public TargetBeforeClimbEvent(EntityUid gettingPutOntable, EntityUid puttingOnTable, Entity<ClimbableComponent> beingClimbedOn) : base(gettingPutOntable, puttingOnTable, beingClimbedOn) { }
}

View File

@@ -1,130 +0,0 @@
using Content.Shared.CCVar;
using Content.Shared.Climbing.Components;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.DragDrop;
using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Player;
using Robust.Shared.Serialization;
namespace Content.Shared.Climbing.Systems;
public sealed partial class BonkSystem : EntitySystem
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly DamageableSystem _damageableSystem = default!;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly SharedStunSystem _stunSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BonkableComponent, BonkDoAfterEvent>(OnBonkDoAfter);
SubscribeLocalEvent<BonkableComponent, AttemptClimbEvent>(OnAttemptClimb);
}
private void OnBonkDoAfter(EntityUid uid, BonkableComponent component, BonkDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Used == null)
return;
TryBonk(args.Args.Used.Value, uid, component, source: args.Args.User);
args.Handled = true;
}
public bool TryBonk(EntityUid user, EntityUid bonkableUid, BonkableComponent? bonkableComponent = null, EntityUid? source = null)
{
if (!Resolve(bonkableUid, ref bonkableComponent, false))
return false;
// BONK!
var userName = Identity.Entity(user, EntityManager);
var bonkableName = Identity.Entity(bonkableUid, EntityManager);
if (user == source)
{
// Non-local, non-bonking players
var othersMessage = Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName));
// Local, bonking player
var selfMessage = Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName));
_popupSystem.PopupPredicted(selfMessage, othersMessage, user, user);
}
else if (source != null)
{
// Local, non-bonking player (dragger)
_popupSystem.PopupClient(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, source.Value);
// Non-local, non-bonking players
_popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-others", ("user", userName), ("bonkable", bonkableName)), user, Filter.Pvs(user).RemoveWhereAttachedEntity(e => e == user || e == source.Value), true);
// Non-local, bonking player
_popupSystem.PopupEntity(Loc.GetString("bonkable-success-message-user", ("user", userName), ("bonkable", bonkableName)), user, user);
}
if (source != null)
_audioSystem.PlayPredicted(bonkableComponent.BonkSound, bonkableUid, source);
else
_audioSystem.PlayPvs(bonkableComponent.BonkSound, bonkableUid);
_stunSystem.TryParalyze(user, TimeSpan.FromSeconds(bonkableComponent.BonkTime), true);
if (bonkableComponent.BonkDamage is { } bonkDmg)
_damageableSystem.TryChangeDamage(user, bonkDmg, true, origin: user);
return true;
}
private bool TryStartBonk(EntityUid uid, EntityUid user, EntityUid climber, BonkableComponent? bonkableComponent = null)
{
if (!Resolve(uid, ref bonkableComponent, false))
return false;
if (!HasComp<ClumsyComponent>(climber) || !HasComp<HandsComponent>(user))
return false;
if (!_cfg.GetCVar(CCVars.GameTableBonk))
{
// Not set to always bonk, try clumsy roll.
if (!_interactionSystem.TryRollClumsy(climber, bonkableComponent.BonkClumsyChance))
return false;
}
var doAfterArgs = new DoAfterArgs(EntityManager, user, bonkableComponent.BonkDelay, new BonkDoAfterEvent(), uid, target: uid, used: climber)
{
BreakOnMove = true,
BreakOnDamage = true,
DuplicateCondition = DuplicateConditions.SameTool | DuplicateConditions.SameTarget
};
return _doAfter.TryStartDoAfter(doAfterArgs);
}
private void OnAttemptClimb(EntityUid uid, BonkableComponent component, ref AttemptClimbEvent args)
{
if (args.Cancelled)
return;
if (TryStartBonk(uid, args.User, args.Climber, component))
args.Cancelled = true;
}
[Serializable, NetSerializable]
private sealed partial class BonkDoAfterEvent : SimpleDoAfterEvent
{
}
}

View File

@@ -251,6 +251,18 @@ public sealed partial class ClimbSystem : VirtualController
if (!Resolve(climbable, ref comp, false))
return;
var selfEvent = new SelfBeforeClimbEvent(uid, user, (climbable, comp));
RaiseLocalEvent(uid, selfEvent);
if (selfEvent.Cancelled)
return;
var targetEvent = new TargetBeforeClimbEvent(uid, user, (climbable, comp));
RaiseLocalEvent(climbable, targetEvent);
if (targetEvent.Cancelled)
return;
if (!ReplaceFixtures(uid, climbing, fixtures))
return;

View File

@@ -33,6 +33,12 @@ public sealed partial class ToggleClothingComponent : Component
/// </summary>
[DataField]
public bool DisableOnUnequip;
/// <summary>
/// If true, the clothes must equip for adding action.
/// </summary>
[DataField]
public bool MustEquip = true;
}
/// <summary>

View File

@@ -39,8 +39,12 @@ public sealed class ToggleClothingSystem : EntitySystem
private void OnGetActions(Entity<ToggleClothingComponent> ent, ref GetItemActionsEvent args)
{
if (args.InHands && ent.Comp.MustEquip)
return;
var ev = new ToggleClothingCheckEvent(args.User);
RaiseLocalEvent(ent, ref ev);
if (!ev.Cancelled)
args.AddAction(ent.Comp.ActionEntity);
}

View File

@@ -0,0 +1,61 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Clumsy;
/// <summary>
/// A simple clumsy tag-component.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ClumsyComponent : Component
{
// Standard options. Try to fit these in if you can!
/// <summary>
/// Sound to play when clumsy interactions fail.
/// </summary>
[DataField]
public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
/// <summary>
/// Default chance to fail a clumsy interaction.
/// If a system needs to use something else, add a new variable in the component, do not modify this percentage.
/// </summary>
[DataField, AutoNetworkedField]
public float ClumsyDefaultCheck = 0.5f;
/// <summary>
/// Default stun time.
/// If a system needs to use something else, add a new variable in the component, do not modify this number.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan ClumsyDefaultStunTime = TimeSpan.FromSeconds(2.5);
// Specific options
/// <summary>
/// Sound to play after hitting your head on a table. Ouch!
/// </summary>
[DataField]
public SoundCollectionSpecifier TableBonkSound = new SoundCollectionSpecifier("TrayHit");
/// <summary>
/// Stun time after failing to shoot a gun.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan GunShootFailStunTime = TimeSpan.FromSeconds(3);
/// <summary>
/// Stun time after failing to shoot a gun.
/// </summary>
[DataField, AutoNetworkedField]
public DamageSpecifier? GunShootFailDamage;
/// <summary>
/// Noise to play after failing to shoot a gun. Boom!
/// </summary>
[DataField]
public SoundSpecifier GunShootFailSound = new SoundPathSpecifier("/Audio/Weapons/Guns/Gunshots/bang.ogg");
}

View File

@@ -0,0 +1,146 @@
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Hypospray.Events;
using Content.Shared.Climbing.Components;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.IdentityManagement;
using Content.Shared.Medical;
using Content.Shared.Popups;
using Content.Shared.Stunnable;
using Content.Shared.Weapons.Ranged.Events;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Shared.Clumsy;
public sealed class ClumsySystem : EntitySystem
{
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedStunSystem _stun = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
public override void Initialize()
{
SubscribeLocalEvent<ClumsyComponent, SelfBeforeHyposprayInjectsEvent>(BeforeHyposprayEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeDefibrillatorZapsEvent>(BeforeDefibrillatorZapsEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeGunShotEvent>(BeforeGunShotEvent);
SubscribeLocalEvent<ClumsyComponent, SelfBeforeClimbEvent>(OnBeforeClimbEvent);
}
// If you add more clumsy interactions add them in this section!
#region Clumsy interaction events
private void BeforeHyposprayEvent(Entity<ClumsyComponent> ent, ref SelfBeforeHyposprayInjectsEvent args)
{
// Clumsy people sometimes inject themselves! Apparently syringes are clumsy proof...
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
args.TargetGettingInjected = args.EntityUsingHypospray;
args.InjectMessageOverride = "hypospray-component-inject-self-clumsy-message";
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
}
private void BeforeDefibrillatorZapsEvent(Entity<ClumsyComponent> ent, ref SelfBeforeDefibrillatorZapsEvent args)
{
// Clumsy people sometimes defib themselves!
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
args.DefibTarget = args.EntityUsingDefib;
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
}
private void BeforeGunShotEvent(Entity<ClumsyComponent> ent, ref SelfBeforeGunShotEvent args)
{
// Clumsy people sometimes can't shoot :(
if (args.Gun.Comp.ClumsyProof)
return;
if (!_random.Prob(ent.Comp.ClumsyDefaultCheck))
return;
if (ent.Comp.GunShootFailDamage != null)
_damageable.TryChangeDamage(ent, ent.Comp.GunShootFailDamage, origin: ent);
_stun.TryParalyze(ent, ent.Comp.GunShootFailStunTime, true);
// Apply salt to the wound ("Honk!") (No idea what this comment means)
_audio.PlayPvs(ent.Comp.GunShootFailSound, ent);
_audio.PlayPvs(ent.Comp.ClumsySound, ent);
_popup.PopupEntity(Loc.GetString("gun-clumsy"), ent, ent);
args.Cancel();
}
private void OnBeforeClimbEvent(Entity<ClumsyComponent> ent, ref SelfBeforeClimbEvent args)
{
// This event is called in shared, thats why it has all the extra prediction stuff.
var rand = new System.Random((int)_timing.CurTick.Value);
// If someone is putting you on the table, always get past the guard.
if (!_cfg.GetCVar(CCVars.GameTableBonk) && args.PuttingOnTable == ent.Owner && !rand.Prob(ent.Comp.ClumsyDefaultCheck))
return;
HitHeadClumsy(ent, args.BeingClimbedOn);
_audio.PlayPredicted(ent.Comp.ClumsySound, ent, ent);
_audio.PlayPredicted(ent.Comp.TableBonkSound, ent, ent);
var gettingPutOnTableName = Identity.Entity(args.GettingPutOnTable, EntityManager);
var puttingOnTableName = Identity.Entity(args.PuttingOnTable, EntityManager);
if (args.PuttingOnTable == ent.Owner)
{
// You are slamming yourself onto the table.
_popup.PopupPredicted(
Loc.GetString("bonkable-success-message-user", ("bonkable", args.BeingClimbedOn)),
Loc.GetString("bonkable-success-message-others", ("victim", gettingPutOnTableName), ("bonkable", args.BeingClimbedOn)),
ent,
ent);
}
else
{
// Someone else slamed you onto the table.
// This is only run in server so you need to use popup entity.
_popup.PopupPredicted(
Loc.GetString("forced-bonkable-success-message",
("bonker", puttingOnTableName),
("victim", gettingPutOnTableName),
("bonkable", args.BeingClimbedOn)),
ent,
null);
}
args.Cancel();
}
#endregion
#region Helper functions
/// <summary>
/// "Hits" an entites head against the given table.
/// </summary>
// Oh this fucntion is public le- NO!! This is only public for the one admin command if you use this anywhere else I will cry.
public void HitHeadClumsy(Entity<ClumsyComponent> target, EntityUid table)
{
var stunTime = target.Comp.ClumsyDefaultStunTime;
if (TryComp<BonkableComponent>(table, out var bonkComp))
{
stunTime = bonkComp.BonkTime;
if (bonkComp.BonkDamage != null)
_damageable.TryChangeDamage(target, bonkComp.BonkDamage, true);
}
_stun.TryParalyze(target, stunTime, true);
}
#endregion
}

View File

@@ -3,12 +3,23 @@ using Robust.Shared.Serialization;
namespace Content.Shared.Crayon
{
/// <summary>
/// Component holding the state of a crayon-like component
/// </summary>
[NetworkedComponent, ComponentProtoName("Crayon"), Access(typeof(SharedCrayonSystem))]
public abstract partial class SharedCrayonComponent : Component
{
/// <summary>
/// The ID of currently selected decal prototype that will be placed when the crayon is used
/// </summary>
public string SelectedState { get; set; } = string.Empty;
[DataField("color")] public Color Color;
/// <summary>
/// Color with which the crayon will draw
/// </summary>
[DataField("color")]
public Color Color;
[Serializable, NetSerializable]
public enum CrayonUiKey : byte
@@ -17,6 +28,9 @@ namespace Content.Shared.Crayon
}
}
/// <summary>
/// Used by the client to notify the server about the selected decal ID
/// </summary>
[Serializable, NetSerializable]
public sealed class CrayonSelectMessage : BoundUserInterfaceMessage
{
@@ -27,6 +41,9 @@ namespace Content.Shared.Crayon
}
}
/// <summary>
/// Sets the color of the crayon, used by Rainbow Crayon
/// </summary>
[Serializable, NetSerializable]
public sealed class CrayonColorMessage : BoundUserInterfaceMessage
{
@@ -37,13 +54,25 @@ namespace Content.Shared.Crayon
}
}
/// <summary>
/// Server to CLIENT. Notifies the BUI that a decal with given ID has been drawn.
/// Allows the client UI to advance forward in the client-only ephemeral queue,
/// preventing the crayon from becoming a magic text storage device.
/// </summary>
[Serializable, NetSerializable]
public enum CrayonVisuals
public sealed class CrayonUsedMessage : BoundUserInterfaceMessage
{
State,
Color
public readonly string DrawnDecal;
public CrayonUsedMessage(string drawn)
{
DrawnDecal = drawn;
}
}
/// <summary>
/// Component state, describes how many charges are left in the crayon in the near-hand UI
/// </summary>
[Serializable, NetSerializable]
public sealed class CrayonComponentState : ComponentState
{
@@ -60,10 +89,17 @@ namespace Content.Shared.Crayon
Capacity = capacity;
}
}
/// <summary>
/// The state of the crayon UI as sent by the server
/// </summary>
[Serializable, NetSerializable]
public sealed class CrayonBoundUserInterfaceState : BoundUserInterfaceState
{
public string Selected;
/// <summary>
/// Whether or not the color can be selected
/// </summary>
public bool SelectableColor;
public Color Color;

View File

@@ -61,6 +61,12 @@ public sealed class DamageExamineSystem : EntitySystem
}
else
{
if (damageSpecifier.GetTotal() == FixedPoint2.Zero && !damageSpecifier.AnyPositive())
{
msg.AddMarkupOrThrow(Loc.GetString("damage-none"));
return msg;
}
msg.AddMarkupOrThrow(Loc.GetString("damage-examine-type", ("type", type)));
}

View File

@@ -96,6 +96,13 @@ public sealed class EmagSystem : EntitySystem
}
}
/// <summary>
/// Shows a popup to emag user (client side only!) and adds <see cref="EmaggedComponent"/> to the entity when handled
/// </summary>
/// <param name="UserUid">Emag user</param>
/// <param name="Handled">Did the emagging succeed? Causes a user-only popup to show on client side</param>
/// <param name="Repeatable">Can the entity be emagged more than once? Prevents adding of <see cref="EmaggedComponent"/></param>
/// <remarks>Needs to be handled in shared/client, not just the server, to actually show the emagging popup</remarks>
[ByRefEvent]
public record struct GotEmaggedEvent(EntityUid UserUid, bool Handled = false, bool Repeatable = false);

View File

@@ -66,5 +66,5 @@ public record struct GenerateDnaEvent()
/// <summary>
/// The generated DNA.
/// </summary>
public string DNA;
public required string DNA;
}

View File

@@ -0,0 +1,33 @@
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Player;
namespace Content.Shared.GameTicking;
/// <summary>
/// Event raised broadcast before a player is spawned by the GameTicker.
/// You can use this event to spawn a player off-station on late-join but also at round start.
/// When this event is handled, the GameTicker will not perform its own player-spawning logic.
/// </summary>
[PublicAPI]
public sealed class PlayerBeforeSpawnEvent : HandledEntityEventArgs
{
public ICommonSession Player { get; }
public HumanoidCharacterProfile Profile { get; }
public string? JobId { get; }
public bool LateJoin { get; }
public EntityUid Station { get; }
public PlayerBeforeSpawnEvent(ICommonSession player,
HumanoidCharacterProfile profile,
string? jobId,
bool lateJoin,
EntityUid station)
{
Player = player;
Profile = profile;
JobId = jobId;
LateJoin = lateJoin;
Station = station;
}
}

View File

@@ -0,0 +1,44 @@
using Content.Shared.Preferences;
using JetBrains.Annotations;
using Robust.Shared.Player;
namespace Content.Shared.GameTicking;
/// <summary>
/// Event raised both directed and broadcast when a player has been spawned by the GameTicker.
/// You can use this to handle people late-joining, or to handle people being spawned at round start.
/// Can be used to give random players a role, modify their equipment, etc.
/// </summary>
[PublicAPI]
public sealed class PlayerSpawnCompleteEvent : EntityEventArgs
{
public EntityUid Mob { get; }
public ICommonSession Player { get; }
public string? JobId { get; }
public bool LateJoin { get; }
public bool Silent { get; }
public EntityUid Station { get; }
public HumanoidCharacterProfile Profile { get; }
// Ex. If this is the 27th person to join, this will be 27.
public int JoinOrder { get; }
public PlayerSpawnCompleteEvent(EntityUid mob,
ICommonSession player,
string? jobId,
bool lateJoin,
bool silent,
int joinOrder,
EntityUid station,
HumanoidCharacterProfile profile)
{
Mob = mob;
Player = player;
JobId = jobId;
LateJoin = lateJoin;
Silent = silent;
Station = station;
Profile = profile;
JoinOrder = joinOrder;
}
}

View File

@@ -0,0 +1,39 @@
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Intellicard;
/// <summary>
/// Allows this entity to download the station AI onto an AiHolderComponent.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class IntellicardComponent : Component
{
/// <summary>
/// The duration it takes to download the AI from an AiHolder.
/// </summary>
[DataField, AutoNetworkedField]
public int DownloadTime = 15;
/// <summary>
/// The duration it takes to upload the AI to an AiHolder.
/// </summary>
[DataField, AutoNetworkedField]
public int UploadTime = 3;
/// <summary>
/// The sound that plays for the AI
/// when they are being downloaded
/// </summary>
[DataField, AutoNetworkedField]
public SoundSpecifier? WarningSound = new SoundPathSpecifier("/Audio/Misc/notice2.ogg");
/// <summary>
/// The delay before allowing the warning to play again in seconds.
/// </summary>
[DataField, AutoNetworkedField]
public TimeSpan WarningDelay = TimeSpan.FromSeconds(8);
[ViewVariables]
public TimeSpan NextWarningAllowed = TimeSpan.Zero;
}

View File

@@ -1,24 +0,0 @@
using Content.Shared.Damage;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
namespace Content.Shared.Interaction.Components;
/// <summary>
/// A simple clumsy tag-component.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ClumsyComponent : Component
{
/// <summary>
/// Damage dealt to a clumsy character when they try to fire a gun.
/// </summary>
[DataField(required: true), AutoNetworkedField]
public DamageSpecifier ClumsyDamage = default!;
/// <summary>
/// Sound to play when clumsy interactions fail.
/// </summary>
[DataField]
public SoundSpecifier ClumsySound = new SoundPathSpecifier("/Audio/Items/bikehorn.ogg");
}

View File

@@ -159,4 +159,26 @@ public sealed class InteractionPopupSystem : EntitySystem
_audio.PlayEntity(sfx, Filter.Empty().FromEntities(target), target, false);
}
}
/// <summary>
/// Sets <see cref="InteractionPopupComponent.InteractSuccessString"/>.
/// </summary>
/// <para>
/// This field is not networked automatically, so this method must be called on both sides of the network.
/// </para>
public void SetInteractSuccessString(Entity<InteractionPopupComponent> ent, string str)
{
ent.Comp.InteractSuccessString = str;
}
/// <summary>
/// Sets <see cref="InteractionPopupComponent.InteractFailureString"/>.
/// </summary>
/// <para>
/// This field is not networked automatically, so this method must be called on both sides of the network.
/// </para>
public void SetInteractFailureString(Entity<InteractionPopupComponent> ent, string str)
{
ent.Comp.InteractFailureString = str;
}
}

View File

@@ -1,26 +0,0 @@
using Content.Shared.Interaction.Components;
using Robust.Shared.Random;
namespace Content.Shared.Interaction
{
public partial class SharedInteractionSystem
{
public bool RollClumsy(ClumsyComponent component, float chance)
{
return component.Running && _random.Prob(chance);
}
/// <summary>
/// Rolls a probability chance for a "bad action" if the target entity is clumsy.
/// </summary>
/// <param name="entity">The entity that the clumsy check is happening for.</param>
/// <param name="chance">
/// The chance that a "bad action" happens if the user is clumsy, between 0 and 1 inclusive.
/// </param>
/// <returns>True if a "bad action" happened, false if the normal action should happen.</returns>
public bool TryRollClumsy(EntityUid entity, float chance, ClumsyComponent? component = null)
{
return Resolve(entity, ref component, false) && RollClumsy(component, chance);
}
}
}

View File

@@ -21,6 +21,7 @@ using Content.Shared.Physics;
using Content.Shared.Players.RateLimiting;
using Content.Shared.Popups;
using Content.Shared.Storage;
using Content.Shared.Strip;
using Content.Shared.Tag;
using Content.Shared.Timing;
using Content.Shared.UserInterface;
@@ -67,6 +68,7 @@ namespace Content.Shared.Interaction
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _ui = default!;
[Dependency] private readonly SharedStrippableSystem _strippable = default!;
[Dependency] private readonly SharedPlayerRateLimitManager _rateLimit = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ISharedChatManager _chat = default!;
@@ -1321,7 +1323,7 @@ namespace Content.Shared.Interaction
if (wearer == user)
return true;
if (slotDef.StripHidden)
if (_strippable.IsStripHidden(slotDef, user))
return false;
return InRangeUnobstructed(user, wearer) && _containerSystem.IsInSameOrParentContainer(user, wearer);

View File

@@ -7,10 +7,12 @@ namespace Content.Shared.Inventory;
[RegisterComponent, NetworkedComponent]
[Access(typeof(InventorySystem))]
[AutoGenerateComponentState(true)]
public sealed partial class InventoryComponent : Component
{
[DataField("templateId", customTypeSerializer: typeof(PrototypeIdSerializer<InventoryTemplatePrototype>))]
public string TemplateId { get; private set; } = "human";
[AutoNetworkedField]
public string TemplateId { get; set; } = "human";
[DataField("speciesId")] public string? SpeciesId { get; set; }
@@ -32,3 +34,9 @@ public sealed partial class InventoryComponent : Component
[DataField]
public Dictionary<string, DisplacementData> MaleDisplacements = new();
}
/// <summary>
/// Raised if the <see cref="InventoryComponent.TemplateId"/> of an inventory changed.
/// </summary>
[ByRefEvent]
public struct InventoryTemplateUpdated;

View File

@@ -10,6 +10,7 @@ using Content.Shared.Inventory.Events;
using Content.Shared.Item;
using Content.Shared.Movement.Systems;
using Content.Shared.Popups;
using Content.Shared.Strip;
using Content.Shared.Strip.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Audio.Systems;
@@ -32,6 +33,7 @@ public abstract partial class InventorySystem
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly SharedStrippableSystem _strippable = default!;
[ValidatePrototypeId<ItemSizePrototype>]
private const string PocketableItemSize = "Small";

View File

@@ -1,6 +1,9 @@
using Content.Shared._CP14.MagicEnergy;
using Content.Shared._CP14.MagicSpell.Events;
using Content.Shared.Chat;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Hypospray.Events;
using Content.Shared.Climbing.Events;
using Content.Shared.Damage;
using Content.Shared.Electrocution;
using Content.Shared.Explosion;
@@ -17,7 +20,7 @@ using Content.Shared.Slippery;
using Content.Shared.Strip.Components;
using Content.Shared.Temperature;
using Content.Shared.Verbs;
using Content.Shared.Chat;
using Content.Shared.Weapons.Ranged.Events;
namespace Content.Shared.Inventory;
@@ -41,6 +44,10 @@ public partial class InventorySystem
SubscribeLocalEvent<InventoryComponent, GetDefaultRadioChannelEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, RefreshNameModifiersEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TransformSpeakerNameEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, TargetBeforeHyposprayInjectsEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeGunShotEvent>(RelayInventoryEvent);
SubscribeLocalEvent<InventoryComponent, SelfBeforeClimbEvent>(RelayInventoryEvent);
// by-ref events
SubscribeLocalEvent<InventoryComponent, GetExplosionResistanceEvent>(RefRelayInventoryEvent);
@@ -115,7 +122,7 @@ public partial class InventorySystem
var enumerator = new InventorySlotEnumerator(component);
while (enumerator.NextItem(out var item, out var slotDef))
{
if (!slotDef.StripHidden || args.User == uid)
if (!_strippable.IsStripHidden(slotDef, args.User) || args.User == uid)
RaiseLocalEvent(item, ev);
}
}

View File

@@ -1,4 +1,5 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Shared.Inventory.Events;
using Content.Shared.Storage;
using Robust.Shared.Containers;
@@ -19,6 +20,8 @@ public partial class InventorySystem : EntitySystem
_vvm.GetTypeHandler<InventoryComponent>()
.AddHandler(HandleViewVariablesSlots, ListViewVariablesSlots);
SubscribeLocalEvent<InventoryComponent, AfterAutoHandleStateEvent>(AfterAutoState);
}
private void ShutdownSlots()
@@ -68,6 +71,27 @@ public partial class InventorySystem : EntitySystem
}
}
private void AfterAutoState(Entity<InventoryComponent> ent, ref AfterAutoHandleStateEvent args)
{
UpdateInventoryTemplate(ent);
}
protected virtual void UpdateInventoryTemplate(Entity<InventoryComponent> ent)
{
if (ent.Comp.LifeStage < ComponentLifeStage.Initialized)
return;
if (!_prototypeManager.TryIndex(ent.Comp.TemplateId, out InventoryTemplatePrototype? invTemplate))
return;
DebugTools.Assert(ent.Comp.Slots.Length == invTemplate.Slots.Length);
ent.Comp.Slots = invTemplate.Slots;
var ev = new InventoryTemplateUpdated();
RaiseLocalEvent(ent, ref ev);
}
private void OnOpenSlotStorage(OpenSlotStorageNetworkMessage ev, EntitySessionEventArgs args)
{
if (args.SenderSession.AttachedEntity is not { Valid: true } uid)
@@ -170,6 +194,31 @@ public partial class InventorySystem : EntitySystem
}
}
/// <summary>
/// Change the inventory template ID an entity is using. The new template must be compatible.
/// </summary>
/// <remarks>
/// <para>
/// For an inventory template to be compatible with another, it must have exactly the same slot names.
/// All other changes are rejected.
/// </para>
/// </remarks>
/// <param name="ent">The entity to update.</param>
/// <param name="newTemplate">The ID of the new inventory template prototype.</param>
/// <exception cref="ArgumentException">
/// Thrown if the new template is not compatible with the existing one.
/// </exception>
public void SetTemplateId(Entity<InventoryComponent> ent, ProtoId<InventoryTemplatePrototype> newTemplate)
{
var newPrototype = _prototypeManager.Index(newTemplate);
if (!newPrototype.Slots.Select(x => x.Name).SequenceEqual(ent.Comp.Slots.Select(x => x.Name)))
throw new ArgumentException("Incompatible inventory template!");
ent.Comp.TemplateId = newTemplate;
Dirty(ent);
}
/// <summary>
/// Enumerator for iterating over an inventory's slot containers. Also has methods that skip empty containers.
/// It should be safe to add or remove items while enumerating.

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Content.Shared.Strip;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
@@ -39,6 +40,10 @@ public sealed partial class SlotDefinition
[DataField("displayName", required: true)]
public string DisplayName { get; private set; } = string.Empty;
/// <summary>
/// Whether or not this slot will have its item hidden in the strip menu, and block interactions.
/// <seealso cref="SharedStrippableSystem.IsStripHidden"/>
/// </summary>
[DataField("stripHidden")] public bool StripHidden { get; private set; }
/// <summary>

View File

@@ -32,6 +32,18 @@ public sealed partial class ItemToggleComponent : Component
[DataField]
public bool OnUse = true;
/// <summary>
/// The localized text to display in the verb to activate.
/// </summary>
[DataField]
public string VerbToggleOn = "item-toggle-activate";
/// <summary>
/// The localized text to display in the verb to de-activate.
/// </summary>
[DataField]
public string VerbToggleOff = "item-toggle-deactivate";
/// <summary>
/// Whether the item's toggle can be predicted by the client.
/// </summary>

View File

@@ -1,18 +0,0 @@
using Content.Shared.Item.ItemToggle;
using Robust.Shared.GameStates;
namespace Content.Shared.Item.ItemToggle.Components;
/// <summary>
/// Adds a verb for toggling something, requires <see cref="ItemToggleComponent"/>.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(ToggleVerbSystem))]
public sealed partial class ToggleVerbComponent : Component
{
/// <summary>
/// Text the verb will have.
/// Gets passed "entity" as the entity's identity string.
/// </summary>
[DataField(required: true)]
public LocId Text = string.Empty;
}

View File

@@ -78,7 +78,7 @@ public sealed class ItemToggleSystem : EntitySystem
args.Verbs.Add(new ActivationVerb()
{
Text = !ent.Comp.Activated ? Loc.GetString("item-toggle-activate") : Loc.GetString("item-toggle-deactivate"),
Text = !ent.Comp.Activated ? Loc.GetString(ent.Comp.VerbToggleOn) : Loc.GetString(ent.Comp.VerbToggleOff),
Act = () =>
{
Toggle((ent.Owner, ent.Comp), user, predicted: ent.Comp.Predictable);

View File

@@ -1,34 +0,0 @@
using Content.Shared.IdentityManagement;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.Verbs;
namespace Content.Shared.Item.ItemToggle;
/// <summary>
/// Adds a verb for toggling something with <see cref="ToggleVerbComponent"/>.
/// </summary>
public sealed class ToggleVerbSystem : EntitySystem
{
[Dependency] private readonly ItemToggleSystem _toggle = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ToggleVerbComponent, GetVerbsEvent<ActivationVerb>>(OnGetVerbs);
}
private void OnGetVerbs(Entity<ToggleVerbComponent> ent, ref GetVerbsEvent<ActivationVerb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
var name = Identity.Entity(ent, EntityManager);
var user = args.User;
args.Verbs.Add(new ActivationVerb()
{
Text = Loc.GetString(ent.Comp.Text, ("entity", name)),
Act = () => _toggle.Toggle(ent.Owner, user)
});
}
}

View File

@@ -0,0 +1,26 @@
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
namespace Content.Shared.Jaunt;
/// <summary>
/// Used to control various aspects of a Jaunt.
/// Can be used in place of giving a jaunt-action directly.
/// </summary>
[RegisterComponent, NetworkedComponent]
public sealed partial class JauntComponent : Component
{
/// <summary>
/// Which Jaunt Action the component should grant.
/// </summary>
[DataField]
public EntProtoId JauntAction = "ActionPolymorphJaunt";
/// <summary>
/// The jaunt action itself.
/// </summary>
public EntityUid? Action;
// TODO: Enter & Exit Times and Whitelist when Actions are reworked and can support it
// TODO: Cooldown pausing when Actions can support it
}

View File

@@ -0,0 +1,26 @@
using Content.Shared.Actions;
namespace Content.Shared.Jaunt;
public sealed class JauntSystem : EntitySystem
{
[Dependency] private readonly SharedActionsSystem _actions = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<JauntComponent, MapInitEvent>(OnInit);
SubscribeLocalEvent<JauntComponent, ComponentShutdown>(OnShutdown);
}
private void OnInit(Entity<JauntComponent> ent, ref MapInitEvent args)
{
_actions.AddAction(ent.Owner, ref ent.Comp.Action, ent.Comp.JauntAction);
}
private void OnShutdown(Entity<JauntComponent> ent, ref ComponentShutdown args)
{
_actions.RemoveAction(ent.Owner, ent.Comp.Action);
}
}

View File

@@ -0,0 +1,23 @@
using Content.Shared.Actions;
using Content.Shared.Storage;
using Robust.Shared.Audio;
namespace Content.Shared.Magic.Events;
public sealed partial class RandomGlobalSpawnSpellEvent : InstantActionEvent, ISpeakSpell
{
/// <summary>
/// The list of prototypes this spell can spawn, will select one randomly
/// </summary>
[DataField]
public List<EntitySpawnEntry> Spawns = new();
/// <summary>
/// Sound that will play globally when cast
/// </summary>
[DataField]
public SoundSpecifier Sound = new SoundPathSpecifier("/Audio/Magic/staff_animation.ogg");
[DataField]
public string? Speech { get; private set; }
}

View File

@@ -1,4 +1,4 @@
using System.Numerics;
using System.Numerics;
using Content.Shared.Actions;
using Content.Shared.Body.Components;
using Content.Shared.Body.Systems;
@@ -7,12 +7,17 @@ using Content.Shared.Doors.Components;
using Content.Shared.Doors.Systems;
using Content.Shared.Hands.Components;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Humanoid;
using Content.Shared.Interaction;
using Content.Shared.Inventory;
using Content.Shared.Lock;
using Content.Shared.Magic.Components;
using Content.Shared.Magic.Events;
using Content.Shared.Maps;
using Content.Shared.Mind;
using Content.Shared.Mind.Components;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Physics;
using Content.Shared.Popups;
using Content.Shared.Speech.Muting;
@@ -20,6 +25,7 @@ using Content.Shared.Storage;
using Content.Shared.Tag;
using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Systems;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Network;
@@ -53,6 +59,9 @@ public abstract class SharedMagicSystem : EntitySystem
[Dependency] private readonly LockSystem _lock = default!;
[Dependency] private readonly SharedHandsSystem _hands = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedMindSystem _mind = default!;
public override void Initialize()
{
@@ -67,6 +76,7 @@ public abstract class SharedMagicSystem : EntitySystem
SubscribeLocalEvent<SmiteSpellEvent>(OnSmiteSpell);
SubscribeLocalEvent<KnockSpellEvent>(OnKnockSpell);
SubscribeLocalEvent<ChargeSpellEvent>(OnChargeSpell);
SubscribeLocalEvent<RandomGlobalSpawnSpellEvent>(OnRandomGlobalSpawnSpell);
// Spell wishlist
// A wishlish of spells that I'd like to implement or planning on implementing in a future PR
@@ -501,6 +511,37 @@ public abstract class SharedMagicSystem : EntitySystem
_gunSystem.UpdateBasicEntityAmmoCount(wand.Value, basicAmmoComp.Count.Value + ev.Charge, basicAmmoComp);
}
// End Charge Spells
#endregion
#region Global Spells
private void OnRandomGlobalSpawnSpell(RandomGlobalSpawnSpellEvent ev)
{
if (!_net.IsServer || ev.Handled || !PassesSpellPrerequisites(ev.Action, ev.Performer) || ev.Spawns is not { } spawns)
return;
ev.Handled = true;
Speak(ev);
var allHumans = _mind.GetAliveHumans();
foreach (var human in allHumans)
{
if (!human.Comp.OwnedEntity.HasValue)
continue;
var ent = human.Comp.OwnedEntity.Value;
var mapCoords = _transform.GetMapCoordinates(ent);
foreach (var spawn in EntitySpawnCollection.GetSpawns(spawns, _random))
{
var spawned = Spawn(spawn, mapCoords);
_hands.PickupOrDrop(ent, spawned);
}
}
_audio.PlayGlobal(ev.Sound, ev.Performer);
}
#endregion
// End Spells
#endregion

View File

@@ -0,0 +1,39 @@
using Content.Shared.Inventory;
namespace Content.Shared.Medical;
[ByRefEvent]
public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);
public abstract class BeforeDefibrillatorZapsEvent : CancellableEntityEventArgs, IInventoryRelayEvent
{
public SlotFlags TargetSlots { get; } = SlotFlags.WITHOUT_POCKET;
public EntityUid EntityUsingDefib;
public readonly EntityUid Defib;
public EntityUid DefibTarget;
public BeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibTarget)
{
EntityUsingDefib = entityUsingDefib;
Defib = defib;
DefibTarget = defibTarget;
}
}
/// <summary>
/// This event is raised on the user using the defibrillator before is actually zaps someone.
/// The event is triggered on the user and all their clothing.
/// </summary>
public sealed class SelfBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
{
public SelfBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
}
/// <summary>
/// This event is raised on the target before it gets zapped with the defibrillator.
/// The event is triggered on the target itself and all its clothing.
/// </summary>
public sealed class TargetBeforeDefibrillatorZapsEvent : BeforeDefibrillatorZapsEvent
{
public TargetBeforeDefibrillatorZapsEvent(EntityUid entityUsingDefib, EntityUid defib, EntityUid defibtarget) : base(entityUsingDefib, defib, defibtarget) { }
}

View File

@@ -1,4 +0,0 @@
namespace Content.Shared.Medical;
[ByRefEvent]
public readonly record struct TargetDefibrillatedEvent(EntityUid User, Entity<DefibrillatorComponent> Defibrillator);

View File

@@ -546,22 +546,19 @@ public abstract class SharedMindSystem : EntitySystem
/// <summary>
/// Returns a list of every living humanoid player's minds, except for a single one which is exluded.
/// </summary>
public List<EntityUid> GetAliveHumansExcept(EntityUid exclude)
public HashSet<Entity<MindComponent>> GetAliveHumans(EntityUid? exclude = null)
{
var mindQuery = EntityQuery<MindComponent>();
var allHumans = new List<EntityUid>();
var allHumans = new HashSet<Entity<MindComponent>>();
// HumanoidAppearanceComponent is used to prevent mice, pAIs, etc from being chosen
var query = EntityQueryEnumerator<MindContainerComponent, MobStateComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var uid, out var mc, out var mobState, out _))
var query = EntityQueryEnumerator<MobStateComponent, HumanoidAppearanceComponent>();
while (query.MoveNext(out var uid, out var mobState, out _))
{
// the player needs to have a mind and not be the excluded one
if (mc.Mind == null || mc.Mind == exclude)
// the player needs to have a mind and not be the excluded one +
// the player has to be alive
if (!TryGetMind(uid, out var mind, out var mindComp) || mind == exclude || !_mobState.IsAlive(uid, mobState))
continue;
// the player has to be alive
if (_mobState.IsAlive(uid, mobState))
allHumans.Add(mc.Mind.Value);
allHumans.Add(new Entity<MindComponent>(mind, mindComp));
}
return allHumans;

View File

@@ -1,4 +1,5 @@
using System.Numerics;
using Content.Shared.Alert;
using Content.Shared.CCVar;
using Content.Shared.Follower.Components;
using Content.Shared.Input;
@@ -8,6 +9,7 @@ using Robust.Shared.GameStates;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -21,6 +23,8 @@ namespace Content.Shared.Movement.Systems
{
public bool CameraRotationLocked { get; set; }
public static ProtoId<AlertPrototype> WalkingAlert = "Walking";
private void InitializeInput()
{
var moveUpCmdHandler = new MoverDirInputCmdHandler(this, Direction.North);
@@ -460,7 +464,7 @@ namespace Content.Shared.Movement.Systems
component.LastInputSubTick = 0;
}
public void SetSprinting(Entity<InputMoverComponent> entity, ushort subTick, bool walking)
public virtual void SetSprinting(Entity<InputMoverComponent> entity, ushort subTick, bool walking)
{
// Logger.Info($"[{_gameTiming.CurTick}/{subTick}] Sprint: {enabled}");

View File

@@ -9,12 +9,14 @@ namespace Content.Shared.Overlays;
/// This component allows you to see health bars above damageable mobs.
/// </summary>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(true)]
public sealed partial class ShowHealthBarsComponent : Component
{
/// <summary>
/// Displays health bars of the damage containers.
/// </summary>
[DataField]
[AutoNetworkedField]
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
{
"Biological"

View File

@@ -8,12 +8,14 @@ namespace Content.Shared.Overlays;
/// This component allows you to see health status icons above damageable mobs.
/// </summary>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(true)]
public sealed partial class ShowHealthIconsComponent : Component
{
/// <summary>
/// Displays health status icons of the damage containers.
/// </summary>
[DataField]
[AutoNetworkedField]
public List<ProtoId<DamageContainerPrototype>> DamageContainers = new()
{
"Biological"

View File

@@ -1,3 +1,4 @@
using Content.Shared.Polymorph.Systems;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
@@ -7,9 +8,22 @@ namespace Content.Shared.Polymorph.Components;
/// Component added to disguise entities.
/// Used by client to copy over appearance from the disguise's source entity.
/// </summary>
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
[RegisterComponent, NetworkedComponent, Access(typeof(SharedChameleonProjectorSystem))]
[AutoGenerateComponentState(true)]
public sealed partial class ChameleonDisguiseComponent : Component
{
/// <summary>
/// The user of this disguise.
/// </summary>
[DataField]
public EntityUid User;
/// <summary>
/// The projector that created this disguise.
/// </summary>
[DataField]
public EntityUid Projector;
/// <summary>
/// The disguise source entity for copying the sprite.
/// </summary>

View File

@@ -0,0 +1,25 @@
using Content.Shared.Polymorph.Systems;
using Robust.Shared.GameStates;
namespace Content.Shared.Polymorph.Components;
/// <summary>
/// Added to a player when they use a chameleon projector.
/// Handles making them invisible and revealing when damaged enough or switching hands.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedChameleonProjectorSystem))]
[AutoGenerateComponentState]
public sealed partial class ChameleonDisguisedComponent : Component
{
/// <summary>
/// The disguise entity parented to the player.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid Disguise;
/// <summary>
/// For client, whether the user's sprite was previously visible or not.
/// </summary>
[DataField]
public bool WasVisible;
}

View File

@@ -1,4 +1,3 @@
using Content.Shared.Polymorph;
using Content.Shared.Polymorph.Systems;
using Content.Shared.Whitelist;
using Robust.Shared.Prototypes;
@@ -25,22 +24,26 @@ public sealed partial class ChameleonProjectorComponent : Component
public EntityWhitelist? Blacklist;
/// <summary>
/// Polymorph configuration for the disguise entity.
/// Disguise entity to spawn and use.
/// </summary>
[DataField(required: true)]
public PolymorphConfiguration Polymorph = new();
public EntProtoId DisguiseProto = string.Empty;
/// <summary>
/// Action for disabling your disguise's rotation.
/// </summary>
[DataField]
public EntProtoId NoRotAction = "ActionDisguiseNoRot";
[DataField]
public EntityUid? NoRotActionEntity;
/// <summary>
/// Action for anchoring your disguise in place.
/// </summary>
[DataField]
public EntProtoId AnchorAction = "ActionDisguiseAnchor";
[DataField]
public EntityUid? AnchorActionEntity;
/// <summary>
/// Minimum health to give the disguise.
@@ -55,14 +58,8 @@ public sealed partial class ChameleonProjectorComponent : Component
public float MaxHealth = 100f;
/// <summary>
/// Popup shown to the user when they try to disguise as an invalid entity.
/// User currently disguised by this projector, if any
/// </summary>
[DataField]
public LocId InvalidPopup = "chameleon-projector-invalid";
/// <summary>
/// Popup shown to the user when they disguise as a valid entity.
/// </summary>
[DataField]
public LocId SuccessPopup = "chameleon-projector-success";
public EntityUid? Disguised;
}

View File

@@ -1,3 +1,4 @@
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Array;
@@ -115,6 +116,18 @@ public sealed partial record PolymorphConfiguration
[DataField(serverOnly: true)]
[ViewVariables(VVAccess.ReadWrite)]
public TimeSpan Cooldown = TimeSpan.Zero;
/// <summary>
/// If not null, this sound will be played when being polymorphed into something.
/// </summary>
[DataField]
public SoundSpecifier? PolymorphSound;
/// <summary>
/// If not null, this sound will be played when being reverted from a polymorph.
/// </summary>
[DataField]
public SoundSpecifier? ExitPolymorphSound;
}
public enum PolymorphInventoryChange : byte

View File

@@ -1,67 +1,264 @@
using Content.Shared.Actions;
using Content.Shared.Coordinates;
using Content.Shared.Damage;
using Content.Shared.Hands;
using Content.Shared.Interaction;
using Content.Shared.Polymorph;
using Content.Shared.Item;
using Content.Shared.Polymorph.Components;
using Content.Shared.Popups;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Prototypes;
using System.Diagnostics.CodeAnalysis;
using Content.Shared.Storage.Components;
using Content.Shared.Verbs;
using Content.Shared.Whitelist;
using Robust.Shared.Containers;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.Manager;
using System.Diagnostics.CodeAnalysis;
namespace Content.Shared.Polymorph.Systems;
/// <summary>
/// Handles whitelist/blacklist checking.
/// Actual polymorphing and deactivation is done serverside.
/// Handles disguise validation, disguising and revealing.
/// Most appearance copying is done clientside.
/// </summary>
public abstract class SharedChameleonProjectorSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageable = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelist = default!;
[Dependency] private readonly INetManager _net = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly ISerializationManager _serMan = default!;
[Dependency] private readonly MetaDataSystem _meta = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
[Dependency] private readonly SharedTransformSystem _xform = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ChameleonDisguiseComponent, InteractHandEvent>(OnDisguiseInteractHand, before: [typeof(SharedItemSystem)]);
SubscribeLocalEvent<ChameleonDisguiseComponent, DamageChangedEvent>(OnDisguiseDamaged);
SubscribeLocalEvent<ChameleonDisguiseComponent, InsertIntoEntityStorageAttemptEvent>(OnDisguiseInsertAttempt);
SubscribeLocalEvent<ChameleonDisguiseComponent, ComponentShutdown>(OnDisguiseShutdown);
SubscribeLocalEvent<ChameleonProjectorComponent, AfterInteractEvent>(OnInteract);
SubscribeLocalEvent<ChameleonProjectorComponent, GetVerbsEvent<UtilityVerb>>(OnGetVerbs);
SubscribeLocalEvent<ChameleonProjectorComponent, DisguiseToggleNoRotEvent>(OnToggleNoRot);
SubscribeLocalEvent<ChameleonProjectorComponent, DisguiseToggleAnchoredEvent>(OnToggleAnchored);
SubscribeLocalEvent<ChameleonProjectorComponent, HandDeselectedEvent>(OnDeselected);
SubscribeLocalEvent<ChameleonProjectorComponent, GotUnequippedHandEvent>(OnUnequipped);
SubscribeLocalEvent<ChameleonProjectorComponent, ComponentShutdown>(OnProjectorShutdown);
}
#region Disguise entity
private void OnDisguiseInteractHand(Entity<ChameleonDisguiseComponent> ent, ref InteractHandEvent args)
{
TryReveal(ent.Comp.User);
args.Handled = true;
}
private void OnDisguiseDamaged(Entity<ChameleonDisguiseComponent> ent, ref DamageChangedEvent args)
{
// this mirrors damage 1:1
if (args.DamageDelta is {} damage)
_damageable.TryChangeDamage(ent.Comp.User, damage);
}
private void OnDisguiseInsertAttempt(Entity<ChameleonDisguiseComponent> ent, ref InsertIntoEntityStorageAttemptEvent args)
{
// stay parented to the user, not the storage
args.Cancelled = true;
}
private void OnDisguiseShutdown(Entity<ChameleonDisguiseComponent> ent, ref ComponentShutdown args)
{
_actions.RemoveProvidedActions(ent.Comp.User, ent.Comp.Projector);
}
#endregion
#region Projector
private void OnInteract(Entity<ChameleonProjectorComponent> ent, ref AfterInteractEvent args)
{
if (!args.CanReach || args.Target is not {} target)
if (args.Handled || !args.CanReach || args.Target is not {} target)
return;
args.Handled = true;
TryDisguise(ent, args.User, target);
}
private void OnGetVerbs(Entity<ChameleonProjectorComponent> ent, ref GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess)
return;
var user = args.User;
args.Handled = true;
var target = args.Target;
args.Verbs.Add(new UtilityVerb()
{
Act = () =>
{
TryDisguise(ent, user, target);
},
Text = Loc.GetString("chameleon-projector-set-disguise")
});
}
public bool TryDisguise(Entity<ChameleonProjectorComponent> ent, EntityUid user, EntityUid target)
{
if (_container.IsEntityInContainer(target))
{
_popup.PopupClient(Loc.GetString("chameleon-projector-inside-container"), target, user);
return false;
}
if (IsInvalid(ent.Comp, target))
{
_popup.PopupClient(Loc.GetString(ent.Comp.InvalidPopup), target, user);
return;
_popup.PopupClient(Loc.GetString("chameleon-projector-invalid"), target, user);
return false;
}
_popup.PopupClient(Loc.GetString(ent.Comp.SuccessPopup), target, user);
Disguise(ent.Comp, user, target);
_popup.PopupClient(Loc.GetString("chameleon-projector-success"), target, user);
Disguise(ent, user, target);
return true;
}
private void OnToggleNoRot(Entity<ChameleonProjectorComponent> ent, ref DisguiseToggleNoRotEvent args)
{
if (ent.Comp.Disguised is not {} uid)
return;
var xform = Transform(uid);
_xform.SetLocalRotationNoLerp(uid, 0, xform);
xform.NoLocalRotation = !xform.NoLocalRotation;
args.Handled = true;
}
private void OnToggleAnchored(Entity<ChameleonProjectorComponent> ent, ref DisguiseToggleAnchoredEvent args)
{
if (ent.Comp.Disguised is not {} uid)
return;
var xform = Transform(uid);
if (xform.Anchored)
_xform.Unanchor(uid, xform);
else
_xform.AnchorEntity((uid, xform));
args.Handled = true;
}
private void OnDeselected(Entity<ChameleonProjectorComponent> ent, ref HandDeselectedEvent args)
{
RevealProjector(ent);
}
private void OnUnequipped(Entity<ChameleonProjectorComponent> ent, ref GotUnequippedHandEvent args)
{
RevealProjector(ent);
}
private void OnProjectorShutdown(Entity<ChameleonProjectorComponent> ent, ref ComponentShutdown args)
{
RevealProjector(ent);
}
#endregion
#region API
/// <summary>
/// Returns true if an entity cannot be used as a disguise.
/// </summary>
public bool IsInvalid(ChameleonProjectorComponent comp, EntityUid target)
{
return _whitelistSystem.IsWhitelistFail(comp.Whitelist, target)
|| _whitelistSystem.IsBlacklistPass(comp.Blacklist, target);
return _whitelist.IsWhitelistFail(comp.Whitelist, target)
|| _whitelist.IsBlacklistPass(comp.Blacklist, target);
}
/// <summary>
/// On server, polymorphs the user into an entity and sets up the disguise.
/// </summary>
public virtual void Disguise(ChameleonProjectorComponent comp, EntityUid user, EntityUid entity)
public void Disguise(Entity<ChameleonProjectorComponent> ent, EntityUid user, EntityUid entity)
{
var proj = ent.Comp;
// no spawning prediction sorry
if (_net.IsClient)
return;
// reveal first to allow quick switching
TryReveal(user);
// add actions for controlling transform aspects
_actions.AddAction(user, ref proj.NoRotActionEntity, proj.NoRotAction, container: ent);
_actions.AddAction(user, ref proj.AnchorActionEntity, proj.AnchorAction, container: ent);
proj.Disguised = user;
var disguise = SpawnAttachedTo(proj.DisguiseProto, user.ToCoordinates());
var disguised = AddComp<ChameleonDisguisedComponent>(user);
disguised.Disguise = disguise;
Dirty(user, disguised);
// make disguise look real (for simple things at least)
var meta = MetaData(entity);
_meta.SetEntityName(disguise, meta.EntityName);
_meta.SetEntityDescription(disguise, meta.EntityDescription);
var comp = EnsureComp<ChameleonDisguiseComponent>(disguise);
comp.User = user;
comp.Projector = ent;
comp.SourceEntity = entity;
comp.SourceProto = Prototype(entity)?.ID;
Dirty(disguise, comp);
// item disguises can be picked up to be revealed, also makes sure their examine size is correct
CopyComp<ItemComponent>((disguise, comp));
_appearance.CopyData(entity, disguise);
}
/// <summary>
/// Removes the disguise, if the user is disguised.
/// </summary>
public bool TryReveal(Entity<ChameleonDisguisedComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp, false))
return false;
if (TryComp<ChameleonDisguiseComponent>(ent.Comp.Disguise, out var disguise)
&& TryComp<ChameleonProjectorComponent>(disguise.Projector, out var proj))
{
proj.Disguised = null;
}
var xform = Transform(ent);
xform.NoLocalRotation = false;
_xform.Unanchor(ent, xform);
Del(ent.Comp.Disguise);
RemComp<ChameleonDisguisedComponent>(ent);
return true;
}
/// <summary>
/// Reveal a projector's user, if any.
/// </summary>
public void RevealProjector(Entity<ChameleonProjectorComponent> ent)
{
if (ent.Comp.Disguised is {} user)
TryReveal(user);
}
#endregion
/// <summary>
/// Copy a component from the source entity/prototype to the disguise entity.
/// </summary>

View File

@@ -8,6 +8,12 @@ namespace Content.Shared.Projectiles;
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ProjectileComponent : Component
{
/// <summary>
/// The angle of the fired projectile.
/// </summary>
[DataField, AutoNetworkedField]
public Angle Angle;
/// <summary>
/// The effect that appears when a projectile collides with an entity.
/// </summary>

View File

@@ -26,10 +26,10 @@ public abstract partial class SharedSalvageSystem : EntitySystem
[ValidatePrototypeId<SalvageLootPrototype>]
public const string ExpeditionsLootProto = "SalvageLoot";
public static string GetFTLName(DatasetPrototype dataset, int seed)
public string GetFTLName(LocalizedDatasetPrototype dataset, int seed)
{
var random = new System.Random(seed);
return $"{dataset.Values[random.Next(dataset.Values.Count)]}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
return $"{Loc.GetString(dataset.Values[random.Next(dataset.Values.Count)])}-{random.Next(10, 100)}-{(char) (65 + random.Next(26))}";
}
public SalvageMission GetMission(SalvageDifficultyPrototype difficulty, int seed)

View File

@@ -0,0 +1,155 @@
using Content.Shared.Interaction.Components;
using Content.Shared.Inventory;
using Content.Shared.Radio;
using Content.Shared.Silicons.Borgs.Components;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Borgs;
/// <summary>
/// Information for a borg type that can be selected by <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
[Prototype]
public sealed partial class BorgTypePrototype : IPrototype
{
[ValidatePrototypeId<SoundCollectionPrototype>]
private static readonly ProtoId<SoundCollectionPrototype> DefaultFootsteps = new("FootstepBorg");
[IdDataField]
public required string ID { get; init; }
//
// Description info (name/desc) is configured via localization strings directly.
//
/// <summary>
/// The prototype displayed in the selection menu for this type.
/// </summary>
[DataField]
public required EntProtoId DummyPrototype { get; init; }
//
// Functional information
//
/// <summary>
/// The amount of free module slots this borg type has.
/// </summary>
/// <remarks>
/// This count is on top of the modules specified in <see cref="DefaultModules"/>.
/// </remarks>
/// <seealso cref="BorgChassisComponent.ModuleCount"/>
[DataField]
public int ExtraModuleCount { get; set; } = 0;
/// <summary>
/// The whitelist for borg modules that can be inserted into this borg type.
/// </summary>
/// <seealso cref="BorgChassisComponent.ModuleWhitelist"/>
[DataField]
public EntityWhitelist? ModuleWhitelist { get; set; }
/// <summary>
/// Inventory template used by this borg.
/// </summary>
/// <remarks>
/// This template must be compatible with the normal borg templates,
/// so in practice it can only be used to differentiate the visual position of the slots on the character sprites.
/// </remarks>
/// <seealso cref="InventorySystem.SetTemplateId"/>
[DataField]
public ProtoId<InventoryTemplatePrototype> InventoryTemplateId { get; set; } = "borgShort";
/// <summary>
/// Radio channels that this borg will gain access to from this module.
/// </summary>
/// <remarks>
/// These channels are provided on top of the ones specified in
/// <see cref="BorgSwitchableTypeComponent.InherentRadioChannels"/>.
/// </remarks>
[DataField]
public ProtoId<RadioChannelPrototype>[] RadioChannels = [];
/// <summary>
/// Borg module types that are always available to borgs of this type.
/// </summary>
/// <remarks>
/// These modules still work like modules, although they cannot be removed from the borg.
/// </remarks>
/// <seealso cref="BorgModuleComponent.DefaultModule"/>
[DataField]
public EntProtoId[] DefaultModules = [];
/// <summary>
/// Additional components to add to the borg entity when this type is selected.
/// </summary>
[DataField]
public ComponentRegistry? AddComponents { get; set; }
//
// Visual information
//
/// <summary>
/// The sprite state for the main borg body.
/// </summary>
[DataField]
public string SpriteBodyState { get; set; } = "robot";
/// <summary>
/// An optional movement sprite state for the main borg body.
/// </summary>
[DataField]
public string? SpriteBodyMovementState { get; set; }
/// <summary>
/// Sprite state used to indicate that the borg has a mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.HasMindState"/>
[DataField]
public string SpriteHasMindState { get; set; } = "robot_e";
/// <summary>
/// Sprite state used to indicate that the borg has no mind in it.
/// </summary>
/// <seealso cref="BorgChassisComponent.NoMindState"/>
[DataField]
public string SpriteNoMindState { get; set; } = "robot_e_r";
/// <summary>
/// Sprite state used when the borg's flashlight is on.
/// </summary>
[DataField]
public string SpriteToggleLightState { get; set; } = "robot_l";
//
// Minor information
//
/// <summary>
/// String to use on petting success.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetSuccessString { get; set; } = "petting-success-generic-cyborg";
/// <summary>
/// String to use on petting failure.
/// </summary>
/// <seealso cref="InteractionPopupComponent"/>
[DataField]
public string PetFailureString { get; set; } = "petting-failure-generic-cyborg";
//
// Sounds
//
/// <summary>
/// Sound specifier for footstep sounds created by this borg.
/// </summary>
[DataField]
public SoundSpecifier FootstepCollection { get; set; } = new SoundCollectionSpecifier(DefaultFootsteps);
}

View File

@@ -89,5 +89,18 @@ public enum BorgVisuals : byte
[Serializable, NetSerializable]
public enum BorgVisualLayers : byte
{
Light
/// <summary>
/// Main borg body layer.
/// </summary>
Body,
/// <summary>
/// Layer for the borg's mind state.
/// </summary>
Light,
/// <summary>
/// Layer for the borg flashlight status.
/// </summary>
LightStatus,
}

View File

@@ -7,6 +7,7 @@ namespace Content.Shared.Silicons.Borgs.Components;
/// to give them unique abilities and attributes.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedBorgSystem))]
[AutoGenerateComponentState]
public sealed partial class BorgModuleComponent : Component
{
/// <summary>
@@ -16,6 +17,13 @@ public sealed partial class BorgModuleComponent : Component
public EntityUid? InstalledEntity;
public bool Installed => InstalledEntity != null;
/// <summary>
/// If true, this is a "default" module that cannot be removed from a borg.
/// </summary>
[DataField]
[AutoNetworkedField]
public bool DefaultModule;
}
/// <summary>

View File

@@ -0,0 +1,72 @@
using Content.Shared.Actions;
using Content.Shared.Radio;
using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Silicons.Borgs.Components;
/// <summary>
/// Component for borgs that can switch their "type" after being created.
/// </summary>
/// <remarks>
/// <para>
/// This is used by all NT borgs, on construction and round-start spawn.
/// Borgs are effectively useless until they have made their choice of type.
/// Borg type selections are currently irreversible.
/// </para>
/// <para>
/// Available types are specified in <see cref="BorgTypePrototype"/>s.
/// </para>
/// </remarks>
/// <seealso cref="SharedBorgSwitchableTypeSystem"/>
[RegisterComponent, NetworkedComponent]
[AutoGenerateComponentState(raiseAfterAutoHandleState: true)]
[Access(typeof(SharedBorgSwitchableTypeSystem))]
public sealed partial class BorgSwitchableTypeComponent : Component
{
/// <summary>
/// Action entity used by players to select their type.
/// </summary>
[DataField, AutoNetworkedField]
public EntityUid? SelectTypeAction;
/// <summary>
/// The currently selected borg type, if any.
/// </summary>
/// <remarks>
/// This can be set in a prototype to immediately apply a borg type, and not have switching support.
/// </remarks>
[DataField, AutoNetworkedField]
public ProtoId<BorgTypePrototype>? SelectedBorgType;
/// <summary>
/// Radio channels that the borg will always have. These are added on top of the selected type's radio channels.
/// </summary>
[DataField]
public ProtoId<RadioChannelPrototype>[] InherentRadioChannels = [];
}
/// <summary>
/// Action event used to open the selection menu of a <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
public sealed partial class BorgToggleSelectTypeEvent : InstantActionEvent;
/// <summary>
/// UI message used by a borg to select their type with <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
/// <param name="prototype">The borg type prototype that the user selected.</param>
[Serializable, NetSerializable]
public sealed class BorgSelectTypeMessage(ProtoId<BorgTypePrototype> prototype) : BoundUserInterfaceMessage
{
public ProtoId<BorgTypePrototype> Prototype = prototype;
}
/// <summary>
/// UI key used by the selection menu for <see cref="BorgSwitchableTypeComponent"/>.
/// </summary>
[NetSerializable, Serializable]
public enum BorgSwitchableTypeUiKey : byte
{
SelectBorgType,
}

View File

@@ -0,0 +1,125 @@
using Content.Shared.Actions;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Components;
using Content.Shared.Movement.Components;
using Content.Shared.Silicons.Borgs.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Shared.Silicons.Borgs;
/// <summary>
/// Implements borg type switching.
/// </summary>
/// <seealso cref="BorgSwitchableTypeComponent"/>
public abstract class SharedBorgSwitchableTypeSystem : EntitySystem
{
// TODO: Allow borgs to be reset to default configuration.
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly SharedUserInterfaceSystem _userInterface = default!;
[Dependency] protected readonly IPrototypeManager Prototypes = default!;
[Dependency] private readonly InteractionPopupSystem _interactionPopup = default!;
[ValidatePrototypeId<EntityPrototype>]
public const string ActionId = "ActionSelectBorgType";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<BorgSwitchableTypeComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<BorgSwitchableTypeComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<BorgSwitchableTypeComponent, BorgToggleSelectTypeEvent>(OnSelectBorgTypeAction);
Subs.BuiEvents<BorgSwitchableTypeComponent>(BorgSwitchableTypeUiKey.SelectBorgType,
sub =>
{
sub.Event<BorgSelectTypeMessage>(SelectTypeMessageHandler);
});
}
//
// UI-adjacent code
//
private void OnMapInit(Entity<BorgSwitchableTypeComponent> ent, ref MapInitEvent args)
{
_actionsSystem.AddAction(ent, ref ent.Comp.SelectTypeAction, ActionId);
Dirty(ent);
if (ent.Comp.SelectedBorgType != null)
{
SelectBorgModule(ent, ent.Comp.SelectedBorgType.Value);
}
}
private void OnShutdown(Entity<BorgSwitchableTypeComponent> ent, ref ComponentShutdown args)
{
_actionsSystem.RemoveAction(ent, ent.Comp.SelectTypeAction);
}
private void OnSelectBorgTypeAction(Entity<BorgSwitchableTypeComponent> ent, ref BorgToggleSelectTypeEvent args)
{
if (args.Handled || !TryComp<ActorComponent>(ent, out var actor))
return;
args.Handled = true;
_userInterface.TryToggleUi((ent.Owner, null), BorgSwitchableTypeUiKey.SelectBorgType, actor.PlayerSession);
}
private void SelectTypeMessageHandler(Entity<BorgSwitchableTypeComponent> ent, ref BorgSelectTypeMessage args)
{
if (ent.Comp.SelectedBorgType != null)
return;
if (!Prototypes.HasIndex(args.Prototype))
return;
SelectBorgModule(ent, args.Prototype);
}
//
// Implementation
//
protected virtual void SelectBorgModule(
Entity<BorgSwitchableTypeComponent> ent,
ProtoId<BorgTypePrototype> borgType)
{
ent.Comp.SelectedBorgType = borgType;
_actionsSystem.RemoveAction(ent, ent.Comp.SelectTypeAction);
ent.Comp.SelectTypeAction = null;
Dirty(ent);
_userInterface.CloseUi((ent.Owner, null), BorgSwitchableTypeUiKey.SelectBorgType);
UpdateEntityAppearance(ent);
}
protected void UpdateEntityAppearance(Entity<BorgSwitchableTypeComponent> entity)
{
if (!Prototypes.TryIndex(entity.Comp.SelectedBorgType, out var proto))
return;
UpdateEntityAppearance(entity, proto);
}
protected virtual void UpdateEntityAppearance(
Entity<BorgSwitchableTypeComponent> entity,
BorgTypePrototype prototype)
{
if (TryComp(entity, out InteractionPopupComponent? popup))
{
_interactionPopup.SetInteractSuccessString((entity.Owner, popup), prototype.PetSuccessString);
_interactionPopup.SetInteractFailureString((entity.Owner, popup), prototype.PetFailureString);
}
if (TryComp(entity, out FootstepModifierComponent? footstepModifier))
{
footstepModifier.FootstepSoundCollection = prototype.FootstepCollection;
}
}
}

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