]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Ice anomaly spawns ice underneath it (#21227)
authorKISS <59531932+YuriyKiss@users.noreply.github.com>
Mon, 6 Nov 2023 02:41:42 +0000 (04:41 +0200)
committerGitHub <noreply@github.com>
Mon, 6 Nov 2023 02:41:42 +0000 (19:41 -0700)
* added TileAnomalySystem to AnomalyIce

* added FloorIce for station

* created ice crust entity to spawn under ice anomaly

* update draw depth for ice crust

* uh oh, added ice-sliding but at what cost

* resolved mispredicts

* updated sprite alpha, removed appearance component (not used)

* fixed function not reflecting event name, left datafield attributes blank, added one comment about saving data (?)

---------

Co-authored-by: Yurii Kis <yurii.kis@smartteksas.com>
Content.Server/Anomaly/Effects/EntityAnomalySystem.cs
Content.Shared/Anomaly/Effects/Components/EntitySpawnAnomalyComponent.cs
Content.Shared/Movement/Components/FrictionContactsComponent.cs [new file with mode: 0644]
Content.Shared/Movement/Components/MovementSpeedModifierComponent.cs
Content.Shared/Movement/Systems/FrictionContactsSystem.cs [new file with mode: 0644]
Content.Shared/Movement/Systems/MovementSpeedModifierSystem.cs
Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Structures/Specific/Anomaly/anomalies.yml
Resources/Textures/Objects/Misc/ice_crust.rsi/ice.png [new file with mode: 0644]
Resources/Textures/Objects/Misc/ice_crust.rsi/meta.json [new file with mode: 0644]

index 5f201833145f289a28d4d6125b7aae2b09b78d2b..ee4e2ac115f52a45a8a1f9131d29b999a0810663 100644 (file)
@@ -21,27 +21,46 @@ public sealed class EntityAnomalySystem : EntitySystem
     {
         SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyPulseEvent>(OnPulse);
         SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical);
+        SubscribeLocalEvent<EntitySpawnAnomalyComponent, AnomalyStabilityChangedEvent>(OnStabilityChanged);
     }
 
     private void OnPulse(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyPulseEvent args)
     {
+        if (!component.SpawnOnPulse)
+            return;
+
         var range = component.SpawnRange * args.Stability;
         var amount = (int) (component.MaxSpawnAmount * args.Severity + 0.5f);
 
         var xform = Transform(uid);
-        SpawnMonstersOnOpenTiles(component, xform, amount, range, component.Spawns);
+        SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns);
     }
 
     private void OnSupercritical(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalySupercriticalEvent args)
     {
+        if (!component.SpawnOnSuperCritical)
+            return;
+
         var xform = Transform(uid);
-        // A cluster of monsters
-        SpawnMonstersOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.Spawns);
+        // A cluster of entities
+        SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.Spawns);
         // And so much meat (for the meat anomaly at least)
-        SpawnMonstersOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.SuperCriticalSpawns);
+        SpawnEntitesOnOpenTiles(component, xform, component.MaxSpawnAmount, component.SpawnRange, component.SuperCriticalSpawns);
+    }
+
+    private void OnStabilityChanged(EntityUid uid, EntitySpawnAnomalyComponent component, ref AnomalyStabilityChangedEvent args)
+    {
+        if (!component.SpawnOnStabilityChanged)
+            return;
+
+        var range = component.SpawnRange * args.Stability;
+        var amount = (int) (component.MaxSpawnAmount * args.Stability + 0.5f);
+
+        var xform = Transform(uid);
+        SpawnEntitesOnOpenTiles(component, xform, amount, range, component.Spawns);
     }
 
-    private void SpawnMonstersOnOpenTiles(EntitySpawnAnomalyComponent component, TransformComponent xform, int amount, float radius, List<EntProtoId> spawns)
+    private void SpawnEntitesOnOpenTiles(EntitySpawnAnomalyComponent component, TransformComponent xform, int amount, float radius, List<EntProtoId> spawns)
     {
         if (!component.Spawns.Any())
             return;
index 7083c91040e63907c04c729b09b118079a64c220..7a816e43123f7341bc9fa1636a7c75876f33283e 100644 (file)
@@ -1,7 +1,4 @@
-using Content.Shared.Maps;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
 
 namespace Content.Shared.Anomaly.Effects.Components;
 
@@ -36,8 +33,21 @@ public sealed partial class EntitySpawnAnomalyComponent : Component
     public float SpawnRange = 5f;
 
     /// <summary>
-    /// The tile that is spawned by the anomaly's effect
+    /// Whether or not anomaly spawns entities on Pulse
     /// </summary>
-    [DataField("floorTileId", customTypeSerializer: typeof(PrototypeIdSerializer<ContentTileDefinition>)), ViewVariables(VVAccess.ReadWrite)]
-    public string FloorTileId = "FloorFlesh";
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public bool SpawnOnPulse = true;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on SuperCritical
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public bool SpawnOnSuperCritical = true;
+
+    /// <summary>
+    /// Whether or not anomaly spawns entities on StabilityChanged
+    /// The idea was to spawn entities either on Pulse/Supercritical OR StabilityChanged
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public bool SpawnOnStabilityChanged = false;
 }
diff --git a/Content.Shared/Movement/Components/FrictionContactsComponent.cs b/Content.Shared/Movement/Components/FrictionContactsComponent.cs
new file mode 100644 (file)
index 0000000..693ada4
--- /dev/null
@@ -0,0 +1,31 @@
+using Content.Shared.Movement.Systems;
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Movement.Components;
+
+[NetworkedComponent, RegisterComponent]
+[AutoGenerateComponentState]
+[Access(typeof(FrictionContactsSystem))]
+public sealed partial class FrictionContactsComponent : Component
+{
+    /// <summary>
+    /// Modified mob friction while on FrictionContactsComponent
+    /// </summary>
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    [AutoNetworkedField]
+    public float MobFriction = 0.5f;
+
+    /// <summary>
+    /// Modified mob friction without input while on FrictionContactsComponent
+    /// </summary>
+    [AutoNetworkedField]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float MobFrictionNoInput = 0.05f;
+
+    /// <summary>
+    /// Modified mob acceleration while on FrictionContactsComponent
+    /// </summary>
+    [AutoNetworkedField]
+    [DataField, ViewVariables(VVAccess.ReadWrite)]
+    public float MobAcceleration = 2.0f;
+}
index 7efc12a7316ac0eaed5647a513b48f74878a212d..a0feab7052c44cd7fc27f61359260a35d843613e 100644 (file)
@@ -87,19 +87,19 @@ namespace Content.Shared.Movement.Components
         /// <summary>
         /// The acceleration applied to mobs when moving.
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite), DataField]
+        [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite), DataField]
         public float Acceleration = DefaultAcceleration;
 
         /// <summary>
         /// The negative velocity applied for friction.
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite), DataField]
+        [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite), DataField]
         public float Friction = DefaultFriction;
 
         /// <summary>
         /// The negative velocity applied for friction.
         /// </summary>
-        [ViewVariables(VVAccess.ReadWrite), DataField]
+        [AutoNetworkedField, ViewVariables(VVAccess.ReadWrite), DataField]
         public float? FrictionNoInput;
 
         [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
diff --git a/Content.Shared/Movement/Systems/FrictionContactsSystem.cs b/Content.Shared/Movement/Systems/FrictionContactsSystem.cs
new file mode 100644 (file)
index 0000000..b104c54
--- /dev/null
@@ -0,0 +1,100 @@
+using Content.Shared.Movement.Components;
+using Robust.Shared.Physics.Components;
+using Robust.Shared.Physics.Events;
+using Robust.Shared.Physics.Systems;
+
+namespace Content.Shared.Movement.Systems;
+
+public sealed class FrictionContactsSystem : EntitySystem
+{
+    [Dependency] private readonly SharedPhysicsSystem _physics = default!;
+    [Dependency] private readonly MovementSpeedModifierSystem _speedModifierSystem = default!;
+
+    // Comment copied from "original" SlowContactsSystem.cs
+    // TODO full-game-save 
+    // Either these need to be processed before a map is saved, or slowed/slowing entities need to update on init.
+    private HashSet<EntityUid> _toUpdate = new();
+
+    public override void Initialize()
+    {
+        base.Initialize();
+        SubscribeLocalEvent<FrictionContactsComponent, StartCollideEvent>(OnEntityEnter);
+        SubscribeLocalEvent<FrictionContactsComponent, EndCollideEvent>(OnEntityExit);
+        SubscribeLocalEvent<FrictionContactsComponent, ComponentShutdown>(OnShutdown);
+
+        UpdatesAfter.Add(typeof(SharedPhysicsSystem));
+    }
+
+    private void OnEntityEnter(EntityUid uid, FrictionContactsComponent component, ref StartCollideEvent args)
+    {
+        var otherUid = args.OtherEntity;
+
+        if (!HasComp(otherUid, typeof(MovementSpeedModifierComponent)))
+            return;
+
+        _toUpdate.Add(otherUid);
+    }
+
+    private void OnEntityExit(EntityUid uid, FrictionContactsComponent component, ref EndCollideEvent args)
+    {
+        var otherUid = args.OtherEntity;
+
+        if (!HasComp(otherUid, typeof(MovementSpeedModifierComponent)))
+            return;
+
+        _toUpdate.Add(otherUid);
+    }
+
+    private void OnShutdown(EntityUid uid, FrictionContactsComponent component, ComponentShutdown args)
+    {
+        if (!TryComp(uid, out PhysicsComponent? phys))
+            return;
+
+        _toUpdate.UnionWith(_physics.GetContactingEntities(uid, phys));
+    }
+
+    public override void Update(float frameTime)
+    {
+        base.Update(frameTime);
+
+        foreach (var uid in _toUpdate)
+        {
+            ApplyFrictionChange(uid);
+        }
+
+        _toUpdate.Clear();
+    }
+
+    private void ApplyFrictionChange(EntityUid uid)
+    {
+        if (!EntityManager.TryGetComponent<PhysicsComponent>(uid, out var physicsComponent))
+            return;
+
+        if (!TryComp(uid, out MovementSpeedModifierComponent? speedModifier))
+            return;
+
+        FrictionContactsComponent? frictionComponent = TouchesFrictionContactsComponent(uid, physicsComponent);
+
+        if (frictionComponent == null)
+        {
+            _speedModifierSystem.ChangeFriction(uid, MovementSpeedModifierComponent.DefaultFriction, null, MovementSpeedModifierComponent.DefaultAcceleration, speedModifier);
+        }
+        else
+        {
+            _speedModifierSystem.ChangeFriction(uid, frictionComponent.MobFriction, frictionComponent.MobFrictionNoInput, frictionComponent.MobAcceleration, speedModifier);
+        }
+    }
+
+    private FrictionContactsComponent? TouchesFrictionContactsComponent(EntityUid uid, PhysicsComponent physicsComponent)
+    {
+        foreach (var ent in _physics.GetContactingEntities(uid, physicsComponent))
+        {
+            if (!TryComp(ent, out FrictionContactsComponent? frictionContacts))
+                continue;
+
+            return frictionContacts;
+        }
+
+        return null;
+    }
+}
index c95ab379c6b9c7792e3867ea140ad6753711a25f..7c793d5eb898949aa10bc1e13d6fdd7bcae961ee 100644 (file)
@@ -25,7 +25,7 @@ namespace Content.Shared.Movement.Systems
 
             move.WalkSpeedModifier = ev.WalkSpeedModifier;
             move.SprintSpeedModifier = ev.SprintSpeedModifier;
-            Dirty(move);
+            Dirty(uid, move);
         }
 
         public void ChangeBaseSpeed(EntityUid uid, float baseWalkSpeed, float baseSprintSpeed, float acceleration, MovementSpeedModifierComponent? move = null)
@@ -36,7 +36,19 @@ namespace Content.Shared.Movement.Systems
             move.BaseWalkSpeed = baseWalkSpeed;
             move.BaseSprintSpeed = baseSprintSpeed;
             move.Acceleration = acceleration;
-            Dirty(move);
+            Dirty(uid, move);
+        }
+
+        // We might want to create separate RefreshMovementFrictionModifiersEvent and RefreshMovementFrictionModifiers function that will call it
+        public void ChangeFriction(EntityUid uid, float friction, float? frictionNoInput, float acceleration, MovementSpeedModifierComponent? move = null)
+        {
+            if (!Resolve(uid, ref move, false))
+                return;
+
+            move.Friction = friction;
+            move.FrictionNoInput = frictionNoInput;
+            move.Acceleration = acceleration;
+            Dirty(uid, move);
         }
     }
 
diff --git a/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml b/Resources/Prototypes/Entities/Objects/Misc/ice_crust.yml
new file mode 100644 (file)
index 0000000..2f8da6d
--- /dev/null
@@ -0,0 +1,52 @@
+- type: entity
+  id: IceCrust
+  name: ice crust
+  description: It's cold and slippery.
+  placement:
+    mode: SnapgridCenter
+    snap:
+      - Wall
+  components:
+    - type: MeleeSound
+      soundGroups:
+        Brute:
+          path:
+            "/Audio/Weapons/slash.ogg"
+    - type: Sprite
+      sprite: Objects/Misc/ice_crust.rsi
+      layers:
+        - state: ice
+      drawdepth: FloorObjects
+      color: "#ffffff44"
+    - type: Clickable
+    - type: Transform
+      anchored: true
+    - type: Physics
+    - type: Fixtures
+      fixtures:
+        fix1:
+          hard: false
+          density: 7
+          shape:
+            !type:PhysShapeAabb
+            bounds: "-0.4,-0.4,0.4,0.4"
+          layer:
+          - MidImpassable
+    - type: Damageable
+      damageModifierSet: Wood
+    - type: Destructible
+      thresholds:
+      - trigger:
+          !type:DamageTrigger
+          damage: 10
+        behaviors:
+        - !type:DoActsBehavior
+          acts: [ "Destruction" ]
+    - type: Temperature
+      heatDamage:
+        types:
+          Heat: 5
+      coldDamage: {}
+      ColdDamageThreshold: 0
+    - type: FrictionContacts
+      
\ No newline at end of file
index 3526216c139ea7d171e0921351f8395c61ed606a..234dd523596ec718b4848ab3bc096cc1973f90ed 100644 (file)
   - type: ProjectileAnomaly
     projectilePrototype: ProjectileIcicle
     targetNonSentientChance: 0.1
+  - type: EntitySpawnAnomaly
+    spawns:
+    - IceCrust
+    maxSpawnAmount: 17
+    spawnOnPulse: false
+    spawnOnSuperCritical: false
+    spawnOnStabilityChanged: true
   - type: TempAffectingAnomaly
     tempChangePerSecond: -25
     hotspotExposeTemperature: -1000
diff --git a/Resources/Textures/Objects/Misc/ice_crust.rsi/ice.png b/Resources/Textures/Objects/Misc/ice_crust.rsi/ice.png
new file mode 100644 (file)
index 0000000..0f460fe
Binary files /dev/null and b/Resources/Textures/Objects/Misc/ice_crust.rsi/ice.png differ
diff --git a/Resources/Textures/Objects/Misc/ice_crust.rsi/meta.json b/Resources/Textures/Objects/Misc/ice_crust.rsi/meta.json
new file mode 100644 (file)
index 0000000..865e457
--- /dev/null
@@ -0,0 +1,14 @@
+{
+  "version": 1,
+  "license": "CC-BY-SA-3.0",
+  "copyright": "Taken from space-station-14+Resources+Textures+Tiles+Planet+Snow",
+  "size": {
+    "x": 32,
+    "y": 32
+  },
+  "states": [
+    {
+      "name": "ice"
+    }
+  ]
+}
\ No newline at end of file