diff --git a/baystation12.dme b/baystation12.dme index e3de1ac51f4..08979087f02 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -335,7 +335,6 @@ #include "code\game\machinery\atmoalter\portable_atmospherics.dm" #include "code\game\machinery\atmoalter\pump.dm" #include "code\game\machinery\atmoalter\scrubber.dm" -#include "code\game\machinery\atmoalter\zvent.dm" #include "code\game\machinery\bots\bots.dm" #include "code\game\machinery\bots\cleanbot.dm" #include "code\game\machinery\bots\ed209bot.dm" @@ -1092,6 +1091,7 @@ #include "code\modules\nano\JSON Writer.dm" #include "code\modules\nano\nanoexternal.dm" #include "code\modules\nano\nanomanager.dm" +#include "code\modules\nano\nanomapgen.dm" #include "code\modules\nano\nanoui.dm" #include "code\modules\organs\blood.dm" #include "code\modules\organs\organ.dm" @@ -1162,7 +1162,8 @@ #include "code\modules\projectiles\guns\energy\stun.dm" #include "code\modules\projectiles\guns\energy\temperature.dm" #include "code\modules\projectiles\guns\projectile\automatic.dm" -#include "code\modules\projectiles\guns\projectile\bow.dm" +#include "code\modules\projectiles\guns\projectile\crossbow.dm" +#include "code\modules\projectiles\guns\projectile\launcher.dm" #include "code\modules\projectiles\guns\projectile\pistol.dm" #include "code\modules\projectiles\guns\projectile\pneumatic.dm" #include "code\modules\projectiles\guns\projectile\revolver.dm" @@ -1426,7 +1427,8 @@ #include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm" #include "code\WorkInProgress\Wrongnumber\weldbackpack.dm" #include "code\ZAS\_docs.dm" -#include "code\ZAS\_gas_mixture.dm" +#include "code\ZAS\_gas_mixture_xgm.dm" +#include "code\ZAS\_xgm_gas_data.dm" #include "code\ZAS\Airflow.dm" #include "code\ZAS\Atom.dm" #include "code\ZAS\Connection.dm" @@ -1436,6 +1438,7 @@ #include "code\ZAS\Debug.dm" #include "code\ZAS\Diagnostic.dm" #include "code\ZAS\Fire.dm" +#include "code\ZAS\Gas.dm" #include "code\ZAS\Phoron.dm" #include "code\ZAS\Turf.dm" #include "code\ZAS\Variable Settings.dm" diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index 4766883a645..4e2fcbc2638 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -44,7 +44,7 @@ return 1 //Calculate necessary moles to transfer using PV = nRT - if((air1.total_moles() > 0) && (air1.temperature>0)) + if((air1.total_moles > 0) && (air1.temperature>0)) var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2) //Can not have a pressure delta that would cause output_pressure > input_pressure @@ -172,4 +172,4 @@ "\blue You have unfastened \the [src].", \ "You hear ratchet.") new /obj/item/pipe(loc, make_from=src) - del(src) \ No newline at end of file + del(src) diff --git a/code/ATMOSPHERICS/components/binary_devices/pump.dm b/code/ATMOSPHERICS/components/binary_devices/pump.dm index 944ed53de16..acacb2e3def 100644 --- a/code/ATMOSPHERICS/components/binary_devices/pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/pump.dm @@ -69,7 +69,7 @@ Thus, the two variables affect pump operation are set in New(): return 1 //Calculate necessary moles to transfer using PV=nRT - if((air1.total_moles() > 0) && (air1.temperature>0)) + if((air1.total_moles > 0) && (air1.temperature>0)) var/pressure_delta = target_pressure - output_starting_pressure var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION) @@ -204,4 +204,4 @@ Thus, the two variables affect pump operation are set in New(): "\blue You have unfastened \the [src].", \ "You hear ratchet.") new /obj/item/pipe(loc, make_from=src) - del(src) \ No newline at end of file + del(src) diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm index 1d1d335cb8a..9f4abcb8d0f 100644 --- a/code/ATMOSPHERICS/components/omni_devices/filter.dm +++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm @@ -46,7 +46,7 @@ ..() if(!on) return 0 - + if(!input || !output) return @@ -54,7 +54,7 @@ var/datum/gas_mixture/input_air = input.air // it's completely happy with them if they're in a loop though i.e. "P.air.return_pressure()"... *shrug* var/output_pressure = output_air.return_pressure() - + if(output_pressure >= target_pressure) return for(var/datum/omni_port/P in filters) @@ -63,49 +63,46 @@ var/pressure_delta = target_pressure - output_pressure - if(input_air.return_temperature() > 0) - input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION) + if(input_air.temperature > 0) + input.transfer_moles = pressure_delta * output_air.volume / (input_air.temperature * R_IDEAL_GAS_EQUATION) if(input.transfer_moles > 0) var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles) - + if(!removed) return - + for(var/datum/omni_port/P in filters) var/datum/gas_mixture/filtered_out = new - filtered_out.temperature = removed.return_temperature() - + filtered_out.temperature = removed.temperature + switch(P.mode) if(ATM_O2) - filtered_out.oxygen = removed.oxygen - removed.oxygen = 0 + filtered_out.gas["oxygen"] = removed.gas["oxygen"] + removed.gas["oxygen"] = null if(ATM_N2) - filtered_out.nitrogen = removed.nitrogen - removed.nitrogen = 0 + filtered_out.gas["nitrogen"] = removed.gas["nitrogen"] + removed.gas["nitrogen"] = null if(ATM_CO2) - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 + filtered_out.gas["carbon_dioxide"] = removed.gas["carbon_dioxide"] + removed.gas["carbon_dioxide"] = null if(ATM_P) - filtered_out.phoron = removed.phoron - removed.phoron = 0 + filtered_out.gas["phoron"] = removed.gas["phoron"] + removed.gas["phoron"] = null if(ATM_N2O) - if(removed.trace_gases.len>0) - for(var/datum/gas/sleeping_agent/trace_gas in removed.trace_gases) - if(istype(trace_gas)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas + filtered_out.gas["sleeping_agent"] = removed.gas["sleeping_agent"] + removed.gas["sleeping_agent"] = null else filtered_out = null - + P.air.merge(filtered_out) if(P.network) P.network.update = 1 - + output_air.merge(removed) if(output.network) output.network.update = 1 - + input.transfer_moles = 0 if(input.network) input.network.update = 1 diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm index 3b5dd1780fe..666825c1cd6 100644 --- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/omni_devices/mixer.dm @@ -9,7 +9,7 @@ var/datum/omni_port/output //setup tags for initial concentration values (must be decimal) - var/tag_north_con + var/tag_north_con var/tag_south_con var/tag_east_con var/tag_west_con @@ -101,22 +101,22 @@ var/pressure_delta = target_pressure - output_pressure for(var/datum/omni_port/P in inputs) - if(P.air.return_temperature() > 0) - P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION) + if(P.air.temperature > 0) + P.transfer_moles = (P.concentration * pressure_delta) * output_air.volume / (P.air.temperature * R_IDEAL_GAS_EQUATION) var/ratio_check = null for(var/datum/omni_port/P in inputs) if(!P.transfer_moles) return - if(P.air.total_moles() < P.transfer_moles) + if(P.air.total_moles < P.transfer_moles) ratio_check = 1 continue if(ratio_check) var/list/ratio_list = new() for(var/datum/omni_port/P in inputs) - ratio_list.Add(P.air.total_moles() / P.transfer_moles) + ratio_list.Add(P.air.total_moles / P.transfer_moles) var/ratio = min(ratio_list) diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 594190bdb8a..ff27f2becf3 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -41,7 +41,7 @@ Filter types: icon_state = "m" else icon_state = "" - + if(!powered()) icon_state += "off" else if(node2 && node3 && node1) @@ -106,38 +106,31 @@ Filter types: switch(filter_type) if(0) //removing hydrocarbons - filtered_out.phoron = removed.phoron - removed.phoron = 0 + filtered_out.gas["phoron"] = removed.gas["phoron"] + removed.gas["phoron"] = 0 - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/oxygen_agent_b)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas + filtered_out.gas["oxygen_agent_b"] = removed.gas["oxygen_agent_b"] + removed.gas["oxygen_agent_b"] = 0 if(1) //removing O2 - filtered_out.oxygen = removed.oxygen - removed.oxygen = 0 + filtered_out.gas["oxygen"] = removed.gas["oxygen"] + removed.gas["oxygen"] = 0 if(2) //removing N2 - filtered_out.nitrogen = removed.nitrogen - removed.nitrogen = 0 + filtered_out.gas["nitrogen"] = removed.gas["nitrogen"] + removed.gas["nitrogen"] = 0 if(3) //removing CO2 - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 + filtered_out.gas["carbon_dioxide"] = removed.gas["carbon_dioxide"] + removed.gas["carbon_dioxide"] = 0 if(4)//removing N2O - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/sleeping_agent)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas + filtered_out.gas["sleeping_agent"] = removed.gas["sleeping_agent"] + removed.gas["sleeping_agent"] = 0 else filtered_out = null - air2.merge(filtered_out) air3.merge(removed) @@ -272,7 +265,7 @@ obj/machinery/atmospherics/trinary/filter/m_filter/New() /obj/machinery/atmospherics/trinary/filter/m_filter/initialize() set_frequency(frequency) - + if(node1 && node2 && node3) return var/node1_connect = turn(dir, -180) @@ -295,4 +288,4 @@ obj/machinery/atmospherics/trinary/filter/m_filter/New() break update_icon() - update_underlays() \ No newline at end of file + update_underlays() diff --git a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm index 228be72020d..3dbfd1fb51c 100644 --- a/code/ATMOSPHERICS/components/trinary_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/mixer.dm @@ -19,7 +19,7 @@ icon_state = "t" else icon_state = "" - + if(!powered()) icon_state += "off" else if(node2 && node3 && node1) @@ -83,8 +83,8 @@ if(air2.temperature > 0) transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION) - var/air1_moles = air1.total_moles() - var/air2_moles = air2.total_moles() + var/air1_moles = air1.total_moles + var/air2_moles = air2.total_moles if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2)) if(!transfer_moles1 || !transfer_moles2) return @@ -271,4 +271,4 @@ obj/machinery/atmospherics/trinary/mixer/m_mixer/initialize() break update_icon() - update_underlays() \ No newline at end of file + update_underlays() diff --git a/code/ATMOSPHERICS/components/unary/oxygen_generator.dm b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm index 9a58be7c302..14bbb46bbaa 100644 --- a/code/ATMOSPHERICS/components/unary/oxygen_generator.dm +++ b/code/ATMOSPHERICS/components/unary/oxygen_generator.dm @@ -33,7 +33,7 @@ obj/machinery/atmospherics/unary/oxygen_generator if(!on) return 0 - var/total_moles = air_contents.total_moles() + var/total_moles = air_contents.total_moles if(total_moles < oxygen_content) var/current_heat_capacity = air_contents.heat_capacity() @@ -41,7 +41,7 @@ obj/machinery/atmospherics/unary/oxygen_generator var/added_oxygen = oxygen_content - total_moles air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen) - air_contents.oxygen += added_oxygen + air_contents.adjust_gas("oxygen", added_oxygen) if(network) network.update = 1 diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 64514b3ebf7..9506da2459c 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -45,7 +45,7 @@ return overlays.Cut() - + var/scrubber_icon = "scrubber" var/turf/T = get_turf(src) @@ -125,8 +125,8 @@ var/datum/gas_mixture/environment = loc.return_air() if(scrubbing) - if((environment.phoron>0.001) || (environment.carbon_dioxide>0.001) || (environment.trace_gases.len>0)) - var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles() + if((environment.gas["phoron"]>0.001) || (environment.gas["carbon_dioxide"]>0.001) || (environment.gas["oxygen_agent_b"]>0.001) || (environment.gas["sleeping_agent"]>0.001)) + var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles //Take a gas sample var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) @@ -137,21 +137,17 @@ var/datum/gas_mixture/filtered_out = new filtered_out.temperature = removed.temperature if(scrub_Toxins) - filtered_out.phoron = removed.phoron - removed.phoron = 0 + filtered_out.gas["phoron"] = removed.gas["phoron"] + removed.gas["phoron"] = 0 if(scrub_CO2) - filtered_out.carbon_dioxide = removed.carbon_dioxide - removed.carbon_dioxide = 0 - - if(removed.trace_gases.len>0) - for(var/datum/gas/trace_gas in removed.trace_gases) - if(istype(trace_gas, /datum/gas/oxygen_agent_b)) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - else if(istype(trace_gas, /datum/gas/sleeping_agent) && scrub_N2O) - removed.trace_gases -= trace_gas - filtered_out.trace_gases += trace_gas - + filtered_out.gas["carbon_dioxide"] = removed.gas["carbon_dioxide"] + removed.gas["carbon_dioxide"] = 0 + if(scrub_N2O) + filtered_out.gas["sleeping_agent"] = removed.gas["sleeping_agent"] + removed.gas["sleeping_agent"] = 0 + if(removed.gas["oxygen_agent_b"]) + filtered_out.gas["oxygen_agent_b"] = removed.gas["oxygen_agent_b"] + removed.gas["oxygen_agent_b"] = 0 //Remix the resulting gases air_contents.merge(filtered_out) @@ -165,7 +161,7 @@ if (air_contents.return_pressure()>=50*ONE_ATMOSPHERE) return - var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume) + var/transfer_moles = environment.total_moles*(volume_rate/environment.volume) var/datum/gas_mixture/removed = loc.remove_air(transfer_moles) diff --git a/code/ATMOSPHERICS/datum_pipe_network.dm b/code/ATMOSPHERICS/datum_pipe_network.dm index 168e5521b6e..0728ff1f4a3 100644 --- a/code/ATMOSPHERICS/datum_pipe_network.dm +++ b/code/ATMOSPHERICS/datum_pipe_network.dm @@ -8,10 +8,10 @@ datum/pipe_network //membership roster to go through for updates and what not var/update = 1 - var/datum/gas_mixture/air_transient = null + //var/datum/gas_mixture/air_transient = null New() - air_transient = new() + //air_transient = new() ..() @@ -70,135 +70,4 @@ datum/pipe_network gases += line_member.air proc/reconcile_air() - //Perfectly equalize all gases members instantly - - //Calculate totals from individual components - var/total_thermal_energy = 0 - var/total_heat_capacity = 0 - - air_transient.volume = 0 - - air_transient.oxygen = 0 - air_transient.nitrogen = 0 - air_transient.phoron = 0 - air_transient.carbon_dioxide = 0 - - - air_transient.trace_gases = list() - - for(var/datum/gas_mixture/gas in gases) - air_transient.volume += gas.volume - var/temp_heatcap = gas.heat_capacity() - total_thermal_energy += gas.temperature*temp_heatcap - total_heat_capacity += temp_heatcap - - air_transient.oxygen += gas.oxygen - air_transient.nitrogen += gas.nitrogen - air_transient.phoron += gas.phoron - air_transient.carbon_dioxide += gas.carbon_dioxide - - if(gas.trace_gases.len) - for(var/datum/gas/trace_gas in gas.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in air_transient.trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - air_transient.trace_gases += corresponding - - corresponding.moles += trace_gas.moles - - if(air_transient.volume > 0) - - if(total_heat_capacity > 0) - air_transient.temperature = total_thermal_energy/total_heat_capacity - - //Allow air mixture to react - if(air_transient.react()) - update = 1 - - else - air_transient.temperature = 0 - - //Update individual gas_mixtures by volume ratio - for(var/datum/gas_mixture/gas in gases) - gas.oxygen = air_transient.oxygen*gas.volume/air_transient.volume - gas.nitrogen = air_transient.nitrogen*gas.volume/air_transient.volume - gas.phoron = air_transient.phoron*gas.volume/air_transient.volume - gas.carbon_dioxide = air_transient.carbon_dioxide*gas.volume/air_transient.volume - - gas.temperature = air_transient.temperature - - if(air_transient.trace_gases.len) - for(var/datum/gas/trace_gas in air_transient.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - gas.trace_gases += corresponding - - corresponding.moles = trace_gas.moles*gas.volume/air_transient.volume - gas.update_values() - air_transient.update_values() - return 1 - -proc/equalize_gases(datum/gas_mixture/list/gases) - //Perfectly equalize all gases members instantly - - //Calculate totals from individual components - var/total_volume = 0 - var/total_thermal_energy = 0 - var/total_heat_capacity = 0 - - var/total_oxygen = 0 - var/total_nitrogen = 0 - var/total_phoron = 0 - var/total_carbon_dioxide = 0 - - var/list/total_trace_gases = list() - - for(var/datum/gas_mixture/gas in gases) - total_volume += gas.volume - var/temp_heatcap = gas.heat_capacity() - total_thermal_energy += gas.temperature*temp_heatcap - total_heat_capacity += temp_heatcap - - total_oxygen += gas.oxygen - total_nitrogen += gas.nitrogen - total_phoron += gas.phoron - total_carbon_dioxide += gas.carbon_dioxide - - if(gas.trace_gases.len) - for(var/datum/gas/trace_gas in gas.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in total_trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - total_trace_gases += corresponding - - corresponding.moles += trace_gas.moles - - if(total_volume > 0) - - //Calculate temperature - var/temperature = 0 - - if(total_heat_capacity > 0) - temperature = total_thermal_energy/total_heat_capacity - - //Update individual gas_mixtures by volume ratio - for(var/datum/gas_mixture/gas in gases) - gas.oxygen = total_oxygen*gas.volume/total_volume - gas.nitrogen = total_nitrogen*gas.volume/total_volume - gas.phoron = total_phoron*gas.volume/total_volume - gas.carbon_dioxide = total_carbon_dioxide*gas.volume/total_volume - - gas.temperature = temperature - - if(total_trace_gases.len) - for(var/datum/gas/trace_gas in total_trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - gas.trace_gases += corresponding - - corresponding.moles = trace_gas.moles*gas.volume/total_volume - gas.update_values() - - return 1 \ No newline at end of file + equalize_gases(gases) diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index b7444d00df8..4c3b191617e 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -37,22 +37,9 @@ datum/pipeline for(var/obj/machinery/atmospherics/pipe/member in members) member.air_temporary = new + member.air_temporary.copy_from(air) member.air_temporary.volume = member.volume - - member.air_temporary.oxygen = air.oxygen*member.volume/air.volume - member.air_temporary.nitrogen = air.nitrogen*member.volume/air.volume - member.air_temporary.phoron = air.phoron*member.volume/air.volume - member.air_temporary.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume - - member.air_temporary.temperature = air.temperature - - if(air.trace_gases.len) - for(var/datum/gas/trace_gas in air.trace_gases) - var/datum/gas/corresponding = new trace_gas.type() - member.air_temporary.trace_gases += corresponding - - corresponding.moles = trace_gas.moles*member.volume/air.volume - member.air_temporary.update_values() + member.air_temporary.multiply(member.volume / air.volume) proc/build_pipeline(obj/machinery/atmospherics/pipe/base) air = new @@ -213,7 +200,7 @@ datum/pipeline air.temperature -= heat/total_heat_capacity if(network) network.update = 1 - + proc/radiate_heat(surface, thermal_conductivity) var/total_heat_capacity = air.heat_capacity() var/heat = STEFAN_BOLTZMANN_CONSTANT * surface * air.temperature ** 4 * thermal_conductivity diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 7ee65162d76..6fca9cc2ca5 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -106,7 +106,7 @@ update_icon() /obj/machinery/atmospherics/pipe/add_underlay(var/obj/machinery/atmospherics/node, var/direction) - if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices + if(istype(src, /obj/machinery/atmospherics/pipe/tank)) //todo: move tanks to unary devices return ..() if(node) @@ -157,7 +157,7 @@ /obj/machinery/atmospherics/pipe/simple/New() ..() - + // Pipe colors and icon states are handled by an image cache - so color and icon should // be null. For mapping purposes color is defined in the object definitions. icon = null @@ -473,7 +473,7 @@ overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "core") overlays += icon_manager.get_atmos_icon("manifold", , , "clamps") underlays.Cut() - + var/list/directions = list(NORTH, SOUTH, EAST, WEST) directions -= dir @@ -678,7 +678,7 @@ overlays += icon_manager.get_atmos_icon("manifold", , pipe_color, "4way") overlays += icon_manager.get_atmos_icon("manifold", , , "clamps_4way") underlays.Cut() - + var/list/directions = list(NORTH, SOUTH, EAST, WEST) directions -= add_underlay(node1) @@ -931,24 +931,13 @@ O << "\red [user] has used the analyzer on \icon[icon]" var/pressure = parent.air.return_pressure() - var/total_moles = parent.air.total_moles() + var/total_moles = parent.air.total_moles user << "\blue Results of analysis of \icon[icon]" if (total_moles>0) - var/o2_concentration = parent.air.oxygen/total_moles - var/n2_concentration = parent.air.nitrogen/total_moles - var/co2_concentration = parent.air.carbon_dioxide/total_moles - var/phoron_concentration = parent.air.phoron/total_moles - - var/unknown_concentration = 1-(o2_concentration+n2_concentration+co2_concentration+phoron_concentration) - user << "\blue Pressure: [round(pressure,0.1)] kPa" - user << "\blue Nitrogen: [round(n2_concentration*100)]%" - user << "\blue Oxygen: [round(o2_concentration*100)]%" - user << "\blue CO2: [round(co2_concentration*100)]%" - user << "\blue Phoron: [round(phoron_concentration*100)]%" - if(unknown_concentration>0.01) - user << "\red Unknown: [round(unknown_concentration*100)]%" + for(var/g in parent.air.gas) + user << "\blue [gas_data.name[g]]: [round((parent.air.gas[g] / total_moles) * 100)]%" user << "\blue Temperature: [round(parent.air.temperature-T0C)]°C" else user << "\blue Tank is empty!" @@ -962,10 +951,11 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.oxygen = (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - air_temporary.nitrogen = (25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.adjust_multi("oxygen", (25*ONE_ATMOSPHERE*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \ + "nitrogen",(25*ONE_ATMOSPHERE*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) - ..() + + ..() icon_state = "air" /obj/machinery/atmospherics/pipe/tank/oxygen @@ -977,7 +967,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.oxygen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.adjust_gas("oxygen", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "o2" @@ -991,7 +981,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.nitrogen = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.adjust_gas("nitrogen", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "n2" @@ -1005,7 +995,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.carbon_dioxide = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.adjust_gas("carbon_dioxide", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "co2" @@ -1019,7 +1009,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.phoron = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) + air_temporary.adjust_gas("phoron", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "phoron" @@ -1033,10 +1023,7 @@ air_temporary.volume = volume air_temporary.temperature = T0C - var/datum/gas/sleeping_agent/trace_gas = new - trace_gas.moles = (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature) - - air_temporary.trace_gases += trace_gas + air_temporary.adjust_gas("sleeping_agent", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "n2o" diff --git a/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm b/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm index c31d6138dff..cd397e10958 100644 --- a/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm +++ b/code/WorkInProgress/Cael_Aislinn/Rust/core_field.dm @@ -140,20 +140,19 @@ Deuterium-tritium fusion: 4.5 x 10^7 K //the amount of phoron pulled in each update is relative to the field strength, with 50T (max field strength) = 100% of area covered by the field //at minimum strength, 0.25% of the field volume is pulled in per update (?) //have a max of 1000 moles suspended - if(held_phoron.phoron < transfer_ratio * 1000) + if(held_phoron.gas["phoron"] < transfer_ratio * 1000) var/moles_covered = environment.return_pressure()*volume_covered/(environment.temperature * R_IDEAL_GAS_EQUATION) //world << "\blue moles_covered: [moles_covered]" // var/datum/gas_mixture/gas_covered = environment.remove(moles_covered) var/datum/gas_mixture/phoron_captured = new /datum/gas_mixture() // - phoron_captured.phoron = round(gas_covered.phoron * transfer_ratio) + phoron_captured.gas["phoron"] = round(gas_covered.gas["phoron"] * transfer_ratio) //world << "\blue[phoron_captured.phoron] moles of phoron captured" phoron_captured.temperature = gas_covered.temperature phoron_captured.update_values() // - gas_covered.phoron -= phoron_captured.phoron - gas_covered.update_values() + gas_covered.adjust_gas("phoron", -phoron_captured.gas["phoron"]) // held_phoron.merge(phoron_captured) // @@ -171,7 +170,7 @@ Deuterium-tritium fusion: 4.5 x 10^7 K //change held phoron temp according to energy levels //SPECIFIC_HEAT_TOXIN - if(mega_energy > 0 && held_phoron.phoron) + if(mega_energy > 0 && held_phoron.gas["phoron"]) var/heat_capacity = held_phoron.heat_capacity()//200 * number of phoron moles if(heat_capacity > 0.0003) //formerly MINIMUM_HEAT_CAPACITY held_phoron.temperature = (heat_capacity + mega_energy * 35000)/heat_capacity @@ -179,7 +178,7 @@ Deuterium-tritium fusion: 4.5 x 10^7 K //if there is too much phoron in the field, lose some /*if( held_phoron.phoron > (MOLES_CELLSTANDARD * 7) * (50 / field_strength) ) LosePhoron()*/ - if(held_phoron.phoron > 1) + if(held_phoron.gas["phoron"] > 1) //lose a random amount of phoron back into the air, increased by the field strength (want to switch this over to frequency eventually) var/loss_ratio = rand() * (0.05 + (0.05 * 50 / field_strength)) //world << "lost [loss_ratio*100]% of held phoron" @@ -187,16 +186,16 @@ Deuterium-tritium fusion: 4.5 x 10^7 K var/datum/gas_mixture/phoron_lost = new phoron_lost.temperature = held_phoron.temperature // - phoron_lost.phoron = held_phoron.phoron * loss_ratio + phoron_lost.gas["phoron"] = held_phoron.gas["phoron"] * loss_ratio //phoron_lost.update_values() - held_phoron.phoron -= held_phoron.phoron * loss_ratio + held_phoron.gas["phoron"] -= held_phoron.gas["phoron"] * loss_ratio //held_phoron.update_values() // environment.merge(phoron_lost) radiation += loss_ratio * mega_energy * 0.1 mega_energy -= loss_ratio * mega_energy * 0.1 else - held_phoron.phoron = 0 + held_phoron.gas["phoron"] = null //held_phoron.update_values() //handle some reactants formatting diff --git a/code/ZAS/ConnectionGroup.dm b/code/ZAS/ConnectionGroup.dm index 481492e7e29..7fab5e94adc 100644 --- a/code/ZAS/ConnectionGroup.dm +++ b/code/ZAS/ConnectionGroup.dm @@ -86,7 +86,8 @@ Class Procs: /connection_edge/proc/tick() /connection_edge/proc/flow(list/movable, differential, repelled) - for(var/atom/movable/M in movable) + for(var/i = 1; i <= movable.len; i++) + var/atom/movable/M = movable[i] //If they're already being tossed, don't do it again. if(M.last_airflow > world.time - vsc.airflow_delay) continue @@ -156,7 +157,7 @@ Class Procs: return //air_master.equalize(A, B) - ShareRatio(A.air,B.air,coefficient) + A.air.share_ratio(B.air, coefficient) air_master.mark_zone_update(A) air_master.mark_zone_update(B) //world << "equalized." @@ -215,7 +216,7 @@ Class Procs: return //world << "[id]: Tick [air_master.current_cycle]: To [B]!" //A.air.mimic(B, coefficient) - ShareSpace(A.air,air,dbg_out) + A.air.share_space(air, dbg_out) air_master.mark_zone_update(A) var/differential = A.air.return_pressure() - air.return_pressure() @@ -224,196 +225,6 @@ Class Procs: var/list/attracted = A.movables() flow(attracted, abs(differential), differential < 0) -var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) - -proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) - //Shares a specific ratio of gas between mixtures using simple weighted averages. - var - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - ratio = sharing_lookup_table[6] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - size = max(1,A.group_multiplier) - share_size = max(1,B.group_multiplier) - - full_oxy = A.oxygen * size - full_nitro = A.nitrogen * size - full_co2 = A.carbon_dioxide * size - full_phoron = A.phoron * size - - full_heat_capacity = A.heat_capacity() * size - - s_full_oxy = B.oxygen * share_size - s_full_nitro = B.nitrogen * share_size - s_full_co2 = B.carbon_dioxide * share_size - s_full_phoron = B.phoron * share_size - - s_full_heat_capacity = B.heat_capacity() * share_size - - oxy_avg = (full_oxy + s_full_oxy) / (size + share_size) - nit_avg = (full_nitro + s_full_nitro) / (size + share_size) - co2_avg = (full_co2 + s_full_co2) / (size + share_size) - phoron_avg = (full_phoron + s_full_phoron) / (size + share_size) - - temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) - - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[connecting_tiles] - //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD - - A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) - A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg ) - A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) - A.phoron = max(0, (A.phoron - phoron_avg) * (1-ratio) + phoron_avg ) - - A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg ) - - B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg ) - B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg ) - B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg ) - B.phoron = max(0, (B.phoron - phoron_avg) * (1-ratio) + phoron_avg ) - - B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg ) - - for(var/datum/gas/G in A.trace_gases) - var/datum/gas/H = locate(G.type) in B.trace_gases - if(H) - var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - else - H = new G.type - B.trace_gases += H - var/G_avg = (G.moles*size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - - for(var/datum/gas/G in B.trace_gases) - var/datum/gas/H = locate(G.type) in A.trace_gases - if(!H) - H = new G.type - A.trace_gases += H - var/G_avg = (G.moles*size) / (size+share_size) - G.moles = (G.moles - G_avg) * (1-ratio) + G_avg - H.moles = (H.moles - G_avg) * (1-ratio) + G_avg - - A.update_values() - B.update_values() - - if(A.compare(B)) return 1 - else return 0 - -proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) - //A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room. - if(!unsimulated_tiles) - return 0 - - var - unsim_oxygen = 0 - unsim_nitrogen = 0 - unsim_co2 = 0 - unsim_phoron = 0 - unsim_heat_capacity = 0 - unsim_temperature = 0 - - size = max(1,A.group_multiplier) - - var/tileslen - var/share_size - - if(istype(unsimulated_tiles, /datum/gas_mixture)) - var/datum/gas_mixture/avg_unsim = unsimulated_tiles - unsim_oxygen = avg_unsim.oxygen - unsim_co2 = avg_unsim.carbon_dioxide - unsim_nitrogen = avg_unsim.nitrogen - unsim_phoron = avg_unsim.phoron - unsim_temperature = avg_unsim.temperature - share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier) - tileslen = avg_unsim.group_multiplier - - if(dbg_output) - world << "O2: [unsim_oxygen] N2: [unsim_nitrogen] Size: [share_size] Tiles: [tileslen]" - - else if(istype(unsimulated_tiles, /list)) - if(!unsimulated_tiles.len) - return 0 - // We use the same size for the potentially single space tile - // as we use for the entire room. Why is this? - // Short answer: We do not want larger rooms to depressurize more - // slowly than small rooms, preserving our good old "hollywood-style" - // oh-shit effect when large rooms get breached, but still having small - // rooms remain pressurized for long enough to make escape possible. - share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len) - var/correction_ratio = share_size / unsimulated_tiles.len - - for(var/turf/T in unsimulated_tiles) - unsim_oxygen += T.oxygen - unsim_co2 += T.carbon_dioxide - unsim_nitrogen += T.nitrogen - unsim_phoron += T.phoron - unsim_temperature += T.temperature/unsimulated_tiles.len - - //These values require adjustment in order to properly represent a room of the specified size. - unsim_oxygen *= correction_ratio - unsim_co2 *= correction_ratio - unsim_nitrogen *= correction_ratio - unsim_phoron *= correction_ratio - tileslen = unsimulated_tiles.len - - else //invalid input type - return 0 - - unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_phoron) - - var - ratio = sharing_lookup_table[6] - - old_pressure = A.return_pressure() - - full_oxy = A.oxygen * size - full_nitro = A.nitrogen * size - full_co2 = A.carbon_dioxide * size - full_phoron = A.phoron * size - - full_heat_capacity = A.heat_capacity() * size - - oxy_avg = (full_oxy + unsim_oxygen*share_size) / (size + share_size) - nit_avg = (full_nitro + unsim_nitrogen*share_size) / (size + share_size) - co2_avg = (full_co2 + unsim_co2*share_size) / (size + share_size) - phoron_avg = (full_phoron + unsim_phoron*share_size) / (size + share_size) - - temp_avg = 0 - - if((full_heat_capacity + unsim_heat_capacity) > 0) - temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity) - - if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick. - ratio = sharing_lookup_table[tileslen] - - if(dbg_output) - world << "Ratio: [ratio]" - world << "Avg O2: [oxy_avg] N2: [nit_avg]" - - A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg ) - A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg ) - A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg ) - A.phoron = max(0, (A.phoron - phoron_avg) * (1 - ratio) + phoron_avg ) - - 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) - G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg - - A.update_values() - - if(dbg_output) world << "Result: [abs(old_pressure - A.return_pressure())] kPa" - - return abs(old_pressure - A.return_pressure()) - - proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) //This implements a simplistic version of the Stefan-Boltzmann law. var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5 diff --git a/code/ZAS/Controller.dm b/code/ZAS/Controller.dm index cef6b068a84..756887cc09c 100644 --- a/code/ZAS/Controller.dm +++ b/code/ZAS/Controller.dm @@ -73,6 +73,7 @@ Class Procs: //Geometry updates lists /datum/controller/air_system/var/list/tiles_to_update = list() /datum/controller/air_system/var/list/zones_to_update = list() +/datum/controller/air_system/var/list/active_fire_zones = list() /datum/controller/air_system/var/list/active_hotspots = list() /datum/controller/air_system/var/active_zones = 0 @@ -171,9 +172,16 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun for(var/connection_edge/edge in edges) edge.tick() - //Process fires. + //Process fire zones. if(.) - tick_progress = "processing fire" + tick_progress = "processing fire zones" + + for(var/zone/Z in active_fire_zones) + Z.process_fire() + + //Process hotspots. + if(.) + tick_progress = "processing hotspots" for(var/obj/fire/fire in active_hotspots) fire.process() diff --git a/code/ZAS/Diagnostic.dm b/code/ZAS/Diagnostic.dm index 31deb69bc52..1d4cc1a3883 100644 --- a/code/ZAS/Diagnostic.dm +++ b/code/ZAS/Diagnostic.dm @@ -19,7 +19,8 @@ client/proc/Zone_Info(turf/T as null|turf) mob << "No zone here." var/datum/gas_mixture/mix = T.return_air() mob << "[mix.return_pressure()] kPa [mix.temperature]C" - mob << "O2: [mix.oxygen] N2: [mix.nitrogen] CO2: [mix.carbon_dioxide] TX: [mix.phoron]" + for(var/g in mix.gas) + mob << "[g]: [mix.gas[g]]\n" else if(zone_debug_images) for(var/zone in zone_debug_images) diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 2d181dc6009..d8738d5fc5e 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -10,6 +10,7 @@ Attach to transfer valve and open. BOOM. */ +/turf/var/obj/fire/fire = null //Some legacy definitions so fires can be started. atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume) @@ -34,12 +35,54 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) if(air_contents.check_combustability(liquid)) igniting = 1 - if(! (locate(/obj/fire) in src)) - - new /obj/fire(src,1000) - + create_fire(1000) return igniting +/zone/proc/process_fire() + if(!air.check_combustability()) + for(var/turf/simulated/T in fire_tiles) + if(istype(T.fire)) + T.fire.RemoveFire() + T.fire = null + fire_tiles.Cut() + + if(!fire_tiles.len) + air_master.active_fire_zones.Remove(src) + return + + var/datum/gas_mixture/burn_gas = air.remove_ratio(vsc.fire_consuption_rate, fire_tiles.len) + var/gm = burn_gas.group_multiplier + + burn_gas.group_multiplier = 1 + burn_gas.zburn(force_burn = 1, no_check = 1) + burn_gas.group_multiplier = gm + + air.merge(burn_gas) + + var/firelevel = air.calculate_firelevel() + + for(var/turf/T in fire_tiles) + if(T.fire) + T.fire.firelevel = firelevel + else + fire_tiles -= T + +/turf/proc/create_fire(fl) + return 0 + +/turf/simulated/create_fire(fl) + if(fire) + fire.firelevel = max(fl, fire.firelevel) + return 1 + + if(!zone) + return 1 + + fire = new(src, fl) + zone.fire_tiles |= src + air_master.active_fire_zones |= zone + return 0 + /obj/fire //Icon for fire on turfs. @@ -58,41 +101,14 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) /obj/fire/process() . = 1 - //get location and check if it is in a proper ZAS zone - var/turf/simulated/S = loc - - if(!istype(S)) - del src - return - - if(!S.zone) - del src - return - - 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 - - //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.1) - air_contents.oxygen = 0 - if(air_contents.phoron < 0.1) - air_contents.phoron = 0 - if(fuel) - if(fuel.moles < 0.1) - air_contents.trace_gases.Remove(fuel) - - //check if there is something to combust - if(!air_contents.check_combustability(liquid)) - //del src + var/turf/simulated/my_tile = loc + if(!istype(my_tile) || !my_tile.zone) + if(my_tile.fire == src) + my_tile.fire = null RemoveFire() - return + return 1 - //get a firelevel and set the icon - firelevel = air_contents.calculate_firelevel(liquid) + var/datum/gas_mixture/air_contents = my_tile.return_air() if(firelevel > 6) icon_state = "3" @@ -106,21 +122,26 @@ 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! + M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the humans! - loc.fire_act(air_contents, air_contents.temperature, air_contents.return_volume()) + loc.fire_act(air_contents, air_contents.temperature, air_contents.volume) for(var/atom/A in loc) - A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume()) + A.fire_act(air_contents, air_contents.temperature, air_contents.volume) + //spread for(var/direction in cardinal) - var/turf/simulated/enemy_tile = get_step(S, direction) + var/turf/simulated/enemy_tile = get_step(my_tile, direction) if(istype(enemy_tile)) - if(S.open_directions & direction) //Grab all valid bordering tiles - 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_combustability(liq)) continue + if(my_tile.open_directions & direction) //Grab all valid bordering tiles + if(!enemy_tile.zone || enemy_tile.fire) + continue + + if(!enemy_tile.zone.fire_tiles.len) + var/datum/gas_mixture/acs = enemy_tile.return_air() + if(!acs || !acs.check_combustability()) + 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) @@ -128,26 +149,11 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) continue //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)) - new/obj/fire(enemy_tile,firelevel) + if(prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && my_tile.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, my_tile, 0,0)) + enemy_tile.create_fire(firelevel) else - enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.return_volume()) - - //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) -///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR /////////////////////////////////////////////// - - if(flow) - //burn baby burn! - flow.zburn(liquid,1) - //merge the air back - S.assume_air(flow) - -///////////////////////////////// FLOW HAS BEEN REMERGED /// feel free to delete the fire again from here on ////////////////////////////////////////////////////////////////// - + enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.volume) /obj/fire/New(newLoc,fl) ..() @@ -171,31 +177,29 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) ..() /obj/fire/proc/RemoveFire() - if (istype(loc, /turf/simulated)) + if (istype(loc, /turf)) SetLuminosity(0) loc = null air_master.active_hotspots.Remove(src) - turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again. turf/proc/apply_fire_protection() turf/simulated/apply_fire_protection() fire_protection = world.time -datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn) - var/value = 0 - - if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid)) +datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn, no_check = 0) + . = 0 + if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(liquid))) var/total_fuel = 0 - var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + var/total_oxidizers = 0 - total_fuel += phoron - - if(fuel) - //Volatile Fuel - total_fuel += fuel.moles + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL) + total_fuel += gas[g] + if(gas_data.flags[g] & XGM_GAS_OXIDIZER) + total_oxidizers += gas[g] if(liquid) //Liquid Fuel @@ -208,36 +212,29 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc return 0 //Calculate the firelevel. - var/firelevel = calculate_firelevel(liquid) + var/firelevel = calculate_firelevel(liquid, total_fuel, total_oxidizers, force = 1) //get the current inner energy of the gas mix //this must be taken here to prevent the addition or deletion of energy by a changing heat capacity var/starting_energy = temperature * heat_capacity() //determine the amount of oxygen used - var/total_oxygen = min(oxygen, 2 * total_fuel) + var/used_oxidizers = min(total_oxidizers, 2 * total_fuel) //determine the amount of fuel actually used - var/used_fuel_ratio = min(oxygen / 2 , total_fuel) / total_fuel + var/used_fuel_ratio = min(total_oxidizers / 2 , total_fuel) / total_fuel total_fuel = total_fuel * used_fuel_ratio - var/total_reactants = total_fuel + total_oxygen + var/total_reactants = total_fuel + used_oxidizers //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 / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants //remove and add gasses as calculated - oxygen -= min(oxygen, total_oxygen * used_reactants_ratio ) + remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers * used_reactants_ratio) + remove_by_flag(XGM_GAS_FUEL, total_fuel * used_reactants_ratio * 3) - phoron -= min(phoron, (phoron * used_fuel_ratio * used_reactants_ratio ) * 3) - if(phoron < 0) - phoron = 0 - - carbon_dioxide += max(2 * total_fuel, 0) - - if(fuel) - fuel.moles -= (fuel.moles * used_fuel_ratio * used_reactants_ratio) * 5 //Fuel burns 5 times as quick - if(fuel.moles <= 0) del fuel + adjust_gas("carbon_dioxide", max(2 * total_fuel, 0)) if(liquid) liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick @@ -248,64 +245,67 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity() update_values() - value = total_reactants * used_reactants_ratio - return value + . = total_reactants * used_reactants_ratio 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. + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_OXIDIZER && gas[g] >= 0.1) + . = 1 + break - var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + if(!.) + return 0 - if(oxygen && (phoron || fuel || liquid)) - if(liquid) - return 1 - if(phoron >= 0.1) - return 1 - if(fuel && fuel.moles >= 0.1) - return 1 + if(liquid) + return 1 - return 0 + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL && gas[g] >= 0.1) + . = 1 + break 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 + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_OXIDIZER && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) + . = 1 + break - var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + if(!.) + return 0 - if(oxygen && (phoron || fuel || liquid)) - if(liquid) - return 1 - if(QUANTIZE(phoron * vsc.fire_consuption_rate) >= 0.1) - return 1 - if(fuel && QUANTIZE(fuel.moles * vsc.fire_consuption_rate) >= 0.1) - return 1 + if(liquid) + return 1 - return 0 + . = 0 + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1) + . = 1 + break -datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid) +datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid, total_fuel = null, total_oxidizers = null, force = 0) //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. - - var/datum/gas/volatile_fuel/fuel = locate() in trace_gases - var/total_fuel = 0 var/firelevel = 0 - if(check_recombustability(liquid)) + if(force || check_recombustability(liquid)) + if(isnull(total_fuel)) + for(var/g in gas) + if(gas_data.flags[g] & XGM_GAS_FUEL) + total_fuel += gas[g] + if(gas_data.flags[g] & XGM_GAS_OXIDIZER) + total_oxidizers += gas[g] + if(liquid) + total_fuel += liquid.amount - total_fuel += phoron - - if(liquid) - total_fuel += liquid.amount - - if(fuel) - total_fuel += fuel.moles - - var/total_combustables = (total_fuel + oxygen) - - if(total_fuel > 0 && oxygen > 0) + var/total_combustables = (total_fuel + total_oxidizers) + if(total_combustables > 0) //slows down the burning when the concentration of the reactants is low - var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide) + var/dampening_multiplier = total_combustables / total_moles //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 * ((total_oxidizers / total_combustables) ** 2))) //toss everything together firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier diff --git a/code/ZAS/Gas.dm b/code/ZAS/Gas.dm new file mode 100644 index 00000000000..66a996457a7 --- /dev/null +++ b/code/ZAS/Gas.dm @@ -0,0 +1,45 @@ +/xgm_gas/oxygen + id = "oxygen" + name = "Oxygen" + specific_heat = 20 + + flags = XGM_GAS_OXIDIZER + +/xgm_gas/nitrogen + id = "nitrogen" + name = "Nitrogen" + specific_heat = 20 + +/xgm_gas/carbon_dioxide + id = "carbon_dioxide" + name = "Carbon Dioxide" + specific_heat = 30 + +/xgm_gas/phoron + id = "phoron" + name = "Phoron" + specific_heat = 200 + + tile_overlay = "phoron" + overlay_limit = 0.7 + flags = XGM_GAS_FUEL | XGM_GAS_CONTAMINANT + +/xgm_gas/volatile_fuel + id = "volatile_fuel" + name = "Volatile Fuel" + specific_heat = 30 + + flags = XGM_GAS_FUEL + +/xgm_gas/sleeping_agent + id = "sleeping_agent" + name = "Sleeping Agent" + specific_heat = 40 + + tile_overlay = "sleeping_agent" + overlay_limit = 1 + +/xgm_gas/oxygen_agent_b + id = "oxygen_agent_b" + name = "Oxygen Agent-B" + specific_heat = 300 diff --git a/code/ZAS/Phoron.dm b/code/ZAS/Phoron.dm index f96e47c188d..98ab1278257 100644 --- a/code/ZAS/Phoron.dm +++ b/code/ZAS/Phoron.dm @@ -111,7 +111,7 @@ obj/var/contaminated = 0 if(vsc.plc.GENETIC_CORRUPTION) if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION) randmutb(src) - src << "\red High levels of phoron cause you to spontaneously mutate." + src << "\red High levels of toxins cause you to spontaneously mutate." domutcheck(src,null) @@ -155,10 +155,11 @@ obj/var/contaminated = 0 turf/Entered(obj/item/I) . = ..() //Items that are in phoron, but not on a mob, can still be contaminated. - if(istype(I) && vsc.plc.CLOTH_CONTAMINATION) + if(istype(I) && vsc.plc.CLOTH_CONTAMINATION && I.can_contaminate()) var/datum/gas_mixture/env = return_air(1) if(!env) return - if(env.phoron > MOLES_PHORON_VISIBLE + 1) - if(I.can_contaminate()) - I.contaminate() \ No newline at end of file + for(var/g in env.gas) + if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && env.gas[g] > gas_data.overlay_limit[g] + 1) + I.contaminate() + break diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm index 35dc8f684eb..4e70e3b627f 100644 --- a/code/ZAS/Turf.dm +++ b/code/ZAS/Turf.dm @@ -6,12 +6,10 @@ /turf/var/datum/gas_mixture/air /turf/simulated/proc/set_graphic(new_graphic) - if(isnum(new_graphic)) - if(new_graphic == 1) new_graphic = plmaster - else if(new_graphic == 2) new_graphic = slmaster - if(gas_graphic) overlays -= gas_graphic - if(new_graphic) overlays += new_graphic gas_graphic = new_graphic + overlays.Cut() + for(var/i in gas_graphic) + overlays += i /turf/proc/update_air_properties() var/block = c_airblock(src) @@ -185,17 +183,15 @@ /turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air return 0 +/turf/proc/assume_gas(gasid, moles, temp = 0) + return 0 + /turf/return_air() //Create gas mixture to hold data for passing var/datum/gas_mixture/GM = new - GM.oxygen = oxygen - GM.carbon_dioxide = carbon_dioxide - GM.nitrogen = nitrogen - GM.phoron = phoron - + GM.adjust_multi("oxygen", oxygen, "carbon_dioxide", carbon_dioxide, "nitrogen", nitrogen, "phoron", phoron) GM.temperature = temperature - GM.update_values() return GM @@ -204,10 +200,10 @@ var/sum = oxygen + carbon_dioxide + nitrogen + phoron if(sum>0) - GM.oxygen = (oxygen/sum)*amount - GM.carbon_dioxide = (carbon_dioxide/sum)*amount - GM.nitrogen = (nitrogen/sum)*amount - GM.phoron = (phoron/sum)*amount + GM.gas["oxygen"] = (oxygen/sum)*amount + GM.gas["carbon_dioxide"] = (carbon_dioxide/sum)*amount + GM.gas["nitrogen"] = (nitrogen/sum)*amount + GM.gas["phoron"] = (phoron/sum)*amount GM.temperature = temperature GM.update_values() @@ -218,6 +214,16 @@ var/datum/gas_mixture/my_air = return_air() my_air.merge(giver) +/turf/simulated/assume_gas(gasid, moles, temp = null) + var/datum/gas_mixture/my_air = return_air() + + if(isnull(temp)) + my_air.adjust_gas(gasid, moles) + else + my_air.adjust_gas_temp(gasid, moles, temp) + + return 1 + /turf/simulated/remove_air(amount as num) var/datum/gas_mixture/my_air = return_air() return my_air.remove(amount) @@ -240,11 +246,11 @@ /turf/proc/make_air() air = new/datum/gas_mixture air.temperature = temperature - air.adjust(oxygen, carbon_dioxide, nitrogen, phoron) + air.adjust_multi("oxygen", oxygen, "carbon_dioxide", carbon_dioxide, "nitrogen", nitrogen, "phoron", phoron) air.group_multiplier = 1 air.volume = CELL_VOLUME /turf/simulated/proc/c_copy_air() if(!air) air = new/datum/gas_mixture air.copy_from(zone.air) - air.group_multiplier = 1 \ No newline at end of file + air.group_multiplier = 1 diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm index 2d285d08f6f..40c509bbd90 100644 --- a/code/ZAS/Zone.dm +++ b/code/ZAS/Zone.dm @@ -43,6 +43,7 @@ Class Procs: /zone/var/name /zone/var/invalid = 0 /zone/var/list/contents = list() +/zone/var/list/fire_tiles = list() /zone/var/needs_update = 0 @@ -67,6 +68,9 @@ Class Procs: add_tile_air(turf_air) T.zone = src contents.Add(T) + if(T.fire) + fire_tiles.Add(T) + air_master.active_fire_zones.Add(src) T.set_graphic(air.graphic) /zone/proc/remove(turf/simulated/T) @@ -77,6 +81,7 @@ Class Procs: soft_assert(T in contents, "Lists are weird broseph") #endif contents.Remove(T) + fire_tiles.Remove(T) T.zone = null T.set_graphic(0) if(contents.len) @@ -123,16 +128,16 @@ Class Procs: air.group_multiplier = contents.len+1 /zone/proc/tick() - air.archive() if(air.check_tile_graphic()) for(var/turf/simulated/T in contents) T.set_graphic(air.graphic) /zone/proc/dbg_data(mob/M) M << name - M << "O2: [air.oxygen] N2: [air.nitrogen] CO2: [air.carbon_dioxide] P: [air.phoron]" + for(var/g in air.gas) + M << "[gas_data.name[g]]: [air.gas[g]]" M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)" - M << "O2 per N2: [(air.nitrogen ? air.oxygen/air.nitrogen : "N/A")] Moles: [air.total_moles]" + M << "O2 per N2: [(air.gas["nitrogen"] ? air.gas["oxygen"]/air.gas["nitrogen"] : "N/A")] Moles: [air.total_moles]" M << "Simulated: [contents.len] ([air.group_multiplier])" //M << "Unsimulated: [unsimulated_contents.len]" //M << "Edges: [edges.len]" diff --git a/code/ZAS/_gas_mixture_xgm.dm b/code/ZAS/_gas_mixture_xgm.dm new file mode 100644 index 00000000000..a60fc0bc09d --- /dev/null +++ b/code/ZAS/_gas_mixture_xgm.dm @@ -0,0 +1,367 @@ +#define QUANTIZE(variable) (round(variable,0.0001)) + +/datum/gas_mixture + //Associative list of gas moles. + //Gases with 0 moles are not tracked and are pruned by update_values() + var/list/gas = list() + //Temperature in Kelvin of this gas mix. + var/temperature = 0 + + //Sum of all the gas moles in this mix. Updated by update_values() + var/total_moles = 0 + //Volume of this mix. + var/volume = CELL_VOLUME + //Size of the group this gas_mixture is representing. 1 for singletons. + var/group_multiplier = 1 + + //List of active tile overlays for this gas_mixture. Updated by check_tile_graphic() + var/list/graphic = list() + +//Takes a gas string, and the amount of moles to adjust by. Calls update_values() if update isn't 0. +/datum/gas_mixture/proc/adjust_gas(gasid, moles, update = 1) + if(moles == 0) + return + + gas[gasid] += moles + + if(update) + update_values() + +//Same as adjust_gas(), but takes a temperature which is mixed in with the gas. +/datum/gas_mixture/proc/adjust_gas_temp(gasid, moles, temp, update = 1) + if(moles == 0) + return + + if(moles > 0 && abs(temperature - temp) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()*group_multiplier + var/giver_heat_capacity = gas_data.specific_heat[gasid] * moles + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (temp * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity + + gas[gasid] += moles + + if(update) + update_values() + +//Variadic version of adjust_gas(). Takes any number of gas and mole pairs, and applies them. +/datum/gas_mixture/proc/adjust_multi() + ASSERT(!(args.len % 2)) + + for(var/i = 1; i < args.len; i += 2) + adjust_gas(args[i], args[i+1], update = 0) + + update_values() + +//Variadic version of adjust_gas_temp(). Takes any number of gas, mole, and temperature tuples, and applies them. +/datum/gas_mixture/proc/adjust_multi_temp() + ASSERT(!(args.len % 3)) + + for(var/i = 1; i < args.len; i += 3) + adjust_gas_temp(args[i], args[i + 1], args[i + 2], update = 0) + + update_values() + +//Merges all the gas from another mixture into this one. Respects group_multiplies and adjusts temperature correctly. +/datum/gas_mixture/proc/merge(datum/gas_mixture/giver) + if(!giver) + return + + if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()*group_multiplier + var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity + + if((group_multiplier != 1)||(giver.group_multiplier != 1)) + for(var/g in giver.gas) + gas[g] += giver.gas[g] * giver.group_multiplier / group_multiplier + else + for(var/g in giver.gas) + gas[g] += giver.gas[g] + + update_values() + +//Returns the heat capacity of the gas mix based on the specific heat of the gases. +/datum/gas_mixture/proc/heat_capacity() + . = 0 + for(var/g in gas) + . += gas_data.specific_heat[g] * gas[g] + +//Updates the total_moles count and trims any empty gases. +/datum/gas_mixture/proc/update_values() + total_moles = 0 + for(var/g in gas) + if(gas[g] <= 0) + gas -= g + else + total_moles += gas[g] + +//Returns the pressure of the gas mix. Only accurate if there have been no gas modifications since update_values() has been called. +/datum/gas_mixture/proc/return_pressure() + if(volume) + return total_moles * R_IDEAL_GAS_EQUATION * temperature / volume + return 0 + +//Removes moles from the gas mixture and returns a gas_mixture containing the removed air. +/datum/gas_mixture/proc/remove(amount) + var/sum = total_moles + amount = min(amount, sum) //Can not take more air than tile has! + if(amount <= 0) + return null + + var/datum/gas_mixture/removed = new + + for(var/g in gas) + removed.gas[g] = QUANTIZE((gas[g] / sum) * amount) + gas[g] -= removed.gas[g] / group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +//Removes a ratio of gas from the mixture and returns a gas_mixture containing the removed air. +/datum/gas_mixture/proc/remove_ratio(ratio, out_group_multiplier = 1) + if(ratio <= 0) + return null + out_group_multiplier = max(1, min(group_multiplier, out_group_multiplier)) + + ratio = min(ratio, 1) + + var/datum/gas_mixture/removed = new + removed.group_multiplier = out_group_multiplier + + for(var/g in gas) + removed.gas[g] = QUANTIZE(gas[g] * ratio) + gas[g] = ((gas[g] * group_multiplier) - (removed.gas[g] * out_group_multiplier)) / group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +//Removes moles from the gas mixture, limited by a given flag. Returns a gax_mixture containing the removed air. +/datum/gas_mixture/proc/remove_by_flag(flag, amount) + if(!flag || amount <= 0) + return + + var/sum = 0 + for(var/g in gas) + if(gas_data.flags[g] & flag) + sum += gas[g] + + var/datum/gas_mixture/removed = new + + for(var/g in gas) + if(gas_data.flags[g] & flag) + removed.gas[g] = QUANTIZE((gas[g] / sum) * amount) + gas[g] -= removed.gas[g] / group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +//Copies gas and temperature from another gas_mixture. +/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample) + gas = sample.gas.Copy() + temperature = sample.temperature + + update_values() + + return 1 + +//Checks if we are within acceptable range of another gas_mixture to suspend processing. +/datum/gas_mixture/proc/compare(datum/gas_mixture/sample) + if(!sample) return 0 + + var/list/marked = list() + for(var/g in gas) + if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \ + ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \ + (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]))) + return 0 + marked[g] = 1 + + for(var/g in sample.gas) + if(!marked[g]) + if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \ + ((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \ + (gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]))) + return 0 + + if(total_moles > MINIMUM_AIR_TO_SUSPEND) + if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ + ((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || \ + (temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) + return 0 + + return 1 + +/datum/gas_mixture/proc/react(atom/dump_location) + zburn(null) + +//Rechecks the gas_mixture and adjusts the graphic list if needed. +/datum/gas_mixture/proc/check_tile_graphic() + //List of new overlays that weren't valid before. + var/list/graphic_add = null + //List of overlays that need to be removed now that they're not valid. + var/list/graphic_remove = null + + for(var/g in gas_data.overlay_limit) + if(graphic.Find(gas_data.tile_overlay[g])) + //Overlay is already applied for this gas, check if it's still valid. + if(gas[g] <= gas_data.overlay_limit[g]) + if(!graphic_remove) + graphic_remove = list() + graphic_remove += gas_data.tile_overlay[g] + else + //Overlay isn't applied for this gas, check if it's valid and needs to be added. + if(gas[g] > gas_data.overlay_limit[g]) + if(!graphic_add) + graphic_add = list() + graphic_add += gas_data.tile_overlay[g] + + . = 0 + //Apply changes + if(graphic_add && graphic_add.len) + graphic += graphic_add + . = 1 + if(graphic_remove && graphic_remove.len) + graphic -= graphic_remove + . = 1 + +//Simpler version of merge(), adjusts gas amounts directly and doesn't account for temperature or group_multiplier. +/datum/gas_mixture/proc/add(datum/gas_mixture/right_side) + for(var/g in right_side.gas) + gas[g] += right_side.gas[g] + + update_values() + return 1 + +//Simpler version of remove(), adjusts gas amounts directly and doesn't account for group_multiplier. +/datum/gas_mixture/proc/subtract(datum/gas_mixture/right_side) + for(var/g in right_side.gas) + gas[g] -= right_side.gas[g] + + update_values() + return 1 + +//Multiply all gas amounts by a factor. +/datum/gas_mixture/proc/multiply(factor) + for(var/g in gas) + gas[g] *= factor + + update_values() + return 1 + +//Divide all gas amounts by a factor. +/datum/gas_mixture/proc/divide(factor) + for(var/g in gas) + gas[g] /= factor + + update_values() + return 1 + +//Shares gas with another gas_mixture based on the amount of connecting tiles and a fixed lookup table. +/datum/gas_mixture/proc/share_ratio(datum/gas_mixture/other, connecting_tiles, share_size = null) + var/static/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) + //Shares a specific ratio of gas between mixtures using simple weighted averages. + var/ratio = sharing_lookup_table[6] + + var/size = max(1, group_multiplier) + if(isnull(share_size)) share_size = max(1, other.group_multiplier) + + var/list/full_gas = list() + for(var/g in gas) + full_gas[g] = gas[g] * size + + var/full_heat_capacity = heat_capacity() * size + + var/list/s_full_gas = list() + for(var/g in other.gas) + s_full_gas[g] = other.gas[g] * share_size + + var/s_full_heat_capacity = other.heat_capacity() * share_size + + var/list/avg_gas = list() + + for(var/g in full_gas) + avg_gas[g] = (full_gas[g] + s_full_gas[g]) / (size + share_size) + + for(var/g in s_full_gas) + if(avg_gas[g] == null) + avg_gas[g] = (full_gas[g] + s_full_gas[g]) / (size + share_size) + + var/temp_avg = 0 + if(full_heat_capacity + s_full_heat_capacity) + temp_avg = (temperature * full_heat_capacity + other.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity) + + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD. + if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick. + ratio = sharing_lookup_table[connecting_tiles] + //WOOT WOOT TOUCH THIS AND YOU ARE A RETARD + + for(var/g in avg_gas) + gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g]) + other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g]) + + temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg) + other.temperature = max(0, (other.temperature - temp_avg) * (1-ratio) + temp_avg) + + update_values() + other.update_values() + + if(compare(other)) return 1 + else return 0 + +//A wrapper around share_ratio for spacing gas at the same rate as if it were going into a large airless room. +/datum/gas_mixture/proc/share_space(datum/gas_mixture/unsim_air) + if(!unsim_air) + return 0 + + var/old_pressure = return_pressure() + + share_ratio(unsim_air, unsim_air.group_multiplier, max(1, max(group_multiplier + 3, 1) + unsim_air.group_multiplier)) + + return abs(old_pressure - return_pressure()) + +//Equalizes a list of gas mixtures. Used for pipe networks. +/proc/equalize_gases(datum/gas_mixture/list/gases) + //Calculate totals from individual components + var/total_volume = 0 + var/total_thermal_energy = 0 + var/total_heat_capacity = 0 + + var/list/total_gas = list() + for(var/datum/gas_mixture/gasmix in gases) + total_volume += gasmix.volume + var/temp_heatcap = gasmix.heat_capacity() + total_thermal_energy += gasmix.temperature * temp_heatcap + total_heat_capacity += temp_heatcap + for(var/g in gasmix.gas) + total_gas[g] += gasmix.gas[g] + + if(total_volume > 0) + //Average out the gases + for(var/g in total_gas) + total_gas[g] /= total_volume + + //Calculate temperature + var/temperature = 0 + + if(total_heat_capacity > 0) + temperature = total_thermal_energy / total_heat_capacity + + //Update individual gas_mixtures + for(var/datum/gas_mixture/gasmix in gases) + gasmix.gas = total_gas.Copy() + gasmix.temperature = temperature + gasmix.multiply(gasmix.volume) + + return 1 diff --git a/code/ZAS/_xgm_gas_data.dm b/code/ZAS/_xgm_gas_data.dm new file mode 100644 index 00000000000..ee33a4d57f3 --- /dev/null +++ b/code/ZAS/_xgm_gas_data.dm @@ -0,0 +1,42 @@ +/var/xgm_gas_data/gas_data + +/xgm_gas_data + //Simple list of all the gas IDs. + var/list/gases = list() + //The friendly, human-readable name for the gas. + var/list/name = list() + //Specific heat of the gas. Used for calculating heat capacity. + var/list/specific_heat = list() + //Tile overlays. /images, created from references to 'icons/effects/tile_effects.dmi' + var/list/tile_overlay = list() + //Overlay limits. There must be at least this many moles for the overlay to appear. + var/list/overlay_limit = list() + //Flags. + var/list/flags = list() + +/xgm_gas + var/id = "" + var/name = "Unnamed Gas" + var/specific_heat = 20 + + var/tile_overlay = null + var/overlay_limit = null + + var/flags = 0 + +/hook/startup/proc/generateGasData() + gas_data = new + for(var/p in (typesof(/xgm_gas) - /xgm_gas)) + var/xgm_gas/gas = new p + + if(gas.id in gas_data.gases) + error("Duplicate gas id `[gas.id]` in `[p]`") + + gas_data.gases += gas.id + gas_data.name[gas.id] = gas.name + gas_data.specific_heat[gas.id] = gas.specific_heat + if(gas.tile_overlay) gas_data.tile_overlay[gas.id] = image('icons/effects/tile_effects.dmi', gas.tile_overlay, FLY_LAYER) + if(gas.overlay_limit) gas_data.overlay_limit[gas.id] = gas.overlay_limit + gas_data.flags[gas.id] = gas.flags + + return 1 diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 63854ca1b51..0bc0cd986a6 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -104,6 +104,8 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al for (var/language_name in all_languages) var/datum/language/L = all_languages[language_name] language_keys[":[lowertext(L.key)]"] = L + language_keys[".[lowertext(L.key)]"] = L + language_keys["#[lowertext(L.key)]"] = L var/rkey = 0 paths = typesof(/datum/species)-/datum/species @@ -128,4 +130,4 @@ var/global/list/backbaglist = list("Nothing", "Backpack", "Satchel", "Satchel Al for(var/t in L) . += " has: [t]\n" world << . -*/ \ No newline at end of file +*/ diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm index ca053f86e6b..bf39744524a 100644 --- a/code/_onclick/hud/human.dm +++ b/code/_onclick/hud/human.dm @@ -13,6 +13,8 @@ using.icon = ui_style using.icon_state = "intent_"+mymob.a_intent using.screen_loc = ui_acti + using.color = ui_color + using.alpha = ui_alpha using.layer = 20 src.adding += using action_intent = using @@ -27,6 +29,7 @@ using.name = "help" using.icon = ico using.screen_loc = ui_acti + using.alpha = ui_alpha using.layer = 21 src.adding += using help_intent = using @@ -38,6 +41,7 @@ using.name = "disarm" using.icon = ico using.screen_loc = ui_acti + using.alpha = ui_alpha using.layer = 21 src.adding += using disarm_intent = using @@ -49,6 +53,7 @@ using.name = "grab" using.icon = ico using.screen_loc = ui_acti + using.alpha = ui_alpha using.layer = 21 src.adding += using grab_intent = using @@ -60,6 +65,7 @@ using.name = "harm" using.icon = ico using.screen_loc = ui_acti + using.alpha = ui_alpha using.layer = 21 src.adding += using hurt_intent = using @@ -440,23 +446,24 @@ //Handle the gun settings buttons mymob.gun_setting_icon = new /obj/screen/gun/mode(null) + //mymob.gun_setting_icon.color = ui_color + mymob.gun_setting_icon.alpha = ui_alpha + + mymob.item_use_icon = new /obj/screen/gun/item(null) + //mymob.item_use_icon.color = ui_color + mymob.item_use_icon.alpha = ui_alpha + + mymob.gun_move_icon = new /obj/screen/gun/move(null) + //mymob.gun_move_icon.color = ui_color + mymob.gun_move_icon.alpha = ui_alpha + + mymob.gun_run_icon = new /obj/screen/gun/run(null) + //mymob.gun_run_icon.color = ui_color + mymob.gun_run_icon.alpha = ui_alpha + if (mymob.client) if (mymob.client.gun_mode) // If in aim mode, correct the sprite mymob.gun_setting_icon.dir = 2 - for(var/obj/item/weapon/gun/G in mymob) // If targeting someone, display other buttons - if (G.target) - mymob.item_use_icon = new /obj/screen/gun/item(null) - if (mymob.client.target_can_click) - mymob.item_use_icon.dir = 1 - src.adding += mymob.item_use_icon - mymob.gun_move_icon = new /obj/screen/gun/move(null) - if (mymob.client.target_can_move) - mymob.gun_move_icon.dir = 1 - mymob.gun_run_icon = new /obj/screen/gun/run(null) - if (mymob.client.target_can_run) - mymob.gun_run_icon.dir = 1 - src.adding += mymob.gun_run_icon - src.adding += mymob.gun_move_icon mymob.client.screen = null @@ -495,7 +502,7 @@ for(var/obj/item/I in src) if(I.icon_action_button) var/obj/screen/item_action/A = new(hud_used) - + //A.icon = 'icons/mob/screen1_action.dmi' //A.icon_state = I.icon_action_button A.icon = ui_style2icon(client.prefs.UI_style) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 996ea857acf..c733d1ad35e 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -276,7 +276,7 @@ var/list/nicename = null var/list/tankcheck = null var/breathes = "oxygen" //default, we'll check later - var/list/contents = list() + var/list/contents = list() if(ishuman(C)) var/mob/living/carbon/human/H = C @@ -284,7 +284,7 @@ nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket") tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store) - else + else nicename = list("Right Hand", "Left Hand", "Back") tankcheck = list(C.r_hand, C.l_hand, C.back) @@ -295,30 +295,30 @@ if (!isnull(t.manipulated_by) && t.manipulated_by != C.real_name && findtext(t.desc,breathes)) contents.Add(t.air_contents.total_moles) //Someone messed with the tank and put unknown gasses continue //in it, so we're going to believe the tank is what it says it is - switch(breathes) + switch(breathes) //These tanks we're sure of their contents if("nitrogen") //So we're a bit more picky about them. - - if(t.air_contents.nitrogen && !t.air_contents.oxygen) - contents.Add(t.air_contents.nitrogen) + + if(t.air_contents.gas["nitrogen"] && !t.air_contents.gas["oxygen"]) + contents.Add(t.air_contents.gas["nitrogen"]) else - contents.Add(0) + contents.Add(0) if ("oxygen") - if(t.air_contents.oxygen && !t.air_contents.phoron) - contents.Add(t.air_contents.oxygen) + if(t.air_contents.gas["oxygen"] && !t.air_contents.gas["phoron"]) + contents.Add(t.air_contents.gas["oxygen"]) else contents.Add(0) // No races breath this, but never know about downstream servers. if ("carbon dioxide") - if(t.air_contents.carbon_dioxide && !t.air_contents.phoron) - contents.Add(t.air_contents.carbon_dioxide) + if(t.air_contents.gas["carbon_dioxide"] && !t.air_contents.gas["phoron"]) + contents.Add(t.air_contents.gas["carbon_dioxide"]) else contents.Add(0) - - - else + + + else //no tank so we set contents to 0 contents.Add(0) @@ -328,19 +328,19 @@ var/bestcontents = 0 for(var/i=1, i < contents.len + 1 , ++i) if(!contents[i]) - continue + continue if(contents[i] > bestcontents) best = i bestcontents = contents[i] - - + + //We've determined the best container now we set it as our internals if(best) C << "You are now running on internals from [tankcheck[best]] on your [nicename[best]]." C.internal = tankcheck[best] - - + + if(C.internal) if(C.internals) C.internals.icon_state = "internal1" diff --git a/code/controllers/lighting_controller.dm b/code/controllers/lighting_controller.dm index 3d4f859efaf..a938586e241 100644 --- a/code/controllers/lighting_controller.dm +++ b/code/controllers/lighting_controller.dm @@ -16,6 +16,8 @@ datum/controller/lighting var/list/changed_turfs = list() var/changed_turfs_workload_max = 0 + var/list/changed_areas = list() + datum/controller/lighting/New() lighting_states = max( 0, length(icon_states(LIGHTING_ICON))-1 ) if(lighting_controller != src) @@ -53,9 +55,18 @@ datum/controller/lighting/proc/process() for(var/i=1, i<=changed_turfs.len, i++) var/turf/T = changed_turfs[i] if(T && T.lighting_changed) + changed_areas |= T.loc T.shift_to_subarea() changed_turfs.Cut() // reset the changed list + for(var/i = 1; i <= changed_areas.len, i++) + var/area/A = changed_areas[i] + if(A.master != A && !A.contents.len) + A.related -= A + active_areas -= A + all_areas -= A + changed_areas.Cut() + process_cost = (world.timeofday - started) sleep(processing_interval) diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index 0b314a25312..cf9214079dc 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -292,7 +292,8 @@ datum/controller/game_controller/proc/process_machines_power() var/area/A = active_areas[i] if(A.powerupdate && A.master == A) A.powerupdate -= 1 - for(var/area/SubArea in A.related) + for(var/j = 1; j <= A.related.len; j++) + var/area/SubArea = A.related[j] for(var/obj/machinery/M in SubArea) if(M) if(M.use_power) diff --git a/code/controllers/verbs.dm b/code/controllers/verbs.dm index a331dab556c..b4ff1ed7ca8 100644 --- a/code/controllers/verbs.dm +++ b/code/controllers/verbs.dm @@ -48,7 +48,7 @@ message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.") return -/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller")) +/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data")) set category = "Debug" set name = "Debug Controller" set desc = "Debug the various periodic loop controllers for the game (be careful!)" @@ -100,5 +100,8 @@ if("Transfer Controller") debug_variables(transfer_controller) feedback_add_details("admin_verb","DAutovoter") + if("Gas Data") + debug_variables(gas_data) + feedback_add_details("admin_verv","DGasdata") message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.") return diff --git a/code/controllers/voting.dm b/code/controllers/voting.dm index ef1e41dd533..1aa410c87be 100644 --- a/code/controllers/voting.dm +++ b/code/controllers/voting.dm @@ -12,6 +12,7 @@ datum/controller/vote var/list/voted = list() var/list/voting = list() var/list/current_votes = list() + var/list/additional_text = list() var/auto_muted = 0 New() @@ -63,6 +64,7 @@ datum/controller/vote voted.Cut() voting.Cut() current_votes.Cut() + additional_text.Cut() /* if(auto_muted && !ooc_allowed) auto_muted = 0 @@ -210,6 +212,13 @@ datum/controller/vote if(ticker.current_state >= 2) return 0 choices.Add(config.votable_modes) + var/list/L = typesof(/datum/game_mode) - /datum/game_mode + for (var/F in choices) + for (var/T in L) + var/datum/game_mode/M = new T() + if (M.config_tag == F) + additional_text.Add("[M.required_players]") + break if("crew_transfer") if(check_rights(R_ADMIN|R_MOD, 0)) question = "End the shift?" @@ -290,16 +299,24 @@ datum/controller/vote if(mode) if(question) . += "

Vote: '[question]'

" else . += "

Vote: [capitalize(mode)]

" - . += "Time Left: [time_remaining] s