--- /dev/null
+using Content.Server.Temperature.Systems;
+using Content.Shared.Temperature;
+
+namespace Content.Server.Temperature.Components;
+
+/// <summary>
+/// Adds thermal energy to entities with <see cref="TemperatureComponent"/> placed on it.
+/// </summary>
+[RegisterComponent, Access(typeof(EntityHeaterSystem))]
+public sealed partial class EntityHeaterComponent : Component
+{
+ /// <summary>
+ /// Power used when heating at the high setting.
+ /// Low and medium are 33% and 66% respectively.
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public float Power = 2400f;
+
+ /// <summary>
+ /// Current setting of the heater. If it is off or unpowered it won't heat anything.
+ /// </summary>
+ [DataField]
+ public EntityHeaterSetting Setting = EntityHeaterSetting.Off;
+}
--- /dev/null
+using Content.Server.Power.Components;
+using Content.Server.Temperature.Components;
+using Content.Shared.Examine;
+using Content.Shared.Placeable;
+using Content.Shared.Popups;
+using Content.Shared.Temperature;
+using Content.Shared.Verbs;
+
+namespace Content.Server.Temperature.Systems;
+
+/// <summary>
+/// Handles <see cref="EntityHeaterComponent"/> updating and events.
+/// </summary>
+public sealed class EntityHeaterSystem : EntitySystem
+{
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly TemperatureSystem _temperature = default!;
+
+ private readonly int SettingCount = Enum.GetValues(typeof(EntityHeaterSetting)).Length;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<EntityHeaterComponent, ExaminedEvent>(OnExamined);
+ SubscribeLocalEvent<EntityHeaterComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerbs);
+ SubscribeLocalEvent<EntityHeaterComponent, PowerChangedEvent>(OnPowerChanged);
+ }
+
+ public override void Update(float deltaTime)
+ {
+ var query = EntityQueryEnumerator<EntityHeaterComponent, ItemPlacerComponent, ApcPowerReceiverComponent>();
+ while (query.MoveNext(out var uid, out var comp, out var placer, out var power))
+ {
+ if (!power.Powered)
+ continue;
+
+ // don't divide by total entities since its a big grill
+ // excess would just be wasted in the air but that's not worth simulating
+ // if you want a heater thermomachine just use that...
+ var energy = power.PowerReceived * deltaTime;
+ foreach (var ent in placer.PlacedEntities)
+ {
+ _temperature.ChangeHeat(ent, energy);
+ }
+ }
+ }
+
+ private void OnExamined(EntityUid uid, EntityHeaterComponent comp, ExaminedEvent args)
+ {
+ if (!args.IsInDetailsRange)
+ return;
+
+ args.PushMarkup(Loc.GetString("entity-heater-examined", ("setting", comp.Setting)));
+ }
+
+ private void OnGetVerbs(EntityUid uid, EntityHeaterComponent comp, GetVerbsEvent<AlternativeVerb> args)
+ {
+ if (!args.CanAccess || !args.CanInteract)
+ return;
+
+ var setting = (int) comp.Setting;
+ setting++;
+ setting %= SettingCount;
+ var nextSetting = (EntityHeaterSetting) setting;
+
+ args.Verbs.Add(new AlternativeVerb()
+ {
+ Text = Loc.GetString("entity-heater-switch-setting", ("setting", nextSetting)),
+ Act = () =>
+ {
+ ChangeSetting(uid, nextSetting, comp);
+ _popup.PopupEntity(Loc.GetString("entity-heater-switched-setting", ("setting", nextSetting)), uid, args.User);
+ }
+ });
+ }
+
+ private void OnPowerChanged(EntityUid uid, EntityHeaterComponent comp, ref PowerChangedEvent args)
+ {
+ // disable heating element glowing layer if theres no power
+ // doesn't actually turn it off since that would be annoying
+ var setting = args.Powered ? comp.Setting : EntityHeaterSetting.Off;
+ _appearance.SetData(uid, EntityHeaterVisuals.Setting, setting);
+ }
+
+ private void ChangeSetting(EntityUid uid, EntityHeaterSetting setting, EntityHeaterComponent? comp = null, ApcPowerReceiverComponent? power = null)
+ {
+ if (!Resolve(uid, ref comp, ref power))
+ return;
+
+ comp.Setting = setting;
+ power.Load = SettingPower(setting, comp.Power);
+ _appearance.SetData(uid, EntityHeaterVisuals.Setting, setting);
+ }
+
+ private float SettingPower(EntityHeaterSetting setting, float max)
+ {
+ switch (setting)
+ {
+ case EntityHeaterSetting.Low:
+ return max / 3f;
+ case EntityHeaterSetting.Medium:
+ return max * 2f / 3f;
+ case EntityHeaterSetting.High:
+ return max;
+ default:
+ return 0f;
+ }
+ }
+}
--- /dev/null
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.Temperature;
+
+[Serializable, NetSerializable]
+public enum EntityHeaterVisuals
+{
+ Setting
+}
+
+/// <summary>
+/// What heat the heater is set to, if on at all.
+/// </summary>
+[Serializable, NetSerializable]
+public enum EntityHeaterSetting
+{
+ Off,
+ Low,
+ Medium,
+ High
+}
--- /dev/null
+entity-heater-examined = It is set to [color=gray]{$setting}[/color]
+entity-heater-switch-setting = Switch to {$setting}
+entity-heater-switched-setting = Switched to {$setting}
materialRequirements:
Glass: 1
+- type: entity
+ parent: BaseMachineCircuitboard
+ id: ElectricGrillMachineCircuitboard
+ name: electric grill machine board
+ description: A machine printed circuit board for an electric grill.
+ components:
+ - type: MachineBoard
+ prototype: KitchenElectricGrill
+ requirements:
+ Capacitor: 4
+ materialRequirements:
+ Glass: 2
+ Cable: 5
+
- type: entity
id: StasisBedMachineCircuitboard
parent: BaseMachineCircuitboard
--- /dev/null
+- type: entity
+ parent: BaseHeaterMachine
+ id: KitchenElectricGrill
+ name: electric grill
+ description: A microwave? No, a real man cooks steaks on a grill!
+ components:
+ - type: Sprite
+ # TODO: draw a sprite
+ sprite: Structures/Machines/electric_grill.rsi
+ drawdepth: SmallObjects
+ snapCardinals: true
+ layers:
+ - state: icon
+ - map: ["enum.EntityHeaterVisuals.Setting"]
+ shader: unshaded
+ visible: false
+ - type: ApcPowerReceiver
+ powerLoad: 0 # off by default
+ - type: EntityHeater
+ - type: ItemPlacer
+ maxEntities: 4 # big grill, many steaks
+ whitelist:
+ components:
+ - Temperature
+ - type: PlaceableSurface
+ - type: Machine
+ board: ElectricGrillMachineCircuitboard
+ - type: GenericVisualizer
+ visuals:
+ enum.EntityHeaterVisuals.Setting:
+ enum.EntityHeaterVisuals.Setting:
+ Off: { visible: false }
+ Low: { visible: true, state: low }
+ Medium: { visible: true, state: medium }
+ High: { visible: true, state: high }
+# heats an entity or solution placed on it
- type: entity
- id: ChemistryHotplate
+ abstract: true
parent: [ BaseMachinePowered, ConstructibleMachine ]
- name: hotplate
- description: "The descendent of the microwaves, our newest invention in beaker heating technology: the hotplate!"
+ id: BaseHeaterMachine
components:
- type: Transform
anchored: true
- MidImpassable
- LowImpassable
hard: false
+ - type: ApcPowerReceiver
+ powerLoad: 300
+ - type: Appearance
+ - type: ContainerContainer
+ containers:
+ machine_board: !type:Container
+ machine_parts: !type:Container
+
+- type: entity
+ parent: BaseHeaterMachine
+ id: ChemistryHotplate
+ name: hotplate
+ description: "The descendent of the microwaves, our newest invention in beaker heating technology: the hotplate!"
+ components:
- type: Sprite
sprite: Structures/Machines/hotplate.rsi
drawdepth: SmallObjects
- state: on
map: ["enum.SolutionHeaterVisuals.IsOn"]
shader: unshaded
- - type: ApcPowerReceiver
- powerLoad: 300
- - type: ItemMapper
- sprite: Structures/Machines/hotplate.rsi
- mapLayers:
- beaker:
- whitelist:
- components:
- - FitsInDispenser
- type: SolutionHeater
- type: ItemPlacer
whitelist:
positionOffset: 0, 0.25
- type: Machine
board: HotplateMachineCircuitboard
- - type: Appearance
- - type: ContainerContainer
- containers:
- machine_board: !type:Container
- machine_parts: !type:Container
- type: GenericVisualizer
visuals:
enum.SolutionHeaterVisuals.IsOn:
- ReagentGrinderMachineCircuitboard
- HotplateMachineCircuitboard
- MicrowaveMachineCircuitboard
+ - ElectricGrillMachineCircuitboard
- FatExtractorMachineCircuitboard
- SheetifierMachineCircuitboard
- UniformPrinterMachineCircuitboard
Steel: 100
Glass: 900
+- type: latheRecipe
+ id: ElectricGrillMachineCircuitboard
+ result: ElectricGrillMachineCircuitboard
+ completetime: 4
+ materials:
+ Steel: 100
+ Glass: 900
+
- type: latheRecipe
id: FatExtractorMachineCircuitboard
result: FatExtractorMachineCircuitboard
recipeUnlocks: #remove all of these once we have more kitchen equipment
- MicrowaveMachineCircuitboard
- ReagentGrinderMachineCircuitboard
+ - ElectricGrillMachineCircuitboard
- BoozeDispenserMachineCircuitboard
- SodaDispenserMachineCircuitboard
--- /dev/null
+{
+ "version": 1,
+ "license": "CC0-1.0",
+ "copyright": "Created by deltanedas (github) for SS14.",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "low"
+ },
+ {
+ "name": "medium"
+ },
+ {
+ "name": "high"
+ }
+ ]
+}