diff --git a/Content.Client/Paper/UI/PaperVisualizerSystem.cs b/Content.Client/Paper/UI/PaperVisualizerSystem.cs index a0d05736adbbf8..e90b6b6b6e00a5 100644 --- a/Content.Client/Paper/UI/PaperVisualizerSystem.cs +++ b/Content.Client/Paper/UI/PaperVisualizerSystem.cs @@ -1,3 +1,4 @@ +using Content.Shared.Tag; using Robust.Client.GameObjects; using static Content.Shared.Paper.PaperComponent; @@ -6,9 +7,11 @@ namespace Content.Client.Paper.UI; public sealed class PaperVisualizerSystem : VisualizerSystem { + [Dependency] private readonly TagSystem _tagSystem = default!; + protected override void OnAppearanceChange(EntityUid uid, PaperVisualsComponent component, ref AppearanceChangeEvent args) { - if (args.Sprite == null) + if (args.Sprite == null || _tagSystem.HasTag(uid, "Book")) return; if (AppearanceSystem.TryGetData(uid, PaperVisuals.Status , out var writingStatus, args.Component)) diff --git a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs index bc96807af2db82..e7bc8a065bc7fc 100644 --- a/Content.Server/Atmos/EntitySystems/FlammableSystem.cs +++ b/Content.Server/Atmos/EntitySystems/FlammableSystem.cs @@ -67,6 +67,7 @@ public override void Initialize() _physicsQuery = GetEntityQuery(); SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnInteract); SubscribeLocalEvent(OnInteractUsing); SubscribeLocalEvent(OnCollide); SubscribeLocalEvent(OnIsHot); @@ -139,6 +140,25 @@ private void OnMapInit(EntityUid uid, FlammableComponent component, MapInitEvent collisionMask: (int) CollisionGroup.FullTileLayer, body: body); } + /// + /// Using something flammable on something that's hot (fireplace, e-sword, lighter) will ignite the item + /// Example: burning paper by using it on a fireplace + /// + private void OnInteract(Entity entity, ref AfterInteractEvent args) + { + if (args.Handled || args.Target == null) + return; + + var isHotEvent = new IsHotEvent(); + RaiseLocalEvent(args.Target.Value, isHotEvent); + + if (!isHotEvent.IsHot) + return; + + Ignite(entity, args.Used, entity.Comp, args.User); + args.Handled = true; + } + private void OnInteractUsing(EntityUid uid, FlammableComponent flammable, InteractUsingEvent args) { if (args.Handled) diff --git a/Content.Server/Temperature/Components/RadiantTemperatureComponent.cs b/Content.Server/Temperature/Components/RadiantTemperatureComponent.cs new file mode 100644 index 00000000000000..a6e83ae620c137 --- /dev/null +++ b/Content.Server/Temperature/Components/RadiantTemperatureComponent.cs @@ -0,0 +1,23 @@ +using Content.Shared.Atmos; + +namespace Content.Server.Temperature.Components; + +/// +/// The entity will cause the surrounding air temperature to change passively without +/// any need for power or anything else. +/// +[RegisterComponent] +public sealed partial class RadiantTemperatureComponent : Component +{ + /// + /// The temperature that the entity will try to reach + /// + [DataField] + public float GoalTemperature = Atmospherics.T20C; + + /// + /// How much energy (in joules) to add to or remove from the surrounding air per second + /// + [DataField] + public float EnergyChangedPerSecond = 1f; +} diff --git a/Content.Server/Temperature/Systems/RadiantTemperatureSystem.cs b/Content.Server/Temperature/Systems/RadiantTemperatureSystem.cs new file mode 100644 index 00000000000000..bf43237750e1bc --- /dev/null +++ b/Content.Server/Temperature/Systems/RadiantTemperatureSystem.cs @@ -0,0 +1,58 @@ +using Content.Server.Atmos.EntitySystems; +using Content.Server.Atmos.Piping.Components; +using Content.Server.Temperature.Components; +using Robust.Server.GameObjects; + +namespace Content.Server.Temperature.Systems; + +public sealed class RadiantTemperatureSystem : EntitySystem +{ + [Dependency] private readonly AtmosphereSystem _atmosphere = default!; + [Dependency] private readonly TransformSystem _xform = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnAtmosUpdate); + } + + private void OnAtmosUpdate(Entity entity, ref AtmosDeviceUpdateEvent args) + { + var entXform = Transform(entity); + var grid = entXform.GridUid; + var map = entXform.MapUid; + var indices = _xform.GetGridTilePositionOrDefault((entity, entXform)); + var mixture = _atmosphere.GetTileMixture(grid, map, indices, true); + + if (mixture is null) + return; + + // do not continue heating if air is hotter than goal temperature, + // and the entity is a radiant HEAT source (positive temp changes) + if (mixture.Temperature > entity.Comp.GoalTemperature && entity.Comp.EnergyChangedPerSecond > 0) + return; + + // do not continue cooling if air is colder than goal temperature + // and the entity is a radiant COOLING source (negative temp changes) + if (mixture.Temperature < entity.Comp.GoalTemperature && entity.Comp.EnergyChangedPerSecond < 0) + return; + + var dQ = entity.Comp.EnergyChangedPerSecond * args.dt; + + // Clamps the heat transferred to not overshoot + // This is just taken straight from GasThermoMachineSystem.cs + var Cin = _atmosphere.GetHeatCapacity(mixture, true); + var dT = entity.Comp.GoalTemperature - mixture.Temperature; + var dQLim = dT * Cin; + var scale = 1f; + if (Math.Abs(dQ) > Math.Abs(dQLim)) + { + scale = dQLim / dQ; + } + + var dQActual = dQ * scale; + _atmosphere.AddHeat(mixture, dQActual); + + } +} diff --git a/Resources/Prototypes/Entities/Objects/Misc/books.yml b/Resources/Prototypes/Entities/Objects/Misc/books.yml index 15ecd5d2a80d35..3c9faf07c2ad07 100644 --- a/Resources/Prototypes/Entities/Objects/Misc/books.yml +++ b/Resources/Prototypes/Entities/Objects/Misc/books.yml @@ -44,6 +44,33 @@ damage: types: Blunt: 1 + - type: Flammable + fireSpread: true + canResistFire: false + alwaysCombustible: true + canExtinguish: true # save the books! + damage: + types: + Heat: 1 + - type: Appearance + - type: FireVisuals + sprite: Effects/fire.rsi + normalState: fire + - type: Damageable + damageModifierSet: Wood + - type: Destructible + thresholds: + - trigger: + !type:DamageTrigger + damage: 40 # sure does take a lot longer to burn a book than a piece of paper + behaviors: + - !type:SpawnEntitiesBehavior + spawn: + Ash: + min: 1 + max: 1 + - !type:DoActsBehavior + acts: [ "Destruction" ] - type: entity parent: BaseItem diff --git a/Resources/Prototypes/Entities/Structures/Decoration/bonfire.yml b/Resources/Prototypes/Entities/Structures/Decoration/bonfire.yml index b60b2bd9435912..0172d4d131d58a 100644 --- a/Resources/Prototypes/Entities/Structures/Decoration/bonfire.yml +++ b/Resources/Prototypes/Entities/Structures/Decoration/bonfire.yml @@ -31,6 +31,12 @@ sound: path: /Audio/Ambience/Objects/fireplace.ogg - type: AlwaysHot + - type: IgnitionSource + ignited: true + - type: AtmosDevice + - type: RadiantTemperature + goalTemperature: 305 + energyChangedPerSecond: 2500 - type: entity id: LegionnaireBonfire diff --git a/Resources/Prototypes/Entities/Structures/Decoration/fireplace.yml b/Resources/Prototypes/Entities/Structures/Decoration/fireplace.yml index acedcb69765847..e13e6e17a7908f 100644 --- a/Resources/Prototypes/Entities/Structures/Decoration/fireplace.yml +++ b/Resources/Prototypes/Entities/Structures/Decoration/fireplace.yml @@ -46,3 +46,9 @@ - !type:DoActsBehavior acts: [ "Destruction" ] - type: AlwaysHot + - type: IgnitionSource + ignited: true + - type: AtmosDevice + - type: RadiantTemperature + goalTemperature: 305 + energyChangedPerSecond: 2500