diff --git a/Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs b/Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs new file mode 100644 index 0000000000..3ca9ed4388 --- /dev/null +++ b/Content.Client/GameObjects/Components/Atmos/FireVisualizer.cs @@ -0,0 +1,68 @@ +using System; +using Content.Shared.GameObjects.Components.Atmos; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; +using Robust.Shared.Utility; +using YamlDotNet.RepresentationModel; + +namespace Content.Client.GameObjects.Components.Atmos +{ + public class FireVisualizer : AppearanceVisualizer + { + private int _fireStackAlternateState = 3; + private string _normalState; + private string _alternateState; + + public override void LoadData(YamlMappingNode node) + { + base.LoadData(node); + + if (node.TryGetNode("fireStackAlternateState", out var fireStack)) + { + _fireStackAlternateState = fireStack.AsInt(); + } + + if (node.TryGetNode("normalState", out var normalState)) + { + _normalState = normalState.AsString(); + } + + if (node.TryGetNode("alternateState", out var alternateState)) + { + _alternateState = alternateState.AsString(); + } + } + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + + if (component.TryGetData(FireVisuals.OnFire, out bool onFire)) + { + var fireStacks = 0f; + + if (component.TryGetData(FireVisuals.FireStacks, out float stacks)) + fireStacks = stacks; + + SetOnFire(component, onFire, fireStacks); + } + } + + private void SetOnFire(AppearanceComponent component, bool onFire, float fireStacks) + { + var sprite = component.Owner.GetComponent(); + + sprite.LayerSetVisible(FireVisualLayers.Fire, onFire); + + if(fireStacks > _fireStackAlternateState && !string.IsNullOrEmpty(_alternateState)) + sprite.LayerSetState(FireVisualLayers.Fire, _alternateState); + else + sprite.LayerSetState(FireVisualLayers.Fire, _normalState); + } + } + + public enum FireVisualLayers + { + Fire + } +} diff --git a/Content.Server/Atmos/FireEvent.cs b/Content.Server/Atmos/FireEvent.cs index 8c1a48abb2..a425fcca6d 100644 --- a/Content.Server/Atmos/FireEvent.cs +++ b/Content.Server/Atmos/FireEvent.cs @@ -2,15 +2,8 @@ namespace Content.Server.Atmos { - public class FireActEvent : EntitySystemMessage + public interface IFireAct { - public float Temperature { get; } - public float Volume { get; } - - public FireActEvent(float temperature, float volume) - { - Temperature = temperature; - Volume = volume; - } + void FireAct(float temperature, float volume); } } diff --git a/Content.Server/Atmos/GasMixture.cs b/Content.Server/Atmos/GasMixture.cs index ff35b50310..c8d795e572 100644 --- a/Content.Server/Atmos/GasMixture.cs +++ b/Content.Server/Atmos/GasMixture.cs @@ -509,7 +509,7 @@ namespace Content.Server.Atmos if (!doReaction) continue; - reaction = prototype.React(this, holder, _atmosphereSystem.EventBus); + reaction = prototype.React(this, holder, _atmosphereSystem.GridTileLookupSystem); if(reaction.HasFlag(ReactionResult.StopReactions)) break; } diff --git a/Content.Server/Atmos/ITemperatureExpose.cs b/Content.Server/Atmos/ITemperatureExpose.cs new file mode 100644 index 0000000000..8b9cfa2d2f --- /dev/null +++ b/Content.Server/Atmos/ITemperatureExpose.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.Server.Atmos +{ + public interface ITemperatureExpose + { + void TemperatureExpose(GasMixture air, float exposedTemperature, float exposedVolume); + } +} diff --git a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs index 732a39fce4..4259f3f3ae 100644 --- a/Content.Server/Atmos/Reactions/GasReactionPrototype.cs +++ b/Content.Server/Atmos/Reactions/GasReactionPrototype.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Content.Server.Interfaces; using Content.Shared.Atmos; +using Robust.Server.GameObjects.EntitySystems.TileLookup; using Robust.Shared.GameObjects; using Robust.Shared.Prototypes; using Robust.Shared.Serialization; @@ -65,13 +66,13 @@ namespace Content.Server.Atmos.Reactions serializer.DataField(ref _effects, "effects", new List()); } - public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder, IEventBus eventBus) + public ReactionResult React(GasMixture mixture, IGasMixtureHolder holder, GridTileLookupSystem gridLookup) { var result = ReactionResult.NoReaction; foreach (var effect in _effects) { - result |= effect.React(mixture, holder, eventBus); + result |= effect.React(mixture, holder, gridLookup); } return result; diff --git a/Content.Server/Atmos/Reactions/PhoronFireReaction.cs b/Content.Server/Atmos/Reactions/PhoronFireReaction.cs index e83301338d..cec03ca069 100644 --- a/Content.Server/Atmos/Reactions/PhoronFireReaction.cs +++ b/Content.Server/Atmos/Reactions/PhoronFireReaction.cs @@ -1,8 +1,10 @@ #nullable enable using System; using Content.Server.Interfaces; +using Content.Server.Utility; using Content.Shared.Atmos; using JetBrains.Annotations; +using Robust.Server.GameObjects.EntitySystems.TileLookup; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; @@ -11,7 +13,7 @@ namespace Content.Server.Atmos.Reactions [UsedImplicitly] public class PhoronFireReaction : IGasReactionEffect { - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, IEventBus eventBus) + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, GridTileLookupSystem gridTileLookup) { var energyReleased = 0f; var oldHeatCapacity = mixture.HeatCapacity; @@ -72,7 +74,15 @@ namespace Content.Server.Atmos.Reactions { location.HotspotExpose(temperature, mixture.Volume); - eventBus.QueueEvent(EventSource.Local, new TemperatureExposeEvent(location.GridIndices, location.GridIndex, mixture, temperature, mixture.Volume)); + foreach (var entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex, gridTileLookup)) + { + foreach (var temperatureExpose in entity.GetAllComponents()) + { + temperatureExpose.TemperatureExpose(mixture, temperature, mixture.Volume); + } + } + + location.TemperatureExpose(mixture, temperature, mixture.Volume); } } diff --git a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs index 29ec566d77..b45222fa32 100644 --- a/Content.Server/Atmos/Reactions/TritiumFireReaction.cs +++ b/Content.Server/Atmos/Reactions/TritiumFireReaction.cs @@ -1,7 +1,9 @@ #nullable enable using Content.Server.Interfaces; +using Content.Server.Utility; using Content.Shared.Atmos; using JetBrains.Annotations; +using Robust.Server.GameObjects.EntitySystems.TileLookup; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; @@ -14,7 +16,7 @@ namespace Content.Server.Atmos.Reactions { } - public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, IEventBus eventBus) + public ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, GridTileLookupSystem gridTileLookup) { var energyReleased = 0f; var oldHeatCapacity = mixture.HeatCapacity; @@ -67,7 +69,15 @@ namespace Content.Server.Atmos.Reactions { location.HotspotExpose(temperature, mixture.Volume); - eventBus.QueueEvent(EventSource.Local, new TemperatureExposeEvent(location.GridIndices, location.GridIndex, mixture, temperature, mixture.Volume)); + foreach (var entity in location.GridIndices.GetEntitiesInTileFast(location.GridIndex, gridTileLookup)) + { + foreach (var temperatureExpose in entity.GetAllComponents()) + { + temperatureExpose.TemperatureExpose(mixture, temperature, mixture.Volume); + } + } + + location.TemperatureExpose(mixture, temperature, mixture.Volume); } } diff --git a/Content.Server/Atmos/TemperatureExposeEvent.cs b/Content.Server/Atmos/TemperatureExposeEvent.cs deleted file mode 100644 index 5401fe0279..0000000000 --- a/Content.Server/Atmos/TemperatureExposeEvent.cs +++ /dev/null @@ -1,23 +0,0 @@ -using Robust.Shared.GameObjects; -using Robust.Shared.Map; - -namespace Content.Server.Atmos -{ - public class TemperatureExposeEvent : EntitySystemMessage - { - public MapIndices Indices { get; } - public GridId Grid { get; } - public GasMixture Air { get; } - public float Temperature { get; } - public float Volume { get; } - - public TemperatureExposeEvent(MapIndices indices, GridId gridId, GasMixture air, float temperature, float volume) - { - Indices = indices; - Grid = gridId; - Air = air; - Temperature = temperature; - Volume = volume; - } - } -} diff --git a/Content.Server/Atmos/TileAtmosphere.cs b/Content.Server/Atmos/TileAtmosphere.cs index 1c05e2a552..33f0c790ad 100644 --- a/Content.Server/Atmos/TileAtmosphere.cs +++ b/Content.Server/Atmos/TileAtmosphere.cs @@ -821,8 +821,14 @@ namespace Content.Server.Atmos if (tileRef == null) return; - _gridAtmosphereComponent.Owner.EntityManager. - EventBus.QueueEvent(EventSource.Local, new FireActEvent(Hotspot.Temperature, Hotspot.Volume)); + foreach (var entity in tileRef?.GetEntitiesInTileFast(_gridTileLookupSystem)) + { + foreach (var fireAct in entity.GetAllComponents()) + { + + fireAct.FireAct(Hotspot.Temperature, Hotspot.Volume); + } + } } private bool ConsiderSuperconductivity() diff --git a/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs b/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs index 723c0cbe84..4dbea6affc 100644 --- a/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/AtmosExposedComponent.cs @@ -5,7 +5,7 @@ using Robust.Shared.GameObjects; namespace Content.Server.GameObjects.Components.Atmos { /// - /// Represents that entity can be exposed to Atmo + /// Represents that entity can be exposed to Atmos /// [RegisterComponent] public class AtmosExposedComponent @@ -13,7 +13,7 @@ namespace Content.Server.GameObjects.Components.Atmos { public override string Name => "AtmosExposed"; - public void Update(TileAtmosphere tile, float timeDelta) + public void Update(TileAtmosphere tile, float frameDelta) { if (Owner.TryGetComponent(out var temperatureComponent)) { @@ -31,6 +31,10 @@ namespace Content.Server.GameObjects.Components.Atmos barotraumaComponent.Update(tile.Air?.Pressure ?? 0); } + if (Owner.TryGetComponent(out var flammableComponent)) + { + flammableComponent.Update(tile); + } } } diff --git a/Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs b/Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs new file mode 100644 index 0000000000..1d9d486bfb --- /dev/null +++ b/Content.Server/GameObjects/Components/Atmos/FlammableComponent.cs @@ -0,0 +1,237 @@ +using System; +using System.Collections.Generic; +using Content.Server.Atmos; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.GameObjects.Components.Temperature; +using Content.Server.GameObjects.EntitySystems; +using Content.Shared.Atmos; +using Content.Shared.Chemistry; +using Content.Shared.Damage; +using Content.Shared.GameObjects.Components.Atmos; +using Content.Shared.GameObjects.Components.Damage; +using Content.Shared.GameObjects.Components.Mobs; +using Content.Shared.GameObjects.EntitySystems; +using Content.Shared.Interfaces; +using Content.Shared.Interfaces.GameObjects.Components; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.GameObjects.Systems; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Serialization; +using Robust.Shared.Timers; +using Robust.Shared.ViewVariables; + +namespace Content.Server.GameObjects.Components.Atmos +{ + [RegisterComponent] + public class FlammableComponent : SharedFlammableComponent, ICollideBehavior, IFireAct, IReagentReaction + { + [Dependency] private IEntityManager _entityManager = default!; + + private bool _resisting = false; + private readonly List _collided = new List(); + + [ViewVariables(VVAccess.ReadWrite)] + public bool OnFire { get; private set; } + + [ViewVariables(VVAccess.ReadWrite)] + public float FireStacks { get; private set; } + + [ViewVariables(VVAccess.ReadWrite)] + public bool FireSpread { get; private set; } = false; + + [ViewVariables(VVAccess.ReadWrite)] + public bool CanResistFire { get; private set; } = false; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(this, x => x.FireSpread, "fireSpread", false); + serializer.DataField(this, x => x.CanResistFire, "canResistFire", false); + } + + public void Ignite() + { + if (FireStacks > 0 && !OnFire) + { + OnFire = true; + + } + + UpdateAppearance(); + } + + public void Extinguish() + { + if (!OnFire) return; + OnFire = false; + FireStacks = 0; + + _collided.Clear(); + + UpdateAppearance(); + } + + public void AdjustFireStacks(float relativeFireStacks) + { + FireStacks = MathF.Max(MathF.Min(-10f, FireStacks + relativeFireStacks), 20f); + if (OnFire && FireStacks <= 0) + Extinguish(); + + UpdateAppearance(); + } + + public void Update(TileAtmosphere tile) + { + // Slowly dry ourselves off if wet. + if (FireStacks < 0) + { + FireStacks = MathF.Min(0, FireStacks + 1); + } + + Owner.TryGetComponent(out ServerStatusEffectsComponent status); + + if (!OnFire) + { + status?.RemoveStatusEffect(StatusEffect.Fire); + return; + } + + status?.ChangeStatusEffect(StatusEffect.Fire, "/Textures/Interface/StatusEffects/Fire/fire.png", null); + + if (FireStacks > 0) + { + if(Owner.TryGetComponent(out TemperatureComponent temp)) + { + temp.ReceiveHeat(200 * FireStacks); + } + + if (Owner.TryGetComponent(out IDamageableComponent damageable)) + { + // TODO ATMOS Fire resistance from armor + var damage = Math.Min((int) (FireStacks * 2.5f), 10); + damageable.ChangeDamage(DamageClass.Burn, damage, false); + } + + AdjustFireStacks(-0.1f * (_resisting ? 10f : 1f)); + } + else + { + Extinguish(); + return; + } + + // If we're in an oxygenless environment, put the fire out. + if (tile?.Air?.GetMoles(Gas.Oxygen) < 1f) + { + Extinguish(); + return; + } + + tile.HotspotExpose(700, 50, true); + + foreach (var uid in _collided.ToArray()) + { + if (!uid.IsValid() || !_entityManager.EntityExists(uid)) + { + _collided.Remove(uid); + continue; + } + + var entity = _entityManager.GetEntity(uid); + var collidable = Owner.GetComponent(); + var otherCollidable = entity.GetComponent(); + + if (!collidable.WorldAABB.Intersects(otherCollidable.WorldAABB)) + { + _collided.Remove(uid); + } + } + } + + public void CollideWith(IEntity collidedWith) + { + if (!collidedWith.TryGetComponent(out FlammableComponent otherFlammable)) + return; + + if (!FireSpread || !otherFlammable.FireSpread) + return; + + if (OnFire) + { + if (otherFlammable.OnFire) + { + var fireSplit = (FireStacks + otherFlammable.FireStacks) / 2; + FireStacks = fireSplit; + otherFlammable.FireStacks = fireSplit; + } + else + { + FireStacks /= 2; + otherFlammable.FireStacks += FireStacks; + otherFlammable.Ignite(); + } + } else if (otherFlammable.OnFire) + { + otherFlammable.FireStacks /= 2; + FireStacks += otherFlammable.FireStacks; + Ignite(); + } + } + + private void UpdateAppearance() + { + if (Owner.Deleted || !Owner.TryGetComponent(out AppearanceComponent appearanceComponent)) return; + appearanceComponent.SetData(FireVisuals.OnFire, OnFire); + appearanceComponent.SetData(FireVisuals.FireStacks, FireStacks); + } + + public void FireAct(float temperature, float volume) + { + AdjustFireStacks(3); + Ignite(); + } + + // This needs some improvements... + public void Resist() + { + if (!OnFire || !ActionBlockerSystem.CanInteract(Owner) || _resisting || !Owner.TryGetComponent(out StunnableComponent stunnable)) return; + + _resisting = true; + + Owner.PopupMessage(Loc.GetString("You stop, drop, and roll!")); + stunnable.Paralyze(2f); + + Timer.Spawn(2000, () => + { + _resisting = false; + FireStacks -= 2f; + UpdateAppearance(); + }); + } + + public ReagentUnit ReagentReactTouch(ReagentPrototype reagent, ReagentUnit volume) + { + switch (reagent.ID) + { + case "chem.H2O": + Extinguish(); + AdjustFireStacks(-1.5f); + return ReagentUnit.Zero; + + case "chem.WeldingFuel": + case "chem.Thermite": + case "chem.Phoron": + case "chem.Ethanol": + AdjustFireStacks(volume.Float() / 10f); + return volume; + + default: + return ReagentUnit.Zero; + } + } + } +} diff --git a/Content.Server/GameObjects/Components/Mobs/ServerStatusEffectsComponent.cs b/Content.Server/GameObjects/Components/Mobs/ServerStatusEffectsComponent.cs index a9cf642938..70cb1a384a 100644 --- a/Content.Server/GameObjects/Components/Mobs/ServerStatusEffectsComponent.cs +++ b/Content.Server/GameObjects/Components/Mobs/ServerStatusEffectsComponent.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using Content.Server.GameObjects.Components.Atmos; using Content.Server.GameObjects.Components.Buckle; using Content.Server.GameObjects.Components.GUI; using Content.Server.GameObjects.Components.Movement; @@ -94,28 +95,30 @@ namespace Content.Server.GameObjects.Components.Mobs { case StatusEffect.Buckled: if (!player.TryGetComponent(out BuckleComponent buckle)) - { break; - } buckle.TryUnbuckle(player); break; case StatusEffect.Piloting: if (!player.TryGetComponent(out ShuttleControllerComponent controller)) - { break; - } controller.RemoveController(); break; case StatusEffect.Pulling: if (!player.TryGetComponent(out HandsComponent hands)) - { break; - } hands.StopPull(); break; + + case StatusEffect.Fire: + if (!player.TryGetComponent(out FlammableComponent flammable)) + break; + + flammable.Resist(); + break; + default: player.PopupMessage(msg.Effect.ToString()); break; diff --git a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs index f29abc5d08..555023b17c 100644 --- a/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs +++ b/Content.Server/GameObjects/Components/Temperature/TemperatureComponent.cs @@ -1,8 +1,10 @@ using System; using System.Diagnostics; +using Content.Server.GameObjects.Components.Mobs; using Content.Shared.Atmos; using Content.Shared.Damage; using Content.Shared.GameObjects.Components.Damage; +using Content.Shared.GameObjects.Components.Mobs; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components; using Robust.Shared.Serialization; @@ -72,11 +74,51 @@ namespace Content.Server.GameObjects.Components.Temperature damageType = DamageType.Cold; } + if (Owner.TryGetComponent(out ServerStatusEffectsComponent status)) + { + switch(CurrentTemperature) + { + // Cold strong. + case var t when t <= 260: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold3.png", null); + break; + + // Cold mild. + case var t when t <= 280 && t > 260: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold2.png", null); + break; + + // Cold weak. + case var t when t <= 292 && t > 280: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/cold1.png", null); + break; + + // Safe. + case var t when t <= 327 && t > 292: + status.RemoveStatusEffect(StatusEffect.Temperature); + break; + + // Heat weak. + case var t when t <= 335 && t > 327: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot1.png", null); + break; + + // Heat mild. + case var t when t <= 345 && t > 335: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot2.png", null); + break; + + // Heat strong. + case var t when t > 345: + status.ChangeStatusEffect(StatusEffect.Temperature, "/Textures/Interface/StatusEffects/Temperature/hot3.png", null); + break; + } + } + if (!damageType.HasValue) return; if (!Owner.TryGetComponent(out IDamageableComponent component)) return; component.ChangeDamage(damageType.Value, tempDamage, false); - Debug.Write($"Temp is: {CurrentTemperature}"); } /// diff --git a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs index 07b67cc560..16f22dfc8d 100644 --- a/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AtmosExposedSystem.cs @@ -13,13 +13,14 @@ namespace Content.Server.GameObjects.EntitySystems { [Dependency] private readonly IEntityManager _entityManager = default!; - private const float UpdateDelay = 3f; + private const float UpdateDelay = 1f; private float _lastUpdate; + public override void Update(float frameTime) { _lastUpdate += frameTime; if (_lastUpdate < UpdateDelay) return; - var atmosSystem = EntitySystemManager.GetEntitySystem(); + // creadth: everything exposable by atmos should be updated as well foreach (var atmosExposedComponent in EntityManager.ComponentManager.EntityQuery()) { diff --git a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs index c5614f08ad..b356b01fbf 100644 --- a/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/GameObjects/EntitySystems/AtmosphereSystem.cs @@ -7,9 +7,11 @@ using Content.Server.Atmos.Reactions; using Content.Server.GameObjects.Components.Atmos; using Content.Shared.GameObjects.EntitySystems.Atmos; using JetBrains.Annotations; +using Robust.Server.GameObjects.EntitySystems.TileLookup; using Robust.Server.Interfaces.Timing; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Map; +using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.Map; using Robust.Shared.IoC; @@ -29,6 +31,7 @@ namespace Content.Server.GameObjects.EntitySystems private GasReactionPrototype[] _gasReactions = Array.Empty(); private SpaceGridAtmosphereComponent _spaceAtmos = default!; + private GridTileLookupSystem? _gridTileLookup = null; /// /// List of gas reactions ordered by priority. @@ -40,6 +43,8 @@ namespace Content.Server.GameObjects.EntitySystems /// public IEventBus EventBus => _entityManager.EventBus; + public GridTileLookupSystem GridTileLookupSystem => _gridTileLookup ??= Get(); + public override void Initialize() { base.Initialize(); diff --git a/Content.Server/Interfaces/IGasReactionEffect.cs b/Content.Server/Interfaces/IGasReactionEffect.cs index 7d2b991236..819ede8b91 100644 --- a/Content.Server/Interfaces/IGasReactionEffect.cs +++ b/Content.Server/Interfaces/IGasReactionEffect.cs @@ -1,6 +1,7 @@ #nullable enable using Content.Server.Atmos; using Content.Server.Atmos.Reactions; +using Robust.Server.GameObjects.EntitySystems.TileLookup; using Robust.Shared.GameObjects; using Robust.Shared.Interfaces.Serialization; @@ -8,6 +9,6 @@ namespace Content.Server.Interfaces { public interface IGasReactionEffect : IExposeData { - ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, IEventBus eventBus); + ReactionResult React(GasMixture mixture, IGasMixtureHolder? holder, GridTileLookupSystem gridTileLookup); } } diff --git a/Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs b/Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs new file mode 100644 index 0000000000..8eac377717 --- /dev/null +++ b/Content.Shared/GameObjects/Components/Atmos/SharedFlammableComponent.cs @@ -0,0 +1,18 @@ +using System; +using Robust.Shared.GameObjects; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.Atmos +{ + public class SharedFlammableComponent : Component + { + public override string Name => "Flammable"; + } + + [Serializable, NetSerializable] + public enum FireVisuals + { + OnFire, + FireStacks, + } +} diff --git a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs index c76a275ddd..d6d094ed76 100644 --- a/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs +++ b/Content.Shared/GameObjects/Components/Mobs/SharedStatusEffectsComponent.cs @@ -57,6 +57,8 @@ namespace Content.Shared.GameObjects.Components.Mobs Hunger, Thirst, Pressure, + Fire, + Temperature, Stun, Cuffed, Buckled, diff --git a/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs b/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs index 5f6edd505f..5814ee2904 100644 --- a/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs +++ b/Content.Shared/GameObjects/Components/Movement/SharedSlipperyComponent.cs @@ -112,6 +112,7 @@ namespace Content.Shared.GameObjects.Components.Movement { if (!uid.IsValid() || !_entityManager.EntityExists(uid)) { + _slipped.Remove(uid); continue; } diff --git a/Content.Shared/Preferences/Appearance/HumanoidCharacterAppearance.cs b/Content.Shared/Preferences/Appearance/HumanoidCharacterAppearance.cs index d1d57c64df..9de3c6ca93 100644 --- a/Content.Shared/Preferences/Appearance/HumanoidCharacterAppearance.cs +++ b/Content.Shared/Preferences/Appearance/HumanoidCharacterAppearance.cs @@ -20,6 +20,7 @@ namespace Content.Shared.Preferences.Appearance RFoot, LFoot, Handcuffs, - StencilMask + StencilMask, + Fire, } } diff --git a/Resources/Prototypes/Entities/Mobs/Species/human.yml b/Resources/Prototypes/Entities/Mobs/Species/human.yml index dd896b04ba..b85d25d8a9 100644 --- a/Resources/Prototypes/Entities/Mobs/Species/human.yml +++ b/Resources/Prototypes/Entities/Mobs/Species/human.yml @@ -116,6 +116,10 @@ sprite: Effects/creampie.rsi state: creampie_human visible: false + - map: ["enum.FireVisualLayers.Fire"] + sprite: Mobs/Effects/onfire.rsi + state: Generic_mob_burning + visible: false - type: Icon sprite: Mobs/Species/Human/parts.rsi state: full @@ -133,6 +137,9 @@ - Opaque - MobImpassable - type: AtmosExposed + - type: Flammable + fireSpread: true + canResistFire: true - type: Temperature heatDamageThreshold: 360 coldDamageThreshold: 260 @@ -163,6 +170,10 @@ visuals: - type: RotationVisualizer - type: BuckleVisualizer + - type: FireVisualizer + normalState: Generic_mob_burning + alternateState: Standing + fireStackAlternateState: 3 - type: CreamPiedVisualizer - type: CombatMode - type: Climbing diff --git a/Resources/Textures/Interface/StatusEffects/Fire/fire.png b/Resources/Textures/Interface/StatusEffects/Fire/fire.png new file mode 100644 index 0000000000..cf65084e44 Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Fire/fire.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/cold1.png b/Resources/Textures/Interface/StatusEffects/Temperature/cold1.png new file mode 100644 index 0000000000..a7408f8e7f Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/cold1.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/cold2.png b/Resources/Textures/Interface/StatusEffects/Temperature/cold2.png new file mode 100644 index 0000000000..e8599a3e91 Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/cold2.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/cold3.png b/Resources/Textures/Interface/StatusEffects/Temperature/cold3.png new file mode 100644 index 0000000000..4c6f07cf5a Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/cold3.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/hot1.png b/Resources/Textures/Interface/StatusEffects/Temperature/hot1.png new file mode 100644 index 0000000000..2d3896f7b0 Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/hot1.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/hot2.png b/Resources/Textures/Interface/StatusEffects/Temperature/hot2.png new file mode 100644 index 0000000000..7408c204c8 Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/hot2.png differ diff --git a/Resources/Textures/Interface/StatusEffects/Temperature/hot3.png b/Resources/Textures/Interface/StatusEffects/Temperature/hot3.png new file mode 100644 index 0000000000..d74178208f Binary files /dev/null and b/Resources/Textures/Interface/StatusEffects/Temperature/hot3.png differ diff --git a/Resources/Textures/Mobs/Effects/onfire.rsi/Generic_mob_burning.png b/Resources/Textures/Mobs/Effects/onfire.rsi/Generic_mob_burning.png new file mode 100644 index 0000000000..553b787a45 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/onfire.rsi/Generic_mob_burning.png differ diff --git a/Resources/Textures/Mobs/Effects/onfire.rsi/Monkey_burning.png b/Resources/Textures/Mobs/Effects/onfire.rsi/Monkey_burning.png new file mode 100644 index 0000000000..cca7c6c66d Binary files /dev/null and b/Resources/Textures/Mobs/Effects/onfire.rsi/Monkey_burning.png differ diff --git a/Resources/Textures/Mobs/Effects/onfire.rsi/Standing.png b/Resources/Textures/Mobs/Effects/onfire.rsi/Standing.png new file mode 100644 index 0000000000..cc01244364 Binary files /dev/null and b/Resources/Textures/Mobs/Effects/onfire.rsi/Standing.png differ diff --git a/Resources/Textures/Mobs/Effects/onfire.rsi/meta.json b/Resources/Textures/Mobs/Effects/onfire.rsi/meta.json new file mode 100644 index 0000000000..7c5353addc --- /dev/null +++ b/Resources/Textures/Mobs/Effects/onfire.rsi/meta.json @@ -0,0 +1 @@ +{"version": 1, "size": {"x": 32, "y": 32}, "license": "CC-BY-SA 3.0", "copyright": "Taken from https://github.com/tgstation/tgstation at 0d9c9a8233dfc3fc55edc538955a761a6328bee0", "states": [{"name": "Generic_mob_burning", "directions": 4, "delays": [[0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1, 0.1]]}, {"name": "Monkey_burning", "directions": 4, "delays": [[0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1]]}, {"name": "Standing", "directions": 4, "delays": [[0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1], [0.1, 0.1, 0.1, 0.1]]}]} \ No newline at end of file diff --git a/SpaceStation14.sln.DotSettings b/SpaceStation14.sln.DotSettings index 509a0e8dc3..9bfa9e6c77 100644 --- a/SpaceStation14.sln.DotSettings +++ b/SpaceStation14.sln.DotSettings @@ -131,6 +131,7 @@ True True True + True True True True