diff --git a/Content.Client/Power/Substation/SubstationVisualsComponent.cs b/Content.Client/Power/Substation/SubstationVisualsComponent.cs new file mode 100644 index 00000000000000..9a9a0859220a38 --- /dev/null +++ b/Content.Client/Power/Substation/SubstationVisualsComponent.cs @@ -0,0 +1,13 @@ +using Content.Shared.Power; + +namespace Content.Client.Power.Substation; + +[RegisterComponent] +public sealed partial class SubstationVisualsComponent : Component +{ + [DataField] + public string LayerMap { get; private set; } = string.Empty; + + [DataField] + public Dictionary IntegrityStates = new(); +} diff --git a/Content.Client/Power/Substation/SubstationVisualsSystem.cs b/Content.Client/Power/Substation/SubstationVisualsSystem.cs new file mode 100644 index 00000000000000..de63392793c9f2 --- /dev/null +++ b/Content.Client/Power/Substation/SubstationVisualsSystem.cs @@ -0,0 +1,22 @@ +using Robust.Shared.GameObjects; +using Robust.Client.GameObjects; +using Robust.Client.Graphics; +using Content.Shared.Power; + +namespace Content.Client.Power.Substation; + +public sealed class SubstationVisualsSystem : VisualizerSystem +{ + protected override void OnAppearanceChange(EntityUid uid, SubstationVisualsComponent component, ref AppearanceChangeEvent args) + { + if(args.Sprite == null || !args.Sprite.LayerMapTryGet(component.LayerMap, out var layer)) + return; + + if(args.AppearanceData.TryGetValue(SubstationVisuals.Screen, out var stateObject) + && stateObject is SubstationIntegrityState + && component.IntegrityStates.TryGetValue((SubstationIntegrityState)stateObject, out var state)) + { + args.Sprite.LayerSetState(layer, new RSI.StateId(state)); + } + } +} diff --git a/Content.Server/Power/EntitySystems/SubstationSystem.cs b/Content.Server/Power/EntitySystems/SubstationSystem.cs new file mode 100644 index 00000000000000..57f6b534806db7 --- /dev/null +++ b/Content.Server/Power/EntitySystems/SubstationSystem.cs @@ -0,0 +1,374 @@ +using System.Diagnostics.CodeAnalysis; +using Content.Server.Atmos; +using Content.Server.Atmos.Components; +using Content.Server.Construction; +using Content.Server.Power.Components; +using Content.Shared.Atmos; +using Content.Shared.CCVar; +using Content.Shared.Power; +using Content.Shared.Rejuvenate; +using Content.Shared.Wires; +using Content.Shared.Tag; +using Content.Shared.Examine; +using Robust.Server.GameObjects; +using Robust.Shared.Configuration; +using Robust.Shared.Containers; +using Content.Server.Atmos.EntitySystems; +using Robust.Shared.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Timing; + +namespace Content.Server.Power.EntitySystems; + +public sealed class SubstationSystem : EntitySystem +{ + [Dependency] private readonly PointLightSystem _lightSystem = default!; + [Dependency] private readonly SharedPointLightSystem _sharedLightSystem = default!; + [Dependency] private readonly AppearanceSystem _appearanceSystem = default!; + [Dependency] private readonly TagSystem _tagSystem = default!; + [Dependency] private readonly IConfigurationManager _cfg = default!; + + private bool _substationDecayEnabled; + private int _substationDecayTimeout; + private float _substationDecayCoefficient; + private float _substationDecayTimer; + + public override void Initialize() + { + base.Initialize(); + + UpdatesAfter.Add(typeof(PowerNetSystem)); + + _substationDecayEnabled = _cfg.GetCVar(CCVars.SubstationDecayEnabled); + _substationDecayTimeout = _cfg.GetCVar(CCVars.SubstationDecayTimeout); + _substationDecayCoefficient = _cfg.GetCVar(CCVars.SubstationDecayCoefficient); + _substationDecayTimer = _cfg.GetCVar(CCVars.SubstationDecayTimer); + + SubscribeLocalEvent(OnExamine); + SubscribeLocalEvent(OnRejuvenate); + SubscribeLocalEvent(OnAnalyzed); + + SubscribeLocalEvent(OnNitrogenBoosterInserted); + SubscribeLocalEvent(OnNitrogenBoosterRemoved); + SubscribeLocalEvent(OnNitrogenBoosterInsertAttempt); + SubscribeLocalEvent(OnNitrogenBoosterRemoveAttempt); + } + + private void OnExamine(EntityUid uid, SubstationComponent component, ExaminedEvent args) + { + if (args.IsInDetailsRange) + { + if (!GetNitrogenBoosterMixture(uid, out var mix)) + { + args.PushMarkup(Loc.GetString("substation-component-examine-no-nitrogenbooster")); + return; + } + + var integrity = CheckNitrogenBoosterIntegrity(component, mix); + if (integrity > 0.0f) + { + var integrityPercentRounded = (int)integrity; + args.PushMarkup(Loc.GetString("substation-component-examine-integrity", ("percent", integrityPercentRounded), ("markupPercentColor", "green"))); + } + else + { + args.PushMarkup(Loc.GetString("substation-component-examine-malfunction")); + } + } + } + + public override void Update(float deltaTime) + { + base.Update(deltaTime); + + var lightQuery = EntityQueryEnumerator(); + while (lightQuery.MoveNext(out var uid, out var subs)) + { + subs.SubstationLightBlinkTimer -= deltaTime; + if (subs.SubstationLightBlinkTimer <= 0f) + { + subs.SubstationLightBlinkTimer = subs.SubstationLightBlinkInterval; + subs.SubstationLightBlinkState = !subs.SubstationLightBlinkState; + + if (subs.State == SubstationIntegrityState.Healthy) + continue; + + if (!_lightSystem.TryGetLight(uid, out var shlight)) + return; + + _sharedLightSystem.SetEnergy(uid, subs.SubstationLightBlinkState ? 1.6f : 1f, shlight); + } + + if (!_substationDecayEnabled) + { + _substationDecayTimer -= deltaTime; + if (_substationDecayTimer <= 0.0f) + { + _substationDecayTimer = 0.0f; + _substationDecayEnabled = true; + } + return; + } + } + } + + private void ConsumeNitrogenBoosterGas(float deltaTime, float scalar, SubstationComponent subs, PowerNetworkBatteryComponent battery, GasMixture mixture) + { + var initialN2 = mixture.GetMoles(Gas.Nitrogen); + var boosterMoles = subs.InitialNitrogenBoosterMoles; + var currentSupply = battery.CurrentSupply; + var decayFactor = _substationDecayCoefficient * scalar; + + var molesConsumed = boosterMoles * currentSupply * deltaTime / decayFactor; + var minimumReaction = Math.Abs(initialN2) * molesConsumed / 2; + + mixture.AdjustMoles(Gas.Nitrogen, -minimumReaction); + mixture.AdjustMoles(Gas.NitrousOxide, minimumReaction); + } + + private float CheckNitrogenBoosterIntegrity(SubstationComponent subs, GasMixture mixture) + { + if (subs.InitialNitrogenBoosterMoles <= 0f) + return 0f; + + var initialN2 = mixture.GetMoles(Gas.Nitrogen); + var usableMoles = initialN2; + return 100 * usableMoles / subs.InitialNitrogenBoosterMoles; + } + + private void NitrogenBoosterChanged(EntityUid uid, SubstationComponent subs) + { + if (!GetNitrogenBoosterMixture(uid, out var mix)) + { + ShutdownSubstation(uid, subs); + subs.LastIntegrity = 0f; + return; + } + + var initialNitrogenBoosterMoles = 0f; + for (var i = 0; i < Atmospherics.TotalNumberOfGases; i++) + { + initialNitrogenBoosterMoles += mix.GetMoles(i); + } + + subs.InitialNitrogenBoosterMoles = initialNitrogenBoosterMoles; + var nitrogenBoosterIntegrity = CheckNitrogenBoosterIntegrity(subs, mix); + + if (nitrogenBoosterIntegrity <= 0.0f) + { + ShutdownSubstation(uid, subs); + subs.LastIntegrity = nitrogenBoosterIntegrity; + return; + } + + if (nitrogenBoosterIntegrity < 30f) + { + ChangeState(uid, SubstationIntegrityState.Bad, subs); + } + else if (nitrogenBoosterIntegrity < 70f) + { + ChangeState(uid, SubstationIntegrityState.Unhealthy, subs); + } + else + { + ChangeState(uid, SubstationIntegrityState.Healthy, subs); + } + + subs.LastIntegrity = nitrogenBoosterIntegrity; + } + + private void ShutdownSubstation(EntityUid uid, SubstationComponent subs) + { + if (!TryComp(uid, out var battery)) + return; + + subs.LastIntegrity = 0.0f; + battery.Enabled = false; + battery.CanCharge = false; + battery.CanDischarge = false; + + if (HasComp(uid)) + RemComp(uid); + + ChangeState(uid, SubstationIntegrityState.Bad, subs); + } + + private void OnRejuvenate(EntityUid uid, SubstationComponent subs, RejuvenateEvent args) + { + subs.LastIntegrity = 100.0f; + ChangeState(uid, SubstationIntegrityState.Healthy, subs); + + if (GetNitrogenBoosterMixture(uid, out var mix)) + { + mix.SetMoles(Gas.Nitrogen, 1.025689525f); + } + } + + private void RestoreSubstation(EntityUid uid, SubstationComponent subs) + { + if (!TryComp(uid, out var battery)) + return; + + battery.Enabled = true; + battery.CanCharge = true; + battery.CanDischarge = true; + + if (!HasComp(uid)) + AddComp(uid); + } + + private void ChangeState(EntityUid uid, SubstationIntegrityState state, SubstationComponent? subs = null) + { + if (!_lightSystem.TryGetLight(uid, out var light)) + return; + + if (!Resolve(uid, ref subs, ref light, false)) + return; + + if (subs.State == state) + return; + + if (state == SubstationIntegrityState.Healthy) + { + if (subs.State == SubstationIntegrityState.Bad) + { + RestoreSubstation(uid, subs); + } + _lightSystem.SetColor(uid, new Color(61, 139, 59), light); + } + else if (state == SubstationIntegrityState.Unhealthy) + { + if (subs.State == SubstationIntegrityState.Bad) + { + RestoreSubstation(uid, subs); + } + _lightSystem.SetColor(uid, Color.Yellow, light); + } + else + { + _lightSystem.SetColor(uid, Color.Red, light); + } + + subs.State = state; + UpdateAppearance(uid, subs.State); + } + + private void UpdateAppearance(EntityUid uid, SubstationIntegrityState subsState) + { + if (!TryComp(uid, out var appearance)) + return; + + _appearanceSystem.SetData(uid, SubstationVisuals.Screen, subsState, appearance); + } + + private void OnAnalyzed(EntityUid uid, SubstationComponent slot, GasAnalyzerScanEvent args) + { + if (!TryComp(uid, out var containers)) + return; + + if (!containers.TryGetContainer(slot.NitrogenBoosterSlotId, out var container)) + return; + + if (!slot.MaintenanceDoorOpen) + return; + + if (container.ContainedEntities.Count > 0) + { + if (container.ContainedEntities.Count > 0 && container.ContainedEntities[0] != null) + { + var gasTankComponent = Comp(container.ContainedEntities[0]); + if (gasTankComponent != null) + { + args.GasMixtures = new List<(string, GasMixture?)> + { + (Name(uid), gasTankComponent.Air) + }; + } + } + } + } + + private bool GetNitrogenBoosterMixture(EntityUid uid, [NotNullWhen(true)] out GasMixture? mix) + { + mix = null; + + if (!TryComp(uid, out var subs) || !TryComp(uid, out var containers)) + return false; + + if (!containers.TryGetContainer(subs.NitrogenBoosterSlotId, out var container)) + return false; + + if (container.ContainedEntities.Count > 0) + { + var gasTank = Comp(container.ContainedEntities[0]); + mix = gasTank.Air; + return true; + } + + return false; + } + + private void OnNitrogenBoosterInsertAttempt(EntityUid uid, SubstationComponent component, ContainerIsInsertingAttemptEvent args) + { + if (!component.Initialized) + return; + + if (args.Container.ID != component.NitrogenBoosterSlotId) + return; + + if (!TryComp(uid, out var panel)) + { + args.Cancel(); + return; + } + + if (component.AllowInsert) + { + component.AllowInsert = false; + return; + } + + if (!panel.Open) + { + args.Cancel(); + } + } + + private void OnNitrogenBoosterRemoveAttempt(EntityUid uid, SubstationComponent component, ContainerIsRemovingAttemptEvent args) + { + if (!component.Initialized) + return; + + if (args.Container.ID != component.NitrogenBoosterSlotId) + return; + + if (!TryComp(uid, out var panel)) + return; + + if (!panel.Open) + { + args.Cancel(); + } + } + + private void OnNitrogenBoosterInserted(EntityUid uid, SubstationComponent component, EntInsertedIntoContainerMessage args) + { + if (!component.Initialized) + return; + + if (args.Container.ID != component.NitrogenBoosterSlotId) + return; + + NitrogenBoosterChanged(uid, component); + } + + private void OnNitrogenBoosterRemoved(EntityUid uid, SubstationComponent component, EntRemovedFromContainerMessage args) + { + if (args.Container.ID != component.NitrogenBoosterSlotId) + return; + + NitrogenBoosterChanged(uid, component); + } +} diff --git a/Content.Shared/CCVar/CCVars.cs b/Content.Shared/CCVar/CCVars.cs index 2d6aa563904dc8..4ad3fe9f5bb251 100644 --- a/Content.Shared/CCVar/CCVars.cs +++ b/Content.Shared/CCVar/CCVars.cs @@ -436,6 +436,31 @@ public static readonly CVarDef public static readonly CVarDef GameEntityMenuLookup = CVarDef.Create("game.entity_menu_lookup", 0.25f, CVar.CLIENTONLY | CVar.ARCHIVE); + /// + /// If true, substation decay will be enabled + /// + public static readonly CVarDef SubstationDecayEnabled = + CVarDef.Create("game.substation_decay_enabled", true, CVar.SERVER | CVar.REPLICATED); + + /// + /// Timeout to substation decay + /// + public static readonly CVarDef SubstationDecayTimeout = + CVarDef.Create("game.substation_decay_timeout", 300, CVar.SERVER | CVar.REPLICATED); + + /// + /// Substation decay coefficient + /// + public static readonly CVarDef SubstationDecayCoefficient = + CVarDef.Create("game.substation_decay_coefficient", 300000f, CVar.SERVER | CVar.REPLICATED); + + /// + /// Substation decay timer + /// + + public static readonly CVarDef SubstationDecayTimer = + CVarDef.Create("game.substation_decay_timer", 0f, CVar.SERVER | CVar.REPLICATED); + /// /// Should the clients window show the server hostname in the title? /// diff --git a/Content.Shared/Power/SharedSubstation.cs b/Content.Shared/Power/SharedSubstation.cs new file mode 100644 index 00000000000000..dc1aecac27a9fa --- /dev/null +++ b/Content.Shared/Power/SharedSubstation.cs @@ -0,0 +1,18 @@ +using Robust.Shared.Serialization; +using Content.Shared.Containers.ItemSlots; + +namespace Content.Shared.Power; + +[Serializable, NetSerializable] +public enum SubstationIntegrityState +{ + Healthy, //At 70% or more + Unhealthy, // <70% to 30% + Bad // <30% +} + +[Serializable, NetSerializable] +public enum SubstationVisuals +{ + Screen +} \ No newline at end of file diff --git a/Content.Shared/Power/SubstationComponent.cs b/Content.Shared/Power/SubstationComponent.cs new file mode 100644 index 00000000000000..0b3dbafc45d68a --- /dev/null +++ b/Content.Shared/Power/SubstationComponent.cs @@ -0,0 +1,36 @@ +namespace Content.Shared.Power; + +[RegisterComponent] +public sealed partial class SubstationComponent : Component +{ + + [ViewVariables(VVAccess.ReadOnly)] + public float LastIntegrity = 100f; + + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public bool DecayEnabled = true; + + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public SubstationIntegrityState State = SubstationIntegrityState.Healthy; + + [DataField] + [ViewVariables(VVAccess.ReadWrite)] + public bool MaintenanceDoorOpen = false; + + // 9.231205828 is the amount of moles in a 5L container (the default conduit) at 1000Kpa 20C° + public float InitialNitrogenBoosterMoles = 2.051379050f; + + [DataField(required: true)] + [ViewVariables(VVAccess.ReadOnly)] + public string NitrogenBoosterSlotId = string.Empty; + + public bool AllowInsert = true; + + public float SubstationLightBlinkInterval = 1f; + + public float SubstationLightBlinkTimer = 1f; + + public bool SubstationLightBlinkState = true; +} diff --git a/Resources/Locale/en-US/machine/machine.ftl b/Resources/Locale/en-US/machine/machine.ftl index 13d9e76b9d2590..580b1e600115db 100644 --- a/Resources/Locale/en-US/machine/machine.ftl +++ b/Resources/Locale/en-US/machine/machine.ftl @@ -7,12 +7,19 @@ machine-upgrade-decreased-by-percentage = [color=yellow]{CAPITALIZE($upgraded)}[ machine-upgrade-increased-by-amount = [color=yellow]{CAPITALIZE($upgraded)}[/color] increased by {$difference}. machine-upgrade-decreased-by-amount = [color=yellow]{CAPITALIZE($upgraded)}[/color] decreased by {$difference}. machine-upgrade-not-upgraded = [color=yellow]{CAPITALIZE($upgraded)}[/color] not upgraded. +machine-upgrade-max-upgrade = [color=yellow]{CAPITALIZE($upgraded)}[/color] fully upgraded. machine-part-name-capacitor = Capacitor machine-part-name-manipulator = Manipulator machine-part-name-matter-bin = Matter Bin machine-part-name-power-cell = Power Cell +upgrade-power-draw = power draw +upgrade-max-charge = max charge +upgrade-power-supply = power supply +upgrade-power-supply-ramping = power ramp rate +upgrade-nitrogenbooster-lifetime = conduit lifetime + two-way-lever-left = push left two-way-lever-right = push right two-way-lever-cant = can't push the lever that way! diff --git a/Resources/Locale/en-US/power/components/substation-component.ftl b/Resources/Locale/en-US/power/components/substation-component.ftl new file mode 100644 index 00000000000000..69c58231137509 --- /dev/null +++ b/Resources/Locale/en-US/power/components/substation-component.ftl @@ -0,0 +1,8 @@ + +### UI + +# Shown when the substation is examined in details range +substation-component-examine-integrity = The substation is at [color={$markupPercentColor}]{$percent}%[/color] integrity. +substation-component-examine-malfunction = The substation is [color=red]malfunctioning[/color]. +substation-component-examine-no-nitrogenbooster = The substation is [color=red]missing a nitrogen booster gas tank[/color]. + diff --git a/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml b/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml index 2cf1354c143cf5..5231fc8b4579c6 100644 --- a/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml +++ b/Resources/Prototypes/Catalog/Fills/Items/gas_tanks.yml @@ -221,3 +221,20 @@ - 0 # CO2 - 2.051379050 # plasma temperature: 293.15 + +- type: entity + id: GasTankNitrogenBoosterFilled + parent: GasTankNitrogenBooster + name: nitrogen booster + suffix: Filled + components: + - type: GasTank + outputPressure: 101.3 + air: + volume: 5 + moles: + - 0 # oxygen + - 2.051379050 # nitrogen + - 0 # CO2 + - 0 # plasma + temperature: 293.15 diff --git a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml index 7baf1f0b5d7684..c6319f73f8bcd8 100644 --- a/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml +++ b/Resources/Prototypes/Entities/Objects/Tools/gas_tanks.yml @@ -244,3 +244,23 @@ slots: - Belt - suitStorage + +- type: entity + parent: GasTankRoundBase + id: GasTankNitrogenBooster + name: nitrogen booster + description: A bulky tank filled with nitrogen designed to maintain substations. + components: + - type: Sprite + sprite: Objects/Tanks/nitrogenbooster.rsi + - type: Item + sprite: Objects/Tanks/nitrogenbooster.rsi + - type: GasTank + outputPressure: 101.3 + air: + volume: 5 + temperature: 293.15 + - type: Tag + tags: + - NitrogenBooster + diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml index a8e4d0f43e0128..2382140f04f9dc 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml @@ -137,6 +137,7 @@ - AirTank - GasAnalyzer - UtilityBelt + - GasTankNitrogenBooster - Pickaxe - ModularReceiver - AppraisalTool diff --git a/Resources/Prototypes/Entities/Structures/Power/substation.yml b/Resources/Prototypes/Entities/Structures/Power/substation.yml index a8bdebd10a37ce..0e2585223c0d7f 100644 --- a/Resources/Prototypes/Entities/Structures/Power/substation.yml +++ b/Resources/Prototypes/Entities/Structures/Power/substation.yml @@ -8,15 +8,39 @@ placement: mode: SnapgridCenter components: - - type: Sprite # TODO: add sprite for maintenance panel open + - type: Sprite # TODO: add sprite for maintenance panel open. This will show the nitrogen booster there or not. sprite: Structures/Power/substation.rsi snapCardinals: true layers: - state: substation - - state: screen + map: ["substationBase"] + - state: screen0 + map: ["substationScreen"] shader: unshaded - state: full + map: ["substationBattery"] shader: unshaded + - type: Substation + nitrogenBoosterSlotId: NitrogenBooster_slot + - type: ContainerContainer + containers: + NitrogenBooster_slot: !type:ContainerSlot {} + - type: ItemSlots + slots: + NitrogenBooster_slot: + ejectOnInteract: true + name: nitrogen booster gas tank + startingItem: GasTankNitrogenBoosterFilled + whitelist: + tags: + - NitrogenBooster + - type: SubstationVisuals + screenLayer: "substationScreen" + integrityStates: + Healthy: screen0 + Unhealthy: screen1 + Bad: screen2 + - type: Appearance - type: Battery maxCharge: 2500000 startingCharge: 0 @@ -29,10 +53,10 @@ - type: NodeContainer examinable: true nodes: - input: + hv: !type:CableDeviceNode nodeGroupID: HVPower - output: + mv: !type:CableDeviceNode nodeGroupID: MVPower - type: PowerMonitoringDevice @@ -71,7 +95,7 @@ acts: ["Destruction"] - !type:PlaySoundBehavior sound: - collection: MetalGlassBreak + path: /Audio/Effects/metalbreak.ogg - !type:ExplodeBehavior - !type:SpawnEntitiesBehavior spawn: @@ -140,6 +164,20 @@ - type: ContainerContainer containers: board: !type:Container + NitrogenBooster_slot: !type:ContainerSlot + - type: ItemSlots + slots: + NitrogenBooster_slot: + ejectOnInteract: true + name: nitrogen booster + startingItem: GasTankNitrogenBoosterFilled + whitelist: + tags: + - GasTankNitrogenBoosterFilled + - type: WiresPanel + - type: Wires + boardName: wires-board-name-substation + layoutId: Substation - type: InteractionOutline - type: Physics bodyType: Static @@ -152,8 +190,19 @@ sprite: Structures/Power/substation.rsi layers: - state: substation_wall - - state: screen_wall + map: ["substationBase"] + - state: screen0 + map: ["substationScreen"] shader: unshaded + - type: Substation + nitrogenBoosterSlotId: NitrogenBooster_slot + - type: SubstationVisuals + screenLayer: "substationScreen" + integrityStates: + Healthy: screen0 + Unhealthy: screen1 + Bad: screen2 + - type: Appearance - type: Battery maxCharge: 2000000 startingCharge: 0 @@ -203,7 +252,7 @@ - !type:ExplodeBehavior - !type:PlaySoundBehavior sound: - collection: MetalGlassBreak + path: /Audio/Effects/metalbreak.ogg - type: Construction graph: WallmountSubstation node: substation @@ -233,6 +282,14 @@ components: - type: Battery startingCharge: 0 + - type: ItemSlots + slots: + NitrogenBooster_slot: + ejectOnInteract: true + name: nitrogen booster gas tank + startingItem: + - type: Substation + state: Bad - type: entity parent: BaseSubstationWall @@ -253,6 +310,23 @@ capacitor: !type:Container powercell: !type:Container +- type: entity + parent: BaseSubstationWall + id: SubstationWallBasicEmpty + suffix: Empty + components: + - type: Battery + maxCharge: 2000000 + startingCharge: 0 + - type: ItemSlots + slots: + NitrogenBooster_slot: + ejectOnInteract: true + name: nitrogen booster gas tank + startingItem: + - type: Substation + state: Bad + # Construction Frame - type: entity id: BaseSubstationWallFrame diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml index 7e4087b20a21b7..c1296ce1d627e5 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/utilities/wallmount_substation.yml @@ -88,7 +88,7 @@ doAfter: 2 - node: substation - entity: BaseSubstationWall + entity: SubstationWallBasicEmpty edges: - to: parts conditions: diff --git a/Resources/Prototypes/Recipes/Lathes/misc.yml b/Resources/Prototypes/Recipes/Lathes/misc.yml index a0e74fc34e2f2a..fa4e34b36b5538 100644 --- a/Resources/Prototypes/Recipes/Lathes/misc.yml +++ b/Resources/Prototypes/Recipes/Lathes/misc.yml @@ -150,6 +150,13 @@ Steel: 750 Plastic: 100 +- type: latheRecipe + id: GasTankNitrogenBooster + result: GasTankNitrogenBooster + completetime: 2 + materials: + Steel: 200 + - type: latheRecipe id: FauxTileAstroGrass result: FloorTileItemAstroGrass diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml index 4f9d0eb3f8cde4..8b5e03b5618356 100644 --- a/Resources/Prototypes/tags.yml +++ b/Resources/Prototypes/tags.yml @@ -983,6 +983,9 @@ - type: Tag id: Multitool + +- type: Tag + id: NitrogenBooster - type: Tag id: NoBlockAnchoring diff --git a/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/equipped-BELT.png b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/equipped-BELT.png new file mode 100644 index 00000000000000..ef0e4a7f81dec2 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/equipped-BELT.png differ diff --git a/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/icon.png b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/icon.png new file mode 100644 index 00000000000000..2655ac5722cb37 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/icon.png differ diff --git a/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-left.png b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-left.png new file mode 100644 index 00000000000000..f24f9842dac6f3 Binary files /dev/null and b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-left.png differ diff --git a/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-right.png b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-right.png new file mode 100644 index 00000000000000..bd5de325be175a Binary files /dev/null and b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/inhand-right.png differ diff --git a/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/meta.json b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/meta.json new file mode 100644 index 00000000000000..cdc584b5551033 --- /dev/null +++ b/Resources/Textures/Objects/Tanks/nitrogenbooster.rsi/meta.json @@ -0,0 +1,26 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Made by joshepvodka", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "icon" + }, + { + "name": "equipped-BELT", + "directions": 4 + }, + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + } + ] +} diff --git a/Resources/Textures/Structures/Power/substation.rsi/meta.json b/Resources/Textures/Structures/Power/substation.rsi/meta.json index d19066274d15e5..027e1e522af24e 100644 --- a/Resources/Textures/Structures/Power/substation.rsi/meta.json +++ b/Resources/Textures/Structures/Power/substation.rsi/meta.json @@ -1,86 +1,108 @@ { - "version": 1, - "license": "CC0-1.0", - "copyright": "Created by EmoGarbage404 (github)", - "size": { - "x": 32, - "y": 32 - }, - "states": [ - { - "name": "substation" + "version": 1, + "license": "CC0-1.0", + "copyright": "Created by EmoGarbage404 (github), screen sprites created by joshepvodka (github) and updated by AwareFoxy(github)", + "size": { + "x": 32, + "y": 32 }, - { - "name": "substation_static" - }, - { - "name": "substation_wall", - "directions": 4 - }, - { - "name": "screen_wall", - "directions": 4, - "delays": [ - [ - 5.0, - 0.5, - 0.5, - 0.5 - ], - [ - 5.0, - 0.5, - 0.5, - 0.5 - ], - [ - 5.0, - 0.5, - 0.5, - 0.5 - ], - [ - 5.0, - 0.5, - 0.5, - 0.5 - ] - ] - }, - { - "name": "substation_wall_static" - }, - { - "name": "full" - }, - { - "name": "charging", - "delays": [ - [ - 0.1, - 0.1 - ] - ] - }, - { - "name": "dead", - "delays": [ - [ - 0.3, - 0.1 - ] - ] - }, - { - "name": "screen", - "delays": [ - [ - 5.0, - 0.5, - 0.5, - 0.5 - ] - ] - } - ] -} + "states": [ + { + "name": "substation" + }, + { + "name": "substation_static" + }, + { + "name": "substation_wall", + "directions": 4 + }, + { + "name": "screen_wall", + "directions": 4, + "delays": [ + [ + 5.0, + 0.5, + 0.5, + 0.5 + ], + [ + 5.0, + 0.5, + 0.5, + 0.5 + ], + [ + 5.0, + 0.5, + 0.5, + 0.5 + ], + [ + 5.0, + 0.5, + 0.5, + 0.5 + ] + ] + }, + { + "name": "substation_wall_static" + }, + { + "name": "full" + }, + { + "name": "charging", + "delays": [ + [ + 0.1, + 0.1 + ] + ] + }, + { + "name": "dead", + "delays": [ + [ + 0.3, + 0.1 + ] + ] + }, + { + "name": "screen0", + "delays": [ + [ + 0.15, + 0.15, + 0.15, + 0.15 + ] + ] + }, + { + "name": "screen1", + "delays": [ + [ + 0.15, + 0.15, + 0.15, + 0.15 + ] + ] + }, + { + "name": "screen2", + "delays": [ + [ + 5.0, + 0.5, + 0.5, + 0.5 + ] + ] + } + ] +} \ No newline at end of file diff --git a/Resources/Textures/Structures/Power/substation.rsi/screen.png b/Resources/Textures/Structures/Power/substation.rsi/screen0.png similarity index 100% rename from Resources/Textures/Structures/Power/substation.rsi/screen.png rename to Resources/Textures/Structures/Power/substation.rsi/screen0.png diff --git a/Resources/Textures/Structures/Power/substation.rsi/screen1.png b/Resources/Textures/Structures/Power/substation.rsi/screen1.png new file mode 100644 index 00000000000000..44c5cdce14e5cb Binary files /dev/null and b/Resources/Textures/Structures/Power/substation.rsi/screen1.png differ diff --git a/Resources/Textures/Structures/Power/substation.rsi/screen2.png b/Resources/Textures/Structures/Power/substation.rsi/screen2.png new file mode 100644 index 00000000000000..5e1b982675db17 Binary files /dev/null and b/Resources/Textures/Structures/Power/substation.rsi/screen2.png differ