From 9c861af7b724e48bcb57ca710e1a9d322d5ba4e9 Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sun, 27 Jun 2021 17:37:32 +0200 Subject: [PATCH] [MIRROR] Greyscale Mat Datum Stationary Smooth Tanks (#6544) * Greyscale Mat Datum Stationary Smooth Tanks * Update icon_smoothing.dm Co-authored-by: Emmett Gaines Co-authored-by: Gandalf --- .../LavaRuins/lavaland_biodome_beach.dmm | 2 +- .../LavaRuins/lavaland_surface_seed_vault.dmm | 2 +- .../RandomRuins/SpaceRuins/caravanambush.dmm | 2 +- .../RandomRuins/SpaceRuins/forgottenship.dmm | 2 +- _maps/RandomRuins/SpaceRuins/hellfactory.dmm | 2 +- .../SpaceRuins/listeningstation.dmm | 2 +- _maps/RandomRuins/SpaceRuins/oldstation.dmm | 2 +- _maps/RandomRuins/SpaceRuins/spacehotel.dmm | 4 +- .../map_files/Deltastation/DeltaStation2.dmm | 4 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 12 +- .../IcemoonUnderground_Above.dmm | 2 +- _maps/map_files/KiloStation/KiloStation.dmm | 6 +- _maps/map_files/MetaStation/MetaStation.dmm | 6 +- _maps/map_files/Mining/Lavaland.dmm | 2 +- _maps/map_files/debug/multiz.dmm | 2 +- _maps/map_files/debug/runtimestation.dmm | 6 +- _maps/map_files/generic/CentCom.dmm | 2 +- _maps/map_files/tramstation/tramstation.dmm | 2 +- _maps/shuttles/emergency_monastery.dmm | 4 +- _maps/shuttles/infiltrator_advanced.dmm | 2 +- _maps/shuttles/pirate_default.dmm | 2 +- _maps/shuttles/pirate_silverscale.dmm | 2 +- _maps/shuttles/ruin_caravan_victim.dmm | 2 +- _maps/shuttles/ruin_pirate_cutter.dmm | 2 +- _maps/shuttles/whiteship_box.dmm | 2 +- _maps/shuttles/whiteship_delta.dmm | 2 +- _maps/shuttles/whiteship_kilo.dmm | 2 +- _maps/shuttles/whiteship_meta.dmm | 2 +- _maps/shuttles/whiteship_tram.dmm | 2 +- code/__DEFINES/construction.dm | 4 + code/__DEFINES/dcs/signals.dm | 8 + code/__DEFINES/icon_smoothing.dm | 9 +- code/__HELPERS/chat.dm | 3 + code/datums/components/cracked.dm | 74 +++ code/datums/elements/crackable.dm | 27 + .../config_types/greyscale_configs.dm | 5 + .../smooth_canister_stationary.json | 186 ++++++ code/datums/mergers/_merger.dm | 132 +++++ code/game/atoms.dm | 20 +- .../items/stacks/sheets/sheet_types.dm | 11 +- code/game/objects/obj_defense.dm | 3 +- code/modules/admin/greyscale_modify_menu.dm | 12 +- .../traitor/equipment/Malf_Modules.dm | 2 +- .../atmospherics/machinery/atmosmachinery.dm | 15 +- .../components/binary_devices/valve.dm | 10 + .../machinery/components/components_base.dm | 16 + .../atmospherics/machinery/components/tank.dm | 545 ++++++++++++++++++ .../unary_devices/portables_connector.dm | 7 + .../components/unary_devices/tank.dm | 115 ---- .../atmospherics/machinery/datum_pipeline.dm | 19 +- .../machinery/portable/canister.dm | 2 +- .../obj/atmospherics/pipes/pressure_tank.dmi | Bin 14599 -> 0 bytes .../obj/atmospherics/stationary_canisters.dmi | Bin 0 -> 2635 bytes sound/effects/structure_stress/pop1.ogg | Bin 0 -> 14694 bytes sound/effects/structure_stress/pop2.ogg | Bin 0 -> 8545 bytes sound/effects/structure_stress/pop3.ogg | Bin 0 -> 10211 bytes tgstation.dme | 5 +- 57 files changed, 1123 insertions(+), 193 deletions(-) create mode 100644 code/datums/components/cracked.dm create mode 100644 code/datums/elements/crackable.dm create mode 100644 code/datums/greyscale/json_configs/smooth_canister_stationary.json create mode 100644 code/datums/mergers/_merger.dm create mode 100644 code/modules/atmospherics/machinery/components/tank.dm delete mode 100644 code/modules/atmospherics/machinery/components/unary_devices/tank.dm delete mode 100644 icons/obj/atmospherics/pipes/pressure_tank.dmi create mode 100644 icons/obj/atmospherics/stationary_canisters.dmi create mode 100644 sound/effects/structure_stress/pop1.ogg create mode 100644 sound/effects/structure_stress/pop2.ogg create mode 100644 sound/effects/structure_stress/pop3.ogg diff --git a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm index 6aa9707c72d..b3e6cb1a190 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_biodome_beach.dmm @@ -1093,7 +1093,7 @@ /turf/open/floor/wood, /area/ruin/powered/beach) "IL" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm index 220b617cd33..6eb8b1a6b11 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_seed_vault.dmm @@ -621,7 +621,7 @@ /turf/closed/wall/r_wall, /area/lavaland/surface/outdoors) "ca" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 4 }, /turf/open/floor/iron/freezer, diff --git a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm index 9cffc15c8fc..389522ca8fb 100644 --- a/_maps/RandomRuins/SpaceRuins/caravanambush.dmm +++ b/_maps/RandomRuins/SpaceRuins/caravanambush.dmm @@ -1038,7 +1038,7 @@ /turf/open/floor/iron/dark/airless, /area/shuttle/caravan/freighter3) "jH" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 4 }, /obj/effect/turf_decal/stripes/line{ diff --git a/_maps/RandomRuins/SpaceRuins/forgottenship.dmm b/_maps/RandomRuins/SpaceRuins/forgottenship.dmm index 0d9d1032084..09658a8b869 100644 --- a/_maps/RandomRuins/SpaceRuins/forgottenship.dmm +++ b/_maps/RandomRuins/SpaceRuins/forgottenship.dmm @@ -965,7 +965,7 @@ /turf/open/floor/mineral/plastitanium/red, /area/ruin/space/has_grav/syndicate_forgotten_ship) "cM" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /turf/open/floor/mineral/plastitanium/red, diff --git a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm index cb6722cceab..f5e0c1cb064 100644 --- a/_maps/RandomRuins/SpaceRuins/hellfactory.dmm +++ b/_maps/RandomRuins/SpaceRuins/hellfactory.dmm @@ -68,7 +68,7 @@ /turf/open/floor/iron/grimy, /area/ruin/space/has_grav/hellfactoryoffice) "ak" = ( -/obj/machinery/atmospherics/components/unary/tank/oxygen{ +/obj/machinery/atmospherics/components/tank/oxygen{ dir = 8; gas_type = /datum/gas/water_vapor; initialize_directions = 8 diff --git a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm index c3d1c60a68a..9371c5207a4 100644 --- a/_maps/RandomRuins/SpaceRuins/listeningstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/listeningstation.dmm @@ -1076,7 +1076,7 @@ /turf/open/floor/plating, /area/ruin/space/has_grav/listeningstation) "bH" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /obj/effect/turf_decal/bot, diff --git a/_maps/RandomRuins/SpaceRuins/oldstation.dmm b/_maps/RandomRuins/SpaceRuins/oldstation.dmm index b21c65051e0..bc8740a333a 100644 --- a/_maps/RandomRuins/SpaceRuins/oldstation.dmm +++ b/_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -4231,7 +4231,7 @@ /area/ruin/space/has_grav/ancientstation/atmo) "kC" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, diff --git a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm index a84ac244e3a..0598e323dca 100644 --- a/_maps/RandomRuins/SpaceRuins/spacehotel.dmm +++ b/_maps/RandomRuins/SpaceRuins/spacehotel.dmm @@ -3570,14 +3570,14 @@ /turf/open/floor/iron/freezer, /area/ruin/space/has_grav/hotel/pool) "lp" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, /area/ruin/space/has_grav/hotel/power) "lq" = ( /obj/machinery/light/small/directional/south, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index 5f3ef9142cd..98302f84847 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -20495,7 +20495,7 @@ /area/science/xenobiology) "cNb" = ( /obj/effect/turf_decal/bot, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/iron, /area/science/xenobiology) "cNc" = ( @@ -34389,7 +34389,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /obj/machinery/firealarm/directional/west, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 381999523ef..e7074daef94 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -2805,7 +2805,7 @@ /turf/open/floor/iron, /area/construction/mining/aux_base) "alF" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/plating, /area/maintenance/port/fore) "alG" = ( @@ -13986,7 +13986,7 @@ dir = 1; layer = 2.9 }, -/obj/machinery/atmospherics/components/unary/tank/toxins, +/obj/machinery/atmospherics/components/tank/toxins, /turf/open/floor/iron, /area/maintenance/disposal/incinerator) "bCq" = ( @@ -17313,7 +17313,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 5 }, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /turf/open/floor/plating, @@ -19014,7 +19014,7 @@ /turf/open/floor/plating, /area/ai_monitored/turret_protected/aisat/atmos) "cui" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/plating, /area/ai_monitored/turret_protected/aisat/atmos) "cuj" = ( @@ -27590,7 +27590,7 @@ /turf/open/floor/iron, /area/commons/cryopods) "gSR" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/maintenance/starboard/aft) @@ -40953,7 +40953,7 @@ /turf/open/floor/iron/white, /area/medical/medbay) "oCz" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/maintenance/port) diff --git a/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm b/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm index 86e7a5ea053..00512e4609a 100644 --- a/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm +++ b/_maps/map_files/IceBoxStation/IcemoonUnderground_Above.dmm @@ -719,7 +719,7 @@ /turf/open/floor/plating, /area/mine/living_quarters) "dr" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /turf/open/floor/plating, diff --git a/_maps/map_files/KiloStation/KiloStation.dmm b/_maps/map_files/KiloStation/KiloStation.dmm index 0a5d0c9189d..ed7cd7429cd 100644 --- a/_maps/map_files/KiloStation/KiloStation.dmm +++ b/_maps/map_files/KiloStation/KiloStation.dmm @@ -2936,7 +2936,7 @@ /turf/open/floor/plating/airless, /area/space/nearstation) "ajj" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /obj/effect/turf_decal/tile/neutral{ @@ -55599,7 +55599,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/delivery, /turf/open/floor/iron/dark, /area/ai_monitored/turret_protected/aisat/atmos) @@ -74625,7 +74625,7 @@ /turf/open/floor/engine, /area/engineering/supermatter/room) "rFl" = ( -/obj/machinery/atmospherics/components/unary/tank/toxins{ +/obj/machinery/atmospherics/components/tank/toxins{ dir = 4 }, /obj/effect/turf_decal/delivery, diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index e26f36b913c..4c2ba0b66e9 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -19526,7 +19526,7 @@ /turf/open/floor/engine, /area/science/mixing/chamber) "eoW" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /turf/open/floor/plating, @@ -29173,7 +29173,7 @@ /obj/effect/turf_decal/tile/green{ dir = 1 }, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/iron/white, /area/medical/virology) "hFg" = ( @@ -44351,7 +44351,7 @@ "mKO" = ( /obj/effect/decal/cleanable/dirt, /obj/effect/turf_decal/delivery, -/obj/machinery/atmospherics/components/unary/tank/toxins{ +/obj/machinery/atmospherics/components/tank/toxins{ dir = 4 }, /turf/open/floor/iron, diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm index f849e4a2bb3..75de8850d8c 100644 --- a/_maps/map_files/Mining/Lavaland.dmm +++ b/_maps/map_files/Mining/Lavaland.dmm @@ -1033,7 +1033,7 @@ /turf/open/floor/plating, /area/mine/living_quarters) "dr" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /turf/open/floor/plating, diff --git a/_maps/map_files/debug/multiz.dmm b/_maps/map_files/debug/multiz.dmm index 60fab950172..5934d8c5b4d 100644 --- a/_maps/map_files/debug/multiz.dmm +++ b/_maps/map_files/debug/multiz.dmm @@ -47,7 +47,7 @@ /turf/open/floor/plating, /area/engineering/atmos) "am" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/plating, /area/engineering/atmos) "an" = ( diff --git a/_maps/map_files/debug/runtimestation.dmm b/_maps/map_files/debug/runtimestation.dmm index 18cdbd6c397..066fffbf7e2 100644 --- a/_maps/map_files/debug/runtimestation.dmm +++ b/_maps/map_files/debug/runtimestation.dmm @@ -41,7 +41,7 @@ /turf/open/floor/iron, /area/engineering/main) "am" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/plating, /area/engineering/atmos) "an" = ( @@ -1107,7 +1107,7 @@ /turf/open/floor/iron, /area/security/brig) "dS" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/machinery/camera/autoname, /turf/open/floor/plating, /area/engineering/atmos) @@ -2651,7 +2651,7 @@ /turf/open/floor/plating, /area/engineering/atmos) "XU" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/machinery/light/directional/north, /turf/open/floor/plating, /area/engineering/atmos) diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index f2f4e17236c..0491227ff45 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -5801,7 +5801,7 @@ dir = 1 }, /obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /obj/machinery/firealarm/directional/south, diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 758ee7e340c..a8f5126fe96 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -61583,7 +61583,7 @@ /turf/open/floor/plating, /area/maintenance/central/secondary) "tMg" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 4 }, /turf/open/floor/plating, diff --git a/_maps/shuttles/emergency_monastery.dmm b/_maps/shuttles/emergency_monastery.dmm index 9a792802784..925e610f087 100644 --- a/_maps/shuttles/emergency_monastery.dmm +++ b/_maps/shuttles/emergency_monastery.dmm @@ -388,7 +388,7 @@ /turf/open/floor/iron/dark, /area/shuttle/escape) "dR" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, @@ -3719,7 +3719,7 @@ /obj/effect/turf_decal/tile/neutral{ dir = 8 }, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/iron/dark, /area/shuttle/escape) "Rd" = ( diff --git a/_maps/shuttles/infiltrator_advanced.dmm b/_maps/shuttles/infiltrator_advanced.dmm index 9f1f824d760..9aee53bffca 100644 --- a/_maps/shuttles/infiltrator_advanced.dmm +++ b/_maps/shuttles/infiltrator_advanced.dmm @@ -1965,7 +1965,7 @@ /turf/open/floor/mineral/plastitanium, /area/shuttle/syndicate/armory) "eb" = ( -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 8 }, /obj/effect/turf_decal/bot, diff --git a/_maps/shuttles/pirate_default.dmm b/_maps/shuttles/pirate_default.dmm index bdbc0ec0d8d..3a9695a20d6 100644 --- a/_maps/shuttles/pirate_default.dmm +++ b/_maps/shuttles/pirate_default.dmm @@ -968,7 +968,7 @@ /turf/open/floor/pod/dark, /area/shuttle/pirate) "km" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/bot, /obj/machinery/firealarm/directional/north, /obj/effect/decal/cleanable/dirt, diff --git a/_maps/shuttles/pirate_silverscale.dmm b/_maps/shuttles/pirate_silverscale.dmm index 5f5b0ef19f3..dc387cfcab6 100644 --- a/_maps/shuttles/pirate_silverscale.dmm +++ b/_maps/shuttles/pirate_silverscale.dmm @@ -661,7 +661,7 @@ /turf/open/floor/pod/dark, /area/shuttle/pirate) "QI" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/pod/dark, /area/shuttle/pirate) "QO" = ( diff --git a/_maps/shuttles/ruin_caravan_victim.dmm b/_maps/shuttles/ruin_caravan_victim.dmm index 04cecafc22d..576993771f1 100644 --- a/_maps/shuttles/ruin_caravan_victim.dmm +++ b/_maps/shuttles/ruin_caravan_victim.dmm @@ -486,7 +486,7 @@ /area/shuttle/caravan/freighter1) "zd" = ( /obj/effect/turf_decal/bot, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 4 }, /obj/effect/decal/cleanable/dirt, diff --git a/_maps/shuttles/ruin_pirate_cutter.dmm b/_maps/shuttles/ruin_pirate_cutter.dmm index 1b35635b151..b9bd78ba0de 100644 --- a/_maps/shuttles/ruin_pirate_cutter.dmm +++ b/_maps/shuttles/ruin_pirate_cutter.dmm @@ -771,7 +771,7 @@ /turf/open/floor/plating, /area/shuttle/caravan/pirate) "Gh" = ( -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/bot, /turf/open/floor/plating, /area/shuttle/caravan/pirate) diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm index 51d2f39ca8b..4728d36e876 100644 --- a/_maps/shuttles/whiteship_box.dmm +++ b/_maps/shuttles/whiteship_box.dmm @@ -767,7 +767,7 @@ /area/shuttle/abandoned/engine) "bq" = ( /obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /obj/effect/turf_decal/bot, diff --git a/_maps/shuttles/whiteship_delta.dmm b/_maps/shuttles/whiteship_delta.dmm index 57536a79d54..00a886c4beb 100644 --- a/_maps/shuttles/whiteship_delta.dmm +++ b/_maps/shuttles/whiteship_delta.dmm @@ -984,7 +984,7 @@ dir = 1 }, /obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /turf/open/floor/plating, diff --git a/_maps/shuttles/whiteship_kilo.dmm b/_maps/shuttles/whiteship_kilo.dmm index bf25d783750..ef4649f54cf 100644 --- a/_maps/shuttles/whiteship_kilo.dmm +++ b/_maps/shuttles/whiteship_kilo.dmm @@ -425,7 +425,7 @@ "aN" = ( /obj/machinery/light/small/built/directional/north, /obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /obj/effect/turf_decal/bot, /obj/effect/turf_decal/stripes/line{ dir = 1 diff --git a/_maps/shuttles/whiteship_meta.dmm b/_maps/shuttles/whiteship_meta.dmm index 46ea40fa84b..84e15ae058e 100644 --- a/_maps/shuttles/whiteship_meta.dmm +++ b/_maps/shuttles/whiteship_meta.dmm @@ -685,7 +685,7 @@ /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt/dust, /obj/effect/decal/cleanable/dirt/dust, -/obj/machinery/atmospherics/components/unary/tank/air{ +/obj/machinery/atmospherics/components/tank/air{ dir = 1 }, /obj/effect/turf_decal/bot, diff --git a/_maps/shuttles/whiteship_tram.dmm b/_maps/shuttles/whiteship_tram.dmm index c06a29e03f1..127b179181a 100644 --- a/_maps/shuttles/whiteship_tram.dmm +++ b/_maps/shuttles/whiteship_tram.dmm @@ -46,7 +46,7 @@ /area/shuttle/abandoned/engine) "ai" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/atmospherics/components/unary/tank/air, +/obj/machinery/atmospherics/components/tank/air, /turf/open/floor/mineral/titanium/tiled/yellow, /area/shuttle/abandoned/engine) "aj" = ( diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm index 0e50c808fb9..bf9dba1f7d2 100644 --- a/code/__DEFINES/construction.dm +++ b/code/__DEFINES/construction.dm @@ -58,6 +58,10 @@ #define FLOODLIGHT_NEEDS_LIGHTS 1 #define FLOODLIGHT_NEEDS_SECURING 2 +// Stationary gas tanks +#define TANK_FRAME 0 +#define TANK_PLATING_UNSECURED 1 + //other construction-related things //windows affected by Nar'Sie turn this color. diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 3c54e10d098..3162a671da2 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -1357,3 +1357,11 @@ /// Called in /obj/structure/moneybot/add_money(). (to_add) #define COMSIG_MONEYBOT_ADD_MONEY "moneybot_add_money" + +// Merger datum signals +/// Called on the object being added to a merger group: (datum/merger/new_merger) +#define COMSIG_MERGER_ADDING "comsig_merger_adding" +/// Called on the object being removed from a merger group: (datum/merger/old_merger) +#define COMSIG_MERGER_REMOVING "comsig_merger_removing" +/// Called on the merger after finishing a refresh: (list/leaving_members, list/joining_members) +#define COMSIG_MERGER_REFRESH_COMPLETE "comsig_merger_refresh_complete" diff --git a/code/__DEFINES/icon_smoothing.dm b/code/__DEFINES/icon_smoothing.dm index 286a920a557..80abc7ae3bf 100644 --- a/code/__DEFINES/icon_smoothing.dm +++ b/code/__DEFINES/icon_smoothing.dm @@ -165,10 +165,13 @@ DEFINE_BITFIELD(smoothing_flags, list( #define SMOOTH_GROUP_CLEANABLE_DIRT S_OBJ(67) ///obj/effect/decal/cleanable/dirt #define SMOOTH_GROUP_INDUSTRIAL_LIFT S_OBJ(70) ///obj/structure/industrial_lift -//SKYRAT EDIT ADDITION -#define SMOOTH_GROUP_SHUTTERS S_OBJ(71) -#define SMOOTH_GROUP_WATER S_OBJ(72) ///obj/effect/abstract/liquid_turf +#define SMOOTH_GROUP_GAS_TANK S_OBJ(71) + +//SKYRAT EDIT ADDITION +#define SMOOTH_GROUP_SHUTTERS S_OBJ(72) + +#define SMOOTH_GROUP_WATER S_OBJ(73) ///obj/effect/abstract/liquid_turf #define MAX_S_OBJ SMOOTH_GROUP_WATER //Always match this value with the one above it. //SKYRAT EDIT END diff --git a/code/__HELPERS/chat.dm b/code/__HELPERS/chat.dm index 27e400f262a..230dd03361e 100644 --- a/code/__HELPERS/chat.dm +++ b/code/__HELPERS/chat.dm @@ -72,3 +72,6 @@ In TGS3 it will always be sent to all connected designated game chats. if(!embed_links) message = GLOB.has_discord_embeddable_links.Replace(replacetext(message, "`", ""), " ```$1``` ") world.TgsTargetedChatBroadcast("[category] | [message]", TRUE) + +/// Handles text formatting for item use hints in examine text +#define EXAMINE_HINT(text) ("" + text + "") diff --git a/code/datums/components/cracked.dm b/code/datums/components/cracked.dm new file mode 100644 index 00000000000..79b5b653442 --- /dev/null +++ b/code/datums/components/cracked.dm @@ -0,0 +1,74 @@ +/// Tracks damage to add or remove crack overlays, when none are needed this components is qdeleted +/datum/component/cracked + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + var/list/icon/crack_icons + var/crack_integrity + var/list/applied_cracks = list() + +/datum/component/cracked/Initialize(list/crack_icons, crack_integrity) + . = ..() + if(!isobj(parent)) + return COMPONENT_INCOMPATIBLE + src.crack_icons = crack_icons + src.crack_integrity = crack_integrity + +/datum/component/cracked/Destroy(force, silent) + RemoveCracks(parent, length(applied_cracks)) + return ..() + +/datum/component/cracked/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_OBJ_INTEGRITY_CHANGED, .proc/IntegrityChanged) + var/obj/master = parent + var/integrity = master.get_integrity() + IntegrityChanged(parent, integrity, integrity) + +/datum/component/cracked/UnregisterFromParent() + . = ..() + UnregisterSignal(parent, COMSIG_OBJ_INTEGRITY_CHANGED) + +/datum/component/cracked/proc/IntegrityChanged(obj/source, old_value, new_value) + SIGNAL_HANDLER + var/cracked_max_integrity = source.max_integrity * crack_integrity + if(new_value >= cracked_max_integrity) + qdel(src) + return + + var/current_percent = 1 - (new_value / cracked_max_integrity) + var/cracks = CEILING(10 * current_percent, 1) // 1 crack per 10% integrity lost + var/current_cracks = length(applied_cracks) + if(!islist(source.filters)) + if(isnull(source.filters)) + source.filters = list() + else + source.filters = list(source.filters) + + if(current_cracks == cracks) + return + + if(current_cracks < cracks) + AddCracks(source, cracks - current_cracks) + else + RemoveCracks(source, current_cracks - cracks) + +/datum/component/cracked/proc/AddCracks(obj/source, count) + for(var/i in 1 to count) + var/rand_x = rand(0, 20) - 10 + var/rand_y = rand(0, 20) - 10 + var/icon/new_crack_icon = pick(crack_icons) + var/list/new_filter_data = alpha_mask_filter(icon=new_crack_icon, x=rand_x, y=rand_y, flags=MASK_INVERSE) + var/name + for(var/k in 1 to 100) + name = "crack[rand(0, 999)]" + if(!applied_cracks[name]) + break + if(applied_cracks[name]) + CRASH("No unique name could be found after 100 iterations.") + applied_cracks[name] = TRUE + source.add_filter(name, 1, new_filter_data) + +/datum/component/cracked/proc/RemoveCracks(obj/source, count) + for(var/i in 1 to count) + var/removed_filter = pick(applied_cracks) + applied_cracks -= removed_filter + source.remove_filter(removed_filter) diff --git a/code/datums/elements/crackable.dm b/code/datums/elements/crackable.dm new file mode 100644 index 00000000000..88d972bc9a8 --- /dev/null +++ b/code/datums/elements/crackable.dm @@ -0,0 +1,27 @@ +/// Adds crack overlays to an object when integrity gets low +/datum/element/crackable + element_flags = ELEMENT_BESPOKE | ELEMENT_DETACH + id_arg_index = 2 + var/list/icon/crack_icons + /// The level at which the object starts showing cracks, 1 being at full health and 0.5 being at half health + var/crack_integrity = 1 + +/datum/element/crackable/Attach(datum/target, icon/crack_icon, list/crack_states, crack_integrity) + . = ..() + if(!isobj(target)) + return ELEMENT_INCOMPATIBLE + src.crack_integrity = crack_integrity || src.crack_integrity + if(!crack_icons) // This is the first attachment and we need to do first time setup + crack_icons = list() + for(var/state in crack_states) + for(var/i in 1 to 36) + var/icon/new_crack_icon = icon(crack_icon, state) + new_crack_icon.Turn(i * 10) + crack_icons += new_crack_icon + RegisterSignal(target, COMSIG_OBJ_INTEGRITY_CHANGED, .proc/IntegrityChanged) + +/datum/element/crackable/proc/IntegrityChanged(obj/source, old_value, new_value) + SIGNAL_HANDLER + if(new_value >= source.max_integrity * crack_integrity) + return + source.AddComponent(/datum/component/cracked, crack_icons, crack_integrity) diff --git a/code/datums/greyscale/config_types/greyscale_configs.dm b/code/datums/greyscale/config_types/greyscale_configs.dm index 7d652ba1702..7a70c906729 100644 --- a/code/datums/greyscale/config_types/greyscale_configs.dm +++ b/code/datums/greyscale/config_types/greyscale_configs.dm @@ -28,6 +28,11 @@ icon_file = 'icons/obj/atmospherics/prototype_canister.dmi' json_config = 'code/datums/greyscale/json_configs/canister_proto.json' +/datum/greyscale_config/stationary_canister + name = "Stationary Canister" + icon_file = 'icons/obj/atmospherics/stationary_canisters.dmi' + json_config = 'code/datums/greyscale/json_configs/smooth_canister_stationary.json' + /datum/greyscale_config/carp name = "Space Carp" icon_file = 'icons/mob/carp.dmi' diff --git a/code/datums/greyscale/json_configs/smooth_canister_stationary.json b/code/datums/greyscale/json_configs/smooth_canister_stationary.json new file mode 100644 index 00000000000..df01ce1e6d2 --- /dev/null +++ b/code/datums/greyscale/json_configs/smooth_canister_stationary.json @@ -0,0 +1,186 @@ +{ + "smooth": [ + { + "type": "icon_state", + "icon_state": "smooth", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "window-fg": [ + { + "type": "icon_state", + "icon_state": "window-fg", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "window-bg": [ + { + "type": "icon_state", + "icon_state": "window-bg", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "1-i": [ + { + "type": "icon_state", + "icon_state": "1-i", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "2-i": [ + { + "type": "icon_state", + "icon_state": "2-i", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "3-i": [ + { + "type": "icon_state", + "icon_state": "3-i", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "4-i": [ + { + "type": "icon_state", + "icon_state": "4-i", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "1-n": [ + { + "type": "icon_state", + "icon_state": "1-n", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "2-n": [ + { + "type": "icon_state", + "icon_state": "2-n", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "3-s": [ + { + "type": "icon_state", + "icon_state": "3-s", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "4-s": [ + { + "type": "icon_state", + "icon_state": "4-s", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "1-w": [ + { + "type": "icon_state", + "icon_state": "1-w", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "2-e": [ + { + "type": "icon_state", + "icon_state": "2-e", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "3-w": [ + { + "type": "icon_state", + "icon_state": "3-w", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "4-e": [ + { + "type": "icon_state", + "icon_state": "4-e", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "1-nw": [ + { + "type": "icon_state", + "icon_state": "1-nw", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "2-ne": [ + { + "type": "icon_state", + "icon_state": "2-ne", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "3-sw": [ + { + "type": "icon_state", + "icon_state": "3-sw", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "4-se": [ + { + "type": "icon_state", + "icon_state": "4-se", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "1-f": [ + { + "type": "icon_state", + "icon_state": "1-f", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "2-f": [ + { + "type": "icon_state", + "icon_state": "2-f", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "3-f": [ + { + "type": "icon_state", + "icon_state": "3-f", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ], + "4-f": [ + { + "type": "icon_state", + "icon_state": "4-f", + "blend_mode": "overlay", + "color_ids": [ 1 ] + } + ] +} diff --git a/code/datums/mergers/_merger.dm b/code/datums/mergers/_merger.dm new file mode 100644 index 00000000000..886117e8fa9 --- /dev/null +++ b/code/datums/mergers/_merger.dm @@ -0,0 +1,132 @@ +#define MERGERS_DEBUG FALSE + +/// A datum that tracks a type or types of objects in a cluster +/datum/merger + /// The unique ID for this merger datum, adjacent merg groups with the same id will combine + var/id + /// The types allowed to be in this merge group + var/list/merged_typecache + /// Optional proc to call on potential members, return true to allow merge + var/attempt_merge_proc + + /// The arbitrary "owner" member of the merge group + var/atom/origin + /// A list of all members in the group + var/list/members = list() + +#if MERGERS_DEBUG + var/debug_color +#endif + + /// Signals in members to trigger a refresh + var/static/list/refresh_signals = list( + COMSIG_PARENT_QDELETING, + COMSIG_MOVABLE_MOVED, + ) + +/datum/merger/New(id, list/merged_typecache, atom/origin, attempt_merge_proc) +#if MERGERS_DEBUG + debug_color = rgb(rand(0, 255), rand(0, 255), rand(0, 255)) +#endif + src.id = id + src.merged_typecache = merged_typecache + src.origin = origin + src.attempt_merge_proc = attempt_merge_proc + Refresh() + +/datum/merger/Destroy(force, ...) + for(var/atom/thing as anything in members) + RemoveMember(thing) + return ..() + +/datum/merger/proc/RemoveMember(atom/thing, clean=TRUE) + SEND_SIGNAL(thing, COMSIG_MERGER_REMOVING, src) + UnregisterSignal(thing, refresh_signals) + if(!thing.mergers) + return + thing.mergers -= id + if(clean && !length(thing.mergers)) + thing.mergers = null + members -= thing + if(origin == thing && length(members)) + origin = pick(members) + +/datum/merger/proc/AddMember(atom/thing, connected_dir) + SEND_SIGNAL(thing, COMSIG_MERGER_ADDING, src) + RegisterSignal(thing, refresh_signals, .proc/QueueRefresh) + if(!thing.mergers) + thing.mergers = list() + else if(thing.mergers[id]) + var/datum/merger/other_merger = thing.mergers[id] + other_merger.RemoveMember(thing) + if(!thing.mergers) + thing.mergers = list() + + thing.mergers[id] = src + members[thing] = connected_dir + if(!origin) + origin = thing + +#if MERGERS_DEBUG + thing.add_atom_colour(debug_color, ADMIN_COLOUR_PRIORITY) + if(SSatoms.initialized != INITIALIZATION_INNEW_MAPLOAD) + sleep(1 SECONDS) +#endif + +/datum/merger/proc/QueueRefresh() + SIGNAL_HANDLER + addtimer(CALLBACK(src, .proc/Refresh), 1, TIMER_UNIQUE) + +/datum/merger/proc/Refresh() + var/list/tips = list() + tips[origin] = NORTH|EAST|SOUTH|WEST + var/list/checked_turfs = list() + var/list/new_members = list() + new_members[origin] = NONE + while(length(tips)) + var/atom/focus = tips[length(tips)] + var/dirs_to_check = tips[focus] + tips.len-- + for(var/dir in GLOB.cardinals) + if(!(dirs_to_check & dir)) + continue + var/turf/location = get_step(focus, dir) + if(!location || checked_turfs[location]) + continue + checked_turfs[location] = TRUE + for(var/i in location) + var/atom/movable/thing = i + if(!merged_typecache[thing.type]) + continue + if(attempt_merge_proc && !call(thing, attempt_merge_proc)(src, new_members)) + continue + if(thing.mergers && thing.mergers[id] != src) + var/datum/merger/existing = thing.mergers[id] + qdel(src) + existing.Refresh() + return + new_members[focus] |= dir // This is not a list, value of the members list is a bitfield of dirs + var/next_dirs = turn(dir, 180) + new_members[thing] |= next_dirs + next_dirs = ~next_dirs + var/existing = tips[thing] || (NORTH|EAST|SOUTH|WEST) + tips[thing] = existing & next_dirs + + var/list/leaving_members = members - new_members + for(var/atom/thing as anything in leaving_members) + RemoveMember(thing) + + var/list/joining_members = new_members - members + for(var/atom/thing as anything in joining_members) + AddMember(thing, joining_members[thing]) + + // They may not need a full update but the connected dirs could change + for(var/atom/thing as anything in new_members) + members[thing] = new_members[thing] + + SEND_SIGNAL(src, COMSIG_MERGER_REFRESH_COMPLETE, leaving_members, joining_members) + + if(!length(members)) + qdel(src) + +#undef MERGERS_DEBUG diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 050062834dd..1eb18d956a8 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -83,7 +83,7 @@ ///The custom materials this atom is made of, used by a lot of things like furniture, walls, and floors (if I finish the functionality, that is.) ///The list referenced by this var can be shared by multiple objects and should not be directly modified. Instead, use [set_custom_materials][/atom/proc/set_custom_materials]. - var/list/custom_materials + var/list/datum/material/custom_materials ///Bitfield for how the atom handles materials. var/material_flags = NONE ///Modifier that raises/lowers the effect of the amount of a material, prevents small and easy to get items from being death machines. @@ -133,6 +133,9 @@ ///A string of hex format colors to be used by greyscale sprites, ex: "#0054aa#badcff" var/greyscale_colors + ///Holds merger groups currently active on the atom. Do not access directly, use GetMergeGroup() instead. + var/list/datum/merger/mergers + ///Icon-smoothing behavior. var/smoothing_flags = NONE ///What directions this is currently smoothing with. IMPORTANT: This uses the smoothing direction flags as defined in icon_smoothing.dm, instead of the BYOND flags. @@ -748,6 +751,10 @@ SHOULD_CALL_PARENT(TRUE) if(greyscale_colors && greyscale_config) icon = SSgreyscale.GetColoredIconByType(greyscale_config, greyscale_colors) + if(!smoothing_flags) // This is a bitfield but we're just checking that some sort of smoothing is happening + return + update_atom_colour() + QUEUE_SMOOTH(src) /** * An atom we are buckled or is contained within us has tried to move @@ -2071,3 +2078,14 @@ usr.hud_used.screentip_text.maptext = "" else usr.hud_used.screentip_text.maptext = MAPTEXT("[name]") + +/// Gets a merger datum representing the connected blob of objects in the allowed_types argument +/atom/proc/GetMergeGroup(id, list/allowed_types) + RETURN_TYPE(/datum/merger) + var/datum/merger/candidate + if(mergers) + candidate = mergers[id] + if(!candidate) + new /datum/merger(id, allowed_types, src) + candidate = mergers[id] + return candidate diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm index 9a6767b5b22..866e4df27fd 100644 --- a/code/game/objects/items/stacks/sheets/sheet_types.dm +++ b/code/game/objects/items/stacks/sheets/sheet_types.dm @@ -174,12 +174,13 @@ GLOBAL_LIST_INIT(metal_recipes, list ( \ * Plasteel */ GLOBAL_LIST_INIT(plasteel_recipes, list ( \ - new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 50, one_per_turf = TRUE), \ - new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 50), \ - null, \ + new/datum/stack_recipe("AI core", /obj/structure/ai_core, 4, time = 50, one_per_turf = TRUE), + new/datum/stack_recipe("bomb assembly", /obj/machinery/syndicatebomb/empty, 10, time = 50), + new/datum/stack_recipe("Large Gas Tank", /obj/structure/tank_frame, 4, time=1 SECONDS, one_per_turf=TRUE), + null, new /datum/stack_recipe_list("airlock assemblies", list( \ - new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1), \ - new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 50, one_per_turf = 1, on_floor = 1), \ + new/datum/stack_recipe("high security airlock assembly", /obj/structure/door_assembly/door_assembly_highsecurity, 4, time = 50, one_per_turf = 1, on_floor = 1), + new/datum/stack_recipe("vault door assembly", /obj/structure/door_assembly/door_assembly_vault, 6, time = 50, one_per_turf = 1, on_floor = 1), )), \ )) diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 619321e1274..f1479ddc04d 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -41,11 +41,12 @@ /// Handles the integrity of an object changing. This must be called instead of changing integrity directly. /obj/proc/update_integrity(new_value) SHOULD_NOT_OVERRIDE(TRUE) + var/old_value = obj_integrity new_value = max(0, new_value) if(obj_integrity == new_value) return obj_integrity = new_value - SEND_SIGNAL(src, COMSIG_OBJ_INTEGRITY_CHANGED) + SEND_SIGNAL(src, COMSIG_OBJ_INTEGRITY_CHANGED, old_value, new_value) /// This mostly exists to keep obj_integrity private. Might be useful in the future. /obj/proc/get_integrity() diff --git a/code/modules/admin/greyscale_modify_menu.dm b/code/modules/admin/greyscale_modify_menu.dm index 0ccc5c4bc54..5f33ceec206 100644 --- a/code/modules/admin/greyscale_modify_menu.dm +++ b/code/modules/admin/greyscale_modify_menu.dm @@ -127,12 +127,16 @@ if("recolor") var/index = text2num(params["color_index"]) - split_colors[index] = lowertext(params["new_color"]) - queue_refresh() + var/new_color = lowertext(params["new_color"]) + if(split_colors[index] != new_color) + split_colors[index] = new_color + queue_refresh() if("recolor_from_string") - ReadColorsFromString(lowertext(params["color_string"])) - queue_refresh() + var/full_color_string = lowertext(params["color_string"]) + if(full_color_string != split_colors.Join()) + ReadColorsFromString(full_color_string) + queue_refresh() if("pick_color") var/group = params["color_index"] diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index 4b25fd19efa..3df7d399fd6 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -25,7 +25,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( /obj/machinery/atmospherics/pipe/heat_exchanging/junction, /obj/machinery/atmospherics/pipe/heat_exchanging/manifold, /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w, - /obj/machinery/atmospherics/components/unary/tank, + /obj/machinery/atmospherics/components/tank, /obj/machinery/atmospherics/components/unary/portables_connector, /obj/machinery/atmospherics/components/unary/passive_vent, /obj/machinery/atmospherics/components/unary/heat_exchanger, diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 88988491cc9..a0089338244 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -135,13 +135,16 @@ var/list/node_connects = list() node_connects.len = device_type + var/init_directions = GetInitDirections() for(var/i in 1 to device_type) - for(var/D in GLOB.cardinals) - if(D & GetInitDirections()) - if(D in node_connects) - continue - node_connects[i] = D - break + for(var/direction in GLOB.cardinals) + if(!(direction & init_directions)) + continue + if(direction in node_connects) + continue + node_connects[i] = direction + break + return node_connects /** diff --git a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm index ad2fd531cb6..4651447d833 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/valve.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/valve.dm @@ -14,6 +14,7 @@ It's like a regular ol' straight pipe, but you can turn it on and off. pipe_flags = PIPING_CARDINAL_AUTONORMALIZE | PIPING_BRIDGE construction_type = /obj/item/pipe/binary pipe_state = "mvalve" + custom_reconcilation = TRUE ///Type of valve (manual or digital), used to set the icon of the component in update_icon_nopipes() var/valve_type = MANUAL_VALVE ///Bool to stop interactions while the opening/closing animation is going @@ -47,6 +48,15 @@ It's like a regular ol' straight pipe, but you can turn it on and off. vent_movement &= ~VENTCRAWL_ALLOWED +// This is what handles the actual functionality of combining 2 pipenets when the valve is open +// Basically when a pipenet updates it will consider both sides to be the same for the purpose of the gas update +/obj/machinery/atmospherics/components/binary/valve/returnPipenetsForReconcilation(datum/pipeline/requester) + . = ..() + if(!on) + return + . += parents[1] + . += parents[2] + /obj/machinery/atmospherics/components/binary/valve/interact(mob/user) add_fingerprint(usr) if(switching) diff --git a/code/modules/atmospherics/machinery/components/components_base.dm b/code/modules/atmospherics/machinery/components/components_base.dm index 153f49b5099..d63353ad7a5 100644 --- a/code/modules/atmospherics/machinery/components/components_base.dm +++ b/code/modules/atmospherics/machinery/components/components_base.dm @@ -13,6 +13,8 @@ var/list/datum/pipeline/parents ///Stores the component gas mixture var/list/datum/gas_mixture/airs + ///Handles whether the custom reconcilation handling should be used + var/custom_reconcilation = FALSE /obj/machinery/atmospherics/components/New() parents = new(device_type) @@ -21,6 +23,8 @@ ..() for(var/i in 1 to device_type) + if(airs[i]) + continue var/datum/gas_mixture/A = new A.volume = 200 airs[i] = A @@ -193,6 +197,8 @@ * This way gases won't get stuck */ /obj/machinery/atmospherics/components/proc/update_parents() + if(!SSair.initialized) + return for(var/i in 1 to device_type) var/datum/pipeline/parent = parents[i] if(!parent) @@ -206,6 +212,16 @@ for(var/i in 1 to device_type) . += returnPipenet(nodes[i]) +/// When this machine is in a pipenet that is reconciling airs, this proc can add pipelines to the calculation. +/// Can be either a list of pipenets or a single pipenet. +/obj/machinery/atmospherics/components/proc/returnPipenetsForReconcilation(datum/pipeline/requester) + return list() + +/// When this machine is in a pipenet that is reconciling airs, this proc can add airs to the calculation. +/// Can be either a list of airs or a single air mix. +/obj/machinery/atmospherics/components/proc/returnAirsForReconcilation(datum/pipeline/requester) + return list() + // UI Stuff /obj/machinery/atmospherics/components/ui_status(mob/user) diff --git a/code/modules/atmospherics/machinery/components/tank.dm b/code/modules/atmospherics/machinery/components/tank.dm new file mode 100644 index 00000000000..bb3f9f5119a --- /dev/null +++ b/code/modules/atmospherics/machinery/components/tank.dm @@ -0,0 +1,545 @@ +/obj/machinery/atmospherics/components/tank + icon = 'icons/obj/atmospherics/stationary_canisters.dmi' + icon_state = "smooth" + + name = "pressure tank" + desc = "A large vessel containing pressurized gas." + + max_integrity = 800 + integrity_failure = 0.2 + density = TRUE + layer = ABOVE_WINDOW_LAYER + + custom_materials = list(/datum/material/alloy/plasteel=4000, /datum/material/iron=20000) + material_flags = MATERIAL_GREYSCALE | MATERIAL_ADD_PREFIX | MATERIAL_AFFECT_STATISTICS + + pipe_flags = PIPING_ONE_PER_TURF + device_type = QUATERNARY + initialize_directions = NONE + custom_reconcilation = TRUE + + smoothing_flags = SMOOTH_CORNERS | SMOOTH_OBJ + smoothing_groups = list(SMOOTH_GROUP_GAS_TANK) + canSmoothWith = list(SMOOTH_GROUP_GAS_TANK) + appearance_flags = KEEP_TOGETHER + + greyscale_config = /datum/greyscale_config/stationary_canister + greyscale_colors = "#ffffff" + + var/image/window + + /// The volume of the gas mixture + var/volume = 2500 //in liters + /// The max pressure of the gas mixture before damaging the tank + var/max_pressure = 20000 + /// The typepath of the gas this tank should be filled with. + var/gas_type = null + + var/datum/gas_mixture/air_contents + + /// The sounds that play when the tank is breaking from overpressure + var/static/list/breaking_sounds = list( + 'sound/effects/structure_stress/pop1.ogg', + 'sound/effects/structure_stress/pop2.ogg', + 'sound/effects/structure_stress/pop3.ogg', + ) + + /// Shared images for the knob overlay representing a side of the tank that is open to connections + var/static/list/knob_overlays + + /// Number of crack states to fill the list with. This exists because I'm lazy and didn't want to keeping adding more things manually to the below list. + var/crack_states_count = 10 + /// The icon states for the cracks in the tank dmi + var/static/list/crack_states + + /// The merger id used to create/get the merger group in charge of handling tanks that share an internal gas storage + var/merger_id = "stationary_tanks" + /// The typecache of types which are allowed to merge internal storage + var/static/list/merger_typecache + +/obj/machinery/atmospherics/components/tank/Initialize() + . = ..() + + if(!knob_overlays) + knob_overlays = list() + for(var/dir in GLOB.cardinals) + knob_overlays["[dir]"] = image('icons/obj/atmospherics/stationary_canisters.dmi', icon_state="knob", dir=dir, layer=FLOAT_LAYER) + + if(!crack_states) + crack_states = list() + for(var/i in 1 to crack_states_count) + crack_states += "crack[i]" + + if(!merger_typecache) + merger_typecache = typecacheof(/obj/machinery/atmospherics/components/tank) + + AddComponent(/datum/component/gas_leaker, leak_rate=0.05) + AddElement(/datum/element/volatile_gas_storage) + AddElement(/datum/element/crackable, 'icons/obj/atmospherics/stationary_canisters.dmi', crack_states) + + RegisterSignal(src, COMSIG_MERGER_ADDING, .proc/MergerAdding) + RegisterSignal(src, COMSIG_MERGER_REMOVING, .proc/MergerRemoving) + RegisterSignal(src, COMSIG_ATOM_SMOOTHED_ICON, .proc/Smoothed) + + air_contents = new + air_contents.temperature = T20C + air_contents.volume = volume + RefreshPressureLimit() + + if(gas_type) + FillToPressure(gas_type) + + setPipingLayer(piping_layer) + QUEUE_SMOOTH(src) + QUEUE_SMOOTH_NEIGHBORS(src) + + return INITIALIZE_HINT_LATELOAD + +// We late initialize here so all stationary tanks have time to set up their +// initial gas mixes and signal registrations. +/obj/machinery/atmospherics/components/tank/LateInitialize() + . = ..() + GetMergeGroup(merger_id, merger_typecache) + +/obj/machinery/atmospherics/components/tank/Destroy() + QUEUE_SMOOTH_NEIGHBORS(src) + return ..() + +/obj/machinery/atmospherics/components/tank/examine(mob/user, thats) + . = ..() + var/wrench_hint = EXAMINE_HINT("wrench") + if(!initialize_directions) + . += "A pipe port can be opened with a [wrench_hint]." + else + . += "The pipe port can be moved or closed with a [wrench_hint]." + +/obj/machinery/atmospherics/components/tank/set_custom_materials(list/materials, multiplier) + . = ..() + RefreshPressureLimit() + +/// Recalculates pressure based on the current max integrity compared to original +/obj/machinery/atmospherics/components/tank/proc/RefreshPressureLimit() + var/max_pressure_multiplier = max_integrity / initial(max_integrity) + max_pressure = max_pressure_multiplier * initial(max_pressure) + +/// Fills the tank to the maximum safe pressure. +/// Safety margin is a multiplier for the cap for the purpose of this proc so it doesn't have to be filled completely. +/obj/machinery/atmospherics/components/tank/proc/FillToPressure(gastype, safety_margin=0.5) + var/pressure_limit = max_pressure * safety_margin + + var/moles_to_add = (pressure_limit * air_contents.volume) / (R_IDEAL_GAS_EQUATION * air_contents.temperature) + air_contents.assert_gas(gastype) + air_contents.gases[gastype][MOLES] += moles_to_add + air_contents.archive() + update_parents() + +/obj/machinery/atmospherics/components/tank/process_atmos() + if(air_contents.react(src)) + update_parents() + + if(air_contents.return_pressure() > max_pressure) + take_damage(0.1, BRUTE, sound_effect=FALSE) + if(prob(40)) + playsound(src, pick(breaking_sounds), 30, vary=TRUE) + + RefreshWindow() + +/////////////////////////////////////////////////////////////////// +// Pipenet stuff + +/obj/machinery/atmospherics/components/tank/returnAirsForReconcilation(datum/pipeline/requester) + . = ..() + if(!air_contents) + return + . += air_contents + +/obj/machinery/atmospherics/components/tank/returnPipenetsForReconcilation(datum/pipeline/requester) + . = ..() + var/datum/merger/merge_group = GetMergeGroup(merger_id, merger_typecache) + for(var/obj/machinery/atmospherics/components/tank/tank as anything in merge_group.members) + . += tank.parents + +/obj/machinery/atmospherics/components/tank/proc/ToggleSidePort(new_dir) + if(initialize_directions & new_dir) + initialize_directions &= ~new_dir + else + initialize_directions |= new_dir + + for(var/i in 1 to length(nodes)) + var/obj/machinery/atmospherics/components/node = nodes[i] + if(!node) + continue + if(src in node.nodes) + node.disconnect(src) + nodes[i] = null + if(parents[i]) + nullifyPipenet(parents[i]) + + atmosinit() + + for(var/obj/machinery/atmospherics/components/node as anything in nodes) + if(!node) + continue + node.atmosinit() + node.addMember(src) + SSair.add_to_rebuild_queue(src) + + update_parents() + +/////////////////////////////////////////////////////////////////// +// Merger handling + +/obj/machinery/atmospherics/components/tank/proc/MergerAdding(obj/machinery/atmospherics/components/tank/us, datum/merger/new_merger) + SIGNAL_HANDLER + if(new_merger.id != merger_id) + return + RegisterSignal(new_merger, COMSIG_MERGER_REFRESH_COMPLETE, .proc/MergerRefreshComplete) + +/obj/machinery/atmospherics/components/tank/proc/MergerRemoving(obj/machinery/atmospherics/components/tank/us, datum/merger/old_merger) + SIGNAL_HANDLER + if(old_merger.id != merger_id) + return + UnregisterSignal(old_merger, COMSIG_MERGER_REFRESH_COMPLETE) + +/// Handles the combined gas tank for the entire merger group, only the origin tank actualy runs this. +/obj/machinery/atmospherics/components/tank/proc/MergerRefreshComplete(datum/merger/merger, list/leaving_members, list/joining_members) + SIGNAL_HANDLER + if(merger.origin != src) + return + var/shares = length(merger.members) + length(leaving_members) - length(joining_members) + for(var/obj/machinery/atmospherics/components/tank/leaver as anything in leaving_members) + var/datum/gas_mixture/gas_share = air_contents.remove_ratio(1/shares--) + air_contents.volume -= leaver.volume + leaver.air_contents = gas_share + leaver.update_appearance() + + for(var/obj/machinery/atmospherics/components/tank/joiner as anything in joining_members) + var/datum/gas_mixture/joiner_share = joiner.air_contents + if(joiner_share) + air_contents.merge(joiner_share) + joiner.air_contents = air_contents + air_contents.volume += joiner.volume + joiner.update_appearance() + + for(var/dir in GLOB.cardinals) + if(dir & initialize_directions & merger.members[src]) + ToggleSidePort(dir) + + update_parents() + +/////////////////////////////////////////////////////////////////// +// Appearance stuff + +/obj/machinery/atmospherics/components/tank/proc/Smoothed() + SIGNAL_HANDLER + RefreshWindow() + +/obj/machinery/atmospherics/components/tank/update_appearance() + . = ..() + RefreshWindow() + +/obj/machinery/atmospherics/components/tank/update_overlays() + . = ..() + if(!initialize_directions) + return + for(var/dir in GLOB.cardinals) + if(initialize_directions & dir) + . += knob_overlays["[dir]"] + +/obj/machinery/atmospherics/components/tank/update_greyscale() + . = ..() + RefreshWindow() + +/obj/machinery/atmospherics/components/tank/proc/RefreshWindow() + cut_overlay(window) + + if(!air_contents) + window = null + return + + window = image(icon, icon_state="window-bg", layer=FLOAT_LAYER) + + var/list/new_underlays = list() + for(var/obj/effect/overlay/gas/gas as anything in air_contents.return_visuals()) + var/image/new_underlay = image(gas.icon, icon_state=gas.icon_state, layer=FLOAT_LAYER) + new_underlay.filters = alpha_mask_filter(icon=icon(icon, icon_state="window-bg")) + new_underlays += new_underlay + + var/image/foreground = image(icon, icon_state="window-fg", layer=FLOAT_LAYER) + foreground.underlays = new_underlays + window.overlays = list(foreground) + + add_overlay(window) + +/////////////////////////////////////////////////////////////////// +// Tool interactions + +/obj/machinery/atmospherics/components/tank/wrench_act(mob/living/user, obj/item/item) + . = TRUE + var/new_dir = get_dir(src, user) + + if(new_dir in GLOB.diagonals) + return + + item.play_tool_sound(src, 10) + if(!item.use_tool(src, user, 3 SECONDS)) + return + + ToggleSidePort(new_dir) + + item.play_tool_sound(src, 50) + +/obj/machinery/atmospherics/components/tank/welder_act(mob/living/user, obj/item/tool) + . = ..() + . = TRUE + if(obj_integrity >= max_integrity) + return + if(!tool.tool_start_check(user, amount=0)) + return + to_chat(user, "You begin to repair the cracks in the gas tank...") + var/repair_amount = max_integrity / 10 + do + if(!tool.use_tool(src, user, 2.5 SECONDS, volume=40)) + return + while(repair_damage(repair_amount)) + to_chat(user, "The gas tank has been fully repaired and all cracks sealed.") + +/obj/machinery/atmospherics/components/tank/welder_act_secondary(mob/living/user, obj/item/tool) + . = ..() + . = TRUE + to_chat(user, "You begin cutting open the gas tank...") + var/turf/current_location = get_turf(src) + var/datum/gas_mixture/airmix = current_location.return_air() + + var/time_taken = 4 SECONDS + + if(air_contents.return_pressure() > airmix.return_pressure()) + time_taken *= 2 + to_chat(user, "The tank seems to be pressurized, are you sure this is a good idea?") + + if(!tool.use_tool(src, user, time_taken, volume=60)) + return + + deconstruct(disassembled=TRUE) + to_chat(user, "You finish cutting open the sealed gas tank, revealing the innards.") + +/obj/machinery/atmospherics/components/tank/deconstruct(disassembled) + var/turf/location = drop_location() + . = ..() + if(!disassembled) + return + var/obj/structure/tank_frame/frame = new(location) + frame.construction_state = TANK_PLATING_UNSECURED + frame.material_end_product = custom_materials[2].type + frame.update_appearance() + +/////////////////////////////////////////////////////////////////// +// Gas tank variants + +/obj/machinery/atmospherics/components/tank/air + name = "pressure tank (Air)" + +/obj/machinery/atmospherics/components/tank/air/Initialize() + . = ..() + FillToPressure(/datum/gas/oxygen, safety_margin=0.1) + FillToPressure(/datum/gas/nitrogen, safety_margin=0.5) + +/obj/machinery/atmospherics/components/tank/carbon_dioxide + gas_type = /datum/gas/carbon_dioxide + +/obj/machinery/atmospherics/components/tank/toxins + gas_type = /datum/gas/plasma + +/obj/machinery/atmospherics/components/tank/nitrogen + gas_type = /datum/gas/nitrogen + +/obj/machinery/atmospherics/components/tank/oxygen + gas_type = /datum/gas/oxygen + +/obj/machinery/atmospherics/components/tank/nitrous + gas_type = /datum/gas/nitrous_oxide + +/obj/machinery/atmospherics/components/tank/bz + gas_type = /datum/gas/bz + +/obj/machinery/atmospherics/components/tank/freon + gas_type = /datum/gas/freon + +/obj/machinery/atmospherics/components/tank/halon + gas_type = /datum/gas/halon + +/obj/machinery/atmospherics/components/tank/healium + gas_type = /datum/gas/healium + +/obj/machinery/atmospherics/components/tank/hydrogen + gas_type = /datum/gas/hydrogen + +/obj/machinery/atmospherics/components/tank/hypernoblium + gas_type = /datum/gas/hypernoblium + +/obj/machinery/atmospherics/components/tank/miasma + gas_type = /datum/gas/miasma + +/obj/machinery/atmospherics/components/tank/nitryl + gas_type = /datum/gas/nitryl + +/obj/machinery/atmospherics/components/tank/pluoxium + gas_type = /datum/gas/pluoxium + +/obj/machinery/atmospherics/components/tank/proto_nitrate + gas_type = /datum/gas/proto_nitrate + +/obj/machinery/atmospherics/components/tank/stimulum + gas_type = /datum/gas/stimulum + +/obj/machinery/atmospherics/components/tank/tritium + gas_type = /datum/gas/tritium + +/obj/machinery/atmospherics/components/tank/water_vapor + gas_type = /datum/gas/water_vapor + +/obj/machinery/atmospherics/components/tank/zauker + gas_type = /datum/gas/zauker + +/obj/machinery/atmospherics/components/tank/helium + gas_type = /datum/gas/helium + +/obj/machinery/atmospherics/components/tank/antinoblium + gas_type = /datum/gas/antinoblium + +/////////////////////////////////////////////////////////////////// +// Tank Frame Structure + +/obj/structure/tank_frame + icon = 'icons/obj/atmospherics/stationary_canisters.dmi' + icon_state = "frame" + anchored = FALSE + density = TRUE + custom_materials = list(/datum/material/alloy/plasteel=4000) + var/construction_state = TANK_FRAME + var/datum/material/material_end_product + +/obj/structure/tank_frame/examine(mob/user) + . = ..() + var/wrenched_hint = EXAMINE_HINT("wrenched") + + if(!anchored) + . += "[src] has not been [wrenched_hint] to the floor yet." + else + . += "[src] is [wrenched_hint] to the floor." + + switch(construction_state) + if(TANK_FRAME) + var/screwed_hint = EXAMINE_HINT("screwed") + var/plating_hint = EXAMINE_HINT("metal plating") + . += "[src] is [screwed_hint] together and now just needs some [plating_hint]." + if(TANK_PLATING_UNSECURED) + var/crowbar_hint = EXAMINE_HINT("crowbar") + var/welder_hint = EXAMINE_HINT("welder") + . += "The plating has been firmly attached and would need a [crowbar_hint] to detach, but still needs to be sealed by a [welder_hint]." + +/obj/structure/tank_frame/deconstruct(disassembled) + if(disassembled) + for(var/datum/material/mat as anything in custom_materials) + new mat.sheet_type(drop_location()) + return ..() + +/obj/structure/tank_frame/update_icon(updates) + . = ..() + switch(construction_state) + if(TANK_FRAME) + icon_state = "frame" + if(TANK_PLATING_UNSECURED) + icon_state = "plated_frame" + +/obj/structure/tank_frame/attackby(obj/item/item, mob/living/user, params) + if(construction_state == TANK_FRAME && istype(item, /obj/item/stack) && add_plating(user, item)) + return + return ..() + +/obj/structure/tank_frame/wrench_act(mob/living/user, obj/item/tool) + . = ..() + return default_unfasten_wrench(user, tool, 0.5 SECONDS) + +/obj/structure/tank_frame/screwdriver_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(construction_state != TANK_FRAME) + return + . = TRUE + to_chat(user, "You begin taking apart [src].") + if(!tool.use_tool(src, user, 1 SECONDS)) + return + deconstruct(TRUE) + to_chat(user, "[src] has been taken apart.") + +/obj/structure/tank_frame/proc/add_plating(mob/living/user, obj/item/stack/stack) + . = FALSE + var/datum/material/stack_mat = GET_MATERIAL_REF(stack.material_type) + if(!(MAT_CATEGORY_RIGID in stack_mat.categories)) + to_chat(user, "This material doesn't seem rigid enough to hold the shape of a tank...") + return + + . = TRUE + to_chat(user, "You begin adding [stack] to [src]...") + if(!stack.use_tool(src, user, 3 SECONDS)) + return + if(!stack.use(20)) + var/amount_more + switch(stack.amount) + if(0) // Wat? + amount_more = "any at all" + if(1 to 4) + amount_more = "a lot more" + if(5 to 9) + amount_more = "about four times as much" + if(10 to 15) + amount_more = "about twice as much" + if(16 to 20) + amount_more = "just a bit more" + else + amount_more = "an indeterminate amount more" + to_chat(user, "You don't have enough [stack] to add all the plating. Maybe [amount_more].") + return + + material_end_product = stack_mat + construction_state = TANK_PLATING_UNSECURED + update_appearance() + to_chat(user, "You finish attaching [stack] to [src].") + +/obj/structure/tank_frame/crowbar_act_secondary(mob/living/user, obj/item/tool) + . = ..() + if(construction_state != TANK_PLATING_UNSECURED) + return + . = TRUE + to_chat(user, "You start prying off the outer plating...") + if(!tool.use_tool(src, user, 2 SECONDS)) + return + construction_state = TANK_FRAME + new material_end_product.sheet_type(drop_location(), 20) + material_end_product = null + update_appearance() + +/obj/structure/tank_frame/welder_act(mob/living/user, obj/item/tool) + . = ..() + if(construction_state != TANK_PLATING_UNSECURED) + return + . = TRUE + if(!anchored) + to_chat(user, "You need to wrench [src] to the floor before finishing.") + return + if(!tool.tool_start_check(user, amount=0)) + return + to_chat(user, "You begin sealing the outer plating with the welder...") + if(!tool.use_tool(src, user, 2 SECONDS, volume=60)) + return + + var/turf/build_location = drop_location() + if(!isturf(build_location)) + return + var/obj/machinery/atmospherics/components/tank/new_tank = new(build_location) + var/list/new_custom_materials = list() + new_custom_materials[/datum/material/alloy/plasteel] = 4000 + new_custom_materials[material_end_product] = 20000 + new_tank.set_custom_materials(new_custom_materials) + to_chat(user, "[new_tank] has been sealed and is ready to accept gases.") + qdel(src) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm index d4673b5a659..7165f0602ed 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/portables_connector.dm @@ -13,6 +13,7 @@ pipe_flags = PIPING_ONE_PER_TURF pipe_state = "connector" + custom_reconcilation = TRUE var/obj/machinery/portable_atmospherics/connected_device @@ -38,6 +39,12 @@ return update_parents() +/obj/machinery/atmospherics/components/unary/portables_connector/returnAirsForReconcilation(datum/pipeline/requester) + . = ..() + if(!connected_device) + return + . += connected_device.return_air() + /obj/machinery/atmospherics/components/unary/portables_connector/can_unwrench(mob/user) . = ..() if(. && connected_device) diff --git a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm b/code/modules/atmospherics/machinery/components/unary_devices/tank.dm deleted file mode 100644 index 7bc46e1433a..00000000000 --- a/code/modules/atmospherics/machinery/components/unary_devices/tank.dm +++ /dev/null @@ -1,115 +0,0 @@ -#define AIR_CONTENTS ((25*ONE_ATMOSPHERE)*(air_contents.volume)/(R_IDEAL_GAS_EQUATION*air_contents.temperature)) -/obj/machinery/atmospherics/components/unary/tank - icon = 'icons/obj/atmospherics/pipes/pressure_tank.dmi' - icon_state = "generic" - - name = "pressure tank" - desc = "A large vessel containing pressurized gas." - - max_integrity = 800 - density = TRUE - layer = ABOVE_WINDOW_LAYER - pipe_flags = PIPING_ONE_PER_TURF - - var/volume = 10000 //in liters - /// The typepath of the gas this tank should be filled with. - var/gas_type = null - -/obj/machinery/atmospherics/components/unary/tank/New() - ..() - var/datum/gas_mixture/air_contents = airs[1] - air_contents.volume = volume - air_contents.temperature = T20C - if(gas_type) - air_contents.assert_gas(gas_type) - air_contents.gases[gas_type][MOLES] = AIR_CONTENTS - name = "[name] ([air_contents.gases[gas_type][GAS_META][META_GAS_NAME]])" - setPipingLayer(piping_layer) - - -/obj/machinery/atmospherics/components/unary/tank/air - icon_state = "grey" - name = "pressure tank (Air)" - -/obj/machinery/atmospherics/components/unary/tank/air/New() - ..() - var/datum/gas_mixture/air_contents = airs[1] - air_contents.assert_gases(/datum/gas/oxygen, /datum/gas/nitrogen) - air_contents.gases[/datum/gas/oxygen][MOLES] = AIR_CONTENTS * 0.2 - air_contents.gases[/datum/gas/nitrogen][MOLES] = AIR_CONTENTS * 0.8 - -/obj/machinery/atmospherics/components/unary/tank/carbon_dioxide - gas_type = /datum/gas/carbon_dioxide - -/obj/machinery/atmospherics/components/unary/tank/toxins - icon_state = "orange" - gas_type = /datum/gas/plasma - -/obj/machinery/atmospherics/components/unary/tank/nitrogen - icon_state = "red" - gas_type = /datum/gas/nitrogen - -/obj/machinery/atmospherics/components/unary/tank/oxygen - icon_state = "blue" - gas_type = /datum/gas/oxygen - -/obj/machinery/atmospherics/components/unary/tank/nitrous - icon_state = "red_white" - gas_type = /datum/gas/nitrous_oxide - -/obj/machinery/atmospherics/components/unary/tank/bz - gas_type = /datum/gas/bz - -/obj/machinery/atmospherics/components/unary/tank/freon - icon_state = "blue" - gas_type = /datum/gas/freon - -/obj/machinery/atmospherics/components/unary/tank/halon - icon_state = "blue" - gas_type = /datum/gas/halon - -/obj/machinery/atmospherics/components/unary/tank/healium - icon_state = "red" - gas_type = /datum/gas/healium - -/obj/machinery/atmospherics/components/unary/tank/hydrogen - icon_state = "grey" - gas_type = /datum/gas/hydrogen - -/obj/machinery/atmospherics/components/unary/tank/hypernoblium - icon_state = "blue" - gas_type = /datum/gas/hypernoblium - -/obj/machinery/atmospherics/components/unary/tank/miasma - gas_type = /datum/gas/miasma - -/obj/machinery/atmospherics/components/unary/tank/nitryl - gas_type = /datum/gas/nitryl - -/obj/machinery/atmospherics/components/unary/tank/pluoxium - icon_state = "blue" - gas_type = /datum/gas/pluoxium - -/obj/machinery/atmospherics/components/unary/tank/proto_nitrate - icon_state = "red" - gas_type = /datum/gas/proto_nitrate - -/obj/machinery/atmospherics/components/unary/tank/stimulum - icon_state = "red" - gas_type = /datum/gas/stimulum - -/obj/machinery/atmospherics/components/unary/tank/tritium - gas_type = /datum/gas/tritium - -/obj/machinery/atmospherics/components/unary/tank/water_vapor - icon_state = "grey" - gas_type = /datum/gas/water_vapor - -/obj/machinery/atmospherics/components/unary/tank/zauker - gas_type = /datum/gas/zauker - -/obj/machinery/atmospherics/components/unary/tank/helium - gas_type = /datum/gas/helium - -/obj/machinery/atmospherics/components/unary/tank/antinoblium - gas_type = /datum/gas/antinoblium diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index 06cd46f306e..73aa1c4bbc1 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -234,6 +234,7 @@ stack_trace("[src] has one or more null gas mixtures, which may cause bugs. Null mixtures will not be considered in reconcile_air().") return removeNullsFromList(.) +/// Called when the pipenet needs to update and mix together all the air mixes /datum/pipeline/proc/reconcile_air() var/list/datum/gas_mixture/gas_mixture_list = list() var/list/datum/pipeline/pipeline_list = list() @@ -245,16 +246,11 @@ continue gas_mixture_list += pipeline.other_airs gas_mixture_list += pipeline.air - for(var/atmosmch in pipeline.other_atmosmch) - if (istype(atmosmch, /obj/machinery/atmospherics/components/binary/valve)) - var/obj/machinery/atmospherics/components/binary/valve/considered_valve = atmosmch - if(considered_valve.on) - pipeline_list |= considered_valve.parents[1] - pipeline_list |= considered_valve.parents[2] - else if (istype(atmosmch, /obj/machinery/atmospherics/components/unary/portables_connector)) - var/obj/machinery/atmospherics/components/unary/portables_connector/considered_connector = atmosmch - if(considered_connector.connected_device) - gas_mixture_list += considered_connector.connected_device.return_air() + for(var/obj/machinery/atmospherics/components/atmosmch as anything in pipeline.other_atmosmch) + if(!atmosmch.custom_reconcilation) + continue + pipeline_list |= atmosmch.returnPipenetsForReconcilation(src) + gas_mixture_list |= atmosmch.returnAirsForReconcilation(src) var/total_thermal_energy = 0 var/total_heat_capacity = 0 @@ -262,8 +258,7 @@ var/list/total_gases = total_gas_mixture.gases - for(var/mixture in gas_mixture_list) - var/datum/gas_mixture/gas_mixture = mixture + for(var/datum/gas_mixture/gas_mixture as anything in gas_mixture_list) total_gas_mixture.volume += gas_mixture.volume // This is sort of a combined merge + heat_capacity calculation diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm index 35d1c9de866..7683fc9ab61 100644 --- a/code/modules/atmospherics/machinery/portable/canister.dm +++ b/code/modules/atmospherics/machinery/portable/canister.dm @@ -435,7 +435,7 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister()) window = image(icon, icon_state="window-base", layer=FLOAT_LAYER) var/list/window_overlays = list() for(var/visual in air_contents.return_visuals()) - var/image/new_visual = image(visual, layer=FLOAT_PLANE) + var/image/new_visual = image(visual, layer=FLOAT_LAYER) new_visual.filters = alpha_filter window_overlays += new_visual window.overlays = window_overlays diff --git a/icons/obj/atmospherics/pipes/pressure_tank.dmi b/icons/obj/atmospherics/pipes/pressure_tank.dmi deleted file mode 100644 index 95103015cfd67515e81ee259cbd72a0f2379b1f0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14599 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 DH%;Dp literal 0 HcmV?d00001 diff --git a/sound/effects/structure_stress/pop1.ogg b/sound/effects/structure_stress/pop1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..e5c3cc95f7bbb3a05f46e8bdb9dc8d3b0cb4e5a9 GIT binary patch literal 14694 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