]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Adds explosion when attempting to microwave metal / bugfix (#23887)
authorTinManTim <73014819+Tin-Man-Tim@users.noreply.github.com>
Tue, 23 Jan 2024 22:59:09 +0000 (17:59 -0500)
committerGitHub <noreply@github.com>
Tue, 23 Jan 2024 22:59:09 +0000 (18:59 -0400)
Content.Server/Kitchen/Components/ActiveMicrowaveComponent.cs
Content.Server/Kitchen/Components/MicrowaveComponent.cs
Content.Server/Kitchen/EntitySystems/MicrowaveSystem.cs
Content.Server/Lightning/LightningSystem.cs
Content.Shared/Destructible/SharedDestructibleSystem.cs
Resources/Prototypes/Entities/Effects/lightning.yml
Resources/Prototypes/Entities/Structures/Machines/microwave.yml
Resources/Prototypes/tags.yml

index da8a35a695c111bab0c936a84dc817c1a44bfab6..bd5449dde60c39cd8daacd8dea7c3346d22d32a0 100644 (file)
@@ -1,4 +1,5 @@
 using Content.Shared.Kitchen;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
 
 namespace Content.Server.Kitchen.Components;
 
@@ -14,6 +15,10 @@ public sealed partial class ActiveMicrowaveComponent : Component
     [ViewVariables(VVAccess.ReadWrite)]
     public float TotalTime;
 
+    [ViewVariables(VVAccess.ReadWrite)]
+    [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+    public TimeSpan MalfunctionTime = TimeSpan.Zero;
+
     [ViewVariables]
     public (FoodRecipePrototype?, int) PortionedRecipe;
 }
index b11370c991fb2c408ce285367a1465639a7fad61..142a98236a7ac7252ed91e5fcf178f98c452c875 100644 (file)
@@ -1,3 +1,4 @@
+using Content.Shared.Construction.Prototypes;
 using Content.Shared.DeviceLinking;
 using Content.Shared.Item;
 using Robust.Shared.Audio;
@@ -12,8 +13,10 @@ namespace Content.Server.Kitchen.Components
     {
         [DataField("cookTimeMultiplier"), ViewVariables(VVAccess.ReadWrite)]
         public float CookTimeMultiplier = 1;
+
         [DataField("baseHeatMultiplier"), ViewVariables(VVAccess.ReadWrite)]
         public float BaseHeatMultiplier = 100;
+
         [DataField("objectHeatMultiplier"), ViewVariables(VVAccess.ReadWrite)]
         public float ObjectHeatMultiplier = 100;
 
@@ -23,10 +26,13 @@ namespace Content.Server.Kitchen.Components
         #region  audio
         [DataField("beginCookingSound")]
         public SoundSpecifier StartCookingSound = new SoundPathSpecifier("/Audio/Machines/microwave_start_beep.ogg");
+
         [DataField("foodDoneSound")]
         public SoundSpecifier FoodDoneSound = new SoundPathSpecifier("/Audio/Machines/microwave_done_beep.ogg");
+
         [DataField("clickSound")]
         public SoundSpecifier ClickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
+
         [DataField("ItemBreakSound")]
         public SoundSpecifier ItemBreakSound = new SoundPathSpecifier("/Audio/Effects/clang.ogg");
 
@@ -72,6 +78,23 @@ namespace Content.Server.Kitchen.Components
 
         [DataField, ViewVariables(VVAccess.ReadWrite)]
         public ProtoId<ItemSizePrototype> MaxItemSize = "Normal";
+
+        /// <summary>
+        /// How frequently the microwave can malfunction.
+        /// </summary>
+        [DataField]
+        public float MalfunctionInterval = 1.0f;
+
+        /// <summary>
+        /// Chance of an explosion occurring when we microwave a metallic object
+        /// </summary>
+        [DataField, ViewVariables(VVAccess.ReadWrite)]
+        public float ExplosionChance = .1f;
+
+        /// <summary>
+        /// Chance of lightning occurring when we microwave a metallic object
+        [DataField, ViewVariables(VVAccess.ReadWrite)]
+        public float LightningChance = .75f;
     }
 
     public sealed class BeingMicrowavedEvent : HandledEntityEventArgs
index efa963f2d081572fbbce4a863069109e21884342..e724a71987a215147760a16b9ebca93afaa1345c 100644 (file)
@@ -1,6 +1,7 @@
 using Content.Server.Body.Systems;
 using Content.Server.Chemistry.Containers.EntitySystems;
 using Content.Server.Construction;
+using Content.Server.Explosion.EntitySystems;
 using Content.Server.DeviceLinking.Events;
 using Content.Server.DeviceLinking.Systems;
 using Content.Server.Hands.Systems;
@@ -18,33 +19,39 @@ using Content.Shared.Destructible;
 using Content.Shared.FixedPoint;
 using Content.Shared.Interaction;
 using Content.Shared.Interaction.Events;
+using Robust.Shared.Random;
+using Robust.Shared.Audio;
+using Content.Server.Lightning;
 using Content.Shared.Item;
 using Content.Shared.Kitchen;
 using Content.Shared.Kitchen.Components;
 using Content.Shared.Popups;
 using Content.Shared.Power;
 using Content.Shared.Tag;
-using Robust.Server.Containers;
 using Robust.Server.GameObjects;
-using Robust.Shared.Audio;
 using Robust.Shared.Audio.Systems;
 using Robust.Shared.Containers;
 using Robust.Shared.Player;
 using System.Linq;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
 
 namespace Content.Server.Kitchen.EntitySystems
 {
     public sealed class MicrowaveSystem : EntitySystem
     {
         [Dependency] private readonly BodySystem _bodySystem = default!;
-        [Dependency] private readonly ContainerSystem _container = default!;
         [Dependency] private readonly DeviceLinkSystem _deviceLink = default!;
         [Dependency] private readonly SharedPopupSystem _popupSystem = default!;
         [Dependency] private readonly PowerReceiverSystem _power = default!;
         [Dependency] private readonly RecipeManager _recipeManager = default!;
         [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
         [Dependency] private readonly SharedAudioSystem _audio = default!;
-        [Dependency] private readonly SharedContainerSystem _sharedContainer = default!;
+        [Dependency] private readonly LightningSystem _lightning = default!;
+        [Dependency] private readonly IRobustRandom _random = default!;
+        [Dependency] private readonly IGameTiming _gameTiming = default!;
+        [Dependency] private readonly ExplosionSystem _explosion = default!;
+        [Dependency] private readonly SharedContainerSystem _container = default!;
         [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
         [Dependency] private readonly TagSystem _tag = default!;
         [Dependency] private readonly TemperatureSystem _temperature = default!;
@@ -52,6 +59,9 @@ namespace Content.Server.Kitchen.EntitySystems
         [Dependency] private readonly HandsSystem _handsSystem = default!;
         [Dependency] private readonly SharedItemSystem _item = default!;
 
+        [ValidatePrototypeId<EntityPrototype>]
+        private const string MalfunctionSpark = "Spark";
+
         public override void Initialize()
         {
             base.Initialize();
@@ -76,6 +86,7 @@ namespace Content.Server.Kitchen.EntitySystems
 
             SubscribeLocalEvent<ActiveMicrowaveComponent, ComponentStartup>(OnCookStart);
             SubscribeLocalEvent<ActiveMicrowaveComponent, ComponentShutdown>(OnCookStop);
+            SubscribeLocalEvent<ActiveMicrowaveComponent, EntityUnpausedEvent>(OnEntityUnpaused);
             SubscribeLocalEvent<ActiveMicrowaveComponent, EntInsertedIntoContainerMessage>(OnActiveMicrowaveInsert);
             SubscribeLocalEvent<ActiveMicrowaveComponent, EntRemovedFromContainerMessage>(OnActiveMicrowaveRemove);
 
@@ -96,9 +107,19 @@ namespace Content.Server.Kitchen.EntitySystems
         {
             if (!TryComp<MicrowaveComponent>(ent, out var microwaveComponent))
                 return;
-            SetAppearance(ent.Owner, MicrowaveVisualState.Idle, microwaveComponent);
 
+            SetAppearance(ent.Owner, MicrowaveVisualState.Idle, microwaveComponent);
             microwaveComponent.PlayingStream = _audio.Stop(microwaveComponent.PlayingStream);
+
+            foreach (var solid in microwaveComponent.Storage.ContainedEntities)
+            {
+                RemComp<ActivelyMicrowavedComponent>(solid);
+            }
+        }
+
+        private void OnEntityUnpaused(Entity<ActiveMicrowaveComponent> ent, ref EntityUnpausedEvent args)
+        {
+            ent.Comp.MalfunctionTime += args.PausedTime;
         }
 
         private void OnActiveMicrowaveInsert(Entity<ActiveMicrowaveComponent> ent, ref EntInsertedIntoContainerMessage args)
@@ -197,7 +218,7 @@ namespace Content.Server.Kitchen.EntitySystems
 
                         if (metaData.EntityPrototype.ID == recipeSolid.Key)
                         {
-                            _sharedContainer.Remove(item, component.Storage);
+                            _container.Remove(item, component.Storage);
                             EntityManager.DeleteEntity(item);
                             break;
                         }
@@ -312,7 +333,7 @@ namespace Content.Server.Kitchen.EntitySystems
             ent.Comp.Broken = true;
             SetAppearance(ent, MicrowaveVisualState.Broken, ent.Comp);
             RemComp<ActiveMicrowaveComponent>(ent);
-            _sharedContainer.EmptyContainer(ent.Comp.Storage);
+            _container.EmptyContainer(ent.Comp.Storage);
             UpdateUserInterfaceState(ent, ent.Comp);
         }
 
@@ -328,8 +349,8 @@ namespace Content.Server.Kitchen.EntitySystems
 
         private void OnAnchorChanged(EntityUid uid, MicrowaveComponent component, ref AnchorStateChangedEvent args)
         {
-            if(!args.Anchored)
-                _sharedContainer.EmptyContainer(component.Storage);
+            if (!args.Anchored)
+                _container.EmptyContainer(component.Storage);
         }
 
         private void OnSignalReceived(Entity<MicrowaveComponent> ent, ref SignalReceivedEvent args)
@@ -370,6 +391,31 @@ namespace Content.Server.Kitchen.EntitySystems
             return component.Storage.ContainedEntities.Any();
         }
 
+        /// <summary>
+        /// Handles the attempted cooking of unsafe objects
+        /// </summary>
+        /// <remarks>
+        /// Returns false if the microwave didn't explode, true if it exploded.
+        /// </remarks>
+        private void RollMalfunction(Entity<ActiveMicrowaveComponent, MicrowaveComponent> ent)
+        {
+            if (ent.Comp1.MalfunctionTime == TimeSpan.Zero)
+                return;
+
+            if (ent.Comp1.MalfunctionTime > _gameTiming.CurTime)
+                return;
+
+            ent.Comp1.MalfunctionTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp2.MalfunctionInterval);
+            if (_random.Prob(ent.Comp2.ExplosionChance))
+            {
+                _explosion.TriggerExplosive(ent);
+                return;  // microwave is fucked, stop the cooking.
+            }
+
+            if (_random.Prob(ent.Comp2.LightningChance))
+                _lightning.ShootRandomLightnings(ent, 1.0f, 2, MalfunctionSpark, triggerLightningEvents: false);
+        }
+
         /// <summary>
         /// Starts Cooking
         /// </summary>
@@ -384,9 +430,9 @@ namespace Content.Server.Kitchen.EntitySystems
 
             var solidsDict = new Dictionary<string, int>();
             var reagentDict = new Dictionary<string, FixedPoint2>();
+            var malfunctioning = false;
             // TODO use lists of Reagent quantities instead of reagent prototype ids.
-
-            foreach (var item in component.Storage.ContainedEntities)
+            foreach (var item in component.Storage.ContainedEntities.ToArray())
             {
                 // special behavior when being microwaved ;)
                 var ev = new BeingMicrowavedEvent(uid, user);
@@ -398,20 +444,17 @@ namespace Content.Server.Kitchen.EntitySystems
                     return;
                 }
 
-                // destroy microwave
-                if (_tag.HasTag(item, "MicrowaveMachineUnsafe") || _tag.HasTag(item, "Metal"))
+                if (_tag.HasTag(item, "Metal"))
                 {
-                    component.Broken = true;
-                    SetAppearance(uid, MicrowaveVisualState.Broken, component);
-                    _audio.PlayPvs(component.ItemBreakSound, uid);
-                    return;
+                    malfunctioning = true;
                 }
 
-                if (_tag.HasTag(item, "MicrowaveSelfUnsafe") || _tag.HasTag(item, "Plastic"))
+                if (_tag.HasTag(item, "Plastic"))
                 {
                     var junk = Spawn(component.BadRecipeEntityId, Transform(uid).Coordinates);
                     _container.Insert(junk, component.Storage);
-                    QueueDel(item);
+                    Del(item);
+                    continue;
                 }
 
                 AddComp<ActivelyMicrowavedComponent>(item);
@@ -454,6 +497,8 @@ namespace Content.Server.Kitchen.EntitySystems
             activeComp.CookTimeRemaining = component.CurrentCookTimerTime * component.CookTimeMultiplier;
             activeComp.TotalTime = component.CurrentCookTimerTime; //this doesn't scale so that we can have the "actual" time
             activeComp.PortionedRecipe = portionedRecipe;
+            if (malfunctioning)
+                activeComp.MalfunctionTime = _gameTiming.CurTime + TimeSpan.FromSeconds(component.MalfunctionInterval);
             UpdateUserInterfaceState(uid, component);
         }
 
@@ -505,8 +550,12 @@ namespace Content.Server.Kitchen.EntitySystems
             var query = EntityQueryEnumerator<ActiveMicrowaveComponent, MicrowaveComponent>();
             while (query.MoveNext(out var uid, out var active, out var microwave))
             {
-                //check if there's still cook time left
+
                 active.CookTimeRemaining -= frameTime;
+
+                RollMalfunction((uid, active,microwave));
+
+                //check if there's still cook time left
                 if (active.CookTimeRemaining > 0)
                 {
                     AddTemperature(microwave, frameTime);
@@ -517,7 +566,9 @@ namespace Content.Server.Kitchen.EntitySystems
                 AddTemperature(microwave, Math.Max(frameTime + active.CookTimeRemaining, 0)); //Though there's still a little bit more heat to pump out
 
                 foreach (var solid in microwave.Storage.ContainedEntities)
+                {
                     EntityManager.RemoveComponentDeferred<ActivelyMicrowavedComponent>(solid);
+                }
 
                 if (active.PortionedRecipe.Item1 != null)
                 {
@@ -529,10 +580,10 @@ namespace Content.Server.Kitchen.EntitySystems
                     }
                 }
 
-                _sharedContainer.EmptyContainer(microwave.Storage);
+                _container.EmptyContainer(microwave.Storage);
                 UpdateUserInterfaceState(uid, microwave);
                 EntityManager.RemoveComponentDeferred<ActiveMicrowaveComponent>(uid);
-                _audio.PlayPvs(microwave.FoodDoneSound, uid, AudioParams.Default.WithVolume(-1));
+                _audio.PlayPvs(microwave.FoodDoneSound, uid);
             }
         }
 
@@ -542,7 +593,7 @@ namespace Content.Server.Kitchen.EntitySystems
             if (!HasContents(ent.Comp) || HasComp<ActiveMicrowaveComponent>(ent))
                 return;
 
-            _sharedContainer.EmptyContainer(ent.Comp.Storage);
+            _container.EmptyContainer(ent.Comp.Storage);
             _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2));
             UpdateUserInterfaceState(ent, ent.Comp);
         }
@@ -552,7 +603,7 @@ namespace Content.Server.Kitchen.EntitySystems
             if (!HasContents(ent.Comp) || HasComp<ActiveMicrowaveComponent>(ent))
                 return;
 
-            _sharedContainer.Remove(EntityManager.GetEntity(args.EntityID), ent.Comp.Storage);
+            _container.Remove(EntityManager.GetEntity(args.EntityID), ent.Comp.Storage);
             UpdateUserInterfaceState(ent, ent.Comp);
         }
 
index 5e975f317935a82b2d04d455a2187c6edc283a73..4f975a60fdab392b24ee1f5232a070cfc95f7428 100644 (file)
@@ -3,7 +3,6 @@ using Content.Server.Beam;
 using Content.Server.Beam.Components;
 using Content.Server.Lightning.Components;
 using Content.Shared.Lightning;
-using Robust.Server.GameObjects;
 using Robust.Shared.Random;
 
 namespace Content.Server.Lightning;
@@ -22,9 +21,6 @@ public sealed class LightningSystem : SharedLightningSystem
     [Dependency] private readonly IRobustRandom _random = default!;
     [Dependency] private readonly EntityLookupSystem _lookup = default!;
 
-    private List<Entity<LightningTargetComponent>> _lookupTargetsList = new();
-    private HashSet<Entity<LightningTargetComponent>> _lookupTargets = new();
-
     public override void Initialize()
     {
         base.Initialize();
@@ -48,15 +44,20 @@ public sealed class LightningSystem : SharedLightningSystem
     /// <param name="user">Where the lightning fires from</param>
     /// <param name="target">Where the lightning fires to</param>
     /// <param name="lightningPrototype">The prototype for the lightning to be created</param>
-    public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning")
+    /// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
+    public void ShootLightning(EntityUid user, EntityUid target, string lightningPrototype = "Lightning", bool triggerLightningEvents = true)
     {
         var spriteState = LightningRandomizer();
         _beam.TryCreateBeam(user, target, lightningPrototype, spriteState);
 
-        var ev = new HitByLightningEvent(user, target);
-        RaiseLocalEvent(target, ref ev);
+        if (triggerLightningEvents) // we don't want certain prototypes to trigger lightning level events
+        {
+            var ev = new HitByLightningEvent(user, target);
+            RaiseLocalEvent(target, ref ev);
+        }
     }
 
+
     /// <summary>
     /// Looks for objects with a LightningTarget component in the radius, prioritizes them, and hits the highest priority targets with lightning.
     /// </summary>
@@ -65,7 +66,8 @@ public sealed class LightningSystem : SharedLightningSystem
     /// <param name="boltCount">Number of lightning bolts</param>
     /// <param name="lightningPrototype">The prototype for the lightning to be created</param>
     /// <param name="arcDepth">how many times to recursively fire lightning bolts from the target points of the first shot.</param>
-    public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0)
+    /// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
+    public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
     {
         //To Do: add support to different priority target tablem for different lightning types
         //To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
@@ -88,10 +90,10 @@ public sealed class LightningSystem : SharedLightningSystem
             if (!_random.Prob(curTarget.HitProbability)) //Chance to ignore target
                 continue;
 
-            ShootLightning(user, targets[count].Owner, lightningPrototype);
+            ShootLightning(user, targets[count].Owner, lightningPrototype, triggerLightningEvents);
             if (arcDepth - targets[count].LightningResistance > 0)
             {
-                ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance);
+                ShootRandomLightnings(targets[count].Owner, range, 1, lightningPrototype, arcDepth - targets[count].LightningResistance, triggerLightningEvents);
             }
             shootedCount++;
         }
index b16009e1981dde0f982d5b160d8c83f60170c0e0..eb87f00b6c80d45947917c0d7f41663098d61f58 100644 (file)
@@ -14,7 +14,7 @@ public abstract class SharedDestructibleSystem : EntitySystem
     }
 
     /// <summary>
-    ///     Force entity to broke.
+    ///     Force entity to break.
     /// </summary>
     public void BreakEntity(EntityUid owner)
     {
index 62a4153c00d4a363d1c1319e42e0abc5c3316f3b..7afd1c07a0cd1f5dff60c30c80af6e05532014cf 100644 (file)
       canArc: true
       lightningPrototype: ChargedLightning
 
+- type: entity
+  name: lightning
+  id: Spark
+  parent: BaseLightning
+  noSpawn: true
+  components:
+  - type: Sprite
+    sprite: /Textures/Effects/lightning.rsi
+    drawdepth: Effects
+    layers:
+    - state: "lightning_1"
+      shader: unshaded
+  - type: Electrified
+    shockDamage: 0
+  - type: Lightning
+    lightningPrototype: Spark
+  - type: PointLight
+    radius: 0.2
+    softness: .4
+  - type: Beam
+    sound: /Audio/Effects/sparks4.ogg
+  - type: TimedDespawn
+    lifetime: .3
+  - type: Tag
+    tags:
+      - HideContextMenu
+
 - type: entity
   name: supercharged lightning
   id: SuperchargedLightning
index 16e43494a672a7f7f63d21e242d371fbd318850e..37b5e50d31dcdb4420d9a26cf39dba0dd0c614ba 100644 (file)
       behaviors:
       - !type:DoActsBehavior
         acts: ["Breakage"]
+  - type: Explosive
+    explosionType: Default
+    maxIntensity: 10
+    totalIntensity: 5
+    intensitySlope: 5
+    canCreateVacuum: false
+    deleteAfterExplosion: false
   - type: ApcPowerReceiver
     powerLoad: 400
   - type: Machine
index 40736c3fc52b21e519aa238a5971a9c6954c1332..cf36243d9dd10e3f0a193df9f6d4fa3328c44bf4 100644 (file)
 
 - type: Tag
   id: Goat
-  
+
 - type: Tag
   id: GPS
-  
+
 - type: Tag
   id: Grenade
 
   id: Matchstick
 
 - type: Tag
-  id: Mayo  
+  id: Mayo
 
 - type: Tag
   id: Meat
 - type: Tag
   id: Metal
 
-- type: Tag
-  id: MicrowaveMachineUnsafe
-
-- type: Tag
-  id: MicrowaveSelfUnsafe
-
 - type: Tag
   id: MindShield