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

This commit is contained in:
VigersRay 2024-08-08 08:10:07 +03:00
commit 461f70ab28
35 changed files with 395 additions and 228 deletions

View file

@ -0,0 +1,10 @@
using Content.Shared.Atmos.EntitySystems;
using JetBrains.Annotations;
namespace Content.Client.Atmos.EntitySystems;
[UsedImplicitly]
public sealed class GasMinerSystem : SharedGasMinerSystem
{
}

View file

@ -90,7 +90,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
/// </summary>
private bool _isReplaying;
private float _deadzone;
public float Deadzone;
private DragState _state = DragState.NotDragging;
@ -122,7 +122,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
private void SetDeadZone(float deadZone)
{
_deadzone = deadZone;
Deadzone = deadZone;
}
public override void Shutdown()
@ -212,7 +212,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
_draggedEntity = entity;
_state = DragState.MouseDown;
_mouseDownScreenPos = _inputManager.MouseScreenPosition;
_mouseDownScreenPos = args.ScreenCoordinates;
_mouseDownTime = 0;
// don't want anything else to process the click,
@ -240,8 +240,13 @@ public sealed class DragDropSystem : SharedDragDropSystem
if (TryComp<SpriteComponent>(_draggedEntity, out var draggedSprite))
{
var screenPos = _inputManager.MouseScreenPosition;
// No _draggedEntity in null window (Happens in tests)
if (!screenPos.IsValid)
return;
// pop up drag shadow under mouse
var mousePos = _eyeManager.PixelToMap(_inputManager.MouseScreenPosition);
var mousePos = _eyeManager.PixelToMap(screenPos);
_dragShadow = EntityManager.SpawnEntity("dragshadow", mousePos);
var dragSprite = Comp<SpriteComponent>(_dragShadow.Value);
dragSprite.CopyFrom(draggedSprite);
@ -534,7 +539,7 @@ public sealed class DragDropSystem : SharedDragDropSystem
case DragState.MouseDown:
{
var screenPos = _inputManager.MouseScreenPosition;
if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > _deadzone)
if ((_mouseDownScreenPos!.Value.Position - screenPos.Position).Length() > Deadzone)
{
StartDrag();
}

View file

@ -1207,11 +1207,12 @@ public abstract partial class InteractionTest
BoundKeyFunction key,
BoundKeyState state,
NetCoordinates? coordinates = null,
NetEntity? cursorEntity = null)
NetEntity? cursorEntity = null,
ScreenCoordinates? screenCoordinates = null)
{
var coords = coordinates ?? TargetCoords;
var target = cursorEntity ?? Target ?? default;
ScreenCoordinates screen = default;
var screen = screenCoordinates ?? default;
var funcId = InputManager.NetworkBindMap.KeyFunctionID(key);
var message = new ClientFullInputCmdMessage(CTiming.CurTick, CTiming.TickFraction, funcId)

View file

@ -0,0 +1,46 @@
using Content.Client.Interaction;
using Content.IntegrationTests.Tests.Interaction;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Map;
namespace Content.IntegrationTests.Tests.Strip;
public sealed class StrippableTest : InteractionTest
{
protected override string PlayerPrototype => "MobHuman";
[Test]
public async Task DragDropOpensStrip()
{
// Spawn one tile away
TargetCoords = SEntMan.GetNetCoordinates(new EntityCoordinates(MapData.MapUid, 1, 0));
await SpawnTarget("MobHuman");
var userInterface = Comp<UserInterfaceComponent>(Target);
Assert.That(userInterface.Actors.Count == 0);
// screenCoordinates diff needs to be larger than DragDropSystem._deadzone
var screenX = CEntMan.System<DragDropSystem>().Deadzone + 1f;
// Start drag
await SetKey(EngineKeyFunctions.Use,
BoundKeyState.Down,
TargetCoords,
Target,
screenCoordinates: new ScreenCoordinates(screenX, 0f, WindowId.Main));
await RunTicks(5);
// End drag
await SetKey(EngineKeyFunctions.Use,
BoundKeyState.Up,
PlayerCoords,
Player,
screenCoordinates: new ScreenCoordinates(0f, 0f, WindowId.Main));
await RunTicks(5);
Assert.That(userInterface.Actors.Count > 0);
}
}

View file

@ -0,0 +1,90 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Atmos.Piping.Components;
using Content.Shared.Atmos;
using Content.Shared.Atmos.Components;
using Content.Shared.Atmos.EntitySystems;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
namespace Content.Server.Atmos.EntitySystems;
[UsedImplicitly]
public sealed class GasMinerSystem : SharedGasMinerSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
}
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
{
var miner = ent.Comp;
var oldState = miner.MinerState;
float toSpawn;
if (!GetValidEnvironment(ent, out var environment) || !Transform(ent).Anchored)
{
miner.MinerState = GasMinerState.Disabled;
}
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
else if ((toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment)) == 0)
{
miner.MinerState = GasMinerState.Idle;
}
else
{
miner.MinerState = GasMinerState.Working;
// Time to mine some gas.
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
merger.SetMoles(miner.SpawnGas, toSpawn);
_atmosphereSystem.Merge(environment, merger);
}
if (miner.MinerState != oldState)
{
Dirty(ent);
}
}
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
{
var (uid, miner) = ent;
var transform = Transform(uid);
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
// Treat space as an invalid environment
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
{
environment = null;
return false;
}
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
return environment != null;
}
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
{
var (uid, miner) = ent;
// How many moles could we theoretically spawn. Cap by pressure and amount.
var allowableMoles = Math.Min(
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
miner.MaxExternalAmount - environment.TotalMoles);
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
if (toSpawnReal < Atmospherics.GasMinMoles) {
return 0f;
}
return toSpawnReal;
}
}

View file

@ -1,43 +0,0 @@
using Content.Shared.Atmos;
namespace Content.Server.Atmos.Piping.Other.Components
{
[RegisterComponent]
public sealed partial class GasMinerComponent : Component
{
[ViewVariables(VVAccess.ReadWrite)]
public bool Enabled { get; set; } = true;
[ViewVariables(VVAccess.ReadOnly)]
public bool Idle { get; set; } = false;
/// <summary>
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxExternalAmount")]
public float MaxExternalAmount { get; set; } = float.PositiveInfinity;
/// <summary>
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("maxExternalPressure")]
public float MaxExternalPressure { get; set; } = Atmospherics.GasMinerDefaultMaxExternalPressure;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnGas")]
public Gas? SpawnGas { get; set; } = null;
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnTemperature")]
public float SpawnTemperature { get; set; } = Atmospherics.T20C;
/// <summary>
/// Number of moles created per second when the miner is working.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("spawnAmount")]
public float SpawnAmount { get; set; } = Atmospherics.MolesCellStandard * 20f;
}
}

View file

@ -1,84 +0,0 @@
using System.Diagnostics.CodeAnalysis;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Atmos.Piping.Components;
using Content.Server.Atmos.Piping.Other.Components;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Server.GameObjects;
namespace Content.Server.Atmos.Piping.Other.EntitySystems
{
[UsedImplicitly]
public sealed class GasMinerSystem : EntitySystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly TransformSystem _transformSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasMinerComponent, AtmosDeviceUpdateEvent>(OnMinerUpdated);
}
private void OnMinerUpdated(Entity<GasMinerComponent> ent, ref AtmosDeviceUpdateEvent args)
{
var miner = ent.Comp;
if (!GetValidEnvironment(ent, out var environment))
{
miner.Idle = true;
return;
}
// SpawnAmount is declared in mol/s so to get the amount of gas we hope to mine, we have to multiply this by
// how long we have been waiting to spawn it and further cap the number according to the miner's state.
var toSpawn = CapSpawnAmount(ent, miner.SpawnAmount * args.dt, environment);
miner.Idle = toSpawn == 0;
if (miner.Idle || !miner.Enabled || !miner.SpawnGas.HasValue)
return;
// Time to mine some gas.
var merger = new GasMixture(1) { Temperature = miner.SpawnTemperature };
merger.SetMoles(miner.SpawnGas.Value, toSpawn);
_atmosphereSystem.Merge(environment, merger);
}
private bool GetValidEnvironment(Entity<GasMinerComponent> ent, [NotNullWhen(true)] out GasMixture? environment)
{
var (uid, miner) = ent;
var transform = Transform(uid);
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
// Treat space as an invalid environment
if (_atmosphereSystem.IsTileSpace(transform.GridUid, transform.MapUid, position))
{
environment = null;
return false;
}
environment = _atmosphereSystem.GetContainingMixture((uid, transform), true, true);
return environment != null;
}
private float CapSpawnAmount(Entity<GasMinerComponent> ent, float toSpawnTarget, GasMixture environment)
{
var (uid, miner) = ent;
// How many moles could we theoretically spawn. Cap by pressure and amount.
var allowableMoles = Math.Min(
(miner.MaxExternalPressure - environment.Pressure) * environment.Volume / (miner.SpawnTemperature * Atmospherics.R),
miner.MaxExternalAmount - environment.TotalMoles);
var toSpawnReal = Math.Clamp(allowableMoles, 0f, toSpawnTarget);
if (toSpawnReal < Atmospherics.GasMinMoles) {
return 0f;
}
return toSpawnReal;
}
}
}

View file

@ -30,13 +30,12 @@ public sealed class TwoStageTriggerSystem : EntitySystem
{
foreach (var (name, entry) in component.SecondStageComponents)
{
var comp = (Component) _factory.GetComponent(name);
var temp = (object) comp;
var comp = (Component)_factory.GetComponent(name);
var temp = (object)comp;
if (EntityManager.TryGetComponent(uid, entry.Component.GetType(), out var c))
RemComp(uid, c);
comp.Owner = uid;
_serializationManager.CopyTo(entry.Component, ref temp);
EntityManager.AddComponent(uid, comp);
}

View file

@ -53,8 +53,7 @@ public sealed class RandomHumanoidSystem : EntitySystem
{
foreach (var entry in prototype.Components.Values)
{
var comp = (Component) _serialization.CreateCopy(entry.Component, notNullableOverride: true);
comp.Owner = humanoid; // This .owner must survive for now.
var comp = (Component)_serialization.CreateCopy(entry.Component, notNullableOverride: true);
EntityManager.RemoveComponent(humanoid, comp.GetType());
EntityManager.AddComponent(humanoid, comp);
}

View file

@ -23,12 +23,11 @@ namespace Content.Server.Jobs
foreach (var (name, data) in Components)
{
var component = (Component) factory.GetComponent(name);
component.Owner = mob;
var temp = (object) component;
var temp = (object)component;
serializationManager.CopyTo(data.Component, ref temp);
entityManager.RemoveComponent(mob, temp!.GetType());
entityManager.AddComponent(mob, (Component) temp);
entityManager.AddComponent(mob, (Component)temp);
}
}
}

View file

@ -6,7 +6,7 @@ namespace Content.Server.Speech
{
public sealed class AccentSystem : EntitySystem
{
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?])", RegexOptions.Compiled);
public static readonly Regex SentenceRegex = new(@"(?<=[\.!\?‽])(?![\.!\?‽])", RegexOptions.Compiled);
public override void Initialize()
{

View file

@ -7,5 +7,4 @@ namespace Content.Server.Speech.Components;
/// </summary>
[RegisterComponent]
[Access(typeof(FrenchAccentSystem))]
public sealed partial class FrenchAccentComponent : Component
{ }
public sealed partial class FrenchAccentComponent : Component {}

View file

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

View file

@ -27,10 +27,10 @@ public sealed class FrenchAccentSystem : EntitySystem
msg = _replacement.ApplyReplacements(msg, "french");
// replaces th with dz
// replaces th with z
msg = RegexTh.Replace(msg, "'z");
// removes the letter h from the start of words.
// replaces h with ' at the start of words.
msg = RegexStartH.Replace(msg, "'");
// spaces out ! ? : and ;.

View file

@ -1,3 +1,4 @@
using System.Text;
using Content.Server.Speech.Components;
namespace Content.Server.Speech.EntitySystems
@ -14,7 +15,7 @@ namespace Content.Server.Speech.EntitySystems
// Insert E before every S
message = InsertS(message);
// If a sentence ends with ?, insert a reverse ? at the beginning of the sentence
message = ReplaceQuestionMark(message);
message = ReplacePunctuation(message);
return message;
}
@ -36,24 +37,32 @@ namespace Content.Server.Speech.EntitySystems
return msg;
}
private string ReplaceQuestionMark(string message)
private string ReplacePunctuation(string message)
{
var sentences = AccentSystem.SentenceRegex.Split(message);
var msg = "";
var msg = new StringBuilder();
foreach (var s in sentences)
{
if (s.EndsWith("?", StringComparison.Ordinal)) // We've got a question => add ¿ to the beginning
var toInsert = new StringBuilder();
for (var i = s.Length - 1; i >= 0 && "?!‽".Contains(s[i]); i--)
{
// Because we don't split by whitespace, we may have some spaces in front of the sentence.
// So we add the symbol before the first non space char
msg += s.Insert(s.Length - s.TrimStart().Length, "¿");
toInsert.Append(s[i] switch
{
'?' => '¿',
'!' => '¡',
'‽' => '⸘',
_ => ' '
});
}
else
if (toInsert.Length == 0)
{
msg += s;
msg.Append(s);
} else
{
msg.Append(s.Insert(s.Length - s.TrimStart().Length, toInsert.ToString()));
}
}
return msg;
return msg.ToString();
}
private void OnAccent(EntityUid uid, SpanishAccentComponent component, AccentGetEvent args)

View file

@ -54,7 +54,6 @@ public sealed partial class BiomePrototype : IPrototype, IInheritingPrototype
foreach (var data in ChunkComponents.Values)
{
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
entityManager.AddComponent(target, comp);
}
}

View file

@ -30,7 +30,6 @@ public sealed partial class WorldgenConfigPrototype : IPrototype
foreach (var data in Components.Values)
{
var comp = (Component) serialization.CreateCopy(data.Component, notNullableOverride: true);
comp.Owner = target; // look im sorry ok this .owner has to live until engine api exists
entityManager.AddComponent(target, comp);
}
}

View file

@ -182,13 +182,12 @@ public sealed partial class ArtifactSystem
EntityManager.RemoveComponent(uid, reg.Type);
}
var comp = (Component) _componentFactory.GetComponent(reg);
comp.Owner = uid;
var comp = (Component)_componentFactory.GetComponent(reg);
var temp = (object) comp;
var temp = (object)comp;
_serialization.CopyTo(entry.Component, ref temp);
EntityManager.RemoveComponent(uid, temp!.GetType());
EntityManager.AddComponent(uid, (Component) temp!);
EntityManager.AddComponent(uid, (Component)temp!);
}
node.Discovered = true;
@ -218,12 +217,11 @@ public sealed partial class ArtifactSystem
// if the entity prototype contained the component originally
if (entityPrototype?.Components.TryGetComponent(name, out var entry) ?? false)
{
var comp = (Component) _componentFactory.GetComponent(name);
comp.Owner = uid;
var temp = (object) comp;
var comp = (Component)_componentFactory.GetComponent(name);
var temp = (object)comp;
_serialization.CopyTo(entry, ref temp);
EntityManager.RemoveComponent(uid, temp!.GetType());
EntityManager.AddComponent(uid, (Component) temp);
EntityManager.AddComponent(uid, (Component)temp);
continue;
}

View file

@ -0,0 +1,60 @@
using Robust.Shared.Serialization;
using Robust.Shared.GameStates;
namespace Content.Shared.Atmos.Components;
[NetworkedComponent]
[AutoGenerateComponentState]
[RegisterComponent]
public sealed partial class GasMinerComponent : Component
{
/// <summary>
/// Operational state of the miner.
/// </summary>
[AutoNetworkedField]
[ViewVariables(VVAccess.ReadOnly)]
public GasMinerState MinerState = GasMinerState.Disabled;
/// <summary>
/// If the number of moles in the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MaxExternalAmount = float.PositiveInfinity;
/// <summary>
/// If the pressure (in kPA) of the external environment exceeds this number, no gas will be mined.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float MaxExternalPressure = Atmospherics.GasMinerDefaultMaxExternalPressure;
/// <summary>
/// Gas to spawn.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField(required: true)]
public Gas SpawnGas;
/// <summary>
/// Temperature in Kelvin.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float SpawnTemperature = Atmospherics.T20C;
/// <summary>
/// Number of moles created per second when the miner is working.
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField]
public float SpawnAmount = Atmospherics.MolesCellStandard * 20f;
}
[Serializable, NetSerializable]
public enum GasMinerState : byte
{
Disabled,
Idle,
Working,
}

View file

@ -0,0 +1,55 @@
using Content.Shared.Atmos.Components;
using Content.Shared.Examine;
using Content.Shared.Temperature;
namespace Content.Shared.Atmos.EntitySystems;
public abstract class SharedGasMinerSystem : EntitySystem
{
[Dependency] private readonly SharedAtmosphereSystem _sharedAtmosphereSystem = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<GasMinerComponent, ExaminedEvent>(OnExamine);
}
private void OnExamine(Entity<GasMinerComponent> ent, ref ExaminedEvent args)
{
var component = ent.Comp;
using (args.PushGroup(nameof(GasMinerComponent)))
{
args.PushMarkup(Loc.GetString("gas-miner-mines-text",
("gas", Loc.GetString(_sharedAtmosphereSystem.GetGas(component.SpawnGas).Name))));
args.PushText(Loc.GetString("gas-miner-amount-text",
("moles", $"{component.SpawnAmount:0.#}")));
args.PushText(Loc.GetString("gas-miner-temperature-text",
("tempK", $"{component.SpawnTemperature:0.#}"),
("tempC", $"{TemperatureHelpers.KelvinToCelsius(component.SpawnTemperature):0.#}")));
if (component.MaxExternalAmount < float.PositiveInfinity)
{
args.PushText(Loc.GetString("gas-miner-moles-cutoff-text",
("moles", $"{component.MaxExternalAmount:0.#}")));
}
if (component.MaxExternalPressure < float.PositiveInfinity)
{
args.PushText(Loc.GetString("gas-miner-pressure-cutoff-text",
("pressure", $"{component.MaxExternalPressure:0.#}")));
}
args.AddMarkup(component.MinerState switch
{
GasMinerState.Disabled => Loc.GetString("gas-miner-state-disabled-text"),
GasMinerState.Idle => Loc.GetString("gas-miner-state-idle-text"),
GasMinerState.Working => Loc.GetString("gas-miner-state-working-text"),
// C# pattern matching is not exhaustive for enums
_ => throw new IndexOutOfRangeException(nameof(component.MinerState)),
});
}
}
}

View file

@ -369,11 +369,10 @@ public abstract class SharedMagicSystem : EntitySystem
if (HasComp(ev.Target, data.Component.GetType()))
continue;
var component = (Component) _compFact.GetComponent(name);
component.Owner = ev.Target;
var temp = (object) component;
var component = (Component)_compFact.GetComponent(name);
var temp = (object)component;
_seriMan.CopyTo(data.Component, ref temp);
EntityManager.AddComponent(ev.Target, (Component) temp!);
EntityManager.AddComponent(ev.Target, (Component)temp!);
}
}
// End Change Component Spells

View file

@ -80,11 +80,6 @@ public partial class MobStateSystem
case MobState.Dead:
RemComp<CollisionWakeComponent>(target);
_standing.Stand(target);
if (!_standing.IsDown(target) && TryComp<PhysicsComponent>(target, out var physics))
{
_physics.SetCanCollide(target, true, body: physics);
}
break;
case MobState.Invalid:
//unused
@ -115,12 +110,6 @@ public partial class MobStateSystem
case MobState.Dead:
EnsureComp<CollisionWakeComponent>(target);
_standing.Down(target);
if (_standing.IsDown(target) && TryComp<PhysicsComponent>(target, out var physics))
{
_physics.SetCanCollide(target, false, body: physics);
}
_appearance.SetData(target, MobStateVisuals.State, MobState.Dead);
break;
case MobState.Invalid:

View file

@ -1,28 +1,4 @@
Entries:
- author: Plykiya
changes:
- message: The ninja's katana dash is now more reliable.
type: Fix
id: 6556
time: '2024-05-08T10:21:59.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27793
- author: K-Dynamic
changes:
- message: Bike Horns, Suspenders and the Clown Recorder are now available from
the Theatrical Performances Crate
type: Tweak
id: 6557
time: '2024-05-08T12:30:43.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27668
- author: Riolume
changes:
- message: Added ability to drink from spray bottles
type: Add
- message: Can now see the amount of liquid in spray bottles
type: Add
id: 6558
time: '2024-05-09T05:56:13.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/27815
- author: Blackern5000
changes:
- message: Atmos metal pipes now deal blunt damage.
@ -3784,3 +3760,24 @@
id: 7055
time: '2024-08-07T09:26:40.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29746
- author: IProduceWidgets
changes:
- message: butter is slippery
type: Tweak
id: 7056
time: '2024-08-07T21:47:03.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/29772
- author: Mervill
changes:
- message: Gas Miners now have detailed examine text
type: Tweak
id: 7057
time: '2024-08-08T02:14:31.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30480
- author: BackeTako
changes:
- message: "!, \u203D and multiple punctuations now work for Spanish."
type: Tweak
id: 7058
time: '2024-08-08T03:08:28.0000000+00:00'
url: https://github.com/space-wizards/space-station-14/pull/30551

View file

@ -1,3 +1,5 @@
advertisement-atmosdrobe-1 = Get your inflammable clothing right here!!!
advertisement-atmosdrobe-2 = Protects you against plasma fires!
advertisement-atmosdrobe-3 = Enjoy your off-brand engineering clothing!
advertisement-atmosdrobe-3 = Enjoy your off-brand engineering clothing!
advertisement-atmosdrobe-4 = Always under control of your atmosphere!
advertisement-atmosdrobe-5 = Providing comfort in every breath!

View file

@ -1,3 +1,4 @@
advertisement-chefdrobe-1 = Our clothes are guaranteed to protect you from food splatters!
advertisement-chefdrobe-1 = Our clothes are guaranteed to protect you from food splatters!
advertisement-chefdrobe-2 = Perfectly white, so everyone knows about the murder in the kitchen!
advertisement-chefdrobe-3 = Easy to clean, easy to see!
advertisement-chefdrobe-4 = Cook like a pro, look like a maestro!

View file

@ -1,3 +1,4 @@
advertisement-chemdrobe-1 = Our clothes are 0.5% more resistant to acid spills! Get yours now!
advertisement-chemdrobe-2 = Professional laboratory clothing, designed by NanoTrasen!
advertisement-chemdrobe-3 = I'm pretty sure these will protect you against acid spills!
advertisement-chemdrobe-3 = I'm pretty sure these will protect you against acid spills!
advertisement-chemdrobe-4 = The best fashion formula!

View file

@ -3,6 +3,7 @@ advertisement-donut-2 = Hope you're hunger!
advertisement-donut-3 = Over 1 million donuts sold!
advertisement-donut-4 = We pride ourselves in the consistency of our products!
advertisement-donut-5 = Sweet, sugary and delicious!
advertisement-donut-6 = Donut worry, be happy!
thankyou-donut-1 = Enjoy your donut!
thankyou-donut-2 = Another donut sold!
thankyou-donut-3 = Have a nice day, officer!

View file

@ -1,4 +1,5 @@
advertisement-hydrobe-1 = Do you love soil? Then buy our clothes!
advertisement-hydrobe-2 = Get outfits to match your green thumb here!
advertisement-hydrobe-3 = Here to give you an outfit perfect for handling plants!
advertisement-hydrobe-4 = Perfect outfits for tree huggers... or just literal trees!
advertisement-hydrobe-4 = Perfect outfits for tree huggers... or just literal trees!
advertisement-hydrobe-5 = Wear green and grow!

View file

@ -1,4 +1,5 @@
advertisement-janidrobe-1 = Come and get your janitorial clothing, now endorsed by lizard janitors everywhere!
advertisement-janidrobe-2 = Here to keep you clean as you clean up non-clean things!
advertisement-janidrobe-3 = Stylishly yellow!
advertisement-janidrobe-4 = Polish your appearance with JaniDrobe!
advertisement-janidrobe-5 = Shine like a shiny floor!

View file

@ -6,6 +6,7 @@ advertisement-lawdrobe-5 = No one is above the law!
advertisement-lawdrobe-6 = No officer, I do not consent to a search!
advertisement-lawdrobe-7 = Injecting space drugs leaves no evidence!
advertisement-lawdrobe-8 = You or a loved one hurt by Nanotrasen? Too bad!
advertisement-lawdrobe-9 = Case closed! Defendant has too much drip!
thankyou-lawdrobe-1 = You can win any case in that outfit!
thankyou-lawdrobe-2 = Get one for your client as well!
thankyou-lawdrobe-3 = Win or lose, you get paid either way!

View file

@ -1,3 +1,4 @@
advertisement-medidrobe-1 = Make those blood stains look fashionable!!
advertisement-medidrobe-2 = Clean and hygienic! Don't get too many bloodstains on yourself!
advertisement-medidrobe-3 = With these outfits, you'll look like a professional doctor now!
advertisement-medidrobe-4 = Jumpsuit, check. Coat, check. Someone who will wear this? Check!

View file

@ -0,0 +1,11 @@
gas-miner-mines-text = It mines [color=lightgray]{$gas}[/color] when active.
gas-miner-amount-text = It mines {$moles} moles of gas a second when active.
gas-miner-temperature-text = Mined gas temp: {$tempK}K ({$tempC}°C).
gas-miner-moles-cutoff-text = Surrounding moles cutoff: {$moles} moles.
gas-miner-pressure-cutoff-text = Surrounding pressure cutoff: {$pressure} kPA.
gas-miner-state-working-text = The miner is [color=green]active[/color] and mining gas.
gas-miner-state-idle-text = The miner is [color=yellow]idle[/color] and not mining gas.
gas-miner-state-disabled-text = The miner is [color=red]disabled[/color] and not mining gas.

View file

@ -8,7 +8,7 @@
id: AtmosDrobeAds
values:
prefix: advertisement-atmosdrobe-
count: 3
count: 5
- type: localizedDataset
id: BarDrobeAds
@ -38,7 +38,7 @@
id: ChefDrobeAds
values:
prefix: advertisement-chefdrobe-
count: 3
count: 4
- type: localizedDataset
id: ChefvendAds
@ -50,7 +50,7 @@
id: ChemDrobeAds
values:
prefix: advertisement-chemdrobe-
count: 3
count: 4
- type: localizedDataset
id: CigaretteMachineAds
@ -110,7 +110,7 @@
id: DonutAds
values:
prefix: advertisement-donut-
count: 5
count: 6
- type: localizedDataset
id: EngiDrobeAds
@ -146,19 +146,19 @@
id: HyDrobeAds
values:
prefix: advertisement-hydrobe-
count: 4
count: 5
- type: localizedDataset
id: JaniDrobeAds
values:
prefix: advertisement-janidrobe-
count: 3
count: 5
- type: localizedDataset
id: LawDrobeAds
values:
prefix: advertisement-lawdrobe-
count: 8
count: 9
- type: localizedDataset
id: MagiVendAds
@ -170,7 +170,7 @@
id: MediDrobeAds
values:
prefix: advertisement-medidrobe-
count: 3
count: 4
- type: localizedDataset
id: MegaSeedAds

View file

@ -1,4 +1,5 @@
# Lots of misc stuff in here, hard to parent it.
# ^ Yeah, this stuff should probably get split into different files but not my fight today.
# Powder (For when you throw stuff like flour and it explodes)
@ -481,10 +482,33 @@
components:
- type: Sprite
state: butter
- type: Slippery
- type: StepTrigger
intersectRatio: 0.2
- type: CollisionWake
enabled: false
- type: Physics
bodyType: Dynamic
- type: Fixtures
fixtures:
slips:
shape:
!type:PhysShapeAabb
bounds: "-0.3,-0.2,0.3,0.2"
layer:
- SlipLayer
hard: false
fix1:
shape:
!type:PhysShapeAabb
bounds: "-0.3,-0.2,0.3,0.2"
density: 10
mask:
- ItemMask
- type: entity
name: stick of cannabis butter
parent: FoodBakingBase
parent: FoodButter
id: FoodCannabisButter
description: Add this to your favorite baked goods for an irie time.
components:

@ -1 +1 @@
Subproject commit 5c0ce43e6c3c22a939fad8a9f9848e489b135651
Subproject commit 49c831b48d1449e90a65acdb0c276d2deea4ce2c