diff --git a/baystation12.dme b/baystation12.dme index 8d90f2ba4e8..1d8b91b8bd6 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -764,7 +764,6 @@ #include "code\modules\clothing\gloves\color.dm" #include "code\modules\clothing\gloves\miscellaneous.dm" #include "code\modules\clothing\gloves\ninja.dm" -#include "code\modules\clothing\gloves\stungloves.dm" #include "code\modules\clothing\head\collectable.dm" #include "code\modules\clothing\head\hardhat.dm" #include "code\modules\clothing\head\helmet.dm" @@ -1141,6 +1140,7 @@ #include "code\modules\power\port_gen.dm" #include "code\modules\power\power.dm" #include "code\modules\power\power_monitor.dm" +#include "code\modules\power\powernet.dm" #include "code\modules\power\profiling.dm" #include "code\modules\power\smes.dm" #include "code\modules\power\smes_construction.dm" diff --git a/code/ATMOSPHERICS/_atmos_setup.dm b/code/ATMOSPHERICS/_atmos_setup.dm index c11b51dbc3d..01a8eb003ee 100644 --- a/code/ATMOSPHERICS/_atmos_setup.dm +++ b/code/ATMOSPHERICS/_atmos_setup.dm @@ -110,6 +110,19 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_ I.color = pipe_colors[pipe_color] pipe_icons[state + "[pipe_colors[pipe_color]]"] = I + pipe = new ('icons/atmos/heat.dmi') + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + pipe_icons["hepipe" + state] = image('icons/atmos/heat.dmi', icon_state = state) + + pipe = new ('icons/atmos/junction.dmi') + for(var/state in pipe.IconStates()) + if(!state || findtext(state, "map")) + continue + pipe_icons["hejunction" + state] = image('icons/atmos/junction.dmi', icon_state = state) + + /datum/pipe_icon_manager/proc/gen_manifold_icons() if(!manifold_icons) manifold_icons = new() @@ -268,4 +281,4 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_ if("pipe_intact-scrubbers") pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I -*/ \ No newline at end of file +*/ diff --git a/code/ATMOSPHERICS/_atmospherics_helpers.dm b/code/ATMOSPHERICS/_atmospherics_helpers.dm index aeeb11d77c8..8e3a2b0dd76 100644 --- a/code/ATMOSPHERICS/_atmospherics_helpers.dm +++ b/code/ATMOSPHERICS/_atmospherics_helpers.dm @@ -1,6 +1,6 @@ /* Atmos processes - + These procs generalize various processes used by atmos machinery, such as pumping, filtering, or scrubbing gas, allowing them to be reused elsewhere. If no gas was moved/pumped/filtered/whatever, they return a negative number. Otherwise they return the amount of energy needed to do whatever it is they do (equivalently power if done over 1 second). @@ -11,6 +11,15 @@ /obj/machinery/atmospherics/var/last_flow_rate = 0 /obj/machinery/portable_atmospherics/var/last_flow_rate = 0 + +/obj/machinery/atmospherics/var/debug = 0 + +/client/proc/atmos_toggle_debug(var/obj/machinery/atmospherics/M in view()) + set name = "Toggle Debug Messages" + set category = "Debug" + M.debug = !M.debug + usr << "[M]: Debug messages toggled [M.debug? "on" : "off"]." + //Generalized gas pumping proc. //Moves gas from one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was pumped. //transfer_moles - Limits the amount of moles to transfer. The actual amount of gas moved may also be limited by available_power, if given. @@ -18,38 +27,45 @@ /proc/pump_gas(var/obj/machinery/M, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/transfer_moles = null, var/available_power = null) if (source.total_moles < MINUMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing return -1 - - if (!transfer_moles) + + //var/source_moles_initial = source.total_moles + + if (isnull(transfer_moles)) transfer_moles = source.total_moles else transfer_moles = min(source.total_moles, transfer_moles) - + //Calculate the amount of energy required and limit transfer_moles based on available power var/specific_power = calculate_specific_power(source, sink)/ATMOS_PUMP_EFFICIENCY //this has to be calculated before we modify any gas mixtures if (!isnull(available_power) && specific_power > 0) transfer_moles = min(transfer_moles, available_power / specific_power) - + if (transfer_moles < MINUMUM_MOLES_TO_PUMP) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //Update flow rate meter if (istype(M, /obj/machinery/atmospherics)) var/obj/machinery/atmospherics/A = M A.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here + + if (A.debug) + A.visible_message("[A]: source entropy: [round(source.specific_entropy(), 0.01)] J/Kmol --> sink entropy: [round(sink.specific_entropy(), 0.01)] J/Kmol") + A.visible_message("[A]: specific entropy change = [round(sink.specific_entropy() - source.specific_entropy(), 0.01)] J/Kmol") + A.visible_message("[A]: specific power = [round(specific_power, 0.1)] W/mol") + A.visible_message("[A]: moles transferred = [transfer_moles] mol") + if (istype(M, /obj/machinery/portable_atmospherics)) var/obj/machinery/portable_atmospherics/P = M P.last_flow_rate = (transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here - + var/datum/gas_mixture/removed = source.remove(transfer_moles) if (!removed) //Just in case return -1 - + var/power_draw = specific_power*transfer_moles - if (power_draw > 0) - removed.add_thermal_energy(power_draw) //1st law - energy is conserved - + sink.merge(removed) - + return power_draw //Generalized gas scrubbing proc. @@ -62,40 +78,40 @@ return -1 filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= - + //Determine the specific power of each filterable gas type, and the total amount of filterable gas (gasses selected to be scrubbed) var/total_filterable_moles = 0 //the total amount of filterable gas var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type for (var/g in filtering) if (source.gas[g] < MINUMUM_MOLES_TO_FILTER) continue - + var/specific_power = calculate_specific_power_gas(g, source, sink)/ATMOS_FILTER_EFFICIENCY specific_power_gas[g] = specific_power total_filterable_moles += source.gas[g] - + if (total_filterable_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //now that we know the total amount of filterable gas, we can calculate the amount of power needed to scrub one mole of gas var/total_specific_power = 0 //the power required to remove one mole of filterable gas for (var/g in filtering) var/ratio = source.gas[g]/total_filterable_moles //this converts the specific power per mole of pure gas to specific power per mole of scrubbed gas total_specific_power = specific_power_gas[g]*ratio - + //Figure out how much of each gas to filter - if (!total_transfer_moles) + if (isnull(total_transfer_moles)) total_transfer_moles = total_filterable_moles else total_transfer_moles = min(total_transfer_moles, total_filterable_moles) - + //limit transfer_moles based on available power if (!isnull(available_power) && total_specific_power > 0) total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) - + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //Update flow rate var if (istype(M, /obj/machinery/atmospherics)) var/obj/machinery/atmospherics/A = M @@ -103,30 +119,27 @@ if (istype(M, /obj/machinery/portable_atmospherics)) var/obj/machinery/portable_atmospherics/P = M P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here - + var/power_draw = 0 for (var/g in filtering) var/transfer_moles = source.gas[g] //filter gas in proportion to the mole ratio transfer_moles = min(transfer_moles, total_transfer_moles*(source.gas[g]/total_filterable_moles)) - + //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. source.adjust_gas(g, -transfer_moles, update=0) sink.adjust_gas_temp(g, transfer_moles, source.temperature, update=0) - + power_draw += specific_power_gas[g]*transfer_moles - + //Remix the resulting gases sink.update_values() source.update_values() - - if (power_draw > 0) - sink.add_thermal_energy(power_draw) //gotta conserve that energy - + return power_draw //Generalized gas filtering proc. -//Filtering is a bit different from scrubbing. Instead of selectively moving the targeted gas types from one gas mix to another, filtering splits +//Filtering is a bit different from scrubbing. Instead of selectively moving the targeted gas types from one gas mix to another, filtering splits //the input gas into two outputs: one that contains /only/ the targeted gas types, and another that completely clean of the targeted gas types. //filtering - A list of gasids to be filtered. These gasses get moved to sink_filtered, while the other gasses get moved to sink_clean. //total_transfer_moles - Limits the amount of moles to input. The actual amount of gas filtered may also be limited by available_power, if given. @@ -136,7 +149,7 @@ return -1 filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= - + var/total_specific_power = 0 //the power required to remove one mole of input gas var/total_filterable_moles = 0 //the total amount of filterable gas var/total_unfilterable_moles = 0 //the total amount of non-filterable gas @@ -144,30 +157,30 @@ for (var/g in source.gas) if (source.gas[g] < MINUMUM_MOLES_TO_FILTER) continue - + if (g in filtering) specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY total_filterable_moles += source.gas[g] else specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY total_unfilterable_moles += source.gas[g] - + var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix total_specific_power = specific_power_gas[g]*ratio - + //Figure out how much of each gas to filter - if (!total_transfer_moles) + if (isnull(total_transfer_moles)) total_transfer_moles = source.total_moles else total_transfer_moles = min(total_transfer_moles, source.total_moles) - + //limit transfer_moles based on available power if (!isnull(available_power) && total_specific_power > 0) total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) - + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //Update flow rate var if (istype(M, /obj/machinery/atmospherics)) var/obj/machinery/atmospherics/A = M @@ -175,16 +188,16 @@ if (istype(M, /obj/machinery/portable_atmospherics)) var/obj/machinery/portable_atmospherics/P = M P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here - + var/datum/gas_mixture/removed = source.remove(total_transfer_moles) if (!removed) //Just in case return -1 - + var/filtered_power_used = 0 //power used to move filterable gas to sink_filtered var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean for (var/g in removed.gas) var/power_used = specific_power_gas[g]*removed.gas[g] - + if (g in filtering) //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=0) @@ -192,17 +205,12 @@ filtered_power_used += power_used else unfiltered_power_used += power_used - + sink_filtered.update_values() removed.update_values() + sink_clean.merge(removed) - - //1LTD energy is conserved - if (filtered_power_used > 0) - sink_filtered.add_thermal_energy(filtered_power_used) - if (unfiltered_power_used > 0) - sink_clean.add_thermal_energy(unfiltered_power_used) - + return filtered_power_used + unfiltered_power_used //For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures. @@ -213,7 +221,7 @@ return -1 filtering = filtering & source.gas //only filter gasses that are actually there. DO NOT USE &= - + var/total_specific_power = 0 //the power required to remove one mole of input gas var/total_filterable_moles = 0 //the total amount of filterable gas var/total_unfilterable_moles = 0 //the total amount of non-filterable gas @@ -221,7 +229,7 @@ for (var/g in source.gas) if (source.gas[g] < MINUMUM_MOLES_TO_FILTER) continue - + if (g in filtering) var/datum/gas_mixture/sink_filtered = filtering[g] specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_filtered)/ATMOS_FILTER_EFFICIENCY @@ -229,23 +237,23 @@ else specific_power_gas[g] = calculate_specific_power_gas(g, source, sink_clean)/ATMOS_FILTER_EFFICIENCY total_unfilterable_moles += source.gas[g] - + var/ratio = source.gas[g]/source.total_moles //converts the specific power per mole of pure gas to specific power per mole of input gas mix total_specific_power = specific_power_gas[g]*ratio - + //Figure out how much of each gas to filter - if (!total_transfer_moles) + if (isnull(total_transfer_moles)) total_transfer_moles = source.total_moles else total_transfer_moles = min(total_transfer_moles, source.total_moles) - + //limit transfer_moles based on available power if (!isnull(available_power) && total_specific_power > 0) total_transfer_moles = min(total_transfer_moles, available_power/total_specific_power) - + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //Update Flow Rate var if (istype(M, /obj/machinery/atmospherics)) var/obj/machinery/atmospherics/A = M @@ -253,16 +261,16 @@ if (istype(M, /obj/machinery/portable_atmospherics)) var/obj/machinery/portable_atmospherics/P = M P.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here - + var/datum/gas_mixture/removed = source.remove(total_transfer_moles) if (!removed) //Just in case return -1 - + var/list/filtered_power_used = list() //power used to move filterable gas to the filtered gas mixes var/unfiltered_power_used = 0 //power used to move unfilterable gas to sink_clean for (var/g in removed.gas) var/power_used = specific_power_gas[g]*removed.gas[g] - + if (g in filtering) var/datum/gas_mixture/sink_filtered = filtering[g] //use update=0. All the filtered gasses are supposed to be added simultaneously, so we update after the for loop. @@ -272,18 +280,15 @@ filtered_power_used[sink_filtered] = power_used else unfiltered_power_used += power_used - + removed.update_values() - sink_clean.merge(removed) - - //1st LTD energy is conserved + var/power_draw = unfiltered_power_used for (var/datum/gas_mixture/sink_filtered in filtered_power_used) power_draw += filtered_power_used[sink_filtered] - sink_filtered.add_thermal_energy(filtered_power_used[sink_filtered]) - if (unfiltered_power_used > 0) - sink_clean.add_thermal_energy(unfiltered_power_used) - + + sink_clean.merge(removed) + return power_draw //Similar deal as the other atmos process procs. @@ -291,7 +296,7 @@ /proc/mix_gas(var/obj/machinery/M, var/list/mix_sources, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null) if (!mix_sources.len) return -1 - + var/total_specific_power = 0 //the power needed to mix one mole of gas var/total_mixing_moles = null //the total amount of gas that can be mixed, given our mix ratios var/total_input_volume = 0 //for flow rate calculation @@ -300,36 +305,36 @@ for (var/datum/gas_mixture/source in mix_sources) if (source.total_moles < MINUMUM_MOLES_TO_FILTER) return -1 //either mix at the set ratios or mix no gas at all - + var/mix_ratio = mix_sources[source] if (!mix_ratio) continue //this gas is not being mixed in - + //mixing rate is limited by the source with the least amount of available gas var/this_mixing_moles = source.total_moles/mix_ratio if (isnull(total_mixing_moles) || total_mixing_moles > this_mixing_moles) total_mixing_moles = this_mixing_moles - + source_specific_power[source] = calculate_specific_power(source, sink)*mix_ratio/ATMOS_FILTER_EFFICIENCY total_specific_power += source_specific_power[source] total_input_volume += source.volume total_input_moles += source.total_moles - + if (total_mixing_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - - if (!total_transfer_moles) + + if (isnull(total_transfer_moles)) total_transfer_moles = total_mixing_moles else total_transfer_moles = min(total_mixing_moles, total_transfer_moles) - + //limit transfer_moles based on available power if (!isnull(available_power) && total_specific_power > 0) total_transfer_moles = min(total_transfer_moles, available_power / total_specific_power) - + if (total_transfer_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing return -1 - + //Update flow rate var if (istype(M, /obj/machinery/atmospherics)) var/obj/machinery/atmospherics/A = M @@ -337,23 +342,22 @@ if (istype(M, /obj/machinery/portable_atmospherics)) var/obj/machinery/portable_atmospherics/P = M P.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here - + var/total_power_draw = 0 for (var/datum/gas_mixture/source in mix_sources) var/mix_ratio = mix_sources[source] if (!mix_ratio) continue - + var/transfer_moles = total_transfer_moles * mix_ratio - + var/datum/gas_mixture/removed = source.remove(transfer_moles) - + var/power_draw = transfer_moles * source_specific_power[source] - removed.add_thermal_energy(power_draw) //conservation of energy total_power_draw += power_draw - + sink.merge(removed) - + return total_power_draw /* @@ -366,11 +370,11 @@ var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature var/specific_entropy = sink.specific_entropy() - source.specific_entropy() //sink is gaining moles, source is loosing var/specific_power = 0 // W/mol - + //If specific_entropy is < 0 then power is required to move gas if (specific_entropy < 0) specific_power = -specific_entropy*air_temperature //how much power we need per mole - + return specific_power //Calculates the amount of power needed to move one mole of a certain gas from source to sink. @@ -379,11 +383,11 @@ var/air_temperature = (sink.temperature > 0)? sink.temperature : source.temperature var/specific_entropy = sink.specific_entropy_gas(gasid) - source.specific_entropy_gas(gasid) //sink is gaining moles, source is loosing var/specific_power = 0 // W/mol - + //If specific_entropy is < 0 then power is required to move gas if (specific_entropy < 0) specific_power = -specific_entropy*air_temperature //how much power we need per mole - + return specific_power //This proc handles power usages. @@ -399,7 +403,7 @@ use_power = 1 //Don't update here. We will use more power than we are supposed to, but trigger less area power updates. else update_use_power(1) - + switch (use_power) if (0) return 0 if (1) return idle_power_usage diff --git a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm index 1da0a6eb711..c31f6f92b78 100644 --- a/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm +++ b/code/ATMOSPHERICS/components/binary_devices/dp_vent_pump.dm @@ -129,7 +129,7 @@ var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) //limit flow rate from turfs - transfer_moles = min(transfer_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here + transfer_moles = min(transfer_moles, environment.total_moles*air2.volume/environment.volume) //group_multiplier gets divided out here power_draw = pump_gas(src, environment, air2, transfer_moles, active_power_usage) diff --git a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm index e70b478b140..d714d7ce1f9 100644 --- a/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm +++ b/code/ATMOSPHERICS/components/binary_devices/passive_gate.dm @@ -63,7 +63,7 @@ pressure_delta = target_pressure - output_starting_pressure var/flowing_old = flowing - if((REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures + if((regulate_mode == REGULATE_NONE || pressure_delta > 0.01) && (air1.temperature > 0 || air2.temperature > 0)) //since it's basically a valve, it makes sense to check both temperatures flowing = 1 //flow rate limit diff --git a/code/ATMOSPHERICS/components/omni_devices/filter.dm b/code/ATMOSPHERICS/components/omni_devices/filter.dm index e5188b7da49..0bb821e9eba 100644 --- a/code/ATMOSPHERICS/components/omni_devices/filter.dm +++ b/code/ATMOSPHERICS/components/omni_devices/filter.dm @@ -8,14 +8,14 @@ var/list/filters = new() var/datum/omni_port/input var/datum/omni_port/output - + use_power = 1 idle_power_usage = 150 //internal circuitry, friction losses and stuff active_power_usage = 7500 //This also doubles as a measure of how powerful the filter is, in Watts. 7500 W ~ 10 HP - + var/max_flow_rate = 200 var/set_flow_rate = 200 - + var/list/filtering_outputs = list() //maps gasids to gas_mixtures /obj/machinery/atmospherics/omni/filter/New() @@ -58,32 +58,26 @@ return 0 /obj/machinery/atmospherics/omni/filter/process() - ..() - if(error_check()) - on = 0 - - if((stat & (NOPOWER|BROKEN)) || !on) - update_use_power(0) //usually we get here because a player turned a pump off - definitely want to update. - last_flow_rate = 0 - return - + if(!..()) + return 0 + var/datum/gas_mixture/output_air = output.air //BYOND doesn't like referencing "output.air.return_pressure()" so we need to make a direct reference 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* - + //Figure out the amount of moles to transfer var/transfer_moles = (set_flow_rate/input_air.volume)*input_air.total_moles - + var/power_draw = -1 if (transfer_moles > MINUMUM_MOLES_TO_FILTER) power_draw = filter_gas_multi(src, filtering_outputs, input_air, output_air, transfer_moles, active_power_usage) - + if (power_draw < 0) //update_use_power(0) use_power = 0 //don't force update - easier on CPU last_flow_rate = 0 else handle_power_draw(power_draw) - + if(input.network) input.network.update = 1 if(output.network) @@ -91,7 +85,7 @@ for(var/datum/omni_port/P in filters) if(P.network) P.network.update = 1 - + return 1 /obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -252,7 +246,7 @@ P.mode = previous_mode if(P.mode != old_mode) handle_port_change(P) - + update_ports() /obj/machinery/atmospherics/omni/filter/proc/rebuild_filtering_list() diff --git a/code/ATMOSPHERICS/components/omni_devices/mixer.dm b/code/ATMOSPHERICS/components/omni_devices/mixer.dm index 89c148a943c..b59c0281c19 100644 --- a/code/ATMOSPHERICS/components/omni_devices/mixer.dm +++ b/code/ATMOSPHERICS/components/omni_devices/mixer.dm @@ -17,10 +17,10 @@ var/tag_south_con var/tag_east_con var/tag_west_con - + var/max_flow_rate = 200 var/set_flow_rate = 200 - + var/list/mixing_inputs = list() /obj/machinery/atmospherics/omni/mixer/New() @@ -45,7 +45,7 @@ if(tag_west_con && tag_west == 1) P.concentration = tag_west_con con += max(0, tag_west_con) - + for(var/datum/omni_port/P in ports) P.air.volume = ATMOS_DEFAULT_VOLUME_MIXER @@ -86,32 +86,26 @@ return 1 if(inputs.len < 2) //requires at least 2 inputs ~otherwise why are you using a mixer? return 1 - + //concentration must add to 1 var/total = 0 for (var/datum/omni_port/P in inputs) total += P.concentration - + if (total != 1) return 1 return 0 /obj/machinery/atmospherics/omni/mixer/process() - ..() - if(error_check()) - on = 0 - - if((stat & (NOPOWER|BROKEN)) || !on) - update_use_power(0) //usually we get here because a player turned a pump off - definitely want to update. - last_flow_rate = 0 - return - + if(!..()) + return 0 + //Figure out the amount of moles to transfer var/transfer_moles = 0 for (var/datum/omni_port/P in inputs) transfer_moles += (set_flow_rate*P.concentration/P.air.volume)*P.air.total_moles - + var/power_draw = -1 if (transfer_moles > MINUMUM_MOLES_TO_FILTER) power_draw = mix_gas(src, mixing_inputs, output, transfer_moles, active_power_usage) @@ -122,14 +116,14 @@ last_flow_rate = 0 else handle_power_draw(power_draw) - + for(var/datum/omni_port/P in inputs) if(P.concentration && P.network) P.network.update = 1 if(output.network) output.network.update = 1 - + return 1 /obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) @@ -291,7 +285,7 @@ P.concentration = new_con else if(!P.con_lock) P.concentration = remain_con - + rebuild_mixing_inputs() /obj/machinery/atmospherics/omni/mixer/proc/rebuild_mixing_inputs() diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm index eb5fbe7abee..7a24bf2fbb5 100644 --- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm +++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm @@ -50,10 +50,8 @@ /obj/machinery/atmospherics/omni/update_icon() if(stat & NOPOWER) overlays = overlays_off - on = 0 else if(error_check()) overlays = overlays_error - on = 0 else overlays = on ? (overlays_on) : (overlays_off) @@ -64,6 +62,16 @@ /obj/machinery/atmospherics/omni/proc/error_check() return +/obj/machinery/atmospherics/omni/process() + if(error_check()) + on = 0 + + if((stat & (NOPOWER|BROKEN)) || !on) + update_use_power(0) //usually we get here because a player turned a pump off - definitely want to update. + last_flow_rate = 0 + return 0 + return 1 + /obj/machinery/atmospherics/omni/power_change() var/old_stat = stat ..() diff --git a/code/ATMOSPHERICS/components/trinary_devices/filter.dm b/code/ATMOSPHERICS/components/trinary_devices/filter.dm index 7590c453e44..5649b25e012 100755 --- a/code/ATMOSPHERICS/components/trinary_devices/filter.dm +++ b/code/ATMOSPHERICS/components/trinary_devices/filter.dm @@ -23,7 +23,7 @@ 3: Carbon Dioxide: Carbon Dioxide ONLY 4: Sleeping Agent (N2O) */ - var/filter_type = 0 + var/filter_type = -1 var/list/filtered_out = list() @@ -38,6 +38,18 @@ /obj/machinery/atmospherics/trinary/filter/New() ..() + switch(filter_type) + if(0) //removing hydrocarbons + filtered_out = list("phoron", "oxygen_agent_b") + if(1) //removing O2 + filtered_out = list("oxygen") + if(2) //removing N2 + filtered_out = list("nitrogen") + if(3) //removing CO2 + filtered_out = list("carbon_dioxide") + if(4)//removing N2O + filtered_out = list("sleeping_agent") + air1.volume = ATMOS_DEFAULT_VOLUME_FILTER air2.volume = ATMOS_DEFAULT_VOLUME_FILTER air3.volume = ATMOS_DEFAULT_VOLUME_FILTER diff --git a/code/ATMOSPHERICS/components/unary/cold_sink.dm b/code/ATMOSPHERICS/components/unary/cold_sink.dm index d49de4adf25..bd3c3b17965 100644 --- a/code/ATMOSPHERICS/components/unary/cold_sink.dm +++ b/code/ATMOSPHERICS/components/unary/cold_sink.dm @@ -1,3 +1,6 @@ +//TODO: Put this under a common parent type with heaters to cut down on the copypasta +#define FREEZER_PERF_MULT 2.5 + /obj/machinery/atmospherics/unary/freezer name = "gas cooling system" desc = "Cools gas when connected to pipe network" @@ -7,14 +10,17 @@ anchored = 1.0 - var/heatsink_temperature = T20C //the constant temperature resevoir into which the freezer pumps heat. Probably the hull of the station or something. + var/heatsink_temperature = T20C //the constant temperature resevoir into which the freezer pumps heat. Probably the hull of the station or something. var/internal_volume = 600 //L - + var/on = 0 use_power = 0 - idle_power_usage = 5 //5 Watts for thermostat related circuitry - active_power_usage = 50000 //50 kW. The power rating of the freezer - + idle_power_usage = 5 //5 Watts for thermostat related circuitry + active_power_usage //50 kW. The power rating of the freezer + + var/max_power_usage = 20000 //power rating when the usage is turned up to 100 + var/power_setting = 100 + var/set_temperature = T20C //thermostat var/cooling = 0 var/opened = 0 //for deconstruction @@ -23,14 +29,16 @@ ..() air_contents.volume = internal_volume initialize_directions = dir - + component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/gas_cooler(src) + component_parts += new /obj/item/weapon/circuitboard/unary_atmos/cooler(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) component_parts += new /obj/item/weapon/stock_parts/manipulator(src) + active_power_usage = max_power_usage * (power_setting/100) + /obj/machinery/atmospherics/unary/freezer/initialize() if(node) return @@ -72,7 +80,8 @@ data["minGasTemperature"] = 0 data["maxGasTemperature"] = round(T20C+500) data["targetGasTemperature"] = round(set_temperature) - + data["powerSetting"] = power_setting + var/temp_class = "good" if (air_contents.temperature > (T0C - 20)) temp_class = "bad" @@ -104,6 +113,9 @@ src.set_temperature = min(src.set_temperature+amount, 1000) else src.set_temperature = max(src.set_temperature+amount, 0) + if(href_list["setPower"]) //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(href_list["setPower"]), 100) + set_power_level(new_setting) src.add_fingerprint(usr) return 1 @@ -113,30 +125,33 @@ if(stat & (NOPOWER|BROKEN) || !on) cooling = 0 update_use_power(0) + update_icon() return - + if (network && air_contents.temperature > set_temperature) cooling = 1 update_use_power(2) - - var/heat_transfer = min(abs(air_contents.get_thermal_energy_change(set_temperature)), active_power_usage) + + var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 ) //Assume the heat is being pumped into the hull which is fixed at heatsink_temperature //not /really/ proper thermodynamics but whatever - var/cop = air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop + var/cop = FREEZER_PERF_MULT * air_contents.temperature/heatsink_temperature //heatpump coefficient of performance from thermodynamics -> power used = heat_transfer/cop heat_transfer = min(heat_transfer, cop * active_power_usage) //limit heat transfer by available power - air_contents.add_thermal_energy(-heat_transfer) //remove the heat - + var/removed = -air_contents.add_thermal_energy(-heat_transfer) //remove the heat + if (debug) + visible_message("[src]: Removing [removed] W.") + network.update = 1 else cooling = 0 update_use_power(1) - + update_icon() //upgrading parts -/obj/machinery/atmospherics/unary/freezer/RefreshParts() +/obj/machinery/atmospherics/unary/freezer/RefreshParts() ..() var/cap_rating = 0 var/cap_count = 0 @@ -144,7 +159,7 @@ var/manip_count = 0 var/bin_rating = 0 var/bin_count = 0 - + for(var/obj/item/weapon/stock_parts/P in component_parts) if(istype(P, /obj/item/weapon/stock_parts/capacitor)) cap_rating += P.rating @@ -158,10 +173,20 @@ cap_rating /= cap_count bin_rating /= bin_count manip_rating /= manip_count - + active_power_usage = initial(active_power_usage)*cap_rating //more powerful heatsink_temperature = initial(heatsink_temperature)/((manip_rating+bin_rating)/2) //more efficient air_contents.volume = max(initial(internal_volume) - 200, 0) + 200*bin_rating + set_power_level(power_setting) + +/obj/machinery/atmospherics/unary/freezer/proc/set_power_level(var/new_power_setting) + power_setting = new_power_setting + + var/old_power_usage = active_power_usage + active_power_usage = max_power_usage * (power_setting/100) + + if (use_power >= 2 && old_power_usage != active_power_usage) + force_power_update() //dismantling code. copied from autolathe /obj/machinery/atmospherics/unary/freezer/attackby(var/obj/item/O as obj, var/mob/user as mob) @@ -173,7 +198,7 @@ if (opened && istype(O, /obj/item/weapon/crowbar)) dismantle() return - + ..() /obj/machinery/atmospherics/unary/freezer/examine() diff --git a/code/ATMOSPHERICS/components/unary/heat_source.dm b/code/ATMOSPHERICS/components/unary/heat_source.dm index f65de389458..707e740f66e 100644 --- a/code/ATMOSPHERICS/components/unary/heat_source.dm +++ b/code/ATMOSPHERICS/components/unary/heat_source.dm @@ -1,3 +1,5 @@ +//TODO: Put this under a common parent type with freezers to cut down on the copypasta + /obj/machinery/atmospherics/unary/heater name = "gas heating system" desc = "Heats gas when connected to a pipe network" @@ -13,9 +15,12 @@ var/on = 0 use_power = 0 - idle_power_usage = 5 //5 Watts for thermostat related circuitry - active_power_usage = 50000 //50 kW. The power rating of the heater + idle_power_usage = 5 //5 Watts for thermostat related circuitry + active_power_usage //50 kW. The power rating of the heater + var/max_power_usage = 20000 //power rating when the usage is turned up to 100 + var/power_setting = 100 + var/heating = 0 //mainly for icon updates var/opened = 0 //for deconstruction @@ -23,12 +28,14 @@ ..() air_contents.volume = internal_volume initialize_directions = dir - + component_parts = list() - component_parts += new /obj/item/weapon/circuitboard/gas_heater(src) + component_parts += new /obj/item/weapon/circuitboard/unary_atmos/heater(src) component_parts += new /obj/item/weapon/stock_parts/matter_bin(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) component_parts += new /obj/item/weapon/stock_parts/capacitor(src) + + active_power_usage = max_power_usage * (power_setting/100) /obj/machinery/atmospherics/unary/heater/initialize() if(node) return @@ -52,26 +59,27 @@ else icon_state = "heater_0" return - + /obj/machinery/atmospherics/unary/heater/process() ..() - + if(stat & (NOPOWER|BROKEN) || !on) heating = 0 update_use_power(0) + update_icon() return - - if (network && air_contents.temperature < set_temperature) + + if (network && air_contents.total_moles && air_contents.temperature < set_temperature) update_use_power(2) air_contents.add_thermal_energy(active_power_usage) - + heating = 1 network.update = 1 else heating = 0 update_use_power(1) - + update_icon() /obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob) @@ -82,7 +90,7 @@ /obj/machinery/atmospherics/unary/heater/attack_hand(mob/user as mob) src.ui_interact(user) - + /obj/machinery/atmospherics/unary/heater/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1) // this is the data which will be sent to the ui var/data[0] @@ -92,7 +100,8 @@ data["minGasTemperature"] = 0 data["maxGasTemperature"] = round(max_temperature) data["targetGasTemperature"] = round(set_temperature) - + data["powerSetting"] = power_setting + var/temp_class = "normal" if (air_contents.temperature > (T20C+40)) temp_class = "bad" @@ -122,14 +131,17 @@ src.set_temperature = min(src.set_temperature+amount, max_temperature) else src.set_temperature = max(src.set_temperature+amount, 0) - + if(href_list["setPower"]) //setting power to 0 is redundant anyways + var/new_setting = between(0, text2num(href_list["setPower"]), 100) + set_power_level(new_setting) + src.add_fingerprint(usr) return 1 //upgrading parts -/obj/machinery/atmospherics/unary/heater/RefreshParts() +/obj/machinery/atmospherics/unary/heater/RefreshParts() ..() - + var/cap_rating = 0 var/cap_count = 0 var/bin_rating = 0 @@ -143,10 +155,20 @@ bin_count++ cap_rating /= cap_count bin_rating /= bin_count - - active_power_usage = initial(active_power_usage)*cap_rating + + max_power_usage = initial(max_power_usage)*cap_rating max_temperature = max(initial(max_temperature) - T20C, 0)*((bin_rating*2 + cap_rating)/3) + T20C air_contents.volume = max(initial(internal_volume) - 200, 0) + 200*bin_rating + set_power_level(power_setting) + +/obj/machinery/atmospherics/unary/heater/proc/set_power_level(var/new_power_setting) + power_setting = new_power_setting + + var/old_power_usage = active_power_usage + active_power_usage = max_power_usage * (power_setting/100) + + if (use_power >= 2 && old_power_usage != active_power_usage) + force_power_update() //dismantling code. copied from autolathe /obj/machinery/atmospherics/unary/heater/attackby(var/obj/item/O as obj, var/mob/user as mob) @@ -158,7 +180,7 @@ if (opened && istype(O, /obj/item/weapon/crowbar)) dismantle() return - + ..() /obj/machinery/atmospherics/unary/heater/examine() diff --git a/code/ATMOSPHERICS/components/unary/outlet_injector.dm b/code/ATMOSPHERICS/components/unary/outlet_injector.dm index fb32ade3d28..d603da8cd14 100644 --- a/code/ATMOSPHERICS/components/unary/outlet_injector.dm +++ b/code/ATMOSPHERICS/components/unary/outlet_injector.dm @@ -1,6 +1,6 @@ //Basically a one way passive valve. If the pressure inside is greater than the environment then gas will flow passively, //but it does not permit gas to flow back from the environment into the injector. Can be turned off to prevent any gas flow. -//When it recieves the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power. +//When it receives the "inject" signal, it will try to pump it's entire contents into the environment regardless of pressure, using power. /obj/machinery/atmospherics/unary/outlet_injector icon = 'icons/atmos/injector.dmi' @@ -12,8 +12,8 @@ desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate." use_power = 1 - idle_power_usage = 5 //internal circuitry - var/inject_power = 15000 //15000 kW ~ 20 HP + idle_power_usage = 150 //internal circuitry, friction losses and stuff + active_power_usage = 15000 //This also doubles as a measure of how powerful the pump is, in Watts. 15000 W ~ 20 HP var/on = 0 var/injecting = 0 @@ -54,26 +54,28 @@ ..() injecting = 0 - if(!on) //only uses power when injecting - return 0 + if((stat & (NOPOWER|BROKEN)) || !on) + update_use_power(0) //usually we get here because a player turned a pump off - definitely want to update. + last_flow_rate = 0 + return + var/power_draw = -1 var/datum/gas_mixture/environment = loc.return_air() - + if(environment && air_contents.temperature > 0) - var/air_temperature = environment.temperature? environment.temperature : air_contents.temperature - var/pressure_delta = air_contents.return_pressure() - environment.return_pressure() - var/output_volume = environment.volume * environment.group_multiplier - - if (pressure_delta > 0.01) - var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) - transfer_moles = min(transfer_moles, (volume_rate/air_contents.volume)*air_contents.total_moles) //apply flow rate limit - - var/datum/gas_mixture/removed = air_contents.remove(transfer_moles) - loc.assume_air(removed) - - if(network) - network.update = 1 - + var/transfer_moles = (volume_rate/air_contents.volume)*air_contents.total_moles //apply flow rate limit + power_draw = pump_gas(src, air_contents, environment, transfer_moles, active_power_usage) + + if (power_draw < 0) + //update_use_power(0) + use_power = 0 //don't force update - easier on CPU + last_flow_rate = 0 + else + handle_power_draw(power_draw) + + if(network) + network.update = 1 + return 1 /obj/machinery/atmospherics/unary/outlet_injector/proc/inject() @@ -87,7 +89,7 @@ injecting = 1 if(air_contents.temperature > 0) - var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, inject_power) + var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, active_power_usage) use_power(power_used) if(network) diff --git a/code/ATMOSPHERICS/components/unary/vent_pump.dm b/code/ATMOSPHERICS/components/unary/vent_pump.dm index 0a9eb3ce800..80b168aabd1 100644 --- a/code/ATMOSPHERICS/components/unary/vent_pump.dm +++ b/code/ATMOSPHERICS/components/unary/vent_pump.dm @@ -88,6 +88,15 @@ ..() air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800 +/obj/machinery/atmospherics/unary/vent_pump/engine + name = "Engine Core Vent" + power_channel = ENVIRON + active_power_usage = 15000 //15 kW ~ 20 HP + +/obj/machinery/atmospherics/unary/vent_pump/engine/New() + ..() + air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //meant to match air injector + /obj/machinery/atmospherics/unary/vent_pump/update_icon(var/safety = 0) if(!check_icon_cache()) return @@ -174,7 +183,7 @@ var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION) //limit flow rate from turfs - transfer_moles = min(transfer_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here + transfer_moles = min(transfer_moles, environment.total_moles*air_contents.volume/environment.volume) //group_multiplier gets divided out here power_draw = pump_gas(src, environment, air_contents, transfer_moles, active_power_usage) diff --git a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm index 0e719addc97..dcd052dd99f 100644 --- a/code/ATMOSPHERICS/components/unary/vent_scrubber.dm +++ b/code/ATMOSPHERICS/components/unary/vent_scrubber.dm @@ -20,7 +20,7 @@ var/on = 0 var/scrubbing = 1 //0 = siphoning, 1 = scrubbing - var/list/scrubbing_gas = list() + var/list/scrubbing_gas = list("carbon_dioxide") var/panic = 0 //is this scrubber panicked? diff --git a/code/ATMOSPHERICS/datum_pipeline.dm b/code/ATMOSPHERICS/datum_pipeline.dm index ca062775513..aa4473babd5 100644 --- a/code/ATMOSPHERICS/datum_pipeline.dm +++ b/code/ATMOSPHERICS/datum_pipeline.dm @@ -202,6 +202,9 @@ datum/pipeline //surface must be the surface area in m^2 proc/radiate_heat_to_space(surface, thermal_conductivity) + var/gas_density = air.total_moles/air.volume + thermal_conductivity *= min(gas_density / ( RADIATOR_OPTIMUM_PRESSURE/(R_IDEAL_GAS_EQUATION*T20C) ), 1) + //if the h/e pipes radiate less than the AVERAGE_SOLAR_RADIATION, then they will heat up, otherwise they will cool down. It turns out the critical temperature is -26 C var/heat_gain = surface*(AVERAGE_SOLAR_RADIATION - STEFAN_BOLTZMANN_CONSTANT*thermal_conductivity*(air.temperature - COSMIC_RADIATION_TEMPERATURE) ** 4) diff --git a/code/ATMOSPHERICS/he_pipes.dm b/code/ATMOSPHERICS/he_pipes.dm index 607e974ee44..c22c483e8c4 100644 --- a/code/ATMOSPHERICS/he_pipes.dm +++ b/code/ATMOSPHERICS/he_pipes.dm @@ -1,7 +1,8 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging - icon = 'icons/obj/pipes/heat.dmi' + icon = 'icons/atmos/heat.dmi' icon_state = "intact" + pipe_icon = "hepipe" level = 2 var/initialize_directions_he var/surface = 2 //surface area in m^2 @@ -35,6 +36,10 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging if(target.initialize_directions_he & get_dir(target,src)) node2 = target break + if(!node1 && !node2) + del(src) + return + update_icon() return @@ -58,8 +63,9 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction - icon = 'icons/obj/pipes/junction.dmi' + icon = 'icons/atmos/junction.dmi' icon_state = "intact" + pipe_icon = "hejunction" level = 2 minimum_temperature_difference = 300 thermal_conductivity = WALL_HEAT_TRANSFER_COEFFICIENT @@ -82,16 +88,6 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction initialize_directions_he = WEST // BubbleWrap END - 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) - initialize() for(var/obj/machinery/atmospherics/target in get_step(src,initialize_directions)) if(target.initialize_directions & get_dir(target,src)) @@ -102,5 +98,9 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging/junction node2 = target break + if(!node1&&!node2) + del(src) + return + update_icon() return diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index 72598779394..77249a4e7e9 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -15,7 +15,7 @@ /obj/machinery/atmospherics/pipe/New() ..() //so pipes under walls are hidden - if(!istype(get_turf(src), /turf/simulated/floor)) + if(istype(get_turf(src), /turf/simulated/wall) || istype(get_turf(src), /turf/simulated/shuttle/wall) || istype(get_turf(src), /turf/unsimulated/wall)) level = 1 /obj/machinery/atmospherics/pipe/proc/pipeline_expansion() @@ -137,6 +137,7 @@ /obj/machinery/atmospherics/pipe/simple icon = 'icons/atmos/pipes.dmi' icon_state = "" + var/pipe_icon = "" //what kind of pipe it is and from which dmi is the icon manager getting its icons, "" for simple pipes, "hepipe" for HE pipes, "hejunction" for HE junctions name = "pipe" desc = "A one meter section of regular pipe" @@ -571,6 +572,10 @@ if (node3) break + if(!node1 && !node2 && !node3) + del(src) + return + var/turf/T = get_turf(src) if(istype(T)) hide(T.intact) @@ -825,6 +830,10 @@ node4 = target break + if(!node1 && !node2 && !node3 && !node4) + del(src) + return + var/turf/T = get_turf(src) if(istype(T)) hide(T.intact) @@ -1028,6 +1037,7 @@ desc = "A large vessel containing pressurized gas." volume = 10000 //in liters, 1 meters by 1 meters by 2 meters ~tweaked it a little to simulate a pressure tank without needing to recode them yet + var/start_pressure = 25*ONE_ATMOSPHERE level = 1 dir = SOUTH @@ -1120,8 +1130,8 @@ air_temporary.volume = volume air_temporary.temperature = T20C - 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)) + air_temporary.adjust_multi("oxygen", (start_pressure*O2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature), \ + "nitrogen",(start_pressure*N2STANDARD)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() @@ -1136,7 +1146,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.adjust_gas("oxygen", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + air_temporary.adjust_gas("oxygen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "o2" @@ -1150,7 +1160,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.adjust_gas("nitrogen", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + air_temporary.adjust_gas("nitrogen", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "n2" @@ -1164,7 +1174,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.adjust_gas("carbon_dioxide", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + air_temporary.adjust_gas("carbon_dioxide", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "co2" @@ -1178,7 +1188,7 @@ air_temporary.volume = volume air_temporary.temperature = T20C - air_temporary.adjust_gas("phoron", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + air_temporary.adjust_gas("phoron", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "phoron" @@ -1192,7 +1202,7 @@ air_temporary.volume = volume air_temporary.temperature = T0C - air_temporary.adjust_gas("sleeping_agent", (25*ONE_ATMOSPHERE)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) + air_temporary.adjust_gas("sleeping_agent", (start_pressure)*(air_temporary.volume)/(R_IDEAL_GAS_EQUATION*air_temporary.temperature)) ..() icon_state = "n2o" diff --git a/code/WorkInProgress/kilakk/fax.dm b/code/WorkInProgress/kilakk/fax.dm index 2934d2ed746..2c342296207 100644 --- a/code/WorkInProgress/kilakk/fax.dm +++ b/code/WorkInProgress/kilakk/fax.dm @@ -5,7 +5,7 @@ var/list/alldepartments = list("Central Command") name = "fax machine" icon = 'icons/obj/library.dmi' icon_state = "fax" - req_one_access = list(access_lawyer, access_heads) + req_one_access = list(access_lawyer, access_heads, access_armory) //Warden needs to be able to Fax solgov too. anchored = 1 density = 1 use_power = 1 @@ -23,12 +23,14 @@ var/list/alldepartments = list("Central Command") var/dpt = "Central Command" // the department we're sending to + /obj/machinery/faxmachine/New() ..() allfaxes += src if( !("[department]" in alldepartments) ) alldepartments += department + alldepartments += "Sol Government" /obj/machinery/faxmachine/process() return 0 @@ -95,9 +97,12 @@ var/list/alldepartments = list("Central Command") if(tofax) if(dpt == "Central Command") - Centcomm_fax(tofax.info, tofax.name, usr) + Centcomm_fax(src, tofax.info, tofax.name, usr) sendcooldown = 1800 + else if(dpt == "Sol Government") + Solgov_fax(src, tofax.info, tofax.name, usr) + sendcooldown = 1800 else SendFax(tofax.info, tofax.name, usr, dpt) sendcooldown = 600 @@ -177,11 +182,18 @@ var/list/alldepartments = list("Central Command") user << "You [anchored ? "wrench" : "unwrench"] \the [src]." return -/proc/Centcomm_fax(var/sent, var/sentname, var/mob/Sender) +/proc/Centcomm_fax(var/originfax, var/sent, var/sentname, var/mob/Sender) + + var/msg = "\blue CENTCOMM FAX: [key_name(Sender, 1)] (PP) (VV) (SM) (JMP) (CA) (RPLY): Receiving '[sentname]' via secure connection ... view message" - var/msg = "\blue CENTCOMM FAX: [key_name(Sender, 1)] (PP) (VV) (SM) (JMP) (CA) (RPLY): Receiving '[sentname]' via secure connection ... view message" admins << msg +/proc/Solgov_fax(var/originfax, var/sent, var/sentname, var/mob/Sender) + var/msg = "\blue SOL GOVERNMENT FAX: [key_name(Sender, 1)] (PP) (VV) (SM) (JMP) (CA) (RPLY): Receiving '[sentname]' via secure connection ... view message" + + admins << msg + + proc/SendFax(var/sent, var/sentname, var/mob/Sender, var/dpt) for(var/obj/machinery/faxmachine/F in allfaxes) diff --git a/code/ZAS/Turf.dm b/code/ZAS/Turf.dm index 4e70e3b627f..e3a28fe3d47 100644 --- a/code/ZAS/Turf.dm +++ b/code/ZAS/Turf.dm @@ -1,15 +1,14 @@ /turf/simulated/var/zone/zone /turf/simulated/var/open_directions -/turf/simulated/var/gas_graphic /turf/var/needs_air_update = 0 /turf/var/datum/gas_mixture/air -/turf/simulated/proc/set_graphic(new_graphic) - gas_graphic = new_graphic - overlays.Cut() - for(var/i in gas_graphic) - overlays += i +/turf/simulated/proc/update_graphic(list/graphic_add = null, list/graphic_remove = null) + if(graphic_add) + overlays += graphic_add + if(graphic_remove) + overlays -= graphic_remove /turf/proc/update_air_properties() var/block = c_airblock(src) diff --git a/code/ZAS/Zone.dm b/code/ZAS/Zone.dm index 40c509bbd90..e794c36b02a 100644 --- a/code/ZAS/Zone.dm +++ b/code/ZAS/Zone.dm @@ -51,6 +51,9 @@ Class Procs: /zone/var/datum/gas_mixture/air = new +/zone/var/list/graphic_add = list() +/zone/var/list/graphic_remove = list() + /zone/New() air_master.add_zone(src) air.temperature = TCMB @@ -71,7 +74,7 @@ Class Procs: if(T.fire) fire_tiles.Add(T) air_master.active_fire_zones.Add(src) - T.set_graphic(air.graphic) + T.update_graphic(air.graphic) /zone/proc/remove(turf/simulated/T) #ifdef ZASDBG @@ -83,7 +86,7 @@ Class Procs: contents.Remove(T) fire_tiles.Remove(T) T.zone = null - T.set_graphic(0) + T.update_graphic(graphic_remove = air.graphic) if(contents.len) air.group_multiplier = contents.len else @@ -128,9 +131,11 @@ Class Procs: air.group_multiplier = contents.len+1 /zone/proc/tick() - if(air.check_tile_graphic()) + if(air.check_tile_graphic(graphic_add, graphic_remove)) for(var/turf/simulated/T in contents) - T.set_graphic(air.graphic) + T.update_graphic(graphic_add, graphic_remove) + graphic_add.len = 0 + graphic_remove.len = 0 /zone/proc/dbg_data(mob/M) M << name diff --git a/code/ZAS/_gas_mixture_xgm.dm b/code/ZAS/_gas_mixture_xgm.dm index 1f31cc6e96e..01f95ee9a58 100644 --- a/code/ZAS/_gas_mixture_xgm.dm +++ b/code/ZAS/_gas_mixture_xgm.dm @@ -112,7 +112,7 @@ //Returns the thermal energy change required to get to a new temperature /datum/gas_mixture/proc/get_thermal_energy_change(var/new_temperature) - return heat_capacity()*(new_temperature - temperature) + return heat_capacity()*(max(new_temperature, 0) - temperature) //Technically vacuum doesn't have a specific entropy. Just use a really big number (infinity would be ideal) here so that it's easy to add gas to vacuum and hard to take gas out. #define SPECIFIC_ENTROPY_VACUUM 150000 @@ -124,19 +124,32 @@ . = 0 for(var/g in gas) - var/ratio = gas[g] / total_moles - . += ratio * specific_entropy_gas(g) + . += gas[g] * specific_entropy_gas(g) . /= total_moles -//Returns the ideal gas specific entropy of a specific gas in the mix. This is the entropy due to that gas per mole of /that/ gas in the mixture, not the entropy due to that gas per mole of gas mixture. +/* + It's arguable whether this should even be called entropy anymore. It's more "based on" entropy than actually entropy now. + + Returns the ideal gas specific entropy of a specific gas in the mix. This is the entropy due to that gas per mole of /that/ gas in the mixture, not the entropy due to that gas per mole of gas mixture. + + For the purposes of SS13, the specific entropy is just a number that tells you how hard it is to move gas. You can replace this with whatever you want. + Just remember that returning a SMALL number == adding gas to this gas mix is HARD, taking gas away is EASY, and that returning a LARGE number means the opposite (so a vacuum should approach infinity). + + So returning a constant/(partial pressure) would probably do what most players expect. Although the version I have implemented below is a bit more nuanced than simply 1/P in that it scales in a way + which is bit more realistic (natural log), and returns a fairly accurate entropy around room temperatures and pressures. +*/ /datum/gas_mixture/proc/specific_entropy_gas(var/gasid) if (!(gasid in gas) || gas[gasid] == 0) return SPECIFIC_ENTROPY_VACUUM //that gas isn't here + //group_multiplier gets divided out in volume/gas[gasid] - also, V/(m*T) = R/(partial pressure) var/molar_mass = gas_data.molar_mass[gasid] var/specific_heat = gas_data.specific_heat[gasid] - //group_multiplier gets divided out in volume/gas[gasid] - return R_IDEAL_GAS_EQUATION * ( log( (IDEAL_GAS_ENTROPY_CONSTANT*volume/gas[gasid]) * sqrt((molar_mass*specific_heat*temperature)**3) + 1 ) + 5/2 ) + return R_IDEAL_GAS_EQUATION * ( log( (IDEAL_GAS_ENTROPY_CONSTANT*volume/(gas[gasid] * temperature)) * (molar_mass*specific_heat*temperature)**(2/3) + 1 ) + 15 ) + + //alternative, simpler equation + //var/partial_pressure = gas[gasid] * R_IDEAL_GAS_EQUATION * temperature / volume + //return R_IDEAL_GAS_EQUATION * ( log (1 + IDEAL_GAS_ENTROPY_CONSTANT/partial_pressure) + 20 ) //Updates the total_moles count and trims any empty gases. /datum/gas_mixture/proc/update_values() @@ -255,12 +268,8 @@ 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 - +//Two lists can be passed by reference if you need know specifically which graphics were added and removed. +/datum/gas_mixture/proc/check_tile_graphic(list/graphic_add = null, 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. diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 77ed7f308e6..8c6befa38f8 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -398,4 +398,65 @@ datum/projectile_data var/r = mixOneColor(weights, reds) var/g = mixOneColor(weights, greens) var/b = mixOneColor(weights, blues) - return rgb(r,g,b) \ No newline at end of file + return rgb(r,g,b) + +/** +* Gets the highest and lowest pressures from the tiles in cardinal directions +* around us, then checks the difference. +*/ +/proc/getOPressureDifferential(var/turf/loc) + var/minp=16777216; + var/maxp=0; + for(var/dir in cardinal) + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/cp=0 + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + cp = environment.return_pressure() + else + if(istype(T,/turf/simulated)) + continue + if(cpmaxp)maxp=cp + return abs(minp-maxp) + +/proc/convert_k2c(var/temp) + return ((temp - T0C)) + +/proc/convert_c2k(var/temp) + return ((temp + T0C)) + +/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature")) + var/list/temps = new/list(4) + for(var/dir in cardinal) + var/direction + switch(dir) + if(NORTH) + direction = 1 + if(SOUTH) + direction = 2 + if(EAST) + direction = 3 + if(WEST) + direction = 4 + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/list/rstats = new /list(stats.len) + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + else if(istype(T, /turf/simulated)) + rstats = null // Exclude zone (wall, door, etc). + else if(istype(T, /turf)) + // Should still work. (/turf/return_air()) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + temps[direction] = rstats + return temps diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index c733d1ad35e..079c551ebf4 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -91,7 +91,7 @@ if(master) var/obj/item/I = usr.get_active_hand() if(I) - master.attackby(I, usr) + usr.ClickOn(master) usr.next_move = world.time+2 return 1 diff --git a/code/controllers/_DynamicAreaLighting_TG.dm b/code/controllers/_DynamicAreaLighting_TG.dm index 03ea77affcb..a93a7b64401 100644 --- a/code/controllers/_DynamicAreaLighting_TG.dm +++ b/code/controllers/_DynamicAreaLighting_TG.dm @@ -74,6 +74,7 @@ datum/light_source changed = 1 if (owner.l_color != _l_color) + readrgb(owner.l_color) changed = 1 if(changed) diff --git a/code/controllers/communications.dm b/code/controllers/communications.dm index 614768a0fe8..e7683de03b8 100644 --- a/code/controllers/communications.dm +++ b/code/controllers/communications.dm @@ -40,7 +40,7 @@ obj/proc/receive_signal(datum/signal/signal, var/receive_method as num, var/receive_param) Handler from received signals. By default does nothing. Define your own for your object. - Avoid of sending signals directly from this proc, use spawn(-1). Do not use sleep() here please. + Avoid of sending signals directly from this proc, use spawn(-1). DO NOT use sleep() here or call procs that sleep please. If you must, use spawn() parameters: signal - see description below. Extract all needed data from the signal before doing sleep(), spawn() or return! receive_method - may be TRANSMISSION_WIRE or TRANSMISSION_RADIO. @@ -84,7 +84,7 @@ On the map: 1311 for prison shuttle console (in fact, it is not used) 1435 for status displays 1437 for atmospherics/fire alerts -1439 for engine components +1438 for engine components 1439 for air pumps, air scrubbers, atmo control 1441 for atmospherics - supply tanks 1443 for atmospherics - distribution loop/mixed air tank @@ -237,13 +237,7 @@ var/global/datum/controller/radio/radio_controller if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range) continue - //allow sequential signals before round start, so that every air alarm sounding off at once doesn't cause trouble. - if(!ticker || ticker.current_state < 3) - device.receive_signal(signal, TRANSMISSION_RADIO, frequency) - else - spawn(0) - if(device) //in case the device got destroyed somehow - device.receive_signal(signal, TRANSMISSION_RADIO, frequency) + device.receive_signal(signal, TRANSMISSION_RADIO, frequency) /datum/radio_frequency/proc/add_listener(obj/device as obj, var/filter as text|null) if (!filter) diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm index f85391b7675..284caa23ac7 100644 --- a/code/controllers/configuration.dm +++ b/code/controllers/configuration.dm @@ -536,7 +536,6 @@ if("limbs_can_break") config.limbs_can_break = value - if("run_speed") config.run_speed = value if("walk_speed") diff --git a/code/controllers/lighting_controller.dm b/code/controllers/lighting_controller.dm index a938586e241..08c29e1a076 100644 --- a/code/controllers/lighting_controller.dm +++ b/code/controllers/lighting_controller.dm @@ -16,7 +16,6 @@ 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 ) @@ -55,18 +54,9 @@ 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 204081716c7..8654fb89a12 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -307,6 +307,7 @@ datum/controller/game_controller/proc/process_machines_power() var/area/A = active_areas[i] if(A.powerupdate && A.master == A) A.powerupdate -= 1 + A.clear_usage() for(var/j = 1; j <= A.related.len; j++) var/area/SubArea = A.related[j] for(var/obj/machinery/M in SubArea) @@ -362,7 +363,7 @@ datum/controller/game_controller/proc/process_powernets() while(i<=powernets.len) var/datum/powernet/Powernet = powernets[i] if(Powernet) - Powernet.reset() + Powernet.process() i++ continue powernets.Cut(i,i+1) diff --git a/code/datums/mixed.dm b/code/datums/mixed.dm index 6732e2a8b94..f0f0c70abda 100644 --- a/code/datums/mixed.dm +++ b/code/datums/mixed.dm @@ -30,20 +30,5 @@ -/datum/powernet - var/list/cables = list() // all cables & junctions - var/list/nodes = list() // all APCs & sources - - var/newload = 0 - var/load = 0 - var/newavail = 0 - var/avail = 0 - var/viewload = 0 - var/number = 0 - var/perapc = 0 // per-apc avilability - var/netexcess = 0 - - - /datum/debug var/list/debuglist diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index cf08713f1f5..c250a757bf8 100755 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -22,11 +22,9 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /datum/supply_packs/New() manifest += "" /datum/supply_packs/specialops @@ -348,20 +346,17 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /datum/supply_packs/exoticseeds name = "Exotic seeds crate" - contains = list(/obj/item/seeds/nettleseed, + contains = list(/obj/item/seeds/replicapod, /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/replicapod, - /obj/item/seeds/plumpmycelium, /obj/item/seeds/libertymycelium, - /obj/item/seeds/amanitamycelium, /obj/item/seeds/reishimycelium, - /obj/item/seeds/bananaseed, - /obj/item/seeds/riceseed, - /obj/item/seeds/eggplantseed, - /obj/item/seeds/limeseed, - /obj/item/seeds/grapeseed, - /obj/item/seeds/eggyseed) + /obj/item/seeds/random, + /obj/item/seeds/random, + /obj/item/seeds/random, + /obj/item/seeds/random, + /obj/item/seeds/random, + /obj/item/seeds/random, + /obj/item/seeds/kudzuseed) cost = 15 containertype = /obj/structure/closet/crate/hydroponics containername = "Exotic Seeds crate" diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 98e9a1af800..183568ad184 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -380,7 +380,7 @@ var/list/ghostteleportlocs = list() //SYNDICATES /area/syndicate_mothership - name = "\improper Syndicate Mothership" + name = "\improper Syndicate Base" icon_state = "syndie-ship" requires_power = 0 unlimited_power = 1 @@ -1103,7 +1103,8 @@ var/list/ghostteleportlocs = list() //Solars /area/solar - requires_power = 0 + requires_power = 1 + always_unpowered = 1 luminosity = 1 lighting_use_dynamic = 0 @@ -1133,7 +1134,7 @@ var/list/ghostteleportlocs = list() /area/maintenance/auxsolarport name = "Fore Port Solar Maintenance" - icon_state = "SolarcontrolA" + icon_state = "SolarcontrolP" /area/maintenance/starboardsolar name = "Aft Starboard Solar Maintenance" @@ -1145,7 +1146,7 @@ var/list/ghostteleportlocs = list() /area/maintenance/auxsolarstarboard name = "Fore Starboard Solar Maintenance" - icon_state = "SolarcontrolA" + icon_state = "SolarcontrolS" /area/maintenance/foresolar name = "Fore Solar Maintenance" @@ -1460,6 +1461,10 @@ var/list/ghostteleportlocs = list() name = "\improper Research and Development" icon_state = "research" +/area/rnd/docking + name = "\improper Research Dock" + icon_state = "research" + /area/rnd/lab name = "\improper Research Lab" icon_state = "toxlab" diff --git a/code/game/gamemodes/calamity/calamity.dm b/code/game/gamemodes/calamity/calamity.dm index c2ab3202f4f..4645fd2d3be 100644 --- a/code/game/gamemodes/calamity/calamity.dm +++ b/code/game/gamemodes/calamity/calamity.dm @@ -17,14 +17,14 @@ uplink_uses = 10 //Possible roundstart antag types. - var/list/atypes = list("syndi","ling","tater","wiz","ninja","vox","slug","cult") + var/list/atypes = list("syndi","ling","tater","wiz","ninja","vox","cult") //Readd slug when borer spawn is fixed. var/list/chosen_atypes = list() var/list/chosen_candidates = list() var/list/already_assigned_candidates = list() //At one antagonist group per 10 players we are just going to go with tiny groups. - var/max_antags = 3 // Antag groups spawn with this many members. - var/antag_type_ratio = 10 // 1 antag type per this many players. + var/max_antags = 5 // Antag groups spawn with this many members. + var/antag_type_ratio = 8 // 1 antag type per this many players. var/const/waittime_l = 600 var/const/waittime_h = 1800 @@ -48,26 +48,37 @@ var/atype var/list/candidates = list() - while(atypes.len && candidates.len == 0) //While there are untested antag mode types and we don't have any candidates selected, loop. + // Go through antag types at random until we find one that has candidates. + while(atypes.len && !candidates.len) atype = pick(atypes) log_debug("Calamity: checking [atype].") atypes -= atype candidates = get_role_candidates(atype) - if(!candidates.len) - log_debug("Calamity mode setup failed, no antag types or candidates left.") - return 0 + //Prune out candidates who are already antagonists. + var/list/remove_players = list() + for(var/datum/mind/player in candidates) + if(player.special_role || player.assigned_role == "MODE") + remove_players += player + candidates -= remove_players log_debug("Calamity: selected [atype] (possible candidates: [candidates.len])") chosen_atypes += atype for(var/j=0;j synd_spawn.len) spawnpos = 1 @@ -254,8 +276,9 @@ update_all_synd_icons() - if(uplinklocker) - new /obj/structure/closet/syndicate/nuclear(uplinklocker.loc) + if(uplinkdevice) + var/obj/item/device/radio/uplink/U = new(uplinkdevice.loc) + U.hidden_uplink.uses = 40 if(nuke_spawn && synd_spawn.len > 0) var/obj/machinery/nuclearbomb/the_bomb = new /obj/machinery/nuclearbomb(nuke_spawn.loc) the_bomb.r_code = nuke_code @@ -264,7 +287,7 @@ for(var/datum/mind/player in candidates) - changelings += player + changelings |= player grant_changeling_powers(player.current) player.special_role = "Changeling" @@ -278,7 +301,7 @@ /datum/game_mode/calamity/proc/spawn_traitors(var/list/candidates) for(var/datum/mind/player in candidates) - traitors += player + traitors |= player if(!config.objectives_disabled) player.objectives += new /datum/objective/escape() @@ -292,7 +315,7 @@ /datum/game_mode/calamity/proc/spawn_cabal(var/list/candidates) for(var/datum/mind/player in candidates) - wizards += player + wizards |= player if(!config.objectives_disabled) player.objectives += new /datum/objective/escape() @@ -314,7 +337,7 @@ ninjastart.Add(L) for(var/datum/mind/player in candidates) - ninjas += player + ninjas |= player player.current << browse(null, "window=playersetup") player.current = create_space_ninja(pick(ninjastart)) @@ -347,7 +370,7 @@ //Create raiders. for(var/datum/mind/player in candidates) - raiders += player + raiders |= player //Place them on the shuttle. var/index = 1 @@ -375,42 +398,43 @@ var/list/possible_hosts = list() for(var/mob/living/carbon/human/H in mob_list) if(!(H.species.flags & IS_SYNTHETIC)) - possible_hosts += H + possible_hosts |= H - for(var/datum/mind/player in candidates) + spawn(10) + for(var/datum/mind/player in candidates) - if(!possible_hosts || possible_hosts.len) - break + if(!possible_hosts || possible_hosts.len) + break - borers += player - var/mob/living/carbon/human/target_host = pick(possible_hosts) - possible_hosts -= target_host + borers |= player + var/mob/living/carbon/human/target_host = pick(possible_hosts) + possible_hosts -= target_host - var/mob/living/simple_animal/borer/roundstart/B = new(target_host) + var/mob/living/simple_animal/borer/roundstart/B = new(target_host) - player.current = B - B.mind = player - B.key = player.key - player.assigned_role = "Cortical Borer" - player.special_role = "Cortical Borer" + player.current = B + B.mind = player + B.key = player.key + player.assigned_role = "Cortical Borer" + player.special_role = "Cortical Borer" - B.host = target_host - B.host_brain.name = target_host.name - B.host_brain.real_name = target_host.real_name + B.host = target_host + B.host_brain.name = target_host.name + B.host_brain.real_name = target_host.real_name - var/datum/organ/external/head = target_host.get_organ("head") - head.implants += B + var/datum/organ/external/head = target_host.get_organ("head") + head.implants += B - player.current << "\blue You are a cortical borer! You are a brain slug that worms its way \ - into the head of its victim, lurking out of sight until it needs to take control." - player.current << "You can speak to your victim with say, to other borers with say ;, and use your Alien tab for abilities." + player.current << "\blue You are a cortical borer! You are a brain slug that worms its way \ + into the head of its victim, lurking out of sight until it needs to take control." + player.current << "You can speak to your victim with say, to other borers with say ;, and use your Alien tab for abilities." - if(!config.objectives_disabled) - player.objectives += new /datum/objective/borer_survive() - player.objectives += new /datum/objective/borer_reproduce() - player.objectives += new /datum/objective/escape() + if(!config.objectives_disabled) + player.objectives += new /datum/objective/borer_survive() + player.objectives += new /datum/objective/borer_reproduce() + player.objectives += new /datum/objective/escape() - show_objectives(player) + show_objectives(player) /datum/game_mode/calamity/proc/spawn_cultists(var/list/candidates) @@ -430,7 +454,7 @@ if(player.assigned_role == job) continue - cult += player + cult |= player equip_cultist(player.current) grant_runeword(player.current) update_cult_icons_added(player) diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 14b253f4159..6750f7c83eb 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -104,7 +104,7 @@ var/list/sacrificed = list() if(M.stat==2) continue usr.say("Mah[pick("'","`")]weyh pleggh at e'ntrath!") - M.visible_message("\red [M] writhes in pain as the markings below him glow a bloody red.", \ + M.visible_message("\red [M] writhes in pain as the markings below \him glow a bloody red.", \ "\red AAAAAAHHHH!.", \ "\red You hear an anguished scream.") if(is_convertable_to_cult(M.mind) && !jobban_isbanned(M, "cultist"))//putting jobban check here because is_convertable uses mind as argument diff --git a/code/game/gamemodes/events/space_ninja.dm b/code/game/gamemodes/events/space_ninja.dm index 2421a354660..c1fd9b219f9 100644 --- a/code/game/gamemodes/events/space_ninja.dm +++ b/code/game/gamemodes/events/space_ninja.dm @@ -142,7 +142,7 @@ Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective comp //Here we pick a location and spawn the ninja. if(ninjastart.len == 0) for(var/obj/effect/landmark/L in landmarks_list) - if(L.name == "carpspawn") + if(L.name == "carpspawn" && locate(/turf/simulated) in range(7, L)) ninjastart.Add(L) var/ninja_key = null diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 723d8102d02..fa7b55c7f8d 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -37,6 +37,8 @@ var/global/datum/controller/gameticker/ticker var/triai = 0//Global holder for Triumvirate + var/round_end_announced = 0 // Spam Prevention. Announce round end only once. + /datum/controller/gameticker/proc/pregame() login_music = pick(\ /*'sound/music/halloween/skeletons.ogg',\ @@ -360,7 +362,9 @@ var/global/datum/controller/gameticker/ticker //call a transfer shuttle vote spawn(50) - world << "\red The round has ended!" + if(!round_end_announced) // Spam Prevention. Now it should announce only once. + world << "\red The round has ended!" + round_end_announced = 1 vote.autotransfer() return 1 diff --git a/code/game/gamemodes/malfunction/malfunction.dm b/code/game/gamemodes/malfunction/malfunction.dm index 1f6f40176c0..2fb432d119a 100644 --- a/code/game/gamemodes/malfunction/malfunction.dm +++ b/code/game/gamemodes/malfunction/malfunction.dm @@ -53,6 +53,7 @@ AI_mind.current.verbs += /mob/living/silicon/ai/proc/choose_modules AI_mind.current:laws = new /datum/ai_laws/malfunction AI_mind.current:malf_picker = new /datum/AI_Module/module_picker + AI_mind.current.verbs += /datum/game_mode/malfunction/proc/ai_win // We run checks if AI overtaken the station in the proc itself. This guarantees you won't have to relog when it refuses to appear on takeover completion. AI_mind.current:show_laws() greet_malf(AI_mind) @@ -113,11 +114,8 @@ for(var/datum/mind/AI_mind in malf_ai) AI_mind.current << "Congratulations you have taken control of the station." AI_mind.current << "You may decide to blow up the station. You have 60 seconds to choose." - AI_mind.current << "You should have a new verb in the Malfunction tab. If you dont - rejoin the game." - AI_mind.current.verbs += /datum/game_mode/malfunction/proc/ai_win + AI_mind.current << "You can use the \"Explode\" verb to activate the self-destruct" spawn (600) - for(var/datum/mind/AI_mind in malf_ai) - AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/ai_win to_nuke_or_not_to_nuke = 0 return @@ -182,19 +180,69 @@ set category = "Malfunction" set name = "Explode" set desc = "Station go boom" - if (!ticker.mode:to_nuke_or_not_to_nuke) + + if(!ticker.mode:station_captured) + usr << "You are unable to access the self-destruct system as you don't control the station yet." return + + if(ticker.mode:explosion_in_progress || ticker.mode:station_was_nuked) + usr << "The self-destruct countdown is already triggered!" + return + + if(!ticker.mode:to_nuke_or_not_to_nuke) //Takeover IS completed, but 60s timer passed. + usr << "You lost control over self-destruct system. It seems to be behind firewall. Unable to hack" + return + + usr << "\red Self-Destruct sequence initialised!" + ticker.mode:to_nuke_or_not_to_nuke = 0 - for(var/datum/mind/AI_mind in ticker.mode:malf_ai) - AI_mind.current.verbs -= /datum/game_mode/malfunction/proc/ai_win ticker.mode:explosion_in_progress = 1 for(var/mob/M in player_list) M << 'sound/machines/Alarm.ogg' - world << "Self-destructing in 10" + + var/obj/item/device/radio/R = new (src) + var/AN = "Self-Destruct System" + + R.autosay("Caution. Self-Destruct sequence has been actived. Self-destructing in Ten..", AN) for (var/i=9 to 1 step -1) sleep(10) - world << i + var/msg = "" + switch(i) + if(9) + msg = "Nine.." + if(8) + msg = "Eight.." + if(7) + msg = "Seven.." + if(6) + msg = "Six.." + if(5) + msg = "Five.." + if(4) + msg = "Four.." + if(3) + msg = "Three.." + if(2) + msg = "Two.." + if(1) + msg = "One.." + + R.autosay(msg, AN) sleep(10) + var/msg = "" + var/abort = 0 + if(ticker.mode:is_malf_ai_dead()) // That. Was. CLOSE. + msg = "Self-destruct sequence has been cancelled." + abort = 1 + else + msg = "Zero. Have a nice day." + R.autosay(msg, AN) + + if(abort) + ticker.mode:explosion_in_progress = 0 + set_security_level("red") //Delta's over + return + enter_allowed = 0 if(ticker) ticker.station_explosion_cinematic(0,null) diff --git a/code/game/gamemodes/nuclear/nuclear.dm b/code/game/gamemodes/nuclear/nuclear.dm index 6f89c015aad..911dc58d846 100644 --- a/code/game/gamemodes/nuclear/nuclear.dm +++ b/code/game/gamemodes/nuclear/nuclear.dm @@ -208,6 +208,7 @@ var/global/list/turf/synd_spawn = list() /datum/game_mode/proc/equip_syndicate(mob/living/carbon/human/synd_mob) var/obj/item/device/radio/R = new /obj/item/device/radio/headset/syndicate(synd_mob) R.set_frequency(SYND_FREQ) + R.freerange = 1 synd_mob.equip_to_slot_or_del(R, slot_l_ear) synd_mob.equip_to_slot_or_del(new /obj/item/clothing/under/syndicate(synd_mob), slot_w_uniform) @@ -217,11 +218,8 @@ var/global/list/turf/synd_spawn = list() if(synd_mob.backbag == 2) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(synd_mob), slot_back) if(synd_mob.backbag == 3) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel_norm(synd_mob), slot_back) if(synd_mob.backbag == 4) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(synd_mob), slot_back) - synd_mob.equip_to_slot_or_del(new /obj/item/ammo_magazine/a12mm(synd_mob), slot_in_backpack) - synd_mob.equip_to_slot_or_del(new /obj/item/ammo_magazine/a12mm(synd_mob), slot_in_backpack) - synd_mob.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), slot_in_backpack) - synd_mob.equip_to_slot_or_del(new /obj/item/weapon/gun/projectile/automatic/c20r(synd_mob), slot_belt) synd_mob.equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(synd_mob.back), slot_in_backpack) + synd_mob.equip_to_slot_or_del(new /obj/item/weapon/reagent_containers/pill/cyanide(synd_mob), slot_in_backpack) /* Commented; nukes now have a suit cycler for changing rig-suits, they don't need to spawn with them var/obj/item/clothing/suit/space/rig/syndi/new_suit = new(synd_mob) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index aa582281048..641e9473add 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -123,18 +123,26 @@ set category = "Object" set src in oview(1) - if(usr.stat || !ishuman(usr) || usr.buckled || usr.restrained()) - return - - if(src.victim) - usr << "\blue The table is already occupied!" + if(usr.stat || !ishuman(usr) || usr.restrained() || !check_table(usr)) return take_victim(usr,usr) /obj/machinery/optable/attackby(obj/item/weapon/W as obj, mob/living/carbon/user as mob) if (istype(W, /obj/item/weapon/grab)) - if(iscarbon(W:affecting)) - take_victim(W:affecting,usr) + var/obj/item/weapon/grab/G = W + if(iscarbon(G.affecting) && check_table(G.affecting)) + take_victim(G.affecting,usr) del(W) - return \ No newline at end of file + return + +/obj/machinery/optable/proc/check_table(mob/living/carbon/patient as mob) + if(src.victim) + usr << "\blue The table is already occupied!" + return 0 + + if(patient.buckled) + usr << "\blue Unbuckle first!" + return 0 + + return 1 diff --git a/code/game/machinery/atmo_control.dm b/code/game/machinery/atmo_control.dm index b5d5af6183e..a62da66d770 100644 --- a/code/game/machinery/atmo_control.dm +++ b/code/game/machinery/atmo_control.dm @@ -1,4 +1,4 @@ -obj/machinery/air_sensor +/obj/machinery/air_sensor icon = 'icons/obj/stationobjs.dmi' icon_state = "gsensor1" name = "Gas Sensor" @@ -22,59 +22,58 @@ obj/machinery/air_sensor var/datum/radio_frequency/radio_connection - update_icon() - icon_state = "gsensor[on]" +/obj/machinery/air_sensor/update_icon() + icon_state = "gsensor[on]" - process() - if(on) - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.data["tag"] = id_tag - signal.data["timestamp"] = world.time +/obj/machinery/air_sensor/process() + if(on) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.data["tag"] = id_tag + signal.data["timestamp"] = world.time - var/datum/gas_mixture/air_sample = return_air() + var/datum/gas_mixture/air_sample = return_air() - if(output&1) - signal.data["pressure"] = num2text(round(air_sample.return_pressure(),0.1),) - if(output&2) - signal.data["temperature"] = round(air_sample.temperature,0.1) + if(output&1) + signal.data["pressure"] = num2text(round(air_sample.return_pressure(),0.1),) + if(output&2) + signal.data["temperature"] = round(air_sample.temperature,0.1) - if(output>4) - var/total_moles = air_sample.total_moles - if(total_moles > 0) - if(output&4) - signal.data["oxygen"] = round(100*air_sample.gas["oxygen"]/total_moles,0.1) - if(output&8) - signal.data["phoron"] = round(100*air_sample.gas["phoron"]/total_moles,0.1) - if(output&16) - signal.data["nitrogen"] = round(100*air_sample.gas["nitrogen"]/total_moles,0.1) - if(output&32) - signal.data["carbon_dioxide"] = round(100*air_sample.gas["carbon_dioxide"]/total_moles,0.1) - else - signal.data["oxygen"] = 0 - signal.data["phoron"] = 0 - signal.data["nitrogen"] = 0 - signal.data["carbon_dioxide"] = 0 - signal.data["sigtype"]="status" - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + if(output>4) + var/total_moles = air_sample.total_moles + if(total_moles > 0) + if(output&4) + signal.data["oxygen"] = round(100*air_sample.gas["oxygen"]/total_moles,0.1) + if(output&8) + signal.data["phoron"] = round(100*air_sample.gas["phoron"]/total_moles,0.1) + if(output&16) + signal.data["nitrogen"] = round(100*air_sample.gas["nitrogen"]/total_moles,0.1) + if(output&32) + signal.data["carbon_dioxide"] = round(100*air_sample.gas["carbon_dioxide"]/total_moles,0.1) + else + signal.data["oxygen"] = 0 + signal.data["phoron"] = 0 + signal.data["nitrogen"] = 0 + signal.data["carbon_dioxide"] = 0 + signal.data["sigtype"]="status" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) +/obj/machinery/air_sensor/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - initialize() +/obj/machinery/air_sensor/initialize() + set_frequency(frequency) + +/obj/machinery/air_sensor/New() + ..() + + if(radio_controller) set_frequency(frequency) - New() - ..() - - if(radio_controller) - set_frequency(frequency) - -obj/machinery/computer/general_air_control +/obj/machinery/computer/general_air_control icon = 'icons/obj/computer.dmi' icon_state = "tank" @@ -87,298 +86,426 @@ obj/machinery/computer/general_air_control var/datum/radio_frequency/radio_connection circuit = /obj/item/weapon/circuitboard/air_management - attack_hand(mob/user) - if(..(user)) - return - user << browse(return_text(),"window=computer") - user.set_machine(src) - onclose(user, "computer") +/obj/machinery/computer/general_air_control/attack_hand(mob/user) + if(..(user)) + return + user << browse(return_text(),"window=computer") + user.set_machine(src) + onclose(user, "computer") - process() - ..() - src.updateUsrDialog() +/obj/machinery/computer/general_air_control/process() + ..() + src.updateUsrDialog() - receive_signal(datum/signal/signal) - if(!signal || signal.encryption) return +/obj/machinery/computer/general_air_control/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return - var/id_tag = signal.data["tag"] - if(!id_tag || !sensors.Find(id_tag)) return + var/id_tag = signal.data["tag"] + if(!id_tag || !sensors.Find(id_tag)) return - sensor_information[id_tag] = signal.data + sensor_information[id_tag] = signal.data - proc/return_text() - var/sensor_data - if(sensors.len) - for(var/id_tag in sensors) - var/long_name = sensors[id_tag] - var/list/data = sensor_information[id_tag] - var/sensor_part = "[long_name]:
" +/obj/machinery/computer/general_air_control/proc/return_text() + var/sensor_data + if(sensors.len) + for(var/id_tag in sensors) + var/long_name = sensors[id_tag] + var/list/data = sensor_information[id_tag] + var/sensor_part = "[long_name]:
" - if(data) - if(data["pressure"]) - sensor_part += " Pressure: [data["pressure"]] kPa
" - if(data["temperature"]) - sensor_part += " Temperature: [data["temperature"]] K
" - if(data["oxygen"]||data["phoron"]||data["nitrogen"]||data["carbon_dioxide"]) - sensor_part += " Gas Composition :" - if(data["oxygen"]) - sensor_part += "[data["oxygen"]]% O2; " - if(data["nitrogen"]) - sensor_part += "[data["nitrogen"]]% N; " - if(data["carbon_dioxide"]) - sensor_part += "[data["carbon_dioxide"]]% CO2; " - if(data["phoron"]) - sensor_part += "[data["phoron"]]% TX; " - sensor_part += "
" + if(data) + if(data["pressure"]) + sensor_part += " Pressure: [data["pressure"]] kPa
" + if(data["temperature"]) + sensor_part += " Temperature: [data["temperature"]] K
" + if(data["oxygen"]||data["phoron"]||data["nitrogen"]||data["carbon_dioxide"]) + sensor_part += " Gas Composition :" + if(data["oxygen"]) + sensor_part += "[data["oxygen"]]% O2; " + if(data["nitrogen"]) + sensor_part += "[data["nitrogen"]]% N; " + if(data["carbon_dioxide"]) + sensor_part += "[data["carbon_dioxide"]]% CO2; " + if(data["phoron"]) + sensor_part += "[data["phoron"]]% TX; " + sensor_part += "
" - else - sensor_part = "[long_name] can not be found!
" + else + sensor_part = "[long_name] can not be found!
" - sensor_data += sensor_part + sensor_data += sensor_part - else - sensor_data = "No sensors connected." + else + sensor_data = "No sensors connected." - var/output = {"[name]
+ var/output = {"[name]
Sensor Data:

[sensor_data]"} - return output + return output - proc - set_frequency(new_frequency) - radio_controller.remove_object(src, frequency) - frequency = new_frequency - radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) +/obj/machinery/computer/general_air_control/proc/set_frequency(new_frequency) + radio_controller.remove_object(src, frequency) + frequency = new_frequency + radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA) - initialize() - set_frequency(frequency) - - large_tank_control - icon = 'icons/obj/computer.dmi' - icon_state = "tank" - - var/input_tag - var/output_tag - - var/list/input_info - var/list/output_info - - var/pressure_setting = ONE_ATMOSPHERE * 45 - circuit = /obj/item/weapon/circuitboard/air_management/tank_control +/obj/machinery/computer/general_air_control/initialize() + set_frequency(frequency) - return_text() - var/output = ..() - //if(signal.data) - // input_info = signal.data // Attempting to fix intake control -- TLE +/obj/machinery/computer/general_air_control/large_tank_control + icon = 'icons/obj/computer.dmi' + icon_state = "tank" - output += "Tank Control System
" - if(input_info) - var/power = (input_info["power"]) - var/volume_rate = input_info["volume_rate"] - output += {"Input: [power?("Injecting"):("On Hold")] Refresh
-Rate: [volume_rate] L/sec
"} - output += "Command: Toggle Power
" + frequency = 1441 + var/input_tag + var/output_tag - else - output += "ERROR: Can not find input port Search
" + var/list/input_info + var/list/output_info - output += "
" + var/input_flow_setting = 200 + var/pressure_setting = ONE_ATMOSPHERE * 45 + circuit = /obj/item/weapon/circuitboard/air_management/tank_control - if(output_info) - var/power = (output_info["power"]) - var/output_pressure = output_info["internal"] - output += {"Output: [power?("Open"):("On Hold")] Refresh
+ +/obj/machinery/computer/general_air_control/large_tank_control/return_text() + var/output = ..() + //if(signal.data) + // input_info = signal.data // Attempting to fix intake control -- TLE + + output += "Tank Control System

" + if(input_info) + var/power = (input_info["power"]) + var/volume_rate = round(input_info["volume_rate"], 0.1) + output += "Input: [power?("Injecting"):("On Hold")] Refresh
Flow Rate Limit: [volume_rate] L/s
" + output += "Command: Toggle Power Set Flow Rate
" + + else + output += "ERROR: Can not find input port Search
" + + output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
" + + output += "
" + + if(output_info) + var/power = (output_info["power"]) + var/output_pressure = output_info["internal"] + output += {"Output: [power?("Open"):("On Hold")] Refresh
Max Output Pressure: [output_pressure] kPa
"} - output += "Command: Toggle Power Set Pressure
" + output += "Command: Toggle Power Set Pressure
" - else - output += "ERROR: Can not find output port Search
" + else + output += "ERROR: Can not find output port Search
" - output += "Max Output Pressure Set: - - - - [pressure_setting] kPa + + + +
" + output += "Max Output Pressure Set: - - - - [pressure_setting] kPa + + + +
" - return output + return output - receive_signal(datum/signal/signal) - if(!signal || signal.encryption) return +/obj/machinery/computer/general_air_control/large_tank_control/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return - var/id_tag = signal.data["tag"] + var/id_tag = signal.data["tag"] - if(input_tag == id_tag) - input_info = signal.data - else if(output_tag == id_tag) - output_info = signal.data - else - ..(signal) + if(input_tag == id_tag) + input_info = signal.data + else if(output_tag == id_tag) + output_info = signal.data + else + ..(signal) - Topic(href, href_list) - if(..()) - return +/obj/machinery/computer/general_air_control/large_tank_control/Topic(href, href_list) + if(..()) + return - if(href_list["adj_pressure"]) - var/change = text2num(href_list["adj_pressure"]) - pressure_setting = between(0, pressure_setting + change, 50*ONE_ATMOSPHERE) - spawn(1) - src.updateUsrDialog() - return + if(href_list["adj_pressure"]) + var/change = text2num(href_list["adj_pressure"]) + pressure_setting = between(0, pressure_setting + change, 50*ONE_ATMOSPHERE) + spawn(1) + src.updateUsrDialog() + return - if(!radio_connection) - return 0 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - if(href_list["in_refresh_status"]) - input_info = null - signal.data = list ("tag" = input_tag, "status") + if(href_list["adj_input_flow_rate"]) + var/change = text2num(href_list["adj_input_flow_rate"]) + input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + spawn(1) + src.updateUsrDialog() + return + + if(!radio_connection) + return 0 + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + if(href_list["in_refresh_status"]) + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) - if(href_list["in_toggle_injector"]) - input_info = null - signal.data = list ("tag" = input_tag, "power_toggle") + if(href_list["in_toggle_injector"]) + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) - if(href_list["out_refresh_status"]) - output_info = null - signal.data = list ("tag" = output_tag, "status") + if(href_list["in_set_flowrate"]) + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") - if(href_list["out_toggle_power"]) - output_info = null - signal.data = list ("tag" = output_tag, "power_toggle") + if(href_list["out_refresh_status"]) + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) - if(href_list["out_set_pressure"]) - output_info = null - signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") + if(href_list["out_toggle_power"]) + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) - signal.data["sigtype"]="command" - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + if(href_list["out_set_pressure"]) + output_info = null + signal.data = list ("tag" = output_tag, "set_internal_pressure" = "[pressure_setting]") - spawn(5) - src.updateUsrDialog() + signal.data["sigtype"]="command" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - fuel_injection - icon = 'icons/obj/computer.dmi' - icon_state = "atmos" + spawn(5) + src.updateUsrDialog() - var/device_tag - var/list/device_info +/obj/machinery/computer/general_air_control/supermatter_core + icon = 'icons/obj/computer.dmi' + icon_state = "tank" - var/automation = 0 + frequency = 1438 + var/input_tag + var/output_tag - var/cutoff_temperature = 2000 - var/on_temperature = 1200 - circuit = /obj/item/weapon/circuitboard/air_management/injector_control + var/list/input_info + var/list/output_info - process() - if(automation) - if(!radio_connection) - return 0 + var/input_flow_setting = 700 + var/pressure_setting = 100 + circuit = /obj/item/weapon/circuitboard/air_management/supermatter_core - var/injecting = 0 - for(var/id_tag in sensor_information) - var/list/data = sensor_information[id_tag] - if(data["temperature"]) - if(data["temperature"] >= cutoff_temperature) - injecting = 0 - break - if(data["temperature"] <= on_temperature) - injecting = 1 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src +/obj/machinery/computer/general_air_control/supermatter_core/return_text() + var/output = ..() + //if(signal.data) + // input_info = signal.data // Attempting to fix intake control -- TLE - signal.data = list( - "tag" = device_tag, - "power" = injecting, - "sigtype"="command" - ) + output += "Core Cooling Control System

" + if(input_info) + var/power = (input_info["power"]) + var/volume_rate = round(input_info["volume_rate"], 0.1) + output += "Coolant Input: [power?("Injecting"):("On Hold")] Refresh
Flow Rate Limit: [volume_rate] L/s
" + output += "Command: Toggle Power Set Flow Rate
" - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + else + output += "ERROR: Can not find input port Search
" + + output += "Flow Rate Limit: - - - - [round(input_flow_setting, 0.1)] L/s + + + +
" - ..() + output += "
" - return_text() - var/output = ..() + if(output_info) + var/power = (output_info["power"]) + var/pressure_limit = output_info["external"] + output += {"Core Outpump: [power?("Open"):("On Hold")] Refresh
+Min Core Pressure: [pressure_limit] kPa
"} + output += "Command: Toggle Power Set Pressure
" - output += "Fuel Injection System
" - if(device_info) - var/power = device_info["power"] - var/volume_rate = device_info["volume_rate"] - output += {"Status: [power?("Injecting"):("On Hold")] Refresh
+ else + output += "ERROR: Can not find output port Search
" + + output += "Min Core Pressure Set: - - - - [pressure_setting] kPa + + + +
" + + return output + +/obj/machinery/computer/general_air_control/supermatter_core/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return + + var/id_tag = signal.data["tag"] + + if(input_tag == id_tag) + input_info = signal.data + else if(output_tag == id_tag) + output_info = signal.data + else + ..(signal) + +/obj/machinery/computer/general_air_control/supermatter_core/Topic(href, href_list) + if(..()) + return + + if(href_list["adj_pressure"]) + var/change = text2num(href_list["adj_pressure"]) + pressure_setting = between(0, pressure_setting + change, 10*ONE_ATMOSPHERE) + spawn(1) + src.updateUsrDialog() + return + + if(href_list["adj_input_flow_rate"]) + var/change = text2num(href_list["adj_input_flow_rate"]) + input_flow_setting = between(0, input_flow_setting + change, ATMOS_DEFAULT_VOLUME_PUMP + 500) //default flow rate limit for air injectors + spawn(1) + src.updateUsrDialog() + return + + if(!radio_connection) + return 0 + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + if(href_list["in_refresh_status"]) + input_info = null + signal.data = list ("tag" = input_tag, "status" = 1) + + if(href_list["in_toggle_injector"]) + input_info = null + signal.data = list ("tag" = input_tag, "power_toggle" = 1) + + if(href_list["in_set_flowrate"]) + input_info = null + signal.data = list ("tag" = input_tag, "set_volume_rate" = "[input_flow_setting]") + + if(href_list["out_refresh_status"]) + output_info = null + signal.data = list ("tag" = output_tag, "status" = 1) + + if(href_list["out_toggle_power"]) + output_info = null + signal.data = list ("tag" = output_tag, "power_toggle" = 1) + + if(href_list["out_set_pressure"]) + output_info = null + signal.data = list ("tag" = output_tag, "set_external_pressure" = "[pressure_setting]", "checks" = 1) + + signal.data["sigtype"]="command" + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + spawn(5) + src.updateUsrDialog() + +/obj/machinery/computer/general_air_control/fuel_injection + icon = 'icons/obj/computer.dmi' + icon_state = "atmos" + + var/device_tag + var/list/device_info + + var/automation = 0 + + var/cutoff_temperature = 2000 + var/on_temperature = 1200 + circuit = /obj/item/weapon/circuitboard/air_management/injector_control + +/obj/machinery/computer/general_air_control/fuel_injection/process() + if(automation) + if(!radio_connection) + return 0 + + var/injecting = 0 + for(var/id_tag in sensor_information) + var/list/data = sensor_information[id_tag] + if(data["temperature"]) + if(data["temperature"] >= cutoff_temperature) + injecting = 0 + break + if(data["temperature"] <= on_temperature) + injecting = 1 + + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + + signal.data = list( + "tag" = device_tag, + "power" = injecting, + "sigtype"="command" + ) + + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + + ..() + +/obj/machinery/computer/general_air_control/fuel_injection/return_text() + var/output = ..() + + output += "Fuel Injection System
" + if(device_info) + var/power = device_info["power"] + var/volume_rate = device_info["volume_rate"] + output += {"Status: [power?("Injecting"):("On Hold")] Refresh
Rate: [volume_rate] L/sec
"} - if(automation) - output += "Automated Fuel Injection: Engaged
" - output += "Injector Controls Locked Out
" - else - output += "Automated Fuel Injection: Disengaged
" - output += "Injector: Toggle Power Inject (1 Cycle)
" + if(automation) + output += "Automated Fuel Injection: Engaged
" + output += "Injector Controls Locked Out
" + else + output += "Automated Fuel Injection: Disengaged
" + output += "Injector: Toggle Power Inject (1 Cycle)
" - else - output += "ERROR: Can not find device Search
" + else + output += "ERROR: Can not find device Search
" - return output + return output - receive_signal(datum/signal/signal) - if(!signal || signal.encryption) return +/obj/machinery/computer/general_air_control/fuel_injection/receive_signal(datum/signal/signal) + if(!signal || signal.encryption) return - var/id_tag = signal.data["tag"] + var/id_tag = signal.data["tag"] - if(device_tag == id_tag) - device_info = signal.data - else - ..(signal) + if(device_tag == id_tag) + device_info = signal.data + else + ..(signal) - Topic(href, href_list) - if(..()) - return +/obj/machinery/computer/general_air_control/fuel_injection/Topic(href, href_list) + if(..()) + return - if(href_list["refresh_status"]) - device_info = null - if(!radio_connection) - return 0 + if(href_list["refresh_status"]) + device_info = null + if(!radio_connection) + return 0 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "status", - "sigtype"="command" - ) - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "status" = 1, + "sigtype"="command" + ) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - if(href_list["toggle_automation"]) - automation = !automation + if(href_list["toggle_automation"]) + automation = !automation - if(href_list["toggle_injector"]) - device_info = null - if(!radio_connection) - return 0 + if(href_list["toggle_injector"]) + device_info = null + if(!radio_connection) + return 0 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "power_toggle", - "sigtype"="command" - ) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "power_toggle" = 1, + "sigtype"="command" + ) - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) - if(href_list["injection"]) - if(!radio_connection) - return 0 + if(href_list["injection"]) + if(!radio_connection) + return 0 - var/datum/signal/signal = new - signal.transmission_method = 1 //radio signal - signal.source = src - signal.data = list( - "tag" = device_tag, - "inject", - "sigtype"="command" - ) + var/datum/signal/signal = new + signal.transmission_method = 1 //radio signal + signal.source = src + signal.data = list( + "tag" = device_tag, + "inject" = 1, + "sigtype"="command" + ) - radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) + radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA) diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm index 9e85bccfda0..ff7821fa0af 100644 --- a/code/game/machinery/atmoalter/canister.dm +++ b/code/game/machinery/atmoalter/canister.dm @@ -49,7 +49,8 @@ icon_state = "grey" canister_color = "grey" can_label = 0 - +/obj/machinery/portable_atmospherics/canister/air/airlock + filled = 0.05 /obj/machinery/portable_atmospherics/canister/empty/oxygen name = "Canister: \[O2\]" icon_state = "blue" diff --git a/code/game/machinery/atmoalter/meter.dm b/code/game/machinery/atmoalter/meter.dm index 9c26fa4a4e5..1c99ff73448 100644 --- a/code/game/machinery/atmoalter/meter.dm +++ b/code/game/machinery/atmoalter/meter.dm @@ -77,7 +77,7 @@ else if(src.target) var/datum/gas_mixture/environment = target.return_air() if(environment) - t += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]°K ([round(environment.temperature-T0C,0.01)]°C)" + t += "The pressure gauge reads [round(environment.return_pressure(), 0.01)] kPa; [round(environment.temperature,0.01)]K ([round(environment.temperature-T0C,0.01)]°C)" else t += "The sensor error light is blinking." else diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index c24d07a2eda..1261d0fc146 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -373,4 +373,15 @@ tot_rating += MB.rating storage_capacity["metal"] = tot_rating * 25000 - storage_capacity["glass"] = tot_rating * 12500 \ No newline at end of file + storage_capacity["glass"] = tot_rating * 12500 + +/obj/machinery/autolathe/dismantle() + ..() + var/list/sheets = list("metal" = /obj/item/stack/sheet/metal, "glass" = /obj/item/stack/sheet/glass) + + for(var/mat in stored_material) + var/T = sheets[mat] + var/obj/item/stack/sheet/S = new T + if(stored_material[mat] > S.perunit) + S.amount = round(stored_material[mat] / S.perunit) + S.loc = loc diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index 0691a74e541..2502277226b 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -79,7 +79,7 @@ var/dat dat += "Automatic Station Floor Repairer v1.0

" dat += "Status: [src.on ? "On" : "Off"]
" - dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
" + dat += "Maintenance panel is [src.open ? "opened" : "closed"]
" dat += "Tiles left: [src.amount]
" dat += "Behvaiour controls are [src.locked ? "locked" : "unlocked"]
" if(!src.locked || issilicon(user)) @@ -448,4 +448,4 @@ if (!in_range(src, usr) && src.loc != usr) return - src.created_name = t \ No newline at end of file + src.created_name = t diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm index c5008e1dc74..f55501c3fb4 100644 --- a/code/game/machinery/bots/medbot.dm +++ b/code/game/machinery/bots/medbot.dm @@ -106,7 +106,7 @@ var/dat dat += "Automatic Medical Unit v1.0

" dat += "Status: [src.on ? "On" : "Off"]
" - dat += "Maintenance panel panel is [src.open ? "opened" : "closed"]
" + dat += "Maintenance panel is [src.open ? "opened" : "closed"]
" dat += "Beaker: " if (src.reagent_glass) dat += "Loaded \[[src.reagent_glass.reagents.total_volume]/[src.reagent_glass.reagents.maximum_volume]\]" diff --git a/code/game/machinery/bots/secbot.dm b/code/game/machinery/bots/secbot.dm index 6358c1466c2..094f3ff7006 100644 --- a/code/game/machinery/bots/secbot.dm +++ b/code/game/machinery/bots/secbot.dm @@ -141,7 +141,7 @@ Automatic Security Unit v[bot_version]

Status: []
Behaviour controls are [src.locked ? "locked" : "unlocked"]
-Maintenance panel panel is [src.open ? "opened" : "closed"]"}, +Maintenance panel is [src.open ? "opened" : "closed"]"}, "[src.on ? "On" : "Off"]" ) diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index b50d38dcb6a..14f8f93e56f 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -70,13 +70,7 @@ cancelCameraAlarm() if(can_use()) cameranet.addCamera(src) - for(var/mob/O in mob_list) - if (istype(O.machine, /obj/machinery/computer/security)) - var/obj/machinery/computer/security/S = O.machine - if (S.current == src) - O.unset_machine() - O.reset_view(null) - O << "The screen bursts into static." + kick_viewers() ..() @@ -193,6 +187,10 @@ // now disconnect anyone using the camera //Apparently, this will disconnect anyone even if the camera was re-activated. //I guess that doesn't matter since they can't use it anyway? + kick_viewers() + +//This might be redundant, because of check_eye() +/obj/machinery/camera/proc/kick_viewers() for(var/mob/O in player_list) if (istype(O.machine, /obj/machinery/computer/security)) var/obj/machinery/computer/security/S = O.machine diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 097c4f9a27e..0017b260c29 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -9,7 +9,7 @@ matter = list("metal" = 700,"glass" = 300) // Motion, EMP-Proof, X-Ray - var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/phoron, /obj/item/weapon/reagent_containers/food/snacks/grown/carrot) + var/list/obj/item/possible_upgrades = list(/obj/item/device/assembly/prox_sensor, /obj/item/stack/sheet/mineral/osmium, /obj/item/weapon/stock_parts/scanning_module) var/list/upgrades = list() var/state = 0 var/busy = 0 @@ -88,7 +88,8 @@ usr << "No network found please hang up and try your call again." return - var/temptag = "[get_area(src)] ([rand(1, 999)])" + var/area/camera_area = get_area(src) + var/temptag = "[sanitize(camera_area.name)] ([rand(1, 999)])" input = strip_html(input(usr, "How would you like to name the camera?", "Set Camera Name", temptag)) state = 4 @@ -125,7 +126,7 @@ // Upgrades! if(is_type_in_list(W, possible_upgrades) && !is_type_in_list(W, upgrades)) // Is a possible upgrade and isn't in the camera already. - user << "You attach the [W] into the assembly inner circuits." + user << "You attach \the [W] into the assembly inner circuits." upgrades += W user.drop_item(W) W.loc = src diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 19f2620630e..0c6f7d95a7f 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -8,6 +8,8 @@ /obj/machinery/camera/process() // motion camera event loop + if (stat & (EMPED|NOPOWER)) + return if(!isMotion()) . = PROCESS_KILL return @@ -40,16 +42,20 @@ cancelAlarm() /obj/machinery/camera/proc/cancelAlarm() + if (!status || (stat & NOPOWER)) + return 0 if (detectTime == -1) for (var/mob/living/silicon/aiPlayer in player_list) - if (status) aiPlayer.cancelAlarm("Motion", get_area(src), src) + aiPlayer.cancelAlarm("Motion", get_area(src), src) detectTime = 0 return 1 /obj/machinery/camera/proc/triggerAlarm() + if (!status || (stat & NOPOWER)) + return 0 if (!detectTime) return 0 for (var/mob/living/silicon/aiPlayer in player_list) - if (status) aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src) + aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src) detectTime = -1 return 1 diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm index 0c0c8457003..21a9dc10616 100644 --- a/code/game/machinery/camera/presets.dm +++ b/code/game/machinery/camera/presets.dm @@ -53,12 +53,14 @@ // CHECKS /obj/machinery/camera/proc/isEmpProof() - var/O = locate(/obj/item/stack/sheet/mineral/phoron) in assembly.upgrades + var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades return O /obj/machinery/camera/proc/isXRay() - var/O = locate(/obj/item/weapon/reagent_containers/food/snacks/grown/carrot) in assembly.upgrades - return O + var/obj/item/weapon/stock_parts/scanning_module/O = locate(/obj/item/weapon/stock_parts/scanning_module) in assembly.upgrades + if (O && O.rating >= 2) + return O + return null /obj/machinery/camera/proc/isMotion() var/O = locate(/obj/item/device/assembly/prox_sensor) in assembly.upgrades @@ -67,11 +69,22 @@ // UPGRADE PROCS /obj/machinery/camera/proc/upgradeEmpProof() - assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/phoron(assembly)) + assembly.upgrades.Add(new /obj/item/stack/sheet/mineral/osmium(assembly)) + setPowerUsage() /obj/machinery/camera/proc/upgradeXRay() - assembly.upgrades.Add(new /obj/item/weapon/reagent_containers/food/snacks/grown/carrot(assembly)) + assembly.upgrades.Add(new /obj/item/weapon/stock_parts/scanning_module/adv(assembly)) + setPowerUsage() // If you are upgrading Motion, and it isn't in the camera's New(), add it to the machines list. /obj/machinery/camera/proc/upgradeMotion() - assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly)) \ No newline at end of file + assembly.upgrades.Add(new /obj/item/device/assembly/prox_sensor(assembly)) + setPowerUsage() + +/obj/machinery/camera/proc/setPowerUsage() + var/mult = 1 + if (isXRay()) + mult++ + if (isMotion()) + mult++ + active_power_usage = mult*initial(active_power_usage) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 50eb026b933..06527e3f97f 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -25,15 +25,16 @@ var/frame_desc = null var/contain_parts = 1 -//Called when the circuitboard is used to contruct a new computer. -/obj/item/weapon/circuitboard/proc/construct_computer(var/obj/machinery/computer/C) - if (istype(C, build_path)) +//Called when the circuitboard is used to contruct a new machine. +/obj/item/weapon/circuitboard/proc/construct(var/obj/machinery/M) + if (istype(M, build_path)) return 1 return 0 -//Called when a computer is deconstructed to produce a circuitboard -/obj/item/weapon/circuitboard/proc/deconstruct_computer(var/obj/machinery/computer/C) - if (istype(C, build_path)) +//Called when a computer is deconstructed to produce a circuitboard. +//Only used by computers, as other machines store their circuitboard instance. +/obj/item/weapon/circuitboard/proc/deconstruct(var/obj/machinery/M) + if (istype(M, build_path)) return 1 return 0 @@ -55,11 +56,11 @@ var/locked = 1 var/emagged = 0 -/obj/item/weapon/circuitboard/security/construct_computer(var/obj/machinery/computer/security/C) +/obj/item/weapon/circuitboard/security/construct(var/obj/machinery/computer/security/C) if (..(C)) C.network = network -/obj/item/weapon/circuitboard/security/deconstruct_computer(var/obj/machinery/computer/security/C) +/obj/item/weapon/circuitboard/security/deconstruct(var/obj/machinery/computer/security/C) if (..(C)) network = C.network @@ -132,15 +133,20 @@ /obj/item/weapon/circuitboard/air_management/tank_control name = "Circuit board (Tank Control)" build_path = "/obj/machinery/computer/general_air_control/large_tank_control" + frequency = 1441 +/obj/item/weapon/circuitboard/air_management/supermatter_core + name = "Circuit board (Core Control)" + build_path = "/obj/machinery/computer/general_air_control/supermatter_core" + frequency = 1438 /obj/item/weapon/circuitboard/air_management/injector_control name = "Circuit board (Injector Control)" build_path = "/obj/machinery/computer/general_air_control/fuel_injection" -/obj/item/weapon/circuitboard/air_management/construct_computer(var/obj/machinery/computer/general_air_control/C) +/obj/item/weapon/circuitboard/air_management/construct(var/obj/machinery/computer/general_air_control/C) if (..(C)) C.frequency = frequency -/obj/item/weapon/circuitboard/air_management/deconstruct_computer(var/obj/machinery/computer/general_air_control/C) +/obj/item/weapon/circuitboard/air_management/deconstruct(var/obj/machinery/computer/general_air_control/C) if (..(C)) frequency = C.frequency @@ -216,11 +222,11 @@ origin_tech = "programming=3" var/contraband_enabled = 0 -/obj/item/weapon/circuitboard/supplycomp/construct_computer(var/obj/machinery/computer/supplycomp/SC) +/obj/item/weapon/circuitboard/supplycomp/construct(var/obj/machinery/computer/supplycomp/SC) if (..(SC)) SC.can_order_contraband = contraband_enabled -/obj/item/weapon/circuitboard/supplycomp/deconstruct_computer(var/obj/machinery/computer/supplycomp/SC) +/obj/item/weapon/circuitboard/supplycomp/deconstruct(var/obj/machinery/computer/supplycomp/SC) if (..(SC)) contraband_enabled = SC.can_order_contraband @@ -446,5 +452,5 @@ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) user << "\blue You connect the monitor." var/B = new src.circuit.build_path ( src.loc ) - src.circuit.construct_computer(B) + src.circuit.construct(B) del(src) \ No newline at end of file diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 13dd68d584c..ef434955a1a 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -21,8 +21,10 @@ check_eye(var/mob/user as mob) - if ((get_dist(user, src) > 1 || !( user.canmove ) || user.blinded || !( current ) || !( current.status )) && (!istype(user, /mob/living/silicon))) + if (user.stat || ((get_dist(user, src) > 1 || !( user.canmove ) || user.blinded) && !istype(user, /mob/living/silicon))) //user can't see - not sure why canmove is here. return null + if ( !current || !current.can_use() ) //camera doesn't work + current = null user.reset_view(current) return 1 @@ -46,7 +48,7 @@ D["Cancel"] = "Cancel" for(var/obj/machinery/camera/C in L) if(can_access_camera(C)) - D[text("[][]", C.c_tag, (C.status ? null : " (Deactivated)"))] = C + D[text("[][]", C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C var/t = input(user, "Which camera should you change to?") as null|anything in D if(!t) @@ -72,19 +74,18 @@ return 0 proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C) - if ((get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) || !( C.can_use() )) && (!istype(user, /mob/living/silicon/ai))) - if(!C.can_use() && !isAI(user)) - src.current = null - return 0 - else - if(isAI(user)) - var/mob/living/silicon/ai/A = user - A.eyeobj.setLoc(get_turf(C)) - A.client.eye = A.eyeobj - else - src.current = C - use_power(50) + //don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras. + if(isAI(user)) + var/mob/living/silicon/ai/A = user + A.eyeobj.setLoc(get_turf(C)) + A.client.eye = A.eyeobj return 1 + + if (!C.can_use() || user.stat || (get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) && !istype(user, /mob/living/silicon))) + return 0 + src.current = C + use_power(50) + return 1 //Camera control: moving. proc/jump_on_click(var/mob/user,var/A) diff --git a/code/game/machinery/computer/camera_monitor.dm b/code/game/machinery/computer/camera_monitor.dm index c8f3b7b3481..11e8ddd43c6 100644 --- a/code/game/machinery/computer/camera_monitor.dm +++ b/code/game/machinery/computer/camera_monitor.dm @@ -40,7 +40,7 @@ D["Cancel"] = "Cancel" for (var/obj/machinery/camera/C in L) if ( C.network in src.networks ) - D[text("[]: [][]", C.network, C.c_tag, (C.status ? null : " (Deactivated)"))] = C + D[text("[]: [][]", C.network, C.c_tag, (C.can_use() ? null : " (Deactivated)"))] = C var/t = input(user, "Which camera should you change to?") as null|anything in D diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm index 23e764efe4f..ff88f89c5a2 100644 --- a/code/game/machinery/computer/computer.dm +++ b/code/game/machinery/computer/computer.dm @@ -120,7 +120,7 @@ user << "\blue You disconnect the monitor." A.state = 4 A.icon_state = "4" - M.deconstruct_computer(src) + M.deconstruct(src) del(src) else src.attack_hand(user) diff --git a/code/game/machinery/computer/crew.dm b/code/game/machinery/computer/crew.dm index 4796afff998..d9b0bbc433f 100644 --- a/code/game/machinery/computer/crew.dm +++ b/code/game/machinery/computer/crew.dm @@ -117,10 +117,7 @@ ui.add_template("mapContent", "crew_monitor_map_content.tmpl") // adding a template with the key "mapHeader" replaces the map header content ui.add_template("mapHeader", "crew_monitor_map_header.tmpl") - - // we want to show the map by default - ui.set_show_map(1) - + ui.set_initial_data(data) ui.open() diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index 8a7060ac7ea..106cd2bbad2 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -115,6 +115,7 @@ playsound(src.loc, 'sound/items/Screwdriver.ogg', 50, 1) var/obj/machinery/new_machine = new src.circuit.build_path(src.loc) new_machine.component_parts.Cut() + src.circuit.construct(new_machine) for(var/obj/O in src) if(circuit.contain_parts) // things like disposal don't want their parts in them O.loc = new_machine @@ -275,10 +276,35 @@ obj/item/weapon/circuitboard/rdserver "/obj/item/weapon/stock_parts/console_screen" = 1, "/obj/item/stack/cable_coil" = 2,) -/obj/item/weapon/circuitboard/gas_heater +/obj/item/weapon/circuitboard/unary_atmos + board_type = "machine" + var/machine_dir = SOUTH + var/init_dirs = SOUTH + +/obj/item/weapon/circuitboard/unary_atmos/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I,/obj/item/weapon/screwdriver)) + machine_dir = turn(machine_dir, 90) + init_dirs = machine_dir + user.visible_message("\blue \The [user] adjusts the jumper on the [src]'s port configuration pins.", "\blue You adjust the jumper on the port configuration pins. Now set to [dir2text(machine_dir)].") + return + +/obj/item/weapon/circuitboard/unary_atmos/examine() + ..() + usr << "The jumper is connecting the [dir2text(machine_dir)] pins." + +/obj/item/weapon/circuitboard/unary_atmos/construct(var/obj/machinery/atmospherics/unary/U) + //TODO: Move this stuff into the relevant constructor when pipe/construction.dm is cleaned up. + U.dir = src.machine_dir + U.initialize_directions = src.init_dirs + U.initialize() + U.build_network() + if (U.node) + U.node.initialize() + U.node.build_network() + +/obj/item/weapon/circuitboard/unary_atmos/heater name = "Circuit Board (Gas Heating System)" build_path = "/obj/machinery/atmospherics/unary/heater" - board_type = "machine" origin_tech = "powerstorage=2;engineering=1" frame_desc = "Requires 5 Pieces of Cable, 1 Matter Bin, and 2 Capacitors." req_components = list( @@ -286,10 +312,9 @@ obj/item/weapon/circuitboard/rdserver "/obj/item/weapon/stock_parts/matter_bin" = 1, "/obj/item/weapon/stock_parts/capacitor" = 2) -/obj/item/weapon/circuitboard/gas_cooler +/obj/item/weapon/circuitboard/unary_atmos/cooler name = "Circuit Board (Gas Cooling System)" build_path = "/obj/machinery/atmospherics/unary/freezer" - board_type = "machine" origin_tech = "magnets=2;engineering=2" frame_desc = "Requires 2 Pieces of Cable, 1 Matter Bin, 1 Micro Manipulator, and 2 Capacitors." req_components = list( diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm index 29451066847..3974ebdd503 100644 --- a/code/game/machinery/cryo.dm +++ b/code/game/machinery/cryo.dm @@ -1,3 +1,5 @@ +#define HEAT_CAPACITY_HUMAN 100 //249840 J/K, for a 72 kg person. + /obj/machinery/atmospherics/unary/cryo_cell name = "cryo cell" icon = 'icons/obj/cryogenics.dmi' @@ -10,7 +12,7 @@ use_power = 1 idle_power_usage = 20 active_power_usage = 200 - + var/temperature_archived var/mob/living/carbon/occupant = null var/obj/item/weapon/reagent_containers/glass/beaker = null diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm index fe569e23647..48321f9fc80 100644 --- a/code/game/machinery/cryopod.dm +++ b/code/game/machinery/cryopod.dm @@ -41,6 +41,7 @@ var/global/list/frozen_items = list() dat += "

Cryogenic Oversight Control
" dat += "Welcome, [user.real_name].


" dat += "View storage log.
" + dat += "View objects.
" dat += "Recover object.
" dat += "Recover all objects.
" @@ -65,16 +66,27 @@ var/global/list/frozen_items = list() user << browse(dat, "window=cryolog") + if(href_list["view"]) + + var/dat = "Recently stored objects


" + for(var/obj/item/I in frozen_items) + dat += "[I.name]
" + dat += "
" + + user << browse(dat, "window=cryoitems") + else if(href_list["item"]) if(frozen_items.len == 0) user << "\blue There is nothing to recover from storage." return - var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as obj in frozen_items + var/obj/item/I = input(usr, "Please choose which object to retrieve.","Object recovery",null) as null|anything in frozen_items + if(!I) + return - if(!I || frozen_items.len == 0) - user << "\blue There is nothing to recover from storage." + if(!(I in frozen_items)) + user << "\blue \The [I] is no longer in storage." return visible_message("\blue The console beeps happily as it disgorges \the [I].", 3) @@ -134,10 +146,10 @@ var/global/list/frozen_items = list() density = 1 anchored = 1 - var/mob/occupant = null // Person waiting to be despawned. - var/orient_right = null // Flips the sprite. - var/time_till_despawn = 9000 // 15 minutes-ish safe period before being despawned. - var/time_entered = 0 // Used to keep track of the safe period. + var/mob/occupant = null // Person waiting to be despawned. + var/orient_right = null // Flips the sprite. + var/time_till_despawn = 18000 // 30 minutes-ish safe period before being despawned. + var/time_entered = 0 // Used to keep track of the safe period. var/obj/item/device/radio/intercom/announce // // These items are preserved when the process() despawn proc occurs. @@ -173,7 +185,6 @@ var/global/list/frozen_items = list() //Lifted from Unity stasis.dm and refactored. ~Zuhayr /obj/machinery/cryopod/process() if(occupant) - //Allow a ten minute gap between entering the pod and actually despawning. if(world.time - time_entered < time_till_despawn) return @@ -187,7 +198,7 @@ var/global/list/frozen_items = list() if(W.contents.len) //Make sure we catch anything not handled by del() on the items. for(var/obj/item/O in W.contents) - if(istype(O,/obj/item/weapon/storage/internal)) //Stop eating pockets you fuck! + if(istype(O,/obj/item/weapon/storage/internal)) //Stop eating pockets, you fuck! continue O.loc = src @@ -333,6 +344,7 @@ var/global/list/frozen_items = list() src.add_fingerprint(M) /obj/machinery/cryopod/verb/eject() + set name = "Eject Pod" set category = "Object" set src in oview(1) @@ -344,6 +356,14 @@ var/global/list/frozen_items = list() else icon_state = "body_scanner_0" + //Eject any items that aren't meant to be in the pod. + var/list/items = src.contents + if(occupant) items -= occupant + if(announce) items -= announce + + for(var/obj/item/W in items) + W.loc = get_turf(src) + src.go_out() add_fingerprint(usr) return diff --git a/code/game/machinery/doors/airlock_control.dm b/code/game/machinery/doors/airlock_control.dm index 3b1700df784..7ad909c8eb4 100644 --- a/code/game/machinery/doors/airlock_control.dm +++ b/code/game/machinery/doors/airlock_control.dm @@ -28,7 +28,8 @@ obj/machinery/door/airlock/receive_signal(datum/signal/signal) if(id_tag != signal.data["tag"] || !signal.data["command"]) return cur_command = signal.data["command"] - execute_current_command() + spawn() + execute_current_command() obj/machinery/door/airlock/proc/execute_current_command() if(operating) diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 12f224ac527..ceb04ad56b2 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -1,4 +1,6 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 +#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed /obj/machinery/door name = "Door" @@ -8,7 +10,9 @@ anchored = 1 opacity = 1 density = 1 - layer = 2.7 + layer = DOOR_OPEN_LAYER + var/open_layer = DOOR_OPEN_LAYER + var/closed_layer = DOOR_CLOSED_LAYER var/secondsElectrified = 0 var/visible = 1 @@ -27,11 +31,11 @@ /obj/machinery/door/New() . = ..() if(density) - layer = 3.1 //Above most items if closed + layer = closed_layer explosion_resistance = initial(explosion_resistance) update_heat_protection(get_turf(src)) else - layer = 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 + layer = open_layer explosion_resistance = 0 @@ -142,7 +146,7 @@ user = null if(!src.requiresID()) user = null - if(src.density && (istype(I, /obj/item/weapon/card/emag)||istype(I, /obj/item/weapon/melee/energy/blade))) + if(src.density && ((operable() && istype(I, /obj/item/weapon/card/emag)) || istype(I, /obj/item/weapon/melee/energy/blade))) flick("door_spark", src) sleep(6) open() @@ -226,7 +230,7 @@ icon_state = "door0" src.SetOpacity(0) sleep(10) - src.layer = 2.7 + src.layer = open_layer src.density = 0 explosion_resistance = 0 update_icon() @@ -250,10 +254,10 @@ if(operating > 0) return operating = 1 - do_animate("closing") src.density = 1 explosion_resistance = initial(explosion_resistance) - src.layer = 3.1 + src.layer = closed_layer + do_animate("closing") sleep(10) update_icon() if(visible && !glass) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 40bc8d7e51d..a814ba1718b 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -1,5 +1,15 @@ /var/const/OPEN = 1 /var/const/CLOSED = 2 + +#define FIREDOOR_MAX_PRESSURE_DIFF 25 // kPa +#define FIREDOOR_MAX_TEMP 50 // °C +#define FIREDOOR_MIN_TEMP 0 + +// Bitflags +#define FIREDOOR_ALERT_HOT 1 +#define FIREDOOR_ALERT_COLD 2 +// Not used #define FIREDOOR_ALERT_LOWPRESS 4 + /obj/machinery/door/firedoor name = "\improper Emergency Shutter" desc = "Emergency air-tight shutter, capable of sealing off breached areas." @@ -8,17 +18,33 @@ req_one_access = list(access_atmospherics, access_engine_equip) opacity = 0 density = 0 + layer = DOOR_OPEN_LAYER - 0.01 + open_layer = DOOR_OPEN_LAYER - 0.01 // Just below doors when open + closed_layer = DOOR_CLOSED_LAYER + 0.01 // Just above doors when closed var/blocked = 0 + var/lockdown = 0 // When the door has detected a problem, it locks. + var/pdiff_alert = 0 + var/pdiff = 0 var/nextstate = null var/net_id var/list/areas_added - var/list/users_to_open - + var/list/users_to_open = new + var/next_process_time = 0 + power_channel = ENVIRON use_power = 1 idle_power_usage = 5 + var/list/tile_info[4] + var/list/dir_alerts[4] // 4 dirs, bitflags + + // MUST be in same order as FIREDOOR_ALERT_* + var/list/ALERT_STATES=list( + "hot", + "cold" + ) + /obj/machinery/door/firedoor/New() . = ..() for(var/obj/machinery/door/firedoor/F in loc) @@ -38,7 +64,6 @@ A.all_doors.Add(src) areas_added += A - /obj/machinery/door/firedoor/Del() for(var/area/A in areas_added) A.all_doors.Remove(src) @@ -48,14 +73,47 @@ /obj/machinery/door/firedoor/examine() set src in view() . = ..() - if( islist(users_to_open) && users_to_open.len) + + if(get_dist(src, usr) > 1 && !isAI(usr)) + return + + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + usr << "WARNING: Current pressure differential is [pdiff]kPa! Opening door may result in injury!" + + usr << "Sensor readings:" + for(var/index = 1; index <= tile_info.len; index++) + var/o = "  " + switch(index) + if(1) + o += "NORTH: " + if(2) + o += "SOUTH: " + if(3) + o += "EAST: " + if(4) + o += "WEST: " + if(tile_info[index] == null) + o += "DATA UNAVAILABLE" + usr << o + continue + var/celsius = convert_k2c(tile_info[index][1]) + var/pressure = tile_info[index][2] + if(dir_alerts[index] & (FIREDOOR_ALERT_HOT|FIREDOOR_ALERT_COLD)) + o += "" + else + o += "" + o += "[celsius]°C " + o += "" + o += "[pressure]kPa" + usr << o + + if(islist(users_to_open) && users_to_open.len) var/users_to_open_string = users_to_open[1] if(users_to_open.len >= 2) for(var/i = 2 to users_to_open.len) users_to_open_string += ", [users_to_open[i]]" usr << "These people have opened \the [src] during an alert: [users_to_open_string]." - /obj/machinery/door/firedoor/Bumped(atom/AM) if(p_open || operating) return @@ -63,7 +121,7 @@ return ..() if(istype(AM, /obj/mecha)) var/obj/mecha/mecha = AM - if (mecha.occupant) + if(mecha.occupant) var/mob/M = mecha.occupant if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent popup message spam. M.last_bumped = world.time @@ -79,12 +137,7 @@ user << "\The [src] is welded solid!" return - if(!allowed(user)) - user << "Access denied." - return - - var/alarmed = 0 - + var/alarmed = lockdown for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor if(A.fire || A.air_doors_activated) alarmed = 1 @@ -100,9 +153,21 @@ user << "\The [src] is not functioning, you'll have to force it open manually." return + if(alarmed && density && lockdown && !allowed(user)) + user << "Access denied. Please wait for authorities to arrive, or for the alert to clear." + return + else + user.visible_message("\The [src] [density ? "open" : "close"]s for \the [user].",\ + "\The [src] [density ? "open" : "close"]s.",\ + "You hear a beep, and a door opening.") + var/needs_to_close = 0 if(density) if(alarmed) + // Accountability! + users_to_open |= user.name + log_admin("[user]([user.ckey]) has opened an alarming emergency shutter.") + message_admins("[user]([user.ckey]) has opened an alarming emergency shutter.") needs_to_close = 1 spawn() open() @@ -128,38 +193,42 @@ var/obj/item/weapon/weldingtool/W = C if(W.remove_fuel(0, user)) blocked = !blocked - user.visible_message("\red \The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ + user.visible_message("\The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ "You [blocked ? "weld" : "unweld"] \the [src] with \the [W].",\ "You hear something being welded.") update_icon() return if(blocked) - user << "\red \The [src] is welded solid!" + user << "\The [src] is welded solid!" return - - if( istype(C, /obj/item/weapon/crowbar) || ( istype(C,/obj/item/weapon/twohanded/fireaxe) && C:wielded == 1 ) ) + if(istype(C, /obj/item/weapon/crowbar) || istype(C,/obj/item/weapon/melee/energy/blade) || istype(C,/obj/item/weapon/twohanded/fireaxe)) if(operating) return - if( blocked && istype(C, /obj/item/weapon/crowbar) ) - user.visible_message("\red \The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ + if(blocked && istype(C, /obj/item/weapon/crowbar)) + user.visible_message("\The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ "You try to pry \the [src] [density ? "open" : "closed"], but it is welded in place!",\ "You hear someone struggle and metal straining.") return - user.visible_message("\red \The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ + if(istype(C,/obj/item/weapon/twohanded/fireaxe)) + var/obj/item/weapon/twohanded/fireaxe/F = C + if(!F.wielded) + return + + user.visible_message("\The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ "You start forcing \the [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain.") if(do_after(user,30)) - if( istype(C, /obj/item/weapon/crowbar) ) - if( stat & (BROKEN|NOPOWER) || !density) - user.visible_message("\red \The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ + if(istype(C, /obj/item/weapon/crowbar)) + if(stat & (BROKEN|NOPOWER) || !density) + user.visible_message("\The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ "You force \the [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain, and a door [density ? "open" : "close"].") else - user.visible_message("\red \The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ + user.visible_message("\The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain and groan, and a door [density ? "opening" : "closing"].") if(density) @@ -170,7 +239,50 @@ close() return +// CHECK PRESSURE +/obj/machinery/door/firedoor/process() + ..() + if(density && next_process_time <= world.time) + next_process_time = world.time + 100 // 10 second delays between process updates + var/changed = 0 + lockdown=0 + // Pressure alerts + pdiff = getOPressureDifferential(src.loc) + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + lockdown = 1 + if(!pdiff_alert) + pdiff_alert = 1 + changed = 1 // update_icon() + else + if(pdiff_alert) + pdiff_alert = 0 + changed = 1 // update_icon() + + tile_info = getCardinalAirInfo(src.loc,list("temperature","pressure")) + var/old_alerts = dir_alerts + for(var/index = 1; index <= 4; index++) + var/list/tileinfo=tile_info[index] + if(tileinfo==null) + continue // Bad data. + var/celsius = convert_k2c(tileinfo[1]) + + var/alerts=0 + + // Temperatures + if(celsius >= FIREDOOR_MAX_TEMP) + alerts |= FIREDOOR_ALERT_HOT + lockdown = 1 + else if(celsius <= FIREDOOR_MIN_TEMP) + alerts |= FIREDOOR_ALERT_COLD + lockdown = 1 + + dir_alerts[index]=alerts + + if(dir_alerts != old_alerts) + changed = 1 + if(changed) + update_icon() /obj/machinery/door/firedoor/proc/latetoggle() if(operating || !nextstate) @@ -178,6 +290,7 @@ switch(nextstate) if(OPEN) nextstate = null + open() if(CLOSED) nextstate = null @@ -189,15 +302,17 @@ return ..() /obj/machinery/door/firedoor/open(var/forced = 0) - if (!forced) - if (stat & (BROKEN|NOPOWER)) + if(!forced) + if(stat & (BROKEN|NOPOWER)) return //needs power to open unless it was forced else use_power(360) + else + log_admin("[usr]([usr.ckey]) has forced open an emergency shutter.") + message_admins("[usr]([usr.ckey]) has forced open an emergency shutter.") latetoggle() return ..() - /obj/machinery/door/firedoor/do_animate(animation) switch(animation) if("opening") @@ -213,6 +328,14 @@ icon_state = "door_closed" if(blocked) overlays += "welded" + if(pdiff_alert) + overlays += "palert" + if(dir_alerts) + for(var/d=1;d<=4;d++) + var/cdir = cardinal[d] + for(var/i=1;i<=ALERT_STATES.len;i++) + if(dir_alerts[d] & (1<<(i-1))) + overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) else icon_state = "door_open" if(blocked) @@ -220,7 +343,6 @@ return - /obj/machinery/door/firedoor/border_only //These are playing merry hell on ZAS. Sorry fellas :( /* diff --git a/code/game/machinery/embedded_controller/airlock_controllers.dm b/code/game/machinery/embedded_controller/airlock_controllers.dm index c7891ef69bf..fb909dee555 100644 --- a/code/game/machinery/embedded_controller/airlock_controllers.dm +++ b/code/game/machinery/embedded_controller/airlock_controllers.dm @@ -8,7 +8,8 @@ var/tag_chamber_sensor var/tag_exterior_sensor var/tag_interior_sensor - var/tag_mech_sensor + var/tag_airlock_mech_sensor + var/tag_shuttle_mech_sensor var/tag_secure = 0 /obj/machinery/embedded_controller/radio/airlock/initialize() diff --git a/code/game/machinery/embedded_controller/airlock_program.dm b/code/game/machinery/embedded_controller/airlock_program.dm index ed93dca9584..8cb3abb9980 100644 --- a/code/game/machinery/embedded_controller/airlock_program.dm +++ b/code/game/machinery/embedded_controller/airlock_program.dm @@ -17,7 +17,8 @@ var/tag_chamber_sensor var/tag_exterior_sensor var/tag_interior_sensor - var/tag_mech_sensor + var/tag_airlock_mech_sensor + var/tag_shuttle_mech_sensor var/state = STATE_IDLE var/target_state = TARGET_NONE @@ -43,7 +44,8 @@ tag_chamber_sensor = controller.tag_chamber_sensor? controller.tag_chamber_sensor : "[id_tag]_sensor" tag_exterior_sensor = controller.tag_exterior_sensor tag_interior_sensor = controller.tag_interior_sensor - tag_mech_sensor = controller.tag_mech_sensor? controller.tag_mech_sensor : "[id_tag]_mech" + tag_airlock_mech_sensor = controller.tag_airlock_mech_sensor? controller.tag_airlock_mech_sensor : "[id_tag]_airlock_mech" + tag_shuttle_mech_sensor = controller.tag_shuttle_mech_sensor? controller.tag_shuttle_mech_sensor : "[id_tag]_shuttle_mech" memory["secure"] = controller.tag_secure spawn(10) @@ -187,7 +189,7 @@ if(memory["purge"]) target_pressure = 0 - + if(memory["purge"]) target_pressure = 0 @@ -202,7 +204,7 @@ //Check for vacuum - this is set after the pumps so the pumps are aiming for 0 if(!memory["target_pressure"]) memory["target_pressure"] = ONE_ATMOSPHERE * 0.05 - + if(STATE_PRESSURIZE) if(memory["chamber_sensor_pressure"] >= memory["target_pressure"] * 0.95) cycleDoors(target_state) @@ -303,11 +305,19 @@ signalDoor(tag_exterior_door, command) signalDoor(tag_interior_door, command) +datum/computer/file/embedded_program/airlock/proc/signal_mech_sensor(var/command, var/sensor) + var/datum/signal/signal = new + signal.data["tag"] = sensor + signal.data["command"] = command + post_signal(signal) + /datum/computer/file/embedded_program/airlock/proc/enable_mech_regulation() - signalDoor(tag_mech_sensor, "enable") + signal_mech_sensor("enable", tag_shuttle_mech_sensor) + signal_mech_sensor("enable", tag_airlock_mech_sensor) /datum/computer/file/embedded_program/airlock/proc/disable_mech_regulation() - signalDoor(tag_mech_sensor, "disable") + signal_mech_sensor("disable", tag_shuttle_mech_sensor) + signal_mech_sensor("disable", tag_airlock_mech_sensor) /*---------------------------------------------------------- toggleDoor() diff --git a/code/game/machinery/embedded_controller/simple_docking_controller.dm b/code/game/machinery/embedded_controller/simple_docking_controller.dm index 83361c3af34..f1001ada553 100644 --- a/code/game/machinery/embedded_controller/simple_docking_controller.dm +++ b/code/game/machinery/embedded_controller/simple_docking_controller.dm @@ -96,12 +96,13 @@ signal.data["command"] = command post_signal(signal) -/datum/computer/file/embedded_program/docking/simple/proc/signal_mech_sensor(var/command) - signal_door(command) +///datum/computer/file/embedded_program/docking/simple/proc/signal_mech_sensor(var/command) +// signal_door(command) +// return /datum/computer/file/embedded_program/docking/simple/proc/open_door() if(memory["door_status"]["state"] == "closed") - signal_mech_sensor("enable") + //signal_mech_sensor("enable") signal_door("secure_open") else if(memory["door_status"]["lock"] == "unlocked") signal_door("lock") @@ -109,7 +110,7 @@ /datum/computer/file/embedded_program/docking/simple/proc/close_door() if(memory["door_status"]["state"] == "open") signal_door("secure_close") - signal_mech_sensor("disable") + //signal_mech_sensor("disable") else if(memory["door_status"]["lock"] == "unlocked") signal_door("lock") diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm index b4ec54d6155..cc2c770a7f1 100644 --- a/code/game/machinery/machinery.dm +++ b/code/game/machinery/machinery.dm @@ -106,7 +106,7 @@ Class Procs: var/active_power_usage = 0 var/power_channel = EQUIP //EQUIP,ENVIRON or LIGHT - var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames. + var/list/component_parts = list() //list of all the parts used to build it, if made from certain kinds of frames. var/uid var/manual = 0 var/global/gl_uid = 1 @@ -166,13 +166,12 @@ Class Procs: use_power = new_use_power //force area power update - //use_power() forces an area power update on the next tick so have to pass the correct power amount for this tick - if (use_power >= 2) - use_power(active_power_usage) - else if (use_power == 1) - use_power(idle_power_usage) - else - use_power(0) + force_power_update() + +/obj/machinery/proc/force_power_update() + var/area/A = get_area(src) + if(A && A.master) + A.master.powerupdate = 1 /obj/machinery/proc/auto_use_power() if(!powered(power_channel)) @@ -183,9 +182,15 @@ Class Procs: use_power(active_power_usage,power_channel, 1) return 1 +/obj/machinery/proc/operable(var/additional_flags = 0) + return !inoperable(additional_flags) + +/obj/machinery/proc/inoperable(var/additional_flags = 0) + return (stat & (NOPOWER|BROKEN|additional_flags)) + /obj/machinery/Topic(href, href_list) ..() - if(stat & (NOPOWER|BROKEN)) + if(inoperable()) return 1 if(usr.restrained() || usr.lying || usr.stat) return 1 @@ -227,7 +232,7 @@ Class Procs: return src.attack_hand(user) /obj/machinery/attack_hand(mob/user as mob) - if(stat & (NOPOWER|BROKEN|MAINT)) + if(inoperable(MAINT)) return 1 if(user.lying || user.stat) return 1 @@ -277,7 +282,7 @@ Class Procs: playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) /obj/machinery/proc/shock(mob/user, prb) - if(stat & (BROKEN|NOPOWER)) + if(inoperable()) return 0 if(!prob(prb)) return 0 diff --git a/code/game/machinery/pipe/construction.dm b/code/game/machinery/pipe/construction.dm index 7d65abb6d78..a1a56bb9768 100644 --- a/code/game/machinery/pipe/construction.dm +++ b/code/game/machinery/pipe/construction.dm @@ -442,6 +442,7 @@ Buildable meters var/pipefailtext = "\red There's nothing to connect this pipe section to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + //TODO: Move all of this stuff into the various pipe constructors. switch(pipe_type) if(PIPE_SIMPLE_STRAIGHT, PIPE_SIMPLE_BENT) var/obj/machinery/atmospherics/pipe/simple/P = new( src.loc ) @@ -522,7 +523,7 @@ Buildable meters if(PIPE_HE_STRAIGHT, PIPE_HE_BENT) var/obj/machinery/atmospherics/pipe/simple/heat_exchanging/P = new ( src.loc ) P.dir = src.dir - P.initialize_directions = 0 + P.initialize_directions = pipe_dir //this var it's used to know if the pipe is bent or not P.initialize_directions_he = pipe_dir //var/turf/T = P.loc //P.level = T.intact ? 2 : 1 @@ -563,7 +564,7 @@ Buildable meters M.level = T.intact ? 2 : 1 M.initialize() if (!M) - usr << "There's nothing to connect this manifold to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + usr << pipefailtext return 1 M.build_network() if (M.node1) @@ -632,7 +633,7 @@ Buildable meters M.level = T.intact ? 2 : 1 M.initialize() if (!M) - usr << "There's nothing to connect this manifold to!" //(with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)" + usr << pipefailtext return 1 M.build_network() if (M.node1) diff --git a/code/game/machinery/spaceheater.dm b/code/game/machinery/spaceheater.dm index ffa69f8b412..f6a1455e78c 100644 --- a/code/game/machinery/spaceheater.dm +++ b/code/game/machinery/spaceheater.dm @@ -98,7 +98,7 @@ dat += "-" - dat += " [set_temperature]°C " + dat += " [set_temperature]K ([set_temperature-T0C]°C)" dat += "+
" user.set_machine(src) @@ -176,7 +176,7 @@ heat_transfer = min(heat_transfer, cop * heating_power) //limit heat transfer by available power heat_transfer = removed.add_thermal_energy(-heat_transfer) //get the actual heat transfer - + var/power_used = abs(heat_transfer)/cop cell.use(power_used*CELLRATE) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index c21616811e4..3f0b7448895 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -622,35 +622,35 @@ model_text = "Engineering" req_access = list(access_construction) departments = list("Engineering","Atmos") - species = list("Human","Tajaran") //Add Unathi when sprites exist for their suits. + species = list("Human","Tajaran","Skrell","Unathi") //Add Unathi when sprites exist for their suits. /obj/machinery/suit_cycler/mining name = "Mining suit cycler" model_text = "Mining" req_access = list(access_mining) departments = list("Mining") - species = list("Human","Tajaran") + species = list("Human","Tajaran","Skrell","Unathi") /obj/machinery/suit_cycler/security name = "Security suit cycler" model_text = "Security" req_access = list(access_security) departments = list("Security") - species = list("Human","Tajaran") + species = list("Human","Tajaran","Skrell","Unathi") /obj/machinery/suit_cycler/medical name = "Medical suit cycler" model_text = "Medical" req_access = list(access_medical) departments = list("Medical") - species = list("Human","Tajaran") + species = list("Human","Tajaran","Skrell","Unathi") /obj/machinery/suit_cycler/syndicate name = "Nonstandard suit cycler" model_text = "Nonstandard" req_access = list(access_syndicate) departments = list("Mercenary") - species = list("Human","Tajaran","Unathi","Skrell") + species = list("Human","Tajaran","Skrell","Unathi") can_repair = 1 /obj/machinery/suit_cycler/attack_ai(mob/user as mob) diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index 43592ae2cb9..78ee794b532 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -1298,9 +1298,9 @@ Powercell charge: [isnull(cell_charge)?"No powercell installed":"[cell.percent()]%"]
Air source: [use_internal_tank?"Internal Airtank":"Environment"]
Airtank pressure: [tank_pressure]kPa
- Airtank temperature: [tank_temperature]°K|[tank_temperature - T0C]°C
+ Airtank temperature: [tank_temperature]K|[tank_temperature - T0C]°C
Cabin pressure: [cabin_pressure>WARNING_HIGH_PRESSURE ? "[cabin_pressure]": cabin_pressure]kPa
- Cabin temperature: [return_temperature()]°K|[return_temperature() - T0C]°C
+ Cabin temperature: [return_temperature()]K|[return_temperature() - T0C]°C
Lights: [lights?"on":"off"]
[src.dna?"DNA-locked:
[src.dna] \[Reset\]
":null] "} diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 5a78b702d04..6e1cc86633c 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -49,18 +49,11 @@ var/list/sprite_sheets = null var/icon_override = null //Used to override hardcoded clothing dmis in human clothing proc. - /* Species-specific sprite sheets for object and inhand sprites + /* Species-specific sprite sheets for inventory sprites Works similarly to worn sprite_sheets, except the alternate sprites are used when the clothing/refit_for_species() proc is called. */ var/list/sprite_sheets_obj = null - //Inhand is not as big a deal as the object sprites, so I'm not sure if these are worth the extra vars. - //Maybe in the future: - //var/list/sprite_sheets_inhand_l = null - //var/list/sprite_sheets_inhand_r = null - //var/icon_l_hand = 'icons/mob/items_lefthand.dmi' - //var/icon_r_hand = 'icons/mob/items_righthand.dmi' - /obj/item/device icon = 'icons/obj/device.dmi' diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index c2aca6807ea..ce8056d46a7 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -30,6 +30,11 @@ R.uneq_all() R.hands.icon_state = "nomod" R.icon_state = "robot" + //world << R.custom_sprite + if(R.custom_sprite == 1) + //world << R.icon_state + icon = 'icons/mob/custom-synthetic.dmi' + R.icon_state = "[R.ckey]-Standard" del(R.module) R.module = null R.camera.network.Remove(list("Engineering","Medical","MINE")) diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm index 88a0decc2b3..c1126464f56 100644 --- a/code/game/objects/items/stacks/sheets/glass.dm +++ b/code/game/objects/items/stacks/sheets/glass.dm @@ -251,7 +251,7 @@ singular_name = "phoron glass sheet" icon_state = "sheet-phoronglass" matter = list("glass" = 7500) - origin_tech = "materials=3;phoron=2" + origin_tech = "materials=3;phorontech=2" created_window = /obj/structure/window/phoronbasic /obj/item/stack/sheet/glass/phoronglass/attack_self(mob/user as mob) @@ -284,7 +284,7 @@ icon_state = "sheet-phoronrglass" matter = list("glass" = 7500,"metal" = 1875) - origin_tech = "materials=4;phoron=2" + origin_tech = "materials=4;phorontech=2" created_window = /obj/structure/window/phoronreinforced /obj/item/stack/sheet/glass/phoronrglass/attack_self(mob/user as mob) diff --git a/code/game/objects/items/weapons/RSF.dm b/code/game/objects/items/weapons/RSF.dm index 9d86411b1a5..d6a707237c3 100644 --- a/code/game/objects/items/weapons/RSF.dm +++ b/code/game/objects/items/weapons/RSF.dm @@ -4,7 +4,6 @@ RSF */ -//TODO: WHAT THE FUCK, FIX THIS GARBAGE. /obj/item/weapon/rsf name = "\improper Rapid-Service-Fabricator" desc = "A device used to rapidly deploy service items." @@ -13,26 +12,29 @@ RSF opacity = 0 density = 0 anchored = 0.0 - var/stored_matter = 0 + var/stored_matter = 30 var/mode = 1 flags = TABLEPASS w_class = 3.0 -/obj/item/weapon/rsf/New() - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return +/obj/item/weapon/rsf/examine() + set src in view(1) + ..() + usr << "It currently holds [stored_matter]/30 fabrication-units." /obj/item/weapon/rsf/attackby(obj/item/weapon/W as obj, mob/user as mob) ..() if (istype(W, /obj/item/weapon/rcd_ammo)) + if ((stored_matter + 10) > 30) - user << "The RSF cant hold any more matter." + user << "The RSF can't hold any more matter." return + del(W) + stored_matter += 10 playsound(src.loc, 'sound/machines/click.ogg', 10, 1) user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." return /obj/item/weapon/rsf/attack_self(mob/user as mob) @@ -64,174 +66,51 @@ RSF // Change mode /obj/item/weapon/rsf/afterattack(atom/A, mob/user as mob, proximity) + if(!proximity) return - if (!(istype(A, /obj/structure/table) || istype(A, /turf/simulated/floor))) + + if(istype(user,/mob/living/silicon/robot)) + var/mob/living/silicon/robot/R = user + if(R.stat || !R.cell || R.cell.charge <= 0) + return + else + if(stored_matter <= 0) + return + + if(!istype(A, /obj/structure/table) && !istype(A, /turf/simulated/floor)) return - if (istype(A, /obj/structure/table) && mode == 1) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Dosh..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/spacecash/c10( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 200 //once money becomes useful, I guess changing this to a high ammount, like 500 units a kick, till then, enjoy dosh! - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return + playsound(src.loc, 'sound/machines/click.ogg', 10, 1) + var/used_energy = 0 + var/obj/product - else if (istype(A, /turf/simulated/floor) && mode == 1) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Dosh..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/spacecash/c10( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 200 //once money becomes useful, I guess changing this to a high ammount, like 500 units a kick, till then, enjoy dosh! - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return + switch(mode) + if(1) + product = new /obj/item/weapon/spacecash/c10() + used_energy = 200 + if(2) + product = new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass() + used_energy = 50 + if(3) + product = new /obj/item/weapon/paper() + used_energy = 10 + if(4) + product = new /obj/item/weapon/pen() + used_energy = 50 + if(5) + product = new /obj/item/weapon/storage/pill_bottle/dice() + used_energy = 200 + if(6) + product = new /obj/item/clothing/mask/cigarette() + used_energy = 10 - else if (istype(A, /obj/structure/table) && mode == 2) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Drinking Glass..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 50 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return + user << "Dispensing [product ? product : "product"]..." + product.loc = get_turf(A) - else if (istype(A, /turf/simulated/floor) && mode == 2) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Drinking Glass..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/reagent_containers/food/drinks/drinkingglass( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 50 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /obj/structure/table) && mode == 3) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Paper Sheet..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/paper( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 10 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /turf/simulated/floor) && mode == 3) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Paper Sheet..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/paper( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 10 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /obj/structure/table) && mode == 4) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Pen..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/pen( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 50 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /turf/simulated/floor) && mode == 4) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Pen..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/pen( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 50 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /obj/structure/table) && mode == 5) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Dice Pack..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/storage/pill_bottle/dice( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 200 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /turf/simulated/floor) && mode == 5) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Dice Pack..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/weapon/storage/pill_bottle/dice( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 200 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /obj/structure/table) && mode == 6) - if (istype(A, /obj/structure/table) && stored_matter >= 1) - user << "Dispensing Cigarette..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/clothing/mask/cigarette( A.loc ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 10 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return - - else if (istype(A, /turf/simulated/floor) && mode == 6) - if (istype(A, /turf/simulated/floor) && stored_matter >= 1) - user << "Dispensing Cigarette..." - playsound(src.loc, 'sound/machines/click.ogg', 10, 1) - new /obj/item/clothing/mask/cigarette( A ) - if (isrobot(user)) - var/mob/living/silicon/robot/engy = user - engy.cell.charge -= 10 - else - stored_matter-- - user << "The RSF now holds [stored_matter]/30 fabrication-units." - desc = "A RSF. It currently holds [stored_matter]/30 fabrication-units." - return \ No newline at end of file + if(isrobot(user)) + var/mob/living/silicon/robot/R = user + if(R.cell) + R.cell.use(used_energy) + else + stored_matter-- + user << "The RSF now holds [stored_matter]/30 fabrication-units." \ No newline at end of file diff --git a/code/game/objects/items/weapons/power_cells.dm b/code/game/objects/items/weapons/power_cells.dm index 5636681f5e8..ba75d32990a 100644 --- a/code/game/objects/items/weapons/power_cells.dm +++ b/code/game/objects/items/weapons/power_cells.dm @@ -28,7 +28,7 @@ desc = "You can't top the plasma top." //TOTALLY TRADEMARK INFRINGEMENT origin_tech = "powerstorage=0" maxcharge = 500 - matter = list("glass" = 40) + matter = list("metal" = 700, "glass" = 40) /obj/item/weapon/cell/crap/empty/New() ..() @@ -38,18 +38,24 @@ name = "security borg rechargable D battery" origin_tech = "powerstorage=0" maxcharge = 600 //600 max charge / 100 charge per shot = six shots - matter = list("glass" = 40) + matter = list("metal" = 700, "glass" = 40) /obj/item/weapon/cell/secborg/empty/New() ..() charge = 0 +/obj/item/weapon/cell/apc + name = "heavy-duty power cell" + origin_tech = "powerstorage=1" + maxcharge = 5000 + matter = list("metal" = 700, "glass" = 50) + /obj/item/weapon/cell/high name = "high-capacity power cell" origin_tech = "powerstorage=2" icon_state = "hcell" maxcharge = 10000 - matter = list("glass" = 60) + matter = list("metal" = 700, "glass" = 60) /obj/item/weapon/cell/high/empty/New() ..() @@ -60,7 +66,7 @@ origin_tech = "powerstorage=5" icon_state = "scell" maxcharge = 20000 - matter = list("glass" = 70) + matter = list("metal" = 700, "glass" = 70) construction_cost = list("metal"=750,"glass"=100) /obj/item/weapon/cell/super/empty/New() @@ -72,7 +78,7 @@ origin_tech = "powerstorage=6" icon_state = "hpcell" maxcharge = 30000 - matter = list("glass" = 80) + matter = list("metal" = 700, "glass" = 80) construction_cost = list("metal"=500,"glass"=150,"gold"=200,"silver"=200) /obj/item/weapon/cell/hyper/empty/New() @@ -84,7 +90,7 @@ icon_state = "icell" origin_tech = null maxcharge = 30000 - matter = list("glass"= 80) + matter = list("metal" = 700, "glass" = 80) use() return 1 diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index af50cd10882..f4400132e80 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -410,7 +410,7 @@ max_fuel = 40 w_class = 3.0 matter = list("metal" = 70, "glass" = 120) - origin_tech = "engineering=4;phoron=3" + origin_tech = "engineering=4;phorontech=3" var/last_gen = 0 diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index 8252934c1e0..1fd6bdff5fc 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -115,7 +115,6 @@ new /obj/item/clothing/glasses/sunglasses/sechud(src) new /obj/item/taperoll/police(src) new /obj/item/weapon/shield/riot(src) - new /obj/item/weapon/storage/lockbox/loyalty(src) new /obj/item/weapon/storage/box/flashbangs(src) new /obj/item/weapon/storage/belt/security(src) new /obj/item/device/flash(src) diff --git a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm index 31a1681eace..f7eafdda9db 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm @@ -153,17 +153,23 @@ if(propelled) var/mob/living/occupant = buckled_mob unbuckle() + + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone, blocked) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone, blocked) occupant.visible_message("[occupant] crashed into \the [A]!") /obj/structure/stool/bed/chair/office/light diff --git a/code/game/objects/structures/stool_bed_chair_nest/stools.dm b/code/game/objects/structures/stool_bed_chair_nest/stools.dm index a068af11938..ba27d070d71 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/stools.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/stools.dm @@ -54,12 +54,27 @@ w_class = 5.0 var/obj/structure/stool/origin = null +/obj/item/weapon/stool/proc/deploy(var/mob/user) + + if(!origin) + del src + + origin.loc = get_turf(src) + + if(user) + user.u_equip(src) + user.visible_message("\blue [user] puts [src] down.", "\blue You put [src] down.") + + del src + +/obj/item/weapon/stool/dropped(mob/user as mob) + ..() + if(istype(loc,/turf/)) + deploy(user) + /obj/item/weapon/stool/attack_self(mob/user as mob) ..() - origin.loc = get_turf(src) - user.u_equip(src) - user.visible_message("\blue [user] puts [src] down.", "\blue You put [src] down.") - del src + deploy(user) /obj/item/weapon/stool/attack(mob/M as mob, mob/user as mob) if (prob(5) && istype(M,/mob/living)) diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm index 9c00ee38963..8e801de6e2d 100644 --- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm +++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm @@ -147,16 +147,22 @@ else if (propelled) occupant.throw_at(A, 3, propelled) - occupant.apply_effect(6, STUN, 0) - occupant.apply_effect(6, WEAKEN, 0) - occupant.apply_effect(6, STUTTER, 0) + var/def_zone = ran_zone() + var/blocked = occupant.run_armor_check(def_zone, "melee") + occupant.throw_at(A, 3, propelled) + occupant.apply_effect(6, STUN, blocked) + occupant.apply_effect(6, WEAKEN, blocked) + occupant.apply_effect(6, STUTTER, blocked) + occupant.apply_damage(10, BRUTE, def_zone) playsound(src.loc, 'sound/weapons/punch1.ogg', 50, 1, -1) if(istype(A, /mob/living)) var/mob/living/victim = A - victim.apply_effect(6, STUN, 0) - victim.apply_effect(6, WEAKEN, 0) - victim.apply_effect(6, STUTTER, 0) - victim.take_organ_damage(10) + def_zone = ran_zone() + blocked = victim.run_armor_check(def_zone, "melee") + victim.apply_effect(6, STUN, blocked) + victim.apply_effect(6, WEAKEN, blocked) + victim.apply_effect(6, STUTTER, blocked) + victim.apply_damage(10, BRUTE, def_zone) if(pulling) occupant.visible_message("[pulling] has thrusted \the [name] into \the [A], throwing \the [occupant] out of it!") diff --git a/code/game/turfs/simulated/floor_types.dm b/code/game/turfs/simulated/floor_types.dm index 98e0f660350..adf6fe4bcea 100644 --- a/code/game/turfs/simulated/floor_types.dm +++ b/code/game/turfs/simulated/floor_types.dm @@ -55,6 +55,9 @@ heat_capacity = 325000 intact = 0 +/turf/simulated/floor/engine/nitrogen + oxygen = 0 + /turf/simulated/floor/engine/attackby(obj/item/weapon/C as obj, mob/user as mob) if(!C) return diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 6b1e1d2b018..1493751ab10 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1492,6 +1492,7 @@ else if(href_list["CentcommFaxReply"]) var/mob/living/carbon/human/H = locate(href_list["CentcommFaxReply"]) + var/obj/machinery/faxmachine/fax = locate(href_list["originfax"]) var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from Centcomm", "") as message|null if(!input) return @@ -1499,32 +1500,76 @@ var/customname = input(src.owner, "Pick a title for the report", "Title") as text|null for(var/obj/machinery/faxmachine/F in machines) - if(! (F.stat & (BROKEN|NOPOWER) ) ) + if(F == fax) + if(! (F.stat & (BROKEN|NOPOWER) ) ) - // animate! it's alive! - flick("faxreceive", F) + // animate! it's alive! + flick("faxreceive", F) - // give the sprite some time to flick - spawn(20) - var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( F.loc ) - P.name = "[command_name()]- [customname]" - P.info = input - P.update_icon() + // give the sprite some time to flick + spawn(20) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( F.loc ) + P.name = "[command_name()]- [customname]" + P.info = input + P.update_icon() - playsound(F.loc, "sound/items/polaroid1.ogg", 50, 1) + playsound(F.loc, "sound/items/polaroid1.ogg", 50, 1) - // Stamps - var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') - stampoverlay.icon_state = "paper_stamp-cent" - if(!P.stamped) - P.stamped = new - P.stamped += /obj/item/weapon/stamp - P.overlays += stampoverlay - P.stamps += "
This paper has been stamped by the Central Command Quantum Relay." + // Stamps + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cent" + if(!P.stamped) + P.stamped = new + P.stamped += /obj/item/weapon/stamp + P.overlays += stampoverlay + P.stamps += "
This paper has been stamped by the Central Command Quantum Relay." + + src.owner << "Message reply to transmitted successfully." + log_admin("[key_name(src.owner)] replied to a fax message from [key_name(H)]: [input]") + message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + return + src.owner << "/red Unable to locate fax!" + + else if(href_list["SolGovFaxReply"]) + var/mob/living/carbon/human/H = locate(href_list["SolGovFaxReply"]) + var/obj/machinery/faxmachine/fax = locate(href_list["originfax"]) + + var/input = input(src.owner, "Please enter a message to reply to [key_name(H)] via secure connection. NOTE: BBCode does not work, but HTML tags do! Use
for line breaks.", "Outgoing message from Centcomm", "") as message|null + if(!input) return + + var/customname = input(src.owner, "Pick a title for the report", "Title") as text|null + + for(var/obj/machinery/faxmachine/F in machines) + if(F == fax) + if(! (F.stat & (BROKEN|NOPOWER) ) ) + + // animate! it's alive! + flick("faxreceive", F) + + // give the sprite some time to flick + spawn(20) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( F.loc ) + P.name = "Sol Government- [customname]" + P.info = input + P.update_icon() + + playsound(F.loc, "sound/items/polaroid1.ogg", 50, 1) + + // Stamps + var/image/stampoverlay = image('icons/obj/bureaucracy.dmi') + stampoverlay.icon_state = "paper_stamp-cap" + if(!P.stamped) + P.stamped = new + P.stamped += /obj/item/weapon/stamp + P.overlays += stampoverlay + P.stamps += "
This paper has been stamped and encrypted by the Sol Government Quantum Relay." + + src.owner << "Message reply to transmitted successfully." + log_admin("[key_name(src.owner)] replied to a fax message from [key_name(H)]: [input]") + message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) + return + src.owner << "/red Unable to locate fax!" - src.owner << "Message reply to transmitted successfully." - log_admin("[key_name(src.owner)] replied to a fax message from [key_name(H)]: [input]") - message_admins("[key_name_admin(src.owner)] replied to a fax message from [key_name_admin(H)]", 1) else if(href_list["jumpto"]) diff --git a/code/modules/admin/verbs/mapping.dm b/code/modules/admin/verbs/mapping.dm index 6e2bd20e322..fa5fba4ba05 100644 --- a/code/modules/admin/verbs/mapping.dm +++ b/code/modules/admin/verbs/mapping.dm @@ -125,7 +125,7 @@ var/intercom_range_display_status = 0 feedback_add_details("admin_verb","mIRD") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc! var/list/debug_verbs = list ( - /client/proc/do_not_use_these + /client/proc/do_not_use_these ,/client/proc/camera_view ,/client/proc/sec_camera_report ,/client/proc/intercom_view @@ -158,9 +158,13 @@ var/list/debug_verbs = list ( ,/client/proc/ZoneTick ,/client/proc/rebootAirMaster ,/client/proc/hide_debug_verbs - ,/client/proc/testZAScolors - ,/client/proc/testZAScolors_remove - ,/client/proc/setup_supermatter_engine + ,/client/proc/testZAScolors + ,/client/proc/testZAScolors_remove + ,/client/proc/setup_supermatter_engine + ,/client/proc/view_power_update_stats_area + ,/client/proc/view_power_update_stats_machines + ,/client/proc/toggle_power_update_profiling + ,/client/proc/atmos_toggle_debug ) diff --git a/code/modules/admin/verbs/modifyvariables.dm b/code/modules/admin/verbs/modifyvariables.dm index e5b1555b0d9..b89b4a67eb5 100644 --- a/code/modules/admin/verbs/modifyvariables.dm +++ b/code/modules/admin/verbs/modifyvariables.dm @@ -215,7 +215,7 @@ var/list/forbidden_varedit_object_types = list( var/list/choices = list("text","num","type","reference","mob reference", "icon","file","list","edit referenced object","restore to default") if(src.holder && src.holder.marked_datum) choices += "marked datum ([holder.marked_datum.type])" - if(!isnull(default) && default != "num" && !isnull(L[variable])) + if(!isnull(default) && default != "num") choices += "edit associated variable" choices += "DELETE FROM LIST" diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm old mode 100644 new mode 100755 index 39213f436da..193d63f96c5 --- a/code/modules/client/preferences.dm +++ b/code/modules/client/preferences.dm @@ -1347,7 +1347,8 @@ datum/preferences organ_data[limb] = "cyborg" if(second_limb) organ_data[second_limb] = "cyborg" - + if(third_limb && organ_data[third_limb] == "amputated") + organ_data[third_limb] = null if("organs") var/organ_name = input(user, "Which internal function do you want to change?") as null|anything in list("Heart", "Eyes") if(!organ_name) return diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index fa519d6f0be..9bd9e779c3c 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -1,6 +1,14 @@ /obj/item/clothing name = "clothing" var/list/species_restricted = null //Only these species can wear this kit. + + /* + Sprites used when the clothing item is refit. This is done by setting icon_override. + For best results, if this is set then sprite_sheets should be null and vice versa, but that is by no means necessary. + Ideally, sprite_sheets_refit should be used for "hard" clothing items that can't change shape very well to fit the wearer (e.g. helmets, hardsuits), + while sprite_sheets should be used for "flexible" clothing items that do not need to be refitted (e.g. vox wearing jumpsuits). + */ + var/list/sprite_sheets_refit = null //BS12: Species-restricted clothing check. /obj/item/clothing/mob_can_equip(M as mob, slot) @@ -41,6 +49,11 @@ species_restricted = list(target_species) //Set icon + if (sprite_sheets_refit && (target_species in sprite_sheets_refit)) + icon_override = sprite_sheets_refit[target_species] + else + icon_override = initial(icon_override) + if (sprite_sheets_obj && (target_species in sprite_sheets_obj)) icon = sprite_sheets_obj[target_species] else @@ -57,12 +70,16 @@ species_restricted = list(target_species) //Set icon + if (sprite_sheets_refit && (target_species in sprite_sheets_refit)) + icon_override = sprite_sheets_refit[target_species] + else + icon_override = initial(icon_override) + if (sprite_sheets_obj && (target_species in sprite_sheets_obj)) icon = sprite_sheets_obj[target_species] else icon = initial(icon) - //Ears: headsets, earmuffs and tiny objects /obj/item/clothing/ears name = "ears" @@ -182,6 +199,24 @@ BLIND // can't see anything /obj/item/clothing/gloves/proc/Touch(var/atom/A, var/proximity) return 0 // return 1 to cancel attack_hand() +/obj/item/clothing/gloves/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) + if (clipped) + user << "The [src] have already been clipped!" + update_icon() + return + + playsound(src.loc, 'sound/items/Wirecutter.ogg', 100, 1) + user.visible_message("\red [user] cuts the fingertips off of the [src].","\red You cut the fingertips off of the [src].") + + clipped = 1 + name = "mangled [name]" + desc = "[desc]
They have had the fingertips cut off of them." + if("exclude" in species_restricted) + species_restricted -= "Unathi" + species_restricted -= "Tajaran" + return + //Head /obj/item/clothing/head name = "head" diff --git a/code/modules/clothing/gloves/boxing.dm b/code/modules/clothing/gloves/boxing.dm index 0865c31e942..02a34b41928 100644 --- a/code/modules/clothing/gloves/boxing.dm +++ b/code/modules/clothing/gloves/boxing.dm @@ -4,6 +4,12 @@ icon_state = "boxing" item_state = "boxing" +/obj/item/clothing/gloves/boxing/attackby(obj/item/weapon/W, mob/user) + if(istype(W, /obj/item/weapon/wirecutters) || istype(W, /obj/item/weapon/scalpel)) + user << "That won't work." //Nope + return + ..() + /obj/item/clothing/gloves/boxing/green icon_state = "boxinggreen" item_state = "boxinggreen" diff --git a/code/modules/clothing/shoes/colour.dm b/code/modules/clothing/shoes/colour.dm index 55d0591a375..e20bea4cc73 100644 --- a/code/modules/clothing/shoes/colour.dm +++ b/code/modules/clothing/shoes/colour.dm @@ -86,29 +86,32 @@ item_color = "orange" var/obj/item/weapon/handcuffs/chained = null -/obj/item/clothing/shoes/orange/proc/attach_cuffs(var/obj/item/weapon/handcuffs/cuffs) +/obj/item/clothing/shoes/orange/proc/attach_cuffs(var/obj/item/weapon/handcuffs/cuffs, mob/user as mob) if (src.chained) return + user.drop_item() cuffs.loc = src src.chained = cuffs src.slowdown = 15 src.icon_state = "orange1" -/obj/item/clothing/shoes/orange/proc/remove_cuffs() +/obj/item/clothing/shoes/orange/proc/remove_cuffs(mob/user as mob) if (!src.chained) return - src.chained.loc = get_turf(src) + user.put_in_hands(src.chained) + src.chained.add_fingerprint(user) + src.slowdown = initial(slowdown) src.icon_state = "orange" src.chained = null /obj/item/clothing/shoes/orange/attack_self(mob/user as mob) ..() - remove_cuffs() + remove_cuffs(user) /obj/item/clothing/shoes/orange/attackby(H as obj, mob/user as mob) ..() if (istype(H, /obj/item/weapon/handcuffs)) - attach_cuffs(H) + attach_cuffs(H, user) diff --git a/code/modules/clothing/spacesuits/ert.dm b/code/modules/clothing/spacesuits/ert.dm index 91bfd9dd059..33d8b19af61 100644 --- a/code/modules/clothing/spacesuits/ert.dm +++ b/code/modules/clothing/spacesuits/ert.dm @@ -30,7 +30,7 @@ w_class = 3 allowed = list(/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs,/obj/item/weapon/tank/emergency_oxygen) slowdown = 1 - armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 60) + armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 100, rad = 100) allowed = list(/obj/item/device/flashlight, /obj/item/weapon/tank, /obj/item/device/t_scanner, /obj/item/weapon/rcd, /obj/item/weapon/crowbar, \ /obj/item/weapon/screwdriver, /obj/item/weapon/weldingtool, /obj/item/weapon/wirecutters, /obj/item/weapon/wrench, /obj/item/device/multitool, \ /obj/item/device/radio, /obj/item/device/analyzer, /obj/item/weapon/gun/energy/laser, /obj/item/weapon/gun/energy/pulse_rifle, \ diff --git a/code/modules/clothing/spacesuits/rig.dm b/code/modules/clothing/spacesuits/rig.dm index 6a0ecc49331..a8017a95da0 100644 --- a/code/modules/clothing/spacesuits/rig.dm +++ b/code/modules/clothing/spacesuits/rig.dm @@ -15,13 +15,15 @@ //Species-specific stuff. species_restricted = list("exclude","Unathi","Tajaran","Skrell","Diona","Vox") - sprite_sheets = list( + sprite_sheets_refit = list( "Unathi" = 'icons/mob/species/unathi/helmet.dmi', "Tajaran" = 'icons/mob/species/tajaran/helmet.dmi', - "Skrell" = 'icons/mob/species/skrell/helmet.dmi' + "Skrell" = 'icons/mob/species/skrell/helmet.dmi', ) sprite_sheets_obj = list( + "Unathi" = 'icons/obj/clothing/species/unathi/hats.dmi', "Tajaran" = 'icons/obj/clothing/species/tajaran/hats.dmi', + "Skrell" = 'icons/obj/clothing/species/skrell/hats.dmi', ) attack_self(mob/user) @@ -63,13 +65,15 @@ max_heat_protection_temperature = SPACE_SUIT_MAX_HEAT_PROTECTION_TEMPERATURE species_restricted = list("exclude","Unathi","Tajaran","Diona","Vox") - sprite_sheets = list( + sprite_sheets_refit = list( "Unathi" = 'icons/mob/species/unathi/suit.dmi', "Tajaran" = 'icons/mob/species/tajaran/suit.dmi', - "Skrell" = 'icons/mob/species/skrell/suit.dmi' + "Skrell" = 'icons/mob/species/skrell/suit.dmi', ) sprite_sheets_obj = list( + "Unathi" = 'icons/obj/clothing/species/unathi/suits.dmi', "Tajaran" = 'icons/obj/clothing/species/tajaran/suits.dmi', + "Skrell" = 'icons/obj/clothing/species/skrell/suits.dmi', ) //Breach thresholds, should ideally be inherited by most (if not all) hardsuits. @@ -322,14 +326,16 @@ icon_state = "rig0-white" item_state = "ce_helm" item_color = "white" - sprite_sheets = null + sprite_sheets_refit = null + sprite_sheets_obj = null /obj/item/clothing/suit/space/rig/engineering/chief icon_state = "rig-white" name = "advanced hardsuit" desc = "An advanced suit that protects against hazardous, low pressure environments. Shines with a high polish." item_state = "ce_hardsuit" - sprite_sheets = null + sprite_sheets_refit = null + sprite_sheets_obj = null //Mining rig /obj/item/clothing/head/helmet/space/rig/mining @@ -359,11 +365,6 @@ siemens_coefficient = 0.6 var/obj/machinery/camera/camera species_restricted = list("exclude","Unathi","Tajaran","Skrell","Vox") - sprite_sheets_obj = list( - "Tajaran" = 'icons/obj/clothing/species/tajaran/hats.dmi', - "Unathi" = 'icons/obj/clothing/species/unathi/hats.dmi', - "Skrell" = 'icons/obj/clothing/species/skrell/hats.dmi', - ) /obj/item/clothing/head/helmet/space/rig/syndi/attack_self(mob/user) @@ -392,11 +393,6 @@ allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank,/obj/item/device/suit_cooling_unit,/obj/item/weapon/gun,/obj/item/ammo_magazine,/obj/item/ammo_casing,/obj/item/weapon/melee/baton,/obj/item/weapon/melee/energy/sword,/obj/item/weapon/handcuffs) siemens_coefficient = 0.6 species_restricted = list("exclude","Unathi","Tajaran","Skrell","Vox") - sprite_sheets_obj = list( - "Tajaran" = 'icons/obj/clothing/species/tajaran/suits.dmi', - "Unathi" = 'icons/obj/clothing/species/unathi/suits.dmi', - "Skrell" = 'icons/obj/clothing/species/skrell/suits.dmi', - ) //Wizard Rig @@ -409,7 +405,7 @@ unacidable = 1 //No longer shall our kind be foiled by lone chemists with spray bottles! armor = list(melee = 40, bullet = 20, laser = 20,energy = 20, bomb = 35, bio = 100, rad = 60) siemens_coefficient = 0.7 - sprite_sheets = null + sprite_sheets_refit = null sprite_sheets_obj = null /obj/item/clothing/suit/space/rig/wizard @@ -422,7 +418,7 @@ unacidable = 1 armor = list(melee = 40, bullet = 20, laser = 20,energy = 20, bomb = 35, bio = 100, rad = 60) siemens_coefficient = 0.7 - sprite_sheets = null + sprite_sheets_refit = null sprite_sheets_obj = null //Medical Rig diff --git a/code/modules/clothing/suits/utility.dm b/code/modules/clothing/suits/utility.dm index 91153fee0fa..e75b3126902 100644 --- a/code/modules/clothing/suits/utility.dm +++ b/code/modules/clothing/suits/utility.dm @@ -102,7 +102,7 @@ w_class = 4//bulky item gas_transfer_coefficient = 0.90 permeability_coefficient = 0.50 - body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS + body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS|FEET allowed = list(/obj/item/device/flashlight,/obj/item/weapon/tank/emergency_oxygen,/obj/item/clothing/head/radiation,/obj/item/clothing/mask/gas) slowdown = 1.5 armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 60, rad = 100) diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm index 7148a5afed6..b5f6dfa2330 100644 --- a/code/modules/detectivework/evidence.dm +++ b/code/modules/detectivework/evidence.dm @@ -7,14 +7,39 @@ icon_state = "evidenceobj" item_state = "" w_class = 2 + var/obj/item/stored_item = null -/obj/item/weapon/evidencebag/afterattack(obj/item/I, mob/user as mob, proximity) - if(!proximity) return - if(!in_range(I, user)) +/obj/item/weapon/evidencebag/MouseDrop(var/obj/item/I as obj) + if (!ishuman(usr)) return - if(!istype(I) || I.anchored == 1) - return ..() + var/mob/living/carbon/human/user = usr + + if (!(user.l_hand == src || user.r_hand == src)) + return //bag must be in your hands to use + + if (isturf(I.loc)) + if (!user.Adjacent(I)) + return + else + //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up. + if(istype(I.loc,/obj/item/weapon/storage)) //in a container. + var/sdepth = I.storage_depth(user) + if (sdepth == -1 || sdepth > 1) + return //too deeply nested to access + + var/obj/item/weapon/storage/U = I.loc + user.client.screen -= I + U.contents.Remove(I) + else if(user.l_hand == I) //in a hand + user.drop_l_hand() + else if(user.r_hand == I) //in a hand + user.drop_r_hand() + else + return + + if(!istype(I) || I.anchored) + return if(istype(I, /obj/item/weapon/evidencebag)) user << "You find putting an evidence bag in another evidence bag to be slightly absurd." @@ -26,19 +51,7 @@ if(contents.len) user << "[src] already has something inside it." - return ..() - - if(!isturf(I.loc)) //If it isn't on the floor. Do some checks to see if it's in our hands or a box. Otherwise give up. - if(istype(I.loc,/obj/item/weapon/storage)) //in a container. - var/obj/item/weapon/storage/U = I.loc - user.client.screen -= I - U.contents.Remove(I) - else if(user.l_hand == I) //in a hand - user.drop_l_hand() - else if(user.r_hand == I) //in a hand - user.drop_r_hand() - else - return + return user.visible_message("[user] puts [I] into [src]", "You put [I] inside [src].",\ "You hear a rustle as someone puts something into a plastic bag.") @@ -55,28 +68,35 @@ overlays += img overlays += "evidence" //should look nicer for transparent stuff. not really that important, but hey. - desc = "An evidence bag containing [I]. [I.desc]" + desc = "An evidence bag containing [I]." I.loc = src + stored_item = I w_class = I.w_class return /obj/item/weapon/evidencebag/attack_self(mob/user as mob) if(contents.len) - var/obj/item/I = contents[1] + var/obj/item/I = stored_item user.visible_message("[user] takes [I] out of [src]", "You take [I] out of [src].",\ "You hear someone rustle around in a plastic bag, and remove something.") overlays.Cut() //remove the overlays + user.put_in_hands(I) - w_class = 1 + stored_item = null + + w_class = initial(w_class) icon_state = "evidenceobj" desc = "An empty evidence bag." - else user << "[src] is empty." icon_state = "evidenceobj" return +/obj/item/weapon/evidencebag/examine() + ..() + if (stored_item) stored_item.examine() + /obj/item/weapon/storage/box/evidence name = "evidence bag box" desc = "A box claiming to contain evidence bags." diff --git a/code/modules/events/borers.dm b/code/modules/events/borers.dm index 2c6a2820fbb..75e1f8b577c 100644 --- a/code/modules/events/borers.dm +++ b/code/modules/events/borers.dm @@ -6,7 +6,7 @@ /datum/event/borer_infestation announceWhen = 400 - var/spawncount = 1 + var/spawncount = 5 var/successSpawn = 0 //So we don't make a command report if nothing gets spawned. /datum/event/borer_infestation/setup() diff --git a/code/modules/events/event_dynamic.dm b/code/modules/events/event_dynamic.dm index 7ca50ad9ebe..fc96c21821f 100644 --- a/code/modules/events/event_dynamic.dm +++ b/code/modules/events/event_dynamic.dm @@ -44,15 +44,23 @@ var/list/event_last_fired = list() //see: // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events.dm // Code/WorkInProgress/Cael_Aislinn/Economy/Economy_Events_Mundane.dm - possibleEvents[/datum/event/economic_event] = 300 - possibleEvents[/datum/event/trivial_news] = 400 - possibleEvents[/datum/event/mundane_news] = 300 + + if(ticker.mode && ticker.mode.name == "calamity") //Calamity mode messes with some events. + possibleEvents[/datum/event/borer_infestation] = 400 + possibleEvents[/datum/event/economic_event] = 25 + possibleEvents[/datum/event/trivial_news] = 25 + possibleEvents[/datum/event/mundane_news] = 25 + else + possibleEvents[/datum/event/economic_event] = 300 + possibleEvents[/datum/event/trivial_news] = 400 + possibleEvents[/datum/event/mundane_news] = 300 possibleEvents[/datum/event/pda_spam] = max(min(25, player_list.len) * 4, 200) possibleEvents[/datum/event/money_lotto] = max(min(5, player_list.len), 50) if(account_hack_attempted) possibleEvents[/datum/event/money_hacker] = max(min(25, player_list.len) * 4, 200) + possibleEvents[/datum/event/carp_migration] = 20 + 10 * active_with_role["Engineer"] possibleEvents[/datum/event/brand_intelligence] = 20 + 25 * active_with_role["Janitor"] diff --git a/code/modules/events/event_manager.dm b/code/modules/events/event_manager.dm index 1311e1c71bb..12efae2facc 100644 --- a/code/modules/events/event_manager.dm +++ b/code/modules/events/event_manager.dm @@ -32,7 +32,7 @@ var/scheduledEvent = null playercount_modifier = 0.8 if(ticker.mode && ticker.mode.name == "calamity") //Calamity mode lowers the time required between events drastically. - playercount_modifier = playercount_modifier * 0.3 + playercount_modifier = playercount_modifier * 0.5 var/next_event_delay = rand(eventTimeLower, eventTimeUpper) * playercount_modifier scheduledEvent = world.timeofday + next_event_delay diff --git a/code/modules/hydroponics/hydro_tools.dm b/code/modules/hydroponics/hydro_tools.dm index a0276e37b73..87cd6079fc2 100644 --- a/code/modules/hydroponics/hydro_tools.dm +++ b/code/modules/hydroponics/hydro_tools.dm @@ -18,7 +18,9 @@ var/datum/seed/grown_seed var/datum/reagents/grown_reagents - if(istype(target,/obj/item/weapon/reagent_containers/food/snacks/grown)) + if(istype(target,/obj/structure/rack) || istype(target,/obj/structure/table)) + return ..() + else if(istype(target,/obj/item/weapon/reagent_containers/food/snacks/grown)) var/obj/item/weapon/reagent_containers/food/snacks/grown/G = target grown_seed = seed_types[G.plantname] @@ -166,7 +168,7 @@ /obj/item/weapon/plantspray icon = 'icons/obj/hydroponics.dmi' item_state = "spray" - flags = TABLEPASS | OPENCONTAINER | FPRINT | NOBLUDGEON + flags = TABLEPASS | FPRINT | NOBLUDGEON slot_flags = SLOT_BELT throwforce = 4 w_class = 2.0 @@ -181,13 +183,13 @@ name = "weed-spray" desc = "It's a toxic mixture, in spray form, to kill small weeds." icon_state = "weedspray" - weed_kill_str = 2 + weed_kill_str = 6 /obj/item/weapon/plantspray/pests name = "pest-spray" desc = "It's some pest eliminator spray! Do not inhale!" icon_state = "pestspray" - pest_kill_str = 2 + pest_kill_str = 6 /obj/item/weapon/plantspray/pests/old name = "bottle of pestkiller" diff --git a/code/modules/hydroponics/hydro_tray.dm b/code/modules/hydroponics/hydro_tray.dm index dc0dda59e45..a7aeba259c8 100644 --- a/code/modules/hydroponics/hydro_tray.dm +++ b/code/modules/hydroponics/hydro_tray.dm @@ -7,14 +7,15 @@ density = 1 anchored = 1 flags = OPENCONTAINER + volume = 100 var/draw_warnings = 1 //Set to 0 to stop it from drawing the alert lights. // Plant maintenance vars. - var/waterlevel = 100 // Water level (max 100) - var/nutrilevel = 10 // Nutrient level (max 10) + var/waterlevel = 100 // Water (max 100) + var/nutrilevel = 100 // Nutrient (max 100) var/pestlevel = 0 // Pests (max 10) - var/weedlevel = 0 // Weeds (max 10)s + var/weedlevel = 0 // Weeds (max 10) // Tray state vars. var/dead = 0 // Is it dead? @@ -25,6 +26,7 @@ var/yield_mod = 0 // Modifier to yield var/mutation_mod = 0 // Modifier to mutation chance var/toxins = 0 // Toxicity in the tray? + var/mutation_level = 0 // When it hits 100, the plant mutates. // Mechanical concerns. var/health = 0 // Plant health. @@ -33,6 +35,7 @@ var/cycledelay = 150 // Delay per cycle. var/closed_system // If set, the tray will attempt to take atmos from a pipe. var/force_update // Set this to bypass the cycle time check. + var/obj/temp_chem_holder // Something to hold reagents during process_reagents() // Seed details/line data. var/datum/seed/seed = null // The currently planted seed @@ -104,7 +107,7 @@ "cryoxadone" = list( 3, 0, 0 ), "ammonia" = list( 0.5, 0, 0 ), "diethylamine" = list( 1, 0, 0 ), - "nutriment" = list( 0.5, 1, 0 ), + "nutriment" = list( 0.5, 0.1, 0 ), "radium" = list( -1.5, 0, 0.2 ), "adminordrazine" = list( 1, 1, 1 ), "robustharvest" = list( 0, 0.2, 0 ), @@ -114,12 +117,14 @@ // Mutagen list specifies minimum value for the mutation to take place, rather // than a bound as the lists above specify. var/global/list/mutagenic_reagents = list( - "radium" = list(8,3), - "mutagen" = list(3,8) + "radium" = 3, + "mutagen" = 8 ) /obj/machinery/portable_atmospherics/hydroponics/New() ..() + temp_chem_holder = new() + temp_chem_holder.create_reagents(10) create_reagents(200) connect() update_icon() @@ -162,9 +167,12 @@ return lastcycle = world.time + // Mutation level drops each main tick. + mutation_level -= rand(2,4) + // Weeds like water and nutrients, there's a chance the weed population will increase. // Bonus chance if the tray is unoccupied. - if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 6 : 3)) + if(waterlevel > 10 && nutrilevel > 2 && prob(isnull(seed) ? 5 : 2)) weedlevel += 1 * HYDRO_SPEED_MULTIPLIER // There's a chance for a weed explosion to happen if the weeds take over. @@ -179,13 +187,19 @@ return // Advance plant age. - if(prob(25)) age += 1 * HYDRO_SPEED_MULTIPLIER + if(prob(30)) age += 1 * HYDRO_SPEED_MULTIPLIER //Highly mutable plants have a chance of mutating every tick. if(seed.immutable == -1) var/mut_prob = rand(1,100) if(mut_prob <= 5) mutate(mut_prob == 1 ? 2 : 1) + // Other plants also mutate if enough mutagenic compounds have been added. + if(!seed.immutable) + if(prob(min(mutation_level,100))) + mutate((rand(100) < 25) ? 2 : 1) + mutation_level = 0 + // Maintain tray nutrient and water levels. if(seed.nutrient_consumption > 0 && nutrilevel > 0 && prob(25)) nutrilevel -= max(0,seed.nutrient_consumption * HYDRO_SPEED_MULTIPLIER) @@ -242,7 +256,7 @@ if(seed.exude_gasses && seed.exude_gasses.len) for(var/gas in seed.exude_gasses) environment.adjust_gas(gas, max(1,round((seed.exude_gasses[gas]*seed.potency)/seed.exude_gasses.len))) - + // If we're attached to a pipenet, then we should let the pipenet know we might have modified some gasses if (closed_system && connected_port) update_connected_network() @@ -291,6 +305,7 @@ // When the plant dies, weeds thrive and pests die off. if(health <= 0) dead = 1 + mutation_level = 0 harvest = 0 weedlevel += 1 * HYDRO_SPEED_MULTIPLIER pestlevel = 0 @@ -302,7 +317,7 @@ lastproduce = age if(prob(3)) // On each tick, there's a chance the pest population will increase - pestlevel += 1 * HYDRO_SPEED_MULTIPLIER + pestlevel += 0.1 * HYDRO_SPEED_MULTIPLIER check_level_sanity() update_icon() @@ -316,19 +331,20 @@ if(reagents.total_volume <= 0) return - for(var/datum/reagent/R in reagents.reagent_list) + reagents.trans_to(temp_chem_holder, min(reagents.total_volume,rand(1,3))) + for(var/datum/reagent/R in temp_chem_holder.reagents.reagent_list) - var/reagent_total = reagents.get_reagent_amount(R.id) + var/reagent_total = temp_chem_holder.reagents.get_reagent_amount(R.id) if(seed && !dead) //Handle some general level adjustments. if(toxic_reagents[R.id]) toxins += toxic_reagents[R.id] * reagent_total if(weedkiller_reagents[R.id]) - weedlevel += weedkiller_reagents[R.id] * reagent_total + weedlevel -= weedkiller_reagents[R.id] * reagent_total if(pestkiller_reagents[R.id]) - pestlevel += pestkiller_reagents[R.id] * reagent_total + pestlevel -= pestkiller_reagents[R.id] * reagent_total // Beneficial reagents have a few impacts along with health buffs. if(beneficial_reagents[R.id]) @@ -338,12 +354,7 @@ // Mutagen is distinct from the previous types and mostly has a chance of proccing a mutation. if(mutagenic_reagents[R.id]) - var/reagent_min_value = mutagenic_reagents[R.id][1] - var/reagent_value = mutagenic_reagents[R.id][2]+mutation_mod - - if(reagent_total >= reagent_min_value) - if(prob(min(reagent_total*reagent_value,100))) - mutate(reagent_total > 10 ? 2 : 1) + mutation_level += reagent_total*mutagenic_reagents[R.id]+mutation_mod // Handle nutrient refilling. if(nutrient_reagents[R.id]) @@ -356,10 +367,11 @@ water_added += water_input waterlevel += water_input + // Water dilutes toxin level. if(water_added > 0) toxins -= round(water_added/4) - reagents.clear_reagents() + temp_chem_holder.reagents.clear_reagents() check_level_sanity() update_icon() @@ -509,11 +521,12 @@ health = 0 dead = 0 - nutrilevel = max(0,min(nutrilevel,10)) - waterlevel = max(0,min(waterlevel,100)) - pestlevel = max(0,min(pestlevel,10)) - weedlevel = max(0,min(weedlevel,10)) - toxins = max(0,min(toxins,10)) + mutation_level = max(0,min(mutation_level,100)) + nutrilevel = max(0,min(nutrilevel,10)) + waterlevel = max(0,min(waterlevel,100)) + pestlevel = max(0,min(pestlevel,10)) + weedlevel = max(0,min(weedlevel,10)) + toxins = max(0,min(toxins,10)) /obj/machinery/portable_atmospherics/hydroponics/proc/mutate_species() @@ -548,10 +561,16 @@ user << "There is nothing to take a sample from in \the [src]." return - seed.harvest(user,yield_mod,1) - health -= (rand(1,5)*10) - check_level_sanity() + if(dead) + user << "\The plant is dead." + return + // Create a sample. + seed.harvest(user,yield_mod,1) + health -= (rand(3,5)*10) + + // Bookkeeping. + check_level_sanity() force_update = 1 process() @@ -565,14 +584,14 @@ if(seed) return ..() else - user << "There's no plant in the tray to inject." + user << "There's no plant to inject." return 1 else if(seed) //Leaving this in in case we want to extract from plants later. user << "You can't get any extract out of this plant." else - user << "There's nothing in the tray to draw something from." + user << "There's nothing to draw something from." return 1 else if (istype(O, /obj/item/seeds)) @@ -637,7 +656,7 @@ user << "There's nothing in [src] to spray!" else if (istype(O, /obj/item/weapon/minihoe)) // The minihoe - //var/deweeding + if(weedlevel > 0) user.visible_message("\red [user] starts uprooting the weeds.", "\red You remove the weeds from the [src].") weedlevel = 0 diff --git a/code/modules/hydroponics/seed_datums.dm b/code/modules/hydroponics/seed_datums.dm index f1d12a1a6a5..206cb535f45 100644 --- a/code/modules/hydroponics/seed_datums.dm +++ b/code/modules/hydroponics/seed_datums.dm @@ -97,6 +97,136 @@ proc/populate_seed_list() var/flower_icon = "vine_fruit" // Which overlay to use. var/flower_colour // Which colour to use. +//Creates a random seed. MAKE SURE THE LINE HAS DIVERGED BEFORE THIS IS CALLED. +/datum/seed/proc/randomize() + + roundstart = 0 + seed_name = "strange plant" // TODO: name generator. + display_name = "strange plants" // TODO: name generator. + + seed_noun = pick("spores","nodes","cuttings","seeds") + products = list(/obj/item/weapon/reagent_containers/food/snacks/grown/generic_fruit) + potency = rand(5,30) + + //TODO: Finish generalizing the product icons so this can be randomized. + packet_icon = "seed-berry" + plant_icon = "berry" + if(prob(20)) + harvest_repeat = 1 + + if(prob(5)) + consume_gasses = list() + var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") + consume_gasses[gas] = rand(3,9) + + if(prob(5)) + exude_gasses = list() + var/gas = pick("oxygen","nitrogen","phoron","carbon_dioxide") + exude_gasses[gas] = rand(3,9) + + chems = list() + if(prob(80)) + chems["nutriment"] = list(rand(1,10),rand(10,20)) + + var/additional_chems = rand(0,5) + + var/list/possible_chems = list( + "bicaridine", + "hyperzine", + "cryoxadone", + "blood", + "water", + "potassium", + "plasticide", + "slimetoxin", + "aslimetoxin", + "inaprovaline", + "space_drugs", + "paroxetine", + "mercury", + "sugar", + "radium", + "ryetalyn", + "alkysine", + "thermite", + "tramadol", + "cryptobiolin", + "dermaline", + "dexalin", + "phoron", + "synaptizine", + "impedrezene", + "hyronalin", + "peridaxon", + "toxin", + "rezadone", + "ethylredoxrazine", + "slimejelly", + "cyanide", + "mindbreaker", + "stoxin" + ) + + for(var/x=1;x<=additional_chems;x++) + if(!possible_chems.len) + break + var/new_chem = pick(possible_chems) + possible_chems -= new_chem + chems[new_chem] = list(rand(1,10),rand(10,20)) + + if(prob(90)) + requires_nutrients = 1 + nutrient_consumption = rand(100)*0.1 + else + requires_nutrients = 0 + + if(prob(90)) + requires_water = 1 + water_consumption = rand(10) + else + requires_water = 0 + + ideal_heat = rand(100,400) + heat_tolerance = rand(10,30) + ideal_light = rand(2,10) + light_tolerance = rand(2,7) + toxins_tolerance = rand(2,7) + pest_tolerance = rand(2,7) + weed_tolerance = rand(2,7) + lowkpa_tolerance = rand(10,50) + highkpa_tolerance = rand(100,300) + + if(prob(5)) + alter_temp = rand(-5,5) + + if(prob(1)) + immutable = -1 + + var/carnivore_prob = rand(100) + if(carnivore_prob < 5) + carnivorous = 2 + else if(carnivore_prob < 10) + carnivorous = 1 + + if(prob(10)) + parasite = 1 + + var/vine_prob = rand(100) + if(vine_prob < 5) + spread = 2 + else if(vine_prob < 10) + spread = 1 + + if(prob(5)) + biolum = 1 + biolum_colour = "#[pick(list("FF0000","FF7F00","FFFF00","00FF00","0000FF","4B0082","8F00FF"))]" + + endurance = rand(60,100) + yield = rand(3,15) + maturation = rand(5,15) + production = maturation + rand(2,5) + lifespan = production + rand(5,10) + //Returns a key corresponding to an entry in the global seed list. /datum/seed/proc/get_mutant_variant() if(!mutants || !mutants.len || immutable > 0) return 0 @@ -188,26 +318,35 @@ proc/populate_seed_list() if(gene.values.len < 6) return - yield = round(yield*0.5) - endurance = round(endurance*0.5) - lifespan = round(lifespan*0.8) + if(yield > 0) yield = max(1,round(yield*0.85)) + if(endurance > 0) endurance = max(1,round(endurance*0.85)) + if(lifespan > 0) lifespan = max(1,round(lifespan*0.85)) if(!products) products = list() products |= gene.values[1] if(!chems) chems = list() - for(var/rid in gene.values[2]) - var/existing_chem - for(var/chem in chems) - if(rid == chem) - existing_chem = 1 - break - if(existing_chem) - chems[rid][1] = max(1,round((chems[rid][1]+gene.values[2][rid][1])/2)) - chems[rid][2] = max(1,round((chems[rid][2]+gene.values[2][rid][2])/2)) + var/list/gene_value = gene.values[2] + for(var/rid in gene_value) + + var/list/gene_chem = gene_value[rid] + + if(chems[rid]) + + var/list/chem_value = chems[rid] + + chems[rid][1] = max(1,round((gene_chem[1] + chem_value[1])/2)) + + if(gene_chem.len > 1) + if(chem_value > 1) + chems[rid][2] = max(1,round((gene_chem[2] + chem_value[2])/2)) + else + chems[rid][2] = gene_chem[2] + else - chems[rid] = gene.values[2][rid] + var/list/new_chem = gene_chem[rid] + chems[rid] = new_chem.Copy() var/list/new_gasses = gene.values[3] if(istype(new_gasses)) @@ -353,7 +492,7 @@ proc/populate_seed_list() if(!isnull(products) && products.len && yield > 0) got_product = 1 - if(!got_product) + if(!got_product && !harvest_sample) user << "\red You fail to harvest anything useful." else user << "You [harvest_sample ? "take a sample" : "harvest"] from the [display_name]." @@ -370,12 +509,14 @@ proc/populate_seed_list() seeds.update_seed() return - var/total_yield - if(isnull(yield_mod) || yield_mod < 1) - yield_mod = 0 - total_yield = yield - else - total_yield = max(1,rand(yield_mod,yield_mod+yield)) + var/total_yield = 0 + if(yield > -1) + if(isnull(yield_mod) || yield_mod < 1) + yield_mod = 0 + total_yield = yield + else + total_yield = yield + rand(yield_mod) + total_yield = max(1,total_yield) currently_querying = list() for(var/i = 0;i 0) user << "That seed is not compatible with our genetics technology." diff --git a/code/modules/hydroponics/seeds.dm b/code/modules/hydroponics/seeds.dm index d0afda2e6fb..77a220792bc 100644 --- a/code/modules/hydroponics/seeds.dm +++ b/code/modules/hydroponics/seeds.dm @@ -40,6 +40,19 @@ ..() src.name = "packet of [seed.seed_name] cuttings" +/obj/item/seeds/random + seed_type = null + +/obj/item/seeds/random/New() + seed = new() + seed.randomize() + + seed.uid = seed_types.len + 1 + seed.name = "[seed.uid]" + seed_types[seed.name] = seed + + update_seed() + /obj/item/seeds/replicapod seed_type = "diona" diff --git a/code/modules/hydroponics/vines.dm b/code/modules/hydroponics/vines.dm index 085229d417c..70265984f30 100644 --- a/code/modules/hydroponics/vines.dm +++ b/code/modules/hydroponics/vines.dm @@ -240,7 +240,7 @@ del src /obj/effect/plantsegment/proc/die() - if(seed && harvest) + if(seed && harvest && rand(5)) seed.harvest(src,1) del(src) diff --git a/code/modules/library/lib_items.dm b/code/modules/library/lib_items.dm index ffb4915d788..e8374d56522 100644 --- a/code/modules/library/lib_items.dm +++ b/code/modules/library/lib_items.dm @@ -41,7 +41,7 @@ /obj/structure/bookcase/attack_hand(var/mob/user as mob) if(contents.len) - var/obj/item/weapon/book/choice = input("Which book would you like to remove from the shelf?") in contents as obj|null + var/obj/item/weapon/book/choice = input("Which book would you like to remove from the shelf?") as null|obj in contents if(choice) if(!usr.canmove || usr.stat || usr.restrained() || !in_range(loc, usr)) return diff --git a/code/modules/mining/machine_processing.dm b/code/modules/mining/machine_processing.dm index d8b671af252..2a029b42eeb 100644 --- a/code/modules/mining/machine_processing.dm +++ b/code/modules/mining/machine_processing.dm @@ -62,7 +62,7 @@ dat += "Currently displaying [show_all_ores ? "all ore types" : "only available ore types"]. \[[show_all_ores ? "show less" : "show more"]\]
" dat += "The ore processor is currently [(machine.active ? "processing" : "disabled")]." user << browse(dat, "window=processor_console;size=400x500") - onclose(user, "computer") + onclose(user, "processor_console") return /obj/machinery/mineral/processing_unit_console/Topic(href, href_list) diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm index bf70bb5c767..c556990e815 100644 --- a/code/modules/mining/mine_turfs.dm +++ b/code/modules/mining/mine_turfs.dm @@ -28,8 +28,6 @@ /turf/simulated/mineral/New() - . = ..() - MineralSpread() spawn(2) @@ -260,8 +258,23 @@ M.Stun(5) M.apply_effect(25, IRRADIATE) + + var/list/step_overlays = list("n" = NORTH, "s" = SOUTH, "e" = EAST, "w" = WEST) + + //Add some rubble, you did just clear out a big chunk of rock. var/turf/simulated/floor/plating/airless/asteroid/N = ChangeTurf(/turf/simulated/floor/plating/airless/asteroid) - for(var/i=0;i last_update + 10) - update_orecount() + update_ore_count() last_update = world.time - var/dat = text("The contents of the ore box reveal...") - if (amt_iron) - dat += text("
Metal ore: [amt_iron]") - if (amt_glass) - dat += text("
Sand: [amt_glass]") - if (amt_phoron) - dat += text("
Phoron ore: [amt_phoron]") - if (amt_uranium) - dat += text("
Uranium ore: [amt_uranium]") - if (amt_silver) - dat += text("
Silver ore: [amt_silver]") - if (amt_gold) - dat += text("
Gold ore: [amt_gold]") - if (amt_diamond) - dat += text("
Diamond ore: [amt_diamond]") - if (amt_strange) - dat += text("
Strange rocks: [amt_strange]") - - usr << dat - + usr << "It holds:" + for(var/ore in stored_ore) + usr << "- [stored_ore[ore]] [ore]" return @@ -106,47 +95,4 @@ O.loc = src.loc usr << "\blue You empty the ore box" - return - - -// Updates ore tally -/obj/structure/ore_box/proc/update_orecount() - amt_iron = 0 - amt_glass = 0 - amt_phoron = 0 - amt_uranium = 0 - amt_silver = 0 - amt_gold = 0 - amt_diamond = 0 - amt_strange = 0 - amt_clown = 0 - - for(var/obj/item/weapon/ore/O in contents) - if(!istype(O)) - continue - - if (istype(O, /obj/item/weapon/ore/iron)) - amt_iron++ - continue - if (istype(O, /obj/item/weapon/ore/glass)) - amt_glass++ - continue - if (istype(O, /obj/item/weapon/ore/phoron)) - amt_phoron++ - continue - if (istype(O, /obj/item/weapon/ore/uranium)) - amt_uranium++ - continue - if (istype(O, /obj/item/weapon/ore/silver)) - amt_silver++ - continue - if (istype(O, /obj/item/weapon/ore/gold)) - amt_gold++ - continue - if (istype(O, /obj/item/weapon/ore/diamond)) - amt_diamond++ - continue - if (istype(O, /obj/item/weapon/ore/strangerock)) - amt_strange++ - continue return \ No newline at end of file diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 575996a84f7..f0c22c9f596 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -122,11 +122,11 @@ "\red You feel a mild shock course through your body.", \ "\red You hear a light zapping." \ ) - + var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread s.set_up(5, 1, loc) s.start() - + return shock_damage diff --git a/code/modules/mob/living/carbon/human/human_damage.dm b/code/modules/mob/living/carbon/human/human_damage.dm index bc6d2832e6a..01caff57e5a 100644 --- a/code/modules/mob/living/carbon/human/human_damage.dm +++ b/code/modules/mob/living/carbon/human/human_damage.dm @@ -165,6 +165,10 @@ hud_updateflag |= 1 << HEALTH_HUD updatehealth() + +/* +In most cases it makes more sense to use apply_damage() instead! And make sure to check armour if applicable. +*/ //Damages ONE external organ, organ gets randomly selected from damagable ones. //It automatically updates damage overlays if necesary //It automatically updates health status diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index d8d97dee787..5659f44a617 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -84,7 +84,7 @@ emp_act /mob/living/carbon/human/getarmor(var/def_zone, var/type) var/armorval = 0 - var/organnum = 0 + var/total = 0 if(def_zone) if(isorgan(def_zone)) @@ -94,10 +94,13 @@ emp_act //If a specific bodypart is targetted, check how that bodypart is protected and return the value. //If you don't specify a bodypart, it checks ALL your bodyparts for protection, and averages out the values - for(var/datum/organ/external/organ in organs) - armorval += getarmor_organ(organ, type) - organnum++ - return (armorval/max(organnum, 1)) + for(var/organ_name in organs_by_name) + if (organ_name in organ_rel_size) + var/datum/organ/external/organ = organs_by_name[organ_name] + var/weight = organ_rel_size[organ_name] + armorval += getarmor_organ(organ, type) * weight + total += weight + return (armorval/max(total, 1)) //this proc returns the Siemens coefficient of electrical resistivity for a particular external organ. /mob/living/carbon/human/proc/get_siemens_coefficient_organ(var/datum/organ/external/def_zone) @@ -117,11 +120,10 @@ emp_act /mob/living/carbon/human/proc/getarmor_organ(var/datum/organ/external/def_zone, var/type) if(!type) return 0 var/protection = 0 - var/list/body_parts = list(head, wear_mask, wear_suit, w_uniform) - for(var/bp in body_parts) - if(!bp) continue - if(bp && istype(bp ,/obj/item/clothing)) - var/obj/item/clothing/C = bp + var/list/protective_gear = list(head, wear_mask, wear_suit, w_uniform) + for(var/gear in protective_gear) + if(gear && istype(gear ,/obj/item/clothing)) + var/obj/item/clothing/C = gear if(C.body_parts_covered & def_zone.body_part) protection += C.armor[type] return protection diff --git a/code/modules/mob/living/carbon/human/life.dm b/code/modules/mob/living/carbon/human/life.dm index 1119225ec17..c5fb663116a 100644 --- a/code/modules/mob/living/carbon/human/life.dm +++ b/code/modules/mob/living/carbon/human/life.dm @@ -642,6 +642,12 @@ var/pressure = environment.return_pressure() var/adjusted_pressure = calculate_affecting_pressure(pressure) + //Check for contaminants before anything else because we don't want to skip it. + for(var/g in environment.gas) + if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && environment.gas[g] > gas_data.overlay_limit[g] + 1) + pl_effects() + break + if(!istype(get_turf(src), /turf/space)) //space is not meant to change your body temperature. var/loc_temp = T0C if(istype(loc, /obj/mecha)) @@ -730,10 +736,6 @@ else pressure_alert = -1 - for(var/g in environment.gas) - if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && environment.gas[g] > gas_data.overlay_limit[g] + 1) - pl_effects() - break return /* diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm index 5431a2775ad..cc76d40c654 100644 --- a/code/modules/mob/living/damage_procs.dm +++ b/code/modules/mob/living/damage_procs.dm @@ -52,7 +52,8 @@ if(AGONY) halloss += effect // Useful for objects that cause "subdual" damage. PAIN! if(IRRADIATE) - radiation += max((((effect - (effect*(getarmor(null, "rad")/100))))/(blocked+1)),0)//Rads auto check armor + var/rad_protection = getarmor(null, "rad")/100 + radiation += max((1-rad_protection)*effect/(blocked+1),0)//Rads auto check armor if(STUTTER) if(status_flags & CANSTUN) // stun is usually associated with stutter stuttering = max(stuttering,(effect/(blocked+1))) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 2c0b3bbdb62..daf0e370049 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -470,7 +470,7 @@ H << "\red You begin doggedly resisting the parasite's control (this will take approximately sixty seconds)." B.host << "\red You feel the captive mind of [src] begin to resist your control." - spawn(rand(350,450)+B.host.brainloss) + spawn(rand(400,500)+B.host.brainloss) if(!B || !B.controlling) return diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 6f308e6add4..3e895c73c2c 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -61,7 +61,7 @@ src <<"\red You have been hit by [P]!" del P return - + //Armor var/absorb = run_armor_check(def_zone, P.flag) var/proj_sharp = is_sharp(P) @@ -78,13 +78,13 @@ //Handles the effects of "stun" weapons /mob/living/proc/stun_effect_act(var/stun_amount, var/agony_amount, var/def_zone, var/used_weapon=null) flash_pain() - + if (stun_amount) Stun(stun_amount) Weaken(stun_amount) apply_effect(STUTTER, stun_amount) apply_effect(EYE_BLUR, stun_amount) - + if (agony_amount) apply_damage(agony_amount, HALLOSS, def_zone, 0, used_weapon) apply_effect(STUTTER, agony_amount/10) @@ -108,16 +108,16 @@ var/obj/item/weapon/W = O dtype = W.damtype var/throw_damage = O.throwforce*(speed/5) - + var/miss_chance = 15 if (O.throw_source) var/distance = get_dist(O.throw_source, loc) miss_chance = min(15*(distance-2), 0) - + if (prob(miss_chance)) visible_message("\blue \The [O] misses [src] narrowly!") return - + src.visible_message("\red [src] has been hit by [O].") var/armor = run_armor_check(null, "melee") @@ -125,7 +125,7 @@ apply_damage(throw_damage, dtype, null, armor, is_sharp(O), has_edge(O), O) O.throwing = 0 //it hit, so stop moving - + if(ismob(O.thrower)) var/mob/M = O.thrower var/client/assailant = M.client @@ -145,7 +145,7 @@ src.throw_at(get_edge_target_turf(src,dir),1,momentum) if(!W || !src) return - + if(W.sharp) //Projectile is suitable for pinning. //Handles embedding for non-humans and simple_animals. O.loc = src @@ -158,6 +158,7 @@ visible_message("[src] is pinned to the wall by [O]!","You are pinned to the wall by [O]!") src.anchored = 1 src.pinned += O + src.verbs += /mob/proc/yank_out_object //This is called when the mob is thrown into a dense turf /mob/living/proc/turf_collision(var/turf/T, var/speed) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index 36a8df5cc15..7a187d2573e 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -3,6 +3,7 @@ var/list/ai_list = list() var/list/ai_verbs_default = list( + /mob/living/silicon/ai/proc/ai_alerts, /mob/living/silicon/ai/proc/ai_announcement, /mob/living/silicon/ai/proc/ai_call_shuttle, // /mob/living/silicon/ai/proc/ai_recall_shuttle, diff --git a/code/modules/mob/living/silicon/pai/pai.dm b/code/modules/mob/living/silicon/pai/pai.dm index dd3e2e6b3cf..efdf6669ac2 100755 --- a/code/modules/mob/living/silicon/pai/pai.dm +++ b/code/modules/mob/living/silicon/pai/pai.dm @@ -32,7 +32,7 @@ "Chirp" = list("chirps","chirrups","cheeps"), "Feline" = list("purrs","yowls","meows") ) - + var/obj/item/weapon/pai_cable/cable // The cable we produce and use when door or camera jacking var/master // Name of the one who commands us @@ -84,7 +84,6 @@ add_language("Tradeband", 1) add_language("Gutter", 1) - verbs += /mob/living/silicon/pai/proc/fold_out verbs += /mob/living/silicon/pai/proc/choose_chassis verbs += /mob/living/silicon/pai/proc/choose_verbs @@ -301,7 +300,7 @@ // mobile pai mob. This also includes handling some of the general shit that can occur // to it. Really this deserves its own file, but for the moment it can sit here. ~ Z -/mob/living/silicon/pai/proc/fold_out() +/mob/living/silicon/pai/verb/fold_out() set category = "pAI Commands" set name = "Unfold Chassis" @@ -315,8 +314,6 @@ return last_special = world.time + 100 - verbs -= /mob/living/silicon/pai/proc/fold_out - verbs += /mob/living/silicon/pai/proc/fold_up var/turf/T = get_turf(src) if(istype(T)) T.visible_message("[src] folds outwards, expanding into a mobile form.") @@ -333,7 +330,7 @@ src.forceMove(get_turf(card)) card.forceMove(src) -/mob/living/silicon/pai/proc/fold_up() +/mob/living/silicon/pai/verb/fold_up() set category = "pAI Commands" set name = "Collapse Chassis" @@ -412,8 +409,8 @@ last_special = world.time + 100 - verbs -= /mob/living/silicon/pai/proc/fold_up - verbs += /mob/living/silicon/pai/proc/fold_out + if(src.loc == card) + return var/turf/T = get_turf(src) if(istype(T)) T.visible_message("[src] neatly folds inwards, compacting down to a rectangular card.") diff --git a/code/modules/mob/living/silicon/pai/recruit.dm b/code/modules/mob/living/silicon/pai/recruit.dm index 73a6d59c158..623b2b5638e 100644 --- a/code/modules/mob/living/silicon/pai/recruit.dm +++ b/code/modules/mob/living/silicon/pai/recruit.dm @@ -108,7 +108,6 @@ var/datum/paiController/paiController // Global handler for pAI candidates candidate.key = M.key pai_candidates.Add(candidate) - var/dat = "" dat += {"