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 95103015cfd..00000000000 Binary files a/icons/obj/atmospherics/pipes/pressure_tank.dmi and /dev/null differ diff --git a/icons/obj/atmospherics/stationary_canisters.dmi b/icons/obj/atmospherics/stationary_canisters.dmi new file mode 100644 index 00000000000..4f87a50845b Binary files /dev/null and b/icons/obj/atmospherics/stationary_canisters.dmi differ diff --git a/sound/effects/structure_stress/pop1.ogg b/sound/effects/structure_stress/pop1.ogg new file mode 100644 index 00000000000..e5c3cc95f7b Binary files /dev/null and b/sound/effects/structure_stress/pop1.ogg differ diff --git a/sound/effects/structure_stress/pop2.ogg b/sound/effects/structure_stress/pop2.ogg new file mode 100644 index 00000000000..2165a55e903 Binary files /dev/null and b/sound/effects/structure_stress/pop2.ogg differ diff --git a/sound/effects/structure_stress/pop3.ogg b/sound/effects/structure_stress/pop3.ogg new file mode 100644 index 00000000000..e441ab15441 Binary files /dev/null and b/sound/effects/structure_stress/pop3.ogg differ diff --git a/tgstation.dme b/tgstation.dme index 3767e461ada..dce2327ca33 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -534,6 +534,7 @@ #include "code\datums\components\chasm.dm" #include "code\datums\components\codeword_hearing.dm" #include "code\datums\components\construction.dm" +#include "code\datums\components\cracked.dm" #include "code\datums\components\creamed.dm" #include "code\datums\components\curse_of_hunger.dm" #include "code\datums\components\customizable_reagent_holder.dm" @@ -730,6 +731,7 @@ #include "code\datums\elements\cleaning.dm" #include "code\datums\elements\climbable.dm" #include "code\datums\elements\connect_loc.dm" +#include "code\datums\elements\crackable.dm" #include "code\datums\elements\curse_announcement.dm" #include "code\datums\elements\cursed.dm" #include "code\datums\elements\deferred_aquarium_content.dm" @@ -835,6 +837,7 @@ #include "code\datums\materials\hauntium.dm" #include "code\datums\materials\meat.dm" #include "code\datums\materials\pizza.dm" +#include "code\datums\mergers\_merger.dm" #include "code\datums\mocking\client.dm" #include "code\datums\mood_events\_mood_event.dm" #include "code\datums\mood_events\beauty_events.dm" @@ -1882,6 +1885,7 @@ #include "code\modules\atmospherics\machinery\bluespace_vendor.dm" #include "code\modules\atmospherics\machinery\datum_pipeline.dm" #include "code\modules\atmospherics\machinery\components\components_base.dm" +#include "code\modules\atmospherics\machinery\components\tank.dm" #include "code\modules\atmospherics\machinery\components\binary_devices\binary_devices.dm" #include "code\modules\atmospherics\machinery\components\binary_devices\circulator.dm" #include "code\modules\atmospherics\machinery\components\binary_devices\dp_vent_pump.dm" @@ -1910,7 +1914,6 @@ #include "code\modules\atmospherics\machinery\components\unary_devices\outlet_injector.dm" #include "code\modules\atmospherics\machinery\components\unary_devices\passive_vent.dm" #include "code\modules\atmospherics\machinery\components\unary_devices\portables_connector.dm" -#include "code\modules\atmospherics\machinery\components\unary_devices\tank.dm" #include "code\modules\atmospherics\machinery\components\unary_devices\unary_devices.dm" #include "code\modules\atmospherics\machinery\components\unary_devices\vent_pump.dm" #include "code\modules\atmospherics\machinery\components\unary_devices\vent_scrubber.dm"