diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index 488debb48e5..1de3f900c8c 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -452,7 +452,7 @@ SUBSYSTEM_DEF(air) border += item net.air.volume += item.volume - item.parent = net + item.replace_pipenet(item.parent, net) if(item.air_temporary) net.air.merge(item.air_temporary) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index c5b9813c554..600bc75a83d 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -230,6 +230,7 @@ GLOBAL_PROTECT(admin_verbs_debug) /client/proc/unload_ctf, /client/proc/validate_cards, /client/proc/validate_puzzgrids, + /client/proc/GeneratePipeSpritesheet, /client/proc/view_runtimes, ) GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release)) diff --git a/code/modules/atmospherics/gasmixtures/gas_types.dm b/code/modules/atmospherics/gasmixtures/gas_types.dm index ae3367ace59..060b5a12ae9 100644 --- a/code/modules/atmospherics/gasmixtures/gas_types.dm +++ b/code/modules/atmospherics/gasmixtures/gas_types.dm @@ -64,6 +64,8 @@ ///How does a single mole of this gas sell for? Formula to calculate maximum value is in code\modules\cargo\exports\large_objects.dm. Doesn't matter for roundstart gasses. var/base_value = 0 var/desc + ///RGB code for use when a generic color representing the gas is needed. Colors taken from contants.ts + var/primary_color /datum/gas/oxygen @@ -74,6 +76,7 @@ purchaseable = TRUE base_value = 0.2 desc = "The gas most life forms need to be able to survive. Also an oxidizer." + primary_color = "#0000ff" /datum/gas/nitrogen id = GAS_N2 @@ -83,6 +86,7 @@ purchaseable = TRUE base_value = 0.1 desc = "A very common gas that used to pad artifical atmospheres to habitable pressure." + primary_color = "#ffff00" /datum/gas/carbon_dioxide //what the fuck is this? id = GAS_CO2 @@ -93,6 +97,7 @@ purchaseable = TRUE base_value = 0.2 desc = "What the fuck is carbon dioxide?" + primary_color = "#808080" /datum/gas/plasma id = GAS_PLASMA @@ -104,6 +109,7 @@ rarity = 800 base_value = 1.5 desc = "A flammable gas with many other curious properties. It's research is one of NT's primary objective." + primary_color = "#ffc0cb" /datum/gas/water_vapor id = GAS_WATER_VAPOR @@ -116,6 +122,7 @@ purchaseable = TRUE base_value = 0.5 desc = "Water, in gas form. Makes things slippery." + primary_color = "#b0c4de" /datum/gas/hypernoblium id = GAS_HYPER_NOBLIUM @@ -127,6 +134,7 @@ rarity = 50 base_value = 2.5 desc = "The most noble gas of them all. High quantities of hyper-noblium actively prevents reactions from occuring." + primary_color = "#008080" /datum/gas/nitrous_oxide id = GAS_N2O @@ -140,6 +148,7 @@ purchaseable = TRUE base_value = 1.5 desc = "Causes drowsiness, euphoria, and eventually unconsciousness." + primary_color = "#ffe4c4" /datum/gas/nitrium id = GAS_NITRIUM @@ -152,6 +161,7 @@ rarity = 1 base_value = 6 desc = "An experimental performance enhancing gas. Nitrium can have amplified effects as more of it gets into your bloodstream." + primary_color = "#a52a2a" /datum/gas/tritium id = GAS_TRITIUM @@ -164,6 +174,7 @@ rarity = 300 base_value = 2.5 desc = "A highly flammable and radioctive gas." + primary_color = "#32cd32" /datum/gas/bz id = GAS_BZ @@ -175,6 +186,7 @@ purchaseable = TRUE base_value = 1.5 desc = "A powerful hallucinogenic nerve agent able to induce cognitive damage." + primary_color = "#9370db" /datum/gas/pluoxium id = GAS_PLUOXIUM @@ -184,6 +196,7 @@ rarity = 200 base_value = 2.5 desc = "A gas that could supply even more oxygen to the bloodstream when inhaled, without being an oxidizer." + primary_color = "#7b68ee" /datum/gas/miasma id = GAS_MIASMA @@ -195,6 +208,7 @@ rarity = 250 base_value = 1 desc = "Not necessarily a gas, miasma refers to biological pollutants found in the atmosphere." + primary_color = "#808000" /datum/gas/freon id = GAS_FREON @@ -207,6 +221,7 @@ rarity = 10 base_value = 5 desc = "A coolant gas. Mainly used for it's endothermic reaction with oxygen." + primary_color = "#afeeee" /datum/gas/hydrogen id = GAS_HYDROGEN @@ -217,6 +232,7 @@ rarity = 600 base_value = 1 desc = "A highly flammable gas." + primary_color = "#ffffff" /datum/gas/healium id = GAS_HEALIUM @@ -228,6 +244,7 @@ rarity = 300 base_value = 5.5 desc = "Causes deep, regenerative sleep." + primary_color = "#fa8072" /datum/gas/proto_nitrate id = GAS_PROTO_NITRATE @@ -239,6 +256,7 @@ rarity = 200 base_value = 2.5 desc = "A very volatile gas that reacts differently with various gases." + primary_color = "#adff2f" /datum/gas/zauker id = GAS_ZAUKER @@ -250,6 +268,7 @@ rarity = 1 base_value = 7 desc = "A highly toxic gas, it's production is highly regulated on top of being difficult. It also breaks down when in contact with nitrogen." + primary_color = "#006400" /datum/gas/halon id = GAS_HALON @@ -261,6 +280,7 @@ rarity = 300 base_value = 4 desc = "A potent fire supressant. Removes oxygen from high temperature fires and cools down the area" + primary_color = "#800080" /datum/gas/helium id = GAS_HELIUM @@ -270,6 +290,7 @@ rarity = 50 base_value = 3.5 desc = "A very inert gas produced by the fusion of hydrogen and it's derivatives." + primary_color = "#f0f8ff" /datum/gas/antinoblium id = GAS_ANTINOBLIUM @@ -282,6 +303,7 @@ rarity = 1 base_value = 10 desc = "We still don't know what it does, but it sells for a lot." + primary_color = "#800000" /obj/effect/overlay/gas icon = 'icons/effects/atmospherics.dmi' diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm index 417e5055de7..62c2b562d51 100644 --- a/code/modules/atmospherics/machinery/atmosmachinery.dm +++ b/code/modules/atmospherics/machinery/atmosmachinery.dm @@ -352,9 +352,9 @@ return /** - * Similar to set_pipenet() but instead of setting a network to a pipeline, it replaces the old pipeline with a new one, called by Merge() in datum_pipeline.dm + * Replaces the connection to the old_pipenet with the new_pipenet */ -/obj/machinery/atmospherics/proc/replace_pipenet() +/obj/machinery/atmospherics/proc/replace_pipenet(datum/pipeline/old_pipenet, datum/pipeline/new_pipenet) return /** diff --git a/code/modules/atmospherics/machinery/datum_pipeline.dm b/code/modules/atmospherics/machinery/datum_pipeline.dm index b8ad06e25ab..77a29b5461d 100644 --- a/code/modules/atmospherics/machinery/datum_pipeline.dm +++ b/code/modules/atmospherics/machinery/datum_pipeline.dm @@ -1,5 +1,7 @@ /datum/pipeline + /// The gases contained within this pipeline var/datum/gas_mixture/air + /// The gas_mixtures of objects directly connected to this pipeline var/list/datum/gas_mixture/other_airs var/list/obj/machinery/atmospherics/pipe/members @@ -8,6 +10,10 @@ /// We're essentially caching this to avoid needing to filter over it when processing our machines var/list/obj/machinery/atmospherics/components/require_custom_reconcilation + /// The weighted color blend of the gas mixture in this pipeline + var/gasmix_color + /// A named list of icon_file:overlay_object that gets automatically colored when the gasmix_color updates + var/list/gas_visuals ///Should we equalize air amoung all our members? var/update = TRUE @@ -19,6 +25,7 @@ members = list() other_atmos_machines = list() require_custom_reconcilation = list() + gas_visuals = list() SSair.networks += src /datum/pipeline/Destroy() @@ -28,7 +35,7 @@ if(air?.volume) temporarily_store_air() for(var/obj/machinery/atmospherics/pipe/considered_pipe in members) - considered_pipe.parent = null + considered_pipe.replace_pipenet(considered_pipe.parent, null) if(QDELETED(considered_pipe)) continue SSair.add_to_rebuild_queue(considered_pipe) @@ -42,6 +49,13 @@ reconcile_air() //Only react if the mix has changed, and don't keep updating if it hasn't update = air.react(src) + CalculateGasmixColor(air) + +/datum/pipeline/proc/set_air(datum/gas_mixture/new_air) + if(new_air == air) + return + air = new_air + CalculateGasmixColor(air) ///Preps a pipeline for rebuilding, insterts it into the rebuild queue /datum/pipeline/proc/build_pipeline(obj/machinery/atmospherics/base) @@ -52,13 +66,13 @@ volume = considered_pipe.volume members += considered_pipe if(considered_pipe.air_temporary) - air = considered_pipe.air_temporary + set_air(considered_pipe.air_temporary) considered_pipe.air_temporary = null else add_machinery_member(base) if(!air) - air = new + set_air(new /datum/gas_mixture) air.volume = volume SSair.add_to_expansion(src, base) @@ -71,13 +85,13 @@ volume = considered_pipe.volume members += considered_pipe if(considered_pipe.air_temporary) - air = considered_pipe.air_temporary + set_air(considered_pipe.air_temporary) considered_pipe.air_temporary = null else add_machinery_member(base) if(!air) - air = new + set_air(new /datum/gas_mixture) var/list/possible_expansions = list(base) while(possible_expansions.len) for(var/obj/machinery/atmospherics/borderline in possible_expansions) @@ -105,7 +119,7 @@ possible_expansions += item volume += item.volume - item.parent = src + item.replace_pipenet(item.parent, src) if(item.air_temporary) air.merge(item.air_temporary) @@ -142,7 +156,7 @@ var/obj/machinery/atmospherics/pipe/reference_pipe = reference_device if(reference_pipe.parent) merge(reference_pipe.parent) - reference_pipe.parent = src + reference_pipe.replace_pipenet(reference_pipe.parent, src) var/list/adjacent = reference_pipe.pipeline_expansion() for(var/obj/machinery/atmospherics/pipe/adjacent_pipe in adjacent) if(adjacent_pipe.parent == src) @@ -159,7 +173,7 @@ air.volume += parent_pipeline.air.volume members.Add(parent_pipeline.members) for(var/obj/machinery/atmospherics/pipe/reference_pipe in parent_pipeline.members) - reference_pipe.parent = src + reference_pipe.replace_pipenet(reference_pipe.parent, src) air.merge(parent_pipeline.air) for(var/obj/machinery/atmospherics/components/reference_component in parent_pipeline.other_atmos_machines) reference_component.replace_pipenet(parent_pipeline, src) @@ -280,3 +294,64 @@ //Update individual gas_mixtures by volume ratio for(var/datum/gas_mixture/gas_mixture as anything in gas_mixture_list) gas_mixture.copy_from_ratio(total_gas_mixture, gas_mixture.volume / volume_sum) + +//-------------------- +// GAS VISUALS STUFF +// +// If I could have gotten layer filters to obey the RESET_COLOR appearance flag I would have used that here +// so that only a single overlay object needs to exist for all pipelines per icon file. It shouldn't be too +// hard to switch over to that if it becomes possible in the future or some other equivalent feature is added. + +/** + * Used to create and/or get the gas visual overlay created using the given icon file. + * The color is automatically kept up to date and expected to be used as a vis_contents object. + */ +/datum/pipeline/proc/GetGasVisual(icon/icon_file) + if(gas_visuals[icon_file]) + return gas_visuals[icon_file] + + var/obj/effect/abstract/new_overlay = new + new_overlay.icon = icon_file + new_overlay.appearance_flags = RESET_COLOR | KEEP_APART + new_overlay.vis_flags = VIS_INHERIT_ICON_STATE | VIS_INHERIT_LAYER | VIS_INHERIT_PLANE | VIS_INHERIT_ID + new_overlay.color = gasmix_color + + gas_visuals[icon_file] = new_overlay + return new_overlay + +/// Called when the gasmix color has changed and the gas visuals need to be updated. +/datum/pipeline/proc/UpdateGasVisuals() + for(var/icon/source as anything in gas_visuals) + var/obj/effect/abstract/overlay = gas_visuals[source] + animate(overlay, time=5, color=gasmix_color) + +/// After updating, this proc handles looking at the new gas mixture and blends the colors together according to percentage of the gas mix. +/datum/pipeline/proc/CalculateGasmixColor(datum/gas_mixture/source) + SIGNAL_HANDLER + + var/current_weight = 0 + var/current_color + for(var/datum/gas/gas_path as anything in air.gases) + var/gas_weight = air.gases[gas_path][MOLES] + if(!gas_weight) + continue + var/gas_color = RGBtoHSV(initial(gas_path.primary_color)) + current_weight += gas_weight + if(!current_color) + current_color = gas_color + else + current_color = BlendHSV(current_color, gas_color, gas_weight / current_weight) + + if(!current_color) + current_color = "#000000" + else + // Empty weight is prety much arbitrary, just tuned to make the color change from black reasonably quickly without hitting max color immediately + var/empty_weight = (air.volume * 1.5 - current_weight) / 10 + if(empty_weight > 0) + current_color = BlendHSV("#000000", current_color, current_weight / (empty_weight + current_weight)) + + current_color = HSVtoRGB(current_color) + + if(gasmix_color != current_color) + gasmix_color = current_color + UpdateGasVisuals() diff --git a/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm b/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm index 9cda298ccd4..472cb3ed203 100644 --- a/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm +++ b/code/modules/atmospherics/machinery/pipes/bridge_pipe.dm @@ -13,6 +13,8 @@ construction_type = /obj/item/pipe/binary pipe_state = "bridge_center" + has_gas_visuals = FALSE + /obj/machinery/atmospherics/pipe/bridge_pipe/set_init_directions() switch(dir) if(NORTH, SOUTH) diff --git a/code/modules/atmospherics/machinery/pipes/color_adapter.dm b/code/modules/atmospherics/machinery/pipes/color_adapter.dm index 02c550fd558..06812aaa649 100644 --- a/code/modules/atmospherics/machinery/pipes/color_adapter.dm +++ b/code/modules/atmospherics/machinery/pipes/color_adapter.dm @@ -16,6 +16,8 @@ paintable = FALSE hide = FALSE + has_gas_visuals = FALSE + ///cache for the icons var/static/list/mutable_appearance/center_cache = list() @@ -34,7 +36,7 @@ . = ..() var/mutable_appearance/center = center_cache["[piping_layer]"] if(!center) - center = mutable_appearance(icon, "adapter_center") + center = mutable_appearance(initial(icon), "adapter_center") PIPING_LAYER_DOUBLE_SHIFT(center, piping_layer) center_cache["[piping_layer]"] = center . += center diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm index fd43e315527..72c9c742781 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/he_pipes.dm @@ -8,6 +8,8 @@ hide = FALSE + has_gas_visuals = FALSE + /obj/machinery/atmospherics/pipe/heat_exchanging/Initialize(mapload) . = ..() diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm index 00ef058333a..a6bfcc533d2 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/junction.dm @@ -15,6 +15,8 @@ construction_type = /obj/item/pipe/directional pipe_state = "junction" + has_gas_visuals = FALSE + /obj/machinery/atmospherics/pipe/heat_exchanging/junction/set_init_directions() switch(dir) if(NORTH, SOUTH) diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm index e340d7f54cc..5841486ba9b 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold.dm @@ -16,6 +16,8 @@ construction_type = /obj/item/pipe/trinary pipe_state = "he_manifold" + has_gas_visuals = FALSE + /obj/machinery/atmospherics/pipe/heat_exchanging/manifold/set_init_directions() initialize_directions = ALL_CARDINALS initialize_directions &= ~dir diff --git a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm index 03ef32b4354..83870ee210b 100644 --- a/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm +++ b/code/modules/atmospherics/machinery/pipes/heat_exchange/manifold4w.dm @@ -15,6 +15,8 @@ construction_type = /obj/item/pipe/quaternary pipe_state = "he_manifold4w" + has_gas_visuals = FALSE + /obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w/set_init_directions() initialize_directions = initial(initialize_directions) diff --git a/code/modules/atmospherics/machinery/pipes/layermanifold.dm b/code/modules/atmospherics/machinery/pipes/layermanifold.dm index bdfbda9ba6c..09c8a3a9367 100644 --- a/code/modules/atmospherics/machinery/pipes/layermanifold.dm +++ b/code/modules/atmospherics/machinery/pipes/layermanifold.dm @@ -12,6 +12,7 @@ construction_type = /obj/item/pipe/binary pipe_state = "manifoldlayer" paintable = TRUE + has_gas_visuals = FALSE ///Reference to all the nodes in the front var/list/front_nodes diff --git a/code/modules/atmospherics/machinery/pipes/multiz.dm b/code/modules/atmospherics/machinery/pipes/multiz.dm index cfc24ab8291..7e14b8a9806 100644 --- a/code/modules/atmospherics/machinery/pipes/multiz.dm +++ b/code/modules/atmospherics/machinery/pipes/multiz.dm @@ -15,6 +15,8 @@ construction_type = /obj/item/pipe/directional pipe_state = "multiz" + has_gas_visuals = FALSE + ///Our central icon var/mutable_appearance/center = null ///The pipe icon diff --git a/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm new file mode 100644 index 00000000000..9642442a973 --- /dev/null +++ b/code/modules/atmospherics/machinery/pipes/pipe_spritesheet_helper.dm @@ -0,0 +1,148 @@ +/client/proc/GeneratePipeSpritesheet() + set name = "Generate Pipe Spritesheet" + set category = "Debug" + + var/datum/pipe_icon_generator/generator = new + generator.Start() + fcopy(generator.generated_icons, "icons/obj/pipes_n_cables/!pipes_bitmask.dmi") + + generator.Start("-gas") + fcopy(generator.generated_icons, "icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi") + +/datum/pipe_icon_generator + var/static/icon/template_pieces = icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi') + var/static/list/icon/damage_masks = list( + "[NORTH]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", NORTH), + "[EAST]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", EAST), + "[SOUTH]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", SOUTH), + "[WEST]"=icon('icons/obj/pipes_n_cables/pipe_template_pieces.dmi', "damage_mask", WEST), + ) + + var/icon/generated_icons + +/datum/pipe_icon_generator/proc/Start(icon_state_suffix="") + var/list/outputs = list() + for(var/layer in 1 to 5) + // Since dirs are bitflags, if we want to iterate over every possible direction + // combination we just need to iterate over every number that can be contained in 4 bits. + // + // I wrote this all the hard way originally >.> + for(var/combined_dirs in 1 to 15) + switch(combined_dirs) + if(NORTH, EAST, SOUTH, WEST) + continue + + outputs += GeneratePipeDir(icon_state_suffix, layer, combined_dirs) + + generated_icons = icon('icons/testing/greyscale_error.dmi') + for(var/icon/generated_icon as anything in outputs) + var/pending_icon_state = outputs[generated_icon] + generated_icons.Insert(generated_icon, pending_icon_state) + +/datum/pipe_icon_generator/proc/GeneratePipeDir(icon_state_suffix, layer, combined_dirs) + var/list/output + + switch(combined_dirs) + if(NORTH | SOUTH, EAST | WEST) + output = GeneratePipeStraight(icon_state_suffix, layer, combined_dirs) + if(NORTH | EAST, SOUTH | EAST, SOUTH | WEST, NORTH | WEST) + output = GeneratePipeElbow(icon_state_suffix, layer, combined_dirs) + if(NORTH | EAST | SOUTH, EAST | SOUTH | WEST, SOUTH | WEST | NORTH, WEST | NORTH | EAST) + output = GeneratePipeTJunction(icon_state_suffix, layer, combined_dirs) + if(NORTH | EAST | SOUTH | WEST) + output = GeneratePipeCross(icon_state_suffix, layer, combined_dirs) + + var/shift_amount = (layer - 1) * 5 + for(var/icon/sprite as anything in output) + if(shift_amount > 0) + sprite.Shift(EAST, shift_amount) + sprite.Shift(NORTH, shift_amount) + sprite.Crop(33, 33, 64, 64) + + return output + +/// Generates all variants of damaged pipe from a given icon and the dirs that can be broken +/datum/pipe_icon_generator/proc/GenerateDamaged(icon/working, layer, dirs, x_offset=1, y_offset=1) + var/outputs = list() + var/completed = list() + for(var/combined_dirs in 1 to 15) + combined_dirs &= dirs + + var/completion_key = "[combined_dirs]" + if(completed[completion_key] || (combined_dirs == NONE)) + continue + completed[completion_key] = TRUE + + var/icon/damaged = icon(working) + for(var/i in 0 to 3) + var/dir = 1 << i + if(!(combined_dirs & dir)) + continue + var/icon/damage_mask = damage_masks["[dir]"] + damaged.Blend(damage_mask, ICON_MULTIPLY, x_offset, y_offset) + + var/icon_state_dirs = (dirs & ~combined_dirs) | CARDINAL_TO_SHORTPIPES(combined_dirs) + outputs[damaged] = "[icon_state_dirs]_[layer]" + return outputs + + +/datum/pipe_icon_generator/proc/GeneratePipeStraight(icon_state_suffix, layer, combined_dirs) + var/list/output = list() + var/north_or_east = combined_dirs & (NORTH | EAST) + var/icon/working = icon(template_pieces, "straight[icon_state_suffix]", north_or_east) + + output[working] = "[combined_dirs]_[layer]" + + var/offset = 1 + (5-layer) * 2 + switch(combined_dirs) + if(NORTH | SOUTH) + output += GenerateDamaged(working, layer, combined_dirs, y_offset=offset) + if(EAST | WEST) + output += GenerateDamaged(working, layer, combined_dirs, x_offset=offset) + + return output + +/datum/pipe_icon_generator/proc/GeneratePipeElbow(icon_state_suffix, layer, combined_dirs) + var/list/output = list() + var/icon/working + switch(combined_dirs) + if(NORTH | EAST) + working = icon(template_pieces, "elbow[icon_state_suffix]", NORTH) + if(NORTH | WEST) + working = icon(template_pieces, "elbow[icon_state_suffix]", WEST) + if(SOUTH | EAST) + working = icon(template_pieces, "elbow[icon_state_suffix]", EAST) + if(SOUTH | WEST) + working = icon(template_pieces, "elbow[icon_state_suffix]", SOUTH) + + output[working] = "[combined_dirs]_[layer]" + output += GenerateDamaged(working, layer, combined_dirs) + + return output + +/datum/pipe_icon_generator/proc/GeneratePipeTJunction(icon_state_suffix, layer, combined_dirs) + var/list/output = list() + var/icon/working + switch(combined_dirs) + if(WEST | NORTH | EAST) + working = icon(template_pieces, "tee[icon_state_suffix]", NORTH) + if(NORTH | EAST | SOUTH) + working = icon(template_pieces, "tee[icon_state_suffix]", EAST) + if(EAST | SOUTH | WEST) + working = icon(template_pieces, "tee[icon_state_suffix]", SOUTH) + if(SOUTH | WEST | NORTH) + working = icon(template_pieces, "tee[icon_state_suffix]", WEST) + + output[working] = "[combined_dirs]_[layer]" + output += GenerateDamaged(working, layer, combined_dirs) + + return output + +/datum/pipe_icon_generator/proc/GeneratePipeCross(icon_state_suffix, layer, combined_dirs) + var/list/output = list() + var/icon/working = icon(template_pieces, "cross[icon_state_suffix]") + + output[working] = "[combined_dirs]_[layer]" + output += GenerateDamaged(working, layer, combined_dirs) + + return output diff --git a/code/modules/atmospherics/machinery/pipes/pipes.dm b/code/modules/atmospherics/machinery/pipes/pipes.dm index c1c128c2e80..c94caf31174 100644 --- a/code/modules/atmospherics/machinery/pipes/pipes.dm +++ b/code/modules/atmospherics/machinery/pipes/pipes.dm @@ -1,15 +1,22 @@ /obj/machinery/atmospherics/pipe - icon = 'icons/obj/pipes_n_cables/pipes_bitmask.dmi' + icon = 'icons/obj/pipes_n_cables/!pipes_bitmask.dmi' damage_deflection = 12 - var/datum/gas_mixture/air_temporary //used when reconstructing a pipeline that broke + /// Temporary holder for gases in the absence of a pipeline + var/datum/gas_mixture/air_temporary + + /// The gas capacity this pipe contributes to a pipeline var/volume = 0 use_power = NO_POWER_USE can_unwrench = 1 + /// The pipeline this pipe is a member of var/datum/pipeline/parent = null paintable = TRUE + /// Determines if this pipe will be given gas visuals + var/has_gas_visuals = TRUE + //Buckling can_buckle = TRUE buckle_requires_restraints = TRUE @@ -27,6 +34,23 @@ if(hide) AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE) //if changing this, change the subtypes RemoveElements too, because thats how bespoke works +/obj/machinery/atmospherics/pipe/Destroy() + QDEL_NULL(parent) + + releaseAirToTurf() + + var/turf/local_turf = loc + for(var/obj/machinery/meter/meter in local_turf) + if(meter.target != src) + continue + var/obj/item/pipe_meter/meter_object = new (local_turf) + meter.transfer_fingerprints_to(meter_object) + qdel(meter) + return ..() + +//----------------- +// PIPENET STUFF + /obj/machinery/atmospherics/pipe/nullify_node(i) var/obj/machinery/atmospherics/old_node = nodes[i] . = ..() @@ -39,7 +63,7 @@ /obj/machinery/atmospherics/pipe/get_rebuild_targets() if(!QDELETED(parent)) return - parent = new + replace_pipenet(parent, new /datum/pipeline) return list(parent) /obj/machinery/atmospherics/pipe/proc/releaseAirToTurf() @@ -73,25 +97,33 @@ /obj/machinery/atmospherics/pipe/return_pipenet() return parent -/obj/machinery/atmospherics/pipe/set_pipenet(datum/pipeline/pipenet_to_set) - parent = pipenet_to_set +/obj/machinery/atmospherics/pipe/replace_pipenet(datum/pipeline/old_pipenet, datum/pipeline/new_pipenet) + if(parent && has_gas_visuals) + vis_contents -= parent.GetGasVisual('icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi') -/obj/machinery/atmospherics/pipe/Destroy() - QDEL_NULL(parent) + parent = new_pipenet - releaseAirToTurf() + if(parent && has_gas_visuals) // null is a valid argument here + vis_contents += parent.GetGasVisual('icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi') - var/turf/local_turf = loc - for(var/obj/machinery/meter/meter in local_turf) - if(meter.target != src) - continue - var/obj/item/pipe_meter/meter_object = new (local_turf) - meter.transfer_fingerprints_to(meter_object) - qdel(meter) +/obj/machinery/atmospherics/pipe/return_pipenets() + . = list(parent) + +//-------------------- +// APPEARANCE STUFF + +/obj/machinery/atmospherics/pipe/update_icon() + update_pipe_icon() + update_layer() return ..() /obj/machinery/atmospherics/pipe/proc/update_pipe_icon() - icon = 'icons/obj/pipes_n_cables/pipes_bitmask.dmi' + switch(initialize_directions) + if(NORTH, EAST, SOUTH, WEST) // Pipes with only a single connection aren't handled by this system + icon = null + return + else + icon = 'icons/obj/pipes_n_cables/!pipes_bitmask.dmi' var/connections = NONE var/bitfield = NONE for(var/i in 1 to device_type) @@ -104,11 +136,6 @@ bitfield |= CARDINAL_TO_SHORTPIPES(initialize_directions & ~connections) icon_state = "[bitfield]_[piping_layer]" -/obj/machinery/atmospherics/pipe/update_icon() - update_pipe_icon() - update_layer() - return ..() - /obj/machinery/atmospherics/proc/update_node_icon() for(var/i in 1 to device_type) if(!nodes[i]) @@ -116,9 +143,6 @@ var/obj/machinery/atmospherics/current_node = nodes[i] current_node.update_icon() -/obj/machinery/atmospherics/pipe/return_pipenets() - . = list(parent) - /obj/machinery/atmospherics/pipe/paint(paint_color) if(paintable) add_atom_colour(paint_color, FIXED_COLOUR_PRIORITY) diff --git a/code/modules/atmospherics/machinery/pipes/smart.dm b/code/modules/atmospherics/machinery/pipes/smart.dm index 95e5839469f..7c530bace5f 100644 --- a/code/modules/atmospherics/machinery/pipes/smart.dm +++ b/code/modules/atmospherics/machinery/pipes/smart.dm @@ -14,7 +14,7 @@ GLOBAL_LIST_INIT(atmos_components, typecacheof(list(/obj/machinery/atmospherics) var/connections = NONE /obj/machinery/atmospherics/pipe/smart/update_pipe_icon() - icon = 'icons/obj/pipes_n_cables/pipes_bitmask.dmi' + icon = 'icons/obj/pipes_n_cables/!pipes_bitmask.dmi' //find all directions this pipe is connected with other nodes connections = NONE diff --git a/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi b/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi new file mode 100644 index 00000000000..0262adcaeb2 Binary files /dev/null and b/icons/obj/pipes_n_cables/!pipe_gas_overlays.dmi differ diff --git a/icons/obj/pipes_n_cables/!pipes_bitmask.dmi b/icons/obj/pipes_n_cables/!pipes_bitmask.dmi new file mode 100644 index 00000000000..97643036fbe Binary files /dev/null and b/icons/obj/pipes_n_cables/!pipes_bitmask.dmi differ diff --git a/icons/obj/pipes_n_cables/pipe_template_pieces.dmi b/icons/obj/pipes_n_cables/pipe_template_pieces.dmi new file mode 100644 index 00000000000..d0d2f7ff7bb Binary files /dev/null and b/icons/obj/pipes_n_cables/pipe_template_pieces.dmi differ diff --git a/icons/obj/pipes_n_cables/pipes_bitmask.dmi b/icons/obj/pipes_n_cables/pipes_bitmask.dmi deleted file mode 100644 index 7a382fb55c5..00000000000 Binary files a/icons/obj/pipes_n_cables/pipes_bitmask.dmi and /dev/null differ diff --git a/tgstation.dme b/tgstation.dme index 2c499469869..bdb2f45dbab 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3200,6 +3200,7 @@ #include "code\modules\atmospherics\machinery\pipes\layermanifold.dm" #include "code\modules\atmospherics\machinery\pipes\mapping.dm" #include "code\modules\atmospherics\machinery\pipes\multiz.dm" +#include "code\modules\atmospherics\machinery\pipes\pipe_spritesheet_helper.dm" #include "code\modules\atmospherics\machinery\pipes\pipes.dm" #include "code\modules\atmospherics\machinery\pipes\smart.dm" #include "code\modules\atmospherics\machinery\pipes\heat_exchange\he_pipes.dm" diff --git a/tgui/packages/tgui/constants.ts b/tgui/packages/tgui/constants.ts index 270ce9873bd..db6b33ca7d2 100644 --- a/tgui/packages/tgui/constants.ts +++ b/tgui/packages/tgui/constants.ts @@ -159,7 +159,7 @@ const GASES = [ path: '/datum/gas/nitrogen', name: 'Nitrogen', label: 'N₂', - color: 'red', + color: 'yellow', }, { id: 'co2',