From 37e732d8db15bbaa9407ee8842aa41f79028bd9e Mon Sep 17 00:00:00 2001 From: ZomgPonies Date: Sat, 12 Oct 2013 14:41:43 -0400 Subject: [PATCH] Updated ZAS and Atmo --- code/ATMOSPHERICS/chiller.dm | 184 ++++++ code/ATMOSPHERICS/components/tvalve.dm | 2 + .../components/unary/cold_sink.dm | 2 +- .../components/unary/thermal_plate.dm | 44 +- .../components/unary/vent_scrubber.dm | 24 +- code/ATMOSPHERICS/components/valve.dm | 5 +- code/ATMOSPHERICS/he_pipes.dm | 162 ++--- code/ATMOSPHERICS/pipes.dm | 87 ++- code/ZAS/Airflow.dm | 181 +++--- code/ZAS/Connection.dm | 5 +- code/ZAS/FEA_gas_mixture.dm | 50 +- code/ZAS/Fire.dm | 101 ++- code/ZAS/NewSettings.dm | 517 ++++++++++++++++ code/ZAS/Plasma.dm | 54 +- code/ZAS/Variable Settings.dm | 582 +++++++++--------- code/ZAS/ZAS_Turfs.dm | 69 ++- code/ZAS/ZAS_Zones.dm | 31 +- icons/obj/atmospherics/cold_sink.dmi | Bin 595 -> 9182 bytes icons/obj/atmospherics/red_pipe.dmi | Bin 3950 -> 5645 bytes icons/obj/atmospherics/vent_scrubber.dmi | Bin 5780 -> 14166 bytes icons/obj/pipes/heat.dmi | Bin 4949 -> 4566 bytes icons/obj/pipes/junction.dmi | Bin 2847 -> 6596 bytes 22 files changed, 1529 insertions(+), 571 deletions(-) create mode 100644 code/ATMOSPHERICS/chiller.dm create mode 100644 code/ZAS/NewSettings.dm diff --git a/code/ATMOSPHERICS/chiller.dm b/code/ATMOSPHERICS/chiller.dm new file mode 100644 index 00000000000..3aa8b0af271 --- /dev/null +++ b/code/ATMOSPHERICS/chiller.dm @@ -0,0 +1,184 @@ +// A freezer and a space heater had a baby. +/obj/machinery/space_heater/air_conditioner + anchored = 0 + density = 1 + icon = 'icons/obj/atmos.dmi' + icon_state = "aircond0" + name = "air conditioner" + desc = "If you can't take the heat, use one of these." + set_temperature = 20 // in celcius, add T0C for kelvin + var/cooling_power = 40000 + + flags = FPRINT + + +/obj/machinery/space_heater/air_conditioner/New() + ..() + cell = new(src) + cell.charge = 1000 + cell.maxcharge = 1000 + update_icon() + return + +/obj/machinery/space_heater/air_conditioner/update_icon() + overlays.Cut() + icon_state = "aircond[on]" + if(open) + overlays += "sheater-open" + return + +/obj/machinery/space_heater/air_conditioner/examine() + set src in oview(12) + if (!( usr )) + return + usr << "This is \icon[src] \an [src.name]." + usr << src.desc + + usr << "The air conditioner is [on ? "on" : "off"] and the hatch is [open ? "open" : "closed"]." + if(open) + usr << "The power cell is [cell ? "installed" : "missing"]." + else + usr << "The charge meter reads [cell ? round(cell.percent(),1) : 0]%" + return + +/obj/machinery/space_heater/air_conditioner/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + if(cell) + cell.emp_act(severity) + ..(severity) + +/obj/machinery/space_heater/air_conditioner/attackby(obj/item/I, mob/user) + if(istype(I, /obj/item/weapon/cell)) + if(open) + if(cell) + user << "There is already a power cell inside." + return + else + // insert cell + var/obj/item/weapon/cell/C = usr.get_active_hand() + if(istype(C)) + user.drop_item() + cell = C + C.loc = src + C.add_fingerprint(usr) + + user.visible_message("\blue [user] inserts a power cell into [src].", "\blue You insert the power cell into [src].") + else + user << "The hatch must be open to insert a power cell." + return + else if(istype(I, /obj/item/weapon/screwdriver)) + open = !open + user.visible_message("\blue [user] [open ? "opens" : "closes"] the hatch on the [src].", "\blue You [open ? "open" : "close"] the hatch on the [src].") + update_icon() + if(!open && user.machine == src) + user << browse(null, "window=aircond") + user.unset_machine() + else + ..() + return +/obj/machinery/space_heater/air_conditioner/attack_hand(mob/user as mob) + src.add_fingerprint(user) + interact(user) + +/obj/machinery/space_heater/air_conditioner/interact(mob/user as mob) + if(open) + var/temp = set_temperature + var/dat + dat = "Power cell: " + if(cell) + dat += "Installed
" + else + dat += "Removed
" + + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\ATMOSPHERICS\chiller.dm:95: dat += "Power Level: [cell ? round(cell.percent(),1) : 0]%

" + dat += {"Power Level: [cell ? round(cell.percent(),1) : 0]%

+ Set Temperature: + - + - + [temp]°C + + + +
"} + // END AUTOFIX + user.set_machine(src) + user << browse("Air Conditioner Control Panel[dat]", "window=aircond") + onclose(user, "aircond") + else + on = !on + user.visible_message("\blue [user] switches [on ? "on" : "off"] the [src].","\blue You switch [on ? "on" : "off"] the [src].") + update_icon() + return + + +/obj/machinery/space_heater/air_conditioner/Topic(href, href_list) + if (usr.stat) + return + if ((in_range(src, usr) && istype(src.loc, /turf)) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + + switch(href_list["op"]) + + if("temp") + var/value = text2num(href_list["val"]) + + // limit to 15c and 20c(room temp) + set_temperature = dd_range(15, 25, set_temperature + value) + + if("cellremove") + if(open && cell && !usr.get_active_hand()) + cell.updateicon() + usr.put_in_hands(cell) + cell.add_fingerprint(usr) + cell = null + usr.visible_message("\blue [usr] removes the power cell from \the [src].", "\blue You remove the power cell from \the [src].") + + + if("cellinstall") + if(open && !cell) + var/obj/item/weapon/cell/C = usr.get_active_hand() + if(istype(C)) + usr.drop_item() + cell = C + C.loc = src + C.add_fingerprint(usr) + + usr.visible_message("\blue [usr] inserts a power cell into \the [src].", "\blue You insert the power cell into \the [src].") + + src.updateDialog() + else + usr << browse(null, "window=aircond") + usr.unset_machine() + return + +/obj/machinery/space_heater/air_conditioner/proc/chill() + var/turf/simulated/L = loc + if(istype(L)) + var/datum/gas_mixture/env = L.return_air() + var/transfer_moles = 0.25 * env.total_moles() + var/datum/gas_mixture/removed = env.remove(transfer_moles) + if(removed) + if(removed.temperature > (set_temperature + T0C)) + var/air_heat_capacity = removed.heat_capacity() + var/combined_heat_capacity = cooling_power + air_heat_capacity + //var/old_temperature = removed.temperature + + if(combined_heat_capacity > 0) + var/combined_energy = set_temperature*cooling_power + air_heat_capacity*removed.temperature + removed.temperature = combined_energy/combined_heat_capacity + env.merge(removed) + return 1 + env.merge(removed) + return 0 + +/obj/machinery/space_heater/air_conditioner/process() + if(on) + if(cell && cell.charge > 0) + if(chill()) + cell.use(cooling_power/20000) + else + on = 0 + update_icon() + return diff --git a/code/ATMOSPHERICS/components/tvalve.dm b/code/ATMOSPHERICS/components/tvalve.dm index 83f592c315f..cb95959ea41 100644 --- a/code/ATMOSPHERICS/components/tvalve.dm +++ b/code/ATMOSPHERICS/components/tvalve.dm @@ -268,6 +268,7 @@ obj/machinery/atmospherics/tvalve icon = 'icons/obj/atmospherics/digital_valve.dmi' attack_ai(mob/user as mob) + src.add_hiddenprint(user) return src.attack_hand(user) attack_hand(mob/user as mob) @@ -387,6 +388,7 @@ obj/machinery/atmospherics/tvalve/mirrored icon = 'icons/obj/atmospherics/digital_valve.dmi' attack_ai(mob/user as mob) + src.add_hiddenprint(user) return src.attack_hand(user) attack_hand(mob/user as mob) diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm index ef1d5f60bea..b1fa6a21b47 100644 --- a/code/ATMOSPHERICS/components/unary/cold_sink.dm +++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm @@ -1,6 +1,6 @@ /obj/machinery/atmospherics/unary/cold_sink icon = 'icons/obj/atmospherics/cold_sink.dmi' - icon_state = "intact_off" + icon_state = "on_cool" density = 1 use_power = 1 diff --git a/code/ATMOSPHERICS/components/unary/thermal_plate.dm b/code/ATMOSPHERICS/components/unary/thermal_plate.dm index 23e27ad0564..daebcf1bd2e 100644 --- a/code/ATMOSPHERICS/components/unary/thermal_plate.dm +++ b/code/ATMOSPHERICS/components/unary/thermal_plate.dm @@ -6,17 +6,18 @@ //Transfers heat between a pipe system and environment, based on which has a greater thermal energy concentration icon = 'icons/obj/atmospherics/cold_sink.dmi' - icon_state = "intact_off" + icon_state = "off" + level = 1 name = "Thermal Transfer Plate" desc = "Transfers heat to and from an area" update_icon() - if(node) - icon_state = "intact_off" - else - icon_state = "exposed" - return + var/prefix="" + //var/suffix="_idle" // Also available: _heat, _cool + if(level == 1 && istype(loc, /turf/simulated)) + prefix="h" + icon_state = "[prefix]off" process() ..() @@ -59,6 +60,37 @@ return 1 + hide(var/i) //to make the little pipe section invisible, the icon changes. + var/prefix="" + //var/suffix="_idle" // Also available: _heat, _cool + if(i == 1 && istype(loc, /turf/simulated)) + prefix="h" + icon_state = "[prefix]off" + return + + attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) + if (!istype(W, /obj/item/weapon/wrench)) + return ..() + var/turf/T = src.loc + if (level==1 && isturf(T) && T.intact) + user << "\red You must remove the plating first." + return 1 + var/datum/gas_mixture/int_air = return_air() + var/datum/gas_mixture/env_air = loc.return_air() + if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE) + user << "\red You cannot unwrench this [src], it too exerted due to internal pressure." + add_fingerprint(user) + return 1 + playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1) + user << "\blue You begin to unfasten \the [src]..." + if (do_after(user, 40)) + user.visible_message( \ + "[user] unfastens \the [src].", \ + "\blue You have unfastened \the [src].", \ + "You hear ratchet.") + new /obj/item/pipe(loc, make_from=src) + del(src) + proc/radiate() var/internal_transfer_moles = 0.25 * air_contents.total_moles() diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index b0470df9330..fa27ee44af4 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -40,13 +40,19 @@ ..() update_icon() + var/hidden="" + if(level == 1 && istype(loc, /turf/simulated)) + hidden="h" + var/suffix="" + if(scrub_O2) + suffix="1" if(node && on && !(stat & (NOPOWER|BROKEN))) if(scrubbing) - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on" + icon_state = "[hidden]on[suffix]" else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in" + icon_state = "[hidden]in" else - icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off" + icon_state = "[hidden]off" return proc @@ -106,7 +112,12 @@ var/datum/gas_mixture/environment = loc.return_air() if(scrubbing) - if((environment.toxins>0) || (environment.carbon_dioxide>0) || (environment.trace_gases.len>0)) + // Are we scrubbing gasses that are present? + if(\ + (scrub_Toxins && environment.toxins > 0) ||\ + (scrub_CO2 && environment.carbon_dioxide > 0) ||\ + (scrub_N2O && environment.trace_gases.len > 0) ||\ + (scrub_O2 && environment.oxygen > 0)) var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() //Take a gas sample @@ -117,12 +128,15 @@ //Filter it var/datum/gas_mixture/filtered_out = new filtered_out.temperature = removed.temperature + if(scrub_Toxins) filtered_out.toxins = removed.toxins removed.toxins = 0 + if(scrub_CO2) filtered_out.carbon_dioxide = removed.carbon_dioxide removed.carbon_dioxide = 0 + if(scrub_O2) filtered_out.oxygen = removed.oxygen removed.oxygen = 0 @@ -184,7 +198,7 @@ on = !on if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing - panic = text2num(signal.data["panic_siphon"] != null) + panic = text2num(signal.data["panic_siphon"]) // We send 0 for false in the alarm. if(panic) on = 1 scrubbing = 0 diff --git a/code/ATMOSPHERICS/components/valve.dm b/code/ATMOSPHERICS/components/valve.dm index 09d0b64f866..d9471470759 100644 --- a/code/ATMOSPHERICS/components/valve.dm +++ b/code/ATMOSPHERICS/components/valve.dm @@ -266,6 +266,7 @@ obj/machinery/atmospherics/valve icon = 'icons/obj/atmospherics/digital_valve.dmi' attack_ai(mob/user as mob) + src.add_hiddenprint(user) return src.attack_hand(user) attack_hand(mob/user as mob) @@ -314,8 +315,8 @@ obj/machinery/atmospherics/valve attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) if (!istype(W, /obj/item/weapon/wrench)) return ..() - if (istype(src, /obj/machinery/atmospherics/valve/digital)) - user << "\red You cannot unwrench this [src], it's too complicated." + if (istype(src,/obj/machinery/atmospherics/valve/digital) && src:frequency) + user << "\red You cannot unwrench this [src], it's digitally connected to another device." return 1 var/turf/T = src.loc if (level==1 && isturf(T) && T.intact) diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm index 3fe69c855d4..259b70b633f 100644 --- a/code/ATMOSPHERICS/he_pipes.dm +++ b/code/ATMOSPHERICS/he_pipes.dm @@ -1,5 +1,5 @@ -obj/machinery/atmospherics/pipe/simple/heat_exchanging +/obj/machinery/atmospherics/pipe/simple/heat_exchanging icon = 'icons/obj/pipes/heat.dmi' icon_state = "intact" level = 2 @@ -9,55 +9,59 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT // BubbleWrap - New() - ..() - initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/New() + ..() + initialize_directions_he = initialize_directions // The auto-detection from /pipe is good enough for a simple HE pipe // BubbleWrap END - initialize() - normalize_dir() - var/node1_dir - var/node2_dir +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/initialize() + normalize_dir() + var/node1_dir + var/node2_dir - for(var/direction in cardinal) - if(direction&initialize_directions_he) - if (!node1_dir) - node1_dir = direction - else if (!node2_dir) - node2_dir = direction + for(var/direction in cardinal) + if(direction&initialize_directions_he) + if (!node1_dir) + node1_dir = direction + else if (!node2_dir) + node2_dir = direction - for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir)) - if(target.initialize_directions_he & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir)) - if(target.initialize_directions_he & get_dir(target,src)) - node2 = target - break - update_icon() - return + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node1_dir)) + if(target.initialize_directions_he & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,node2_dir)) + if(target.initialize_directions_he & get_dir(target,src)) + node2 = target + break + update_icon() + return - - process() - if(!parent) - ..() - else - var/environment_temperature = 0 - if(istype(loc, /turf/simulated/)) - if(loc:blocks_air) - environment_temperature = loc:temperature - else - var/datum/gas_mixture/environment = loc.return_air() - environment_temperature = environment.temperature - else +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/process() + if(!parent) + ..() + else + var/environment_temperature = 0 + if(istype(loc, /turf/simulated/)) + if(loc:blocks_air) environment_temperature = loc:temperature - var/datum/gas_mixture/pipe_air = return_air() - if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) - parent.temperature_interact(loc, volume, thermal_conductivity) + else + var/datum/gas_mixture/environment = loc.return_air() + environment_temperature = environment.temperature + else + environment_temperature = loc:temperature + var/datum/gas_mixture/pipe_air = return_air() + if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference) + parent.temperature_interact(loc, volume, thermal_conductivity) +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/hidden + level=1 + icon_state="intact-f" - -obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction +///////////////////////////////// +// JUNCTION +///////////////////////////////// +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction icon = 'icons/obj/pipes/junction.dmi' icon_state = "intact" level = 2 @@ -65,42 +69,46 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT // BubbleWrap - New() - .. () - switch ( dir ) - if ( SOUTH ) - initialize_directions = NORTH - initialize_directions_he = SOUTH - if ( NORTH ) - initialize_directions = SOUTH - initialize_directions_he = NORTH - if ( EAST ) - initialize_directions = WEST - initialize_directions_he = EAST - if ( WEST ) - initialize_directions = EAST - initialize_directions_he = WEST +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/New() + .. () + switch ( dir ) + if ( SOUTH ) + initialize_directions = NORTH + initialize_directions_he = SOUTH + if ( NORTH ) + initialize_directions = SOUTH + initialize_directions_he = NORTH + if ( EAST ) + initialize_directions = WEST + initialize_directions_he = EAST + if ( WEST ) + initialize_directions = EAST + initialize_directions_he = WEST // BubbleWrap END +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/update_icon() + if(node1&&node2) + icon_state = "intact[invisibility ? "-f" : "" ]" + else + var/have_node1 = node1?1:0 + var/have_node2 = node2?1:0 + icon_state = "exposed[have_node1][have_node2]" + if(!node1&&!node2) + del(src) + +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/initialize() + for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions)) + if(target.initialize_directions & get_dir(target,src)) + node1 = target + break + for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he)) + if(target.initialize_directions_he & get_dir(target,src)) + node2 = target + break + update_icon() - if(node1&&node2) - icon_state = "intact" - else - var/have_node1 = node1?1:0 - var/have_node2 = node2?1:0 - icon_state = "exposed[have_node1][have_node2]" - if(!node1&&!node2) - del(src) + return - initialize() - for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions)) - if(target.initialize_directions & get_dir(target,src)) - node1 = target - break - for(var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/target in get_step(src,initialize_directions_he)) - if(target.initialize_directions_he & get_dir(target,src)) - node2 = target - break - - update_icon() - return +/obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction/hidden + level=1 + icon_state="intact-f" \ No newline at end of file diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 0b206866c58..754c82f5982 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -247,7 +247,6 @@ obj/machinery/atmospherics/pipe node2 = null update_icon() - return null simple/scrubbers @@ -315,9 +314,23 @@ obj/machinery/atmospherics/pipe level = 1 icon_state = "intact-y-f" + simple/filtering + name="Pipe" + _color="green" + icon_state = "" + + simple/filtering/visible + level = 2 + icon_state = "intact-g" + + simple/filtering/hidden + level = 1 + icon_state = "intact-g-f" + simple/insulated + name = "Insulated pipe" icon = 'icons/obj/atmospherics/red_pipe.dmi' icon_state = "intact" @@ -329,6 +342,10 @@ obj/machinery/atmospherics/pipe level = 2 + hidden + level=1 + icon_state="intact-f" + tank icon = 'icons/obj/atmospherics/pipe_tank.dmi' @@ -792,6 +809,22 @@ obj/machinery/atmospherics/pipe _color="yellow" icon_state = "" + manifold/filtering + name="Air filtering pipe" + _color="green" + icon_state = "" + + manifold/insulated + //thermal_conductivity = 0 + name="Insulated pipe" + icon = 'icons/obj/atmospherics/red_pipe.dmi' + icon_state = "manifold" + //minimum_temperature_difference = 10000 + //maximum_pressure = 1000*ONE_ATMOSPHERE + //fatigue_pressure = 900*ONE_ATMOSPHERE + alert_pressure = 900*ONE_ATMOSPHERE + level = 2 + manifold/scrubbers/visible level = 2 icon_state = "manifold-r" @@ -824,6 +857,14 @@ obj/machinery/atmospherics/pipe level = 1 icon_state = "manifold-f" + manifold/insulated/visible + level = 2 + icon_state = "manifold" + + manifold/insulated/hidden + level = 1 + icon_state = "manifold-f" + manifold/yellow/visible level = 2 icon_state = "manifold-y" @@ -832,6 +873,15 @@ obj/machinery/atmospherics/pipe level = 1 icon_state = "manifold-y-f" + manifold/filtering/visible + level = 2 + icon_state = "manifold-g" + + manifold/filtering/hidden + level = 1 + icon_state = "manifold-g-f" + + manifold4w icon = 'icons/obj/atmospherics/pipe_manifold.dmi' icon_state = "manifold4w-f" @@ -998,6 +1048,16 @@ obj/machinery/atmospherics/pipe _color="gray" icon_state = "" + manifold4w/insulated + name="Insulated pipe" + _color="" + //minimum_temperature_difference = 10000 + //maximum_pressure = 1000*ONE_ATMOSPHERE + //fatigue_pressure = 900*ONE_ATMOSPHERE + alert_pressure = 900*ONE_ATMOSPHERE + level = 2 + icon_state = "manifold4w" + manifold4w/scrubbers/visible level = 2 icon_state = "manifold4w-r" @@ -1030,6 +1090,10 @@ obj/machinery/atmospherics/pipe level = 1 icon_state = "manifold4w-f" + manifold4w/insulated/hidden + level = 1 + icon_state = "manifold4w-f" + cap name = "pipe endcap" desc = "An endcap for pipes" @@ -1118,7 +1182,26 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u if (istype(src, /obj/machinery/atmospherics/pipe/vent)) return ..() - if(istype(W,/obj/item/device/pipe_painter)) + // ===== Handle paints ===== + if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/red)) + src._color = "red" + user << "\red You paint the pipe red." + update_icon() + return 1 + if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/blue)) + src._color = "blue" + user << "\red You paint the pipe blue." + update_icon() + return 1 + if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/green)) + src._color = "green" + user << "\red You paint the pipe green." + update_icon() + return 1 + if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/yellow)) + src._color = "yellow" + user << "\red You paint the pipe yellow." + update_icon() return 1 if (!istype(W, /obj/item/weapon/wrench)) diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index 894dc92c72b..87f4bda7ecf 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -52,12 +52,17 @@ mob/var/tmp/last_airflow_stun = 0 mob/proc/airflow_stun() if(stat == 2) return 0 - if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0 + if(last_airflow_stun > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown)) return 0 if(!(status_flags & CANSTUN) && !(status_flags & CANWEAKEN)) src << "\blue You stay upright as the air rushes past you." return 0 - if(weakened <= 0) src << "\red The sudden rush of air knocks you over!" - weakened = max(weakened,5) + + if(zas_settings.Get(/datum/ZAS_Setting/airflow_push)) + if(weakened <= 0) src << "\red The sudden rush of air knocks you over!" + weakened = max(weakened,5) + last_airflow_stun = world.time + return + src << "\blue You stay upright as the air rushes past you." last_airflow_stun = world.time mob/living/silicon/airflow_stun() @@ -67,27 +72,34 @@ mob/living/carbon/metroid/airflow_stun() return mob/living/carbon/human/airflow_stun() - if(last_airflow_stun > world.time - vsc.airflow_stun_cooldown) return 0 + if(last_airflow_stun > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_stun_cooldown)) return 0 if(buckled) return 0 if(shoes) if(shoes.flags & NOSLIP) return 0 if(!(status_flags & CANSTUN) && !(status_flags & CANWEAKEN)) src << "\blue You stay upright as the air rushes past you." return 0 - if(weakened <= 0) src << "\red The sudden rush of air knocks you over!" - weakened = max(weakened,rand(1,5)) + + if(zas_settings.Get(/datum/ZAS_Setting/airflow_push)) + if(weakened <= 0) src << "\red The sudden rush of air knocks you over!" + weakened = max(weakened,rand(1,5)) + last_airflow_stun = world.time + return + src << "\blue You stay upright as the air rushes past you." last_airflow_stun = world.time atom/movable/proc/check_airflow_movable(n) - - if(anchored && !ismob(src)) return 0 - - if(!istype(src,/obj/item) && n < vsc.airflow_dense_pressure) return 0 + if(!zas_settings.Get(/datum/ZAS_Setting/airflow_push)) + return 0 + if(anchored && !ismob(src)) + return 0 + if(!istype(src,/obj/item) && n < zas_settings.Get(/datum/ZAS_Setting/airflow_dense_pressure)) + return 0 return 1 mob/check_airflow_movable(n) - if(n < vsc.airflow_heavy_pressure) + if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_heavy_pressure)) return 0 return 1 @@ -102,11 +114,11 @@ obj/item/check_airflow_movable(n) . = ..() switch(w_class) if(2) - if(n < vsc.airflow_lightest_pressure) return 0 + if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) return 0 if(3) - if(n < vsc.airflow_light_pressure) return 0 + if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_light_pressure)) return 0 if(4,5) - if(n < vsc.airflow_medium_pressure) return 0 + if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure)) return 0 //The main airflow code. Called by zone updates. //Zones A and B are air zones. n represents the amount of air moved. @@ -116,7 +128,7 @@ proc/Airflow(zone/A, zone/B) var/n = B.air.return_pressure() - A.air.return_pressure() //Don't go any further if n is lower than the lowest value needed for airflow. - if(abs(n) < vsc.airflow_lightest_pressure) return + if(abs(n) < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) return //These turfs are the midway point between A and B, and will be the destination point for thrown objects. var/list/connection/connections_A = A.connections @@ -141,53 +153,52 @@ proc/Airflow(zone/A, zone/B) var/list/temporary_pplz = air_sucked air_sucked = air_repelled air_repelled = temporary_pplz + if(zas_settings.Get(/datum/ZAS_Setting/airflow_push)) // If enabled + for(var/atom/movable/M in air_sucked) + if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay)) continue - for(var/atom/movable/M in air_sucked) + //Check for knocking people over + if(ismob(M) && n > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure)) + if(M:status_flags & GODMODE) continue + M:airflow_stun() - if(M.last_airflow > world.time - vsc.airflow_delay) continue + if(M.check_airflow_movable(n)) - //Check for knocking people over - if(ismob(M) && n > vsc.airflow_stun_pressure) - if(M:status_flags & GODMODE) continue - M:airflow_stun() + //Check for things that are in range of the midpoint turfs. + var/list/close_turfs = list() + for(var/turf/U in connected_turfs) + if(M in range(U)) close_turfs += U + if(!close_turfs.len) continue - if(M.check_airflow_movable(n)) + //If they're already being tossed, don't do it again. + if(!M.airflow_speed) - //Check for things that are in range of the midpoint turfs. - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue + M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) + spawn M.GotoAirflowDest(abs(n)/5) - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. + //Do it again for the stuff in the other zone, making it fly away. + for(var/atom/movable/M in air_repelled) - spawn M.GotoAirflowDest(abs(n)/5) + if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay)) continue - //Do it again for the stuff in the other zone, making it fly away. - for(var/atom/movable/M in air_repelled) + if(ismob(M) && abs(n) > zas_settings.Get(/datum/ZAS_Setting/airflow_medium_pressure)) + if(M:status_flags & GODMODE) continue + M:airflow_stun() - if(M.last_airflow > world.time - vsc.airflow_delay) continue + if(M.check_airflow_movable(abs(n))) - if(ismob(M) && abs(n) > vsc.airflow_medium_pressure) - if(M:status_flags & GODMODE) continue - M:airflow_stun() + var/list/close_turfs = list() + for(var/turf/U in connected_turfs) + if(M in range(U)) close_turfs += U + if(!close_turfs.len) continue - if(M.check_airflow_movable(abs(n))) + //If they're already being tossed, don't do it again. + if(!M.airflow_speed) - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue + M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - - spawn M.RepelAirflowDest(abs(n)/5) + spawn M.RepelAirflowDest(abs(n)/5) proc/AirflowSpace(zone/A) @@ -196,34 +207,34 @@ proc/AirflowSpace(zone/A) var/n = A.air.return_pressure() //Here, n is determined by only the pressure in the room. - if(n < vsc.airflow_lightest_pressure) return + if(n < zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) return var/list/connected_turfs = A.unsimulated_tiles //The midpoints are now all the space connections. var/list/pplz = A.movables() //We only need to worry about things in the zone, not things in space. - for(var/atom/movable/M in pplz) + if(zas_settings.Get(/datum/ZAS_Setting/airflow_push)) // If enabled + for(var/atom/movable/M in pplz) + if(M.last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay)) continue - if(M.last_airflow > world.time - vsc.airflow_delay) continue + if(ismob(M) && n > zas_settings.Get(/datum/ZAS_Setting/airflow_stun_pressure)) + var/mob/O = M + if(O.status_flags & GODMODE) continue + O.airflow_stun() - if(ismob(M) && n > vsc.airflow_stun_pressure) - var/mob/O = M - if(O.status_flags & GODMODE) continue - O.airflow_stun() + if(M.check_airflow_movable(n)) - if(M.check_airflow_movable(n)) + var/list/close_turfs = list() + for(var/turf/U in connected_turfs) + if(M in range(U)) close_turfs += U + if(!close_turfs.len) continue - var/list/close_turfs = list() - for(var/turf/U in connected_turfs) - if(M in range(U)) close_turfs += U - if(!close_turfs.len) continue + //If they're already being tossed, don't do it again. + if(!M.airflow_speed) - //If they're already being tossed, don't do it again. - if(!M.airflow_speed) - - M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. - spawn - if(M) M.GotoAirflowDest(n/10) - //Sometimes shit breaks, and M isn't there after the spawn. + M.airflow_dest = pick(close_turfs) //Pick a random midpoint to fly towards. + spawn + if(M) M.GotoAirflowDest(n/10) + //Sometimes shit breaks, and M isn't there after the spawn. /atom/movable/var/tmp/turf/airflow_dest @@ -232,9 +243,10 @@ proc/AirflowSpace(zone/A) /atom/movable/var/tmp/last_airflow = 0 /atom/movable/proc/GotoAirflowDest(n) + if(!zas_settings.Get(/datum/ZAS_Setting/airflow_push)) return // If not enabled, fuck it. if(!airflow_dest) return if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return + if(last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay)) return if(airflow_speed) airflow_speed = n/max(get_dist(src,airflow_dest),1) return @@ -268,7 +280,7 @@ proc/AirflowSpace(zone/A) while(airflow_speed > 0) if(airflow_speed <= 0) return airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay + airflow_speed -= zas_settings.Get(/datum/ZAS_Setting/airflow_speed_decay) if(airflow_speed > 7) if(airflow_time++ >= airflow_speed - 7) if(od) @@ -288,7 +300,7 @@ proc/AirflowSpace(zone/A) return step_towards(src, src.airflow_dest) if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown + src:client:move_delay = world.time + zas_settings.Get(/datum/ZAS_Setting/airflow_mob_slowdown) airflow_dest = null airflow_speed = 0 airflow_time = 0 @@ -297,9 +309,10 @@ proc/AirflowSpace(zone/A) /atom/movable/proc/RepelAirflowDest(n) + if(!zas_settings.Get(/datum/ZAS_Setting/airflow_push)) return // If not enabled, fuck it. if(!airflow_dest) return if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return + if(last_airflow > world.time - zas_settings.Get(/datum/ZAS_Setting/airflow_delay)) return if(airflow_speed) airflow_speed = n/max(get_dist(src,airflow_dest),1) return @@ -333,7 +346,7 @@ proc/AirflowSpace(zone/A) while(airflow_speed > 0) if(airflow_speed <= 0) return airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay + airflow_speed -= zas_settings.Get(/datum/ZAS_Setting/airflow_speed_decay) if(airflow_speed > 7) if(airflow_time++ >= airflow_speed - 7) sleep(1 * tick_multiplier) @@ -347,7 +360,7 @@ proc/AirflowSpace(zone/A) return step_towards(src, src.airflow_dest) if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown + src:client:move_delay = world.time + zas_settings.Get(/datum/ZAS_Setting/airflow_mob_slowdown) airflow_dest = null airflow_speed = 0 airflow_time = 0 @@ -369,14 +382,14 @@ atom/movable/proc/airflow_hit(atom/A) mob/airflow_hit(atom/A) for(var/mob/M in hearers(src)) M.show_message("\red \The [src] slams into \a [A]!",1,"\red You hear a loud slam!",2) - playsound(src.loc, "smash.ogg", 25, 1, -1) + //playsound(src.loc, "smash.ogg", 25, 1, -1) weakened = max(weakened, (istype(A,/obj/item) ? A:w_class : rand(1,5))) //Heheheh . = ..() obj/airflow_hit(atom/A) for(var/mob/M in hearers(src)) M.show_message("\red \The [src] slams into \a [A]!",1,"\red You hear a loud slam!",2) - playsound(src.loc, "smash.ogg", 25, 1, -1) + //playsound(src.loc, "smash.ogg", 25, 1, -1) . = ..() obj/item/airflow_hit(atom/A) @@ -386,13 +399,13 @@ obj/item/airflow_hit(atom/A) mob/living/carbon/human/airflow_hit(atom/A) // for(var/mob/M in hearers(src)) // M.show_message("\red [src] slams into [A]!",1,"\red You hear a loud slam!",2) - playsound(src.loc, "punch", 25, 1, -1) + //playsound(src.loc, "punch", 25, 1, -1) loc:add_blood(src) if (src.wear_suit) src.wear_suit.add_blood(src) if (src.w_uniform) src.w_uniform.add_blood(src) - var/b_loss = airflow_speed * vsc.airflow_damage + var/b_loss = airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_damage) var/blocked = run_armor_check("head","melee") apply_damage(b_loss/3, BRUTE, "head", blocked, 0, "Airflow") @@ -403,17 +416,19 @@ mob/living/carbon/human/airflow_hit(atom/A) blocked = run_armor_check("groin","melee") apply_damage(b_loss/3, BRUTE, "groin", blocked, 0, "Airflow") - if(airflow_speed > 10) - paralysis += round(airflow_speed * vsc.airflow_stun) - stunned = max(stunned,paralysis + 3) - else - stunned += round(airflow_speed * vsc.airflow_stun/2) + if(zas_settings.Get(/datum/ZAS_Setting/airflow_push)) + if(airflow_speed > 10) + paralysis += round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun)) + stunned = max(stunned,paralysis + 3) + else + stunned += round(airflow_speed * zas_settings.Get(/datum/ZAS_Setting/airflow_stun)/2) + . = ..() zone/proc/movables() . = list() for(var/turf/T in contents) for(var/atom/A in T) - if(istype(A, /obj/effect) || istype(A, /mob/aiEye)) + if(istype(A, /obj/effect) || isobserver(A) || istype(A, /mob/camera)) continue . += A diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm index b26217eeb6c..8a919d50435 100644 --- a/code/ZAS/Connection.dm +++ b/code/ZAS/Connection.dm @@ -104,7 +104,8 @@ Indirect connections will not merge the two zones after they reach equilibrium. //Disconnect zones while handling unusual conditions. // e.g. loss of a zone on a turf - DisconnectZones(zone_A, zone_B) + if(A && A.zone && B && B.zone) + DisconnectZones(A.zone, B.zone) //Finally, preform actual deletion. . = ..() @@ -399,4 +400,4 @@ Indirect connections will not merge the two zones after they reach equilibrium. #undef CONNECTION_DIRECT #undef CONNECTION_INDIRECT -#undef CONNECTION_CLOSED +#undef CONNECTION_CLOSED \ No newline at end of file diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm index 8b7ab992c93..37c53c8feda 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/FEA_gas_mixture.dm @@ -14,6 +14,15 @@ What are the archived variables for? #define QUANTIZE(variable) (round(variable,0.0001)) #define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer +#define TEMPERATURE_ICE_FORMATION 273.15 // 273 kelvin is the freezing point of water. +#define MIN_PRESSURE_ICE_FORMATION 10 // 10kPa should be okay + +#define GRAPHICS_PLASMA 1 +#define GRAPHICS_N2O 2 +#define GRAPHICS_REAGENTS 4 // Not used. Yet. +#define GRAPHICS_COLD 8 + + /datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy. /datum/gas/oxygen_agent_b/specific_heat = 300 @@ -43,7 +52,7 @@ What are the archived variables for? //Size of the group this gas_mixture is representing. //=1 for singletons - var/graphic + var/graphics=0 var/list/datum/gas/trace_gases = list() //Seemed to be a good idea that was abandoned @@ -54,7 +63,7 @@ What are the archived variables for? var/tmp/temperature_archived - var/tmp/graphic_archived = 0 + var/tmp/graphics_archived = 0 var/tmp/fuel_burnt = 0 //FOR THE LOVE OF GOD PLEASE USE THIS PROC @@ -81,7 +90,7 @@ What are the archived variables for? update_values() return - //tg seems to like using these a lot +//tg seems to like using these a lot /datum/gas_mixture/proc/return_temperature() return temperature @@ -105,7 +114,7 @@ What are the archived variables for? var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) - if(trace_gases.len) + if(trace_gases && trace_gases.len) //sanity check because somehow the tracegases gets nulled? for(var/datum/gas/trace_gas in trace_gases) heat_capacity += trace_gas.moles*trace_gas.specific_heat @@ -189,17 +198,30 @@ What are the archived variables for? //Inputs: None //Outputs: 1 if graphic changed, 0 if unchanged - graphic = 0 + graphics = 0 + + // If configured and cold, maek ice + if(zas_settings.Get(/datum/ZAS_Setting/ice_formation)) + if(temperature <= TEMPERATURE_ICE_FORMATION && return_pressure()>MIN_PRESSURE_ICE_FORMATION) + // If we're just forming, do a probability check. Otherwise, KEEP IT ON~ + // This ordering will hopefully keep it from sampling random noise every damn tick. + //if(was_icy || (!was_icy && prob(25))) + graphics |= GRAPHICS_COLD + if(toxins > MOLES_PLASMA_VISIBLE) - graphic = 1 - else if(length(trace_gases)) + graphics |= GRAPHICS_PLASMA + if(length(trace_gases)) var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases if(sleeping_agent && (sleeping_agent.moles > 1)) - graphic = 2 - else - graphic = 0 + graphics |= GRAPHICS_N2O - return graphic != graphic_archived + /* + var/datum/gas/reagent = exact_locate(/datum/gas/reagent,trace_gases) + if(reagent && (reagent.moles > 0.1)) + graphics |= GRAPHICS_REAGENTS + */ + + return graphics != graphics_archived /datum/gas_mixture/proc/react(atom/dump_location) //Purpose: Calculating if it is possible for a fire to occur in the airmix @@ -298,7 +320,7 @@ What are the archived variables for? temperature_archived = temperature - graphic_archived = graphic + graphics_archived = graphics return 1 @@ -373,6 +395,10 @@ What are the archived variables for? //Inputs: How many moles to remove. //Outputs: Removed air. + // Fix a singuloth problem + if(group_multiplier==0) + return null + var/sum = total_moles() amount = min(amount,sum) //Can not take more air than tile has! if(amount <= 0) diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index d057bad4c3d..6909ccd213d 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -62,22 +62,34 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) . = 1 //get location and check if it is in a proper ZAS zone - var/turf/simulated/floor/S = loc - if(!S.zone) - del src + var/turf/simulated/S = loc if(!istype(S)) del src + if(!S.zone) + del src + var/datum/gas_mixture/air_contents = S.return_air() //get liquid fuels on the ground. var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S //and the volatile stuff from the air - //var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases + var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases + + //since the air is processed in fractions, we need to make sure not to have any minuscle residue or + //the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour + if(air_contents.oxygen < 0.001) + air_contents.oxygen = 0 + if(air_contents.toxins < 0.001) + air_contents.toxins = 0 + if(fuel) + if(fuel.moles < 0.001) + air_contents.trace_gases.Remove(fuel) //check if there is something to combust - if(!air_contents.check_combustability(liquid)) - del src + if(!air_contents.check_recombustability(liquid)) + //del src + RemoveFire() //get a firelevel and set the icon firelevel = air_contents.calculate_firelevel(liquid) @@ -95,15 +107,19 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) //im not sure how to implement a version that works for every creature so for now monkeys are firesafe for(var/mob/living/carbon/human/M in loc) M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans! - - - //spread! + for(var/atom/A in loc) + A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume()) + //spread for(var/direction in cardinal) if(S.air_check_directions&direction) //Grab all valid bordering tiles var/turf/simulated/enemy_tile = get_step(S, direction) if(istype(enemy_tile)) + var/datum/gas_mixture/acs = enemy_tile.return_air() + var/obj/effect/decal/cleanable/liquid_fuel/liq = locate() in enemy_tile + if(!acs) continue + if(!acs.check_recombustability(liq)) continue //If extinguisher mist passed over the turf it's trying to spread to, don't spread and //reduce firelevel. if(enemy_tile.fire_protection > world.time-30) @@ -112,25 +128,25 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) //Spread the fire. if(!(locate(/obj/fire) in enemy_tile)) - if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) + if( prob( 50 + 50 * (firelevel/zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier)) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) new/obj/fire(enemy_tile,firelevel) //seperate part of the present gas //this is done to prevent the fire burning all gases in a single pass - var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate) - + var/datum/gas_mixture/flow = air_contents.remove_ratio(zas_settings.Get(/datum/ZAS_Setting/fire_consumption_rate)) ///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR /////////////////////////////////////////////// if(flow) - if(flow.check_combustability(liquid)) + + if(flow.check_recombustability(liquid)) //Ensure flow temperature is higher than minimum fire temperatures. //this creates some energy ex nihilo but is necessary to get a fire started //lets just pretend this energy comes from the ignition source and dont mention this again //flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) //burn baby burn! - flow.zburn(liquid,1) + flow.zburn(liquid,1) //merge the air back S.assume_air(flow) @@ -158,6 +174,12 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) ..() +/obj/fire/proc/RemoveFire() + if (istype(loc, /turf/simulated)) + SetLuminosity(0) + loc = null + air_master.active_hotspots.Remove(src) + turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again. @@ -166,10 +188,10 @@ turf/simulated/apply_fire_protection() fire_protection = world.time -datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid,force_burn) +datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn) var/value = 0 - if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_combustability(liquid) ) + if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid)) var/total_fuel = 0 var/datum/gas/volatile_fuel/fuel = locate() in trace_gases @@ -203,38 +225,63 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid,force var/total_reactants = total_fuel + total_oxygen //determine the amount of reactants actually reacting - var/used_reactants_ratio = min( max(total_reactants * firelevel / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants + var/used_reactants_ratio = min( max(total_reactants * firelevel / zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier), 0.2), total_reactants) / total_reactants //remove and add gasses as calculated oxygen -= min(oxygen, total_oxygen * used_reactants_ratio ) - toxins -= min(toxins, toxins * used_fuel_ratio * used_reactants_ratio ) + toxins -= min(toxins, (toxins * used_fuel_ratio * used_reactants_ratio ) * 3) + if(toxins < 0) + toxins = 0 carbon_dioxide += max(2 * total_fuel, 0) if(fuel) - fuel.moles -= fuel.moles * used_fuel_ratio * used_reactants_ratio + fuel.moles -= (fuel.moles * used_fuel_ratio * used_reactants_ratio) * 5 //Fuel burns 5 times as quick if(fuel.moles <= 0) del fuel if(liquid) - liquid.amount -= liquid.amount * used_fuel_ratio * used_reactants_ratio + liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick + if(liquid.amount <= 0) del liquid //calculate the energy produced by the reaction and then set the new temperature of the mix - temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity() + temperature = (starting_energy + zas_settings.Get(/datum/ZAS_Setting/fire_fuel_energy_release) * total_fuel) / heat_capacity() update_values() value = total_reactants * used_reactants_ratio return value +datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_fuel/liquid) + //this is a copy proc to continue a fire after its been started. + + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + var/value = 0 + + if(oxygen && (toxins || fuel || liquid)) + if(liquid) + value = 1 + else if (toxins && !value) + value = 1 + else if(fuel && !value) + value = 1 + + return value + datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid) //this check comes up very often and is thus centralized here to ease adding stuff var/datum/gas/volatile_fuel/fuel = locate() in trace_gases var/value = 0 - if(oxygen > 0.01 && (toxins > 0.01 || (fuel && fuel.moles > 0.01) || liquid)) - value = 1 + if(oxygen && (toxins || fuel || liquid)) + if(liquid) + value = 1 + else if (toxins >= 0.7 && !value) + value = 1 + else if(fuel && !value) + if(fuel.moles >= 1.4) + value = 1 return value @@ -245,7 +292,7 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue var/total_fuel = 0 var/firelevel = 0 - if(check_combustability(liquid)) + if(check_recombustability(liquid)) total_fuel += toxins @@ -262,9 +309,9 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue //slows down the burning when the concentration of the reactants is low var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide) //calculates how close the mixture of the reactants is to the optimum - var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ** 2))) + var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ^2))) //toss everything together - firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier + firelevel = zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier) * mix_multiplier * dampening_multiplier return max( 0, firelevel) @@ -283,7 +330,7 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue //determine the multiplier //minimize this for low-pressure enviroments - var/mx = 5 * firelevel/vsc.fire_firelevel_multiplier * min(pressure / ONE_ATMOSPHERE, 1) + var/mx = 5 * firelevel/zas_settings.Get(/datum/ZAS_Setting/fire_firelevel_multiplier) * min(pressure / ONE_ATMOSPHERE, 1) //Get heat transfer coefficients for clothing. //skytodo: kill anyone who breaks things then orders me to fix them diff --git a/code/ZAS/NewSettings.dm b/code/ZAS/NewSettings.dm new file mode 100644 index 00000000000..f3821367f48 --- /dev/null +++ b/code/ZAS/NewSettings.dm @@ -0,0 +1,517 @@ +/* +ZAS Settings System 2.0 + +Okay, so VariableSettings is a mess of spaghetticode and + is about as flexible as a grandmother covered in + starch. + +This is an attempt to fix that by using getters and + setters instead of stupidity. It's a little more difficult + to code with, but dammit, it's better than hackery. + +NOTE: plc was merged into the main settings. We can set up + visual groups later. + +HOW2GET: + zas_setting.Get(/datum/ZAS_Setting/herp) + +HOW2SET: + zas_setting.Set(/datum/ZAS_Setting/herp, "dsfargeg") +*/ + +var/global/ZAS_Settings/zas_settings = new + +#define ZAS_TYPE_UNDEFINED -1 +#define ZAS_TYPE_BOOLEAN 0 +#define ZAS_TYPE_NUMERIC 1 + +/** +* ZAS Setting Datum +* +* Stores a single setting. +* @author N3X15 +* @package SS13 +* @subpackage ZAS +*/ +/datum/ZAS_Setting/ + var/name="Clown" // Friendly name. + var/desc="Honk" + var/value=null + var/valtype=ZAS_TYPE_UNDEFINED + +/datum/ZAS_Setting/fire_consumption_rate + name = "Fire - Air Consumption Ratio" + desc = "Ratio of air removed and combusted per tick." + valtype=ZAS_TYPE_NUMERIC + value = 0.75 + +/datum/ZAS_Setting/fire_firelevel_multiplier + value = 25 + name = "Fire - Firelevel Constant" + desc = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/fire_fuel_energy_release + value = 550000 + name = "Fire - Fuel energy release" + desc = "The energy in joule released when burning one mol of a burnable substance" + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_lightest_pressure + value = 20 + name = "Airflow - Small Movement Threshold %" + desc = "Percent of 1 Atm. at which items with the small weight classes will move." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_light_pressure + value = 35 + name = "Airflow - Medium Movement Threshold %" + desc = "Percent of 1 Atm. at which items with the medium weight classes will move." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_medium_pressure + value = 50 + name = "Airflow - Heavy Movement Threshold %" + desc = "Percent of 1 Atm. at which items with the largest weight classes will move." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_heavy_pressure + value = 65 + name = "Airflow - Mob Movement Threshold %" + desc = "Percent of 1 Atm. at which mobs will move." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_dense_pressure + value = 85 + name = "Airflow - Dense Movement Threshold %" + desc = "Percent of 1 Atm. at which items with canisters and closets will move." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_stun_pressure + value = 60 + name = "Airflow - Mob Stunning Threshold %" + desc = "Percent of 1 Atm. at which mobs will be stunned by airflow." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_stun_cooldown + value = 60 + name = "Aiflow Stunning - Cooldown" + desc = "How long, in tenths of a second, to wait before stunning them again." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_stun + value = 1 + name = "Airflow Impact - Stunning" + desc = "How much a mob is stunned when hit by an object." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_damage + value = 2 + name = "Airflow Impact - Damage" + desc = "Damage from airflow impacts." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_speed_decay + value = 1.5 + name = "Airflow Speed Decay" + desc = "How rapidly the speed gained from airflow decays." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_delay + value = 30 + name = "Airflow Retrigger Delay" + desc = "Time in deciseconds before things can be moved by airflow again." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/airflow_mob_slowdown + value = 1 + name = "Airflow Slowdown" + desc = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + valtype=ZAS_TYPE_NUMERIC + +// N3X15 - Added back in so we can tweak performance. +/datum/ZAS_Setting/airflow_push + name="Airflow - Push" + value = 0 + desc="1=yes please rape my server, 0=no" + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/connection_insulation + value = 0.4 + name = "Connections - Insulation" + desc = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive." + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/connection_temperature_delta + value = 10 + name = "Connections - Temperature Difference" + desc = "The smallest temperature difference which will cause heat to travel through doors." + valtype=ZAS_TYPE_NUMERIC + +// N3X15 - Ice is disabled by default, per Pomf's request. +/datum/ZAS_Setting/ice_formation + name="Airflow - Enable Ice Formation" + value = 0 + desc="1=yes, 0=no - Slippin' and slidin' when pressure > 10kPa and temperature < 273K" + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/space_isnt_cold + name="Airflow - Disable Cold Space" + value = 0 // Pomf requested + desc="1=yes, 0=no - Disables space behaving as being very fucking cold (0K)." + valtype=ZAS_TYPE_BOOLEAN + + +/////////////////////////////////////// +// PLASMA SHIT +/////////////////////////////////////// +// ALL CAPS BECAUSE PLASMA IS HARDCORE YO +// And I'm too lazy to fix the refs. + +/datum/ZAS_Setting/PLASMA_DMG + name = "Plasma Damage Amount" + desc = "Self Descriptive" + value = 3 + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/CLOTH_CONTAMINATION + name = "Cloth Contamination" + desc = "If this is on, plasma does damage by getting into cloth." + value = 1 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/PLASMAGUARD_ONLY + name = "PlasmaGuard Only" + desc = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." + value = 0 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/GENETIC_CORRUPTION + name = "Genetic Corruption Chance" + desc = "Chance of genetic corruption as well as toxic damage, X in 10,000." + value = 0 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/SKIN_BURNS + name = "Skin Burns" + desc = "Plasma has an effect similar to mustard gas on the un-suited." + value = 0 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/EYE_BURNS + name = "Eye Burns" + desc = "Plasma burns the eyes of anyone not wearing eye protection." + value = 1 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/CONTAMINATION_LOSS + name = "Contamination Loss" + desc = "How much toxin damage is dealt from contaminated clothing" + value = 0.02 //Per tick? ASK ARYN + valtype=ZAS_TYPE_NUMERIC + +/datum/ZAS_Setting/PLASMA_HALLUCINATION + name = "Plasma Hallucination" + desc = "Does being in plasma cause you to hallucinate?" + value = 0 + valtype=ZAS_TYPE_BOOLEAN + +/datum/ZAS_Setting/N2O_HALLUCINATION + name = "N2O Hallucination" + desc = "Does being in sleeping gas cause you to hallucinate?" + value = 1 + valtype=ZAS_TYPE_BOOLEAN + +/** +* ZAS Settings +* +* Stores our settings for ZAS in an editable form. +* @author N3X15 +* @package SS13 +* @subpackage ZAS +*/ +/ZAS_Settings + // INTERNAL USE ONLY + var/list/datum/ZAS_Setting/settings = list() + +/ZAS_Settings/New() + .=..() + for(var/S in typesof(/datum/ZAS_Setting) - /datum/ZAS_Setting) + var/id=idfrompath("[S]") + //testing("Creating zas_settings\[[id]\] = new [S]") + src.settings[id]=new S + + + if(fexists("config/ZAS.txt") == 0) + Save() + Load() + +/ZAS_Settings/proc/Save() + var/F = file("config/ZAS.txt") + fdel(F) + for(var/id in src.settings) + var/datum/ZAS_Setting/setting = src.settings[id] + F << "# [setting.name]" + F << "# [setting.desc]" + F << "[id] [setting.value]" + F << "" + +/ZAS_Settings/proc/Load() + for(var/t in file2list("config/ZAS.txt")) + if(!t) continue + + t = trim(t) + if (length(t) == 0) + continue + else if (copytext(t, 1, 2) == "#") + continue + + var/pos = findtext(t, " ") + var/name = null + var/value = null + + if (pos) + name = copytext(t, 1, pos) + value = copytext(t, pos + 1) + else + name = t + + if (!name) + continue + + src.SetFromConfig(name,value) + +// INTERNAL USE ONLY +/ZAS_Settings/proc/idfrompath(var/str) + return replacetext(str,"/datum/ZAS_Setting/","") + +// INTERNAL USE ONLY +/ZAS_Settings/proc/ChangeSetting(var/user,var/id) + var/datum/ZAS_Setting/setting = src.settings[id] + var/displayedValue="" + switch(setting.valtype) + if(ZAS_TYPE_NUMERIC) + setting.value = input(user,"Enter a number:","Settings",setting.value) as num + displayedValue="\"[setting.value]\"" + /* + if(ZAS_TYPE_BITFLAG) + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + */ + if(ZAS_TYPE_BOOLEAN) + setting.value = !setting.value + displayedValue = (setting.value) ? "ON" : "OFF" + /* + if(ZAS_TYPE_STRING) + setting.value = input(user,"Enter text:","Settings",newvar) as message + */ + else + error("[id] has an invalid typeval.") + return + world << "\blue [key_name(user)] changed ZAS setting [setting.name] to [displayedValue]." + + ChangeSettingsDialog(user) + +/** +* Set the value of a setting. +* +* Recommended to use the actual type of the setting rather than the ID, since +* this will allow for the compiler to check the validity of id. Kinda. +* +* @param id Either the typepath of the desired setting, or the string ID of the setting. +* @param value The value that the setting should be set to. +*/ +/ZAS_Settings/proc/Set(var/id, var/value) + var/datum/ZAS_Setting/setting = src.settings[idfrompath(id)] + setting.value=value + +// INTERNAL USE ONLY +/ZAS_Settings/proc/SetFromConfig(var/id, var/value) + var/datum/ZAS_Setting/setting = src.settings[id] + switch(setting.valtype) + if(ZAS_TYPE_NUMERIC) + setting.value = text2num(value) + /* + if(ZAS_TYPE_BITFLAG) + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + */ + if(ZAS_TYPE_BOOLEAN) + setting.value = (value == "1") + /* + if(ZAS_TYPE_STRING) + setting.value = input(user,"Enter text:","Settings",newvar) as message + */ + +/** +* Get a setting. +* +* Recommended to use the actual type of the setting rather than the ID, since +* this will allow for the compiler to check the validity of id. Kinda. +* +* @param id Either the typepath of the desired setting, or the string ID of the setting. +* @returns Value of the desired setting +*/ +/ZAS_Settings/proc/Get(var/id) + if(ispath(id)) + id="[id]" + var/datum/ZAS_Setting/setting = src.settings[idfrompath(id)] + if(!setting || !istype(setting)) + world.log << "ZAS_SETTING DEBUG: [id] | [idfrompath(id)]" + return setting.value + +/ZAS_Settings/proc/ChangeSettingsDialog(mob/user) + var/dat = {" + + + ZAS Settings 2.0 + + + +

ZAS Configuration

+

Save Settings | Load Settings

+

Please note that changing these settings can and probably will result in death, destruction and mayhem. Change at your own risk.

+
"} + for(var/id in src.settings) + var/datum/ZAS_Setting/s = src.settings[id] + + // AUTOFIXED BY fix_string_idiocy.py + // C:\Users\Rob\Documents\Projects\vgstation13\code\ZAS\NewSettings.dm:393: dat += "
[s.name] = [s.value] \[Change\]
" + dat += {"
[s.name] = [s.value] \[Change\]
+
[s.desc]
"} + // END AUTOFIX + dat += "
" + user << browse(dat,"window=settings") + +/ZAS_Settings/Topic(href,href_list) + if("changevar" in href_list) + ChangeSetting(usr,href_list["changevar"]) + if("save" in href_list) + var/sure = input(usr,"Are you sure? This will overwrite your ZAS configuration!","Overwrite ZAS.txt?", "No") in list("Yes","No") + if(sure=="Yes") + Save() + message_admins("[key_name(usr)] saved ZAS settings to disk.") + if("load" in href_list) + var/sure = input(usr,"Are you sure?","Reload ZAS.txt?", "No") in list("Yes","No") + if(sure=="Yes") + Load() + message_admins("[key_name(usr)] reloaded ZAS settings from disk.") + +/ZAS_Settings/proc/SetDefault(var/mob/user) + var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!", "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") + var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices + if(!def) + return + switch(def) + if("Plasma - Standard") + Set("CLOTH_CONTAMINATION", 1) //If this is on, plasma does damage by getting into cloth. + Set("PLASMAGUARD_ONLY", 0) + Set("GENETIC_CORRUPTION", 0) //Chance of genetic corruption as well as toxic damage, X in 1000. + Set("SKIN_BURNS", 0) //Plasma has an effect similar to mustard gas on the un-suited. + Set("EYE_BURNS", 1) //Plasma burns the eyes of anyone not wearing eye protection. + Set("PLASMA_HALLUCINATION", 0) + Set("CONTAMINATION_LOSS", 0.02) + + if("Plasma - Low Hazard") + Set("CLOTH_CONTAMINATION", 0) //If this is on, plasma does damage by getting into cloth. + Set("PLASMAGUARD_ONLY", 0) + Set("GENETIC_CORRUPTION", 0) //Chance of genetic corruption as well as toxic damage, X in 1000 + Set("SKIN_BURNS", 0) //Plasma has an effect similar to mustard gas on the un-suited. + Set("EYE_BURNS", 1) //Plasma burns the eyes of anyone not wearing eye protection. + Set("PLASMA_HALLUCINATION", 0) + Set("CONTAMINATION_LOSS", 0.01) + + if("Plasma - High Hazard") + Set("CLOTH_CONTAMINATION", 1) //If this is on, plasma does damage by getting into cloth. + Set("PLASMAGUARD_ONLY", 0) + Set("GENETIC_CORRUPTION", 0) //Chance of genetic corruption as well as toxic damage, X in 1000. + Set("SKIN_BURNS", 1) //Plasma has an effect similar to mustard gas on the un-suited. + Set("EYE_BURNS", 1) //Plasma burns the eyes of anyone not wearing eye protection. + Set("PLASMA_HALLUCINATION", 1) + Set("CONTAMINATION_LOSS", 0.05) + + if("Plasma - Oh Shit!") + Set("CLOTH_CONTAMINATION", 1) //If this is on, plasma does damage by getting into cloth. + Set("PLASMAGUARD_ONLY", 1) + Set("GENETIC_CORRUPTION", 5) //Chance of genetic corruption as well as toxic damage, X in 1000. + Set("SKIN_BURNS", 1) //Plasma has an effect similar to mustard gas on the un-suited. + Set("EYE_BURNS", 1) //Plasma burns the eyes of anyone not wearing eye protection. + Set("PLASMA_HALLUCINATION", 1) + Set("CONTAMINATION_LOSS", 0.075) + + if("ZAS - Normal") + Set("airflow_push", 0) + Set("airflow_lightest_pressure", 20) + Set("airflow_light_pressure", 35) + Set("airflow_medium_pressure", 50) + Set("airflow_heavy_pressure", 65) + Set("airflow_dense_pressure", 85) + Set("airflow_stun_pressure", 60) + Set("airflow_stun_cooldown", 60) + Set("airflow_stun", 1) + Set("airflow_damage", 2) + Set("airflow_speed_decay", 1.5) + Set("airflow_delay", 30) + Set("airflow_mob_slowdown", 1) + + if("ZAS - Forgiving") + Set("airflow_push", 0) + Set("airflow_lightest_pressure", 45) + Set("airflow_light_pressure", 60) + Set("airflow_medium_pressure", 120) + Set("airflow_heavy_pressure", 110) + Set("airflow_dense_pressure", 200) + Set("airflow_stun_pressure", 150) + Set("airflow_stun_cooldown", 90) + Set("airflow_stun", 0.15) + Set("airflow_damage", 0.15) + Set("airflow_speed_decay", 1.5) + Set("airflow_delay", 50) + Set("airflow_mob_slowdown", 0) + + if("ZAS - Dangerous") + Set("airflow_push", 1) + Set("airflow_lightest_pressure", 15) + Set("airflow_light_pressure", 30) + Set("airflow_medium_pressure", 45) + Set("airflow_heavy_pressure", 55) + Set("airflow_dense_pressure", 70) + Set("airflow_stun_pressure", 50) + Set("airflow_stun_cooldown", 50) + Set("airflow_stun", 2) + Set("airflow_damage", 3) + Set("airflow_speed_decay", 1.2) + Set("airflow_delay", 25) + Set("airflow_mob_slowdown", 2) + + if("ZAS - Hellish") + Set("airflow_push", 1) + Set("airflow_lightest_pressure", 20) + Set("airflow_light_pressure", 30) + Set("airflow_medium_pressure", 40) + Set("airflow_heavy_pressure", 50) + Set("airflow_dense_pressure", 60) + Set("airflow_stun_pressure", 40) + Set("airflow_stun_cooldown", 40) + Set("airflow_stun", 3) + Set("airflow_damage", 4) + Set("airflow_speed_decay", 1) + Set("airflow_delay", 20) + Set("airflow_mob_slowdown", 3) + world << "\blue [key_name(usr)] loaded ZAS preset [def]" \ No newline at end of file diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Plasma.dm index 9f0e95f6617..5936f3843b0 100644 --- a/code/ZAS/Plasma.dm +++ b/code/ZAS/Plasma.dm @@ -1,43 +1,5 @@ var/image/contamination_overlay = image('icons/effects/contamination.dmi') -/pl_control - var/PLASMA_DMG = 3 - var/PLASMA_DMG_NAME = "Plasma Damage Amount" - var/PLASMA_DMG_DESC = "Self Descriptive" - - var/CLOTH_CONTAMINATION = 1 - var/CLOTH_CONTAMINATION_NAME = "Cloth Contamination" - var/CLOTH_CONTAMINATION_DESC = "If this is on, plasma does damage by getting into cloth." - - var/PLASMAGUARD_ONLY = 0 - var/PLASMAGUARD_ONLY_NAME = "\"PlasmaGuard Only\"" - var/PLASMAGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." - - var/GENETIC_CORRUPTION = 0 - var/GENETIC_CORRUPTION_NAME = "Genetic Corruption Chance" - var/GENETIC_CORRUPTION_DESC = "Chance of genetic corruption as well as toxic damage, X in 10,000." - - var/SKIN_BURNS = 0 - var/SKIN_BURNS_DESC = "Plasma has an effect similar to mustard gas on the un-suited." - var/SKIN_BURNS_NAME = "Skin Burns" - - var/EYE_BURNS = 1 - var/EYE_BURNS_NAME = "Eye Burns" - var/EYE_BURNS_DESC = "Plasma burns the eyes of anyone not wearing eye protection." - - var/CONTAMINATION_LOSS = 0.02 - var/CONTAMINATION_LOSS_NAME = "Contamination Loss" - var/CONTAMINATION_LOSS_DESC = "How much toxin damage is dealt from contaminated clothing" //Per tick? ASK ARYN - - var/PLASMA_HALLUCINATION = 0 - var/PLASMA_HALLUCINATION_NAME = "Plasma Hallucination" - var/PLASMA_HALLUCINATION_DESC = "Does being in plasma cause you to hallucinate?" - - var/N2O_HALLUCINATION = 1 - var/N2O_HALLUCINATION_NAME = "N2O Hallucination" - var/N2O_HALLUCINATION_DESC = "Does being in sleeping gas cause you to hallucinate?" - - obj/var/contaminated = 0 @@ -78,21 +40,21 @@ obj/var/contaminated = 0 //Handles all the bad things plasma can do. //Contamination - if(vsc.plc.CLOTH_CONTAMINATION) contaminate() + if(zas_settings.Get(/datum/ZAS_Setting/CLOTH_CONTAMINATION)) contaminate() //Anything else requires them to not be dead. if(stat >= 2) return //Burn skin if exposed. - if(vsc.plc.SKIN_BURNS) + if(zas_settings.Get(/datum/ZAS_Setting/SKIN_BURNS)) if(!pl_head_protected() || !pl_suit_protected()) burn_skin(0.75) if(prob(20)) src << "\red Your skin burns!" updatehealth() //Burn eyes if exposed. - if(vsc.plc.EYE_BURNS) + if(zas_settings.Get(/datum/ZAS_Setting/EYE_BURNS)) if(!head) if(!wear_mask) burn_eyes() @@ -108,8 +70,8 @@ obj/var/contaminated = 0 burn_eyes() //Genetic Corruption - if(vsc.plc.GENETIC_CORRUPTION) - if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION) + if(zas_settings.Get(/datum/ZAS_Setting/GENETIC_CORRUPTION)) + if(rand(1,10000) < zas_settings.Get(/datum/ZAS_Setting/GENETIC_CORRUPTION)) randmutb(src) src << "\red High levels of toxins cause you to spontaneously mutate." domutcheck(src,null) @@ -128,7 +90,7 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/pl_head_protected() //Checks if the head is adequately sealed. if(head) - if(vsc.plc.PLASMAGUARD_ONLY) + if(zas_settings.Get(/datum/ZAS_Setting/PLASMAGUARD_ONLY)) if(head.flags & PLASMAGUARD) return 1 else if(head.flags & HEADCOVERSEYES) @@ -138,7 +100,7 @@ obj/var/contaminated = 0 /mob/living/carbon/human/proc/pl_suit_protected() //Checks if the suit is adequately sealed. if(wear_suit) - if(vsc.plc.PLASMAGUARD_ONLY) + if(zas_settings.Get(/datum/ZAS_Setting/PLASMAGUARD_ONLY)) if(wear_suit.flags & PLASMAGUARD) return 1 else if(wear_suit.flags_inv & HIDEJUMPSUIT) return 1 @@ -154,7 +116,7 @@ obj/var/contaminated = 0 turf/Entered(obj/item/I) . = ..() //Items that are in plasma, but not on a mob, can still be contaminated. - if(istype(I) && vsc.plc.CLOTH_CONTAMINATION) + if(istype(I) && zas_settings.Get(/datum/ZAS_Setting/CLOTH_CONTAMINATION)) var/datum/gas_mixture/env = return_air(1) if(!env) return diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index 743eadd3178..09501ffc78a 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -1,68 +1,75 @@ var/global/vs_control/vsc = new -/vs_control - var/fire_consuption_rate = 0.25 - var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" - var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." +// Whoever made this fucking thing: I hate you so much. +vs_control/var + // N3X15 - Added back in so we can tweak performance. + airflow_push = 0 + airflow_push_NAME="Airflow - Push shit around" + airflow_push_DESC="1=yes please rape my server, 0=no" + airflow_push_METHOD="Toggle" // See ChangeSettings(). I'd rather not let people break this. - var/fire_firelevel_multiplier = 25 - var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" - var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." + fire_consuption_rate = 0.75 + fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" + fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." - var/fire_fuel_energy_release = 397000 - var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" - var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" + fire_firelevel_multiplier = 25 + fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" + fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." + + fire_fuel_energy_release = 550000 + fire_fuel_energy_release_NAME = "Fire - Fuel energy release" + fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" - var/airflow_lightest_pressure = 20 - var/airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" - var/airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." + airflow_lightest_pressure = 20 + airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" + airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." - var/airflow_light_pressure = 35 - var/airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" - var/airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." + airflow_light_pressure = 35 + airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" + airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." - var/airflow_medium_pressure = 50 - var/airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" - var/airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." + airflow_medium_pressure = 50 + airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" + airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." - var/airflow_heavy_pressure = 65 - var/airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" - var/airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." + airflow_heavy_pressure = 65 + airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" + airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." - var/airflow_dense_pressure = 85 - var/airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" - var/airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." + airflow_dense_pressure = 85 + airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" + airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." - var/airflow_stun_pressure = 60 - var/airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" - var/airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." + airflow_stun_pressure = 60 + airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" + airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." - var/airflow_stun_cooldown = 60 - var/airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" - var/airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." + airflow_stun_cooldown = 60 + airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" + airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." - var/airflow_stun = 1 - var/airflow_stun_NAME = "Airflow Impact - Stunning" - var/airflow_stun_DESC = "How much a mob is stunned when hit by an object." + airflow_stun = 1 + airflow_stun_NAME = "Airflow Impact - Stunning" + airflow_stun_DESC = "How much a mob is stunned when hit by an object." - var/airflow_damage = 2 - var/airflow_damage_NAME = "Airflow Impact - Damage" - var/airflow_damage_DESC = "Damage from airflow impacts." + airflow_damage = 2 + airflow_damage_NAME = "Airflow Impact - Damage" + airflow_damage_DESC = "Damage from airflow impacts." - var/airflow_speed_decay = 1.5 - var/airflow_speed_decay_NAME = "Airflow Speed Decay" - var/airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." + airflow_speed_decay = 1.5 + airflow_speed_decay_NAME = "Airflow Speed Decay" + airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." - var/airflow_delay = 30 - var/airflow_delay_NAME = "Airflow Retrigger Delay" - var/airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." + airflow_delay = 30 + airflow_delay_NAME = "Airflow Retrigger Delay" + airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." - var/airflow_mob_slowdown = 1 - var/airflow_mob_slowdown_NAME = "Airflow Slowdown" - var/airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + airflow_mob_slowdown = 1 + airflow_mob_slowdown_NAME = "Airflow Slowdown" + airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." - var/connection_insulation = 1 + var/connection_insulation = 0.4 var/connection_insulation_NAME = "Connections - Insulation" var/connection_insulation_DESC = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive." @@ -70,263 +77,264 @@ var/global/vs_control/vsc = new var/connection_temperature_delta_NAME = "Connections - Temperature Difference" var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors." +vs_control + var + list/settings = list() + list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") // Oh jesus why. Learn to shift bits, you idiots. + pl_control/plc = new() -/vs_control/var/list/settings = list() -/vs_control/var/list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") -/vs_control/var/pl_control/plc = new() + New() + . = ..() + settings = vars.Copy() -/vs_control/New() - . = ..() - settings = vars.Copy() - - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) - settings -= V - - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) settings -= V - settings -= "settings" - settings -= "bitflags" - settings -= "plc" + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) + settings -= V -/vs_control/proc/ChangeSettingsDialog(mob/user,list/L) - //var/which = input(user,"Choose a setting:") in L - var/dat = "" - for(var/ch in L) - if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue + settings -= "settings" + settings -= "bitflags" + settings -= "plc" + + proc/ChangeSettingsDialog(mob/user,list/L) + //var/which = input(user,"Choose a setting:") in L + var/dat = "" + for(var/ch in L) + if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue + var/vw + var/vw_desc = "No Description." + var/vw_name = ch + if(ch in plc.settings) + vw = plc.vars[ch] + if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"] + if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"] + else + vw = vars[ch] + if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] + if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] + dat += "[vw_name] = [vw] \[Change\]
" + dat += "[vw_desc]

" + user << browse(dat,"window=settings") + Topic(href,href_list) + if("changevar" in href_list) + ChangeSetting(usr,href_list["changevar"]) + proc/ChangeSetting(mob/user,ch) var/vw - var/vw_desc = "No Description." - var/vw_name = ch + var/how = "Text" + var/display_description = ch if(ch in plc.settings) vw = plc.vars[ch] - if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"] - if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"] + if("[ch]_NAME" in plc.vars) + display_description = plc.vars["[ch]_NAME"] + if("[ch]_METHOD" in plc.vars) + how = plc.vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" else vw = vars[ch] - if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] - if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] - dat += "[vw_name] = [vw] \[Change\]
" - dat += "[vw_desc]

" - user << browse(dat,"window=settings") - -/vs_control/Topic(href,href_list) - if("changevar" in href_list) - ChangeSetting(usr,href_list["changevar"]) - -/vs_control/proc/ChangeSetting(mob/user,ch) - var/vw - var/how = "Text" - var/display_description = ch - if(ch in plc.settings) - vw = plc.vars[ch] - if("[ch]_NAME" in plc.vars) - display_description = plc.vars["[ch]_NAME"] - if("[ch]_METHOD" in plc.vars) - how = plc.vars["[ch]_METHOD"] + if("[ch]_NAME" in vars) + display_description = vars["[ch]_NAME"] + if("[ch]_METHOD" in vars) + how = vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + var/newvar = vw + switch(how) + if("Numeric") + newvar = input(user,"Enter a number:","Settings",newvar) as num + if("Bit Flag") + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + if("Toggle") + newvar = !newvar + if("Text") + newvar = input(user,"Enter a string:","Settings",newvar) as text + if("Long Text") + newvar = input(user,"Enter text:","Settings",newvar) as message + vw = newvar + if(ch in plc.settings) + plc.vars[ch] = vw else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" - else - vw = vars[ch] - if("[ch]_NAME" in vars) - display_description = vars["[ch]_NAME"] - if("[ch]_METHOD" in vars) - how = vars["[ch]_METHOD"] + vars[ch] = vw + if(how == "Toggle") + newvar = (newvar?"ON":"OFF") + world << "\blue [key_name(user)] changed the setting [display_description] to [newvar]." + if(ch in plc.settings) + ChangeSettingsDialog(user,plc.settings) else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" - var/newvar = vw - switch(how) - if("Numeric") - newvar = input(user,"Enter a number:","Settings",newvar) as num - if("Bit Flag") - var/flag = input(user,"Toggle which bit?","Settings") in bitflags - flag = text2num(flag) - if(newvar & flag) - newvar &= ~flag - else - newvar |= flag - if("Toggle") - newvar = !newvar - if("Text") - newvar = input(user,"Enter a string:","Settings",newvar) as text - if("Long Text") - newvar = input(user,"Enter text:","Settings",newvar) as message - vw = newvar - if(ch in plc.settings) - plc.vars[ch] = vw - else - vars[ch] = vw - if(how == "Toggle") - newvar = (newvar?"ON":"OFF") - world << "\blue [key_name(user)] changed the setting [display_description] to [newvar]." - if(ch in plc.settings) - ChangeSettingsDialog(user,plc.settings) - else - ChangeSettingsDialog(user,settings) + ChangeSettingsDialog(user,settings) + proc/RandomizeWithProbability() + for(var/V in settings) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + newvalue = roll(vars["[V]_RANDOM"]) + else + newvalue = vars[V] + V = newvalue -/vs_control/proc/RandomizeWithProbability() - for(var/V in settings) + proc/ChangePlasma() + for(var/V in plc.settings) + plc.Randomize(V) + + proc/SetDefault(var/mob/user) + var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\ + "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") + var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices + if(!def) + return + switch(def) + if("Plasma - Standard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.02 + + if("Plasma - Low Hazard") + plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 + plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.01 + + if("Plasma - High Hazard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.05 + + if("Plasma - Oh Shit!") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 1 + plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.075 + + if("ZAS - Normal") + airflow_push=0 + airflow_lightest_pressure = 20 + airflow_light_pressure = 35 + airflow_medium_pressure = 50 + airflow_heavy_pressure = 65 + airflow_dense_pressure = 85 + airflow_stun_pressure = 60 + airflow_stun_cooldown = 60 + airflow_stun = 1 + airflow_damage = 2 + airflow_speed_decay = 1.5 + airflow_delay = 30 + airflow_mob_slowdown = 1 + + if("ZAS - Forgiving") + airflow_push=0 + airflow_lightest_pressure = 45 + airflow_light_pressure = 60 + airflow_medium_pressure = 120 + airflow_heavy_pressure = 110 + airflow_dense_pressure = 200 + airflow_stun_pressure = 150 + airflow_stun_cooldown = 90 + airflow_stun = 0.15 + airflow_damage = 0.15 + airflow_speed_decay = 1.5 + airflow_delay = 50 + airflow_mob_slowdown = 0 + + if("ZAS - Dangerous") + airflow_push=1 + airflow_lightest_pressure = 15 + airflow_light_pressure = 30 + airflow_medium_pressure = 45 + airflow_heavy_pressure = 55 + airflow_dense_pressure = 70 + airflow_stun_pressure = 50 + airflow_stun_cooldown = 50 + airflow_stun = 2 + airflow_damage = 3 + airflow_speed_decay = 1.2 + airflow_delay = 25 + airflow_mob_slowdown = 2 + + if("ZAS - Hellish") + airflow_push=1 + airflow_lightest_pressure = 20 + airflow_light_pressure = 30 + airflow_medium_pressure = 40 + airflow_heavy_pressure = 50 + airflow_dense_pressure = 60 + airflow_stun_pressure = 40 + airflow_stun_cooldown = 40 + airflow_stun = 3 + airflow_damage = 4 + airflow_speed_decay = 1 + airflow_delay = 20 + airflow_mob_slowdown = 3 + + + world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\"" + +pl_control + var/list/settings = list() + New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) + settings -= V + + settings -= "settings" + proc/Randomize(V) var/newvalue if("[V]_RANDOM" in vars) if(isnum(vars["[V]_RANDOM"])) newvalue = prob(vars["[V]_RANDOM"]) else if(istext(vars["[V]_RANDOM"])) - newvalue = roll(vars["[V]_RANDOM"]) + var/txt = vars["[V]_RANDOM"] + if(findtextEx(txt,"PROB")) + txt = text2list(txt,"/") + txt[1] = replacetext(txt[1],"PROB","") + var/p = text2num(txt[1]) + var/r = txt[2] + if(prob(p)) + newvalue = roll(r) + else + newvalue = vars[V] + else if(findtextEx(txt,"PICK")) + txt = replacetext(txt,"PICK","") + txt = text2list(txt,",") + newvalue = pick(txt) + else + newvalue = roll(txt) else newvalue = vars[V] - V = newvalue - -/vs_control/proc/ChangePlasma() - for(var/V in plc.settings) - plc.Randomize(V) - -/vs_control/proc/SetDefault(var/mob/user) - var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\ - "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") - var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices - if(!def) - return - switch(def) - if("Plasma - Standard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 - plc.CONTAMINATION_LOSS = 0.02 - - if("Plasma - Low Hazard") - plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 - plc.CONTAMINATION_LOSS = 0.01 - - if("Plasma - High Hazard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 - plc.CONTAMINATION_LOSS = 0.05 - - if("Plasma - Oh Shit!") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 1 - plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 - plc.CONTAMINATION_LOSS = 0.075 - - if("ZAS - Normal") - airflow_lightest_pressure = 20 - airflow_light_pressure = 35 - airflow_medium_pressure = 50 - airflow_heavy_pressure = 65 - airflow_dense_pressure = 85 - airflow_stun_pressure = 60 - airflow_stun_cooldown = 60 - airflow_stun = 1 - airflow_damage = 2 - airflow_speed_decay = 1.5 - airflow_delay = 30 - airflow_mob_slowdown = 1 - - if("ZAS - Forgiving") - airflow_lightest_pressure = 45 - airflow_light_pressure = 60 - airflow_medium_pressure = 120 - airflow_heavy_pressure = 110 - airflow_dense_pressure = 200 - airflow_stun_pressure = 150 - airflow_stun_cooldown = 90 - airflow_stun = 0.15 - airflow_damage = 0.15 - airflow_speed_decay = 1.5 - airflow_delay = 50 - airflow_mob_slowdown = 0 - - if("ZAS - Dangerous") - airflow_lightest_pressure = 15 - airflow_light_pressure = 30 - airflow_medium_pressure = 45 - airflow_heavy_pressure = 55 - airflow_dense_pressure = 70 - airflow_stun_pressure = 50 - airflow_stun_cooldown = 50 - airflow_stun = 2 - airflow_damage = 3 - airflow_speed_decay = 1.2 - airflow_delay = 25 - airflow_mob_slowdown = 2 - - if("ZAS - Hellish") - airflow_lightest_pressure = 20 - airflow_light_pressure = 30 - airflow_medium_pressure = 40 - airflow_heavy_pressure = 50 - airflow_dense_pressure = 60 - airflow_stun_pressure = 40 - airflow_stun_cooldown = 40 - airflow_stun = 3 - airflow_damage = 4 - airflow_speed_decay = 1 - airflow_delay = 20 - airflow_mob_slowdown = 3 - - - world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\"" - -/pl_control/var/list/settings = list() - -/pl_control/New() - . = ..() - settings = vars.Copy() - - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) - settings -= V - - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) - settings -= V - - settings -= "settings" - -/pl_control/proc/Randomize(V) - var/newvalue - if("[V]_RANDOM" in vars) - if(isnum(vars["[V]_RANDOM"])) - newvalue = prob(vars["[V]_RANDOM"]) - else if(istext(vars["[V]_RANDOM"])) - var/txt = vars["[V]_RANDOM"] - if(findtextEx(txt,"PROB")) - txt = text2list(txt,"/") - txt[1] = replacetext(txt[1],"PROB","") - var/p = text2num(txt[1]) - var/r = txt[2] - if(prob(p)) - newvalue = roll(r) - else - newvalue = vars[V] - else if(findtextEx(txt,"PICK")) - txt = replacetext(txt,"PICK","") - txt = text2list(txt,",") - newvalue = pick(txt) - else - newvalue = roll(txt) - else - newvalue = vars[V] - vars[V] = newvalue + vars[V] = newvalue diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 04af9a05283..e7f5f4402f8 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -20,6 +20,15 @@ return GM +// For new turfs +/turf/proc/copy_air_from(var/turf/T) + oxygen = T.oxygen + carbon_dioxide = T.carbon_dioxide + nitrogen = T.nitrogen + toxins = T.toxins + + temperature = T.temperature + /turf/remove_air(amount as num) var/datum/gas_mixture/GM = new @@ -36,14 +45,11 @@ return GM /turf/simulated/var/current_graphic = null - /turf/simulated/var/tmp/datum/gas_mixture/air - /turf/simulated/var/tmp/processing = 1 - /turf/simulated/var/tmp/air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update - /turf/simulated/var/tmp/obj/fire/active_hotspot +/turf/simulated/var/tmp/was_icy=0 /turf/simulated/proc/update_visuals() overlays = null @@ -51,12 +57,47 @@ var/siding_icon_state = return_siding_icon_state() if(siding_icon_state) overlays += image('icons/turf/floors.dmi',siding_icon_state) + + // ONLY USED IF ZAS_SETTINGS SAYS SO. var/datum/gas_mixture/model = return_air() - switch(model.graphic) - if(1) - overlays.Add(plmaster) //TODO: Make invisible plasma an option - if(2) - overlays.Add(slmaster) + if(model.graphics & GRAPHICS_COLD) + if(!was_icy) + wet=3 // Custom ice + was_icy=1 + var/o="" + //if(is_plating()) + // o="snowfloor_s" + //else + if(is_plasteel_floor()) + o="snowfloor" + if(o!="") + overlays += image('icons/turf/overlays.dmi',o) + else + if(was_icy) + wet=0 + was_icy=0 + if(prob(10)) + wet = 1 + if(wet_overlay) + overlays -= wet_overlay + wet_overlay = null + wet_overlay = image('icons/effects/water.dmi',src,"wet_floor") + overlays += wet_overlay + + spawn(800) + if (!istype(src)) return + if(wet >= 2) return + wet = 0 + if(wet_overlay) + overlays -= wet_overlay + wet_overlay = null + if(model.graphics & GRAPHICS_PLASMA) + overlays.Add(plmaster) + if(model.graphics & GRAPHICS_N2O) + overlays.Add(slmaster) + //if(model.graphics & GRAPHICS_REAGENTS) + // overlays.Add(slmaster/*rlmaster*/) + /turf/simulated/New() ..() @@ -92,6 +133,12 @@ air_master.tiles_to_update.Add(tile) ..() +/turf/simulated/copy_air_from(var/turf/T) + //if(istype(T,/turf/simulated)) + // var/turf/simulated/ST=T + // air=ST.air + air=T.return_air() + /turf/simulated/assume_air(datum/gas_mixture/giver) if(!giver) return 0 if(zone) @@ -113,6 +160,8 @@ if(zone) var/datum/gas_mixture/removed = null removed = zone.air.remove(amount) + if(zone.air.check_tile_graphic()) + update_visuals(zone.air) return removed else if(air) var/datum/gas_mixture/removed = null @@ -162,6 +211,8 @@ air_master.connections_to_check |= C if(zone && !zone.rebuild) + if(zone.air.check_tile_graphic()) + update_visuals(zone.air) for(var/direction in cardinal) var/turf/T = get_step(src,direction) if(!istype(T)) diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index 860f57cd370..c538a6c7c2a 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -170,7 +170,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs if(unsimulated_tiles.len) var/moved_air = ShareSpace(air,unsimulated_tiles) - if(moved_air > vsc.airflow_lightest_pressure) + if(moved_air > zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) AirflowSpace(src) else unsimulated_tiles = null @@ -178,24 +178,28 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //Check the graphic. progress = "problem with: modifying turf graphics" - air.graphic = 0 + air.graphics = 0 if(air.toxins > MOLES_PLASMA_VISIBLE) - air.graphic = 1 - else if(air.trace_gases.len) + air.graphics |= GRAPHICS_PLASMA + if(air.trace_gases.len) var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in air.trace_gases if(sleeping_agent && (sleeping_agent.moles > 1)) - air.graphic = 2 + air.graphics |= GRAPHICS_N2O + // If configured and cold, maek ice + if(zas_settings.Get(/datum/ZAS_Setting/ice_formation)) + if(air.temperature <= TEMPERATURE_ICE_FORMATION && air.return_pressure()>MIN_PRESSURE_ICE_FORMATION) + air.graphics |= GRAPHICS_COLD progress = "problem with an inbuilt byond function: some conditional checks" //Only run through the individual turfs if there's reason to. - if(air.graphic != air.graphic_archived || air.temperature > PLASMA_FLASHPOINT) + if(air.graphics != air.graphics_archived || air.temperature > PLASMA_FLASHPOINT) progress = "problem with: turf/simulated/update_visuals()" for(var/turf/simulated/S in contents) //Update overlays. - if(air.graphic != air.graphic_archived) + if(air.graphics != air.graphics_archived) if(S.HasDoor(1)) S.update_visuals() else @@ -212,7 +216,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs progress = "problem with: calculating air graphic" //Archive graphic so we can know if it's different. - air.graphic_archived = air.graphic + air.graphics_archived = air.graphics progress = "problem with: calculating air temp" @@ -252,7 +256,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs //Ensure we're not doing pointless calculations on equilibrium zones. var/moles_delta = abs(air.total_moles() - Z.air.total_moles()) if(moles_delta > 0.1 || abs(air.temperature - Z.air.temperature) > 0.1) - if(abs(Z.air.return_pressure() - air.return_pressure()) > vsc.airflow_lightest_pressure) + if(abs(Z.air.return_pressure() - air.return_pressure()) > zas_settings.Get(/datum/ZAS_Setting/airflow_lightest_pressure)) Airflow(src,Z) var/unsimulated_boost = 0 if(unsimulated_tiles) @@ -267,7 +271,7 @@ var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs if(Z.last_update > last_update) continue if(air && Z.air) - if( abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta ) + if( abs(air.temperature - Z.air.temperature) > zas_settings.Get(/datum/ZAS_Setting/connection_temperature_delta) ) ShareHeat(air, Z.air, closed_connection_zones[Z]) progress = "all components completed successfully, the problem is not here" @@ -412,7 +416,10 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg ) A.toxins = max(0, (A.toxins - plasma_avg) * (1 - ratio) + plasma_avg ) - A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg ) + // EXPERIMENTAL: Disable space being cold + // N3X: Made this togglable for Pomf. Comment recovered from older code. + if(!zas_settings.Get(/datum/ZAS_Setting/space_isnt_cold)) + A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg ) for(var/datum/gas/G in A.trace_gases) var/G_avg = (G.moles * size) / (size + share_size) @@ -442,7 +449,7 @@ proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD //We need to adjust it to account for the insulation settings. - ratio *= 1 - vsc.connection_insulation + ratio *= 1 - zas_settings.Get(/datum/ZAS_Setting/connection_insulation) A.temperature = max(0, (A.temperature - temp_avg) * (1- (ratio / max(1,A.group_multiplier)) ) + temp_avg ) B.temperature = max(0, (B.temperature - temp_avg) * (1- (ratio / max(1,B.group_multiplier)) ) + temp_avg ) diff --git a/icons/obj/atmospherics/cold_sink.dmi b/icons/obj/atmospherics/cold_sink.dmi index 09f9be43514f4a8019f63004afd0f7b3b12b8b88..e36d5ceb96cad323a948f8623e80e2b58962bede 100644 GIT binary patch literal 9182 zcmbuFc|26_!}re^YuQpUWv7tJmXI(gvWG08ED=;To^38ky##IcgkKaKl^INH@sRINKn)?$IMB_Qe}Jl!{3qnWa9jGs8}jYFp?1 zdQ8Q|=4L}I&t$iM;PtZKU2yiT1WP6ANv0y@#DbA)@&S(Eu=hogfo~*Yr%x``pQ^Rc zn|jCn<n3;h;N=K*CuuTg9aC`5?1G@Z?i#Wrxu&OnO7$)G=Q}}N@^rb^GL9zJ zzW@2cHyRR);0r0|I7WY6Bgysd+YgUS9$voO_e`?Z5+5=bhUU4{|CXv&>$xz%SG%&V zI`=k~M<(vcY23ThnJV?;O$iG>x(~h%UE`9reLbJsr1jw%b*K4iCsOFf9Tk-@vV83v zeyI-HcLUW_>e4nwgt>1bbeLrmPphpt<;)`?&$Z)qhH6I64nu)QJIS3o`0!p*-raD@ zb3*TMKu41J>6g*?&^5U(|3q@9A~d?Zp+DV)sUVK*#X|F|3yyhXMYc5`{A+S+iEL1% zD%?pXj_^}b5X?|q4_a~u+`Wq93CaBXUN*{ABqtQUq!@lxbOBz6sgv4msh?A85m3dX zoi&a+P=r^2&YvPP3YD~Ds+;++6sl6Mw3?d7gn&WH=B-h}(NCx^%r|e=hO`t$w~>SX z5HMs%z4+Yj%Jo`52*HViS4J@CE`KzIaJsN7l^v>^UF*%m!MHliO7#l75eQ4I6v=Db zkvSkCH8?>)wQ6Ou$PQm_VW$ky?juSKkNg-*6of=#{2C?x^$gxn!*(Voq|Pd7dT{j0bu}SgsIzE9oAMDM zao*-&A&0s=HrEdC=U({o*Di~&aHg~!1W2SrhY9Lv_yQ$+Oo|pt#}TIk&)e-K^m&XqNjH2Oe0Gav9#@iS#bGu5vw|ZExnVBonaHAkk9urP2snbJ=xR=tq=aO@gNx= zAmzoKsTQ^u9lS`NAc%ffU|BT3IMMO}SMeZ4k}vkG{}jgCEloUqV^VUS>+xRQ&+2gL z($^@#khVd)rYkc6QV%s=Agr)z+2lt4tYR@Ws!@^X5`Y9JqPfvSu(m(CK z96gRQ*`>=7$LY9M20hb+3XdNvkmx))skBuh#BxCD5yQ1EOjWu5t43!URca^uWEjodg)@l+eJU!zw zfxcG2sZJ9?hm`4Ofk=nJFrt^^Y&Py=4*~6p7tP151Wxcryi|kuFvN^FWF;JdKFC+A zFy$#1DMy^6up7%^xwcd?YdEl{Y+&|H8)ZTo^XhInfh_sXzND52q*#E8@Sv2%3UwmP z7{W;fb`#-7i*2TsB=h+ClVOCl)E>)Yj2Yw<8wOh~{79RB%@6MH;|oelWrg?1%WGnU zX;g$RxpPUnu*i|Mig<)63uvcqeGZQ!C=g(^Iqd;Jw`5 zIBvUJ`^s8Ob~z~V(Lo_K!x>H2Htb$;n%?L{%Je&Bc;v2*y^Ym!vFa)~`hK8)Xz1qL z`n-y#$(xGOQY17LP|bYZexcOw=5}G_1FDc9I{Y>VdSkw~b~|}>JfQ~6W&50=FUK zLd=|6J5<^t=GJ2i*}$L!L(7{_`nf~G2~);ACi_K}IYQSHSv=A&!bwB4O>(}q)$qFy zS~JEp1gb6MH6Y7IKFVNaL`q+p^dIrhFnV$n#j4_QQ~092!G0aOivBeH&MuiXn1Cw` zdB~aZja|JNx^Od!FJCX+f?=>~w98~zt3*^4t|Iy}WH~_uiNcnMLPd3MGwz=BryT7V zUB4eL?CJz4vGF^vJ-?*2J#$nG z;|}RDwu{A?DNfWX+UImso++rRsi}E-C2U~Mq!72VqN8HT&`Fk}$4(FOViOT&xi@Ps z4=*#aHpnciaExqxSM&}Fif(DqfB5j>v)8s|YQiV^4IkB`Fi%ku9w(e$$hAQz*CgComB| z<=Zlkxd=r%paKO|KPva6oU5T`x9{uAw)0~xpVDu`zYOn??aP){g{O(Vu&NO~QJDeg8YYlBoe{LJxLH2}+Lm$WBF*NnW_bcw7du72n%{Z4{Pbw2> z$uqGw9-M5P4_uAM?f{UbDzec_PG@XZ9PAAxL`Z7 zcwazZ;Ma9El{TB?`I(s+2&x*Ax-N8f<4{dQMjrxPg|#kGNmW&=(4xUj0SOsAIb$HU z6H+hjKUrhTggxHNc@+Tm2I4GToHlZDa+3KvWU{M%NoBP*VPUnrCA^^fO{m%_zNXkK zedC`5rZD~v&^`6Vn*lwESu(8S>FK;GuJ|1PbGdwA*H?wKL=-EdZPg#+l8L2JEvTIb zILLN}t1QJQJ5^gdpL|4kDi2Gcjb^Sv4y`JGSl0;vuXdB{P6Z1# z@4$9?s_TZO#O*ft%=B#pn@E=AJ(%{CW9pB&!t3FWq2zF+-j4!Tf@6uA5X_kTdGnd7 zySt?36N=c>FClY@OcB?_`|ny>qpwj5*3LgBi1+=(Ji52qa`cXtO2MldQWs`B;g#^z=g?VKH+3QSqBhhsYYY8fGRH966d5DK?; z8HO(G69j|QjfnPz0+cf>O3ZM4`jf%K@5D=Y9-*C30N<379ITi@AIJ zMlK04x|%cR##cuX+_3sOU#5XclI_a^vgjnI-+shODWgCGv&-6J>B~!UR(4v_N0Lb9 zx9gp@h$hQ8M82=AiQjlPd9%^n-zTL9E<`sM6_v!6-6Bf@`eK$e!oyO|KQsKiNx%DT z^lP07BdzbzwQ`2$*^g78&=(guY;~QK_ME~0wscM$jz`tN>4Sl!j zFfSwPGYhYne0Ws{%m;*}NumCp-(8*X%v!au?~w3~sjOs(FHT!YO^p$&#nk_AA+(_O z3O73Fv8Y3RzktT!%_kZo@^>k?so_$O9@30%Nan^qdGZ7pl(bf72utvbX?CK6z@+xH zce(8}g!SMz6)LDyyn`@!*O7T3shcMDQ%)~ZFcLR!83sK0VXPt|l{=_w!s;YN48b#~55RVzuB zdg6gIb?);uv)-D_9a`TZGjr>5$cI$L=OH5e=$OJeEedSuhqT=Cdt;;0 z8=2edl<x|M$B4Vn{RA^o8vDIV3rFpA1Dt;;12YeZ1;S? zhUjSwWpb?yp2nMH7uukg9_iST7pm{S_2;v9+Ts9u?W_D!nKb^qWxo3ZK!)gP_*+YV z89WP{<`gw$yD_?_$vu|8+abbemX9IT7*N?dn zwlQV%&<^kl35l^TjO=$~gwl+jq#1}oSm)APA(Vh_g)p`b4lv!c%I{@+h{FMhn_75Dl(iDPg8>|%Ju|he@>2axMZ82LlGEkSlxYZh^};}f zx&co2dQKM)VaglD4_c8J&v|In4rZ&w`RRu|f6Cp&0Pn%>;{gJ;v9akJ8EN|ZRai<| z+S|wHdWUOcu{SiZF{!4Wc;6|(+UL-tIsB_IgV$@iYHmavLPxHH;Ah=z5%=w^X4?|? zd4uSoz8`4hop0}!Jm9`2+4X>`XhZ4|NLQ?r*FS8e$xm5pmsTv*ztO{u1kUz3B9I_^ z-@wb?|K?Y(N*{(heYXs$zPtO>f#Oz{m%Y5au(7e*A7*6iS>G?;%t5haLL>I-6m)9> zZdVLw74 zS9wrgx5F3OF%P8-^fd`+o_NBfHeq=TvAI9%^rw6mxaOwLM|A%%LXo{QaoRpLSlbYW4I+cUU=Q=Am z$a4zjBz&^(wWKYtC4I>1gWdCsgTuqNub!R$7(uNzOrc2chfd|}h)+mB*qcc?1{-2HPfZk@^a3|e7k+`eOnhltA zNG8JwJZ#X~IqxKqXY&oodoOSR{OA9`96&gLwG3L-p?FVOiUaM;lxSLN4@)FSDBF3aoV zdtfDCz!9-5<@Nm5_CFce#z$R3O;gCO~?_- zzbt9I>r$9Hl}+N0qLLTaZ;`RJidif)OJ-&W0#Lr|AEhjy(AeNLHr*Tth-#!gf9Fz> z4KV5KjL6d^qR&8NnpLcm%ms+ra%AS+ll4<8#UHQ}+}~Obf9TSw*f$w-*?S64k%4@< zwh96YC5%r%U~F-bOI%zW7~$9bd|2uL!#d)-P=8J`pZ?Uk=i>xLJf$78ZVx%cWuih_5cL;^iQ4pVbKh&ivDQ!2FrGa=CR#D>K>d40sIxHQZ08f+Uq{d%*?hZ za8O7`Kp+*1C9yzR{chQ|Maa60E77X$@Z~qqp=;VX*Or!i={2wtF{8l(p(9N}p#v9d zx-UDZ;Y8!d-yWUucHto6t3a3&TGKp!Mc4T6>@#HtyS#V}bZKS9&}Z-6&HbepZ{JF$ z1-=dXvm%5{XTq6xSVex%R6+4&kl~n+GNM3x7DJ=c9-;gbVf&8%R^tB}hNk3*`nsf< z_Xi7c>TvglR2Oll+X~)Te`A9CbIalUE!|lI-3?TZ!ZnCh1%RK5^73LlKB1xE#5r5r zv2Wk#b2_3G(~-0s(+ZzkhmutFnqTy&INyT$K zssGj<+6mpTW{Obrt(j()*~Y`*Dj?Q;hYUPF6T<|%2)j&nxrfRfmqmiNC@0%Z?HmnK zdFLco-`%}Cvf=B8-9i_{X&Gq|y&@@dSDdvW$kUU9iHWJQva+tf|NaX*&7=(gw_@Jg z*IxcxiAC&;S;DzC2U;h6KTrG9YuIl{@-;J3dXdO>^~CN9r=#(pm9S(&wsUsYd`pab z+Wb|y5ok>Sg=O>xWhQ%rjFCe2*#(8e3C2Lrd6oqE6d zUk#%H|0DF(gy{r;ViH-t(G;%=6apxV9mSic(Ib! zKisZ^)r8+oMcq&6Y!q>0y2ox0c2l0rK%VyNY{lDXW%B7P_;R?VIVo6%tolsO{uRTT zPwb+6=i%m8+17kyPc&=Y!~d?X2&fOo9@ANt*x$rOrlu3dTRlOcriQ}qApjrl^oQE9 zd+p$<@NB=JNE|UjVHxIM51^O5Kh|bQX~MJD5NUUb+J+-5vKdA@v^ugedtUI8J;hn; z=x#STg4*cZ`SYM#etr(IF8~}}|K5BQILMkBRX#qx(XlZ);Dt80z6b-IKP8U5KaKs{ z(n3PbI3Ms?akS)D=XWpzMCp(k&{c4%1{*e;#m84~?dLT~ zYA}zcfG4sEQRYD-O;n_J$&RC8A-g!b$_2sPp}c_)+X*o;vjNq`l`*!?Vzk!3d8@YH zN`@G2ioxLp{CdsYBsWZ5sZC!$ra;*8tI}$16uy)uRN59J(O1Lo(U_SAy24P2&eHJ& zxme5~tns@k+(e=^KhxP?$h2GkVJT-!KBBqdXHqwM;VQ z&<;$=wOE*%n)(!%acDxiSI)!Jv*=up_;-!X5|AFWRsX@d*4F9VV&CfR8h`$j3LS}> z436c>%*fz})IpNqq>shr1y=4nzSRP9{il8e@|vWXR{R4%y{rz`(Txp0uq+fK5|qgV zhKs;RfR$&Nbz0kG^mvdr+ttB-fUEHPJHt>WG62jju3Z0fYcoaiw+WAb0Vbkl-f zbY$2`La35z%-h>`Z54^T4~H4_Y!!*Lbr_DPvooegDP;%=cWg3svnE;8n-*`!9L2ZD zQ|JdM(x167uNX)^u|KwSXTb+Xnba!A6RM2^1F5j^@XXxY`20L)YHF&|v19eF@?)*v zAsVZe(7kGPP6?(yhcf2y!Bw}UGr!SBeH_(=z0T-Km)^Y}Nsa`Swt>GDfX4fEd_=DL zXdd_8PDAM$Kxx-s9+emO(dZ+XSK|t)JY;&Mf7;aOJ{C}|r*E{?Y%}=w??pc6nbh`u zAk^{CFgpHyk#9?h1rZ2WW`c#@p9_2_{I*ji8ZfC2lE33bI&2ju>Y)L5*F*9*{G?xj zjObIz{z8yk#Kf4Tan8;z0r<_NxTl1!hM=@^piR=Q%aM0dvk#gnOifEL+DWO|Ng4GP z;&{k*tmGoQ-(|hoqXeM7Z<#dpxenz1y{}Ks!w0O7Vk ziBlJyOa827IsrAaY|v*;P2p702lqYCPbzpx6~`YMm~hj+EGXe$(Pd~Z`PD;@#qgU>w0C=x}GPW z1D(B+{v|}3i&m6AdHEMEe5AZg3xfRo{3dVi*I#QXyA6uVgQ=uj!8B@=zykVGe{_$W4B)5*iIUfaq-I%*pzdu-i=)=gVyhxj_~gQ?fnRAm9Sr=C1_X%=5si z#Q~T-PY;jzEJ}Qj_gx>5YtCGR^#>S_pjcn~ooO=P=aO(wR?Jjj%N<-ALC^(WeUNwh zKHae2>+|6c`;Zi13uxBQ9P~FK*QRYNH!Do@yo*|tUX$TdB{}&o3!lQE+{fNVJk9?@ z-2`;fYk!qH_$wu_*4G?g+(~Ak zt;5{`OE?sIa?$rdb8{S1&PanK@}A8d=?aO{qC<%f59Ysp1TQy0A9aB%@9E)QURn8T zk0ME2yFVM>eG6e_57?yC)N0Gl@(0r2;yN?BCfZ2Vpb1%S<9aRh3srZ@^V z%?uDkh$Fxy?$Q0r!yYE5?x=nQ2Y}>I_fG?>PBX9qRCKwJ7*EtXd<}eI2h!CtI{94F H{`&s`2yb*} literal 595 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 Sx0fCB0(J)-Z7Zz(Fa8Tft`Qjk literal 3950 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 diff --git a/icons/obj/atmospherics/vent_scrubber.dmi b/icons/obj/atmospherics/vent_scrubber.dmi index 83536121c49177bd972511065a90aa44bae4aee6..b828539004a60012eb25c7695fff0a25f9e2e014 100644 GIT binary patch literal 14166 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 kCk=%B-*WzcZmHzPU~yE)UXTrKZ5gD$p8QV literal 5780 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 diff --git a/icons/obj/pipes/heat.dmi b/icons/obj/pipes/heat.dmi index 6d1ed47e7ef869a5947c3f9a26f0d36a4ca1615f..8561b0168078f2bf52614b532d54d8a9fd587aa3 100644 GIT binary patch literal 4566 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 literal 4949 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 diff --git a/icons/obj/pipes/junction.dmi b/icons/obj/pipes/junction.dmi index 70286bde155d30de04911477296cdde32faa7b1d..0424ceecb81ccfeac55502fd677160f0857c284b 100644 GIT binary patch literal 6596 zcmYjWcU%)qx84u}(xrr|fRq=cBOMe&eHBnZibyZgyYy-ZO*+zxKtMndDN2U`p-8VH z9Ybi+1OlN*zwx`@{r&DAyR$nx^PJgpp7YGiZj8>;f2qh>$pHYMdi+TB8KFcH4)_fc z!a3f?nvGB-1nL`ktJ-?mymIvLc64_G0RMN9Ltn@{#Te9=&*E0E#-~^ zv6u6`8I4!E9E(ayH%nH+k|vhNI4*C<_&0l&1!P-|yGoS>C8k(@S$wPUZuGIaF7J)5 zqW+qQRLNp%5h&yBva$$@=SErX_1T6?q*;q_j_HzDl7T))8FLq@!e`?hRQdV;*sITl z`{4xufcfCDs*=9{yB)KTV1~)2Q0eR!9SO?B6-34k40WvyjVU`+aT_{y8g)dhszgp` zQBISaU&t|2BJ~1BQ(4mKqM}^sRpbyJ!!NCCYV+H5Ma;#aW8EZFLP!Q1TH<>(mn-ii zvg2o8YWvEh4v*kR&vRY!(Ex75_hJUTkp z#ItRf@;F#{(RWkb_xoJUcirY& z1o&pf-`lKP4he3~OlE`0eqs24tUk2t0Ecm!|+)k|;q2HqcMFD@!~DRb8H z+fH*T=hHP}dQUXG`?~Q#+_Ms5<~=peRJE+%NA=P?kD$MO@^=k3_AQwTVE4GRjNrmC zqfX&3zurg<8%pMcDq7mpS-d+J*Y@5Mg-EYo>_QTTVq?lf{iqOqKGS zGo<=dy9&=-1;`I$6BihGgUmMHQTSTFPd5nOX}n&lA1Ux)a=ATiRG@y&kamQ339nOl zI(<6fvs<5Bd0tQrs0ng6=hP?GK=TTDpOSV@X%Z-raen(mR=1Jj*?+kZDF|aq?1UmI z{=LHs^RsaCwIMLWDtkqh^S`$Pt0tZIdSlQ#i2q{`m-^v5o+Q1*N~dFA^*5WfI{Yu$ z+wY}QH)!^CS=()YZp00yp#q_0gUO5 z{*4t)pSPxW0)2Diiy;81igM0ol0@V2k*NoDGfrUv`<7k=vjfM| z3t9{uW7KRtBAqXLRUC&#r@tQ!y&xol=4+Yp@9SoA4+|zd7D&Abh)NT+Mwd-rD5TFrU&RKv1M$UyEu;D-gZSRh!S@!T->*6unspYsMocrz9IzVaXYu`_UR zuj8HXU+M8~5@{?~qFfcuCM!-|J-+2@uWMfWFyq+SgkBMlZPQe>&86#|9{ALO z(!ql4PS9_zx|^EsW8>mXE`5%*;OBJ91U|OYFLPPR?t+`!=~I4sgus~0sQ>C_tcbnp zAc~g!oJ;rVKl8Wqpk^BIed*C!;&X3ZF4XaEhz~8t*He&9eK6cJNrClvSmJBTvT<&E z?HcKj25sr~m0$V=T>Si3R)#8_yG8Y%MgM|0k+~EOv2E2XLasW5qHA|3o-po9Yw>+2 z`bVC`g;xT>&81}<+NL__PX9MV*KeNz5PkG2ZWxO8ehX#ScpaE=Fo){x97`p{J+s)O#pyI^@@W5RNNu zwShUS^Ye9Q_T5wpzSg3%%Dl-r#?z^a2iMzE&b%dQfi>gtatR{bFl>2l(aYpMb3;CN zhvtL7b-XZS2v>hZ2A3HDGpdDi@;`j||MF4^NZc^-K6=BN|H*qgyif zmM??5=PV6ooexpO?&I2AmONB@*H9p<{t$n0Nbk7SXP3MD$Kun|^fnbwzUr&ENZw;l7%~2c@Wb z$MwZmL8aiC8;oj^Zg+zc3|Y`TU|DK3MeP8+avX!fxCUAN&AAmdgIeXN2KnWXLQBnR z)W_I-Dfm1kmKmOkF2YU*z~2I&9-#Y}tA9Bs1-0z7@cGveoh1;v+j#c*t>#gM^%LH7 z0dSLni-Nqtafs+!mO7LUxN3g(Hzv?Ai6}u>TIlmGBy)9uXZJbNbp{quBoH_N?25tP z1I^)Tx`mfsaCULd#jc`{V+ssobY%GsR=bsDAHLDu--n@I9J30iU}H$FAL~Me(+C&K zWkmwUmVh5Cnik*-SL>K~1y>PA?^)^o7}SRxz7#}#eofIf06dKWHDJW?{sC6d2a`9@ zz|&P=&mZ0%%z=`$S{0t|(m^F$~ejc2|IsNh`5z72A49&-PlsEFnfOMA3Ip);+TVrJ_}1mndZ> z&yM>Yf@GCggR&E(grC3BjKGvhuv)KexUjbG{LtJP3)z61(D8)S^b;(8)teE{n#qg!9Nmh(*SNyuu0 zeu{P|7}D>XU-zDNj1Cle7l1Ct0BTSlX`EeVF2$i3{Nfhlhv15CzoWMFFbjSpM_p%4 zrp)^GokcYt1u!036vR6)c*ckWU9E<`9n4>t@S06+5o6t_W?#?@%7552;d8v2xF$UG zTNYKW$!%_#UEe>#Ht1g?yC=4O#E6=E#Iy;N)LAwNAO;lUm=3+S-@D*f1X$hx`Wme zexdBQ1PGNyK`Xen&z6hsjO%7Y0WTJb+S*T^?5(C`cU;(C^D!6ePI0nhm3*`vM6H$H-i!x=5 zJ`7z@*iH>X3^M4H5xbuhXdJZFIGHSsm9%Ual3}_-?<~%4-^Dc)<$1>uk6!N(uz&c3 z?b_-#&jO(@0bRg8Os$4jAI=`gN}M$kzq4s1dzMmK$j*5E1T?jcjyGjgV`@|fB}l8+<xPxb?u-lg7!2t9a zYaod3>nS~$5=4%d)myzhz}Jy(&ZO!FmP9EfpnDe6R;@ZQodS^?#^66+KtDhmG>pT1 z<`5DoA}aDYiJr_=$I)HkV5K|F>Ij+rt`w9m_?Yp^{LWdZAS#61Bb_=J2|Sk~@=_G+ zZ~54Z>12Wy(bBCYwDGPgu$wZ;eh|`l&W6^e#Bu;6aJ3rSXJPCKu(r-3hX5HtWI2!j z&p2*O$zB@iwW*%=q6D0j3abJv0&$4Ud!T=E3#z1y{7OoUBeb1zHounxhPZZTAkZIv z!5sIqsY;Ffkp%pU`o!-@>!oxe*;UYmI3vWpoT<6~>oFOuomut1#vMmRvOs%Bz*h zihe?pOaUW}Lon6vs|HjFAg$<7OZ1utBl*qmaSr28o4bLYeI{bC5IN=^u>AlX&m32T zYUf85lIU1hTR10$sdaDzYwSp_o+50CDmNd6=SKY`9If+>lD@VALMuji6QQDyh4pManmxcU+5)6&ooGfR&bX(ViDVf9oa zZwhUEwaiX1u5U0%6J#dTkxQ6*@_c)KW7A4{`$aqE=lE80&#=vCKSEZ&1uZy97AQ+{ z@X!QpABDF=@Y|maVd2JDUSTvLzPz#CcK^t(kW(#6&ZK4fkPigEa`nn9QeM=9F=^ns zsZg~-8cfVC1B3EDy#7AcvBO}kB&qb1Fd}&iM8o+&visVW z4V-`*#VPK`2--aIV-m4;a63nu+NKb=aS)&e_krW=G#zqt=oj4!h~y_a@i%p!HRb80 z6KGP*t&r}Zw8!2)C3Do_6UH`B^kWbxWk#<9Pa$!?X81^rIKX!PMhwt1ZHRXcvG$E$ zMo%8BY2vyQ+P?^CJfO1tG`;}Hm|$)p?~~{g+D*?Q;en5E-9FM&KPJlP?tA8~5d0q7 z5g%CY=~f>hm%%6ob+77QU3cF0ItQo3GCoHQeV&xOrL6Z2_QyAv#0H&}ytg_y4RI5W z`~H~3>(4bARz)d%rX9Po~Z(b{`d$!VIEGf#m9_7 z2B?r+(cehk4>b(o8{nVl@{+N)TV6Id<0iKX&C@p;iQOgCP=>j1!XHkBQ$i@U};(?m8;uV#ote%eQs`LQI~eSF|<^rk~;3JxNmI-1C`21*NI)~ z>$DOWacE!2AM#nkX4dI2M+KZd%=3l?awp46f9zj^POK-6DtPQgN76)_zyC>xy7-iW z!bt^DoR_Qm(4olPa5OqGSK~yY+aYL$svp&w_SDzW4zIR`#dBQMl@|Ws4aP|6P?y1W z*yXvvKnr^ba2-I7E|ROSAw>B=L|a3GLiQ8{Hmc+$Mk=Ce z?@H3-upCicRGhWzk8RVT$KuKi{VF(-Z4V{v{oWH7iBbZ@Gv@PFhGp zx?IVvW=5L$SI=F7Y+-szJRO6g)TbH+^DNAjbgtvs1&&AOS{-kW;@BC#`Gh`)Tt2o} zES%hvFpof@@dSQ&mv`iSuHmmJwCo7Uk6<6LpkCw}z&_ ziqyvU(raHt>7<2L)kGE>vh^^;`v(nK>3WAve?&6z__Id@cVUod?dadd0%VxT7A{QE zmE^<5y9^~yTygADa5Xuh-G_XuEkP$EXdi)bynIdeXWzGXU2-c7#${H^%d05k^_AEr zzT6U=!2MohZL!w7>F9xRp4g*eXL)JbNOjj(UCY#XI0F+$pF3BH0HPma&)j_ovRB|QnVrlT~@n6G} z&Rm#^8dO)k&`*Pt;>b+=#^BjsyMnGLKH{X;?VsI2k+i}t%=_I;JF<`3f01mN10m?5 zS>9PjhuDm}#Rvgj{~{DNG5k<4`@o-~MuMTlV#{T1pB)J4D4K=DLJEV`j=PQers>ne zHU&N^Blre_WEe{Lc>I^wwpw-4228NFt-$NoB~iWJSjF6NXX>x6nj@saLBW`hTMr^n z%2n|^{!|~LgO|XOVK1ES4!ed=Ymz?gx7|na((bL!%RubQRg+$+%n`)K?7qcve!*ao zKPS76Qqm)w^g;S$i;8Zb5u)L=fp$;RMjG<^Gu`Dow(nEvlXlNtB}QsO^}gHi0nF$V zDAt=s%m74`F)XuqR4p^pmVjmx$0lq+qcvfYN%+!N7#o3=n4Of&d4E1?{ZL)RvmCZ) zK51UFCD4?oxg<$&@cGaRFK1vHzSIMAe}sOXcXVYf54(0rSO+I&0*8-onK$sdw5-C| z+&}uQSv3o4(DW|FxE8O^`-k^dZ(qo*Klz1fLNr9}H+y0h{^!fW#Oym0vpi_Km+S+ zxsZ=Vz6Q6v-j_FQ<3-jPg{LWJvo#YweJ8|>A;&c!%VFGHM`_waWv*F72X{74}GoKbEiBL{Q4GJ0x0000DNk~Le0001h0001h2nGNE0K-0E%K!iXiIF8C ze_ayonnhAdhV~tTxta{Nl3cWp-$9{^;&|ZWv^e*JpWsGMPcAhtGc3A;CiTiu5-d(f zQi<~|$vdh9VOTVImT-}VRLrHqq9b)J;m#EnW@kGv-vO_WrE)a-@9HD9`6XNQlY<*Q zZDDacBOk!KhX4QyQAtEWRCt{2olR&Qf5{cc|09nhtb;KU?7?^sVGtpE@+1g+@oEsn z3HUP3^js|L1tao7CNRSIl3*XKuooXZfq~uZL9hawgpA2tbl5$Z76M}s$ru8p!nvy{>*;a$Ogq)M_=aTCJi|f2m+N z9AYpSz;)e{@QyfbIgW!~uLsw4OQOp_ZjasdyEe_F<*RTRm2uVWe+`noO7$bmcwd!Xe zd6v_LZhVp*RRzhqI*y}U1jY!Ue^RN8`~{9LOw{_cpoJHe8vp9+H7{zU61JXnE0s#c z7rH7Dl*avD0I?V3T8G17V1uW5AAr6V^l|C%0POx%oTCvQfZXI^F9eIsg-IH;1szkR zQqk&($i7tsoJI%$_$UG(*xk$iDw4(wY(o!+LjX|j0a#nA1ZIo?fM5{-f5}{;stZXP z9)Ok@pjxf^HdMwtMhO5oDT1W^A>D8?u#GVs4*ftaX#0QseKpc;2dxkC0K`^OgayF% z#dLpU;sgv8t~$sy>mH4$3N(cT5Eh7;EP|xR8`UMLVk|}hVZ)ugcmi2Ox+E2O0M)~8 zE&=eSILYv*s3M?;f2v~uf3jcIIhR-guqjSD*a`YfSITnSp(mv3$^+;~aB+75biYQc zkxhZp>x%~69q8J>>V0wxfVdvw>f)A*ifLZYP6#PDRsaRZ3ZURv0Tdh|0oZx@`9nwm zc3yt|uw6jGu>vSKQgZ^cCha+idB(U2A!$RWcG*-f&vJT4Du?X?e>h<8go-YYGgbfv z#|l7zJmx{H00hWm9>fZu;8+0^oY-OD{D)!9hTxD!_Is9Oh|EZGUAM%Y2bizbJl@8f z*ElW85{^iHf?lr&fWrf9xNeCwD31u}#?RBQKdaYTz^* z-_|D>JvQ0;1VS+Ye{j+hG#v-S;Sm3!jOFc@59G5x0e1|*LW|&^A9g~o6WyOF>l4`9!Gh$eK7nuy037#OL3l2(LX?+5r`T%U>lVMQPakPuT)+Y!iX?+6j`T#+{e|#{X=@NmhPY{i4eFCl+ zAgu9&>I3|&TJ>`RszhMx6YwEgpMX0Cpc}sgph{ivp!xthL_qH!u=NSTkf~3=9Rrjw z>T06u1JK=pDr|iMK197t)OE?c58!UJSUtyc58-L6M6Y$V+} z7!1&AwMv7*z)w8~Z9ndey$1-xwCC{06(cDLPvc7LeguQs6GJge$sw_y=kbf4?yVkdQ#OwlGFzP zBx3+#e@Nvk(s{{SeE{I2sAR9FOnm@?P#%Dg)hHm3^#KU7$E~D3fJh!-oEqQO2T)WW zfF}mf_5OMuY<+-eWa|R}f-yjv2@Zm-55R|LeEpPte+U@pVMn#|NdF-n_O}BgKUM_ z=CR-J_ebKIPN#!7`yym6fNxg6^ymw~UZ{G#E+mTH^vRU=^}{Q8^zHXp{Nng;v*{?k zf2+x5e{C0wH)rr@Z5K`F$6D?GoLT>q!z*~a_8qR@{3RZ*eFw*B`t~yyKotEq|C*To z^S8z4}bh~;5Lm$!)v$O==b|LckUeS+_{6Tt*zL7&&|!@!Gi~Q{rWZP^*TD8 z4xT)DBHS1%?O(lm73Fdn@7}%hw|o2ce=QCU4shno8Js?S+W(wvx4yoPB=$2O1>C-U z+uPjS^cs!Ei6LBl^4iho>uzY{7lDI=0}KWOJbU&`%l^mO1IQ56N1r`=7JGYp!u>tX z)2B~!nPbRY03^s^8|U7=d!gUCfB$}>K!^>>WP}kF3`PZgVPtjwV>=97SXc;ce}sjF zg^_7$udtnHH1NsvXLyC}$Z2IF9w4gmJDrZd4gEjM_V#w@J{-sK=Wo#G&%1B>v&=of z^768mW;9GA+a2)QXSqIx_JiI58H$eN$Km0jN21}27cZjU?@LGH^?DsIUc8Ww#)>%5HqVY` ze}CU^n8n4#u?q;vvE8_F0|0+8%;f>-S;49&hKh=c&5RWdHZhho7#)cL;+_rE@mv7i zpsJ&B8Q5cp3+Qy(PUHN`>@3o_=K^#-fWZ@ur|khYHa0@nRjbvJnaDw-e-ROa&Oa_S z9@GYWsqtMbeldfR<2X_mH0iT}Cz?4 z&dy?PZZ0wy+P8PWUgdqE}(YQ(W z%e3OstPhaIlf`MkHX3gV?Pq=_nJ9gQl&g$oz_|8+;>?8(arf)yOIPC6P7f+saD z@&gJw|I8!ZZnyn_s@-m%ZfKmSy1HaN-N@{W+4=eT zSo>j9)`Nuc@Zm$DdjnxJc*Fizeg5SCvG4#q+v#|SQ-nDCtOpQj1QqsKc+Wp`0mKbs ubVb9w