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;
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!;
[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();
SubscribeLocalEvent<ActiveMicrowaveComponent, ComponentStartup>(OnCookStart);
SubscribeLocalEvent<ActiveMicrowaveComponent, ComponentShutdown>(OnCookStop);
+ SubscribeLocalEvent<ActiveMicrowaveComponent, EntityUnpausedEvent>(OnEntityUnpaused);
SubscribeLocalEvent<ActiveMicrowaveComponent, EntInsertedIntoContainerMessage>(OnActiveMicrowaveInsert);
SubscribeLocalEvent<ActiveMicrowaveComponent, EntRemovedFromContainerMessage>(OnActiveMicrowaveRemove);
{
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)
if (metaData.EntityPrototype.ID == recipeSolid.Key)
{
- _sharedContainer.Remove(item, component.Storage);
+ _container.Remove(item, component.Storage);
EntityManager.DeleteEntity(item);
break;
}
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);
}
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)
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>
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);
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);
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);
}
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);
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)
{
}
}
- _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);
}
}
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);
}
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);
}
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;
[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();
/// <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>
/// <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)
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++;
}