Merge remote-tracking branch 'refs/remotes/wizards/master'

# Conflicts:
#	Content.Server/Construction/ConstructionSystem.Initial.cs
#	Resources/ServerInfo/Guidebook/Engineering/Fires.xml
This commit is contained in:
VigersRay 2024-06-14 19:01:52 +03:00
commit 562dc416a2
57 changed files with 7329 additions and 584 deletions

View file

@ -1,4 +1,5 @@
root = true
[*]
charset = utf-8
@ -278,7 +279,7 @@ dotnet_naming_style.t_upper_camel_case_style.capitalization = pascal_case
dotnet_naming_style.t_upper_camel_case_style.required_prefix = T
dotnet_naming_style.upper_camel_case_style.capitalization = pascal_case
dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.constants_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.constants_symbols.applicable_kinds = field
dotnet_naming_symbols.constants_symbols.required_modifiers = const
@ -317,20 +318,20 @@ dotnet_naming_symbols.private_static_fields_symbols.required_modifiers = static
dotnet_naming_symbols.private_static_readonly_symbols.applicable_accessibilities = private
dotnet_naming_symbols.private_static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static,readonly
dotnet_naming_symbols.private_static_readonly_symbols.required_modifiers = static, readonly
dotnet_naming_symbols.property_symbols.applicable_accessibilities = *
dotnet_naming_symbols.property_symbols.applicable_kinds = property
dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.public_fields_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.public_fields_symbols.applicable_kinds = field
dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public,internal,protected,protected_internal,private_protected
dotnet_naming_symbols.static_readonly_symbols.applicable_accessibilities = public, internal, protected, protected_internal, private_protected
dotnet_naming_symbols.static_readonly_symbols.applicable_kinds = field
dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static,readonly
dotnet_naming_symbols.static_readonly_symbols.required_modifiers = static, readonly
dotnet_naming_symbols.types_and_namespaces_symbols.applicable_accessibilities = *
dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace,class,struct,enum,delegate
dotnet_naming_symbols.types_and_namespaces_symbols.applicable_kinds = namespace, class, struct, enum, delegate
dotnet_naming_symbols.type_parameters_symbols.applicable_accessibilities = *
dotnet_naming_symbols.type_parameters_symbols.applicable_kinds = type_parameter
@ -342,6 +343,7 @@ resharper_csharp_wrap_parameters_style = chop_if_long
resharper_keep_existing_attribute_arrangement = true
resharper_wrap_chained_binary_patterns = chop_if_long
resharper_wrap_chained_method_calls = chop_if_long
resharper_csharp_trailing_comma_in_multiline_lists = true
[*.{csproj,xml,yml,yaml,dll.config,msbuildproj,targets,props}]
indent_size = 2

View file

@ -1,8 +0,0 @@
using Content.Server.Bed.Sleep;
namespace Content.Client.Bed;
public sealed class SleepingSystem : SharedSleepingSystem
{
}

View file

@ -135,6 +135,10 @@ namespace Content.Server.Atmos.Piping.Unary.Components
[ViewVariables(VVAccess.ReadWrite)]
[DataField("depressurizePressure")]
public float DepressurizePressure = 0;
// When true, ignore under-pressure lockout. Used to re-fill rooms in air alarm "Fill" mode.
[DataField]
public bool PressureLockoutOverride = false;
#endregion
public GasVentPumpData ToAirAlarmData()
@ -146,7 +150,8 @@ namespace Content.Server.Atmos.Piping.Unary.Components
PumpDirection = PumpDirection,
PressureChecks = PressureChecks,
ExternalPressureBound = ExternalPressureBound,
InternalPressureBound = InternalPressureBound
InternalPressureBound = InternalPressureBound,
PressureLockoutOverride = PressureLockoutOverride
};
}
@ -158,6 +163,7 @@ namespace Content.Server.Atmos.Piping.Unary.Components
PressureChecks = data.PressureChecks;
ExternalPressureBound = data.ExternalPressureBound;
InternalPressureBound = data.InternalPressureBound;
PressureLockoutOverride = data.PressureLockoutOverride;
}
}
}

View file

@ -108,7 +108,8 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
// (ignoring temperature differences because I am lazy)
var transferMoles = pressureDelta * environment.Volume / (pipe.Air.Temperature * Atmospherics.R);
if (vent.UnderPressureLockout)
// Only run if the device is under lockout and not being overriden
if (vent.UnderPressureLockout & !vent.PressureLockoutOverride)
{
// Leak only a small amount of gas as a proportion of supply pipe pressure.
var pipeDelta = pipe.Air.Pressure - environment.Pressure;
@ -280,7 +281,7 @@ namespace Content.Server.Atmos.Piping.Unary.EntitySystems
return;
if (args.IsInDetailsRange)
{
if (pumpComponent.UnderPressureLockout)
if (pumpComponent.UnderPressureLockout & !pumpComponent.PressureLockoutOverride)
{
args.PushMarkup(Loc.GetString("gas-vent-pump-uvlo"));
}

View file

@ -1,6 +1,5 @@
using Content.Server.Actions;
using Content.Server.Bed.Components;
using Content.Server.Bed.Sleep;
using Content.Server.Body.Systems;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;

View file

@ -1,254 +0,0 @@
using Content.Server.Popups;
using Content.Server.Sound;
using Content.Shared.Sound.Components;
using Content.Shared.Actions;
using Content.Shared.Audio;
using Content.Shared.Bed.Sleep;
using Content.Shared.Damage;
using Content.Shared.Examine;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Slippery;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
namespace Content.Server.Bed.Sleep
{
public sealed class SleepingSystem : SharedSleepingSystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IRobustRandom _robustRandom = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
[Dependency] private readonly EmitSoundSystem _emitSound = default!;
[ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MobStateComponent, SleepStateChangedEvent>(OnSleepStateChanged);
SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<MobStateComponent, SleepActionEvent>(OnSleepAction);
SubscribeLocalEvent<ActionsContainerComponent, SleepActionEvent>(OnBedSleepAction);
SubscribeLocalEvent<MobStateComponent, WakeActionEvent>(OnWakeAction);
SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<SleepingComponent, SlipAttemptEvent>(OnSlip);
SubscribeLocalEvent<SleepingComponent, ConsciousAttemptEvent>(OnConsciousAttempt);
SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
}
/// <summary>
/// when sleeping component is added or removed, we do some stuff with other components.
/// </summary>
private void OnSleepStateChanged(EntityUid uid, MobStateComponent component, SleepStateChangedEvent args)
{
if (args.FellAsleep)
{
// Expiring status effects would remove the components needed for sleeping
_statusEffectsSystem.TryRemoveStatusEffect(uid, "Stun");
_statusEffectsSystem.TryRemoveStatusEffect(uid, "KnockedDown");
EnsureComp<StunnedComponent>(uid);
EnsureComp<KnockedDownComponent>(uid);
if (TryComp<SleepEmitSoundComponent>(uid, out var sleepSound))
{
var emitSound = EnsureComp<SpamEmitSoundComponent>(uid);
if (HasComp<SnoringComponent>(uid))
{
emitSound.Sound = sleepSound.Snore;
}
emitSound.MinInterval = sleepSound.Interval;
emitSound.MaxInterval = sleepSound.MaxInterval;
emitSound.PopUp = sleepSound.PopUp;
}
return;
}
RemComp<StunnedComponent>(uid);
RemComp<KnockedDownComponent>(uid);
RemComp<SpamEmitSoundComponent>(uid);
}
/// <summary>
/// Wake up on taking an instance of damage at least the value of WakeThreshold.
/// </summary>
private void OnDamageChanged(EntityUid uid, SleepingComponent component, DamageChangedEvent args)
{
if (!args.DamageIncreased || args.DamageDelta == null)
return;
if (args.DamageDelta.GetTotal() >= component.WakeThreshold)
TryWaking(uid, component);
}
private void OnSleepAction(EntityUid uid, MobStateComponent component, SleepActionEvent args)
{
TrySleeping(uid);
}
private void OnBedSleepAction(EntityUid uid, ActionsContainerComponent component, SleepActionEvent args)
{
TrySleeping(args.Performer);
}
private void OnWakeAction(EntityUid uid, MobStateComponent component, WakeActionEvent args)
{
if (!TryWakeCooldown(uid))
return;
if (TryWaking(uid))
args.Handled = true;
}
/// <summary>
/// In crit, we wake up if we are not being forced to sleep.
/// And, you can't sleep when dead...
/// </summary>
private void OnMobStateChanged(EntityUid uid, SleepingComponent component, MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
{
RemComp<SpamEmitSoundComponent>(uid);
RemComp<SleepingComponent>(uid);
return;
}
if (TryComp<SpamEmitSoundComponent>(uid, out var spam))
_emitSound.SetEnabled((uid, spam), args.NewMobState == MobState.Alive);
}
private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
AlternativeVerb verb = new()
{
Act = () =>
{
if (!TryWakeCooldown(uid))
return;
TryWaking(args.Target, user: args.User);
},
Text = Loc.GetString("action-name-wake"),
Priority = 2
};
args.Verbs.Add(verb);
}
/// <summary>
/// When you click on a sleeping person with an empty hand, try to wake them.
/// </summary>
private void OnInteractHand(EntityUid uid, SleepingComponent component, InteractHandEvent args)
{
args.Handled = true;
if (!TryWakeCooldown(uid))
return;
TryWaking(args.Target, user: args.User);
}
private void OnExamined(EntityUid uid, SleepingComponent component, ExaminedEvent args)
{
if (args.IsInDetailsRange)
{
args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(uid, EntityManager))));
}
}
private void OnSlip(EntityUid uid, SleepingComponent component, SlipAttemptEvent args)
{
args.Cancel();
}
private void OnConsciousAttempt(EntityUid uid, SleepingComponent component, ConsciousAttemptEvent args)
{
args.Cancel();
}
private void OnInit(EntityUid uid, ForcedSleepingComponent component, ComponentInit args)
{
TrySleeping(uid);
}
/// <summary>
/// Try sleeping. Only mobs can sleep.
/// </summary>
public bool TrySleeping(EntityUid uid)
{
if (!HasComp<MobStateComponent>(uid))
return false;
var tryingToSleepEvent = new TryingToSleepEvent(uid);
RaiseLocalEvent(uid, ref tryingToSleepEvent);
if (tryingToSleepEvent.Cancelled)
return false;
EnsureComp<SleepingComponent>(uid);
return true;
}
private bool TryWakeCooldown(EntityUid uid, SleepingComponent? component = null)
{
if (!Resolve(uid, ref component, false))
return false;
var curTime = _gameTiming.CurTime;
if (curTime < component.CoolDownEnd)
{
return false;
}
component.CoolDownEnd = curTime + component.Cooldown;
return true;
}
/// <summary>
/// Try to wake up.
/// </summary>
public bool TryWaking(EntityUid uid, SleepingComponent? component = null, bool force = false, EntityUid? user = null)
{
if (!Resolve(uid, ref component, false))
return false;
if (!force && HasComp<ForcedSleepingComponent>(uid))
{
if (user != null)
{
_audio.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
_popupSystem.PopupEntity(Loc.GetString("wake-other-failure", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), true, Shared.Popups.PopupType.SmallCaution);
}
return false;
}
if (user != null)
{
_audio.PlayPvs("/Audio/Effects/thudswoosh.ogg", uid, AudioHelpers.WithVariation(0.05f, _robustRandom));
_popupSystem.PopupEntity(Loc.GetString("wake-other-success", ("target", Identity.Entity(uid, EntityManager))), uid, Filter.Entities(user.Value), true);
}
RemComp<SleepingComponent>(uid);
return true;
}
}
}

View file

@ -506,6 +506,7 @@ namespace Content.Server.Cargo.Systems
"cargo-console-paper-print-text",
("orderNumber", order.OrderId),
("itemName", MetaData(item).EntityName),
("orderQuantity", order.OrderQuantity),
("requester", order.Requester),
("reason", order.Reason),
("approver", order.Approver ?? string.Empty)),

View file

@ -263,7 +263,7 @@ namespace Content.Server.Construction
}
var newEntityProto = graph.Nodes[edge.Target].Entity.GetId(null, user, new(EntityManager));
var newEntity = EntityManager.SpawnEntity(newEntityProto, EntityManager.GetComponent<TransformComponent>(user).Coordinates);
var newEntity = EntityManager.SpawnAttachedTo(newEntityProto, coords, rotation: angle);
if (!TryComp(newEntity, out ConstructionComponent? construction))
{

View file

@ -1,3 +1,4 @@
using Content.Shared.Bed.Sleep;
using Content.Shared.Damage;
using Content.Shared.Damage.ForceSay;
using Content.Shared.FixedPoint;

View file

@ -43,13 +43,19 @@ namespace Content.Server.PDA.Ringer
SubscribeLocalEvent<RingerComponent, RingerPlayRingtoneMessage>(RingerPlayRingtone);
SubscribeLocalEvent<RingerComponent, RingerRequestUpdateInterfaceMessage>(UpdateRingerUserInterfaceDriver);
SubscribeLocalEvent<RingerUplinkComponent, CurrencyInsertAttemptEvent>(OnCurrencyInsert);
SubscribeLocalEvent<RingerComponent, CurrencyInsertAttemptEvent>(OnCurrencyInsert);
}
//Event Functions
private void OnCurrencyInsert(EntityUid uid, RingerUplinkComponent uplink, CurrencyInsertAttemptEvent args)
private void OnCurrencyInsert(EntityUid uid, RingerComponent ringer, CurrencyInsertAttemptEvent args)
{
if (!TryComp<RingerUplinkComponent>(uid, out var uplink))
{
args.Cancel();
return;
}
// if the store can be locked, it must be unlocked first before inserting currency. Stops traitor checking.
if (!uplink.Unlocked)
args.Cancel();

View file

@ -16,6 +16,7 @@ using Content.Server.Station.Events;
using Content.Server.Station.Systems;
using Content.Shared.Administration;
using Content.Shared.CCVar;
using Content.Shared.Damage.Components;
using Content.Shared.DeviceNetwork;
using Content.Shared.Mobs.Components;
using Content.Shared.Movement.Components;
@ -63,6 +64,16 @@ public sealed class ArrivalsSystem : EntitySystem
/// </summary>
public bool Enabled { get; private set; }
/// <summary>
/// Flags if all players must arrive via the Arrivals system, or if they can spawn in other ways.
/// </summary>
public bool Forced { get; private set; }
/// <summary>
/// Flags if all players spawning at the departure terminal have godmode until they leave the terminal.
/// </summary>
public bool ArrivalsGodmode { get; private set; }
/// <summary>
/// The first arrival is a little early, to save everyone 10s
/// </summary>
@ -86,7 +97,12 @@ public sealed class ArrivalsSystem : EntitySystem
// Don't invoke immediately as it will get set in the natural course of things.
Enabled = _cfgManager.GetCVar(CCVars.ArrivalsShuttles);
Subs.CVar(_cfgManager, CCVars.ArrivalsShuttles, SetArrivals);
Forced = _cfgManager.GetCVar(CCVars.ForceArrivals);
ArrivalsGodmode = _cfgManager.GetCVar(CCVars.GodmodeArrivals);
_cfgManager.OnValueChanged(CCVars.ArrivalsShuttles, SetArrivals);
_cfgManager.OnValueChanged(CCVars.ForceArrivals, b => Forced = b);
_cfgManager.OnValueChanged(CCVars.GodmodeArrivals, b => ArrivalsGodmode = b);
// Command so admins can set these for funsies
_console.RegisterCommand("arrivals", ArrivalsCommand, ArrivalsCompletion);
@ -242,6 +258,9 @@ public sealed class ArrivalsSystem : EntitySystem
// The player has successfully left arrivals and is also not on the shuttle. Remove their warp coupon.
RemCompDeferred<PendingClockInComponent>(pUid);
RemCompDeferred<AutoOrientComponent>(pUid);
if (ArrivalsGodmode)
RemCompDeferred<GodmodeComponent>(pUid);
}
}
@ -349,7 +368,7 @@ public sealed class ArrivalsSystem : EntitySystem
return;
// Only works on latejoin even if enabled.
if (!Enabled || _ticker.RunLevel != GameRunLevel.InRound)
if (!Enabled || !Forced && _ticker.RunLevel != GameRunLevel.InRound)
return;
if (!HasComp<StationArrivalsComponent>(ev.Station))
@ -357,33 +376,37 @@ public sealed class ArrivalsSystem : EntitySystem
TryGetArrivalsSource(out var arrivals);
if (TryComp(arrivals, out TransformComponent? arrivalsXform))
if (!TryComp(arrivals, out TransformComponent? arrivalsXform))
return;
var mapId = arrivalsXform.MapID;
var points = EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
var possiblePositions = new List<EntityCoordinates>();
while (points.MoveNext(out var uid, out var spawnPoint, out var xform))
{
var mapId = arrivalsXform.MapID;
if (spawnPoint.SpawnType != SpawnPointType.LateJoin || xform.MapID != mapId)
continue;
var points = EntityQueryEnumerator<SpawnPointComponent, TransformComponent>();
var possiblePositions = new List<EntityCoordinates>();
while (points.MoveNext(out var uid, out var spawnPoint, out var xform))
{
if (spawnPoint.SpawnType != SpawnPointType.LateJoin || xform.MapID != mapId)
continue;
possiblePositions.Add(xform.Coordinates);
}
if (possiblePositions.Count > 0)
{
var spawnLoc = _random.Pick(possiblePositions);
ev.SpawnResult = _stationSpawning.SpawnPlayerMob(
spawnLoc,
ev.Job,
ev.HumanoidCharacterProfile,
ev.Station);
EnsureComp<PendingClockInComponent>(ev.SpawnResult.Value);
EnsureComp<AutoOrientComponent>(ev.SpawnResult.Value);
}
possiblePositions.Add(xform.Coordinates);
}
if (possiblePositions.Count <= 0)
return;
var spawnLoc = _random.Pick(possiblePositions);
ev.SpawnResult = _stationSpawning.SpawnPlayerMob(
spawnLoc,
ev.Job,
ev.HumanoidCharacterProfile,
ev.Station);
EnsureComp<PendingClockInComponent>(ev.SpawnResult.Value);
EnsureComp<AutoOrientComponent>(ev.SpawnResult.Value);
// If you're forced to spawn, you're invincible until you leave wherever you were forced to spawn.
if (ArrivalsGodmode)
EnsureComp<GodmodeComponent>(ev.SpawnResult.Value);
}
private bool TryTeleportToMapSpawn(EntityUid player, EntityUid stationId, TransformComponent? transform = null)

View file

@ -66,7 +66,15 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
_spawnerCallbacks = new Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>>()
{
{ SpawnPriorityPreference.Arrivals, _arrivalsSystem.HandlePlayerSpawning },
{ SpawnPriorityPreference.Cryosleep, _containerSpawnPointSystem.HandlePlayerSpawning }
{
SpawnPriorityPreference.Cryosleep, ev =>
{
if (_arrivalsSystem.Forced)
_arrivalsSystem.HandlePlayerSpawning(ev);
else
_containerSpawnPointSystem.HandlePlayerSpawning(ev);
}
}
};
}

View file

@ -5,11 +5,11 @@ using Content.Shared.Implants.Components;
using Content.Shared.Interaction;
using Content.Shared.Popups;
using Content.Shared.Stacks;
using Content.Shared.Store.Components;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using System.Linq;
using Content.Shared.Store.Components;
using Robust.Shared.Utility;
using System.Linq;
namespace Content.Server.Store.Systems;

View file

@ -17,6 +17,7 @@ using Content.Shared.Weapons.Ranged.Components;
using Content.Shared.Weapons.Ranged.Events;
using Content.Shared.Weapons.Ranged.Systems;
using Content.Shared.Weapons.Reflect;
using Content.Shared.Damage.Components;
using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Physics;
@ -202,6 +203,20 @@ public sealed partial class GunSystem : SharedGunSystem
break;
var result = rayCastResults[0];
// Checks if the laser should pass over unless targeted by its user
foreach (var collide in rayCastResults)
{
if (collide.HitEntity != gun.Target &&
CompOrNull<RequireProjectileTargetComponent>(collide.HitEntity)?.Active == true)
{
continue;
}
result = collide;
break;
}
var hit = result.HitEntity;
lastHit = hit;

View file

@ -3,6 +3,7 @@ using Content.Server.Xenoarchaeology.Equipment.Components;
using Content.Server.Xenoarchaeology.XenoArtifacts;
using Content.Shared.Interaction;
using Content.Shared.Timing;
using Content.Shared.Verbs;
namespace Content.Server.Xenoarchaeology.Equipment.Systems;
@ -14,23 +15,44 @@ public sealed class NodeScannerSystem : EntitySystem
/// <inheritdoc/>
public override void Initialize()
{
SubscribeLocalEvent<NodeScannerComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<NodeScannerComponent, BeforeRangedInteractEvent>(OnBeforeRangedInteract);
SubscribeLocalEvent<NodeScannerComponent, GetVerbsEvent<UtilityVerb>>(AddScanVerb);
}
private void OnAfterInteract(EntityUid uid, NodeScannerComponent component, AfterInteractEvent args)
private void OnBeforeRangedInteract(EntityUid uid, NodeScannerComponent component, BeforeRangedInteractEvent args)
{
if (!args.CanReach || args.Target == null)
if (args.Handled || !args.CanReach || args.Target is not {} target)
return;
if (!TryComp<ArtifactComponent>(target, out var artifact) || artifact.CurrentNodeId == null)
return;
CreatePopup(uid, target, artifact);
args.Handled = true;
}
private void AddScanVerb(EntityUid uid, NodeScannerComponent component, GetVerbsEvent<UtilityVerb> args)
{
if (!args.CanAccess)
return;
if (!TryComp<ArtifactComponent>(args.Target, out var artifact) || artifact.CurrentNodeId == null)
return;
if (args.Handled)
return;
args.Handled = true;
var verb = new UtilityVerb()
{
Act = () =>
{
CreatePopup(uid, args.Target, artifact);
},
Text = Loc.GetString("node-scan-tooltip")
};
var target = args.Target.Value;
args.Verbs.Add(verb);
}
private void CreatePopup(EntityUid uid, EntityUid target, ArtifactComponent artifact)
{
if (TryComp(uid, out UseDelayComponent? useDelay)
&& !_useDelay.TryResetDelay((uid, useDelay), true))
return;

View file

@ -13,6 +13,7 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
public VentPressureBound PressureChecks { get; set; } = VentPressureBound.ExternalBound;
public float ExternalPressureBound { get; set; } = Atmospherics.OneAtmosphere;
public float InternalPressureBound { get; set; } = 0f;
public bool PressureLockoutOverride { get; set; } = false;
// Presets for 'dumb' air alarm modes
@ -22,7 +23,8 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
PumpDirection = VentPumpDirection.Releasing,
PressureChecks = VentPressureBound.ExternalBound,
ExternalPressureBound = Atmospherics.OneAtmosphere,
InternalPressureBound = 0f
InternalPressureBound = 0f,
PressureLockoutOverride = false
};
public static GasVentPumpData FillModePreset = new GasVentPumpData
@ -32,7 +34,8 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
PumpDirection = VentPumpDirection.Releasing,
PressureChecks = VentPressureBound.ExternalBound,
ExternalPressureBound = Atmospherics.OneAtmosphere * 50,
InternalPressureBound = 0f
InternalPressureBound = 0f,
PressureLockoutOverride = true
};
public static GasVentPumpData PanicModePreset = new GasVentPumpData
@ -42,7 +45,8 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
PumpDirection = VentPumpDirection.Releasing,
PressureChecks = VentPressureBound.ExternalBound,
ExternalPressureBound = Atmospherics.OneAtmosphere,
InternalPressureBound = 0f
InternalPressureBound = 0f,
PressureLockoutOverride = false
};
public static GasVentPumpData ReplaceModePreset = new GasVentPumpData
@ -53,7 +57,8 @@ namespace Content.Shared.Atmos.Piping.Unary.Components
PumpDirection = VentPumpDirection.Releasing,
PressureChecks = VentPressureBound.ExternalBound,
ExternalPressureBound = Atmospherics.OneAtmosphere,
InternalPressureBound = 0f
InternalPressureBound = 0f,
PressureLockoutOverride = false
};
}

View file

@ -1,92 +0,0 @@
using Content.Shared.Actions;
using Content.Shared.Bed.Sleep;
using Content.Shared.Damage.ForceSay;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.Pointing;
using Content.Shared.Speech;
using Robust.Shared.Network;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Server.Bed.Sleep
{
public abstract class SharedSleepingSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
[ValidatePrototypeId<EntityPrototype>] private const string WakeActionId = "ActionWake";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SleepingComponent, ComponentShutdown>(OnShutdown);
SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
}
private void OnMapInit(EntityUid uid, SleepingComponent component, MapInitEvent args)
{
var ev = new SleepStateChangedEvent(true);
RaiseLocalEvent(uid, ev);
_blindableSystem.UpdateIsBlind(uid);
_actionsSystem.AddAction(uid, ref component.WakeAction, WakeActionId, uid);
// TODO remove hardcoded time.
_actionsSystem.SetCooldown(component.WakeAction, _gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(2f));
}
private void OnShutdown(EntityUid uid, SleepingComponent component, ComponentShutdown args)
{
_actionsSystem.RemoveAction(uid, component.WakeAction);
var ev = new SleepStateChangedEvent(false);
RaiseLocalEvent(uid, ev);
_blindableSystem.UpdateIsBlind(uid);
}
private void OnSpeakAttempt(EntityUid uid, SleepingComponent component, SpeakAttemptEvent args)
{
// TODO reduce duplication of this behavior with MobStateSystem somehow
if (HasComp<AllowNextCritSpeechComponent>(uid))
{
RemCompDeferred<AllowNextCritSpeechComponent>(uid);
return;
}
args.Cancel();
}
private void OnSeeAttempt(EntityUid uid, SleepingComponent component, CanSeeAttemptEvent args)
{
if (component.LifeStage <= ComponentLifeStage.Running)
args.Cancel();
}
private void OnPointAttempt(EntityUid uid, SleepingComponent component, PointAttemptEvent args)
{
args.Cancel();
}
}
}
public sealed partial class SleepActionEvent : InstantActionEvent {}
public sealed partial class WakeActionEvent : InstantActionEvent {}
/// <summary>
/// Raised on an entity when they fall asleep or wake up.
/// </summary>
public sealed class SleepStateChangedEvent : EntityEventArgs
{
public bool FellAsleep = false;
public SleepStateChangedEvent(bool fellAsleep)
{
FellAsleep = fellAsleep;
}
}

View file

@ -1,31 +1,42 @@
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Shared.Bed.Sleep;
/// <summary>
/// Added to entities when they go to sleep.
/// </summary>
[NetworkedComponent, RegisterComponent, AutoGenerateComponentPause(Dirty = true)]
[NetworkedComponent, RegisterComponent]
[AutoGenerateComponentState, AutoGenerateComponentPause(Dirty = true)]
public sealed partial class SleepingComponent : Component
{
/// <summary>
/// How much damage of any type it takes to wake this entity.
/// </summary>
[DataField("wakeThreshold")]
[DataField]
public FixedPoint2 WakeThreshold = FixedPoint2.New(2);
/// <summary>
/// Cooldown time between users hand interaction.
/// </summary>
[DataField("cooldown")]
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public TimeSpan Cooldown = TimeSpan.FromSeconds(1f);
[DataField("cooldownEnd", customTypeSerializer:typeof(TimeOffsetSerializer))]
[AutoPausedField]
public TimeSpan CoolDownEnd;
[DataField]
[AutoNetworkedField, AutoPausedField]
public TimeSpan CooldownEnd;
[DataField("wakeAction")] public EntityUid? WakeAction;
[DataField]
[AutoNetworkedField]
public EntityUid? WakeAction;
/// <summary>
/// Sound to play when another player attempts to wake this entity.
/// </summary>
[DataField]
public SoundSpecifier WakeAttemptSound = new SoundPathSpecifier("/Audio/Effects/thudswoosh.ogg")
{
Params = AudioParams.Default.WithVariation(0.05f)
};
}

View file

@ -0,0 +1,314 @@
using Content.Shared.Actions;
using Content.Shared.Damage;
using Content.Shared.Damage.ForceSay;
using Content.Shared.Examine;
using Content.Shared.Eye.Blinding.Systems;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Mobs;
using Content.Shared.Mobs.Components;
using Content.Shared.Pointing;
using Content.Shared.Popups;
using Content.Shared.Slippery;
using Content.Shared.Sound;
using Content.Shared.Sound.Components;
using Content.Shared.Speech;
using Content.Shared.StatusEffect;
using Content.Shared.Stunnable;
using Content.Shared.Verbs;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Shared.Bed.Sleep;
public sealed partial class SleepingSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
[Dependency] private readonly BlindableSystem _blindableSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedEmitSoundSystem _emitSound = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
public static readonly ProtoId<EntityPrototype> SleepActionId = "ActionSleep";
public static readonly ProtoId<EntityPrototype> WakeActionId = "ActionWake";
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<ActionsContainerComponent, SleepActionEvent>(OnBedSleepAction);
SubscribeLocalEvent<MobStateComponent, SleepStateChangedEvent>(OnSleepStateChanged);
SubscribeLocalEvent<MobStateComponent, WakeActionEvent>(OnWakeAction);
SubscribeLocalEvent<MobStateComponent, SleepActionEvent>(OnSleepAction);
SubscribeLocalEvent<SleepingComponent, DamageChangedEvent>(OnDamageChanged);
SubscribeLocalEvent<SleepingComponent, MobStateChangedEvent>(OnMobStateChanged);
SubscribeLocalEvent<SleepingComponent, MapInitEvent>(OnMapInit);
SubscribeLocalEvent<SleepingComponent, SpeakAttemptEvent>(OnSpeakAttempt);
SubscribeLocalEvent<SleepingComponent, CanSeeAttemptEvent>(OnSeeAttempt);
SubscribeLocalEvent<SleepingComponent, PointAttemptEvent>(OnPointAttempt);
SubscribeLocalEvent<SleepingComponent, SlipAttemptEvent>(OnSlip);
SubscribeLocalEvent<SleepingComponent, ConsciousAttemptEvent>(OnConsciousAttempt);
SubscribeLocalEvent<SleepingComponent, ExaminedEvent>(OnExamined);
SubscribeLocalEvent<SleepingComponent, GetVerbsEvent<AlternativeVerb>>(AddWakeVerb);
SubscribeLocalEvent<SleepingComponent, InteractHandEvent>(OnInteractHand);
SubscribeLocalEvent<ForcedSleepingComponent, ComponentInit>(OnInit);
}
private void OnBedSleepAction(Entity<ActionsContainerComponent> ent, ref SleepActionEvent args)
{
TrySleeping(args.Performer);
}
private void OnWakeAction(Entity<MobStateComponent> ent, ref WakeActionEvent args)
{
if (TryWakeWithCooldown(ent.Owner))
args.Handled = true;
}
private void OnSleepAction(Entity<MobStateComponent> ent, ref SleepActionEvent args)
{
TrySleeping((ent, ent.Comp));
}
/// <summary>
/// when sleeping component is added or removed, we do some stuff with other components.
/// </summary>
private void OnSleepStateChanged(Entity<MobStateComponent> ent, ref SleepStateChangedEvent args)
{
if (args.FellAsleep)
{
// Expiring status effects would remove the components needed for sleeping
_statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "Stun");
_statusEffectsSystem.TryRemoveStatusEffect(ent.Owner, "KnockedDown");
EnsureComp<StunnedComponent>(ent);
EnsureComp<KnockedDownComponent>(ent);
if (TryComp<SleepEmitSoundComponent>(ent, out var sleepSound))
{
var emitSound = EnsureComp<SpamEmitSoundComponent>(ent);
if (HasComp<SnoringComponent>(ent))
{
emitSound.Sound = sleepSound.Snore;
}
emitSound.MinInterval = sleepSound.Interval;
emitSound.MaxInterval = sleepSound.MaxInterval;
emitSound.PopUp = sleepSound.PopUp;
Dirty(ent.Owner, emitSound);
}
return;
}
RemComp<StunnedComponent>(ent);
RemComp<KnockedDownComponent>(ent);
RemComp<SpamEmitSoundComponent>(ent);
}
private void OnMapInit(Entity<SleepingComponent> ent, ref MapInitEvent args)
{
var ev = new SleepStateChangedEvent(true);
RaiseLocalEvent(ent, ref ev);
_blindableSystem.UpdateIsBlind(ent.Owner);
_actionsSystem.AddAction(ent, ref ent.Comp.WakeAction, WakeActionId, ent);
// TODO remove hardcoded time.
_actionsSystem.SetCooldown(ent.Comp.WakeAction, _gameTiming.CurTime, _gameTiming.CurTime + TimeSpan.FromSeconds(2f));
}
private void OnSpeakAttempt(Entity<SleepingComponent> ent, ref SpeakAttemptEvent args)
{
// TODO reduce duplication of this behavior with MobStateSystem somehow
if (HasComp<AllowNextCritSpeechComponent>(ent))
{
RemCompDeferred<AllowNextCritSpeechComponent>(ent);
return;
}
args.Cancel();
}
private void OnSeeAttempt(Entity<SleepingComponent> ent, ref CanSeeAttemptEvent args)
{
if (ent.Comp.LifeStage <= ComponentLifeStage.Running)
args.Cancel();
}
private void OnPointAttempt(Entity<SleepingComponent> ent, ref PointAttemptEvent args)
{
args.Cancel();
}
private void OnSlip(Entity<SleepingComponent> ent, ref SlipAttemptEvent args)
{
args.Cancel();
}
private void OnConsciousAttempt(Entity<SleepingComponent> ent, ref ConsciousAttemptEvent args)
{
args.Cancel();
}
private void OnExamined(Entity<SleepingComponent> ent, ref ExaminedEvent args)
{
if (args.IsInDetailsRange)
{
args.PushMarkup(Loc.GetString("sleep-examined", ("target", Identity.Entity(ent, EntityManager))));
}
}
private void AddWakeVerb(Entity<SleepingComponent> ent, ref GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanInteract || !args.CanAccess)
return;
var target = args.Target;
var user = args.User;
AlternativeVerb verb = new()
{
Act = () =>
{
TryWakeWithCooldown((ent, ent.Comp), user: user);
},
Text = Loc.GetString("action-name-wake"),
Priority = 2
};
args.Verbs.Add(verb);
}
/// <summary>
/// When you click on a sleeping person with an empty hand, try to wake them.
/// </summary>
private void OnInteractHand(Entity<SleepingComponent> ent, ref InteractHandEvent args)
{
args.Handled = true;
TryWakeWithCooldown((ent, ent.Comp), args.User);
}
/// <summary>
/// Wake up on taking an instance of damage at least the value of WakeThreshold.
/// </summary>
private void OnDamageChanged(Entity<SleepingComponent> ent, ref DamageChangedEvent args)
{
if (!args.DamageIncreased || args.DamageDelta == null)
return;
if (args.DamageDelta.GetTotal() >= ent.Comp.WakeThreshold)
TryWaking((ent, ent.Comp));
}
/// <summary>
/// In crit, we wake up if we are not being forced to sleep.
/// And, you can't sleep when dead...
/// </summary>
private void OnMobStateChanged(Entity<SleepingComponent> ent, ref MobStateChangedEvent args)
{
if (args.NewMobState == MobState.Dead)
{
RemComp<SpamEmitSoundComponent>(ent);
RemComp<SleepingComponent>(ent);
return;
}
if (TryComp<SpamEmitSoundComponent>(ent, out var spam))
_emitSound.SetEnabled((ent, spam), args.NewMobState == MobState.Alive);
}
private void OnInit(Entity<ForcedSleepingComponent> ent, ref ComponentInit args)
{
TrySleeping(ent.Owner);
}
private void Wake(Entity<SleepingComponent> ent)
{
RemComp<SleepingComponent>(ent);
_actionsSystem.RemoveAction(ent, ent.Comp.WakeAction);
var ev = new SleepStateChangedEvent(false);
RaiseLocalEvent(ent, ref ev);
_blindableSystem.UpdateIsBlind(ent.Owner);
}
/// <summary>
/// Try sleeping. Only mobs can sleep.
/// </summary>
public bool TrySleeping(Entity<MobStateComponent?> ent)
{
if (!Resolve(ent, ref ent.Comp, logMissing: false))
return false;
var tryingToSleepEvent = new TryingToSleepEvent(ent);
RaiseLocalEvent(ent, ref tryingToSleepEvent);
if (tryingToSleepEvent.Cancelled)
return false;
EnsureComp<SleepingComponent>(ent);
return true;
}
/// <summary>
/// Tries to wake up <paramref name="ent"/>, with a cooldown between attempts to prevent spam.
/// </summary>
public bool TryWakeWithCooldown(Entity<SleepingComponent?> ent, EntityUid? user = null)
{
if (!Resolve(ent, ref ent.Comp, false))
return false;
var curTime = _gameTiming.CurTime;
if (curTime < ent.Comp.CooldownEnd)
return false;
ent.Comp.CooldownEnd = curTime + ent.Comp.Cooldown;
Dirty(ent, ent.Comp);
return TryWaking(ent, user: user);
}
/// <summary>
/// Try to wake up <paramref name="ent"/>.
/// </summary>
public bool TryWaking(Entity<SleepingComponent?> ent, bool force = false, EntityUid? user = null)
{
if (!Resolve(ent, ref ent.Comp, false))
return false;
if (!force && HasComp<ForcedSleepingComponent>(ent))
{
if (user != null)
{
_audio.PlayPredicted(ent.Comp.WakeAttemptSound, ent, user);
_popupSystem.PopupClient(Loc.GetString("wake-other-failure", ("target", Identity.Entity(ent, EntityManager))), ent, user, PopupType.SmallCaution);
}
return false;
}
if (user != null)
{
_audio.PlayPredicted(ent.Comp.WakeAttemptSound, ent, user);
_popupSystem.PopupClient(Loc.GetString("wake-other-success", ("target", Identity.Entity(ent, EntityManager))), ent, user);
}
Wake((ent, ent.Comp));
return true;
}
}
public sealed partial class SleepActionEvent : InstantActionEvent;
public sealed partial class WakeActionEvent : InstantActionEvent;
/// <summary>
/// Raised on an entity when they fall asleep or wake up.
/// </summary>
[ByRefEvent]
public record struct SleepStateChangedEvent(bool FellAsleep);

View file

@ -1,9 +1,11 @@
namespace Content.Server.Bed.Sleep;
using Robust.Shared.GameStates;
namespace Content.Shared.Bed.Sleep;
/// <summary>
/// This is used for the snoring trait.
/// </summary>
[RegisterComponent]
[RegisterComponent, NetworkedComponent]
public sealed partial class SnoringComponent : Component
{

View file

@ -1427,6 +1427,18 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<bool> ArrivalsReturns =
CVarDef.Create("shuttle.arrivals_returns", false, CVar.SERVERONLY);
/// <summary>
/// Should all players be forced to spawn at departures, even on roundstart, even if their loadout says they spawn in cryo?
/// </summary>
public static readonly CVarDef<bool> ForceArrivals =
CVarDef.Create("shuttle.force_arrivals", 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>
/// Whether to automatically spawn escape shuttles.
/// </summary>

View file

@ -1,76 +1,4 @@
Entries:
- author: SoulFN
changes:
- message: The borg tool module now has an industrial welding tool.
type: Tweak
id: 6221
time: '2024-03-24T22:35:55.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26332
- author: IProduceWidgets
changes:
- message: Ammo techfab now accepts ingot and cloth material types.
type: Fix
id: 6222
time: '2024-03-25T00:43:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26413
- author: Luminight
changes:
- message: Wooden fence gate sprites are no longer swapped.
type: Fix
id: 6223
time: '2024-03-25T00:55:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26409
- author: Callmore
changes:
- message: Holoprojectors no longer come with a cell when made at a lathe.
type: Tweak
id: 6224
time: '2024-03-25T00:55:48.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26405
- author: IProduceWidgets
changes:
- message: The captain can now return his laser to the glass display box.
type: Fix
id: 6225
time: '2024-03-25T00:58:33.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26398
- author: IProduceWidgets
changes:
- message: More varieties of astro-grass are now available.
type: Add
- message: Astro-grass must now be cut instead of pried.
type: Tweak
id: 6226
time: '2024-03-25T01:14:04.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26381
- author: Tayrtahn
changes:
- message: Parrots now sound more like parrots when they talk. RAWWK!
type: Add
id: 6227
time: '2024-03-25T01:26:41.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26340
- author: DenisShvalov
changes:
- message: Added Cleaner Grenades that will help janitors in their work
type: Add
id: 6228
time: '2024-03-25T06:46:21.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/25444
- author: Weax
changes:
- message: Harmonicas can now be equipped (and played) in the neck slot.
type: Tweak
id: 6229
time: '2024-03-25T07:05:01.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26261
- author: nikthechampiongr
changes:
- message: Mailing units no longer spontaneously turn into disposal units when flushed.
type: Fix
id: 6230
time: '2024-03-25T13:20:39.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26383
- author: Simyon
changes:
- message: All implants are now unable to be implanted more than once.
@ -3847,3 +3775,74 @@
id: 6720
time: '2024-06-13T06:30:39.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28756
- author: Doomsdrayk
changes:
- message: The Drozd and C-20r do not unwield on use again.
type: Fix
id: 6721
time: '2024-06-13T18:10:56.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28728
- author: EmoGarbage404
changes:
- message: Fixed constructed items rotating strangely.
type: Fix
id: 6722
time: '2024-06-13T18:21:49.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28427
- author: lzk228
changes:
- message: Added order quantity to cargo invoice label.
type: Tweak
id: 6723
time: '2024-06-13T18:36:38.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28821
- author: osjarw
changes:
- message: Added context menu action for scanning artifacts.
type: Add
id: 6724
time: '2024-06-14T02:01:32.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/26873
- author: Cojoke-dot
changes:
- message: Lasers now pass over things unless clicked like projectiles
type: Tweak
id: 6725
time: '2024-06-14T02:04:45.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28768
- author: Boaz1111
changes:
- message: The PKA can now mine rocks in one hit again.
type: Tweak
id: 6726
time: '2024-06-14T02:40:23.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27476
- author: KyuPolaris
changes:
- message: Chickens now make a clucking sound when they speak.
type: Add
id: 6727
time: '2024-06-14T02:43:02.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28948
- author: Killerqu00
changes:
- message: Time between uncuff attempts is now 30 seconds instead of 6.
type: Tweak
id: 6728
time: '2024-06-14T06:19:47.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28095
- author: Moomoobeef
changes:
- message: Fax machines can now be purchased at cargo, for when you need more paper
pushing on your station!
type: Add
id: 6729
time: '2024-06-14T06:24:18.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28968
- author: Zonespace27
changes:
- message: Non-uplink PDAs can no longer have telecrystals inserted into them.
type: Fix
id: 6730
time: '2024-06-14T15:24:40.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/28985

View file

@ -36,6 +36,7 @@ cargo-console-paper-print-name = Order #{$orderNumber}
cargo-console-paper-print-text =
Order #{$orderNumber}
Item: {$itemName}
Quantity: {$orderQuantity}
Requested by: {$requester}
Reason: {$reason}
Approved by: {$approver}

View file

@ -1 +1,2 @@
node-scan-popup = The node ID is {$id}
node-scan-popup = The node ID is {$id}
node-scan-tooltip = Scan artifact

File diff suppressed because it is too large Load diff

View file

@ -504,8 +504,8 @@ entities:
3339: -40,44
3341: -36,30
3762: -39,-8
3814: 8,43
3815: 8,51
3808: 8,43
3809: 8,51
- node:
color: '#FFFFFFFF'
id: Arrows
@ -527,8 +527,8 @@ entities:
3351: -26,38
3759: 47,-23
3763: -40,-4
3810: -8,51
3811: -8,43
3806: -8,51
3807: -8,43
- node:
color: '#FFFFFFFF'
id: ArrowsGreyscale
@ -557,12 +557,12 @@ entities:
color: '#FFFFFFFF'
id: Bot
decals:
3816: -7,46
3817: -7,47
3818: -7,48
3819: 7,46
3820: 7,47
3821: 7,48
3810: -7,46
3811: -7,47
3812: -7,48
3813: 7,46
3814: 7,47
3815: 7,48
- node:
color: '#FFFFFFFF'
id: Bot
@ -675,7 +675,7 @@ entities:
3493: 39,-13
3539: 45,-9
3672: -17,-54
3841: 2,27
3835: 2,27
- node:
angle: 1.5707963267948966 rad
color: '#FFFFFFFF'
@ -714,8 +714,8 @@ entities:
3254: 6,-36
3349: -19,46
3745: 50,-11
3834: -25,-1
3835: -25,0
3828: -25,-1
3829: -25,0
- node:
color: '#FFFFFFFF'
id: BotLeftGreyscale
@ -753,15 +753,15 @@ entities:
color: '#FFFFFFFF'
id: BotRightGreyscale
decals:
3837: -29,-1
3838: -29,0
3839: -29,1
3852: 7,34
3853: 7,35
3854: 7,36
3855: 8,36
3858: 8,34
3859: 8,35
3831: -29,-1
3832: -29,0
3833: -29,1
3846: 7,34
3847: 7,35
3848: 7,36
3849: 8,36
3850: 8,34
3851: 8,35
- node:
color: '#79150096'
id: Box
@ -884,7 +884,7 @@ entities:
2380: -14,11
3038: 21,1
3049: 23,1
3851: 6,37
3845: 6,37
- node:
color: '#FFFFFFFF'
id: BrickTileDarkInnerSw
@ -901,9 +901,9 @@ entities:
2989: -115,13
3041: 23,0
3325: 37,18
3848: 6,34
3849: 6,35
3850: 6,36
3842: 6,34
3843: 6,35
3844: 6,36
- node:
color: '#FFFFFFFF'
id: BrickTileDarkLineN
@ -5520,22 +5520,22 @@ entities:
color: '#FFFFFFFF'
id: WarnCornerNE
decals:
3832: -33,21
3826: -33,21
- node:
color: '#FFFFFFFF'
id: WarnCornerNW
decals:
3829: -31,21
3823: -31,21
- node:
color: '#FFFFFFFF'
id: WarnCornerSE
decals:
3833: -33,19
3827: -33,19
- node:
color: '#FFFFFFFF'
id: WarnCornerSW
decals:
3828: -31,19
3822: -31,19
- node:
color: '#FFFFFFFF'
id: WarnCornerSmallNE
@ -5545,7 +5545,7 @@ entities:
1366: -2,31
3332: -2,24
3392: -19,40
3827: -8,29
3821: -8,29
- node:
color: '#FFFFFFFF'
id: WarnCornerSmallNW
@ -5555,7 +5555,7 @@ entities:
2137: 2,24
3380: -27,38
3391: -15,40
3826: -5,29
3820: -5,29
- node:
color: '#FFFFFFFF'
id: WarnCornerSmallSE
@ -5563,7 +5563,7 @@ entities:
1053: -2,-78
1364: -2,36
3390: -19,42
3840: -29,-1
3834: -29,-1
- node:
color: '#FFFFFFFF'
id: WarnCornerSmallSW
@ -5574,7 +5574,7 @@ entities:
2568: 40,-35
3379: -27,40
3389: -15,42
3836: -25,-1
3830: -25,-1
- node:
color: '#52B4E996'
id: WarnFullGreyscale
@ -5649,7 +5649,7 @@ entities:
3201: 56,11
3388: -19,41
3440: 1,-13
3831: -33,20
3825: -33,20
- node:
color: '#52B4E996'
id: WarnLineGreyscaleE
@ -5944,8 +5944,8 @@ entities:
3381: -18,42
3382: -17,42
3383: -16,42
3822: -7,31
3823: -6,31
3816: -7,31
3817: -6,31
- node:
color: '#DE3A3A96'
id: WarnLineS
@ -5997,7 +5997,7 @@ entities:
3378: -27,39
3384: -15,41
3441: -1,-13
3830: -31,20
3824: -31,20
- node:
color: '#DE3A3A96'
id: WarnLineW
@ -6065,14 +6065,14 @@ entities:
3386: -17,40
3387: -18,40
3393: -43,-2
3824: -7,29
3825: -6,29
3842: 4,37
3843: 5,37
3844: 6,37
3845: -4,37
3846: -5,37
3847: -6,37
3818: -7,29
3819: -6,29
3836: 4,37
3837: 5,37
3838: 6,37
3839: -4,37
3840: -5,37
3841: -6,37
- node:
angle: -3.141592653589793 rad
color: '#FFFFFFFF'
@ -8110,7 +8110,7 @@ entities:
1: 39312
-12,8:
4: 12
6: 3072
5: 3072
-11,5:
0: 63351
-11,6:
@ -8119,7 +8119,7 @@ entities:
-11,8:
4: 1
1: 17476
6: 256
5: 256
-11,7:
1: 17484
-10,5:
@ -8222,10 +8222,10 @@ entities:
0: 255
1: 57344
-8,11:
5: 816
6: 816
1: 34952
-9,11:
5: 2176
6: 2176
1: 8738
-8,12:
1: 34959
@ -8245,7 +8245,7 @@ entities:
-6,11:
0: 4095
-6,12:
5: 61166
6: 61166
-5,9:
0: 65535
-5,10:
@ -8253,7 +8253,7 @@ entities:
-5,11:
0: 36863
-5,12:
5: 30515
6: 30515
0: 12
-4,9:
0: 65535
@ -8263,7 +8263,7 @@ entities:
0: 4095
-4,12:
0: 1
5: 65518
6: 65518
-4,13:
1: 61680
-5,13:
@ -8277,7 +8277,7 @@ entities:
-5,15:
1: 17487
-3,12:
5: 13107
6: 13107
1: 34944
-3,13:
1: 47792
@ -8343,7 +8343,7 @@ entities:
1: 61713
-12,9:
0: 16
5: 3084
6: 3084
-13,9:
1: 39305
-13,10:
@ -8353,18 +8353,18 @@ entities:
0: 12544
-12,10:
3: 12
5: 3072
6: 3072
-12,11:
5: 12
6: 12
-11,9:
5: 257
6: 257
1: 17476
-11,10:
3: 1
5: 256
6: 256
1: 17476
-11,11:
5: 1
6: 1
1: 17476
-11,12:
1: 17487
@ -8418,7 +8418,7 @@ entities:
1: 15
-13,12:
1: 34952
6: 48
5: 48
4: 12288
-12,13:
1: 61455
@ -8452,11 +8452,11 @@ entities:
1: 62671
-7,14:
1: 244
5: 57344
6: 57344
0: 1024
-7,15:
1: 61440
5: 238
6: 238
0: 1024
-7,16:
1: 65524
@ -8515,7 +8515,7 @@ entities:
-14,12:
0: 1
1: 8738
6: 128
5: 128
4: 32768
-17,12:
0: 52232
@ -9040,7 +9040,7 @@ entities:
- volume: 2500
temperature: 293.15
moles:
- 0
- 6666.982
- 0
- 0
- 0
@ -9055,7 +9055,7 @@ entities:
- volume: 2500
temperature: 293.15
moles:
- 6666.982
- 0
- 0
- 0
- 0
@ -9075,6 +9075,16 @@ entities:
- type: GasTileOverlay
- type: GridPathfinding
- type: NavMap
- type: Joint
joints:
docking43669: !type:WeldJoint
bodyB: 60
bodyA: 7536
id: docking43669
localAnchorB: -47.5,-40
localAnchorA: 0.5,0
damping: 1559.7855
stiffness: 14000.604
- uid: 943
components:
- type: MetaData
@ -9356,6 +9366,16 @@ entities:
- type: GasTileOverlay
- type: RadiationGridResistance
- type: GridPathfinding
- type: Joint
joints:
docking43669: !type:WeldJoint
bodyB: 60
bodyA: 7536
id: docking43669
localAnchorB: -47.5,-40
localAnchorA: 0.5,0
damping: 1559.7855
stiffness: 14000.604
- proto: AcousticGuitarInstrument
entities:
- uid: 2133
@ -12011,6 +12031,13 @@ entities:
rot: 3.141592653589793 rad
pos: 0.5,-0.5
parent: 7536
- type: Docking
dockJointId: docking43669
dockedWith: 7332
- type: DeviceLinkSource
lastSignals:
DoorStatus: False
DockStatus: True
- proto: AirlockExternalLocked
entities:
- uid: 1435
@ -13331,10 +13358,16 @@ entities:
- type: Transform
pos: -47.5,-39.5
parent: 60
- type: Docking
dockJointId: docking43669
dockedWith: 8108
- type: DeviceLinkSource
linkedPorts:
7316:
- DoorStatus: DoorBolt
lastSignals:
DoorStatus: False
DockStatus: True
- type: DeviceLinkSink
links:
- 7316
@ -16567,7 +16600,7 @@ entities:
- uid: 178
components:
- type: Transform
pos: -26.404684,-13.628057
pos: -26.426329,-14.112597
parent: 60
- proto: BoxLatexGloves
entities:
@ -56281,18 +56314,6 @@ entities:
- type: Transform
pos: 45.485657,-24.447033
parent: 60
- proto: chem_master
entities:
- uid: 2626
components:
- type: Transform
pos: 41.5,-26.5
parent: 60
- uid: 2627
components:
- type: Transform
pos: 41.5,-29.5
parent: 60
- proto: ChemDispenser
entities:
- uid: 2520
@ -56312,6 +56333,18 @@ entities:
- type: Transform
pos: 40.5,-28.5
parent: 60
- proto: ChemMaster
entities:
- uid: 2626
components:
- type: Transform
pos: 41.5,-26.5
parent: 60
- uid: 2627
components:
- type: Transform
pos: 41.5,-29.5
parent: 60
- proto: ChessBoard
entities:
- uid: 5198
@ -67347,17 +67380,17 @@ entities:
- uid: 14454
components:
- type: Transform
pos: -26.766462,-13.446835
pos: -27.223204,-13.440722
parent: 60
- uid: 14618
components:
- type: Transform
pos: -26.953962,-13.46246
pos: -27.098204,-13.175097
parent: 60
- uid: 14625
components:
- type: Transform
pos: -26.860212,-13.30621
pos: -27.035704,-13.425097
parent: 60
- uid: 20082
components:
@ -68112,6 +68145,8 @@ entities:
- type: Transform
pos: -40.5,5.5
parent: 60
- type: FaxMachine
name: RD Office
- uid: 11100
components:
- type: Transform
@ -68168,6 +68203,13 @@ entities:
parent: 60
- type: FaxMachine
name: Library
- uid: 24176
components:
- type: Transform
pos: -26.5,-13.5
parent: 60
- type: FaxMachine
name: Security Fax
- proto: FaxMachineCaptain
entities:
- uid: 15836
@ -75245,11 +75287,15 @@ entities:
- uid: 898
components:
- type: Transform
anchored: False
rot: 1.5707963267948966 rad
pos: -10.5,-22.5
parent: 60
- type: AtmosPipeColor
color: '#0335FCFF'
- type: Physics
canCollide: True
bodyType: Dynamic
- uid: 899
components:
- type: Transform
@ -75277,11 +75323,15 @@ entities:
- uid: 902
components:
- type: Transform
anchored: False
rot: 1.5707963267948966 rad
pos: -13.5,-22.5
parent: 60
- type: AtmosPipeColor
color: '#0335FCFF'
- type: Physics
canCollide: True
bodyType: Dynamic
- uid: 903
components:
- type: Transform
@ -82912,11 +82962,15 @@ entities:
- uid: 8899
components:
- type: Transform
anchored: False
rot: 1.5707963267948966 rad
pos: 22.5,-31.5
parent: 60
- type: AtmosPipeColor
color: '#0335FCFF'
- type: Physics
canCollide: True
bodyType: Dynamic
- uid: 8918
components:
- type: Transform
@ -125617,7 +125671,7 @@ entities:
- type: Transform
pos: -2.5112958,-11.444662
parent: 60
- proto: soda_dispenser
- proto: SodaDispenser
entities:
- uid: 2257
components:

View file

@ -68,6 +68,16 @@
category: cargoproduct-category-name-service
group: market
- type: cargoProduct
id: ServiceFaxMachine
icon:
sprite: Structures/Machines/fax_machine.rsi
state: icon
product: CrateServiceFaxMachine
cost: 2000
category: cargoproduct-category-name-service
group: market
- type: cargoProduct
id: ServicePersonnel
icon:

View file

@ -129,6 +129,17 @@
- id: BoxFolderYellow
- id: NewtonCradle
- type: entity
id: CrateServiceFaxMachine
parent: CrateGenericSteel
name: fax machine crate
description: A fax machine and a screwdriver to set the name with.
components:
- type: StorageFill
contents:
- id: Screwdriver
- id: FaxMachineFlatpack
- type: entity
id: CrateServicePersonnel
parent: CrateCommandSecure

View file

@ -132,8 +132,8 @@
- type: entity
id: CrateVendingMachineRestockRobustSoftdrinksFilled
parent: CratePlastic
name: Robust Softdrinks restock crate
description: Contains two restock boxes for the Robust Softdrinks LLC vending machine.
name: beverage vendor restock crate
description: Contains restock boxes for beverage vending machines.
components:
- type: StorageFill
contents:

View file

@ -181,6 +181,9 @@
- MobMask
layer:
- MobLayer
- type: Speech
speechVerb: SmallMob
speechSounds: Cluck
- type: Tag
tags:
- DoorBumpOpener

View file

@ -204,3 +204,15 @@
components:
- type: Flatpack
entity: SpaceHeaterAnchored
- type: entity
parent: BaseFlatpack
id: FaxMachineFlatpack
name: fax machine flatpack
description: A flatpack used for constructing a fax machine.
components:
- type: Sprite
layers:
- state: fax-machine
- type: Flatpack
entity: FaxMachineBase

View file

@ -27,7 +27,7 @@
guides:
- Security
- type: UseDelay
delay: 6
delay: 30
- type: entity
name: makeshift handcuffs

View file

@ -400,6 +400,7 @@
# Short lifespan
- type: TimedDespawn
lifetime: 0.4
- type: GatheringProjectile
- type: entity
id: BulletKineticShuttle

View file

@ -94,6 +94,7 @@
- type: Clothing
sprite: Objects/Weapons/Guns/SMGs/c20r.rsi
- type: Wieldable
unwieldOnUse: false
- type: GunWieldBonus
minAngle: -19
maxAngle: -16
@ -131,6 +132,7 @@
- type: Clothing
sprite: Objects/Weapons/Guns/SMGs/drozd.rsi
- type: Wieldable
unwieldOnUse: false
- type: GunWieldBonus
minAngle: -19
maxAngle: -16

View file

@ -201,6 +201,7 @@
- BoxLethalshot
- BoxShotgunFlare
- BoxShotgunSlug
- CombatKnife
- MagazineBoxLightRifle
- MagazineBoxMagnum
- MagazineBoxPistol
@ -716,6 +717,7 @@
- BoxShotgunPractice
- BoxShotgunSlug
- ClothingEyesHudSecurity
- CombatKnife
- Flash
- ForensicPad
- Handcuffs

View file

@ -240,6 +240,30 @@
prob: 0.02
- id: MobMouseCancer
prob: 0.001
# Events always spawn a critter regardless of Probability https://github.com/space-wizards/space-station-14/issues/28480 I added the Rat King to their own event with a player cap.
- type: entity
id: KingRatMigration
parent: BaseStationEventShortDelay
components:
- type: StationEvent
startAnnouncement: station-event-vent-creatures-start-announcement
startAudio:
path: /Audio/Announcements/attention.ogg
earliestStart: 15
weight: 6
duration: 50
minimumPlayers: 15 # Hopefully this is enough for the Rat King's potential Army
- type: VentCrittersRule
entries:
- id: MobMouse
prob: 0.02
- id: MobMouse1
prob: 0.02
- id: MobMouse2
prob: 0.02
- id: MobMouseCancer
prob: 0.001
specialEntries:
- id: SpawnPointGhostRatKing
prob: 0.001

View file

@ -13,7 +13,7 @@
!type:NanotrasenNameGenerator
prefixCreator: 'B'
- type: StationEmergencyShuttle
emergencyShuttlePath: /Maps/Shuttles/emergency_delta.yml
emergencyShuttlePath: /Maps/Shuttles/emergency_accordia.yml
- type: StationJobs
availableJobs:
#service

View file

@ -150,3 +150,12 @@
path: /Audio/Animals/dog_bark3.ogg
exclaimSound:
path: /Audio/Animals/dog_bark2.ogg
- type: speechSounds
id: Cluck
saySound:
path: /Audio/Animals/chicken_cluck_happy.ogg
askSound:
path: /Audio/Animals/chicken_cluck_happy.ogg
exclaimSound:
path: /Audio/Animals/chicken_cluck_happy.ogg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 751 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 903 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Created by brainfood# 7460, hamster-0 resprite by RamZ (discord)",
"copyright": "Created by brainfood# 7460, hamster-0 resprite by RamZ (discord), inhands resprited by Vermidia.",
"size": {
"x": 32,
"y": 32
@ -59,11 +59,11 @@
"name": "splat-0"
},
{
"name": "0-inhand-left",
"name": "inhand-left",
"directions": 4
},
{
"name": "0-inhand-right",
"name": "inhand-right",
"directions": 4
}
]

Binary file not shown.

Before

Width:  |  Height:  |  Size: 482 B

After

Width:  |  Height:  |  Size: 807 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 492 B

After

Width:  |  Height:  |  Size: 792 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 508 B

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 510 B

After

Width:  |  Height:  |  Size: 811 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 491 B

After

Width:  |  Height:  |  Size: 805 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 499 B

After

Width:  |  Height:  |  Size: 801 B

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Taken from https://github.com/tgstation/tgstation/commit/e15c63d100db65eaaa5231133b8a2662ff439131#diff-8dd94e19fdb2ff341b57e31bce101298",
"copyright": "Taken from https://github.com/tgstation/tgstation/commit/e15c63d100db65eaaa5231133b8a2662ff439131#diff-8dd94e19fdb2ff341b57e31bce101298, modified by Vermidia.",
"size": {
"x": 32,
"y": 32

Binary file not shown.

After

Width:  |  Height:  |  Size: 897 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 898 B

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC-BY-SA-3.0",
"copyright": "Created by brainfood# 7460, hamlet resprite by RamZ (discord)",
"copyright": "Created by brainfood# 7460, hamlet resprite by RamZ (discord), inhands made by Vermidia",
"size": {
"x": 32,
"y": 32
@ -54,6 +54,14 @@
},
{
"name": "splat-0"
},
{
"name": "inhand-left",
"directions": 4
},
{
"name": "inhand-right",
"directions": 4
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 429 B

View file

@ -1,7 +1,7 @@
{
"version": 1,
"license": "CC0-1.0",
"copyright": "Created by EmoGarbage404 (github) for SS14, solar-assembly-part taken from tgstation and modified at https://tgstation13.org/wiki/Guide_to_construction#Solar_Panels_and_Trackers, ame-part taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1b7952787c06c21ef1623e494dcfe7cb1f46e041; singularity-generator, tesla-generator, radiation-collector, containment-field-generator, tesla-coil, grounding-rod inner icons made by lzk228; emitter made by pigeonpeas",
"copyright": "Created by EmoGarbage404 (github) for SS14, solar-assembly-part taken from tgstation and modified at https://tgstation13.org/wiki/Guide_to_construction#Solar_Panels_and_Trackers, ame-part taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1b7952787c06c21ef1623e494dcfe7cb1f46e041; singularity-generator, tesla-generator, radiation-collector, containment-field-generator, tesla-coil, grounding-rod inner icons made by lzk228; emitter made by pigeonpeas. fax-machine made by moomoobeef",
"size": {
"x": 32,
"y": 32
@ -42,6 +42,9 @@
},
{
"name": "emitter"
},
{
"name": "fax-machine"
}
]
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB