From 8939fa10df019d71d76dc6399a8a0dc164d74106 Mon Sep 17 00:00:00 2001 From: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> Date: Thu, 18 Jul 2024 11:22:51 +0300 Subject: [PATCH 1/8] Fix Foreigner Translators AGAIN (#559) # Description Previous fix made it so that foreigner translators use no power (due to being parented off of the wrong proto). So I took some time to rearrange translators.yml because the file was shitfucked and that's what caused the mistake in the first place. This time it was made sure that: - All (powered) translators can hold a power cell and do use power - Foreigner's translator starts with a high-cap power cell and unspawnable Translator spawns with a medium - All children of the base powered translator spawn without a power cell and cannot work as such until a power cell is inserted. --- # Changelog :cl: - fix: Foreigner translator should now consume power, as intended. Signed-off-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com> --- .../Entities/Objects/Devices/translators.yml | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/Resources/Prototypes/Entities/Objects/Devices/translators.yml b/Resources/Prototypes/Entities/Objects/Devices/translators.yml index 2eb44264548..d75b7af7fd6 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/translators.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/translators.yml @@ -1,3 +1,4 @@ +# Translator that doesn't need power to work - type: entity noSpawn: true id: TranslatorUnpowered @@ -29,37 +30,38 @@ unequipDelay: 0.3 quickEquip: false # Would conflict +# Base translator that uses a power cell. Starts with an empty slot. - type: entity noSpawn: true - id: Translator + id: TranslatorPoweredBase parent: [ TranslatorUnpowered, PowerCellSlotMediumItem ] - suffix: Powered components: - type: PowerCellDraw drawRate: 1 - -- type: entity - noSpawn: true - id: TranslatorEmpty - parent: Translator - suffix: Empty - components: - type: ItemSlots slots: cell_slot: name: power-cell-slot-component-slot-name-default +# Normal translator with medium power cell in it +- type: entity + noSpawn: true + id: Translator + parent: [ PowerCellSlotMediumItem, TranslatorPoweredBase ] + suffix: Powered + +# Normal translator with a high power cell and special appearance - type: entity noSpawn: true id: TranslatorForeigner - parent: [ TranslatorUnpowered, PowerCellSlotHighItem ] + parent: [ PowerCellSlotHighItem, TranslatorPoweredBase ] name: foreigner's translator description: A special-issue translator that helps foreigner's speak and understand this station's primary language. - type: entity id: CanilunztTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Canilunzt translator description: Translates speech between Canilunzt and Galactic Common, allowing your local yeepers to communicate with the locals and vice versa! components: @@ -76,7 +78,7 @@ - type: entity id: BubblishTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Bubblish translator description: Translates speech between Bubblish and Galactic Common, helping communicate with slimes and slime people. components: @@ -93,7 +95,7 @@ - type: entity id: NekomimeticTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Nekomimetic translator description: Translates speech between Nekomimetic and Galactic Common, enabling you to communicate with your pet cats. components: @@ -110,7 +112,7 @@ - type: entity id: DraconicTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Draconic translator description: Translates speech between Draconic and Galactic Common, making it easier to understand your local Uniathi. components: @@ -127,7 +129,7 @@ - type: entity id: SolCommonTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Sol Common translator description: Translates speech between Sol Common and Galactic Common. Like a true Earthman! components: @@ -144,7 +146,7 @@ - type: entity id: RootSpeakTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: RootSpeak translator description: Translates speech between RootSpeak and Galactic Common. You may now speak for the trees. components: @@ -161,7 +163,7 @@ - type: entity id: MofficTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Moffic translator description: Translates speech between Moffic and Galactic Common, helping you understand the buzzes of your pet mothroach! components: @@ -178,7 +180,7 @@ - type: entity id: XenoTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Xeno translator description: Translates speech between Xeno and Galactic Common. This will probably not help you survive an encounter, though. components: @@ -194,7 +196,7 @@ - type: entity id: AnimalTranslator - parent: [ TranslatorEmpty ] + parent: [ TranslatorPoweredBase ] name: Animal translator description: Translates all the cutes noises that most animals make into a more understandable form! components: From 20fe5d3887148186c31e321db7fb21e0b1365088 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Thu, 18 Jul 2024 08:23:18 +0000 Subject: [PATCH 2/8] Automatic Changelog Update (#559) --- Resources/Changelog/Changelog.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 6f15a1c5c3d..99af9f7d9bd 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4529,3 +4529,9 @@ Entries: wear due to having digitigrade legs. id: 6168 time: '2024-07-18T02:34:52.0000000+00:00' +- author: Mnemotechnician + changes: + - type: Fix + message: Foreigner translator should now consume power, as intended. + id: 6169 + time: '2024-07-18T08:22:52.0000000+00:00' From 952953be0788a5d4154de1e5c76ae042cc06a112 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 18 Jul 2024 04:24:58 -0400 Subject: [PATCH 3/8] Physics Based Air Throws (#342) # Description I've made it so that when a room is explosively depressurized(or when a body of high pressure air flows into one of lower pressure air), that entities inside are launched by the air pressure with effects according to their mass. An entity's mass is now used as an innate resistance to forced movement by airflow, and more massive entities are both less likely to be launched, and will launch less far than others. While lighter entities are launched far more easily, and will shoot off into space quite quickly! Spacing departments has never been so exciting! This can be made extraordinarily fun if more objects are given the ability to injure people when colliding with them at high speeds. As a note, Humans are very unlikely to be sucked into space at a typical force generated from a 101kpa room venting into 0kpa, unless they happened to be standing right next to the opening to space when it was created. The same cannot be said for "Lighter-Than-Human" species such as Felinids and Harpies. I guess that's just the price to pay for being cute. :) On a plus side, because the math behind this is simplified even further than it was before, this actually runs more efficiently than the previous system. # TODO Nothing, this is basically done. I've spent a good 6 hours straight finely tuning the system until I was satisfied that it reflects something close to reality. # MEDIA **Before the Space Wind Rework:** https://github.com/Simple-Station/Einstein-Engines/assets/16548818/0bf56c50-58e6-4aef-97f8-027fbe62331e **With this Rework:** https://github.com/Simple-Station/Einstein-Engines/assets/16548818/6be507a9-e9de-4bb8-9d46-8b7c83ed5f1d # Changelog :cl: VMSolidus - add: Atmospheric "Throws" are now calculated using object mass, and behave accordingly. Tiny objects will shoot out of rooms quite fast! --------- Signed-off-by: VMSolidus Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> --- .../EntitySystems/AtmosphereSystem.CVars.cs | 12 ++ .../AtmosphereSystem.HighPressureDelta.cs | 93 ++++++---------- .../AtmosphereSystem.Monstermos.cs | 19 ++-- .../Atmos/EntitySystems/AtmosphereSystem.cs | 2 + .../Temperature/Systems/TemperatureSystem.cs | 5 +- Content.Shared/CCVar/CCVars.cs | 50 ++++++++- Content.Shared/Maps/ContentTileDefinition.cs | 6 + .../Prototypes/Entities/Mobs/NPCs/animals.yml | 46 ++++++-- Resources/Prototypes/Tiles/floors.yml | 103 ++++++++++++++++++ 9 files changed, 255 insertions(+), 81 deletions(-) diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs index 3aaa5429fb0..4d50700738b 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.CVars.cs @@ -12,9 +12,14 @@ public sealed partial class AtmosphereSystem public float SpaceWindPressureForceDivisorPush { get; private set; } public float SpaceWindMaxVelocity { get; private set; } public float SpaceWindMaxPushForce { get; private set; } + public float SpaceWindMinimumCalculatedMass { get; private set; } + public float SpaceWindMaximumCalculatedInverseMass { get; private set; } + public bool MonstermosUseExpensiveAirflow { get; private set; } public bool MonstermosEqualization { get; private set; } public bool MonstermosDepressurization { get; private set; } public bool MonstermosRipTiles { get; private set; } + public float MonstermosRipTilesMinimumPressure { get; private set; } + public float MonstermosRipTilesPressureOffset { get; private set; } public bool GridImpulse { get; private set; } public float SpacingEscapeRatio { get; private set; } public float SpacingMinGas { get; private set; } @@ -26,6 +31,7 @@ public sealed partial class AtmosphereSystem public float AtmosTickRate { get; private set; } public float Speedup { get; private set; } public float HeatScale { get; private set; } + public float HumanoidThrowMultiplier { get; private set; } /// /// Time between each atmos sub-update. If you are writing an atmos device, use AtmosDeviceUpdateEvent.dt @@ -41,9 +47,14 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.SpaceWindPressureForceDivisorPush, value => SpaceWindPressureForceDivisorPush = value, true); Subs.CVar(_cfg, CCVars.SpaceWindMaxVelocity, value => SpaceWindMaxVelocity = value, true); Subs.CVar(_cfg, CCVars.SpaceWindMaxPushForce, value => SpaceWindMaxPushForce = value, true); + Subs.CVar(_cfg, CCVars.SpaceWindMinimumCalculatedMass, value => SpaceWindMinimumCalculatedMass = value, true); + Subs.CVar(_cfg, CCVars.SpaceWindMaximumCalculatedInverseMass, value => SpaceWindMaximumCalculatedInverseMass = value, true); + Subs.CVar(_cfg, CCVars.MonstermosUseExpensiveAirflow, value => MonstermosUseExpensiveAirflow = value, true); Subs.CVar(_cfg, CCVars.MonstermosEqualization, value => MonstermosEqualization = value, true); Subs.CVar(_cfg, CCVars.MonstermosDepressurization, value => MonstermosDepressurization = value, true); Subs.CVar(_cfg, CCVars.MonstermosRipTiles, value => MonstermosRipTiles = value, true); + Subs.CVar(_cfg, CCVars.MonstermosRipTilesMinimumPressure, value => MonstermosRipTilesMinimumPressure = value, true); + Subs.CVar(_cfg, CCVars.MonstermosRipTilesPressureOffset, value => MonstermosRipTilesPressureOffset = value, true); Subs.CVar(_cfg, CCVars.AtmosGridImpulse, value => GridImpulse = value, true); Subs.CVar(_cfg, CCVars.AtmosSpacingEscapeRatio, value => SpacingEscapeRatio = value, true); Subs.CVar(_cfg, CCVars.AtmosSpacingMinGas, value => SpacingMinGas = value, true); @@ -55,6 +66,7 @@ private void InitializeCVars() Subs.CVar(_cfg, CCVars.AtmosHeatScale, value => { HeatScale = value; InitializeGases(); }, true); Subs.CVar(_cfg, CCVars.ExcitedGroups, value => ExcitedGroups = value, true); Subs.CVar(_cfg, CCVars.ExcitedGroupsSpaceIsAllConsuming, value => ExcitedGroupsSpaceIsAllConsuming = value, true); + Subs.CVar(_cfg, CCVars.AtmosHumanoidThrowMultiplier, value => HumanoidThrowMultiplier = value, true); } } } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs index cb50ff114e0..461435f0624 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.HighPressureDelta.cs @@ -1,5 +1,6 @@ using Content.Server.Atmos.Components; using Content.Shared.Atmos; +using Content.Shared.Humanoid; using Content.Shared.Mobs.Components; using Content.Shared.Physics; using Robust.Shared.Audio; @@ -49,8 +50,7 @@ private void UpdateHighPressure(float frameTime) comp.Accumulator = 0f; toRemove.Add(ent); - if (HasComp(uid) && - TryComp(uid, out var body)) + if (TryComp(uid, out var body)) { _physics.SetBodyStatus(uid, body, BodyStatus.OnGround); } @@ -70,27 +70,10 @@ private void UpdateHighPressure(float frameTime) } } - private void AddMobMovedByPressure(EntityUid uid, MovedByPressureComponent component, PhysicsComponent body) - { - if (!TryComp(uid, out var fixtures)) - return; - - _physics.SetBodyStatus(uid, body, BodyStatus.InAir); - - foreach (var (id, fixture) in fixtures.Fixtures) - { - _physics.RemoveCollisionMask(uid, id, fixture, (int) CollisionGroup.TableLayer, manager: fixtures); - } - - // TODO: Make them dynamic type? Ehh but they still want movement so uhh make it non-predicted like weightless? - // idk it's hard. - - component.Accumulator = 0f; - _activePressures.Add((uid, component)); - } - private void HighPressureMovements(Entity gridAtmosphere, TileAtmosphere tile, EntityQuery bodies, EntityQuery xforms, EntityQuery pressureQuery, EntityQuery metas) { + if (tile.PressureDifference < SpaceWindMinimumCalculatedMass * SpaceWindMinimumCalculatedMass) + return; // TODO ATMOS finish this // Don't play the space wind sound on tiles that are on fire... @@ -120,7 +103,8 @@ private void HighPressureMovements(Entity gridAtmospher var gridWorldRotation = xforms.GetComponent(gridAtmosphere).WorldRotation; // If we're using monstermos, smooth out the yeet direction to follow the flow - if (MonstermosEqualization) + //TODO This is bad, don't run this. It just makes the throws worse by somehow rounding them to orthogonal + if (!MonstermosEqualization) { // We step through tiles according to the pressure direction on the current tile. // The goal is to get a general direction of the airflow in the area. @@ -160,7 +144,7 @@ private void HighPressureMovements(Entity gridAtmospher (entity, pressureMovements), gridAtmosphere.Comp.UpdateCounter, tile.PressureDifference, - tile.PressureDirection, 0, + tile.PressureDirection, tile.PressureSpecificTarget != null ? _mapSystem.ToCenterCoordinates(tile.GridIndex, tile.PressureSpecificTarget.GridIndices) : EntityCoordinates.Invalid, gridWorldRotation, xforms.GetComponent(entity), @@ -181,12 +165,29 @@ private void ConsiderPressureDifference(GridAtmosphereComponent gridAtmosphere, tile.PressureDirection = differenceDirection; } + //INFO The EE version of this function drops pressureResistanceProbDelta, since it's not needed. If you are for whatever reason calling this function + //INFO And if it isn't working, you've probably still got the pressureResistanceProbDelta line included. + /// + /// EXPLANATION: + /// pressureDifference = Force of Air Flow on a given tile + /// physics.Mass = Mass of the object potentially being thrown + /// physics.InvMass = 1 divided by said Mass. More CPU efficient way to do division. + /// + /// Objects can only be thrown if the force of air flow is greater than the SQUARE of their mass or {SpaceWindMinimumCalculatedMass}, whichever is heavier + /// This means that the heavier an object is, the exponentially more force is required to move it + /// The force of a throw is equal to the force of air pressure, divided by an object's mass. So not only are heavier objects + /// less likely to be thrown, they are also harder to throw, + /// while lighter objects are yeeted easily, and from great distance. + /// + /// For a human sized entity with a standard weight of 80kg and a spacing between a hard vacuum and a room pressurized at 101kpa, + /// The human shall only be moved if he is either very close to the hole, or is standing in a region of high airflow + /// + public void ExperiencePressureDifference( Entity ent, int cycle, float pressureDifference, AtmosDirection direction, - float pressureResistanceProbDelta, EntityCoordinates throwTarget, Angle gridWorldRotation, TransformComponent? xform = null, @@ -199,50 +200,28 @@ public void ExperiencePressureDifference( if (!Resolve(uid, ref xform)) return; - // TODO ATMOS stuns? - - var maxForce = MathF.Sqrt(pressureDifference) * 2.25f; - var moveProb = 100f; - if (component.PressureResistance > 0) - moveProb = MathF.Abs((pressureDifference / component.PressureResistance * MovedByPressureComponent.ProbabilityBasePercent) - - MovedByPressureComponent.ProbabilityOffset); - - // Can we yeet the thing (due to probability, strength, etc.) - if (moveProb > MovedByPressureComponent.ProbabilityOffset && _robustRandom.Prob(MathF.Min(moveProb / 100f, 1f)) - && !float.IsPositiveInfinity(component.MoveResist) - && (physics.BodyType != BodyType.Static - && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForcePushRatio))) - || (physics.BodyType == BodyType.Static && (maxForce >= (component.MoveResist * MovedByPressureComponent.MoveForceForcePushRatio)))) + if (physics.BodyType != BodyType.Static + && !float.IsPositiveInfinity(component.MoveResist)) { - if (HasComp(uid)) + var moveForce = pressureDifference * MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass); + if (HasComp(ent)) + moveForce *= HumanoidThrowMultiplier; + if (moveForce > physics.Mass) { - AddMobMovedByPressure(uid, component, physics); - } - - if (maxForce > MovedByPressureComponent.ThrowForce) - { - var moveForce = maxForce; - moveForce /= (throwTarget != EntityCoordinates.Invalid) ? SpaceWindPressureForceDivisorThrow : SpaceWindPressureForceDivisorPush; - moveForce *= MathHelper.Clamp(moveProb, 0, 100); - - // Apply a sanity clamp to prevent being thrown through objects. - var maxSafeForceForObject = SpaceWindMaxVelocity * physics.Mass; - moveForce = MathF.Min(moveForce, maxSafeForceForObject); - // Grid-rotation adjusted direction var dirVec = (direction.ToAngle() + gridWorldRotation).ToWorldVec(); + moveForce *= MathF.Max(physics.InvMass, SpaceWindMaximumCalculatedInverseMass); - // TODO: Technically these directions won't be correct but uhh I'm just here for optimisations buddy not to fix my old bugs. + //TODO Consider replacing throw target with proper trigonometry angles. if (throwTarget != EntityCoordinates.Invalid) { - var pos = ((throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition).Normalized() + dirVec).Normalized(); - _physics.ApplyLinearImpulse(uid, pos * moveForce, body: physics); + var pos = throwTarget.ToMap(EntityManager, _transformSystem).Position - xform.WorldPosition + dirVec; + _throwing.TryThrow(uid, pos.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce); } else { - moveForce = MathF.Min(moveForce, SpaceWindMaxPushForce); - _physics.ApplyLinearImpulse(uid, dirVec * moveForce, body: physics); + _throwing.TryThrow(uid, dirVec.Normalized() * MathF.Min(moveForce, SpaceWindMaxVelocity), moveForce); } component.LastHighPressureMovementAirCycle = cycle; diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs index dcbc1e86ee2..1ba9a48aa0c 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Monstermos.cs @@ -5,11 +5,13 @@ using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Database; +using Content.Shared.Maps; +using Robust.Shared.Map; using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; +using Robust.Shared.Prototypes; using Robust.Shared.Random; using Robust.Shared.Utility; - namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem @@ -137,7 +139,7 @@ private void EqualizePressureInZone( var logN = MathF.Log2(tileCount); // Optimization - try to spread gases using an O(n log n) algorithm that has a chance of not working first to avoid O(n^2) - if (giverTilesLength > logN && takerTilesLength > logN) + if (!MonstermosUseExpensiveAirflow && giverTilesLength > logN && takerTilesLength > logN) { // Even if it fails, it will speed up the next part. Array.Sort(_equalizeTiles, 0, tileCount, _monstermosComparer); @@ -550,7 +552,8 @@ private void ExplosivelyDepressurize( } InvalidateVisuals(otherTile.GridIndex, otherTile.GridIndices, visuals); - HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.MonstermosInfo.CurrentTransferAmount); + if (MonstermosRipTiles && otherTile.PressureDifference > MonstermosRipTilesMinimumPressure) + HandleDecompressionFloorRip(mapGrid, otherTile, otherTile.PressureDifference); } if (GridImpulse && tileCount > 0) @@ -676,14 +679,14 @@ private void AdjustEqMovement(TileAtmosphere tile, AtmosDirection direction, flo adj.MonstermosInfo[direction.GetOpposite()] -= amount; } - private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float sum) + private void HandleDecompressionFloorRip(MapGridComponent mapGrid, TileAtmosphere tile, float delta) { - if (!MonstermosRipTiles) + if (!mapGrid.TryGetTileRef(tile.GridIndices, out var tileRef)) return; + var tileref = tileRef.Tile; - var chance = MathHelper.Clamp(0.01f + (sum / SpacingMaxWind) * 0.3f, 0.003f, 0.3f); - - if (sum > 20 && _robustRandom.Prob(chance)) + var tileDef = (ContentTileDefinition) _tileDefinitionManager[tileref.TypeId]; + if (!tileDef.Reinforced && tileDef.TileRipResistance < delta * MonstermosRipTilesPressureOffset) PryTile(mapGrid, tile.GridIndices); } diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index d2f40e77169..39425157ad4 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -6,6 +6,7 @@ using Content.Shared.Atmos.EntitySystems; using Content.Shared.Doors.Components; using Content.Shared.Maps; +using Content.Shared.Throwing; using JetBrains.Annotations; using Robust.Server.GameObjects; using Robust.Shared.Audio.Systems; @@ -37,6 +38,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapSystem _map = default!; [Dependency] public readonly PuddleSystem Puddle = default!; + [Dependency] private readonly ThrowingSystem _throwing = default!; private const float ExposedUpdateDelay = 1f; private float _exposedTimer = 0f; diff --git a/Content.Server/Temperature/Systems/TemperatureSystem.cs b/Content.Server/Temperature/Systems/TemperatureSystem.cs index 6c9e99e5f3b..0f57da4b881 100644 --- a/Content.Server/Temperature/Systems/TemperatureSystem.cs +++ b/Content.Server/Temperature/Systems/TemperatureSystem.cs @@ -161,8 +161,9 @@ public float GetHeatCapacity(EntityUid uid, TemperatureComponent? comp = null, P { return Atmospherics.MinimumHeatCapacity; } - - return comp.SpecificHeat * physics.FixturesMass; + if (physics.Mass < 1) + return comp.SpecificHeat; + else return comp.SpecificHeat * physics.FixturesMass; } private void OnInit(EntityUid uid, InternalTemperatureComponent comp, MapInitEvent args) diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index ed2e552a9f0..2ba535c2539 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -1169,7 +1169,7 @@ public static readonly CVarDef /// Useful to prevent clipping through objects. /// public static readonly CVarDef SpaceWindMaxVelocity = - CVarDef.Create("atmos.space_wind_max_velocity", 30f, CVar.SERVERONLY); + CVarDef.Create("atmos.space_wind_max_velocity", 15f, CVar.SERVERONLY); /// /// The maximum force that may be applied to an object by pushing (i.e. not throwing) atmospheric pressure differences. @@ -1178,6 +1178,24 @@ public static readonly CVarDef public static readonly CVarDef SpaceWindMaxPushForce = CVarDef.Create("atmos.space_wind_max_push_force", 20f, CVar.SERVERONLY); + /// + /// If an object's mass is below this number, then this number is used in place of mass to determine whether air pressure can throw an object. + /// This has nothing to do with throwing force, only acting as a way of reducing the odds of tiny 5 gram objects from being yeeted by people's breath + /// + /// + /// If you are reading this because you want to change it, consider looking into why almost every item in the game weighs only 5 grams + /// And maybe do your part to fix that? :) + /// + public static readonly CVarDef SpaceWindMinimumCalculatedMass = + CVarDef.Create("atmos.space_wind_minimum_calculated_mass", 10f, CVar.SERVERONLY); + + /// + /// Calculated as 1/Mass, where Mass is the physics.Mass of the desired threshold. + /// If an object's inverse mass is lower than this, it is capped at this. Basically, an upper limit to how heavy an object can be before it stops resisting space wind more. + /// + public static readonly CVarDef SpaceWindMaximumCalculatedInverseMass = + CVarDef.Create("atmos.space_wind_maximum_calculated_inverse_mass", 0.04f, CVar.SERVERONLY); + /// /// Whether monstermos tile equalization is enabled. /// @@ -1199,7 +1217,21 @@ public static readonly CVarDef /// Also looks weird on slow spacing for unrelated reasons. If you do want to enable this, you should probably turn on instaspacing. /// public static readonly CVarDef MonstermosRipTiles = - CVarDef.Create("atmos.monstermos_rip_tiles", false, CVar.SERVERONLY); + CVarDef.Create("atmos.monstermos_rip_tiles", true, CVar.SERVERONLY); + + /// + /// Taken as the cube of a tile's mass, this acts as a minimum threshold of mass for which air pressure calculates whether or not to rip a tile from the floor + /// This should be set by default to the cube of the game's lowest mass tile as defined in their prototypes, but can be increased for server performance reasons + /// + public static readonly CVarDef MonstermosRipTilesMinimumPressure = + CVarDef.Create("atmos.monstermos_rip_tiles_min_pressure", 7500f, CVar.SERVERONLY); + + /// + /// Taken after the minimum pressure is checked, the effective pressure is multiplied by this amount. + /// This allows server hosts to finely tune how likely floor tiles are to be ripped apart by air pressure + /// + public static readonly CVarDef MonstermosRipTilesPressureOffset = + CVarDef.Create("atmos.monstermos_rip_tiles_pressure_offset", 0.44f, CVar.SERVERONLY); /// /// Whether explosive depressurization will cause the grid to gain an impulse. @@ -1230,6 +1262,13 @@ public static readonly CVarDef public static readonly CVarDef AtmosSpacingMaxWind = CVarDef.Create("atmos.mmos_max_wind", 500f, CVar.SERVERONLY); + /// + /// Increases default airflow calculations to O(n^2) complexity, for use with heavy space wind optimizations. Potato servers BEWARE + /// This solves the problem of objects being trapped in an infinite loop of slamming into a wall repeatedly. + /// + public static readonly CVarDef MonstermosUseExpensiveAirflow = + CVarDef.Create("atmos.mmos_expensive_airflow", true, CVar.SERVERONLY); + /// /// Whether atmos superconduction is enabled. /// @@ -1286,6 +1325,13 @@ public static readonly CVarDef public static readonly CVarDef AtmosHeatScale = CVarDef.Create("atmos.heat_scale", 8f, CVar.SERVERONLY); + /// + /// A multiplier on the amount of force applied to Humanoid entities, as tracked by HumanoidAppearanceComponent + /// This multiplier is added after all other checks are made, and applies to both throwing force, and how easy it is for an entity to be thrown. + /// + public static readonly CVarDef AtmosHumanoidThrowMultiplier = + CVarDef.Create("atmos.humanoid_throw_multiplier", 2f, CVar.SERVERONLY); + /* * MIDI instruments */ diff --git a/Content.Shared/Maps/ContentTileDefinition.cs b/Content.Shared/Maps/ContentTileDefinition.cs index 32f5db0e821..be171559d02 100644 --- a/Content.Shared/Maps/ContentTileDefinition.cs +++ b/Content.Shared/Maps/ContentTileDefinition.cs @@ -121,5 +121,11 @@ public void AssignTileId(ushort id) { TileId = id; } + + [DataField] + public bool Reinforced = false; + + [DataField] + public float TileRipResistance = 125f; } } diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml index 5d8753e669e..9bdfacb81ab 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/animals.yml @@ -23,7 +23,7 @@ shape: !type:PhysShapeCircle radius: 0.25 - density: 10 + density: 0.8 mask: - FlyingMobMask layer: @@ -89,7 +89,7 @@ shape: !type:PhysShapeCircle radius: 0.1 - density: 30 + density: 0.1 mask: - FlyingMobMask layer: @@ -346,7 +346,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 100 + density: 0.0007 mask: - SmallMobMask layer: @@ -450,7 +450,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 120 + density: 0.007 mask: - SmallMobMask layer: @@ -1581,7 +1581,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 100 + density: 0.76 mask: - SmallMobMask layer: @@ -2540,7 +2540,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 50 #They actually are pretty light, I looked it up + density: 16.66 mask: - MobMask layer: @@ -2623,7 +2623,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 50 + density: 25.5 mask: - MobMask layer: @@ -2778,7 +2778,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 15 + density: 9 mask: - MobMask layer: @@ -2931,6 +2931,17 @@ Base: caracal_flop Dead: Base: caracal_dead + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 30 + mask: + - MobMask + layer: + - MobLayer - type: entity name: kitten @@ -2966,6 +2977,17 @@ thresholds: 0: Alive 25: Dead + - type: Fixtures + fixtures: + fix1: + shape: + !type:PhysShapeCircle + radius: 0.35 + density: 2 + mask: + - MobMask + layer: + - MobLayer - type: entity name: sloth @@ -3052,7 +3074,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 5 + density: 4 mask: - MobMask layer: @@ -3129,7 +3151,7 @@ shape: !type:PhysShapeCircle radius: 0.2 - density: 120 + density: 0.8 mask: - SmallMobMask layer: @@ -3253,7 +3275,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 250 + density: 750 mask: - MobMask layer: @@ -3330,7 +3352,7 @@ shape: !type:PhysShapeCircle radius: 0.35 - density: 100 # High, because wood is heavy. + density: 15 mask: - MobMask layer: diff --git a/Resources/Prototypes/Tiles/floors.yml b/Resources/Prototypes/Tiles/floors.yml index b5ca240d5ca..2abaab63fb0 100644 --- a/Resources/Prototypes/Tiles/floors.yml +++ b/Resources/Prototypes/Tiles/floors.yml @@ -15,6 +15,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelCheckerLight @@ -33,6 +34,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteelCheckerLight heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelCheckerDark @@ -51,6 +53,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteelCheckerDark heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelMini @@ -69,6 +72,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelPavement @@ -87,6 +91,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelDiagonal @@ -105,6 +110,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelOffset @@ -117,6 +123,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelMono @@ -135,6 +142,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelPavementVertical @@ -153,6 +161,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelHerringbone @@ -171,6 +180,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorSteelDiagonalMini @@ -189,6 +199,7 @@ collection: FootstepTile itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorBrassFilled @@ -201,6 +212,7 @@ collection: FootstepHull itemDrop: FloorTileItemBrassFilled heatCapacity: 10000 + tileRipResistance: 220 - type: tile id: FloorBrassReebe @@ -213,6 +225,7 @@ collection: FootstepHull itemDrop: FloorTileItemBrassReebe heatCapacity: 10000 + tileRipResistance: 220 - type: tile id: FloorPlastic @@ -231,6 +244,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWood @@ -251,6 +265,7 @@ collection: BarestepWood itemDrop: FloorTileItemWood heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhite @@ -269,6 +284,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteMini @@ -287,6 +303,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePavement @@ -305,6 +322,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteDiagonal @@ -323,6 +341,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteOffset @@ -335,6 +354,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteMono @@ -353,6 +373,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePavementVertical @@ -371,6 +392,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteHerringbone @@ -389,6 +411,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhiteDiagonalMini @@ -407,6 +430,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorWhitePlastic @@ -425,6 +449,7 @@ collection: FootstepTile itemDrop: FloorTileItemWhite heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorDark @@ -443,6 +468,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkMini @@ -461,6 +487,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPavement @@ -479,6 +506,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkDiagonal @@ -497,6 +525,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkOffset @@ -509,6 +538,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkMono @@ -527,6 +557,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPavementVertical @@ -545,6 +576,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkHerringbone @@ -563,6 +595,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkDiagonalMini @@ -581,6 +614,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorDarkPlastic @@ -599,6 +633,7 @@ collection: FootstepTile itemDrop: FloorTileItemDark heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorTechMaint @@ -611,6 +646,7 @@ collection: FootstepHull itemDrop: FloorTileItemTechmaint heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorReinforced @@ -623,6 +659,7 @@ collection: FootstepHull itemDrop: FloorTileItemReinforced heatCapacity: 10000 + reinforced: true - type: tile id: FloorMono @@ -635,6 +672,7 @@ collection: FootstepTile itemDrop: FloorTileItemMono heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorLino @@ -647,6 +685,7 @@ collection: FootstepTile itemDrop: FloorTileItemLino heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorSteelDirty @@ -659,6 +698,7 @@ collection: FootstepPlating itemDrop: FloorTileItemDirty heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorElevatorShaft @@ -671,6 +711,7 @@ collection: FootstepHull itemDrop: FloorTileItemElevatorShaft heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorMetalDiamond @@ -683,6 +724,7 @@ collection: FootstepHull itemDrop: FloorTileItemMetalDiamond heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorRockVault @@ -695,6 +737,7 @@ collection: FootstepAsteroid itemDrop: FloorTileItemRockVault heatCapacity: 10000 + tileRipResistance: 400 - type: tile id: FloorBlue @@ -707,6 +750,7 @@ collection: FootstepTile itemDrop: FloorTileItemBlue heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorSteelLime @@ -725,6 +769,7 @@ collection: FootstepFloor itemDrop: FloorTileItemLime heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorMining @@ -737,6 +782,7 @@ collection: FootstepTile itemDrop: FloorTileItemMining heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorMiningDark @@ -749,6 +795,7 @@ collection: FootstepTile itemDrop: FloorTileItemMiningDark heatCapacity: 10000 + tileRipResistance: 250 - type: tile id: FloorMiningLight @@ -761,6 +808,7 @@ collection: FootstepTile itemDrop: FloorTileItemMiningLight heatCapacity: 10000 + tileRipResistance: 250 # Departamental - type: tile @@ -774,6 +822,7 @@ collection: FootstepHull itemDrop: FloorTileItemFreezer heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorShowroom @@ -786,6 +835,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShowroom heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorHydro @@ -798,6 +848,7 @@ collection: FootstepFloor itemDrop: FloorTileItemHydro heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorBar @@ -816,6 +867,7 @@ collection: FootstepFloor itemDrop: FloorTileItemBar heatCapacity: 10000 + tileRipResistance: 100 - type: tile id: FloorClown @@ -828,6 +880,7 @@ collection: FootstepFloor itemDrop: FloorTileItemClown heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorMime @@ -840,6 +893,7 @@ collection: FootstepFloor itemDrop: FloorTileItemMime heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorKitchen @@ -852,6 +906,7 @@ collection: FootstepTile itemDrop: FloorTileItemKitchen heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorLaundry @@ -864,6 +919,7 @@ collection: FootstepTile itemDrop: FloorTileItemLaundry heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorSteelDamaged @@ -883,6 +939,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel #This should probably be made null when it becomes possible to make it such, in SS13 prying destroyed tiles wouldn't give you anything. heatCapacity: 10000 + tileRipResistance: 175 - type: tile id: FloorSteelBurnt @@ -899,6 +956,7 @@ collection: FootstepFloor itemDrop: FloorTileItemSteel #Same case as FloorSteelDamaged, make it null when possible heatCapacity: 10000 + tileRipResistance: 175 # Concrete @@ -920,6 +978,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorConcreteMono @@ -939,6 +998,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorConcreteSmooth @@ -958,6 +1018,7 @@ itemDrop: FloorTileItemConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcrete @@ -977,6 +1038,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcreteMono @@ -996,6 +1058,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorGrayConcreteSmooth @@ -1015,6 +1078,7 @@ itemDrop: FloorTileItemGrayConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcrete @@ -1034,6 +1098,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcreteMono @@ -1053,6 +1118,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 - type: tile id: FloorOldConcreteSmooth @@ -1072,6 +1138,7 @@ itemDrop: FloorTileItemOldConcrete heatCapacity: 10000 weather: true + tileRipResistance: 300 # Carpets (non smoothing) - type: tile @@ -1088,6 +1155,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeBlue heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorArcadeBlue2 @@ -1103,6 +1171,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeBlue2 heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorArcadeRed @@ -1118,6 +1187,7 @@ friction: 0.25 itemDrop: FloorTileItemArcadeRed heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorEighties @@ -1133,6 +1203,7 @@ friction: 0.25 itemDrop: FloorTileItemEighties heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorCarpetClown @@ -1148,6 +1219,7 @@ friction: 0.25 itemDrop: FloorTileItemCarpetClown heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorCarpetOffice @@ -1163,6 +1235,7 @@ friction: 0.25 itemDrop: FloorTileItemCarpetOffice heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorBoxing @@ -1182,6 +1255,7 @@ friction: 0.25 itemDrop: FloorTileItemBoxing heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorGym @@ -1201,6 +1275,7 @@ friction: 0.25 itemDrop: FloorTileItemGym heatCapacity: 10000 + tileRipResistance: 50 # Shuttle - type: tile @@ -1214,6 +1289,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleWhite heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleGrey @@ -1226,6 +1302,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleGrey heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleBlack @@ -1238,6 +1315,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleBlack heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleBlue @@ -1250,6 +1328,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleBlue heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleOrange @@ -1262,6 +1341,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleOrange heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttlePurple @@ -1274,6 +1354,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttlePurple heatCapacity: 10000 + tileRipResistance: 4500 - type: tile id: FloorShuttleRed @@ -1286,6 +1367,7 @@ collection: FootstepFloor itemDrop: FloorTileItemShuttleRed heatCapacity: 10000 + tileRipResistance: 4500 # Materials @@ -1300,6 +1382,7 @@ collection: FootstepTile itemDrop: FloorTileItemGold heatCapacity: 10000 + tileRipResistance: 600 - type: tile id: FloorSilver @@ -1312,6 +1395,7 @@ collection: FootstepTile itemDrop: FloorTileItemSilver heatCapacity: 10000 + tileRipResistance: 500 - type: tile id: FloorGlass @@ -1330,6 +1414,7 @@ collection: FootstepTile itemDrop: SheetGlass1 heatCapacity: 10000 + tileRipResistance: 150 - type: tile id: FloorRGlass @@ -1348,6 +1433,7 @@ collection: FootstepTile itemDrop: SheetRGlass1 heatCapacity: 10000 + tileRipResistance: 175 # Circuits - type: tile @@ -1361,6 +1447,7 @@ collection: FootstepHull itemDrop: FloorTileItemGCircuit heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorBlueCircuit @@ -1373,6 +1460,7 @@ collection: FootstepHull itemDrop: FloorTileItemBCircuit heatCapacity: 10000 + tileRipResistance: 225 # Terrain - type: tile @@ -1666,6 +1754,7 @@ itemDrop: FloorTileItemFlesh friction: 0.05 #slippy heatCapacity: 10000 + tileRipResistance: 80 - type: tile id: FloorTechMaint2 @@ -1678,6 +1767,7 @@ collection: FootstepHull itemDrop: FloorTileItemSteelMaint heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorTechMaint3 @@ -1696,6 +1786,7 @@ collection: FootstepHull itemDrop: FloorTileItemGratingMaint heatCapacity: 10000 + tileRipResistance: 225 - type: tile id: FloorWoodTile @@ -1716,6 +1807,7 @@ collection: BarestepWood itemDrop: FloorTileItemWoodPattern heatCapacity: 10000 + tileRipResistance: 75 - type: tile id: FloorBrokenWood @@ -1739,6 +1831,7 @@ collection: BarestepWood itemDrop: MaterialWoodPlank1 heatCapacity: 10000 + tileRipResistance: 60 - type: tile id: FloorWebTile @@ -1753,6 +1846,7 @@ collection: BarestepCarpet itemDrop: FloorTileItemWeb heatCapacity: 10000 + tileRipResistance: 30 - type: tile id: FloorChromite @@ -1784,6 +1878,7 @@ collection: FootstepHull itemDrop: FloorTileItemSteel #probably should not be normally obtainable, but the game shits itself and dies when you try to put null here heatCapacity: 10000 + tileRipResistance: 500 - type: tile id: FloorHullReinforced @@ -1796,6 +1891,7 @@ itemDrop: FloorTileItemSteel heatCapacity: 100000 #/tg/ has this set as "INFINITY." I don't know if that exists here so I've just added an extra 0 indestructible: true + reinforced: true - type: tile id: FloorReinforcedHardened @@ -1806,6 +1902,7 @@ footstepSounds: collection: FootstepHull itemDrop: FloorTileItemReinforced #same case as FloorHull + reinforced: true # Faux sci tiles @@ -1837,6 +1934,7 @@ collection: FootstepGrass itemDrop: FloorTileItemAstroGrass heatCapacity: 10000 + tileRipResistance: 50 - type: tile id: FloorMowedAstroGrass @@ -1846,6 +1944,7 @@ isSubfloor: false deconstructTools: [ Cutting ] itemDrop: FloorTileItemMowedAstroGrass + tileRipResistance: 50 - type: tile id: FloorJungleAstroGrass @@ -1855,6 +1954,7 @@ isSubfloor: false deconstructTools: [ Cutting ] itemDrop: FloorTileItemJungleAstroGrass + tileRipResistance: 50 # Ice - type: tile @@ -1870,6 +1970,7 @@ mobFrictionNoInput: 0.05 mobAcceleration: 2 itemDrop: FloorTileItemAstroIce + tileRipResistance: 50 - type: tile id: FloorAstroSnow @@ -1879,6 +1980,7 @@ isSubfloor: false deconstructTools: [ Prying ] itemDrop: FloorTileItemAstroSnow + tileRipResistance: 50 - type: tile id: FloorWoodLarge @@ -1899,3 +2001,4 @@ collection: BarestepWood itemDrop: FloorTileItemWoodLarge heatCapacity: 10000 + tileRipResistance: 100 From 4177b703b65e4c6f54dbae3e68a08865963361ea Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Thu, 18 Jul 2024 08:25:22 +0000 Subject: [PATCH 4/8] Automatic Changelog Update (#342) --- Resources/Changelog/Changelog.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 99af9f7d9bd..e357069c73b 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4535,3 +4535,11 @@ Entries: message: Foreigner translator should now consume power, as intended. id: 6169 time: '2024-07-18T08:22:52.0000000+00:00' +- author: VMSolidus + changes: + - type: Add + message: >- + Atmospheric "Throws" are now calculated using object mass, and behave + accordingly. Tiny objects will shoot out of rooms quite fast! + id: 6170 + time: '2024-07-18T08:24:58.0000000+00:00' From 542a7085c4f300412c2a1f80898f27fe5aa6d0a2 Mon Sep 17 00:00:00 2001 From: VMSolidus Date: Thu, 18 Jul 2024 15:30:00 -0400 Subject: [PATCH 5/8] Rework Mimic as Rampant Brand Intelligence (#395) # Description This PR was originally just going to be me fixing the stupid MobMimic bug. Over the course of 5 hours, and in a state of sleep deprived delirium, I somehow expanded this into something resembling the Rampant Brand Intelligence midround event. You're welcome I guess? I'm going to go get some sleep. # TODO - [x] Re-examine this after at least 9 hours of sleep, and vomit after I read my own shitcode - [x] Make it not shitcode # Changelog :cl: - add: Rampant Brand Intelligence has been spotted infesting NT Stations, be on the lookout for highly aggressive vending machines. --------- Signed-off-by: VMSolidus Co-authored-by: DEATHB4DEFEAT <77995199+DEATHB4DEFEAT@users.noreply.github.com> --- .../Advertise/AdvertiseComponent.cs | 8 +- .../Mimic/MobReplacementRuleComponent.cs | 24 +++ .../Antag/MobReplacementRuleSystem.cs | 152 +++++++++++++++++- .../GameTicking/GameTicker.Spawning.cs | 2 +- .../events/rempant-brand-intelligence.ftl | 1 + .../Prototypes/Entities/Mobs/NPCs/mimic.yml | 10 +- .../Structures/Machines/vending_machines.yml | 2 +- Resources/Prototypes/GameRules/events.yml | 1 + 8 files changed, 184 insertions(+), 16 deletions(-) create mode 100644 Resources/Locale/en-US/station-events/events/rempant-brand-intelligence.ftl diff --git a/Content.Server/Advertise/AdvertiseComponent.cs b/Content.Server/Advertise/AdvertiseComponent.cs index f36cc7ae1e6..144d4db975b 100644 --- a/Content.Server/Advertise/AdvertiseComponent.cs +++ b/Content.Server/Advertise/AdvertiseComponent.cs @@ -3,23 +3,21 @@ namespace Content.Server.Advertise { - [RegisterComponent, Access(typeof(AdvertiseSystem))] + [RegisterComponent] public sealed partial class AdvertiseComponent : Component { /// /// Minimum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal to 1. /// - [ViewVariables(VVAccess.ReadWrite)] [DataField("minWait")] - public int MinimumWait { get; private set; } = 8 * 60; + public int MinimumWait = 8 * 60; /// /// Maximum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal /// to /// - [ViewVariables(VVAccess.ReadWrite)] [DataField("maxWait")] - public int MaximumWait { get; private set; } = 10 * 60; + public int MaximumWait = 10 * 60; /// /// The identifier for the advertisements pack prototype. diff --git a/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs b/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs index d89d61606db..0824d48ae27 100644 --- a/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs +++ b/Content.Server/Antag/Mimic/MobReplacementRuleComponent.cs @@ -13,9 +13,33 @@ public sealed partial class MobReplacementRuleComponent : Component [DataField] public EntProtoId Proto = "MobMimic"; + [DataField] + public int NumberToReplace { get; set; } + + [DataField] + public string Announcement = "station-event-rampant-intelligence-announcement"; + /// /// Chance per-entity. /// [DataField] public float Chance = 0.001f; + + [DataField] + public bool DoAnnouncement = true; + + [DataField] + public float MimicMeleeDamage = 20f; + + [DataField] + public float MimicMoveSpeed = 1f; + + [DataField] + public string MimicAIType = "SimpleHostileCompound"; + + [DataField] + public bool MimicSmashGlass = true; + + [DataField] + public bool VendorModify = true; } diff --git a/Content.Server/Antag/MobReplacementRuleSystem.cs b/Content.Server/Antag/MobReplacementRuleSystem.cs index 2446b976e1a..dd65d36067e 100644 --- a/Content.Server/Antag/MobReplacementRuleSystem.cs +++ b/Content.Server/Antag/MobReplacementRuleSystem.cs @@ -1,15 +1,44 @@ +using System.Numerics; using Content.Server.Antag.Mimic; +using Content.Server.Chat.Systems; using Content.Server.GameTicking.Rules; using Content.Server.GameTicking.Rules.Components; +using Content.Server.NPC.Systems; +using Content.Server.Station.Systems; +using Content.Server.GameTicking; using Content.Shared.VendingMachines; using Robust.Shared.Map; +using Robust.Shared.Prototypes; using Robust.Shared.Random; +using Robust.Server.GameObjects; +using Robust.Shared.Physics.Systems; +using System.Linq; +using Robust.Shared.Physics; +using Content.Shared.Movement.Components; +using Content.Shared.Damage; +using Content.Server.NPC.HTN; +using Content.Server.NPC; +using Content.Shared.Weapons.Melee; +using Content.Server.Advertise; +using Content.Server.Power.Components; +using Content.Shared.CombatMode; namespace Content.Server.Antag; public sealed class MobReplacementRuleSystem : GameRuleSystem { [Dependency] private readonly IRobustRandom _random = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly GameTicker _gameTicker = default!; + [Dependency] private readonly ChatSystem _chat = default!; + [Dependency] private readonly IPrototypeManager _prototype = default!; + [Dependency] private readonly IComponentFactory _componentFactory = default!; + [Dependency] private readonly SharedPhysicsSystem _physics = default!; + [Dependency] private readonly NpcFactionSystem _npcFaction = default!; + [Dependency] private readonly NPCSystem _npc = default!; + [Dependency] private readonly TransformSystem _transform = default!; + [Dependency] private readonly AdvertiseSystem _advertise = default!; + protected override void Started(EntityUid uid, MobReplacementRuleComponent component, GameRuleComponent gameRule, GameRuleStartedEvent args) { @@ -17,21 +46,134 @@ protected override void Started(EntityUid uid, MobReplacementRuleComponent compo var query = AllEntityQuery(); var spawns = new List<(EntityUid Entity, EntityCoordinates Coordinates)>(); + var stations = _gameTicker.GetSpawnableStations(); while (query.MoveNext(out var vendingUid, out _, out var xform)) { - if (!_random.Prob(component.Chance)) + var ownerStation = _station.GetOwningStation(vendingUid); + + if (ownerStation == null + || ownerStation != stations[0]) + continue; + + // Make sure that we aren't running this on something that is already a mimic + if (HasComp(vendingUid)) continue; spawns.Add((vendingUid, xform.Coordinates)); } - foreach (var entity in spawns) + if (spawns == null) { - var coordinates = entity.Coordinates; - Del(entity.Entity); + //WTF THE STATION DOESN'T EXIST! WE MUST BE IN A TEST! QUICK, PUT A MIMIC AT 0,0!!! + Spawn(component.Proto, new EntityCoordinates(uid, new Vector2(0, 0))); + } + else + { + // This is intentionally not clamped. If a server host wants to replace every vending machine in the entire station with a mimic, who am I to stop them? + var k = MathF.MaxMagnitude(component.NumberToReplace, 1); + while (k > 0 && spawns != null && spawns.Count > 0) + { + if (k > 1) + { + var spawnLocation = _random.PickAndTake(spawns); + BuildAMimicWorkshop(spawnLocation.Entity, component); + } + else + { + BuildAMimicWorkshop(spawns[0].Entity, component); + } + + if (k == MathF.MaxMagnitude(component.NumberToReplace, 1) + && component.DoAnnouncement) + _chat.DispatchStationAnnouncement(stations[0], Loc.GetString("station-event-rampant-intelligence-announcement"), playDefaultSound: true, + colorOverride: Color.Red, sender: "Central Command"); + + k--; + } + } + } + + /// + /// It's like Build a Bear, but MURDER + /// + /// + public void BuildAMimicWorkshop(EntityUid uid, MobReplacementRuleComponent component) + { + var metaData = MetaData(uid); + var vendorPrototype = metaData.EntityPrototype; + var mimicProto = _prototype.Index(component.Proto); + + var vendorComponents = vendorPrototype?.Components.Keys + .Where(n => n != "Transform" && n != "MetaData") + .Select(name => (name, _componentFactory.GetRegistration(name).Type)) + .ToList() ?? new List<(string name, Type type)>(); + + var mimicComponents = mimicProto?.Components.Keys + .Where(n => n != "Transform" && n != "MetaData") + .Select(name => (name, _componentFactory.GetRegistration(name).Type)) + .ToList() ?? new List<(string name, Type type)>(); - Spawn(component.Proto, coordinates); + foreach (var name in mimicComponents.Except(vendorComponents)) + { + var newComponent = _componentFactory.GetComponent(name.name); + EntityManager.AddComponent(uid, newComponent); } + + var xform = Transform(uid); + if (xform.Anchored) + _transform.Unanchor(uid, xform); + + SetupMimicNPC(uid, component); + + if (TryComp(uid, out var vendor) + && component.VendorModify) + SetupMimicVendor(uid, component, vendor); + } + /// + /// This handles getting the entity ready to be a hostile NPC + /// + /// + /// + private void SetupMimicNPC(EntityUid uid, MobReplacementRuleComponent component) + { + _physics.SetBodyType(uid, BodyType.KinematicController); + _npcFaction.AddFaction(uid, "SimpleHostile"); + + var melee = EnsureComp(uid); + melee.Angle = 0; + DamageSpecifier dspec = new() + { + DamageDict = new() + { + { "Blunt", component.MimicMeleeDamage } + } + }; + melee.Damage = dspec; + + var movementSpeed = EnsureComp(uid); + (movementSpeed.BaseSprintSpeed, movementSpeed.BaseWalkSpeed) = (component.MimicMoveSpeed, component.MimicMoveSpeed); + + var htn = EnsureComp(uid); + htn.RootTask = new HTNCompoundTask() { Task = component.MimicAIType }; + htn.Blackboard.SetValue(NPCBlackboard.NavSmash, component.MimicSmashGlass); + _npc.WakeNPC(uid, htn); + } + + /// + /// Handling specific interactions with vending machines + /// + /// + /// + /// + private void SetupMimicVendor(EntityUid uid, MobReplacementRuleComponent mimicComponent, AdvertiseComponent vendorComponent) + { + vendorComponent.MinimumWait = 5; + vendorComponent.MaximumWait = 15; + _advertise.SayAdvertisement(uid, vendorComponent); + _advertise.RefreshTimer(uid, vendorComponent); + + if (TryComp(uid, out var aPC)) + aPC.NeedsPower = false; } } diff --git a/Content.Server/GameTicking/GameTicker.Spawning.cs b/Content.Server/GameTicking/GameTicker.Spawning.cs index bf69b4b9094..8f8c787f3f3 100644 --- a/Content.Server/GameTicking/GameTicker.Spawning.cs +++ b/Content.Server/GameTicking/GameTicker.Spawning.cs @@ -43,7 +43,7 @@ public sealed partial class GameTicker // Mainly to avoid allocations. private readonly List _possiblePositions = new(); - private List GetSpawnableStations() + public List GetSpawnableStations() { var spawnableStations = new List(); var query = EntityQueryEnumerator(); diff --git a/Resources/Locale/en-US/station-events/events/rempant-brand-intelligence.ftl b/Resources/Locale/en-US/station-events/events/rempant-brand-intelligence.ftl new file mode 100644 index 00000000000..8f7403dabd2 --- /dev/null +++ b/Resources/Locale/en-US/station-events/events/rempant-brand-intelligence.ftl @@ -0,0 +1 @@ +station-event-rampant-intelligence-announcement = Rampant brand intelligence has been detected board your station. Please inspect any vendors for aggressive marketing tactics, and reboot them if necessary. diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/mimic.yml b/Resources/Prototypes/Entities/Mobs/NPCs/mimic.yml index 657ac466f84..1f153ff3141 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/mimic.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/mimic.yml @@ -1,13 +1,17 @@ - type: entity name: Mimic id: MobMimic - parent: [ SimpleMobBase, MobCombat ] description: Surprise. # When this gets a proper write this should use the object's actual description >:) components: - type: Tag tags: - FootstepSound + - type: Clickable + - type: CombatMode + - type: InteractionOutline - type: InputMover + - type: Input + context: "human" - type: MobMover - type: NpcFactionMember factions: @@ -20,6 +24,7 @@ - type: Icon sprite: Structures/Machines/VendingMachines/cola.rsi state: normal + - type: Physics - type: Fixtures fixtures: fix1: @@ -38,6 +43,3 @@ damage: types: Blunt: 20 - - type: MovementSpeedModifier - baseWalkSpeed : 1 - baseSprintSpeed : 1 diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index c90d42b42cc..c9d9cfbf2c2 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -29,7 +29,7 @@ - MachineMask layer: - MachineLayer - density: 200 + density: 1000 - type: Destructible thresholds: - trigger: diff --git a/Resources/Prototypes/GameRules/events.yml b/Resources/Prototypes/GameRules/events.yml index f4936f51f50..e9c7e5fbad7 100644 --- a/Resources/Prototypes/GameRules/events.yml +++ b/Resources/Prototypes/GameRules/events.yml @@ -447,3 +447,4 @@ minimumPlayers: 20 weight: 5 - type: MobReplacementRule + numberToReplace: 1 From 9e57377d649b34f7ba0c37868c28f9e4dc397260 Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Thu, 18 Jul 2024 19:30:24 +0000 Subject: [PATCH 6/8] Automatic Changelog Update (#395) --- Resources/Changelog/Changelog.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index e357069c73b..d92e4f75d17 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4543,3 +4543,11 @@ Entries: accordingly. Tiny objects will shoot out of rooms quite fast! id: 6170 time: '2024-07-18T08:24:58.0000000+00:00' +- author: VMSolidus + changes: + - type: Add + message: >- + Rampant Brand Intelligence has been spotted infesting NT Stations, be on + the lookout for highly aggressive vending machines. + id: 6171 + time: '2024-07-18T19:30:00.0000000+00:00' From 61719b756b0c9f68b0937af961ed35f36ad61fca Mon Sep 17 00:00:00 2001 From: FoxxoTrystan <45297731+FoxxoTrystan@users.noreply.github.com> Date: Fri, 19 Jul 2024 19:20:30 +0200 Subject: [PATCH 7/8] Sign Languages! (#553) # Description Gives a new way to speak, Sign Languages using the Language system by only adding a nullable variable. Sign Language uses the default Emote system, meaning its will not get picked up by Radio or others devices or get blocked by accents. When a Sign Language is on, "Say/Whisper" will talk in Sign Language, Emote will still act like normal emotes. The Glorious Sign Language has arrived... and there can be more then one! ---

Media

![image](https://github.com/user-attachments/assets/ac0c1a57-da49-4419-bb75-da0a308eee7d) ![image](https://github.com/user-attachments/assets/0739a740-4adf-4ba1-a852-0a382a534d8d)

--- # Changelog :cl: FoxxoTrystan - add: Added the ability to speak with Sign Language. --- Content.Server/Chat/Systems/ChatSystem.cs | 54 ++++++++++++++++--- Content.Shared/Language/LanguagePrototype.cs | 8 ++- Resources/Locale/en-US/language/languages.ftl | 3 ++ .../Locale/en-US/language/sign-language.ftl | 4 ++ Resources/Prototypes/Language/languages.yml | 9 ++++ 5 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 Resources/Locale/en-US/language/sign-language.ftl diff --git a/Content.Server/Chat/Systems/ChatSystem.cs b/Content.Server/Chat/Systems/ChatSystem.cs index 58bc5dac65f..bfb38457e92 100644 --- a/Content.Server/Chat/Systems/ChatSystem.cs +++ b/Content.Server/Chat/Systems/ChatSystem.cs @@ -241,6 +241,17 @@ public void TrySendInGameICMessage( if (string.IsNullOrEmpty(message)) return; + // Check if the message is in sign language + if (desiredType == InGameICChatType.Speak || desiredType == InGameICChatType.Whisper) + { + var language = languageOverride ?? _language.GetLanguage(source); + if (language.SignLanguage ?? false) + { + SendEntityEmote(source, message, range, nameOverride, ignoreActionBlocker, signLanguage: true, languageOverride: languageOverride); + return; + } + } + // This message may have a radio prefix, and should then be whispered to the resolved radio channel if (checkRadioPrefix) { @@ -573,7 +584,9 @@ private void SendEntityEmote( bool hideLog = false, bool checkEmote = true, bool ignoreActionBlocker = false, - NetUserId? author = null + NetUserId? author = null, + LanguagePrototype? languageOverride = null, + bool? signLanguage = false ) { if (!_actionBlocker.CanEmote(source) && !ignoreActionBlocker) @@ -583,15 +596,32 @@ private void SendEntityEmote( var ent = Identity.Entity(source, EntityManager); string name = FormattedMessage.EscapeText(nameOverride ?? Name(ent)); + var language = languageOverride ?? _language.GetLanguage(source); + // Emotes use Identity.Name, since it doesn't actually involve your voice at all. - var wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", - ("entityName", name), - ("entity", ent), - ("message", FormattedMessage.RemoveMarkup(action))); + var wrappedMessage = ""; + var obfuscatedWrappedMessage = ""; + if (signLanguage == true) + { + wrappedMessage = Loc.GetString("entity-signlanguage-message", + ("entityName", name), + ("message", FormattedMessage.EscapeText(action))); + + obfuscatedWrappedMessage = Loc.GetString(_language.ObfuscateSpeech(action, language), + ("entityName", name)); + } + else + { + wrappedMessage = Loc.GetString("chat-manager-entity-me-wrap-message", + ("entityName", name), + ("entity", ent), + ("message", FormattedMessage.RemoveMarkup(action))); + + } if (checkEmote) TryEmoteChatInput(source, action); - SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage: "", source, range, author); + SendInVoiceRange(ChatChannel.Emotes, name, action, wrappedMessage, obfuscated: "", obfuscatedWrappedMessage, source, range, author, signLanguage: true); if (!hideLog) if (name != Name(source)) _adminLogger.Add(LogType.Chat, LogImpact.Low, $"Emote from {ToPrettyString(source):user} as {name}: {action}"); @@ -705,7 +735,7 @@ private MessageRangeCheckResult MessageRangeCheck(ICommonSession session, ICChat /// /// Sends a chat message to the given players in range of the source entity. /// - private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null) + private void SendInVoiceRange(ChatChannel channel, string name, string message, string wrappedMessage, string obfuscated, string obfuscatedWrappedMessage, EntityUid source, ChatTransmitRange range, NetUserId? author = null, LanguagePrototype? languageOverride = null, bool? signLanguage = false) { var language = languageOverride ?? _language.GetLanguage(source); foreach (var (session, data) in GetRecipients(source, VoiceRange)) @@ -718,9 +748,17 @@ private void SendInVoiceRange(ChatChannel channel, string name, string message, continue; EntityUid listener = session.AttachedEntity.Value; + // Quickly Checking if the Emote is a real one or Sign Language. + var notSignLanguage = false; + if (channel == ChatChannel.Emotes) + { + notSignLanguage = true; + if (signLanguage == true) + notSignLanguage = false; + } // If the channel does not support languages, or the entity can understand the message, send the original message, otherwise send the obfuscated version - if (channel == ChatChannel.LOOC || channel == ChatChannel.Emotes || _language.CanUnderstand(listener, language.ID)) + if (channel == ChatChannel.LOOC || notSignLanguage || _language.CanUnderstand(listener, language.ID)) { _chatManager.ChatMessageToOne(channel, message, wrappedMessage, source, entHideChat, session.Channel, author: author); } diff --git a/Content.Shared/Language/LanguagePrototype.cs b/Content.Shared/Language/LanguagePrototype.cs index be54b45aa1f..79c17daccd8 100644 --- a/Content.Shared/Language/LanguagePrototype.cs +++ b/Content.Shared/Language/LanguagePrototype.cs @@ -16,7 +16,13 @@ public sealed class LanguagePrototype : IPrototype [DataField("fontSize")] public int? FontSize; - + + /// + /// If true, will mark the language as a SignLanguage and will be handled as such. + /// + [DataField("signLanguage")] + public bool? SignLanguage; + /// /// Obfuscation method used by this language. By default, uses /// diff --git a/Resources/Locale/en-US/language/languages.ftl b/Resources/Locale/en-US/language/languages.ftl index 69c5d0a4a76..209daf92de8 100644 --- a/Resources/Locale/en-US/language/languages.ftl +++ b/Resources/Locale/en-US/language/languages.ftl @@ -4,6 +4,9 @@ language-Universal-description = What are you? language-GalacticCommon-name = Galactic common language-GalacticCommon-description = The standard Galatic language, most commonly used for inter-species communications and legal work. +language-SignLanguage-name = Sign Language +language-SignLanguage-description = The standard Galactic sign language, used by those that are unable to speak Galactic Common or at all. + language-Bubblish-name = Bubblish language-Bubblish-description = The language of Slimes. Being a mixture of bubbling noises and pops it's very difficult to speak for humans without the use of mechanical aids. diff --git a/Resources/Locale/en-US/language/sign-language.ftl b/Resources/Locale/en-US/language/sign-language.ftl new file mode 100644 index 00000000000..f4548f995c5 --- /dev/null +++ b/Resources/Locale/en-US/language/sign-language.ftl @@ -0,0 +1,4 @@ +entity-signlanguage-message = [italic]{$entityName} signs "[BubbleContent]{$message}[/BubbleContent]"[/italic] + +language-signlanguage-1 = [italic]{$entityName} signs something.[/italic] +language-signlanguage-2 = [italic]{$entityName} makes weird hand gestures.[/italic] diff --git a/Resources/Prototypes/Language/languages.yml b/Resources/Prototypes/Language/languages.yml index 048fdc6f24c..bec1884fe5c 100644 --- a/Resources/Prototypes/Language/languages.yml +++ b/Resources/Prototypes/Language/languages.yml @@ -35,6 +35,15 @@ - nah - wah +- type: language + id: SignLanguage + signLanguage: true + obfuscation: + !type:ReplacementObfuscation + replacement: + - "language-signlanguage-1" + - "language-signlanguage-2" + # Spoken by slimes. - type: language id: Bubblish From 56294947e49913b2b49c432790e50e2a57d8dcfc Mon Sep 17 00:00:00 2001 From: SimpleStation Changelogs Date: Fri, 19 Jul 2024 17:21:18 +0000 Subject: [PATCH 8/8] Automatic Changelog Update (#553) --- Resources/Changelog/Changelog.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index d92e4f75d17..d63426bf1e7 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -4551,3 +4551,9 @@ Entries: the lookout for highly aggressive vending machines. id: 6171 time: '2024-07-18T19:30:00.0000000+00:00' +- author: FoxxoTrystan + changes: + - type: Add + message: Added the ability to speak with Sign Language. + id: 6172 + time: '2024-07-19T17:20:30.0000000+00:00'