Merge pull request #6336 from Baystation12/dev-freeze

[DNM] Dev freeze > Master
This commit is contained in:
Zuhayr
2014-09-13 17:47:32 +09:30
608 changed files with 31398 additions and 24692 deletions
+30 -13
View File
@@ -48,6 +48,8 @@
#include "code\_onclick\hud\other_mobs.dm"
#include "code\_onclick\hud\robot.dm"
#include "code\_onclick\hud\screen_objects.dm"
#include "code\ATMOSPHERICS\_atmos_setup.dm"
#include "code\ATMOSPHERICS\_atmospherics_helpers.dm"
#include "code\ATMOSPHERICS\atmospherics.dm"
#include "code\ATMOSPHERICS\datum_pipe_network.dm"
#include "code\ATMOSPHERICS\datum_pipeline.dm"
@@ -82,6 +84,7 @@
#include "code\ATMOSPHERICS\components\unary\vent_scrubber.dm"
#include "code\controllers\_DynamicAreaLighting_TG.dm"
#include "code\controllers\autotransfer.dm"
#include "code\controllers\communications.dm"
#include "code\controllers\configuration.dm"
#include "code\controllers\emergency_shuttle_controller.dm"
#include "code\controllers\failsafe.dm"
@@ -173,7 +176,6 @@
#include "code\game\asteroid.dm"
#include "code\game\atoms.dm"
#include "code\game\atoms_movable.dm"
#include "code\game\communications.dm"
#include "code\game\response_team.dm"
#include "code\game\shuttle_engines.dm"
#include "code\game\skincmd.dm"
@@ -205,6 +207,7 @@
#include "code\game\gamemodes\blob\blobs\factory.dm"
#include "code\game\gamemodes\blob\blobs\node.dm"
#include "code\game\gamemodes\blob\blobs\shield.dm"
#include "code\game\gamemodes\calamity\calamity.dm"
#include "code\game\gamemodes\changeling\changeling.dm"
#include "code\game\gamemodes\changeling\changeling_powers.dm"
#include "code\game\gamemodes\changeling\modularchangling.dm"
@@ -297,7 +300,6 @@
#include "code\game\machinery\doppler_array.dm"
#include "code\game\machinery\flasher.dm"
#include "code\game\machinery\floodlight.dm"
#include "code\game\machinery\Freezer.dm"
#include "code\game\machinery\hologram.dm"
#include "code\game\machinery\holosign.dm"
#include "code\game\machinery\igniter.dm"
@@ -310,14 +312,12 @@
#include "code\game\machinery\newscaster.dm"
#include "code\game\machinery\OpTable.dm"
#include "code\game\machinery\overview.dm"
#include "code\game\machinery\podmen.dm"
#include "code\game\machinery\portable_turret.dm"
#include "code\game\machinery\recharger.dm"
#include "code\game\machinery\rechargestation.dm"
#include "code\game\machinery\requests_console.dm"
#include "code\game\machinery\robot_fabricator.dm"
#include "code\game\machinery\seed_extractor.dm"
#include "code\game\machinery\shieldgen.dm"
#include "code\game\machinery\Sleeper.dm"
#include "code\game\machinery\spaceheater.dm"
#include "code\game\machinery\status_display.dm"
@@ -334,7 +334,6 @@
#include "code\game\machinery\atmoalter\portable_atmospherics.dm"
#include "code\game\machinery\atmoalter\pump.dm"
#include "code\game\machinery\atmoalter\scrubber.dm"
#include "code\game\machinery\atmoalter\zvent.dm"
#include "code\game\machinery\bots\bots.dm"
#include "code\game\machinery\bots\cleanbot.dm"
#include "code\game\machinery\bots\ed209bot.dm"
@@ -366,7 +365,6 @@
#include "code\game\machinery\computer\message.dm"
#include "code\game\machinery\computer\Operating.dm"
#include "code\game\machinery\computer\pod.dm"
#include "code\game\machinery\computer\power.dm"
#include "code\game\machinery\computer\prisoner.dm"
#include "code\game\machinery\computer\prisonshuttle.dm"
#include "code\game\machinery\computer\robot.dm"
@@ -415,6 +413,7 @@
#include "code\game\magic\Uristrunes.dm"
#include "code\game\mecha\mech_bay.dm"
#include "code\game\mecha\mech_fabricator.dm"
#include "code\game\mecha\mech_sensor.dm"
#include "code\game\mecha\mecha.dm"
#include "code\game\mecha\mecha_construction_paths.dm"
#include "code\game\mecha\mecha_control_console.dm"
@@ -485,6 +484,7 @@
#include "code\game\objects\items\devices\debugger.dm"
#include "code\game\objects\items\devices\flash.dm"
#include "code\game\objects\items\devices\flashlight.dm"
#include "code\game\objects\items\devices\floor_painter.dm"
#include "code\game\objects\items\devices\lightreplacer.dm"
#include "code\game\objects\items\devices\megaphone.dm"
#include "code\game\objects\items\devices\modkit.dm"
@@ -746,6 +746,7 @@
#include "code\modules\client\client defines.dm"
#include "code\modules\client\client procs.dm"
#include "code\modules\client\preferences.dm"
#include "code\modules\client\preferences_factions.dm"
#include "code\modules\client\preferences_gear.dm"
#include "code\modules\client\preferences_savefile.dm"
#include "code\modules\client\preferences_spawnpoints.dm"
@@ -803,10 +804,11 @@
#include "code\modules\customitems\item_defines.dm"
#include "code\modules\customitems\item_spawning.dm"
#include "code\modules\destilery\main.dm"
#include "code\modules\detectivework\detective_work.dm"
#include "code\modules\detectivework\evidence.dm"
#include "code\modules\detectivework\footprints_and_rag.dm"
#include "code\modules\detectivework\forensics.dm"
#include "code\modules\detectivework\scanner.dm"
#include "code\modules\detectivework\scanning_console.dm"
#include "code\modules\economy\Accounts.dm"
#include "code\modules\economy\Accounts_DB.dm"
#include "code\modules\economy\ATM.dm"
@@ -857,7 +859,11 @@
#include "code\modules\hydroponics\grown_inedible.dm"
#include "code\modules\hydroponics\hydro_tools.dm"
#include "code\modules\hydroponics\hydro_tray.dm"
#include "code\modules\hydroponics\seed_datums.dm"
#include "code\modules\hydroponics\seed_machines.dm"
#include "code\modules\hydroponics\seed_mobs.dm"
#include "code\modules\hydroponics\seeds.dm"
#include "code\modules\hydroponics\vines.dm"
#include "code\modules\library\lib_items.dm"
#include "code\modules\library\lib_machines.dm"
#include "code\modules\library\lib_readme.dm"
@@ -982,6 +988,7 @@
#include "code\modules\mob\living\carbon\metroid\login.dm"
#include "code\modules\mob\living\carbon\metroid\metroid.dm"
#include "code\modules\mob\living\carbon\metroid\powers.dm"
#include "code\modules\mob\living\carbon\metroid\say.dm"
#include "code\modules\mob\living\carbon\metroid\subtypes.dm"
#include "code\modules\mob\living\carbon\metroid\update_icons.dm"
#include "code\modules\mob\living\carbon\monkey\death.dm"
@@ -1032,6 +1039,7 @@
#include "code\modules\mob\living\silicon\robot\laws.dm"
#include "code\modules\mob\living\silicon\robot\life.dm"
#include "code\modules\mob\living\silicon\robot\login.dm"
#include "code\modules\mob\living\silicon\robot\photos.dm"
#include "code\modules\mob\living\silicon\robot\robot.dm"
#include "code\modules\mob\living\silicon\robot\robot_damage.dm"
#include "code\modules\mob\living\silicon\robot\robot_items.dm"
@@ -1090,6 +1098,7 @@
#include "code\modules\nano\JSON Writer.dm"
#include "code\modules\nano\nanoexternal.dm"
#include "code\modules\nano\nanomanager.dm"
#include "code\modules\nano\nanomapgen.dm"
#include "code\modules\nano\nanoui.dm"
#include "code\modules\organs\blood.dm"
#include "code\modules\organs\organ.dm"
@@ -1108,6 +1117,7 @@
#include "code\modules\paperwork\pen.dm"
#include "code\modules\paperwork\photocopier.dm"
#include "code\modules\paperwork\photography.dm"
#include "code\modules\paperwork\silicon_photography.dm"
#include "code\modules\paperwork\stamps.dm"
#include "code\modules\power\apc.dm"
#include "code\modules\power\batteryrack.dm"
@@ -1122,6 +1132,9 @@
#include "code\modules\power\lighting.dm"
#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\solar.dm"
#include "code\modules\power\switch.dm"
@@ -1306,6 +1319,13 @@
#include "code\modules\scripting\Scanner\Tokens.dm"
#include "code\modules\security levels\keycard authentication.dm"
#include "code\modules\security levels\security levels.dm"
#include "code\modules\shieldgen\circuits_and_designs.dm"
#include "code\modules\shieldgen\emergency_shield.dm"
#include "code\modules\shieldgen\energy_field.dm"
#include "code\modules\shieldgen\sheldwallgen.dm"
#include "code\modules\shieldgen\shield_capacitor.dm"
#include "code\modules\shieldgen\shield_gen.dm"
#include "code\modules\shieldgen\shield_gen_external.dm"
#include "code\modules\shuttles\antagonist.dm"
#include "code\modules\shuttles\departmental.dm"
#include "code\modules\shuttles\escape_pods.dm"
@@ -1379,11 +1399,6 @@
#include "code\WorkInProgress\Cael_Aislinn\Rust\gyrotron_controller.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\radiation.dm"
#include "code\WorkInProgress\Cael_Aislinn\Rust\virtual_particle_catcher.dm"
#include "code\WorkInProgress\Cael_Aislinn\ShieldGen\circuits_and_designs.dm"
#include "code\WorkInProgress\Cael_Aislinn\ShieldGen\energy_field.dm"
#include "code\WorkInProgress\Cael_Aislinn\ShieldGen\shield_capacitor.dm"
#include "code\WorkInProgress\Cael_Aislinn\ShieldGen\shield_gen.dm"
#include "code\WorkInProgress\Cael_Aislinn\ShieldGen\shield_gen_external.dm"
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\LaserComputer.dm"
#include "code\WorkInProgress\Cael_Aislinn\Supermatter\ZeroPointLaser.dm"
#include "code\WorkInProgress\Chinsky\ashtray.dm"
@@ -1426,7 +1441,8 @@
#include "code\WorkInProgress\SkyMarshal\Ultralight_procs.dm"
#include "code\WorkInProgress\Wrongnumber\weldbackpack.dm"
#include "code\ZAS\_docs.dm"
#include "code\ZAS\_gas_mixture.dm"
#include "code\ZAS\_gas_mixture_xgm.dm"
#include "code\ZAS\_xgm_gas_data.dm"
#include "code\ZAS\Airflow.dm"
#include "code\ZAS\Atom.dm"
#include "code\ZAS\Connection.dm"
@@ -1436,6 +1452,7 @@
#include "code\ZAS\Debug.dm"
#include "code\ZAS\Diagnostic.dm"
#include "code\ZAS\Fire.dm"
#include "code\ZAS\Gas.dm"
#include "code\ZAS\Phoron.dm"
#include "code\ZAS\Turf.dm"
#include "code\ZAS\Variable Settings.dm"
+215
View File
@@ -0,0 +1,215 @@
//--------------------------------------------
// Pipe colors
//
// Add them here and to the pipe_colors list
// to automatically add them to all relevant
// atmospherics devices.
//--------------------------------------------
#define PIPE_COLOR_GREY "#ffffff" //yes white is grey
#define PIPE_COLOR_RED "#ff0000"
#define PIPE_COLOR_BLUE "#0000ff"
#define PIPE_COLOR_CYAN "#00ffff"
#define PIPE_COLOR_GREEN "#00ff00"
#define PIPE_COLOR_YELLOW "#ffcc00"
#define PIPE_COLOR_PURPLE "#5c1ec0"
var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE)
/proc/pipe_color_lookup(var/color)
for(var/C in pipe_colors)
if(color == pipe_colors[C])
return "[C]"
/proc/pipe_color_check(var/color)
if(!color)
return 1
for(var/C in pipe_colors)
if(color == pipe_colors[C])
return 1
return 0
//--------------------------------------------
// Icon cache generation
//--------------------------------------------
/datum/pipe_icon_manager
var/list/pipe_icons[]
var/list/manifold_icons[]
var/list/device_icons[]
var/list/underlays_down[]
var/list/underlays_exposed[]
var/list/underlays_intact[]
var/list/pipe_underlays_exposed[]
var/list/pipe_underlays_intact[]
var/list/omni_icons[]
/datum/pipe_icon_manager/New()
check_icons()
/datum/pipe_icon_manager/proc/get_atmos_icon(var/device, var/dir, var/color, var/state)
check_icons()
device = "[device]"
state = "[state]"
color = "[color]"
dir = "[dir]"
switch(device)
if("pipe")
return pipe_icons[state + color]
if("manifold")
return manifold_icons[state + color]
if("device")
return device_icons[state]
if("omni")
return omni_icons[state]
if("underlay_intact")
return underlays_intact[dir + color]
if("underlay_exposed")
return underlays_exposed[dir + color]
if("underlay_down")
return underlays_down[dir + color]
if("pipe_underlay_exposed")
return pipe_underlays_exposed[dir + color]
if("pipe_underlay_intact")
return pipe_underlays_intact[dir + color]
/datum/pipe_icon_manager/proc/check_icons()
if(!pipe_icons)
gen_pipe_icons()
if(!manifold_icons)
gen_manifold_icons()
if(!device_icons)
gen_device_icons()
if(!omni_icons)
gen_omni_icons()
if(!underlays_intact || !underlays_down || !underlays_exposed || !pipe_underlays_exposed || !pipe_underlays_intact)
gen_underlay_icons()
/datum/pipe_icon_manager/proc/gen_pipe_icons()
if(!pipe_icons)
pipe_icons = new()
var/icon/pipe = new('icons/atmos/pipes.dmi')
for(var/state in pipe.IconStates())
if(!state || findtext(state, "map"))
continue
var/cache_name = state
var/image/I = image('icons/atmos/pipes.dmi', icon_state = state)
pipe_icons[cache_name] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/pipes.dmi', icon_state = state)
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()
var/icon/pipe = new('icons/atmos/manifold.dmi')
for(var/state in pipe.IconStates())
if(findtext(state, "clamps"))
var/image/I = image('icons/atmos/manifold.dmi', icon_state = state)
manifold_icons[state] = I
continue
if(state == "core" || state == "4way")
var/image/I = image('icons/atmos/manifold.dmi', icon_state = state)
manifold_icons[state] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/manifold.dmi', icon_state = state)
I.color = pipe_colors[pipe_color]
manifold_icons[state + pipe_colors[pipe_color]] = I
/datum/pipe_icon_manager/proc/gen_device_icons()
if(!device_icons)
device_icons = new()
var/icon/device
device = new('icons/atmos/vent_pump.dmi')
for(var/state in device.IconStates())
if(!state || findtext(state, "map"))
continue
device_icons["vent" + state] = image('icons/atmos/vent_pump.dmi', icon_state = state)
device = new('icons/atmos/vent_scrubber.dmi')
for(var/state in device.IconStates())
if(!state || findtext(state, "map"))
continue
device_icons["scrubber" + state] = image('icons/atmos/vent_scrubber.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_omni_icons()
if(!omni_icons)
omni_icons = new()
var/icon/omni = new('icons/atmos/omni_devices.dmi')
for(var/state in omni.IconStates())
if(!state || findtext(state, "map"))
continue
omni_icons[state] = image('icons/atmos/omni_devices.dmi', icon_state = state)
/datum/pipe_icon_manager/proc/gen_underlay_icons()
if(!underlays_intact)
underlays_intact = new()
if(!underlays_exposed)
underlays_exposed = new()
if(!underlays_down)
underlays_down = new()
if(!pipe_underlays_exposed)
pipe_underlays_exposed = new()
if(!pipe_underlays_intact)
pipe_underlays_intact = new()
var/icon/pipe = new('icons/atmos/pipe_underlays.dmi')
for(var/state in pipe.IconStates())
if(state == "")
continue
for(var/D in cardinal)
var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
switch(state)
if("intact")
underlays_intact["[D]"] = I
if("exposed")
underlays_exposed["[D]"] = I
if("down")
underlays_down["[D]"] = I
if("pipe_exposed")
pipe_underlays_exposed["[D]"] = I
if("pipe_intact")
pipe_underlays_intact["[D]"] = I
for(var/pipe_color in pipe_colors)
I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
I.color = pipe_colors[pipe_color]
switch(state)
if("intact")
underlays_intact["[D]" + pipe_colors[pipe_color]] = I
if("exposed")
underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("down")
underlays_down["[D]" + pipe_colors[pipe_color]] = I
if("pipe_exposed")
pipe_underlays_exposed["[D]" + pipe_colors[pipe_color]] = I
if("pipe_intact")
pipe_underlays_intact["[D]" + pipe_colors[pipe_color]] = I
+423
View File
@@ -0,0 +1,423 @@
/*
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).
In the case of free-flowing gas you can do things with gas and still use 0 power, hence the distinction between negative and non-negative return values.
*/
/obj/machinery/atmospherics/var/last_flow_rate = 0
/obj/machinery/portable_atmospherics/var/last_flow_rate = 0
/obj/machinery/atmospherics/var/debug = 0
/obj/machinery/atmospherics/verb/toggle_debug()
set name = "Toggle Debug Messages"
set category = "Debug"
set src in view()
debug = !debug
usr << "[src]: Debug messages toggled [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.
//available_power - the maximum amount of power that may be used when moving gas. If null then the transfer is not limited by power.
/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)
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 * config.atmos_machine_heat) //1st law - energy is conserved
sink.merge(removed)
return power_draw
//Generalized gas scrubbing proc.
//Selectively moves specified gasses one gas_mixture to another and returns the amount of power needed (assuming 1 second), or -1 if no gas was filtered.
//filtering - A list of gasids to be scrubbed from source
//total_transfer_moles - Limits the amount of moles to scrub. The actual amount of gas scrubbed may also be limited by available_power, if given.
//available_power - the maximum amount of power that may be used when scrubbing gas. If null then the scrubbing is not limited by power.
/proc/scrub_gas(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink, var/total_transfer_moles = null, var/available_power = null)
if (source.total_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
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)
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
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
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 * config.atmos_machine_heat) //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
//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.
//available_power - the maximum amount of power that may be used when filtering gas. If null then the filtering is not limited by power.
/proc/filter_gas(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_filtered, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null)
if (source.total_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
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
var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
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)
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
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
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)
removed.adjust_gas(g, -removed.gas[g], update=0)
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 * config.atmos_machine_heat)
if (unfiltered_power_used > 0)
sink_clean.add_thermal_energy(unfiltered_power_used * config.atmos_machine_heat)
return filtered_power_used + unfiltered_power_used
//For omni devices. Instead filtering is an associative list mapping gasids to gas mixtures.
//I don't like the copypasta, but I decided to keep both versions of gas filtering as filter_gas is slightly faster (doesn't create as many temporary lists, doesn't call update_values() as much)
//filter_gas can be removed and replaced with this proc if need be.
/proc/filter_gas_multi(var/obj/machinery/M, var/list/filtering, var/datum/gas_mixture/source, var/datum/gas_mixture/sink_clean, var/total_transfer_moles = null, var/available_power = null)
if (source.total_moles < MINUMUM_MOLES_TO_FILTER) //if we cant transfer enough gas just stop to avoid further processing
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
var/list/specific_power_gas = list() //the power required to remove one mole of pure gas, for each gas type
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
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)
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
A.last_flow_rate = (total_transfer_moles/source.total_moles)*source.volume //group_multiplier gets divided out here
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.
sink_filtered.adjust_gas_temp(g, removed.gas[g], removed.temperature, update=1)
removed.adjust_gas(g, -removed.gas[g], update=0)
if (power_used)
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] * config.atmos_machine_heat)
if (unfiltered_power_used > 0)
sink_clean.add_thermal_energy(unfiltered_power_used * config.atmos_machine_heat)
return power_draw
//Similar deal as the other atmos process procs.
//mix_sources maps input gas mixtures to mix ratios. The mix ratios MUST add up to 1.
/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
var/total_input_moles = 0 //for flow rate calculation
var/list/source_specific_power = list()
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)
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
A.last_flow_rate = (total_transfer_moles/total_input_moles)*total_input_volume //group_multiplier gets divided out here
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 * config.atmos_machine_heat) //conservation of energy
total_power_draw += power_draw
sink.merge(removed)
return total_power_draw
/*
Helper procs for various things.
*/
//Calculates the amount of power needed to move one mole from source to sink.
/proc/calculate_specific_power(datum/gas_mixture/source, datum/gas_mixture/sink)
//Calculate the amount of energy required
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.
/proc/calculate_specific_power_gas(var/gasid, datum/gas_mixture/source, datum/gas_mixture/sink)
//Calculate the amount of energy required
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.
//Calling update_use_power() or use_power() too often will result in lag since updating area power can be costly.
//This proc implements an approximation scheme that will cause area power updates to be triggered less often.
//By having atmos machinery use this proc it is easy to change the power usage approximation for all atmos machines
/obj/machinery/proc/handle_power_draw(var/usage_amount)
//This code errs on the side of using more power. Using this will mean that sometimes atmos machines use more power than they need, but won't get power for free.
if (usage_amount > idle_power_usage)
update_use_power(2)
else
if (use_power >= 2)
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
if (2 to INFINITY) return max(idle_power_usage, usage_amount)
+59 -12
View File
@@ -9,49 +9,96 @@ Pipes -> Pipelines
Pipelines + Other Objects -> Pipe network
*/
obj/machinery/atmospherics
/obj/machinery/atmospherics
anchored = 1
idle_power_usage = 0
active_power_usage = 0
power_channel = ENVIRON
var/nodealert = 0
var/initialize_directions = 0
var/pipe_color
var/global/datum/pipe_icon_manager/icon_manager
/obj/machinery/atmospherics/New()
if(!icon_manager)
icon_manager = new()
if(!pipe_color)
pipe_color = color
color = null
if(!pipe_color_check(pipe_color))
pipe_color = null
..()
obj/machinery/atmospherics/var/initialize_directions = 0
obj/machinery/atmospherics/var/pipe_color
/obj/machinery/atmospherics/attackby(atom/A, mob/user as mob)
if(istype(A, /obj/item/device/pipe_painter))
return
..()
obj/machinery/atmospherics/process()
/obj/machinery/atmospherics/proc/add_underlay(var/turf/T, var/obj/machinery/atmospherics/node, var/direction)
if(node)
if(T.intact && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
underlays += icon_manager.get_atmos_icon("underlay_down", direction, color_cache_name(node))
else
underlays += icon_manager.get_atmos_icon("underlay_intact", direction, color_cache_name(node))
else
underlays += icon_manager.get_atmos_icon("underlay_exposed", direction, pipe_color)
/obj/machinery/atmospherics/proc/update_underlays()
if(check_icon_cache())
return 1
else
return 0
/obj/machinery/atmospherics/proc/check_icon_cache(var/safety = 0)
if(!istype(icon_manager))
if(!safety) //to prevent infinite loops
icon_manager = new()
check_icon_cache(1)
return 0
return 1
/obj/machinery/atmospherics/proc/color_cache_name(var/obj/machinery/atmospherics/node)
//Don't use this for standard pipes
if(!istype(node))
return null
return node.pipe_color
/obj/machinery/atmospherics/process()
build_network()
obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/proc/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
// Check to see if should be added to network. Add self if so and adjust variables appropriately.
// Note don't forget to have neighbors look as well!
return null
obj/machinery/atmospherics/proc/build_network()
/obj/machinery/atmospherics/proc/build_network()
// Called to build a network from this node
return null
obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/proc/return_network(obj/machinery/atmospherics/reference)
// Returns pipe_network associated with connection to reference
// Notes: should create network if necessary
// Should never return null
return null
obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
/obj/machinery/atmospherics/proc/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
// Used when two pipe_networks are combining
obj/machinery/atmospherics/proc/return_network_air(datum/network/reference)
/obj/machinery/atmospherics/proc/return_network_air(datum/network/reference)
// Return a list of gas_mixture(s) in the object
// associated with reference pipe_network for use in rebuilding the networks gases list
// Is permitted to return null
obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
/obj/machinery/atmospherics/proc/disconnect(obj/machinery/atmospherics/reference)
obj/machinery/atmospherics/update_icon()
/obj/machinery/atmospherics/update_icon()
return null
@@ -76,6 +76,7 @@ obj/machinery/atmospherics/binary
break
update_icon()
update_underlays()
build_network()
if(!network1 && node1)
@@ -127,4 +128,7 @@ obj/machinery/atmospherics/binary
del(network2)
node2 = null
update_icon()
update_underlays()
return null
@@ -1,6 +1,18 @@
#define DEFAULT_PRESSURE_DELTA 10000
#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
#define INTERNAL_PRESSURE_BOUND 0
#define PRESSURE_CHECKS 1
#define PRESSURE_CHECK_EXTERNAL 1
#define PRESSURE_CHECK_INPUT 2
#define PRESSURE_CHECK_OUTPUT 4
#undefine
/obj/machinery/atmospherics/binary/dp_vent_pump
icon = 'icons/obj/atmospherics/dp_vent_pump.dmi'
icon_state = "off"
icon = 'icons/atmos/vent_pump.dmi'
icon_state = "map_dp_vent"
//node2 is output port
//node1 is input port
@@ -10,190 +22,246 @@
level = 1
high_volume
name = "Large Dual Port Air Vent"
New()
..()
air1.volume = 1000
air2.volume = 1000
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 pump is, in Watts. 7500 W ~ 10 HP
var/last_power_draw = 0
var/on = 0
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/external_pressure_bound = ONE_ATMOSPHERE
var/input_pressure_min = 0
var/output_pressure_max = 0
var/pressure_checks = 1
//1: Do not pass external_pressure_bound
//2: Do not pass input_pressure_min
//4: Do not pass output_pressure_max
update_icon()
if(on)
if(pump_direction)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(on)
if(pump_direction)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
process()
..()
if(!on)
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/environment_pressure = environment.return_pressure()
if(pump_direction) //input -> external
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (air1.return_pressure() - input_pressure_min))
if(pressure_delta > 0)
if(air1.temperature > 0)
var/transfer_moles = pressure_delta*environment.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
loc.assume_air(removed)
if(network1)
network1.update = 1
else //external -> output
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
if(pressure_checks&4)
pressure_delta = min(pressure_delta, (output_pressure_max - air2.return_pressure()))
if(pressure_delta > 0)
if(environment.temperature > 0)
var/transfer_moles = pressure_delta*air2.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
air2.merge(removed)
if(network2)
network2.update = 1
return 1
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "ADVP",
"power" = on,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"input" = input_pressure_min,
"output" = output_pressure_max,
"external" = external_pressure_bound,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/input_pressure_min = INTERNAL_PRESSURE_BOUND
var/output_pressure_max = DEFAULT_PRESSURE_DELTA
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
var/pressure_checks = PRESSURE_CHECK_EXTERNAL
//1: Do not pass external_pressure_bound
//2: Do not pass input_pressure_min
//4: Do not pass output_pressure_max
receive_signal(datum/signal/signal)
/obj/machinery/atmospherics/binary/dp_vent_pump/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
icon = null
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power" in signal.data)
on = text2num(signal.data["power"])
/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume
name = "Large Dual Port Air Vent"
if("power_toggle" in signal.data)
on = !on
/obj/machinery/atmospherics/binary/dp_vent_pump/high_volume/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP + 800
if("direction" in signal.data)
pump_direction = text2num(signal.data["direction"])
/obj/machinery/atmospherics/binary/dp_vent_pump/update_icon(var/safety = 0)
if(!check_icon_cache())
return
if("checks" in signal.data)
pressure_checks = text2num(signal.data["checks"])
overlays.Cut()
var/vent_icon = "vent"
if("purge" in signal.data)
pressure_checks &= ~1
pump_direction = 0
var/turf/T = get_turf(src)
if(!istype(T))
return
if("stabalize" in signal.data)
pressure_checks |= 1
pump_direction = 1
if(T.intact && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
vent_icon += "h"
if(!powered())
vent_icon += "off"
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
if("set_input_pressure" in signal.data)
input_pressure_min = between(
0,
text2num(signal.data["set_input_pressure"]),
ONE_ATMOSPHERE*50
)
overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
if("set_output_pressure" in signal.data)
output_pressure_max = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
/obj/machinery/atmospherics/binary/dp_vent_pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && node1 && node2 && node1.level == 1 && node2.level == 1 && istype(node1, /obj/machinery/atmospherics/pipe) && istype(node2, /obj/machinery/atmospherics/pipe))
return
else
add_underlay(T, node1, turn(dir, -180))
add_underlay(T, node2, dir)
if("set_external_pressure" in signal.data)
external_pressure_bound = between(
0,
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
/obj/machinery/atmospherics/binary/dp_vent_pump/hide(var/i)
update_icon()
update_underlays()
if("status" in signal.data)
spawn(2)
broadcast_status()
return //do not update_icon
//if(signal.data["tag"])
/obj/machinery/atmospherics/binary/dp_vent_pump/process()
..()
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_power_draw = 0
last_flow_rate = 0
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/power_draw = -1
//Figure out the target pressure difference
var/pressure_delta = get_pressure_delta(environment)
if(pressure_delta > 0.5)
if(pump_direction) //internal -> external
if (node1 && (environment.temperature || air1.temperature))
var/output_volume = environment.volume * environment.group_multiplier
var/air_temperature = environment.temperature? environment.temperature : air1.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
power_draw = pump_gas(src, air1, environment, transfer_moles, active_power_usage)
if(power_draw >= 0 && network1)
network1.update = 1
else //external -> internal
if (node2 && (environment.temperature || air2.temperature))
var/output_volume = air2.volume + (network2? network2.volume : 0)
var/air_temperature = air2.temperature? air2.temperature : environment.temperature
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*air2.volume/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air2, transfer_moles, active_power_usage)
if(power_draw >= 0 && network2)
network2.update = 1
if (power_draw < 0)
last_power_draw = 0
last_flow_rate = 0
//update_use_power(0)
use_power = 0 //don't force update - easier on CPU
else
last_power_draw = handle_power_draw(power_draw)
return 1
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
var/pressure_delta = DEFAULT_PRESSURE_DELTA
var/environment_pressure = environment.return_pressure()
if(pump_direction) //internal -> external
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INPUT)
pressure_delta = min(pressure_delta, air1.return_pressure() - input_pressure_min) //decreasing the pressure here
else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
if(pressure_checks & PRESSURE_CHECK_OUTPUT)
pressure_delta = min(pressure_delta, output_pressure_max - air2.return_pressure()) //increasing the pressure here
return pressure_delta
//Radio remote control
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/dp_vent_pump/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "ADVP",
"power" = on,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"input" = input_pressure_min,
"output" = output_pressure_max,
"external" = external_pressure_bound,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/binary/dp_vent_pump/initialize()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/binary/dp_vent_pump/examine()
set src in oview(1)
..()
if (get_dist(usr, src) <= 1)
usr << "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W"
/obj/machinery/atmospherics/unary/vent_pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/binary/dp_vent_pump/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"])
on = text2num(signal.data["power"])
if(signal.data["power_toggle"])
on = !on
if(signal.data["direction"])
pump_direction = text2num(signal.data["direction"])
if(signal.data["checks"])
pressure_checks = text2num(signal.data["checks"])
if(signal.data["purge"])
pressure_checks &= ~1
pump_direction = 0
if(signal.data["stabalize"])
pressure_checks |= 1
pump_direction = 1
if(signal.data["set_input_pressure"])
input_pressure_min = between(
0,
text2num(signal.data["set_input_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_output_pressure"])
output_pressure_max = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_external_pressure"])
external_pressure_bound = between(
0,
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["status"])
spawn(2)
broadcast_status()
update_icon()
return //do not update_icon
spawn(2)
broadcast_status()
update_icon()
@@ -1,188 +1,264 @@
obj/machinery/atmospherics/binary/passive_gate
//Tries to achieve target pressure at output (like a normal pump) except
// Uses no power but can not transfer gases from a low pressure area to a high pressure area
icon = 'icons/obj/atmospherics/passive_gate.dmi'
icon_state = "intact_off"
#define REGULATE_NONE 0
#define REGULATE_INPUT 1 //shuts off when input side is below the target pressure
#define REGULATE_OUTPUT 2 //shuts off when output side is above the target pressure
name = "Passive gate"
desc = "A one-way air valve that does not require power"
#undefine
var/on = 0
/obj/machinery/atmospherics/binary/passive_gate
icon = 'icons/atmos/passive_gate.dmi'
icon_state = "map"
level = 1
name = "pressure regulator"
desc = "A one-way air valve that can be used to regulate input or output pressure, and flow rate. Does not require power."
use_power = 0
var/on = 0 //doesn't actually use power. this is just whether the valve is open or not
var/target_pressure = ONE_ATMOSPHERE
var/max_pressure_setting = 15000 //kPa
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
var/regulate_mode = REGULATE_OUTPUT
var/flowing = 0 //for icons - becomes zero if the valve closes itself due to regulation mode
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
update_icon()
if(stat & NOPOWER)
icon_state = "intact_off"
else if(node1 && node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
return
/obj/machinery/atmospherics/binary/passive_gate/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP * 2.5
process()
..()
if(!on)
return 0
/obj/machinery/atmospherics/binary/passive_gate/update_icon()
icon_state = (on && flowing)? "on" : "off"
var/output_starting_pressure = air2.return_pressure()
var/input_starting_pressure = air1.return_pressure()
/obj/machinery/atmospherics/binary/passive_gate/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, 180))
add_underlay(T, node2, dir)
if(output_starting_pressure >= min(target_pressure,input_starting_pressure-10))
//No need to pump gas if target is already reached or input pressure is too low
//Need at least 10 KPa difference to overcome friction in the mechanism
return 1
/obj/machinery/atmospherics/binary/passive_gate/hide(var/i)
update_underlays()
//Calculate necessary moles to transfer using PV = nRT
if((air1.total_moles() > 0) && (air1.temperature>0))
var/pressure_delta = min(target_pressure - output_starting_pressure, (input_starting_pressure - output_starting_pressure)/2)
//Can not have a pressure delta that would cause output_pressure > input_pressure
/obj/machinery/atmospherics/binary/passive_gate/process()
..()
if(!on)
last_flow_rate = 0
return 0
var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
air2.merge(removed)
var/output_starting_pressure = air2.return_pressure()
var/input_starting_pressure = air1.return_pressure()
var/pressure_delta
switch (regulate_mode)
if (REGULATE_INPUT)
pressure_delta = input_starting_pressure - target_pressure
if (REGULATE_OUTPUT)
pressure_delta = target_pressure - output_starting_pressure
var/flowing_old = flowing
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
var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
//Figure out how much gas to transfer to meet the target pressure.
switch (regulate_mode)
if (REGULATE_INPUT)
var/air_temperature = (air1.temperature > 0)? air1.temperature : air2.temperature
var/input_volume = air1.volume + (network1? network1.volume : 0)
transfer_moles = min(transfer_moles, pressure_delta*input_volume/(air_temperature * R_IDEAL_GAS_EQUATION))
if (REGULATE_OUTPUT)
var/air_temperature = (air2.temperature > 0)? air2.temperature : air1.temperature
var/output_volume = air2.volume + (network2? network2.volume : 0)
transfer_moles = min(transfer_moles, pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION))
//pump_gas() will return a negative number if no flow occurred
var/flow = pump_gas(src, air1, air2, transfer_moles, available_power=0) //available_power=0 means we only move gas if it would flow naturally
if (flow >= 0)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
else
flowing = 0
last_flow_rate = 0
if (flowing != flowing_old)
update_icon()
//Radio remote control
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
/obj/machinery/atmospherics/binary/passive_gate/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
broadcast_status()
if(!radio_connection)
return 0
/obj/machinery/atmospherics/binary/passive_gate/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = on,
"target_output" = target_pressure,
"sigtype" = "status"
)
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = on,
"target_output" = target_pressure,
"regulate_mode" = regulate_mode,
"set_flow_rate" = set_flow_rate,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
return 1
return 1
interact(mob/user as mob)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[on?"On":"Off"]</a><br>
<b>Desirable output pressure: </b>
[round(target_pressure,0.1)]kPa | <a href='?src=\ref[src];set_press=1'>Change</a>
"}
/obj/machinery/atmospherics/binary/passive_gate/initialize()
..()
if(frequency)
set_frequency(frequency)
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_pump")
onclose(user, "atmo_pump")
/obj/machinery/atmospherics/binary/passive_gate/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
initialize()
..()
if(frequency)
set_frequency(frequency)
if("power" in signal.data)
on = text2num(signal.data["power"])
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power_toggle" in signal.data)
on = !on
if("power" in signal.data)
on = text2num(signal.data["power"])
if("set_target_pressure" in signal.data)
target_pressure = between(
0,
text2num(signal.data["set_target_pressure"]),
max_pressure_setting
)
if("power_toggle" in signal.data)
on = !on
if("set_regulate_mode" in signal.data)
regulate_mode = text2num(signal.data["set_regulate_mode"])
if("set_output_pressure" in signal.data)
target_pressure = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if("status" in signal.data)
spawn(2)
broadcast_status()
return //do not update_icon
if("set_flow_rate" in signal.data)
regulate_mode = text2num(signal.data["set_flow_rate"])
if("status" in signal.data)
spawn(2)
broadcast_status()
update_icon()
return //do not update_icon
spawn(2)
broadcast_status()
update_icon()
return
/obj/machinery/atmospherics/binary/passive_gate/attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
ui_interact(user)
return
/obj/machinery/atmospherics/binary/passive_gate/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
// this is the data which will be sent to the ui
var/data[0]
data = list(
"on" = on,
"pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
"max_pressure" = max_pressure_setting,
"input_pressure" = round(air1.return_pressure()*100),
"output_pressure" = round(air2.return_pressure()*100),
"regulate_mode" = regulate_mode,
"set_flow_rate" = round(set_flow_rate*10),
"last_flow_rate" = round(last_flow_rate*10),
)
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "pressure_regulator.tmpl", name, 470, 370)
ui.set_initial_data(data) // when the ui is first opened this is the data it will use
ui.open() // open the new ui window
ui.set_auto_update(1) // auto update every Master Controller tick
attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
interact(user)
return
Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
if(href_list["set_press"])
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num
src.target_pressure = max(0, min(4500, new_pressure))
usr.set_machine(src)
src.update_icon()
src.updateUsrDialog()
return
power_change()
..()
update_icon()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/binary/passive_gate/Topic(href,href_list)
if(..()) return
if(href_list["toggle_valve"])
on = !on
if(href_list["regulate_mode"])
switch(href_list["regulate_mode"])
if ("off") regulate_mode = REGULATE_NONE
if ("input") regulate_mode = REGULATE_INPUT
if ("output") regulate_mode = REGULATE_OUTPUT
switch(href_list["set_press"])
if ("min")
target_pressure = 0
if ("max")
target_pressure = max_pressure_setting
if ("set")
var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure Control",src.target_pressure) as num
src.target_pressure = between(0, new_pressure, max_pressure_setting)
switch(href_list["set_flow_rate"])
if ("min")
set_flow_rate = 0
if ("max")
set_flow_rate = air1.volume
if ("set")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[air1.volume]kPa)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = between(0, new_flow_rate, air1.volume)
usr.set_machine(src) //Is this even needed with NanoUI?
src.update_icon()
src.add_fingerprint(usr)
return
/obj/machinery/atmospherics/binary/passive_gate/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
@@ -12,194 +12,238 @@ Thus, the two variables affect pump operation are set in New():
but overall network volume is also increased as this increases...
*/
obj/machinery/atmospherics/binary/pump
icon = 'icons/obj/atmospherics/pump.dmi'
icon_state = "intact_off"
/obj/machinery/atmospherics/binary/pump
icon = 'icons/atmos/pump.dmi'
icon_state = "map_off"
level = 1
name = "Gas pump"
name = "gas pump"
desc = "A pump"
var/on = 0
var/target_pressure = ONE_ATMOSPHERE
//var/max_volume_transfer = 10000
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 pump is, in Watts. 7500 W ~ 10 HP
var/last_power_draw = 0 //for UI
var/max_pressure_setting = 15000 //kPa
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
highcap
name = "High capacity gas pump"
desc = "A high capacity pump"
/obj/machinery/atmospherics/binary/pump/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_PUMP
air2.volume = ATMOS_DEFAULT_VOLUME_PUMP
target_pressure = 15000000
/obj/machinery/atmospherics/binary/pump/on
icon_state = "map_on"
on = 1
on
on = 1
icon_state = "intact_on"
update_icon()
if(stat & NOPOWER)
icon_state = "intact_off"
else if(node1 && node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
/obj/machinery/atmospherics/binary/pump/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[on ? "on" : "off"]"
/obj/machinery/atmospherics/binary/pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
add_underlay(T, node2, dir)
/obj/machinery/atmospherics/binary/pump/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/binary/pump/process()
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_power_draw = 0
last_flow_rate = 0
return
process()
// ..()
if(stat & (NOPOWER|BROKEN))
return
if(!on)
return 0
var/power_draw = -1
var/pressure_delta = target_pressure - air2.return_pressure()
var/output_starting_pressure = air2.return_pressure()
if(pressure_delta > 0.01 && air1.temperature > 0)
//Figure out how much gas to transfer to meet the target pressure.
var/air_temperature = (air2.temperature > 0)? air2.temperature : air1.temperature
var/output_volume = air2.volume + (network2? network2.volume : 0)
//get the number of moles that would have to be transfered to bring sink to the target pressure
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
power_draw = pump_gas(src, air1, air2, transfer_moles, active_power_usage)
if (power_draw < 0)
//update_use_power(0)
use_power = 0 //don't force update - easier on CPU
last_power_draw = 0
last_flow_rate = 0
else
last_power_draw = handle_power_draw(power_draw)
if(network1)
network1.update = 1
if( (target_pressure - output_starting_pressure) < 0.01)
//No need to pump gas if target is already reached!
return 1
if(network2)
network2.update = 1
//Calculate necessary moles to transfer using PV=nRT
if((air1.total_moles() > 0) && (air1.temperature>0))
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles = pressure_delta*air2.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
return 1
//Actually transfer the gas
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
air2.merge(removed)
//Radio remote control
if(network1)
network1.update = 1
/obj/machinery/atmospherics/binary/pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
if(network2)
network2.update = 1
/obj/machinery/atmospherics/binary/pump/proc/broadcast_status()
if(!radio_connection)
return 0
return 1
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
//Radio remote control
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = on,
"target_output" = target_pressure,
"sigtype" = "status"
)
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, filter = RADIO_ATMOSIA)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
broadcast_status()
if(!radio_connection)
return 0
return 1
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
/obj/machinery/atmospherics/binary/pump/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(stat & (BROKEN|NOPOWER))
return
signal.data = list(
"tag" = id,
"device" = "AGP",
"power" = on,
"target_output" = target_pressure,
"sigtype" = "status"
)
// this is the data which will be sent to the ui
var/data[0]
data = list(
"on" = on,
"pressure_set" = round(target_pressure*100), //Nano UI can't handle rounded non-integers, apparently.
"max_pressure" = max_pressure_setting,
"last_flow_rate" = round(last_flow_rate*10),
"last_power_draw" = round(last_power_draw),
"max_power_draw" = active_power_usage,
)
radio_connection.post_signal(src, signal, filter = RADIO_ATMOSIA)
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "gas_pump.tmpl", name, 470, 290)
ui.set_initial_data(data) // when the ui is first opened this is the data it will use
ui.open() // open the new ui window
ui.set_auto_update(1) // auto update every Master Controller tick
return 1
/obj/machinery/atmospherics/binary/pump/initialize()
..()
if(frequency)
set_frequency(frequency)
interact(mob/user as mob)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[on?"On":"Off"]</a><br>
<b>Desirable output pressure: </b>
[round(target_pressure,0.1)]kPa | <a href='?src=\ref[src];set_press=1'>Change</a>
"}
/obj/machinery/atmospherics/binary/pump/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_pump")
onclose(user, "atmo_pump")
if(signal.data["power"])
if(text2num(signal.data["power"]))
on = 1
else
on = 0
initialize()
..()
if(frequency)
set_frequency(frequency)
if("power_toggle" in signal.data)
on = !on
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power" in signal.data)
on = text2num(signal.data["power"])
if("power_toggle" in signal.data)
on = !on
if("set_output_pressure" in signal.data)
target_pressure = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if("status" in signal.data)
spawn(2)
broadcast_status()
return //do not update_icon
if(signal.data["set_output_pressure"])
target_pressure = between(
0,
text2num(signal.data["set_output_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["status"])
spawn(2)
broadcast_status()
update_icon()
return //do not update_icon
spawn(2)
broadcast_status()
update_icon()
return
/obj/machinery/atmospherics/binary/pump/attack_hand(user as mob)
if(..())
return
attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
interact(user)
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
ui_interact(user)
return
Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
if(href_list["set_press"])
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num
src.target_pressure = max(0, min(4500, new_pressure))
usr.set_machine(src)
src.update_icon()
src.updateUsrDialog()
return
/obj/machinery/atmospherics/binary/pump/Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
switch(href_list["set_press"])
if ("min")
target_pressure = 0
if ("max")
target_pressure = max_pressure_setting
if ("set")
var/new_pressure = input(usr,"Enter new output pressure (0-[max_pressure_setting]kPa)","Pressure control",src.target_pressure) as num
src.target_pressure = between(0, new_pressure, max_pressure_setting)
usr.set_machine(src)
src.add_fingerprint(usr)
src.update_icon()
power_change()
..()
/obj/machinery/atmospherics/binary/pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/binary/pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
@@ -1,199 +1,19 @@
/*
Every cycle, the pump uses the air in air_in to try and make air_out the perfect pressure.
/obj/machinery/atmospherics/binary/pump/high_power
icon = 'icons/atmos/volume_pump.dmi'
icon_state = "map_off"
level = 1
node1, air1, network1 correspond to input
node2, air2, network2 correspond to output
name = "high power gas pump"
desc = "A pump. Has double the power rating of the standard gas pump."
Thus, the two variables affect pump operation are set in New():
air1.volume
This is the volume of gas available to the pump that may be transfered to the output
air2.volume
Higher quantities of this cause more air to be perfected later
but overall network volume is also increased as this increases...
*/
active_power_usage = 15000 //This also doubles as a measure of how powerful the pump is, in Watts. 15000 W ~ 20 HP
obj/machinery/atmospherics/binary/volume_pump
icon = 'icons/obj/atmospherics/volume_pump.dmi'
icon_state = "intact_off"
name = "Volumetric gas pump"
desc = "A volumetric pump"
var/on = 0
var/transfer_rate = 200
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
on
on = 1
icon_state = "intact_on"
update_icon()
if(stat & NOPOWER)
icon_state = "intact_off"
else if(node1 && node2)
icon_state = "intact_[on?("on"):("off")]"
else
if(node1)
icon_state = "exposed_1_off"
else if(node2)
icon_state = "exposed_2_off"
else
icon_state = "exposed_3_off"
return
process()
// ..()
if(stat & (NOPOWER|BROKEN))
return
if(!on)
return 0
// Pump mechanism just won't do anything if the pressure is too high/too low
var/input_starting_pressure = air1.return_pressure()
var/output_starting_pressure = air2.return_pressure()
if((input_starting_pressure < 0.01) || (output_starting_pressure > 9000))
return 1
var/transfer_ratio = max(1, transfer_rate/air1.volume)
var/datum/gas_mixture/removed = air1.remove_ratio(transfer_ratio)
air2.merge(removed)
if(network1)
network1.update = 1
if(network2)
network2.update = 1
return 1
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency)
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "APV",
"power" = on,
"transfer_rate" = transfer_rate,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal)
return 1
interact(mob/user as mob)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[on?"On":"Off"]</a><br>
<b>Desirable output flow: </b>
[round(transfer_rate,1)]l/s | <a href='?src=\ref[src];set_transfer_rate=1'>Change</a>
"}
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_pump")
onclose(user, "atmo_pump")
initialize()
..()
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power" in signal.data)
on = text2num(signal.data["power"])
if("power_toggle" in signal.data)
on = !on
if("set_transfer_rate" in signal.data)
transfer_rate = between(
0,
text2num(signal.data["set_transfer_rate"]),
air1.volume
)
if("status" in signal.data)
spawn(2)
broadcast_status()
return //do not update_icon
spawn(2)
broadcast_status()
update_icon()
attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
interact(user)
return
Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
if(href_list["set_transfer_rate"])
var/new_transfer_rate = input(usr,"Enter new output volume (0-200l/s)","Flow control",src.transfer_rate) as num
src.transfer_rate = max(0, min(200, new_transfer_rate))
usr.set_machine(src)
src.update_icon()
src.updateUsrDialog()
return
power_change()
..()
update_icon()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/binary/pump/high_power/on
on = 1
icon_state = "map_on"
/obj/machinery/atmospherics/binary/pump/high_power/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[on ? "on" : "off"]"
@@ -11,33 +11,6 @@
#define ATM_P 6 //Phoron
#define ATM_N2O 7
//--------------------------------------------
// Omni device cached icon list
//--------------------------------------------
var/global/list/omni_icons[]
/proc/gen_omni_icons()
omni_icons = new()
var/icon/omni = new('icons/obj/atmospherics/omni_devices.dmi')
for(var/state in omni.IconStates())
if(!state || findtext(state, "map"))
continue
var/image/I = image('icons/obj/atmospherics/omni_devices.dmi', icon_state = state)
if(findtext(state, "pipe"))
for(var/pipe_color in pipe_colors)
I = image('icons/obj/atmospherics/omni_devices.dmi', icon_state = state)
I.color = pipe_colors[pipe_color]
var/cache_name = state
if(I.color)
cache_name += "_[pipe_colors[pipe_color]]"
omni_icons[cache_name] = I
else
omni_icons[state] = I
//--------------------------------------------
// Omni port datum
//
@@ -83,16 +56,6 @@ var/global/list/omni_icons[]
// Need to find somewhere else for these
//--------------------------------------------
#define PIPE_COLOR_RED "#ff0000"
#define PIPE_COLOR_BLUE "#0000ff"
#define PIPE_COLOR_CYAN "#00ffff"
#define PIPE_COLOR_GREEN "#00ff00"
#define PIPE_COLOR_YELLOW "#ffcc00"
#define PIPE_COLOR_PURPLE "#5c1ec0"
var/global/list/pipe_colors = list("grey" = null, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE)
//returns a text string based on the direction flag input
// if capitalize is true, it will return the string capitalized
// otherwise it will return the direction string in lower case
@@ -127,4 +90,20 @@ var/global/list/pipe_colors = list("grey" = null, "red" = PIPE_COLOR_RED, "blue"
if("west")
return WEST
else
return 0
return 0
/proc/mode_to_gasid(var/mode)
switch(mode)
if(ATM_O2)
return "oxygen"
if(ATM_N2)
return "nitrogen"
if(ATM_CO2)
return "carbon_dioxide"
if(ATM_P)
return "phoron"
if(ATM_N2O)
return "sleeping_agent"
else
return null
@@ -8,6 +8,21 @@
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()
..()
rebuild_filtering_list()
for(var/datum/omni_port/P in ports)
P.air.volume = ATMOS_DEFAULT_VOLUME_FILTER
/obj/machinery/atmospherics/omni/filter/Del()
input = null
@@ -37,89 +52,56 @@
/obj/machinery/atmospherics/omni/filter/error_check()
if(!input || !output || !filters)
return 1
if(filters.len < 1 || filters.len > 2) //requires 1 or 2 filters ~otherwise why are you using a filter?
if(filters.len < 1) //requires at least 1 filter ~otherwise why are you using a filter?
return 1
return 0
/obj/machinery/atmospherics/omni/filter/process()
..()
if(!on)
return 0
if(error_check())
on = 0
if(!input || !output)
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/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*
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure)
return
for(var/datum/omni_port/P in filters)
if(P.air.return_pressure() >= target_pressure)
return
var/pressure_delta = target_pressure - output_pressure
if(input_air.return_temperature() > 0)
input.transfer_moles = pressure_delta * output_air.volume / (input_air.return_temperature() * R_IDEAL_GAS_EQUATION)
if(input.transfer_moles > 0)
var/datum/gas_mixture/removed = input_air.remove(input.transfer_moles)
//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(!removed)
return
for(var/datum/omni_port/P in filters)
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.return_temperature()
switch(P.mode)
if(ATM_O2)
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(ATM_N2)
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(ATM_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(ATM_P)
filtered_out.phoron = removed.phoron
removed.phoron = 0
if(ATM_N2O)
if(removed.trace_gases.len>0)
for(var/datum/gas/sleeping_agent/trace_gas in removed.trace_gases)
if(istype(trace_gas))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
else
filtered_out = null
P.air.merge(filtered_out)
if(P.network)
P.network.update = 1
output_air.merge(removed)
if(output.network)
output.network.update = 1
input.transfer_moles = 0
if(input.network)
input.network.update = 1
if(output.network)
output.network.update = 1
for(var/datum/omni_port/P in filters)
if(P.network)
P.network.update = 1
return 1
return
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
/obj/machinery/atmospherics/omni/filter/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
usr.set_machine(src)
var/list/data = new()
data = build_uidata()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_filter.tmpl", "Omni Filter Control", 330, 330)
@@ -161,7 +143,8 @@
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals.
data["last_flow_rate"] = round(last_flow_rate*10)
return data
@@ -196,9 +179,9 @@
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("set_flow_rate")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), mode_return_switch(href_list["mode"]))
if("switch_filter")
@@ -257,6 +240,7 @@
target_port.mode = mode
if(target_port.mode != previous_mode)
handle_port_change(target_port)
rebuild_filtering_list()
else
return
else
@@ -268,9 +252,16 @@
P.mode = previous_mode
if(P.mode != old_mode)
handle_port_change(P)
update_ports()
/obj/machinery/atmospherics/omni/filter/proc/rebuild_filtering_list()
filtering_outputs.Cut()
for(var/datum/omni_port/P in ports)
var/gasid = mode_to_gasid(P.mode)
if(gasid)
filtering_outputs[gasid] = P.air
/obj/machinery/atmospherics/omni/filter/proc/handle_port_change(var/datum/omni_port/P)
switch(P.mode)
if(ATM_NONE)
@@ -5,14 +5,23 @@
name = "omni gas mixer"
icon_state = "map_mixer"
use_power = 1
idle_power_usage = 150 //internal circuitry, friction losses and stuff
active_power_usage = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
var/list/inputs = new()
var/datum/omni_port/output
//setup tags for initial concentration values (must be decimal)
var/tag_north_con
var/tag_north_con
var/tag_south_con
var/tag_east_con
var/tag_west_con
var/max_flow_rate = 200
var/set_flow_rate = 200
var/list/mixing_inputs = list()
/obj/machinery/atmospherics/omni/mixer/New()
..()
@@ -36,13 +45,11 @@
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
//mappers who are bad at maths will be punished (total concentration must be 100%)
if(con != 1)
tag_north_con = null
tag_south_con = null
tag_east_con = null
tag_west_con = null
rebuild_mixing_inputs()
/obj/machinery/atmospherics/omni/mixer/Del()
inputs.Cut()
@@ -57,7 +64,6 @@
if(inputs.Find(P))
inputs -= P
P.air.volume = 200
switch(P.mode)
if(ATM_INPUT)
inputs += P
@@ -69,7 +75,7 @@
P.concentration = 1 / max(1, inputs.len)
if(output)
output.air.volume *= 0.75 * inputs.len
output.air.volume = ATMOS_DEFAULT_VOLUME_MIXER * 0.75 * inputs.len
output.concentration = 1
/obj/machinery/atmospherics/omni/mixer/proc/mapper_set()
@@ -78,73 +84,62 @@
/obj/machinery/atmospherics/omni/mixer/error_check()
if(!output || !inputs)
return 1
if(inputs.len < 2 || inputs.len > 3) //requires 2 or 3 inputs ~otherwise why are you using a mixer?
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(!on)
return 0
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
//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)
var/datum/gas_mixture/output_air = output.air
var/output_pressure = output_air.return_pressure()
if(output_pressure >= target_pressure * 0.999)
//No need to mix if target is already full! - 0.1% margin of error so we minimize processing minor gas volumes
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_pressure
for(var/datum/omni_port/P in inputs)
if(P.air.return_temperature() > 0)
P.transfer_moles = (P.concentration * pressure_delta) * output_air.return_volume() / (P.air.return_temperature() * R_IDEAL_GAS_EQUATION)
var/ratio_check = null
for(var/datum/omni_port/P in inputs)
if(!P.transfer_moles)
return
if(P.air.total_moles() < P.transfer_moles)
ratio_check = 1
continue
if(ratio_check)
var/list/ratio_list = new()
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)
for(var/datum/omni_port/P in inputs)
ratio_list.Add(P.air.total_moles() / P.transfer_moles)
var/ratio = min(ratio_list)
for(var/datum/omni_port/P in inputs)
P.transfer_moles *= ratio
for(var/datum/omni_port/P in inputs)
if(P.transfer_moles > 0)
output_air.merge(P.air.remove(P.transfer_moles))
if(P.network)
if(P.concentration && P.network)
P.network.update = 1
P.transfer_moles = 0
if(output.network)
output.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)
/obj/machinery/atmospherics/omni/mixer/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
usr.set_machine(src)
var/list/data = new()
data = build_uidata()
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "omni_mixer.tmpl", "Omni Mixer Control", 360, 330)
@@ -180,7 +175,8 @@
if(portData.len)
data["ports"] = portData
if(output)
data["pressure"] = target_pressure
data["set_flow_rate"] = round(set_flow_rate*10) //because nanoui can't handle rounded decimals.
data["last_flow_rate"] = round(last_flow_rate*10)
return data
@@ -201,9 +197,9 @@
//only allows config changes when in configuring mode ~otherwise you'll get weird pressure stuff going on
if(configuring && !on)
switch(href_list["command"])
if("set_pressure")
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",target_pressure) as num
target_pressure = between(0, new_pressure, 4500)
if("set_flow_rate")
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",set_flow_rate) as num
set_flow_rate = between(0, new_flow_rate, max_flow_rate)
if("switch_mode")
switch_mode(dir_flag(href_list["dir"]), href_list["mode"])
if("switch_con")
@@ -253,6 +249,7 @@
P.update = 1
update_ports()
rebuild_mixing_inputs()
/obj/machinery/atmospherics/omni/mixer/proc/change_concentration(var/port = NORTH)
tag_north_con = null
@@ -294,6 +291,13 @@
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()
mixing_inputs.Cut()
for(var/datum/omni_port/P in inputs)
mixing_inputs[P.air] = P.concentration
/obj/machinery/atmospherics/omni/mixer/proc/con_lock(var/port = NORTH)
for(var/datum/omni_port/P in inputs)
@@ -3,14 +3,15 @@
//--------------------------------------------
/obj/machinery/atmospherics/omni
name = "omni device"
icon = 'icons/obj/atmospherics/omni_devices.dmi'
icon = 'icons/atmos/omni_devices.dmi'
icon_state = "base"
use_power = 1
initialize_directions = 0
level = 1
var/on = 0
var/configuring = 0
var/target_pressure = ONE_ATMOSPHERE
//var/target_pressure = ONE_ATMOSPHERE //a base type as abstract as this should NOT be making these kinds of assumptions
var/tag_north = ATM_NONE
var/tag_south = ATM_NONE
@@ -70,12 +71,6 @@
update_icon()
/obj/machinery/atmospherics/omni/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if(istype(W, /obj/item/device/pipe_painter)) //for updating the color of connected pipe ends
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
return
if(!istype(W, /obj/item/weapon/wrench))
return ..()
@@ -106,8 +101,8 @@
return
/obj/machinery/atmospherics/omni/proc/build_icons()
if(!omni_icons)
gen_omni_icons()
if(!check_icon_cache())
return
var/core_icon = null
if(istype(src, /obj/machinery/atmospherics/omni/mixer))
@@ -119,13 +114,16 @@
//directional icons are layers 1-4, with the core icon on layer 5
if(core_icon)
overlays_off[5] = omni_icons[core_icon]
overlays_on[5] = omni_icons[core_icon + "_glow"]
overlays_off[5] = icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_on[5] = icon_manager.get_atmos_icon("omni", , , core_icon + "_glow")
overlays_error[1] = omni_icons[core_icon]
overlays_error[2] = omni_icons["error"]
overlays_error[1] = icon_manager.get_atmos_icon("omni", , , core_icon)
overlays_error[2] = icon_manager.get_atmos_icon("omni", , , "error")
/obj/machinery/atmospherics/omni/proc/update_port_icons()
if(!check_icon_cache())
return
for(var/datum/omni_port/P in ports)
if(P.update)
var/ref_layer = 0
@@ -145,11 +143,11 @@
var/list/port_icons = select_port_icons(P)
if(port_icons)
if(P.node)
underlays_current[ref_layer] = omni_icons[port_icons["pipe_icon"]]
underlays_current[ref_layer] = port_icons["pipe_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = omni_icons[port_icons["off_icon"]]
overlays_on[ref_layer] = omni_icons[port_icons["on_icon"]]
overlays_off[ref_layer] = port_icons["off_icon"]
overlays_on[ref_layer] = port_icons["on_icon"]
else
underlays_current[ref_layer] = null
overlays_off[ref_layer] = null
@@ -175,14 +173,29 @@
if(ATM_O2 to ATM_N2O)
ic_on += "_filter"
ic_off += "_out"
var/pipe_state = ic_dir + "_pipe"
if(P.node)
if(P.node.color)
pipe_state += "_[P.node.color]"
ic_on = icon_manager.get_atmos_icon("omni", , , ic_on)
ic_off = icon_manager.get_atmos_icon("omni", , , ic_off)
var/pipe_state
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && istype(P.node, /obj/machinery/atmospherics/pipe) && P.node.level == 1 )
pipe_state = icon_manager.get_atmos_icon("underlay_down", P.dir, color_cache_name(P.node))
else
pipe_state = icon_manager.get_atmos_icon("underlay_intact", P.dir, color_cache_name(P.node))
return list("on_icon" = ic_on, "off_icon" = ic_off, "pipe_icon" = pipe_state)
/obj/machinery/atmospherics/omni/update_underlays()
for(var/datum/omni_port/P in ports)
P.update = 1
update_ports()
/obj/machinery/atmospherics/omni/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/omni/proc/update_ports()
sort_ports()
update_port_icons()
@@ -1,6 +1,6 @@
/obj/machinery/atmospherics/portables_connector
icon = 'icons/obj/atmospherics/portables_connector.dmi'
icon_state = "intact"
icon = 'icons/atmos/connector.dmi'
icon_state = "map_connector"
name = "Connector Port"
desc = "For connecting portables devices related to atmospherics control."
@@ -16,142 +16,139 @@
var/on = 0
use_power = 0
level = 0
level = 1
New()
initialize_directions = dir
..()
/obj/machinery/atmospherics/portables_connector/New()
initialize_directions = dir
..()
update_icon()
if(node)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
dir = get_dir(src, node)
else
icon_state = "exposed"
/obj/machinery/atmospherics/portables_connector/update_icon()
icon_state = "connector"
/obj/machinery/atmospherics/portables_connector/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node, dir)
/obj/machinery/atmospherics/portables_connector/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/portables_connector/process()
..()
if(!on)
return
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(node)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]intact"
dir = get_dir(src, node)
else
icon_state = "exposed"
process()
..()
if(!on)
return
if(!connected_device)
on = 0
return
if(network)
network.update = 1
return 1
if(!connected_device)
on = 0
return
if(network)
network.update = 1
return 1
// Housekeeping and pipe network stuff below
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
/obj/machinery/atmospherics/portables_connector/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node)
network = new_network
if(new_network.normal_members.Find(src))
return 0
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
new_network.normal_members += src
return null
return null
Del()
loc = null
/obj/machinery/atmospherics/portables_connector/Del()
loc = null
if(connected_device)
connected_device.disconnect()
if(connected_device)
connected_device.disconnect()
if(node)
node.disconnect(src)
del(network)
if(node)
node.disconnect(src)
del(network)
node = null
node = null
..()
..()
initialize()
if(node) return
/obj/machinery/atmospherics/portables_connector/initialize()
if(node) return
var/node_connect = dir
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
update_icon()
update_icon()
update_underlays()
/obj/machinery/atmospherics/portables_connector/build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
/obj/machinery/atmospherics/portables_connector/return_network(obj/machinery/atmospherics/reference)
build_network()
if(!network && node)
network = new /datum/pipe_network()
network.normal_members += src
network.build_network(node, src)
if(reference==node)
return network
if(reference==connected_device)
return network
return null
/obj/machinery/atmospherics/portables_connector/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
return 1
/obj/machinery/atmospherics/portables_connector/return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(connected_device)
results += connected_device.air_contents
return results
/obj/machinery/atmospherics/portables_connector/disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
del(network)
node = null
update_underlays()
return null
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node)
return network
if(reference==connected_device)
return network
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network == old_network)
network = new_network
/obj/machinery/atmospherics/portables_connector/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (connected_device)
user << "\red You cannot unwrench this [src], dettach [connected_device] first."
return 1
return_network_air(datum/pipe_network/reference)
var/list/results = list()
if(connected_device)
results += connected_device.air_contents
return results
disconnect(obj/machinery/atmospherics/reference)
if(reference==node)
del(network)
node = null
return null
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (connected_device)
user << "\red You cannot unwrench this [src], dettach [connected_device] first."
return 1
if (locate(/obj/machinery/portable_atmospherics, src.loc))
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
if (locate(/obj/machinery/portable_atmospherics, src.loc))
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
@@ -1,124 +1,103 @@
obj/machinery/atmospherics/trinary/filter
icon = 'icons/obj/atmospherics/filter.dmi'
icon_state = "intact_off"
/obj/machinery/atmospherics/trinary/filter
icon = 'icons/atmos/filter.dmi'
icon_state = "map"
density = 0
level = 1
name = "Gas filter"
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/on = 0
var/temp = null // -- TLE
var/target_pressure = ONE_ATMOSPHERE
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_FILTER
/*
Filter types:
-1: Nothing
0: Phoron: Phoron, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen ONLY
3: Carbon Dioxide: Carbon Dioxide ONLY
4: Sleeping Agent (N2O)
*/
var/filter_type = 0
/*
Filter types:
-1: Nothing
0: Phoron: Phoron, Oxygen Agent B
1: Oxygen: Oxygen ONLY
2: Nitrogen: Nitrogen ONLY
3: Carbon Dioxide: Carbon Dioxide ONLY
4: Sleeping Agent (N2O)
*/
var/list/filtered_out = list()
var/frequency = 0
var/datum/radio_frequency/radio_connection
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/trinary/filter/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
New()
if(radio_controller)
initialize()
..()
/obj/machinery/atmospherics/trinary/filter/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_FILTER
air2.volume = ATMOS_DEFAULT_VOLUME_FILTER
air3.volume = ATMOS_DEFAULT_VOLUME_FILTER
if(radio_controller)
initialize()
update_icon()
if(stat & NOPOWER)
icon_state = "intact_off"
else if(node2 && node3 && node1)
icon_state = "intact_[on?("on"):("off")]"
/obj/machinery/atmospherics/trinary/filter/update_icon()
if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
icon_state = "m"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += on ? "on" : "off"
else
icon_state += "off"
on = 0
/obj/machinery/atmospherics/trinary/filter/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/trinary/filter/m_filter))
add_underlay(T, node2, turn(dir, 90))
else
icon_state = "intact_off"
on = 0
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/trinary/filter/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/trinary/filter/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/filter/process()
..()
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
power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
process()
..()
if(!on)
return 0
var/output_starting_pressure = air3.return_pressure()
if(output_starting_pressure >= target_pressure || air2.return_pressure() >= target_pressure )
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles
if(air1.temperature > 0)
transfer_moles = pressure_delta*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
//Actually transfer the gas
if(transfer_moles > 0)
var/datum/gas_mixture/removed = air1.remove(transfer_moles)
if(!removed)
return
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.temperature
switch(filter_type)
if(0) //removing hydrocarbons
filtered_out.phoron = removed.phoron
removed.phoron = 0
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/oxygen_agent_b))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
if(1) //removing O2
filtered_out.oxygen = removed.oxygen
removed.oxygen = 0
if(2) //removing N2
filtered_out.nitrogen = removed.nitrogen
removed.nitrogen = 0
if(3) //removing CO2
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(4)//removing N2O
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/sleeping_agent))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
else
filtered_out = null
air2.merge(filtered_out)
air3.merge(removed)
//Figure out the amount of moles to transfer
var/transfer_moles = (set_flow_rate/air1.volume)*air1.total_moles
var/power_draw = -1
if (transfer_moles > MINUMUM_MOLES_TO_FILTER)
power_draw = filter_gas(src, filtered_out, air1, air2, air3, transfer_moles, active_power_usage)
if(network2)
network2.update = 1
@@ -128,37 +107,40 @@ Filter types:
if(network1)
network1.update = 1
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)
return 1
/obj/machinery/atmospherics/trinary/filter/initialize()
set_frequency(frequency)
..()
/obj/machinery/atmospherics/trinary/filter/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
initialize()
set_frequency(frequency)
..()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
/obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
if(..())
return
@@ -194,8 +176,10 @@ obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
<A href='?src=\ref[src];filterset=3'>Carbon Dioxide</A><BR>
<A href='?src=\ref[src];filterset=4'>Nitrous Oxide</A><BR>
<A href='?src=\ref[src];filterset=-1'>Nothing</A><BR>
<HR><B>Desirable output pressure:</B>
[src.target_pressure]kPa | <a href='?src=\ref[src];set_press=1'>Change</a>
<HR>
<B>Set Flow Rate Limit:</B>
[src.set_flow_rate]L/s | <a href='?src=\ref[src];set_flow_rate=1'>Change</a><BR>
<B>Flow rate: </B>[round(last_flow_rate, 0.1)]L/s
"}
/*
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD>[dat]","window=atmo_filter")
@@ -211,18 +195,33 @@ obj/machinery/atmospherics/trinary/filter/attack_hand(user as mob) // -- TLE
onclose(user, "atmo_filter")
return
obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
/obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
if(..())
return
usr.set_machine(src)
src.add_fingerprint(usr)
if(href_list["filterset"])
src.filter_type = text2num(href_list["filterset"])
filter_type = text2num(href_list["filterset"])
filtered_out.Cut() //no need to create new lists unnecessarily
switch(filter_type)
if(0) //removing hydrocarbons
filtered_out += "phoron"
filtered_out += "oxygen_agent_b"
if(1) //removing O2
filtered_out += "oxygen"
if(2) //removing N2
filtered_out += "nitrogen"
if(3) //removing CO2
filtered_out += "carbon_dioxide"
if(4)//removing N2O
filtered_out += "sleeping_agent"
if (href_list["temp"])
src.temp = null
if(href_list["set_press"])
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num
src.target_pressure = max(0, min(4500, new_pressure))
if(href_list["set_flow_rate"])
var/new_flow_rate = input(usr,"Enter new flow rate (0-[air1.volume]L/s)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = max(0, min(air1.volume, new_flow_rate))
if(href_list["power"])
on=!on
src.update_icon()
@@ -234,9 +233,8 @@ obj/machinery/atmospherics/trinary/filter/Topic(href, href_list) // -- TLE
*/
return
obj/machinery/atmospherics/trinary/filter/m_filter
icon = 'icons/obj/atmospherics/m_filter.dmi'
icon_state = "intact_off"
/obj/machinery/atmospherics/trinary/filter/m_filter
icon_state = "mmap"
dir = SOUTH
initialize_directions = SOUTH|NORTH|EAST
@@ -253,7 +251,9 @@ obj/machinery/atmospherics/trinary/filter/m_filter/New()
if(WEST)
initialize_directions = WEST|SOUTH|EAST
obj/machinery/atmospherics/trinary/filter/m_filter/initialize()
/obj/machinery/atmospherics/trinary/filter/m_filter/initialize()
set_frequency(frequency)
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -180)
@@ -276,3 +276,4 @@ obj/machinery/atmospherics/trinary/filter/m_filter/initialize()
break
update_icon()
update_underlays()
@@ -1,169 +1,185 @@
obj/machinery/atmospherics/trinary/mixer
icon = 'icons/obj/atmospherics/mixer.dmi'
icon_state = "intact_off"
/obj/machinery/atmospherics/trinary/mixer
icon = 'icons/atmos/mixer.dmi'
icon_state = "map"
density = 0
level = 1
name = "Gas mixer"
var/on = 0
use_power = 1
idle_power_usage = 150 //internal circuitry, friction losses and stuff
active_power_usage = 3700 //This also doubles as a measure of how powerful the mixer is, in Watts. 3700 W ~ 5 HP
var/target_pressure = ONE_ATMOSPHERE
var/set_flow_rate = ATMOS_DEFAULT_VOLUME_MIXER
var/list/mixing_inputs
//for mapping
var/node1_concentration = 0.5
var/node2_concentration = 0.5
//node 3 is the outlet, nodes 1 & 2 are intakes
update_icon()
if(stat & NOPOWER)
icon_state = "intact_off"
else if(node2 && node3 && node1)
icon_state = "intact_[on?("on"):("off")]"
/obj/machinery/atmospherics/trinary/mixer/update_icon(var/safety = 0)
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer))
icon_state = "m"
else if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
icon_state = "t"
else
icon_state = ""
if(!powered())
icon_state += "off"
else if(node2 && node3 && node1)
icon_state += on ? "on" : "off"
else
icon_state += "off"
on = 0
/obj/machinery/atmospherics/trinary/mixer/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
add_underlay(T, node1, turn(dir, -90))
else
icon_state = "intact_off"
on = 0
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/trinary/mixer/m_mixer) || istype(src, /obj/machinery/atmospherics/trinary/mixer/t_mixer))
add_underlay(T, node2, turn(dir, 90))
else
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
/obj/machinery/atmospherics/trinary/mixer/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/trinary/mixer/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/trinary/mixer/New()
..()
air1.volume = ATMOS_DEFAULT_VOLUME_MIXER
air2.volume = ATMOS_DEFAULT_VOLUME_MIXER
air3.volume = ATMOS_DEFAULT_VOLUME_MIXER * 1.5
/obj/machinery/atmospherics/trinary/mixer/process()
..()
//For some reason this doesn't work even in initialize(), so it goes here.
if (!mixing_inputs)
mixing_inputs = list(src.air1 = node1_concentration, src.air2 = node2_concentration)
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
power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
New()
..()
air3.volume = 300
process()
..()
if(!on)
return 0
var/output_starting_pressure = air3.return_pressure()
if(output_starting_pressure >= target_pressure)
//No need to mix if target is already full!
return 1
//Calculate necessary moles to transfer using PV=nRT
var/pressure_delta = target_pressure - output_starting_pressure
var/transfer_moles1 = 0
var/transfer_moles2 = 0
if(air1.temperature > 0)
transfer_moles1 = (node1_concentration*pressure_delta)*air3.volume/(air1.temperature * R_IDEAL_GAS_EQUATION)
if(air2.temperature > 0)
transfer_moles2 = (node2_concentration*pressure_delta)*air3.volume/(air2.temperature * R_IDEAL_GAS_EQUATION)
var/air1_moles = air1.total_moles()
var/air2_moles = air2.total_moles()
if((air1_moles < transfer_moles1) || (air2_moles < transfer_moles2))
if(!transfer_moles1 || !transfer_moles2) return
var/ratio = min(air1_moles/transfer_moles1, air2_moles/transfer_moles2)
transfer_moles1 *= ratio
transfer_moles2 *= ratio
//Actually transfer the gas
if(transfer_moles1 > 0)
var/datum/gas_mixture/removed1 = air1.remove(transfer_moles1)
air3.merge(removed1)
if(transfer_moles2 > 0)
var/datum/gas_mixture/removed2 = air2.remove(transfer_moles2)
air3.merge(removed2)
if(network1 && transfer_moles1)
//Figure out the amount of moles to transfer
var/transfer_moles = (set_flow_rate*mixing_inputs[air1]/air1.volume)*air1.total_moles + (set_flow_rate*mixing_inputs[air1]/air2.volume)*air2.total_moles
var/power_draw = -1
if (transfer_moles > MINUMUM_MOLES_TO_FILTER)
power_draw = mix_gas(src, mixing_inputs, air3, transfer_moles, active_power_usage)
if(network1 && mixing_inputs[air1])
network1.update = 1
if(network2 && transfer_moles2)
if(network2 && mixing_inputs[air2])
network2.update = 1
if(network3)
network3.update = 1
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)
return 1
/obj/machinery/atmospherics/trinary/mixer/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
attack_hand(user as mob)
if(..())
return
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[on?"On":"Off"]</a><br>
<b>Desirable output pressure: </b>
[target_pressure]kPa | <a href='?src=\ref[src];set_press=1'>Change</a>
<br>
<b>Node 1 Concentration:</b>
<a href='?src=\ref[src];node1_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node1_c=-0.01'>-</a>
[node1_concentration]([node1_concentration*100]%)
<a href='?src=\ref[src];node1_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node1_c=0.1'>+</a>
<br>
<b>Node 2 Concentration:</b>
<a href='?src=\ref[src];node2_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node2_c=-0.01'>-</a>
[node2_concentration]([node2_concentration*100]%)
<a href='?src=\ref[src];node2_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node2_c=0.1'>+</a>
"}
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_mixer")
onclose(user, "atmo_mixer")
/obj/machinery/atmospherics/trinary/mixer/attack_hand(user as mob)
if(..())
return
Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
if(href_list["set_press"])
var/new_pressure = input(usr,"Enter new output pressure (0-4500kPa)","Pressure control",src.target_pressure) as num
src.target_pressure = max(0, min(4500, new_pressure))
if(href_list["node1_c"])
var/value = text2num(href_list["node1_c"])
src.node1_concentration = max(0, min(1, src.node1_concentration + value))
src.node2_concentration = max(0, min(1, src.node2_concentration - value))
if(href_list["node2_c"])
var/value = text2num(href_list["node2_c"])
src.node2_concentration = max(0, min(1, src.node2_concentration + value))
src.node1_concentration = max(0, min(1, src.node1_concentration - value))
src.update_icon()
src.updateUsrDialog()
src.add_fingerprint(usr)
if(!src.allowed(user))
user << "\red Access denied."
return
usr.set_machine(src)
var/dat = {"<b>Power: </b><a href='?src=\ref[src];power=1'>[on?"On":"Off"]</a><br>
<b>Set Flow Rate Limit: </b>
[set_flow_rate]L/s | <a href='?src=\ref[src];set_press=1'>Change</a>
<br>
<b>Flow Rate: </b>[round(last_flow_rate, 0.1)]L/s
<br><hr>
<b>Node 1 Concentration:</b>
<a href='?src=\ref[src];node1_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node1_c=-0.01'>-</a>
[mixing_inputs[air1]]([mixing_inputs[air1]*100]%)
<a href='?src=\ref[src];node1_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node1_c=0.1'>+</a>
<br>
<b>Node 2 Concentration:</b>
<a href='?src=\ref[src];node2_c=-0.1'><b>-</b></a>
<a href='?src=\ref[src];node2_c=-0.01'>-</a>
[mixing_inputs[air2]]([mixing_inputs[air2]*100]%)
<a href='?src=\ref[src];node2_c=0.01'><b>+</b></a>
<a href='?src=\ref[src];node2_c=0.1'>+</a>
"}
user << browse("<HEAD><TITLE>[src.name] control</TITLE></HEAD><TT>[dat]</TT>", "window=atmo_mixer")
onclose(user, "atmo_mixer")
return
/obj/machinery/atmospherics/trinary/mixer/Topic(href,href_list)
if(..()) return
if(href_list["power"])
on = !on
if(href_list["set_press"])
var/max_flow_rate = min(air1.volume, air2.volume)
var/new_flow_rate = input(usr,"Enter new flow rate limit (0-[max_flow_rate]L/s)","Flow Rate Control",src.set_flow_rate) as num
src.set_flow_rate = max(0, min(max_flow_rate, new_flow_rate))
if(href_list["node1_c"])
var/value = text2num(href_list["node1_c"])
src.mixing_inputs[air1] = max(0, min(1, src.mixing_inputs[air1] + value))
src.mixing_inputs[air2] = 1.0 - mixing_inputs[air1]
if(href_list["node2_c"])
var/value = text2num(href_list["node2_c"])
src.mixing_inputs[air2] = max(0, min(1, src.mixing_inputs[air2] + value))
src.mixing_inputs[air1] = 1.0 - mixing_inputs[air2]
src.update_icon()
src.updateUsrDialog()
return
obj/machinery/atmospherics/trinary/mixer/t_mixer
icon = 'icons/obj/atmospherics/t_mixer.dmi'
icon_state = "intact_off"
icon_state = "tmap"
dir = SOUTH
initialize_directions = SOUTH|EAST|WEST
@@ -183,6 +199,7 @@ obj/machinery/atmospherics/trinary/mixer/t_mixer/New()
initialize_directions = WEST|NORTH|SOUTH
obj/machinery/atmospherics/trinary/mixer/t_mixer/initialize()
..()
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -90)
@@ -205,10 +222,10 @@ obj/machinery/atmospherics/trinary/mixer/t_mixer/initialize()
break
update_icon()
update_underlays()
obj/machinery/atmospherics/trinary/mixer/m_mixer
icon = 'icons/obj/atmospherics/m_mixer.dmi'
icon_state = "intact_off"
icon_state = "mmap"
dir = SOUTH
initialize_directions = SOUTH|NORTH|EAST
@@ -228,6 +245,7 @@ obj/machinery/atmospherics/trinary/mixer/m_mixer/New()
initialize_directions = WEST|SOUTH|EAST
obj/machinery/atmospherics/trinary/mixer/m_mixer/initialize()
..()
if(node1 && node2 && node3) return
var/node1_connect = turn(dir, -180)
@@ -249,4 +267,5 @@ obj/machinery/atmospherics/trinary/mixer/m_mixer/initialize()
node3 = target
break
update_icon()
update_icon()
update_underlays()
@@ -2,6 +2,8 @@ obj/machinery/atmospherics/trinary
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
use_power = 1
var/on = 0
var/datum/gas_mixture/air1
var/datum/gas_mixture/air2
@@ -94,6 +96,7 @@ obj/machinery/atmospherics/trinary
break
update_icon()
update_underlays()
build_network()
if(!network1 && node1)
@@ -160,5 +163,7 @@ obj/machinery/atmospherics/trinary
else if(reference==node3)
del(network3)
node3 = null
update_underlays()
return null
+449 -397
View File
@@ -1,10 +1,11 @@
obj/machinery/atmospherics/tvalve
icon = 'icons/obj/atmospherics/valve.dmi'
icon_state = "tvalve0"
/obj/machinery/atmospherics/tvalve
icon = 'icons/atmos/tvalve.dmi'
icon_state = "map_tvalve0"
name = "manual switching valve"
desc = "A pipe valve"
level = 1
dir = SOUTH
initialize_directions = SOUTH|NORTH|WEST
@@ -19,415 +20,466 @@ obj/machinery/atmospherics/tvalve
var/datum/pipe_network/network_node2
var/datum/pipe_network/network_node3
update_icon(animation)
if(animation)
flick("tvalve[src.state][!src.state]",src)
/obj/machinery/atmospherics/tvalve/bypass
icon_state = "map_tvalve1"
state = 1
/obj/machinery/atmospherics/tvalve/update_icon(animation)
if(animation)
flick("tvalve[src.state][!src.state]",src)
else
icon_state = "tvalve[state]"
/obj/machinery/atmospherics/tvalve/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, turn(dir, -180))
if(istype(src, /obj/machinery/atmospherics/tvalve/mirrored))
add_underlay(T, node2, turn(dir, 90))
else
icon_state = "tvalve[state]"
add_underlay(T, node2, turn(dir, -90))
add_underlay(T, node3, dir)
New()
initialize_directions()
..()
proc/initialize_directions()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|EAST
if(SOUTH)
initialize_directions = NORTH|SOUTH|WEST
if(EAST)
initialize_directions = WEST|EAST|SOUTH
if(WEST)
initialize_directions = EAST|WEST|NORTH
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(state)
network_node2 = new_network
else
network_node3 = new_network
else if(reference == node2)
network_node2 = new_network
if(state)
network_node1 = new_network
else if(reference == node3)
network_node3 = new_network
if(!state)
network_node1 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
if(state)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
else
if(reference == node1)
if(node3)
return node3.network_expand(new_network, src)
else if(reference == node3)
if(node1)
return node1.network_expand(new_network, src)
return null
Del()
loc = null
if(node1)
node1.disconnect(src)
del(network_node1)
if(node2)
node2.disconnect(src)
del(network_node2)
if(node3)
node3.disconnect(src)
del(network_node3)
node1 = null
node2 = null
node3 = null
..()
proc/go_to_side()
if(state) return 0
state = 1
update_icon()
if(network_node1)
del(network_node1)
if(network_node3)
del(network_node3)
build_network()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
proc/go_straight()
if(!state)
return 0
state = 0
update_icon()
if(network_node1)
del(network_node1)
if(network_node2)
del(network_node2)
build_network()
if(network_node1&&network_node3)
network_node1.merge(network_node3)
network_node3 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node3)
network_node3.update = 1
return 1
attack_ai(mob/user as mob)
return
attack_paw(mob/user as mob)
return attack_hand(user)
attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.state)
src.go_straight()
else
src.go_to_side()
process()
..()
machines.Remove(src)
/* if(open && (!node1 || !node2))
close()
if(!node1)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if (!node2)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if (nodealert)
nodealert = 0
*/
return
initialize()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 180)
node2_dir = turn(dir, -90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
if(!network_node3 && node3)
network_node3 = new /datum/pipe_network()
network_node3.normal_members += src
network_node3.build_network(node3, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
if(reference==node3)
return network_node3
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
if(network_node3 == old_network)
network_node3 = new_network
return 1
return_network_air(datum/network/reference)
return null
disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network_node1)
node1 = null
else if(reference==node2)
del(network_node2)
node2 = null
else if(reference==node3)
del(network_node3)
node2 = null
return null
digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/obj/atmospherics/digital_valve.dmi'
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if(!src.allowed(user))
user << "\red Access denied."
return
..()
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
if("valve_close")
if(state)
go_straight()
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (istype(src, /obj/machinery/atmospherics/tvalve/digital))
user << "\red You cannot unwrench this [src], it's too complicated."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
obj/machinery/atmospherics/tvalve/mirrored
icon_state = "tvalvem0"
/obj/machinery/atmospherics/tvalve/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/tvalve/New()
initialize_directions()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|WEST
if(SOUTH)
initialize_directions = NORTH|SOUTH|EAST
if(EAST)
initialize_directions = WEST|EAST|NORTH
if(WEST)
initialize_directions = EAST|WEST|SOUTH
..()
initialize()
var/node1_dir
var/node2_dir
var/node3_dir
/obj/machinery/atmospherics/tvalve/proc/initialize_directions()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|EAST
if(SOUTH)
initialize_directions = NORTH|SOUTH|WEST
if(EAST)
initialize_directions = WEST|EAST|SOUTH
if(WEST)
initialize_directions = EAST|WEST|NORTH
node1_dir = turn(dir, 180)
node2_dir = turn(dir, 90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon(animation)
if(animation)
flick("tvalvem[src.state][!src.state]",src)
/obj/machinery/atmospherics/tvalve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(state)
network_node2 = new_network
else
icon_state = "tvalvem[state]"
network_node3 = new_network
else if(reference == node2)
network_node2 = new_network
if(state)
network_node1 = new_network
else if(reference == node3)
network_node3 = new_network
if(!state)
network_node1 = new_network
digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/obj/atmospherics/digital_valve.dmi'
if(new_network.normal_members.Find(src))
return 0
attack_ai(mob/user as mob)
return src.attack_hand(user)
new_network.normal_members += src
attack_hand(mob/user as mob)
if(!src.allowed(user))
user << "\red Access denied."
return
..()
if(state)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
else
if(reference == node1)
if(node3)
return node3.network_expand(new_network, src)
else if(reference == node3)
if(node1)
return node1.network_expand(new_network, src)
//Radio remote control -eh?
return null
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/tvalve/Del()
loc = null
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
if(node1)
node1.disconnect(src)
del(network_node1)
if(node2)
node2.disconnect(src)
del(network_node2)
if(node3)
node3.disconnect(src)
del(network_node3)
initialize()
..()
if(frequency)
set_frequency(frequency)
node1 = null
node2 = null
node3 = null
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
..()
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
/obj/machinery/atmospherics/tvalve/proc/go_to_side()
if("valve_close")
if(state)
go_straight()
if(state) return 0
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
state = 1
update_icon()
if(network_node1)
del(network_node1)
if(network_node3)
del(network_node3)
build_network()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
/obj/machinery/atmospherics/tvalve/proc/go_straight()
if(!state)
return 0
state = 0
update_icon()
if(network_node1)
del(network_node1)
if(network_node2)
del(network_node2)
build_network()
if(network_node1&&network_node3)
network_node1.merge(network_node3)
network_node3 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node3)
network_node3.update = 1
return 1
/obj/machinery/atmospherics/tvalve/attack_ai(mob/user as mob)
return
/obj/machinery/atmospherics/tvalve/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/atmospherics/tvalve/attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.state)
src.go_straight()
else
src.go_to_side()
/obj/machinery/atmospherics/tvalve/process()
..()
. = PROCESS_KILL
//machines.Remove(src)
return
/obj/machinery/atmospherics/tvalve/initialize()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 180)
node2_dir = turn(dir, -90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/tvalve/build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
if(!network_node3 && node3)
network_node3 = new /datum/pipe_network()
network_node3.normal_members += src
network_node3.build_network(node3, src)
/obj/machinery/atmospherics/tvalve/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
if(reference==node3)
return network_node3
return null
/obj/machinery/atmospherics/tvalve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
if(network_node3 == old_network)
network_node3 = new_network
return 1
/obj/machinery/atmospherics/tvalve/return_network_air(datum/network/reference)
return null
/obj/machinery/atmospherics/tvalve/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network_node1)
node1 = null
else if(reference==node2)
del(network_node2)
node2 = null
else if(reference==node3)
del(network_node3)
node2 = null
update_underlays()
return null
/obj/machinery/atmospherics/tvalve/digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_tvalve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/tvalve/digital/bypass
icon_state = "map_tvalve1"
state = 1
/obj/machinery/atmospherics/tvalve/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/tvalve/digital/update_icon()
..()
if(!powered())
icon_state = "tvalvenopower"
/obj/machinery/atmospherics/tvalve/digital/attack_ai(mob/user as mob)
return src.attack_hand(user)
/obj/machinery/atmospherics/tvalve/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
user << "\red Access denied."
return
..()
//Radio remote control
/obj/machinery/atmospherics/tvalve/digital/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/tvalve/digital/initialize()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/tvalve/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
if("valve_close")
if(state)
go_straight()
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
/obj/machinery/atmospherics/tvalve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (istype(src, /obj/machinery/atmospherics/tvalve/digital))
user << "\red You cannot unwrench this [src], it's too complicated."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/tvalve/mirrored
icon_state = "map_tvalvem0"
/obj/machinery/atmospherics/tvalve/mirrored/bypass
icon_state = "map_tvalvem1"
state = 1
/obj/machinery/atmospherics/tvalve/mirrored/initialize_directions()
switch(dir)
if(NORTH)
initialize_directions = SOUTH|NORTH|WEST
if(SOUTH)
initialize_directions = NORTH|SOUTH|EAST
if(EAST)
initialize_directions = WEST|EAST|NORTH
if(WEST)
initialize_directions = EAST|WEST|SOUTH
/obj/machinery/atmospherics/tvalve/mirrored/initialize()
var/node1_dir
var/node2_dir
var/node3_dir
node1_dir = turn(dir, 180)
node2_dir = turn(dir, 90)
node3_dir = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node3_dir))
if(target.initialize_directions & get_dir(target,src))
node3 = target
break
update_icon()
update_underlays()
/obj/machinery/atmospherics/tvalve/mirrored/update_icon(animation)
if(animation)
flick("tvalvem[src.state][!src.state]",src)
else
icon_state = "tvalvem[state]"
/obj/machinery/atmospherics/tvalve/mirrored/digital // can be controlled by AI
name = "digital switching valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_tvalve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
/obj/machinery/atmospherics/tvalve/mirrored/digital/bypass
icon_state = "map_tvalvem1"
state = 1
/obj/machinery/atmospherics/tvalve/mirrored/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
/obj/machinery/atmospherics/tvalve/mirrored/digital/update_icon()
..()
if(!powered())
icon_state = "tvalvemnopower"
/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_ai(mob/user as mob)
return src.attack_hand(user)
/obj/machinery/atmospherics/tvalve/mirrored/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
user << "\red Access denied."
return
..()
//Radio remote control -eh?
/obj/machinery/atmospherics/tvalve/mirrored/digital/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
/obj/machinery/atmospherics/tvalve/mirrored/digital/initialize()
..()
if(frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/tvalve/mirrored/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!state)
go_to_side()
if("valve_close")
if(state)
go_straight()
if("valve_toggle")
if(state)
go_straight()
else
go_to_side()
+192 -26
View File
@@ -1,41 +1,207 @@
/obj/machinery/atmospherics/unary/cold_sink
icon = 'icons/obj/atmospherics/cold_sink.dmi'
icon_state = "intact_off"
density = 1
use_power = 1
//TODO: Put this under a common parent type with heaters to cut down on the copypasta
#define FREEZER_PERF_MULT 2.5
name = "Cold Sink"
/obj/machinery/atmospherics/unary/freezer
name = "gas cooling system"
desc = "Cools gas when connected to pipe network"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "freezer_0"
density = 1
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/internal_volume = 600 //L
var/on = 0
use_power = 0
idle_power_usage = 5 //5 Watts for thermostat related circuitry
active_power_usage //50 kW. The power rating of the freezer
var/current_temperature = T20C
var/current_heat_capacity = 50000 //totally random
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
/obj/machinery/atmospherics/unary/freezer/New()
..()
air_contents.volume = internal_volume
initialize_directions = dir
component_parts = list()
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
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
/obj/machinery/atmospherics/unary/freezer/update_icon()
if(src.node)
if(src.on && cooling)
icon_state = "freezer_1"
else
icon_state = "exposed"
icon_state = "freezer"
else
icon_state = "freezer_0"
return
on = 0
/obj/machinery/atmospherics/unary/freezer/attack_ai(mob/user as mob)
src.ui_interact(user)
/obj/machinery/atmospherics/unary/freezer/attack_paw(mob/user as mob)
src.ui_interact(user)
/obj/machinery/atmospherics/unary/freezer/attack_hand(mob/user as mob)
src.ui_interact(user)
/obj/machinery/atmospherics/unary/freezer/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]
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
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"
else if (air_contents.temperature < (T0C - 20) && air_contents.temperature > (T0C - 100))
temp_class = "average"
data["gasTemperatureClass"] = temp_class
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "freezer.tmpl", "Gas Cooling System", 440, 300)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/atmospherics/unary/freezer/Topic(href, href_list)
if (href_list["toggleStatus"])
src.on = !src.on
update_icon()
update_use_power(on)
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
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
/obj/machinery/atmospherics/unary/freezer/process()
..()
if(stat & (NOPOWER|BROKEN) || !on)
cooling = 0
update_use_power(0)
update_icon()
return
process()
..()
if(!on || !network)
return 0
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = current_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
if (network && air_contents.temperature > set_temperature)
cooling = 1
update_use_power(2)
if(combined_heat_capacity > 0)
var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature
air_contents.temperature = combined_energy/combined_heat_capacity
var/heat_transfer = max( -air_contents.get_thermal_energy_change(set_temperature - 5), 0 )
//todo: have current temperature affected. require power to bring down current temperature again
//Assume the heat is being pumped into the hull which is fixed at heatsink_temperature
//not /really/ proper thermodynamics but whatever
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
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
return 1
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()
..()
var/cap_rating = 0
var/cap_count = 0
var/manip_rating = 0
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
cap_count++
if(istype(P, /obj/item/weapon/stock_parts/manipulator))
manip_rating += P.rating
manip_count++
if(istype(P, /obj/item/weapon/stock_parts/matter_bin))
bin_rating += P.rating
bin_count++
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)
if(istype(O, /obj/item/weapon/screwdriver))
opened = !opened
user << "You [opened ? "open" : "close"] the maintenance hatch of [src]."
return
if (opened && istype(O, /obj/item/weapon/crowbar))
dismantle()
return
..()
/obj/machinery/atmospherics/unary/freezer/examine()
..()
if (opened)
usr << "The maintenance hatch is open."
+173 -27
View File
@@ -1,43 +1,189 @@
/obj/machinery/atmospherics/unary/heat_reservoir
//currently the same code as cold_sink but anticipating process() changes
//TODO: Put this under a common parent type with freezers to cut down on the copypasta
icon = 'icons/obj/atmospherics/cold_sink.dmi'
icon_state = "intact_off"
/obj/machinery/atmospherics/unary/heater
name = "gas heating system"
desc = "Heats gas when connected to a pipe network"
icon = 'icons/obj/Cryogenic2.dmi'
icon_state = "heater_0"
density = 1
use_power = 1
name = "Heat Reservoir"
desc = "Heats gas when connected to pipe network"
anchored = 1.0
var/set_temperature = T20C //thermostat
var/max_temperature = T20C + 680
var/internal_volume = 600 //L
var/on = 0
use_power = 0
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/current_temperature = T20C
var/current_heat_capacity = 50000 //totally random
var/heating = 0 //mainly for icon updates
var/opened = 0 //for deconstruction
/obj/machinery/atmospherics/unary/heater/New()
..()
air_contents.volume = internal_volume
initialize_directions = dir
component_parts = list()
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
var/node_connect = dir
for(var/obj/machinery/atmospherics/target in get_step(src,node_connect))
if(target.initialize_directions & get_dir(target,src))
node = target
break
update_icon()
if(node)
icon_state = "intact_[on?("on"):("off")]"
/obj/machinery/atmospherics/unary/heater/update_icon()
if(src.node)
if(src.on && src.heating)
icon_state = "heater_1"
else
icon_state = "exposed"
icon_state = "heater"
else
icon_state = "heater_0"
return
on = 0
/obj/machinery/atmospherics/unary/heater/process()
..()
if(stat & (NOPOWER|BROKEN) || !on)
heating = 0
update_use_power(0)
update_icon()
return
process()
..()
if(!on || !network)
return 0
var/air_heat_capacity = air_contents.heat_capacity()
var/combined_heat_capacity = current_heat_capacity + air_heat_capacity
var/old_temperature = air_contents.temperature
if (network && air_contents.total_moles && air_contents.temperature < set_temperature)
update_use_power(2)
air_contents.add_thermal_energy(active_power_usage)
if(combined_heat_capacity > 0)
var/combined_energy = current_temperature*current_heat_capacity + air_heat_capacity*air_contents.temperature
air_contents.temperature = combined_energy/combined_heat_capacity
heating = 1
network.update = 1
else
heating = 0
update_use_power(1)
//todo: have current temperature affected. require power to bring up current temperature again
update_icon()
if(abs(old_temperature-air_contents.temperature) > 1)
network.update = 1
return 1
/obj/machinery/atmospherics/unary/heater/attack_ai(mob/user as mob)
src.ui_interact(user)
/obj/machinery/atmospherics/unary/heater/attack_paw(mob/user as mob)
src.ui_interact(user)
/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]
data["on"] = on ? 1 : 0
data["gasPressure"] = round(air_contents.return_pressure())
data["gasTemperature"] = round(air_contents.temperature)
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"
data["gasTemperatureClass"] = temp_class
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "freezer.tmpl", "Gas Heating System", 440, 300)
// when the ui is first opened this is the data it will use
ui.set_initial_data(data)
// open the new ui window
ui.open()
// auto update every Master Controller tick
ui.set_auto_update(1)
/obj/machinery/atmospherics/unary/heater/Topic(href, href_list)
if (href_list["toggleStatus"])
src.on = !src.on
update_use_power(on)
update_icon()
if(href_list["temp"])
var/amount = text2num(href_list["temp"])
if(amount > 0)
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()
..()
var/cap_rating = 0
var/cap_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
cap_count++
if(istype(P, /obj/item/weapon/stock_parts/matter_bin))
bin_rating += P.rating
bin_count++
cap_rating /= cap_count
bin_rating /= bin_count
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)
if(istype(O, /obj/item/weapon/screwdriver))
opened = !opened
user << "You [opened ? "open" : "close"] the maintenance hatch of [src]."
return
if (opened && istype(O, /obj/item/weapon/crowbar))
dismantle()
return
..()
/obj/machinery/atmospherics/unary/heater/examine()
..()
if (opened)
usr << "The maintenance hatch is open."
@@ -1,15 +1,24 @@
//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 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/obj/atmospherics/outlet_injector.dmi'
icon_state = "off"
icon = 'icons/atmos/injector.dmi'
icon_state = "map_injector"
use_power = 1
layer = 3
name = "Air Injector"
desc = "Has a valve and pump attached to it"
name = "air injector"
desc = "Passively injects air into its surroundings. Has a valve attached to it that can control flow rate."
use_power = 1
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
var/volume_rate = 50
var/volume_rate = 50 //flow rate limit
var/frequency = 0
var/id = null
@@ -17,131 +26,136 @@
level = 1
update_icon()
if(node)
if(on && !(stat & NOPOWER))
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
else
icon_state = "exposed"
on = 0
/obj/machinery/atmospherics/unary/outlet_injector/New()
..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP + 500 //Give it a small reservoir for injecting. Also allows it to have a higher flow rate limit than vent pumps, to differentiate injectors a bit more.
return
/obj/machinery/atmospherics/unary/outlet_injector/update_icon()
if(!powered())
icon_state = "off"
else
icon_state = "[on ? "on" : "off"]"
power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
process()
..()
injecting = 0
if(!on || stat & NOPOWER)
return 0
if(air_contents.temperature > 0)
var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
return 1
proc/inject()
if(on || injecting)
return 0
injecting = 1
if(air_contents.temperature > 0)
var/transfer_moles = (air_contents.return_pressure())*volume_rate/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
flick("inject", src)
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency)
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AO",
"power" = on,
"volume_rate" = volume_rate,
//"timestamp" = world.time,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal)
return 1
initialize()
..()
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if("power" in signal.data)
on = text2num(signal.data["power"])
if("power_toggle" in signal.data)
on = !on
if("inject" in signal.data)
spawn inject()
/obj/machinery/atmospherics/unary/outlet_injector/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node, dir)
if("set_volume_rate" in signal.data)
var/number = text2num(signal.data["set_volume_rate"])
volume_rate = between(0, number, air_contents.volume)
if("status" in signal.data)
spawn(2)
broadcast_status()
return //do not update_icon
//log_admin("DEBUG \[[world.timeofday]\]: outlet_injector/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
//return
spawn(2)
broadcast_status()
/obj/machinery/atmospherics/unary/outlet_injector/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(node)
if(on)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]exposed"
on = 0
return
/obj/machinery/atmospherics/unary/outlet_injector/process()
..()
injecting = 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/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()
if(on || injecting || (stat & NOPOWER))
return 0
var/datum/gas_mixture/environment = loc.return_air()
if (!environment)
return 0
injecting = 1
if(air_contents.temperature > 0)
var/power_used = pump_gas(src, air_contents, environment, air_contents.total_moles, active_power_usage)
use_power(power_used)
if(network)
network.update = 1
flick("inject", src)
/obj/machinery/atmospherics/unary/outlet_injector/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency)
/obj/machinery/atmospherics/unary/outlet_injector/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"tag" = id,
"device" = "AO",
"power" = on,
"volume_rate" = volume_rate,
"sigtype" = "status"
)
radio_connection.post_signal(src, signal)
return 1
/obj/machinery/atmospherics/unary/outlet_injector/initialize()
..()
set_frequency(frequency)
/obj/machinery/atmospherics/unary/outlet_injector/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"])
on = text2num(signal.data["power"])
update_use_power(on)
if(signal.data["power_toggle"])
on = !on
update_use_power(on)
if(signal.data["inject"])
spawn inject()
return
if(signal.data["set_volume_rate"])
var/number = text2num(signal.data["set_volume_rate"])
volume_rate = between(0, number, air_contents.volume)
if(signal.data["status"])
spawn(2)
broadcast_status()
return //do not update_icon
spawn(2)
broadcast_status()
update_icon()
/obj/machinery/atmospherics/unary/outlet_injector/hide(var/i)
update_underlays()
@@ -33,7 +33,7 @@ obj/machinery/atmospherics/unary/oxygen_generator
if(!on)
return 0
var/total_moles = air_contents.total_moles()
var/total_moles = air_contents.total_moles
if(total_moles < oxygen_content)
var/current_heat_capacity = air_contents.heat_capacity()
@@ -41,7 +41,7 @@ obj/machinery/atmospherics/unary/oxygen_generator
var/added_oxygen = oxygen_content - total_moles
air_contents.temperature = (current_heat_capacity*air_contents.temperature + 20*added_oxygen*T0C)/(current_heat_capacity+20*added_oxygen)
air_contents.oxygen += added_oxygen
air_contents.adjust_gas("oxygen", added_oxygen)
if(network)
network.update = 1
@@ -50,6 +50,7 @@
break
update_icon()
update_underlays()
build_network()
if(!network && node)
@@ -85,4 +86,7 @@
del(network)
node = null
update_icon()
update_underlays()
return null
+316 -255
View File
@@ -1,16 +1,24 @@
#define DEFAULT_PRESSURE_DELTA 10000
#define EXTERNAL_PRESSURE_BOUND ONE_ATMOSPHERE
#define INTERNAL_PRESSURE_BOUND 0
#define PRESSURE_CHECKS 1
#define PRESSURE_CHECK_EXTERNAL 1
#define PRESSURE_CHECK_INTERNAL 2
#undefine
/obj/machinery/atmospherics/unary/vent_pump
icon = 'icons/obj/atmospherics/vent_pump.dmi'
icon_state = "off"
icon = 'icons/atmos/vent_pump.dmi'
icon_state = "map_vent"
name = "Air Vent"
desc = "Has a valve and pump attached to it"
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 pump is, in Watts. 7500 W ~ 10 HP
var/area/initial_loc
level = 1
var/area_uid
@@ -19,6 +27,8 @@
var/on = 0
var/pump_direction = 1 //0 = siphoning, 1 = releasing
var/last_power_draw = 0
var/external_pressure_bound = EXTERNAL_PRESSURE_BOUND
var/internal_pressure_bound = INTERNAL_PRESSURE_BOUND
@@ -40,316 +50,367 @@
var/radio_filter_out
var/radio_filter_in
on
on = 1
icon_state = "out"
/obj/machinery/atmospherics/unary/vent_pump/on
on = 1
icon_state = "map_vent_out"
siphon
pump_direction = 0
icon_state = "off"
/obj/machinery/atmospherics/unary/vent_pump/siphon
pump_direction = 0
on
on = 1
icon_state = "in"
/obj/machinery/atmospherics/unary/vent_pump/siphon/on
on = 1
icon_state = "map_vent_in"
New()
initial_loc = get_area(loc)
if (initial_loc.master)
initial_loc = initial_loc.master
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
if(ticker && ticker.current_state == 3)//if the game is running
src.initialize()
src.broadcast_status()
..()
/obj/machinery/atmospherics/unary/vent_pump/New()
..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_PUMP
icon = null
initial_loc = get_area(loc)
if (initial_loc.master)
initial_loc = initial_loc.master
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
if(ticker && ticker.current_state == 3)//if the game is running
src.initialize()
src.broadcast_status()
high_volume
name = "Large Air Vent"
power_channel = EQUIP
New()
..()
air_contents.volume = 1000
/obj/machinery/atmospherics/unary/vent_pump/high_volume
name = "Large Air Vent"
power_channel = EQUIP
active_power_usage = 15000 //15 kW ~ 20 HP
update_icon()
if(welded)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]weld"
return
if(on && !(stat & (NOPOWER|BROKEN)))
if(pump_direction)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
/obj/machinery/atmospherics/unary/vent_pump/high_volume/New()
..()
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
if (!node)
on = 0
overlays.Cut()
var/vent_icon = "vent"
var/turf/T = get_turf(src)
if(!istype(T))
return
process()
..()
if(stat & (NOPOWER|BROKEN))
if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
vent_icon += "h"
if(welded)
vent_icon += "weld"
else if(!powered())
vent_icon += "off"
else
vent_icon += "[on ? "[pump_direction ? "out" : "in"]" : "off"]"
overlays += icon_manager.get_atmos_icon("device", , , vent_icon)
/obj/machinery/atmospherics/unary/vent_pump/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if (!node)
on = 0
//broadcast_status() // from now air alarm/control computer should request update purposely --rastaf0
if(!on)
return 0
if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
return
else
add_underlay(T, node, dir)
if(welded)
return 0
/obj/machinery/atmospherics/unary/vent_pump/hide()
update_icon()
update_underlays()
var/datum/gas_mixture/environment = loc.return_air()
var/environment_pressure = environment.return_pressure()
/obj/machinery/atmospherics/unary/vent_pump/proc/can_pump()
if(stat & (NOPOWER|BROKEN))
return 0
if(!on)
return 0
if(welded)
return 0
return 1
if(pump_direction) //internal -> external
var/pressure_delta = 10000
/obj/machinery/atmospherics/unary/vent_pump/process()
..()
if (!node)
on = 0
if(!can_pump())
update_use_power(0) //usually we get here because a player turned a pump off - definitely want to update.
last_power_draw = 0
last_flow_rate = 0
return 0
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (external_pressure_bound - environment_pressure))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (air_contents.return_pressure() - internal_pressure_bound))
var/datum/gas_mixture/environment = loc.return_air()
if(pressure_delta > 0.5)
if(air_contents.temperature > 0)
var/transfer_moles = pressure_delta*environment.volume/(air_contents.temperature * R_IDEAL_GAS_EQUATION)
var/datum/gas_mixture/removed = air_contents.remove(transfer_moles)
loc.assume_air(removed)
if(network)
network.update = 1
var/power_draw = -1
//Figure out the target pressure difference
var/pressure_delta = get_pressure_delta(environment)
//src.visible_message("DEBUG >>> [src]: pressure_delta = [pressure_delta]")
if((environment.temperature || air_contents.temperature) && pressure_delta > 0.5)
if(pump_direction) //internal -> external
var/output_volume = environment.volume * environment.group_multiplier
var/air_temperature = environment.temperature? environment.temperature : air_contents.temperature
var/transfer_moles = pressure_delta*output_volume/(air_temperature * R_IDEAL_GAS_EQUATION)
//src.visible_message("DEBUG >>> [src]: output_volume = [output_volume]L; air_temperature = [air_temperature]K; transfer_moles = [transfer_moles] mol")
power_draw = pump_gas(src, air_contents, environment, transfer_moles, active_power_usage)
else //external -> internal
var/pressure_delta = 10000
if(pressure_checks&1)
pressure_delta = min(pressure_delta, (environment_pressure - external_pressure_bound))
if(pressure_checks&2)
pressure_delta = min(pressure_delta, (internal_pressure_bound - air_contents.return_pressure()))
var/output_volume = air_contents.volume + (network? network.volume : 0)
var/air_temperature = air_contents.temperature? air_contents.temperature : environment.temperature
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*air_contents.volume/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air_contents, transfer_moles, active_power_usage)
if(pressure_delta > 0.5)
if(environment.temperature > 0)
var/transfer_moles = pressure_delta*air_contents.volume/(environment.temperature * R_IDEAL_GAS_EQUATION)
if (power_draw < 0)
last_power_draw = 0
last_flow_rate = 0
//update_use_power(0)
use_power = 0 //don't force update - easier on CPU
else
last_power_draw = handle_power_draw(power_draw)
if(network)
network.update = 1
return 1
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
if (isnull(removed)) //in space
return
/obj/machinery/atmospherics/unary/vent_pump/proc/get_pressure_delta(datum/gas_mixture/environment)
var/pressure_delta = DEFAULT_PRESSURE_DELTA
var/environment_pressure = environment.return_pressure()
if(pump_direction) //internal -> external
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, external_pressure_bound - environment_pressure) //increasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INTERNAL)
pressure_delta = min(pressure_delta, air_contents.return_pressure() - internal_pressure_bound) //decreasing the pressure here
else //external -> internal
if(pressure_checks & PRESSURE_CHECK_EXTERNAL)
pressure_delta = min(pressure_delta, environment_pressure - external_pressure_bound) //decreasing the pressure here
if(pressure_checks & PRESSURE_CHECK_INTERNAL)
pressure_delta = min(pressure_delta, internal_pressure_bound - air_contents.return_pressure()) //increasing the pressure here
return pressure_delta
air_contents.merge(removed)
//Radio remote control
if(network)
network.update = 1
/obj/machinery/atmospherics/unary/vent_pump/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency,radio_filter_in)
return 1
/obj/machinery/atmospherics/unary/vent_pump/proc/broadcast_status()
if(!radio_connection)
return 0
//Radio remote control
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency,radio_filter_in)
signal.data = list(
"area" = src.area_uid,
"tag" = src.id_tag,
"device" = "AVP",
"power" = on,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"internal" = internal_pressure_bound,
"external" = external_pressure_bound,
"timestamp" = world.time,
"sigtype" = "status",
"power_draw" = last_power_draw,
"flow_rate" = last_flow_rate,
)
broadcast_status()
if(!radio_connection)
return 0
if(!initial_loc.air_vent_names[id_tag])
var/new_name = "[initial_loc.name] Vent Pump #[initial_loc.air_vent_names.len+1]"
initial_loc.air_vent_names[id_tag] = new_name
src.name = new_name
initial_loc.air_vent_info[id_tag] = signal.data
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
radio_connection.post_signal(src, signal, radio_filter_out)
signal.data = list(
"area" = src.area_uid,
"tag" = src.id_tag,
"device" = "AVP",
"power" = on,
"direction" = pump_direction?("release"):("siphon"),
"checks" = pressure_checks,
"internal" = internal_pressure_bound,
"external" = external_pressure_bound,
"timestamp" = world.time,
"sigtype" = "status"
)
if(!initial_loc.air_vent_names[id_tag])
var/new_name = "[initial_loc.name] Vent Pump #[initial_loc.air_vent_names.len+1]"
initial_loc.air_vent_names[id_tag] = new_name
src.name = new_name
initial_loc.air_vent_info[id_tag] = signal.data
radio_connection.post_signal(src, signal, radio_filter_out)
return 1
return 1
initialize()
..()
/obj/machinery/atmospherics/unary/vent_pump/initialize()
..()
//some vents work his own spesial way
radio_filter_in = frequency==1439?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==1439?(RADIO_TO_AIRALARM):null
if(frequency)
set_frequency(frequency)
//some vents work his own spesial way
radio_filter_in = frequency==1439?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==1439?(RADIO_TO_AIRALARM):null
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
//log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])")
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
/obj/machinery/atmospherics/unary/vent_pump/receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
//log_admin("DEBUG \[[world.timeofday]\]: /obj/machinery/atmospherics/unary/vent_pump/receive_signal([signal.debug_print()])")
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["purge"] != null)
pressure_checks &= ~1
pump_direction = 0
if(signal.data["purge"] != null)
pressure_checks &= ~1
pump_direction = 0
if(signal.data["stabalize"] != null)
pressure_checks |= 1
pump_direction = 1
if(signal.data["stabalize"] != null)
pressure_checks |= 1
pump_direction = 1
if(signal.data["power"] != null)
on = text2num(signal.data["power"])
if(signal.data["power"] != null)
on = text2num(signal.data["power"])
if(signal.data["power_toggle"] != null)
on = !on
if(signal.data["power_toggle"] != null)
on = !on
if(signal.data["checks"] != null)
if (signal.data["checks"] == "default")
pressure_checks = pressure_checks_default
else
pressure_checks = text2num(signal.data["checks"])
if(signal.data["checks"] != null)
if (signal.data["checks"] == "default")
pressure_checks = pressure_checks_default
else
pressure_checks = text2num(signal.data["checks"])
if(signal.data["checks_toggle"] != null)
pressure_checks = (pressure_checks?0:3)
if(signal.data["checks_toggle"] != null)
pressure_checks = (pressure_checks?0:3)
if(signal.data["direction"] != null)
pump_direction = text2num(signal.data["direction"])
if(signal.data["direction"] != null)
pump_direction = text2num(signal.data["direction"])
if(signal.data["set_internal_pressure"] != null)
if (signal.data["set_internal_pressure"] == "default")
internal_pressure_bound = internal_pressure_bound_default
else
internal_pressure_bound = between(
0,
text2num(signal.data["set_internal_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["set_external_pressure"] != null)
if (signal.data["set_external_pressure"] == "default")
external_pressure_bound = external_pressure_bound_default
else
external_pressure_bound = between(
0,
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["adjust_internal_pressure"] != null)
if(signal.data["set_internal_pressure"] != null)
if (signal.data["set_internal_pressure"] == "default")
internal_pressure_bound = internal_pressure_bound_default
else
internal_pressure_bound = between(
0,
internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),
text2num(signal.data["set_internal_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["adjust_external_pressure"] != null)
if(signal.data["set_external_pressure"] != null)
if (signal.data["set_external_pressure"] == "default")
external_pressure_bound = external_pressure_bound_default
else
external_pressure_bound = between(
0,
external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),
text2num(signal.data["set_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["init"] != null)
name = signal.data["init"]
return
if(signal.data["adjust_internal_pressure"] != null)
internal_pressure_bound = between(
0,
internal_pressure_bound + text2num(signal.data["adjust_internal_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["status"] != null)
spawn(2)
broadcast_status()
return //do not update_icon
if(signal.data["adjust_external_pressure"] != null)
//log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
external_pressure_bound = between(
0,
external_pressure_bound + text2num(signal.data["adjust_external_pressure"]),
ONE_ATMOSPHERE*50
)
if(signal.data["init"] != null)
name = signal.data["init"]
return
if(signal.data["status"] != null)
spawn(2)
broadcast_status()
update_icon()
return
return //do not update_icon
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(welded)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]weld"
return
if(on&&node)
if(pump_direction)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]out"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
//log_admin("DEBUG \[[world.timeofday]\]: vent_pump/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
spawn(2)
broadcast_status()
update_icon()
return
attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if (WT.remove_fuel(0,user))
user << "\blue Now welding the vent."
if(do_after(user, 20))
if(!src || !WT.isOn()) return
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
if(!welded)
user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.")
welded = 1
update_icon()
else
user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.")
welded = 0
update_icon()
/obj/machinery/atmospherics/unary/vent_pump/attackby(obj/item/W, mob/user)
if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if (WT.remove_fuel(0,user))
user << "\blue Now welding the vent."
if(do_after(user, 20))
if(!src || !WT.isOn()) return
playsound(src.loc, 'sound/items/Welder2.ogg', 50, 1)
if(!welded)
user.visible_message("[user] welds the vent shut.", "You weld the vent shut.", "You hear welding.")
welded = 1
update_icon()
else
user << "\blue The welding tool needs to be on to start this task."
user.visible_message("[user] unwelds the vent.", "You unweld the vent.", "You hear welding.")
welded = 0
update_icon()
else
user << "\blue You need more welding fuel to complete this task."
return 1
examine()
set src in oview(1)
..()
if(welded)
usr << "It seems welded shut."
power_change()
if(powered(power_channel))
stat &= ~NOPOWER
user << "\blue The welding tool needs to be on to start this task."
else
stat |= NOPOWER
user << "\blue You need more welding fuel to complete this task."
return 1
else
..()
/obj/machinery/atmospherics/unary/vent_pump/examine()
set src in oview(1)
..()
if (get_dist(usr, src) <= 1)
usr << "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W"
else
usr << "You are too far away to read the gauge."
if(welded)
usr << "It seems welded shut."
/obj/machinery/atmospherics/unary/vent_pump/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/unary/vent_pump/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (node && node.level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/unary/vent_pump/Del()
if(initial_loc)
@@ -1,10 +1,13 @@
/obj/machinery/atmospherics/unary/vent_scrubber
icon = 'icons/obj/atmospherics/vent_scrubber.dmi'
icon_state = "off"
icon = 'icons/atmos/vent_scrubber.dmi'
icon_state = "map_scrubber"
name = "Air Scrubber"
desc = "Has a valve and pump attached to it"
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 pump is, in Watts. 7500 W ~ 10 HP
var/last_power_draw = 0
level = 1
@@ -15,255 +18,246 @@
var/on = 0
var/scrubbing = 1 //0 = siphoning, 1 = scrubbing
var/scrub_CO2 = 1
var/scrub_Toxins = 0
var/scrub_N2O = 0
var/list/scrubbing_gas = list()
var/volume_rate = 120
var/panic = 0 //is this scrubber panicked?
var/area_uid
var/radio_filter_out
var/radio_filter_in
New()
initial_loc = get_area(loc)
if (initial_loc.master)
initial_loc = initial_loc.master
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
if(ticker && ticker.current_state == 3)//if the game is running
src.initialize()
src.broadcast_status()
..()
/obj/machinery/atmospherics/unary/vent_scrubber/New()
..()
air_contents.volume = ATMOS_DEFAULT_VOLUME_FILTER
icon = null
initial_loc = get_area(loc)
if (initial_loc.master)
initial_loc = initial_loc.master
area_uid = initial_loc.uid
if (!id_tag)
assign_uid()
id_tag = num2text(uid)
if(ticker && ticker.current_state == 3)//if the game is running
src.initialize()
src.broadcast_status()
/obj/machinery/atmospherics/unary/vent_scrubber/update_icon(var/safety = 0)
if(!check_icon_cache())
return
overlays.Cut()
var/scrubber_icon = "scrubber"
var/turf/T = get_turf(src)
if(!istype(T))
return
if(!powered())
scrubber_icon += "off"
else
scrubber_icon += "[on ? "[scrubbing ? "on" : "in"]" : "off"]"
overlays += icon_manager.get_atmos_icon("device", , , scrubber_icon)
/obj/machinery/atmospherics/unary/vent_scrubber/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
if(T.intact && node && node.level == 1 && istype(node, /obj/machinery/atmospherics/pipe))
return
else
add_underlay(T, node, dir)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, radio_filter_in)
/obj/machinery/atmospherics/unary/vent_scrubber/proc/broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"area" = area_uid,
"tag" = id_tag,
"device" = "AScr",
"timestamp" = world.time,
"power" = on,
"scrubbing" = scrubbing,
"panic" = panic,
"filter_co2" = ("carbon_dioxide" in scrubbing_gas),
"filter_phoron" = ("phoron" in scrubbing_gas),
"filter_n2o" = ("sleeping_agent" in scrubbing_gas),
"sigtype" = "status"
)
if(!initial_loc.air_scrub_names[id_tag])
var/new_name = "[initial_loc.name] Air Scrubber #[initial_loc.air_scrub_names.len+1]"
initial_loc.air_scrub_names[id_tag] = new_name
src.name = new_name
initial_loc.air_scrub_info[id_tag] = signal.data
radio_connection.post_signal(src, signal, radio_filter_out)
return 1
/obj/machinery/atmospherics/unary/vent_scrubber/initialize()
..()
radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
if (frequency)
set_frequency(frequency)
/obj/machinery/atmospherics/unary/vent_scrubber/process()
..()
if (!node)
on = 0
//broadcast_status()
if(!on || (stat & (NOPOWER|BROKEN)))
update_use_power(0) //we got here because a player turned a pump off - definitely want to update.
last_flow_rate = 0
last_power_draw = 0
return 0
var/datum/gas_mixture/environment = loc.return_air()
var/power_draw = -1
if(scrubbing)
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SCRUBBER_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = scrub_gas(src, scrubbing_gas, environment, air_contents, transfer_moles, active_power_usage)
else //Just siphon all air
//limit flow rate from turfs
var/transfer_moles = min(environment.total_moles, environment.total_moles*MAX_SIPHON_FLOWRATE/environment.volume) //group_multiplier gets divided out here
power_draw = pump_gas(src, environment, air_contents, transfer_moles, active_power_usage)
if (power_draw < 0)
//update_use_power(0)
use_power = 0 //don't force update. Sure, we will continue to use power even though we're not pumping anything, but it is easier on the CPU
last_power_draw = 0
last_flow_rate = 0
else
last_power_draw = handle_power_draw(power_draw)
if(network)
network.update = 1
return 1
/obj/machinery/atmospherics/unary/vent_scrubber/hide(var/i) //to make the little pipe section invisible, the icon changes.
update_icon()
if(node && on && !(stat & (NOPOWER|BROKEN)))
if(scrubbing)
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
/obj/machinery/atmospherics/unary/vent_scrubber/receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"] != null)
on = text2num(signal.data["power"])
if(signal.data["power_toggle"] != null)
on = !on
if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing
panic = text2num(signal.data["panic_siphon"] != null)
if(panic)
on = 1
scrubbing = 0
else
icon_state = "[level == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
scrubbing = 1
if(signal.data["toggle_panic_siphon"] != null)
panic = !panic
if(panic)
on = 1
scrubbing = 0
else
scrubbing = 1
if(signal.data["scrubbing"] != null)
scrubbing = text2num(signal.data["scrubbing"])
if(signal.data["toggle_scrubbing"])
scrubbing = !scrubbing
var/list/toggle = list()
if(!isnull(signal.data["co2_scrub"]) && text2num(signal.data["co2_scrub"]) != ("carbon_dioxide" in scrubbing_gas))
toggle += "carbon_dioxide"
else if(signal.data["toggle_co2_scrub"])
toggle += "carbon_dioxide"
if(!isnull(signal.data["tox_scrub"]) && text2num(signal.data["tox_scrub"]) != ("phoron" in scrubbing_gas))
toggle += "phoron"
else if(signal.data["toggle_tox_scrub"])
toggle += "phoron"
if(!isnull(signal.data["n2o_scrub"]) && text2num(signal.data["n2o_scrub"]) != ("sleeping_agent" in scrubbing_gas))
toggle += "sleeping_agent"
else if(signal.data["toggle_n2o_scrub"])
toggle += "sleeping_agent"
scrubbing_gas ^= toggle
if(signal.data["init"] != null)
name = signal.data["init"]
return
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
radio_connection = radio_controller.add_object(src, frequency, radio_filter_in)
broadcast_status()
if(!radio_connection)
return 0
var/datum/signal/signal = new
signal.transmission_method = 1 //radio signal
signal.source = src
signal.data = list(
"area" = area_uid,
"tag" = id_tag,
"device" = "AScr",
"timestamp" = world.time,
"power" = on,
"scrubbing" = scrubbing,
"panic" = panic,
"filter_co2" = scrub_CO2,
"filter_phoron" = scrub_Toxins,
"filter_n2o" = scrub_N2O,
"sigtype" = "status"
)
if(!initial_loc.air_scrub_names[id_tag])
var/new_name = "[initial_loc.name] Air Scrubber #[initial_loc.air_scrub_names.len+1]"
initial_loc.air_scrub_names[id_tag] = new_name
src.name = new_name
initial_loc.air_scrub_info[id_tag] = signal.data
radio_connection.post_signal(src, signal, radio_filter_out)
return 1
initialize()
..()
radio_filter_in = frequency==initial(frequency)?(RADIO_FROM_AIRALARM):null
radio_filter_out = frequency==initial(frequency)?(RADIO_TO_AIRALARM):null
if (frequency)
set_frequency(frequency)
process()
..()
if(stat & (NOPOWER|BROKEN))
return
if (!node)
on = 0
//broadcast_status()
if(!on)
return 0
var/datum/gas_mixture/environment = loc.return_air()
if(scrubbing)
if((environment.phoron>0.001) || (environment.carbon_dioxide>0.001) || (environment.trace_gases.len>0))
var/transfer_moles = min(1, volume_rate/environment.volume)*environment.total_moles()
//Take a gas sample
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
if (isnull(removed)) //in space
return
//Filter it
var/datum/gas_mixture/filtered_out = new
filtered_out.temperature = removed.temperature
if(scrub_Toxins)
filtered_out.phoron = removed.phoron
removed.phoron = 0
if(scrub_CO2)
filtered_out.carbon_dioxide = removed.carbon_dioxide
removed.carbon_dioxide = 0
if(removed.trace_gases.len>0)
for(var/datum/gas/trace_gas in removed.trace_gases)
if(istype(trace_gas, /datum/gas/oxygen_agent_b))
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
else if(istype(trace_gas, /datum/gas/sleeping_agent) && scrub_N2O)
removed.trace_gases -= trace_gas
filtered_out.trace_gases += trace_gas
//Remix the resulting gases
air_contents.merge(filtered_out)
loc.assume_air(removed)
if(network)
network.update = 1
else //Just siphoning all air
if (air_contents.return_pressure()>=50*ONE_ATMOSPHERE)
return
var/transfer_moles = environment.total_moles()*(volume_rate/environment.volume)
var/datum/gas_mixture/removed = loc.remove_air(transfer_moles)
air_contents.merge(removed)
if(network)
network.update = 1
return 1
/* //unused piece of code
hide(var/i) //to make the little pipe section invisible, the icon changes.
if(on&&node)
if(scrubbing)
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]on"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]in"
else
icon_state = "[i == 1 && istype(loc, /turf/simulated) ? "h" : "" ]off"
on = 0
return
*/
receive_signal(datum/signal/signal)
if(stat & (NOPOWER|BROKEN))
return
if(!signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command"))
return 0
if(signal.data["power"] != null)
on = text2num(signal.data["power"])
if(signal.data["power_toggle"] != null)
on = !on
if(signal.data["panic_siphon"]) //must be before if("scrubbing" thing
panic = text2num(signal.data["panic_siphon"] != null)
if(panic)
on = 1
scrubbing = 0
volume_rate = 2000
else
scrubbing = 1
volume_rate = initial(volume_rate)
if(signal.data["toggle_panic_siphon"] != null)
panic = !panic
if(panic)
on = 1
scrubbing = 0
volume_rate = 2000
else
scrubbing = 1
volume_rate = initial(volume_rate)
if(signal.data["scrubbing"] != null)
scrubbing = text2num(signal.data["scrubbing"])
if(signal.data["toggle_scrubbing"])
scrubbing = !scrubbing
if(signal.data["co2_scrub"] != null)
scrub_CO2 = text2num(signal.data["co2_scrub"])
if(signal.data["toggle_co2_scrub"])
scrub_CO2 = !scrub_CO2
if(signal.data["tox_scrub"] != null)
scrub_Toxins = text2num(signal.data["tox_scrub"])
if(signal.data["toggle_tox_scrub"])
scrub_Toxins = !scrub_Toxins
if(signal.data["n2o_scrub"] != null)
scrub_N2O = text2num(signal.data["n2o_scrub"])
if(signal.data["toggle_n2o_scrub"])
scrub_N2O = !scrub_N2O
if(signal.data["init"] != null)
name = signal.data["init"]
return
if(signal.data["status"] != null)
spawn(2)
broadcast_status()
return //do not update_icon
// log_admin("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
if(signal.data["status"] != null)
spawn(2)
broadcast_status()
update_icon()
return
return //do not update_icon
power_change()
if(powered(power_channel))
stat &= ~NOPOWER
else
stat |= NOPOWER
// log_admin("DEBUG \[[world.timeofday]\]: vent_scrubber/receive_signal: unknown command \"[signal.data["command"]]\"\n[signal.debug_print()]")
spawn(2)
broadcast_status()
update_icon()
return
/obj/machinery/atmospherics/unary/vent_scrubber/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/unary/vent_scrubber/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (!(stat & NOPOWER) && on)
user << "\red You cannot unwrench this [src], turn it off first."
return 1
var/turf/T = src.loc
if (node && node.level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
/obj/machinery/atmospherics/unary/vent_scrubber/examine()
set src in oview(1)
..()
if (get_dist(usr, src) <= 1)
usr << "A small gauge in the corner reads [round(last_flow_rate, 0.1)] L/s; [round(last_power_draw)] W"
else
usr << "You are too far away to read the gauge."
/obj/machinery/atmospherics/unary/vent_scrubber/Del()
if(initial_loc)
+271 -295
View File
@@ -1,10 +1,11 @@
obj/machinery/atmospherics/valve
icon = 'icons/obj/atmospherics/valve.dmi'
icon_state = "valve0"
/obj/machinery/atmospherics/valve
icon = 'icons/atmos/valve.dmi'
icon_state = "map_valve0"
name = "manual valve"
desc = "A pipe valve"
level = 1
dir = SOUTH
initialize_directions = SOUTH|NORTH
@@ -17,322 +18,297 @@ obj/machinery/atmospherics/valve
var/datum/pipe_network/network_node1
var/datum/pipe_network/network_node2
open
open = 1
icon_state = "valve1"
/obj/machinery/atmospherics/valve/open
open = 1
icon_state = "map_valve1"
update_icon(animation)
if(animation)
flick("valve[src.open][!src.open]",src)
else
icon_state = "valve[open]"
/obj/machinery/atmospherics/valve/update_icon(animation)
if(animation)
flick("valve[src.open][!src.open]",src)
else
icon_state = "valve[open]"
New()
switch(dir)
if(NORTH || SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST || WEST)
initialize_directions = EAST|WEST
..()
/obj/machinery/atmospherics/valve/update_underlays()
if(..())
underlays.Cut()
var/turf/T = get_turf(src)
if(!istype(T))
return
add_underlay(T, node1, get_dir(src, node1))
add_underlay(T, node2, get_dir(src, node2))
network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
/obj/machinery/atmospherics/valve/hide(var/i)
update_underlays()
/obj/machinery/atmospherics/valve/New()
switch(dir)
if(NORTH || SOUTH)
initialize_directions = NORTH|SOUTH
if(EAST || WEST)
initialize_directions = EAST|WEST
..()
if(reference == node1)
network_node1 = new_network
if(open)
network_node2 = new_network
else if(reference == node2)
network_node2 = new_network
if(open)
network_node1 = new_network
if(new_network.normal_members.Find(src))
return 0
new_network.normal_members += src
/obj/machinery/atmospherics/valve/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(reference == node1)
network_node1 = new_network
if(open)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
network_node2 = new_network
else if(reference == node2)
network_node2 = new_network
if(open)
network_node1 = new_network
return null
if(new_network.normal_members.Find(src))
return 0
Del()
loc = null
new_network.normal_members += src
if(node1)
node1.disconnect(src)
del(network_node1)
if(node2)
node2.disconnect(src)
del(network_node2)
if(open)
if(reference == node1)
if(node2)
return node2.network_expand(new_network, src)
else if(reference == node2)
if(node1)
return node1.network_expand(new_network, src)
return null
/obj/machinery/atmospherics/valve/Del()
loc = null
if(node1)
node1.disconnect(src)
del(network_node1)
if(node2)
node2.disconnect(src)
del(network_node2)
node1 = null
node2 = null
..()
/obj/machinery/atmospherics/valve/proc/open()
if(open) return 0
open = 1
update_icon()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
return 1
/obj/machinery/atmospherics/valve/proc/close()
if(!open)
return 0
open = 0
update_icon()
if(network_node1)
del(network_node1)
if(network_node2)
del(network_node2)
build_network()
return 1
/obj/machinery/atmospherics/valve/proc/normalize_dir()
if(dir==3)
dir = 1
else if(dir==12)
dir = 4
/obj/machinery/atmospherics/valve/attack_ai(mob/user as mob)
return
/obj/machinery/atmospherics/valve/attack_paw(mob/user as mob)
return attack_hand(user)
/obj/machinery/atmospherics/valve/attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.open)
src.close()
else
src.open()
/obj/machinery/atmospherics/valve/process()
..()
. = PROCESS_KILL
return
/obj/machinery/atmospherics/valve/initialize()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_directions)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
build_network()
update_icon()
update_underlays()
if(openDuringInit)
close()
open()
openDuringInit = 0
/obj/machinery/atmospherics/valve/build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
/obj/machinery/atmospherics/valve/return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
return null
/obj/machinery/atmospherics/valve/reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
return 1
/obj/machinery/atmospherics/valve/return_network_air(datum/network/reference)
return null
/obj/machinery/atmospherics/valve/disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network_node1)
node1 = null
else if(reference==node2)
del(network_node2)
node2 = null
..()
update_underlays()
proc/open()
return null
if(open) return 0
/obj/machinery/atmospherics/valve/digital // can be controlled by AI
name = "digital valve"
desc = "A digitally controlled valve."
icon = 'icons/atmos/digital_valve.dmi'
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
open = 1
/obj/machinery/atmospherics/valve/digital/attack_ai(mob/user as mob)
return src.attack_hand(user)
/obj/machinery/atmospherics/valve/digital/attack_hand(mob/user as mob)
if(!powered())
return
if(!src.allowed(user))
user << "\red Access denied."
return
..()
/obj/machinery/atmospherics/valve/digital/open
open = 1
icon_state = "map_valve1"
/obj/machinery/atmospherics/valve/digital/power_change()
var/old_stat = stat
..()
if(old_stat != stat)
update_icon()
if(network_node1&&network_node2)
network_node1.merge(network_node2)
network_node2 = network_node1
/obj/machinery/atmospherics/valve/digital/update_icon()
..()
if(!powered())
icon_state = "valve[open]nopower"
if(network_node1)
network_node1.update = 1
else if(network_node2)
network_node2.update = 1
/obj/machinery/atmospherics/valve/digital/proc/set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
return 1
/obj/machinery/atmospherics/valve/digital/initialize()
..()
if(frequency)
set_frequency(frequency)
proc/close()
/obj/machinery/atmospherics/valve/digital/receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
if(!open)
return 0
switch(signal.data["command"])
if("valve_open")
if(!open)
open()
open = 0
update_icon()
if("valve_close")
if(open)
close()
if(network_node1)
del(network_node1)
if(network_node2)
del(network_node2)
build_network()
return 1
proc/normalize_dir()
if(dir==3)
dir = 1
else if(dir==12)
dir = 4
attack_ai(mob/user as mob)
return
attack_paw(mob/user as mob)
return attack_hand(user)
attack_hand(mob/user as mob)
src.add_fingerprint(usr)
update_icon(1)
sleep(10)
if (src.open)
src.close()
else
src.open()
process()
..()
. = PROCESS_KILL
/* if(open && (!node1 || !node2))
close()
if(!node1)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if (!node2)
if(!nodealert)
//world << "Missing node from [src] at [src.x],[src.y],[src.z]"
nodealert = 1
else if (nodealert)
nodealert = 0
*/
return
initialize()
normalize_dir()
var/node1_dir
var/node2_dir
for(var/direction in cardinal)
if(direction&initialize_directions)
if (!node1_dir)
node1_dir = direction
else if (!node2_dir)
node2_dir = direction
for(var/obj/machinery/atmospherics/target in get_step(src,node1_dir))
if(target.initialize_directions & get_dir(target,src))
node1 = target
break
for(var/obj/machinery/atmospherics/target in get_step(src,node2_dir))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
build_network()
if(openDuringInit)
close()
open()
openDuringInit = 0
/*
var/connect_directions
switch(dir)
if(NORTH)
connect_directions = NORTH|SOUTH
if(SOUTH)
connect_directions = NORTH|SOUTH
if(EAST)
connect_directions = EAST|WEST
if(WEST)
connect_directions = EAST|WEST
if("valve_toggle")
if(open)
close()
else
connect_directions = dir
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
connect_directions &= ~direction
node1 = target
break
if(node1)
break
for(var/direction in cardinal)
if(direction&connect_directions)
for(var/obj/machinery/atmospherics/target in get_step(src,direction))
if(target.initialize_directions & get_dir(target,src))
node2 = target
break
if(node1)
break
*/
build_network()
if(!network_node1 && node1)
network_node1 = new /datum/pipe_network()
network_node1.normal_members += src
network_node1.build_network(node1, src)
if(!network_node2 && node2)
network_node2 = new /datum/pipe_network()
network_node2.normal_members += src
network_node2.build_network(node2, src)
return_network(obj/machinery/atmospherics/reference)
build_network()
if(reference==node1)
return network_node1
if(reference==node2)
return network_node2
return null
reassign_network(datum/pipe_network/old_network, datum/pipe_network/new_network)
if(network_node1 == old_network)
network_node1 = new_network
if(network_node2 == old_network)
network_node2 = new_network
open()
/obj/machinery/atmospherics/valve/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (istype(src, /obj/machinery/atmospherics/valve/digital))
user << "\red You cannot unwrench this [src], it's too complicated."
return 1
return_network_air(datum/network/reference)
return null
disconnect(obj/machinery/atmospherics/reference)
if(reference==node1)
del(network_node1)
node1 = null
else if(reference==node2)
del(network_node2)
node2 = null
return null
digital // can be controlled by AI
name = "digital valve"
desc = "A digitally controlled valve."
icon = 'icons/obj/atmospherics/digital_valve.dmi'
attack_ai(mob/user as mob)
return src.attack_hand(user)
attack_hand(mob/user as mob)
if(!src.allowed(user))
user << "\red Access denied."
return
..()
//Radio remote control
proc
set_frequency(new_frequency)
radio_controller.remove_object(src, frequency)
frequency = new_frequency
if(frequency)
radio_connection = radio_controller.add_object(src, frequency, RADIO_ATMOSIA)
var/frequency = 0
var/id = null
var/datum/radio_frequency/radio_connection
initialize()
..()
if(frequency)
set_frequency(frequency)
receive_signal(datum/signal/signal)
if(!signal.data["tag"] || (signal.data["tag"] != id))
return 0
switch(signal.data["command"])
if("valve_open")
if(!open)
open()
if("valve_close")
if(open)
close()
if("valve_toggle")
if(open)
close()
else
open()
attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
if (!istype(W, /obj/item/weapon/wrench))
return ..()
if (istype(src, /obj/machinery/atmospherics/valve/digital))
user << "\red You cannot unwrench this [src], it's too complicated."
return 1
var/turf/T = src.loc
if (level==1 && isturf(T) && T.intact)
user << "\red You must remove the plating first."
return 1
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
var/datum/gas_mixture/int_air = return_air()
var/datum/gas_mixture/env_air = loc.return_air()
if ((int_air.return_pressure()-env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
user << "\red You cannot unwrench this [src], it too exerted due to internal pressure."
add_fingerprint(user)
return 1
playsound(src.loc, 'sound/items/Ratchet.ogg', 50, 1)
user << "\blue You begin to unfasten \the [src]..."
if (do_after(user, 40))
user.visible_message( \
"[user] unfastens \the [src].", \
"\blue You have unfastened \the [src].", \
"You hear ratchet.")
new /obj/item/pipe(loc, make_from=src)
del(src)
+8 -134
View File
@@ -2,16 +2,17 @@ var/global/list/datum/pipe_network/pipe_networks = list()
datum/pipe_network
var/list/datum/gas_mixture/gases = list() //All of the gas_mixtures continuously connected in this network
var/volume = 0 //caches the total volume for atmos machines to use in gas calculations
var/list/obj/machinery/atmospherics/normal_members = list()
var/list/datum/pipeline/line_members = list()
//membership roster to go through for updates and what not
var/update = 1
var/datum/gas_mixture/air_transient = null
//var/datum/gas_mixture/air_transient = null
New()
air_transient = new()
//air_transient = new()
..()
@@ -61,6 +62,7 @@ datum/pipe_network
//Go through membership roster and make sure gases is up to date
gases = list()
volume = 0
for(var/obj/machinery/atmospherics/normal_member in normal_members)
var/result = normal_member.return_network_air(src)
@@ -68,137 +70,9 @@ datum/pipe_network
for(var/datum/pipeline/line_member in line_members)
gases += line_member.air
for(var/datum/gas_mixture/air in gases)
volume += air.volume
proc/reconcile_air()
//Perfectly equalize all gases members instantly
//Calculate totals from individual components
var/total_thermal_energy = 0
var/total_heat_capacity = 0
air_transient.volume = 0
air_transient.oxygen = 0
air_transient.nitrogen = 0
air_transient.phoron = 0
air_transient.carbon_dioxide = 0
air_transient.trace_gases = list()
for(var/datum/gas_mixture/gas in gases)
air_transient.volume += gas.volume
var/temp_heatcap = gas.heat_capacity()
total_thermal_energy += gas.temperature*temp_heatcap
total_heat_capacity += temp_heatcap
air_transient.oxygen += gas.oxygen
air_transient.nitrogen += gas.nitrogen
air_transient.phoron += gas.phoron
air_transient.carbon_dioxide += gas.carbon_dioxide
if(gas.trace_gases.len)
for(var/datum/gas/trace_gas in gas.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in air_transient.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
air_transient.trace_gases += corresponding
corresponding.moles += trace_gas.moles
if(air_transient.volume > 0)
if(total_heat_capacity > 0)
air_transient.temperature = total_thermal_energy/total_heat_capacity
//Allow air mixture to react
if(air_transient.react())
update = 1
else
air_transient.temperature = 0
//Update individual gas_mixtures by volume ratio
for(var/datum/gas_mixture/gas in gases)
gas.oxygen = air_transient.oxygen*gas.volume/air_transient.volume
gas.nitrogen = air_transient.nitrogen*gas.volume/air_transient.volume
gas.phoron = air_transient.phoron*gas.volume/air_transient.volume
gas.carbon_dioxide = air_transient.carbon_dioxide*gas.volume/air_transient.volume
gas.temperature = air_transient.temperature
if(air_transient.trace_gases.len)
for(var/datum/gas/trace_gas in air_transient.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
gas.trace_gases += corresponding
corresponding.moles = trace_gas.moles*gas.volume/air_transient.volume
gas.update_values()
air_transient.update_values()
return 1
proc/equalize_gases(datum/gas_mixture/list/gases)
//Perfectly equalize all gases members instantly
//Calculate totals from individual components
var/total_volume = 0
var/total_thermal_energy = 0
var/total_heat_capacity = 0
var/total_oxygen = 0
var/total_nitrogen = 0
var/total_phoron = 0
var/total_carbon_dioxide = 0
var/list/total_trace_gases = list()
for(var/datum/gas_mixture/gas in gases)
total_volume += gas.volume
var/temp_heatcap = gas.heat_capacity()
total_thermal_energy += gas.temperature*temp_heatcap
total_heat_capacity += temp_heatcap
total_oxygen += gas.oxygen
total_nitrogen += gas.nitrogen
total_phoron += gas.phoron
total_carbon_dioxide += gas.carbon_dioxide
if(gas.trace_gases.len)
for(var/datum/gas/trace_gas in gas.trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in total_trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
total_trace_gases += corresponding
corresponding.moles += trace_gas.moles
if(total_volume > 0)
//Calculate temperature
var/temperature = 0
if(total_heat_capacity > 0)
temperature = total_thermal_energy/total_heat_capacity
//Update individual gas_mixtures by volume ratio
for(var/datum/gas_mixture/gas in gases)
gas.oxygen = total_oxygen*gas.volume/total_volume
gas.nitrogen = total_nitrogen*gas.volume/total_volume
gas.phoron = total_phoron*gas.volume/total_volume
gas.carbon_dioxide = total_carbon_dioxide*gas.volume/total_volume
gas.temperature = temperature
if(total_trace_gases.len)
for(var/datum/gas/trace_gas in total_trace_gases)
var/datum/gas/corresponding = locate(trace_gas.type) in gas.trace_gases
if(!corresponding)
corresponding = new trace_gas.type()
gas.trace_gases += corresponding
corresponding.moles = trace_gas.moles*gas.volume/total_volume
gas.update_values()
return 1
equalize_gases(gases)
+12 -21
View File
@@ -1,4 +1,3 @@
#define STEFAN_BOLTZMANN_CONSTANT 0.0000000567
datum/pipeline
var/datum/gas_mixture/air
@@ -37,22 +36,9 @@ datum/pipeline
for(var/obj/machinery/atmospherics/pipe/member in members)
member.air_temporary = new
member.air_temporary.copy_from(air)
member.air_temporary.volume = member.volume
member.air_temporary.oxygen = air.oxygen*member.volume/air.volume
member.air_temporary.nitrogen = air.nitrogen*member.volume/air.volume
member.air_temporary.phoron = air.phoron*member.volume/air.volume
member.air_temporary.carbon_dioxide = air.carbon_dioxide*member.volume/air.volume
member.air_temporary.temperature = air.temperature
if(air.trace_gases.len)
for(var/datum/gas/trace_gas in air.trace_gases)
var/datum/gas/corresponding = new trace_gas.type()
member.air_temporary.trace_gases += corresponding
corresponding.moles = trace_gas.moles*member.volume/air.volume
member.air_temporary.update_values()
member.air_temporary.multiply(member.volume / air.volume)
proc/build_pipeline(obj/machinery/atmospherics/pipe/base)
air = new
@@ -213,10 +199,15 @@ datum/pipeline
air.temperature -= heat/total_heat_capacity
if(network)
network.update = 1
proc/radiate_heat(surface, thermal_conductivity)
var/total_heat_capacity = air.heat_capacity()
var/heat = STEFAN_BOLTZMANN_CONSTANT * surface * air.temperature ** 4 * thermal_conductivity
air.temperature = max(0, air.temperature - heat / total_heat_capacity)
//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)
air.add_thermal_energy(heat_gain)
if(network)
network.update = 1
+15 -15
View File
@@ -1,10 +1,11 @@
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
var/surface = 2 //surface area in m^2
minimum_temperature_difference = 20
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
@@ -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
@@ -53,13 +58,14 @@ obj/machinery/atmospherics/pipe/simple/heat_exchanging
var/datum/gas_mixture/pipe_air = return_air()
if(abs(environment_temperature-pipe_air.temperature) > minimum_temperature_difference)
parent.temperature_interact(loc, volume, thermal_conductivity)
else
parent.radiate_heat(surface, 1)
else if(istype(loc, /turf/space/))
parent.radiate_heat_to_space(surface, 1)
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
-16
View File
@@ -1,16 +0,0 @@
client/verb/discon_pipes()
set name = "Show Disconnected Pipes"
set category = "Debug"
for(var/obj/machinery/atmospherics/pipe/simple/P in world)
if(!P.node1 || !P.node2)
usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]"
for(var/obj/machinery/atmospherics/pipe/manifold/P in world)
if(!P.node1 || !P.node2 || !P.node3)
usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]"
for(var/obj/machinery/atmospherics/pipe/manifold4w/P in world)
if(!P.node1 || !P.node2 || !P.node3 || !P.node4)
usr << "[P], [P.x], [P.y], [P.z], [P.loc.loc]"
//With thanks to mini. Check before use, uncheck after. Do Not Use on a live server.
+460 -459
View File
File diff suppressed because it is too large Load Diff
@@ -65,7 +65,6 @@ var/jungle_plants_init = 0
reagent_effects = shuffle(reagent_effects)
/obj/item/weapon/reagent_containers/food/snacks/grown/jungle_fruit
seed = ""
name = "jungle fruit"
desc = "It smells weird and looks off."
icon = 'code/WorkInProgress/Cael_Aislinn/Jungle/jungle.dmi'
@@ -140,20 +140,19 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
//the amount of phoron pulled in each update is relative to the field strength, with 50T (max field strength) = 100% of area covered by the field
//at minimum strength, 0.25% of the field volume is pulled in per update (?)
//have a max of 1000 moles suspended
if(held_phoron.phoron < transfer_ratio * 1000)
if(held_phoron.gas["phoron"] < transfer_ratio * 1000)
var/moles_covered = environment.return_pressure()*volume_covered/(environment.temperature * R_IDEAL_GAS_EQUATION)
//world << "\blue moles_covered: [moles_covered]"
//
var/datum/gas_mixture/gas_covered = environment.remove(moles_covered)
var/datum/gas_mixture/phoron_captured = new /datum/gas_mixture()
//
phoron_captured.phoron = round(gas_covered.phoron * transfer_ratio)
phoron_captured.gas["phoron"] = round(gas_covered.gas["phoron"] * transfer_ratio)
//world << "\blue[phoron_captured.phoron] moles of phoron captured"
phoron_captured.temperature = gas_covered.temperature
phoron_captured.update_values()
//
gas_covered.phoron -= phoron_captured.phoron
gas_covered.update_values()
gas_covered.adjust_gas("phoron", -phoron_captured.gas["phoron"])
//
held_phoron.merge(phoron_captured)
//
@@ -171,7 +170,7 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
//change held phoron temp according to energy levels
//SPECIFIC_HEAT_TOXIN
if(mega_energy > 0 && held_phoron.phoron)
if(mega_energy > 0 && held_phoron.gas["phoron"])
var/heat_capacity = held_phoron.heat_capacity()//200 * number of phoron moles
if(heat_capacity > 0.0003) //formerly MINIMUM_HEAT_CAPACITY
held_phoron.temperature = (heat_capacity + mega_energy * 35000)/heat_capacity
@@ -179,7 +178,7 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
//if there is too much phoron in the field, lose some
/*if( held_phoron.phoron > (MOLES_CELLSTANDARD * 7) * (50 / field_strength) )
LosePhoron()*/
if(held_phoron.phoron > 1)
if(held_phoron.gas["phoron"] > 1)
//lose a random amount of phoron back into the air, increased by the field strength (want to switch this over to frequency eventually)
var/loss_ratio = rand() * (0.05 + (0.05 * 50 / field_strength))
//world << "lost [loss_ratio*100]% of held phoron"
@@ -187,16 +186,16 @@ Deuterium-tritium fusion: 4.5 x 10^7 K
var/datum/gas_mixture/phoron_lost = new
phoron_lost.temperature = held_phoron.temperature
//
phoron_lost.phoron = held_phoron.phoron * loss_ratio
phoron_lost.gas["phoron"] = held_phoron.gas["phoron"] * loss_ratio
//phoron_lost.update_values()
held_phoron.phoron -= held_phoron.phoron * loss_ratio
held_phoron.gas["phoron"] -= held_phoron.gas["phoron"] * loss_ratio
//held_phoron.update_values()
//
environment.merge(phoron_lost)
radiation += loss_ratio * mega_energy * 0.1
mega_energy -= loss_ratio * mega_energy * 0.1
else
held_phoron.phoron = 0
held_phoron.gas["phoron"] = null
//held_phoron.update_values()
//handle some reactants formatting
@@ -1,44 +0,0 @@
//---------- external shield generator
//generates an energy field that loops around any built up area in space (is useless inside) halts movement and airflow, is blocked by walls, windows, airlocks etc
/obj/machinery/shield_gen/external
name = "hull shield generator"
/obj/machinery/shield_gen/external/New()
..()
/obj/machinery/shield_gen/external/get_shielded_turfs()
var
list
open = list(get_turf(src))
closed = list()
while(open.len)
for(var/turf/T in open)
for(var/turf/O in orange(1, T))
if(get_dist(O,src) > field_radius)
continue
var/add_this_turf = 0
if(istype(O,/turf/space))
for(var/turf/simulated/G in orange(1, O))
add_this_turf = 1
break
//uncomment this for structures (but not lattices) to be surrounded by shield as well
/*if(!add_this_turf)
for(var/obj/structure/S in orange(1, O))
if(!istype(S, /obj/structure/lattice))
add_this_turf = 1
break
if(add_this_turf)
for(var/obj/structure/S in O)
if(!istype(S, /obj/structure/lattice))
add_this_turf = 0
break*/
if(add_this_turf && !(O in open) && !(O in closed))
open += O
open -= T
closed += T
return closed
@@ -30,7 +30,7 @@
ui_interact(user)
/obj/machinery/computer/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
/obj/machinery/computer/engines/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
return
@@ -50,7 +50,7 @@
data["engines_info"] = enginfo
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "engines_control.tmpl", "[linked.name] Engines Control", 380, 530)
ui.set_initial_data(data)
@@ -70,7 +70,7 @@
ui_interact(user)
/obj/machinery/computer/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
/obj/machinery/computer/helm/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(!linked)
return
@@ -101,7 +101,7 @@
data["locations"] = locations
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "helm.tmpl", "[linked.name] Helm Control", 380, 530)
ui.set_initial_data(data)
@@ -44,7 +44,7 @@
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
return shuttle && destination && get_dist(home, destination) <= shuttle.range
/obj/machinery/computer/shuttle_control/explore/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
/obj/machinery/computer/shuttle_control/explore/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
var/data[0]
var/datum/shuttle/ferry/shuttle = shuttle_controller.shuttles[shuttle_tag]
if (!istype(shuttle))
@@ -103,7 +103,7 @@
"can_force" = can_go && shuttle.can_force(),
)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
ui = new(user, src, ui_key, "shuttle_control_console_exploration.tmpl", "[shuttle_tag] Shuttle Control", 470, 310)
+2 -2
View File
@@ -97,8 +97,8 @@
//is_blocked_turf(var/turf/T)
usr << "\blue You finish placing the [src]." //Git Test
/obj/item/taperoll/afterattack(var/atom/A, mob/user as mob)
if (istype(A, /obj/machinery/door/airlock))
/obj/item/taperoll/afterattack(var/atom/A, mob/user as mob, proximity)
if (proximity && istype(A, /obj/machinery/door/airlock))
var/turf/T = get_turf(A)
var/obj/item/tape/P = new tape_type(T.x,T.y,T.z)
P.loc = locate(T.x,T.y,T.z)
@@ -83,9 +83,9 @@ proc/assign_sec_to_department(var/mob/living/carbon/human/H)
else
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_in_backpack)
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
implant_loyalty(H)
return 1
/obj/item/device/radio/headset/headset_sec/department/New()
+10 -12
View File
@@ -23,9 +23,9 @@
H.equip_to_slot_or_del(new /obj/item/weapon/gun/energy/taser(H), slot_s_store)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_in_backpack)
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
H.implant_loyalty(src) // Will not do so if config is set to disallow.
return 1
@@ -52,9 +52,9 @@
H.equip_to_slot_or_del(new /obj/item/device/flash(H), slot_l_store)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_in_backpack)
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
H.implant_loyalty(src) // // Will not do so if config is set to disallow.
return 1
@@ -89,9 +89,7 @@
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/evidence(H), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/device/detective_scanner(H), slot_in_backpack)
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
H.implant_loyalty(src) // Will not do so if config is set to disallow.
return 1
@@ -118,9 +116,9 @@
H.equip_to_slot_or_del(new /obj/item/device/flash(H), slot_l_store)
H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H.back), slot_in_backpack)
H.equip_to_slot_or_del(new /obj/item/weapon/handcuffs(H), slot_in_backpack)
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
H.implant_loyalty(src) // Will not do so if config is set to disallow.
return 1
/datum/job/hop
@@ -70,7 +70,7 @@
new /obj/item/weapon/storage/backpack/satchel_sec(src)
new /obj/item/weapon/cartridge/hos(src)
new /obj/item/device/radio/headset/heads/hos(src)
new /obj/item/weapon/storage/lockbox/loyalty(src)
if (config.use_loyalty_implants) new /obj/item/weapon/storage/lockbox/loyalty(src)
new /obj/item/weapon/storage/flashbang_kit(src)
new /obj/item/weapon/storage/belt/security(src)
new /obj/item/device/flash(src)
+3 -3
View File
@@ -164,15 +164,15 @@
return
if(use_power && istype(battery) && battery.charge > 0)
if(use_power == 1)
battery.use(idle_power_usage)
battery.use(idle_power_usage*CELLRATE) //idle and active_power_usage are in WATTS. battery.use() expects CHARGE.
else
battery.use(active_power_usage)
battery.use(active_power_usage*CELLRATE)
return 1
return 0
use_power(var/amount, var/chan = -1)
if(battery && battery.charge > 0)
battery.use(amount)
battery.use(amount*CELLRATE)
power_change()
if( !battery || battery.charge <= 0 )
+1 -3
View File
@@ -231,9 +231,7 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams
// equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(src), slot_in_backpack) // Regular medkit
// Loyalty implants
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src)
L.imp_in = src
L.implanted = 1
implant_loyalty(src)
// ID cards
var/obj/item/weapon/card/id/E = new(src)
+4 -193
View File
@@ -86,7 +86,8 @@ Class Procs:
/connection_edge/proc/tick()
/connection_edge/proc/flow(list/movable, differential, repelled)
for(var/atom/movable/M in movable)
for(var/i = 1; i <= movable.len; i++)
var/atom/movable/M = movable[i]
//If they're already being tossed, don't do it again.
if(M.last_airflow > world.time - vsc.airflow_delay) continue
@@ -156,7 +157,7 @@ Class Procs:
return
//air_master.equalize(A, B)
ShareRatio(A.air,B.air,coefficient)
A.air.share_ratio(B.air, coefficient)
air_master.mark_zone_update(A)
air_master.mark_zone_update(B)
//world << "equalized."
@@ -215,7 +216,7 @@ Class Procs:
return
//world << "[id]: Tick [air_master.current_cycle]: To [B]!"
//A.air.mimic(B, coefficient)
ShareSpace(A.air,air,dbg_out)
A.air.share_space(air, dbg_out)
air_master.mark_zone_update(A)
var/differential = A.air.return_pressure() - air.return_pressure()
@@ -224,196 +225,6 @@ Class Procs:
var/list/attracted = A.movables()
flow(attracted, abs(differential), differential < 0)
var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
ratio = sharing_lookup_table[6]
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
size = max(1,A.group_multiplier)
share_size = max(1,B.group_multiplier)
full_oxy = A.oxygen * size
full_nitro = A.nitrogen * size
full_co2 = A.carbon_dioxide * size
full_phoron = A.phoron * size
full_heat_capacity = A.heat_capacity() * size
s_full_oxy = B.oxygen * share_size
s_full_nitro = B.nitrogen * share_size
s_full_co2 = B.carbon_dioxide * share_size
s_full_phoron = B.phoron * share_size
s_full_heat_capacity = B.heat_capacity() * share_size
oxy_avg = (full_oxy + s_full_oxy) / (size + share_size)
nit_avg = (full_nitro + s_full_nitro) / (size + share_size)
co2_avg = (full_co2 + s_full_co2) / (size + share_size)
phoron_avg = (full_phoron + s_full_phoron) / (size + share_size)
temp_avg = (A.temperature * full_heat_capacity + B.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1-ratio) + nit_avg )
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
A.phoron = max(0, (A.phoron - phoron_avg) * (1-ratio) + phoron_avg )
A.temperature = max(0, (A.temperature - temp_avg) * (1-ratio) + temp_avg )
B.oxygen = max(0, (B.oxygen - oxy_avg) * (1-ratio) + oxy_avg )
B.nitrogen = max(0, (B.nitrogen - nit_avg) * (1-ratio) + nit_avg )
B.carbon_dioxide = max(0, (B.carbon_dioxide - co2_avg) * (1-ratio) + co2_avg )
B.phoron = max(0, (B.phoron - phoron_avg) * (1-ratio) + phoron_avg )
B.temperature = max(0, (B.temperature - temp_avg) * (1-ratio) + temp_avg )
for(var/datum/gas/G in A.trace_gases)
var/datum/gas/H = locate(G.type) in B.trace_gases
if(H)
var/G_avg = (G.moles*size + H.moles*share_size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
else
H = new G.type
B.trace_gases += H
var/G_avg = (G.moles*size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
for(var/datum/gas/G in B.trace_gases)
var/datum/gas/H = locate(G.type) in A.trace_gases
if(!H)
H = new G.type
A.trace_gases += H
var/G_avg = (G.moles*size) / (size+share_size)
G.moles = (G.moles - G_avg) * (1-ratio) + G_avg
H.moles = (H.moles - G_avg) * (1-ratio) + G_avg
A.update_values()
B.update_values()
if(A.compare(B)) return 1
else return 0
proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output)
//A modified version of ShareRatio for spacing gas at the same rate as if it were going into a large airless room.
if(!unsimulated_tiles)
return 0
var
unsim_oxygen = 0
unsim_nitrogen = 0
unsim_co2 = 0
unsim_phoron = 0
unsim_heat_capacity = 0
unsim_temperature = 0
size = max(1,A.group_multiplier)
var/tileslen
var/share_size
if(istype(unsimulated_tiles, /datum/gas_mixture))
var/datum/gas_mixture/avg_unsim = unsimulated_tiles
unsim_oxygen = avg_unsim.oxygen
unsim_co2 = avg_unsim.carbon_dioxide
unsim_nitrogen = avg_unsim.nitrogen
unsim_phoron = avg_unsim.phoron
unsim_temperature = avg_unsim.temperature
share_size = max(1, max(size + 3, 1) + avg_unsim.group_multiplier)
tileslen = avg_unsim.group_multiplier
if(dbg_output)
world << "O2: [unsim_oxygen] N2: [unsim_nitrogen] Size: [share_size] Tiles: [tileslen]"
else if(istype(unsimulated_tiles, /list))
if(!unsimulated_tiles.len)
return 0
// We use the same size for the potentially single space tile
// as we use for the entire room. Why is this?
// Short answer: We do not want larger rooms to depressurize more
// slowly than small rooms, preserving our good old "hollywood-style"
// oh-shit effect when large rooms get breached, but still having small
// rooms remain pressurized for long enough to make escape possible.
share_size = max(1, max(size + 3, 1) + unsimulated_tiles.len)
var/correction_ratio = share_size / unsimulated_tiles.len
for(var/turf/T in unsimulated_tiles)
unsim_oxygen += T.oxygen
unsim_co2 += T.carbon_dioxide
unsim_nitrogen += T.nitrogen
unsim_phoron += T.phoron
unsim_temperature += T.temperature/unsimulated_tiles.len
//These values require adjustment in order to properly represent a room of the specified size.
unsim_oxygen *= correction_ratio
unsim_co2 *= correction_ratio
unsim_nitrogen *= correction_ratio
unsim_phoron *= correction_ratio
tileslen = unsimulated_tiles.len
else //invalid input type
return 0
unsim_heat_capacity = HEAT_CAPACITY_CALCULATION(unsim_oxygen, unsim_co2, unsim_nitrogen, unsim_phoron)
var
ratio = sharing_lookup_table[6]
old_pressure = A.return_pressure()
full_oxy = A.oxygen * size
full_nitro = A.nitrogen * size
full_co2 = A.carbon_dioxide * size
full_phoron = A.phoron * size
full_heat_capacity = A.heat_capacity() * size
oxy_avg = (full_oxy + unsim_oxygen*share_size) / (size + share_size)
nit_avg = (full_nitro + unsim_nitrogen*share_size) / (size + share_size)
co2_avg = (full_co2 + unsim_co2*share_size) / (size + share_size)
phoron_avg = (full_phoron + unsim_phoron*share_size) / (size + share_size)
temp_avg = 0
if((full_heat_capacity + unsim_heat_capacity) > 0)
temp_avg = (A.temperature * full_heat_capacity + unsim_temperature * unsim_heat_capacity) / (full_heat_capacity + unsim_heat_capacity)
if(sharing_lookup_table.len >= tileslen) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[tileslen]
if(dbg_output)
world << "Ratio: [ratio]"
world << "Avg O2: [oxy_avg] N2: [nit_avg]"
A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg )
A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg )
A.carbon_dioxide = max(0, (A.carbon_dioxide - co2_avg) * (1 - ratio) + co2_avg )
A.phoron = max(0, (A.phoron - phoron_avg) * (1 - ratio) + phoron_avg )
A.temperature = max(TCMB, (A.temperature - temp_avg) * (1 - ratio) + temp_avg )
for(var/datum/gas/G in A.trace_gases)
var/G_avg = (G.moles * size) / (size + share_size)
G.moles = (G.moles - G_avg) * (1 - ratio) + G_avg
A.update_values()
if(dbg_output) world << "Result: [abs(old_pressure - A.return_pressure())] kPa"
return abs(old_pressure - A.return_pressure())
proc/ShareHeat(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles)
//This implements a simplistic version of the Stefan-Boltzmann law.
var/energy_delta = ((A.temperature - B.temperature) ** 4) * 5.6704e-8 * connecting_tiles * 2.5
+10 -2
View File
@@ -73,6 +73,7 @@ Class Procs:
//Geometry updates lists
/datum/controller/air_system/var/list/tiles_to_update = list()
/datum/controller/air_system/var/list/zones_to_update = list()
/datum/controller/air_system/var/list/active_fire_zones = list()
/datum/controller/air_system/var/list/active_hotspots = list()
/datum/controller/air_system/var/active_zones = 0
@@ -171,9 +172,16 @@ Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_coun
for(var/connection_edge/edge in edges)
edge.tick()
//Process fires.
//Process fire zones.
if(.)
tick_progress = "processing fire"
tick_progress = "processing fire zones"
for(var/zone/Z in active_fire_zones)
Z.process_fire()
//Process hotspots.
if(.)
tick_progress = "processing hotspots"
for(var/obj/fire/fire in active_hotspots)
fire.process()
+2 -1
View File
@@ -19,7 +19,8 @@ client/proc/Zone_Info(turf/T as null|turf)
mob << "No zone here."
var/datum/gas_mixture/mix = T.return_air()
mob << "[mix.return_pressure()] kPa [mix.temperature]C"
mob << "O2: [mix.oxygen] N2: [mix.nitrogen] CO2: [mix.carbon_dioxide] TX: [mix.phoron]"
for(var/g in mix.gas)
mob << "[g]: [mix.gas[g]]\n"
else
if(zone_debug_images)
for(var/zone in zone_debug_images)
+131 -131
View File
@@ -10,6 +10,7 @@ Attach to transfer valve and open. BOOM.
*/
/turf/var/obj/fire/fire = null
//Some legacy definitions so fires can be started.
atom/proc/temperature_expose(datum/gas_mixture/air, exposed_temperature, exposed_volume)
@@ -34,12 +35,54 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
if(air_contents.check_combustability(liquid))
igniting = 1
if(! (locate(/obj/fire) in src))
new /obj/fire(src,1000)
create_fire(1000)
return igniting
/zone/proc/process_fire()
if(!air.check_combustability())
for(var/turf/simulated/T in fire_tiles)
if(istype(T.fire))
T.fire.RemoveFire()
T.fire = null
fire_tiles.Cut()
if(!fire_tiles.len)
air_master.active_fire_zones.Remove(src)
return
var/datum/gas_mixture/burn_gas = air.remove_ratio(vsc.fire_consuption_rate, fire_tiles.len)
var/gm = burn_gas.group_multiplier
burn_gas.group_multiplier = 1
burn_gas.zburn(force_burn = 1, no_check = 1)
burn_gas.group_multiplier = gm
air.merge(burn_gas)
var/firelevel = air.calculate_firelevel()
for(var/turf/T in fire_tiles)
if(T.fire)
T.fire.firelevel = firelevel
else
fire_tiles -= T
/turf/proc/create_fire(fl)
return 0
/turf/simulated/create_fire(fl)
if(fire)
fire.firelevel = max(fl, fire.firelevel)
return 1
if(!zone)
return 1
fire = new(src, fl)
zone.fire_tiles |= src
air_master.active_fire_zones |= zone
return 0
/obj/fire
//Icon for fire on turfs.
@@ -58,41 +101,14 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
/obj/fire/process()
. = 1
//get location and check if it is in a proper ZAS zone
var/turf/simulated/S = loc
if(!istype(S))
del src
return
if(!S.zone)
del src
return
var/datum/gas_mixture/air_contents = S.return_air()
//get liquid fuels on the ground.
var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S
//and the volatile stuff from the air
var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases
//since the air is processed in fractions, we need to make sure not to have any minuscle residue or
//the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour
if(air_contents.oxygen < 0.1)
air_contents.oxygen = 0
if(air_contents.phoron < 0.1)
air_contents.phoron = 0
if(fuel)
if(fuel.moles < 0.1)
air_contents.trace_gases.Remove(fuel)
//check if there is something to combust
if(!air_contents.check_combustability(liquid))
//del src
var/turf/simulated/my_tile = loc
if(!istype(my_tile) || !my_tile.zone)
if(my_tile.fire == src)
my_tile.fire = null
RemoveFire()
return
return 1
//get a firelevel and set the icon
firelevel = air_contents.calculate_firelevel(liquid)
var/datum/gas_mixture/air_contents = my_tile.return_air()
if(firelevel > 6)
icon_state = "3"
@@ -106,21 +122,26 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
//im not sure how to implement a version that works for every creature so for now monkeys are firesafe
for(var/mob/living/carbon/human/M in loc)
M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans!
M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the humans!
loc.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
loc.fire_act(air_contents, air_contents.temperature, air_contents.volume)
for(var/atom/A in loc)
A.fire_act(air_contents, air_contents.temperature, air_contents.return_volume())
A.fire_act(air_contents, air_contents.temperature, air_contents.volume)
//spread
for(var/direction in cardinal)
var/turf/simulated/enemy_tile = get_step(S, direction)
var/turf/simulated/enemy_tile = get_step(my_tile, direction)
if(istype(enemy_tile))
if(S.open_directions & direction) //Grab all valid bordering tiles
var/datum/gas_mixture/acs = enemy_tile.return_air()
var/obj/effect/decal/cleanable/liquid_fuel/liq = locate() in enemy_tile
if(!acs) continue
if(!acs.check_combustability(liq)) continue
if(my_tile.open_directions & direction) //Grab all valid bordering tiles
if(!enemy_tile.zone || enemy_tile.fire)
continue
if(!enemy_tile.zone.fire_tiles.len)
var/datum/gas_mixture/acs = enemy_tile.return_air()
if(!acs || !acs.check_combustability())
continue
//If extinguisher mist passed over the turf it's trying to spread to, don't spread and
//reduce firelevel.
if(enemy_tile.fire_protection > world.time-30)
@@ -128,26 +149,11 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
continue
//Spread the fire.
if(!(locate(/obj/fire) in enemy_tile))
if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0))
new/obj/fire(enemy_tile,firelevel)
if(prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && my_tile.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, my_tile, 0,0))
enemy_tile.create_fire(firelevel)
else
enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.return_volume())
//seperate part of the present gas
//this is done to prevent the fire burning all gases in a single pass
var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate)
///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR ///////////////////////////////////////////////
if(flow)
//burn baby burn!
flow.zburn(liquid,1)
//merge the air back
S.assume_air(flow)
///////////////////////////////// FLOW HAS BEEN REMERGED /// feel free to delete the fire again from here on //////////////////////////////////////////////////////////////////
enemy_tile.adjacent_fire_act(loc, air_contents, air_contents.temperature, air_contents.volume)
/obj/fire/New(newLoc,fl)
..()
@@ -171,31 +177,29 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh)
..()
/obj/fire/proc/RemoveFire()
if (istype(loc, /turf/simulated))
if (istype(loc, /turf))
SetLuminosity(0)
loc = null
air_master.active_hotspots.Remove(src)
turf/simulated/var/fire_protection = 0 //Protects newly extinguished tiles from being overrun again.
turf/proc/apply_fire_protection()
turf/simulated/apply_fire_protection()
fire_protection = world.time
datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn)
var/value = 0
if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && check_recombustability(liquid))
datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, force_burn, no_check = 0)
. = 0
if((temperature > PHORON_MINIMUM_BURN_TEMPERATURE || force_burn) && (no_check ||check_recombustability(liquid)))
var/total_fuel = 0
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
var/total_oxidizers = 0
total_fuel += phoron
if(fuel)
//Volatile Fuel
total_fuel += fuel.moles
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL)
total_fuel += gas[g]
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizers += gas[g]
if(liquid)
//Liquid Fuel
@@ -208,36 +212,29 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc
return 0
//Calculate the firelevel.
var/firelevel = calculate_firelevel(liquid)
var/firelevel = calculate_firelevel(liquid, total_fuel, total_oxidizers, force = 1)
//get the current inner energy of the gas mix
//this must be taken here to prevent the addition or deletion of energy by a changing heat capacity
var/starting_energy = temperature * heat_capacity()
//determine the amount of oxygen used
var/total_oxygen = min(oxygen, 2 * total_fuel)
var/used_oxidizers = min(total_oxidizers, total_fuel / 2)
//determine the amount of fuel actually used
var/used_fuel_ratio = min(oxygen / 2 , total_fuel) / total_fuel
var/used_fuel_ratio = min(2 * total_oxidizers , total_fuel) / total_fuel
total_fuel = total_fuel * used_fuel_ratio
var/total_reactants = total_fuel + total_oxygen
var/total_reactants = total_fuel + used_oxidizers
//determine the amount of reactants actually reacting
var/used_reactants_ratio = min( max(total_reactants * firelevel / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants
var/used_reactants_ratio = min(max(total_reactants * firelevel / vsc.fire_firelevel_multiplier, 0.2), total_reactants) / total_reactants
//remove and add gasses as calculated
oxygen -= min(oxygen, total_oxygen * used_reactants_ratio )
remove_by_flag(XGM_GAS_OXIDIZER, used_oxidizers * used_reactants_ratio)
remove_by_flag(XGM_GAS_FUEL, total_fuel * used_reactants_ratio)
phoron -= min(phoron, (phoron * used_fuel_ratio * used_reactants_ratio ) * 3)
if(phoron < 0)
phoron = 0
carbon_dioxide += max(2 * total_fuel, 0)
if(fuel)
fuel.moles -= (fuel.moles * used_fuel_ratio * used_reactants_ratio) * 5 //Fuel burns 5 times as quick
if(fuel.moles <= 0) del fuel
adjust_gas("carbon_dioxide", max(total_fuel*used_reactants_ratio, 0))
if(liquid)
liquid.amount -= (liquid.amount * used_fuel_ratio * used_reactants_ratio) * 5 // liquid fuel burns 5 times as quick
@@ -248,64 +245,67 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid, forc
temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity()
update_values()
value = total_reactants * used_reactants_ratio
return value
. = total_reactants * used_reactants_ratio
datum/gas_mixture/proc/check_recombustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
//this is a copy proc to continue a fire after its been started.
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER && gas[g] >= 0.1)
. = 1
break
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
if(!.)
return 0
if(oxygen && (phoron || fuel || liquid))
if(liquid)
return 1
if(phoron >= 0.1)
return 1
if(fuel && fuel.moles >= 0.1)
return 1
if(liquid)
return 1
return 0
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL && gas[g] >= 0.1)
. = 1
break
datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid)
//this check comes up very often and is thus centralized here to ease adding stuff
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_OXIDIZER && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
. = 1
break
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
if(!.)
return 0
if(oxygen && (phoron || fuel || liquid))
if(liquid)
return 1
if(QUANTIZE(phoron * vsc.fire_consuption_rate) >= 0.1)
return 1
if(fuel && QUANTIZE(fuel.moles * vsc.fire_consuption_rate) >= 0.1)
return 1
if(liquid)
return 1
return 0
. = 0
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL && QUANTIZE(gas[g] * vsc.fire_consuption_rate) >= 0.1)
. = 1
break
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid)
datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid, total_fuel = null, total_oxidizers = null, force = 0)
//Calculates the firelevel based on one equation instead of having to do this multiple times in different areas.
var/datum/gas/volatile_fuel/fuel = locate() in trace_gases
var/total_fuel = 0
var/firelevel = 0
if(check_recombustability(liquid))
if(force || check_recombustability(liquid))
if(isnull(total_fuel))
for(var/g in gas)
if(gas_data.flags[g] & XGM_GAS_FUEL)
total_fuel += gas[g]
if(gas_data.flags[g] & XGM_GAS_OXIDIZER)
total_oxidizers += gas[g]
if(liquid)
total_fuel += liquid.amount
total_fuel += phoron
if(liquid)
total_fuel += liquid.amount
if(fuel)
total_fuel += fuel.moles
var/total_combustables = (total_fuel + oxygen)
if(total_fuel > 0 && oxygen > 0)
var/total_combustables = (total_fuel + total_oxidizers)
if(total_combustables > 0)
//slows down the burning when the concentration of the reactants is low
var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide)
var/dampening_multiplier = total_combustables / total_moles
//calculates how close the mixture of the reactants is to the optimum
var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ** 2)))
var/mix_multiplier = 1 / (1 + (5 * ((total_oxidizers / total_combustables) ** 2)))
//toss everything together
firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier
+56
View File
@@ -0,0 +1,56 @@
/xgm_gas/oxygen
id = "oxygen"
name = "Oxygen"
specific_heat = 20 // J/(mol*K)
molar_mass = 0.032 // kg/mol
flags = XGM_GAS_OXIDIZER
/xgm_gas/nitrogen
id = "nitrogen"
name = "Nitrogen"
specific_heat = 20 // J/(mol*K)
molar_mass = 0.028 // kg/mol
/xgm_gas/carbon_dioxide
id = "carbon_dioxide"
name = "Carbon Dioxide"
specific_heat = 30 // J/(mol*K)
molar_mass = 0.044 // kg/mol
/xgm_gas/phoron
id = "phoron"
name = "Phoron"
specific_heat = 200 // J/(mol*K)
//Hypothetical group 14 (same as carbon), period 8 element.
//Using multiplicity rule, it's atomic number is 162
//and following a N/Z ratio of 1.5, the molar mass of a monatomic gas is:
molar_mass = 0.405 // kg/mol
tile_overlay = "phoron"
overlay_limit = 0.7
flags = XGM_GAS_FUEL | XGM_GAS_CONTAMINANT
/xgm_gas/volatile_fuel
id = "volatile_fuel"
name = "Volatile Fuel"
specific_heat = 253 // J/(mol*K) C8H18 gasoline. Isobaric, but good enough.
molar_mass = 0.114 // kg/mol. same.
flags = XGM_GAS_FUEL
/xgm_gas/sleeping_agent
id = "sleeping_agent"
name = "Sleeping Agent"
specific_heat = 40 // J/(mol*K)
molar_mass = 0.044 // kg/mol. N2O
tile_overlay = "sleeping_agent"
overlay_limit = 1
/xgm_gas/oxygen_agent_b
id = "oxygen_agent_b"
name = "Oxygen Agent-B" //what is this?
specific_heat = 300 // J/(mol*K)
molar_mass = 0.032 // kg/mol
+6 -5
View File
@@ -111,7 +111,7 @@ obj/var/contaminated = 0
if(vsc.plc.GENETIC_CORRUPTION)
if(rand(1,10000) < vsc.plc.GENETIC_CORRUPTION)
randmutb(src)
src << "\red High levels of phoron cause you to spontaneously mutate."
src << "\red High levels of toxins cause you to spontaneously mutate."
domutcheck(src,null)
@@ -155,10 +155,11 @@ obj/var/contaminated = 0
turf/Entered(obj/item/I)
. = ..()
//Items that are in phoron, but not on a mob, can still be contaminated.
if(istype(I) && vsc.plc.CLOTH_CONTAMINATION)
if(istype(I) && vsc.plc.CLOTH_CONTAMINATION && I.can_contaminate())
var/datum/gas_mixture/env = return_air(1)
if(!env)
return
if(env.phoron > MOLES_PHORON_VISIBLE + 1)
if(I.can_contaminate())
I.contaminate()
for(var/g in env.gas)
if(gas_data.flags[g] & XGM_GAS_CONTAMINANT && env.gas[g] > gas_data.overlay_limit[g] + 1)
I.contaminate()
break
+25 -20
View File
@@ -1,17 +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)
if(isnum(new_graphic))
if(new_graphic == 1) new_graphic = plmaster
else if(new_graphic == 2) new_graphic = slmaster
if(gas_graphic) overlays -= gas_graphic
if(new_graphic) overlays += new_graphic
gas_graphic = new_graphic
/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)
@@ -185,17 +182,15 @@
/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air
return 0
/turf/proc/assume_gas(gasid, moles, temp = 0)
return 0
/turf/return_air()
//Create gas mixture to hold data for passing
var/datum/gas_mixture/GM = new
GM.oxygen = oxygen
GM.carbon_dioxide = carbon_dioxide
GM.nitrogen = nitrogen
GM.phoron = phoron
GM.adjust_multi("oxygen", oxygen, "carbon_dioxide", carbon_dioxide, "nitrogen", nitrogen, "phoron", phoron)
GM.temperature = temperature
GM.update_values()
return GM
@@ -204,10 +199,10 @@
var/sum = oxygen + carbon_dioxide + nitrogen + phoron
if(sum>0)
GM.oxygen = (oxygen/sum)*amount
GM.carbon_dioxide = (carbon_dioxide/sum)*amount
GM.nitrogen = (nitrogen/sum)*amount
GM.phoron = (phoron/sum)*amount
GM.gas["oxygen"] = (oxygen/sum)*amount
GM.gas["carbon_dioxide"] = (carbon_dioxide/sum)*amount
GM.gas["nitrogen"] = (nitrogen/sum)*amount
GM.gas["phoron"] = (phoron/sum)*amount
GM.temperature = temperature
GM.update_values()
@@ -218,6 +213,16 @@
var/datum/gas_mixture/my_air = return_air()
my_air.merge(giver)
/turf/simulated/assume_gas(gasid, moles, temp = null)
var/datum/gas_mixture/my_air = return_air()
if(isnull(temp))
my_air.adjust_gas(gasid, moles)
else
my_air.adjust_gas_temp(gasid, moles, temp)
return 1
/turf/simulated/remove_air(amount as num)
var/datum/gas_mixture/my_air = return_air()
return my_air.remove(amount)
@@ -240,11 +245,11 @@
/turf/proc/make_air()
air = new/datum/gas_mixture
air.temperature = temperature
air.adjust(oxygen, carbon_dioxide, nitrogen, phoron)
air.adjust_multi("oxygen", oxygen, "carbon_dioxide", carbon_dioxide, "nitrogen", nitrogen, "phoron", phoron)
air.group_multiplier = 1
air.volume = CELL_VOLUME
/turf/simulated/proc/c_copy_air()
if(!air) air = new/datum/gas_mixture
air.copy_from(zone.air)
air.group_multiplier = 1
air.group_multiplier = 1
+17 -7
View File
@@ -43,6 +43,7 @@ Class Procs:
/zone/var/name
/zone/var/invalid = 0
/zone/var/list/contents = list()
/zone/var/list/fire_tiles = list()
/zone/var/needs_update = 0
@@ -50,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
@@ -67,7 +71,10 @@ Class Procs:
add_tile_air(turf_air)
T.zone = src
contents.Add(T)
T.set_graphic(air.graphic)
if(T.fire)
fire_tiles.Add(T)
air_master.active_fire_zones.Add(src)
T.update_graphic(air.graphic)
/zone/proc/remove(turf/simulated/T)
#ifdef ZASDBG
@@ -77,8 +84,9 @@ Class Procs:
soft_assert(T in contents, "Lists are weird broseph")
#endif
contents.Remove(T)
fire_tiles.Remove(T)
T.zone = null
T.set_graphic(0)
T.update_graphic(graphic_remove = air.graphic)
if(contents.len)
air.group_multiplier = contents.len
else
@@ -123,16 +131,18 @@ Class Procs:
air.group_multiplier = contents.len+1
/zone/proc/tick()
air.archive()
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
M << "O2: [air.oxygen] N2: [air.nitrogen] CO2: [air.carbon_dioxide] P: [air.phoron]"
for(var/g in air.gas)
M << "[gas_data.name[g]]: [air.gas[g]]"
M << "P: [air.return_pressure()] kPa V: [air.volume]L T: [air.temperature]°K ([air.temperature - T0C]°C)"
M << "O2 per N2: [(air.nitrogen ? air.oxygen/air.nitrogen : "N/A")] Moles: [air.total_moles]"
M << "O2 per N2: [(air.gas["nitrogen"] ? air.gas["oxygen"]/air.gas["nitrogen"] : "N/A")] Moles: [air.total_moles]"
M << "Simulated: [contents.len] ([air.group_multiplier])"
//M << "Unsimulated: [unsimulated_contents.len]"
//M << "Edges: [edges.len]"
+419
View File
@@ -0,0 +1,419 @@
#define QUANTIZE(variable) (round(variable,0.0001))
/datum/gas_mixture
//Associative list of gas moles.
//Gases with 0 moles are not tracked and are pruned by update_values()
var/list/gas = list()
//Temperature in Kelvin of this gas mix.
var/temperature = 0
//Sum of all the gas moles in this mix. Updated by update_values()
var/total_moles = 0
//Volume of this mix.
var/volume = CELL_VOLUME
//Size of the group this gas_mixture is representing. 1 for singletons.
var/group_multiplier = 1
//List of active tile overlays for this gas_mixture. Updated by check_tile_graphic()
var/list/graphic = list()
//Takes a gas string, and the amount of moles to adjust by. Calls update_values() if update isn't 0.
/datum/gas_mixture/proc/adjust_gas(gasid, moles, update = 1)
if(moles == 0)
return
if (group_multiplier != 1)
gas[gasid] += moles/group_multiplier
else
gas[gasid] += moles
if(update)
update_values()
//Same as adjust_gas(), but takes a temperature which is mixed in with the gas.
/datum/gas_mixture/proc/adjust_gas_temp(gasid, moles, temp, update = 1)
if(moles == 0)
return
if(moles > 0 && abs(temperature - temp) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
var/giver_heat_capacity = gas_data.specific_heat[gasid] * moles
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
temperature = (temp * giver_heat_capacity + temperature * self_heat_capacity) / combined_heat_capacity
if (group_multiplier != 1)
gas[gasid] += moles/group_multiplier
else
gas[gasid] += moles
if(update)
update_values()
//Variadic version of adjust_gas(). Takes any number of gas and mole pairs, and applies them.
/datum/gas_mixture/proc/adjust_multi()
ASSERT(!(args.len % 2))
for(var/i = 1; i < args.len; i += 2)
adjust_gas(args[i], args[i+1], update = 0)
update_values()
//Variadic version of adjust_gas_temp(). Takes any number of gas, mole, and temperature tuples, and applies them.
/datum/gas_mixture/proc/adjust_multi_temp()
ASSERT(!(args.len % 3))
for(var/i = 1; i < args.len; i += 3)
adjust_gas_temp(args[i], args[i + 1], args[i + 2], update = 0)
update_values()
//Merges all the gas from another mixture into this one. Respects group_multipliers and adjusts temperature correctly.
/datum/gas_mixture/proc/merge(datum/gas_mixture/giver)
if(!giver)
return
if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER)
var/self_heat_capacity = heat_capacity()
var/giver_heat_capacity = giver.heat_capacity()
var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity
if(combined_heat_capacity != 0)
temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity
if((group_multiplier != 1)||(giver.group_multiplier != 1))
for(var/g in giver.gas)
gas[g] += giver.gas[g] * giver.group_multiplier / group_multiplier
else
for(var/g in giver.gas)
gas[g] += giver.gas[g]
update_values()
//Returns the heat capacity of the gas mix based on the specific heat of the gases.
/datum/gas_mixture/proc/heat_capacity()
. = 0
for(var/g in gas)
. += gas_data.specific_heat[g] * gas[g]
. *= group_multiplier
//Adds or removes thermal energy. Returns the actual thermal energy change, as in the case of removing energy we can't go below TCMB.
/datum/gas_mixture/proc/add_thermal_energy(var/thermal_energy)
if (total_moles == 0)
return 0
var/heat_capacity = heat_capacity()
if (thermal_energy < 0)
if (temperature < TCMB)
return 0
var/thermal_energy_limit = -(temperature - TCMB)*heat_capacity //ensure temperature does not go below TCMB
thermal_energy = max( thermal_energy, thermal_energy_limit ) //thermal_energy and thermal_energy_limit are negative here.
temperature += thermal_energy/heat_capacity
return thermal_energy
//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()*(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
//Returns the ideal gas specific entropy of the whole mix. This is the entropy per mole of /mixed/ gas.
/datum/gas_mixture/proc/specific_entropy()
if (!gas.len || total_moles == 0)
return SPECIFIC_ENTROPY_VACUUM
. = 0
for(var/g in gas)
. += gas[g] * specific_entropy_gas(g)
. /= total_moles
/*
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]
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()
total_moles = 0
for(var/g in gas)
if(gas[g] <= 0)
gas -= g
else
total_moles += gas[g]
//Returns the pressure of the gas mix. Only accurate if there have been no gas modifications since update_values() has been called.
/datum/gas_mixture/proc/return_pressure()
if(volume)
return total_moles * R_IDEAL_GAS_EQUATION * temperature / volume
return 0
//Removes moles from the gas mixture and returns a gas_mixture containing the removed air.
/datum/gas_mixture/proc/remove(amount)
amount = min(amount, total_moles * group_multiplier) //Can not take more air than the gas mixture has!
if(amount <= 0)
return null
var/datum/gas_mixture/removed = new
for(var/g in gas)
removed.gas[g] = QUANTIZE((gas[g] / total_moles) * amount)
gas[g] -= removed.gas[g] / group_multiplier
removed.temperature = temperature
update_values()
removed.update_values()
return removed
//Removes a ratio of gas from the mixture and returns a gas_mixture containing the removed air.
/datum/gas_mixture/proc/remove_ratio(ratio, out_group_multiplier = 1)
if(ratio <= 0)
return null
out_group_multiplier = max(1, min(group_multiplier, out_group_multiplier))
ratio = min(ratio, 1)
var/datum/gas_mixture/removed = new
removed.group_multiplier = out_group_multiplier
for(var/g in gas)
removed.gas[g] = (gas[g] * ratio * group_multiplier / out_group_multiplier)
gas[g] = gas[g] * (1 - ratio)
removed.temperature = temperature
update_values()
removed.update_values()
return removed
//Removes moles from the gas mixture, limited by a given flag. Returns a gax_mixture containing the removed air.
/datum/gas_mixture/proc/remove_by_flag(flag, amount)
if(!flag || amount <= 0)
return
var/sum = 0
for(var/g in gas)
if(gas_data.flags[g] & flag)
sum += gas[g]
var/datum/gas_mixture/removed = new
for(var/g in gas)
if(gas_data.flags[g] & flag)
removed.gas[g] = QUANTIZE((gas[g] / sum) * amount)
gas[g] -= removed.gas[g] / group_multiplier
removed.temperature = temperature
update_values()
removed.update_values()
return removed
//Copies gas and temperature from another gas_mixture.
/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample)
gas = sample.gas.Copy()
temperature = sample.temperature
update_values()
return 1
//Checks if we are within acceptable range of another gas_mixture to suspend processing or merge.
/datum/gas_mixture/proc/compare(datum/gas_mixture/sample)
if(!sample) return 0
var/list/marked = list()
for(var/g in gas)
if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
(gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
return 0
marked[g] = 1
for(var/g in sample.gas)
if(!marked[g])
if((abs(gas[g] - sample.gas[g]) > MINIMUM_AIR_TO_SUSPEND) && \
((gas[g] < (1 - MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g]) || \
(gas[g] > (1 + MINIMUM_AIR_RATIO_TO_SUSPEND) * sample.gas[g])))
return 0
if(total_moles > MINIMUM_AIR_TO_SUSPEND)
if((abs(temperature - sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \
((temperature < (1 - MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || \
(temperature > (1 + MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature)))
return 0
return 1
/datum/gas_mixture/proc/react(atom/dump_location)
zburn(null)
//Rechecks the gas_mixture and adjusts the graphic list if needed.
//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.
if(gas[g] <= gas_data.overlay_limit[g])
if(!graphic_remove)
graphic_remove = list()
graphic_remove += gas_data.tile_overlay[g]
else
//Overlay isn't applied for this gas, check if it's valid and needs to be added.
if(gas[g] > gas_data.overlay_limit[g])
if(!graphic_add)
graphic_add = list()
graphic_add += gas_data.tile_overlay[g]
. = 0
//Apply changes
if(graphic_add && graphic_add.len)
graphic += graphic_add
. = 1
if(graphic_remove && graphic_remove.len)
graphic -= graphic_remove
. = 1
//Simpler version of merge(), adjusts gas amounts directly and doesn't account for temperature or group_multiplier.
/datum/gas_mixture/proc/add(datum/gas_mixture/right_side)
for(var/g in right_side.gas)
gas[g] += right_side.gas[g]
update_values()
return 1
//Simpler version of remove(), adjusts gas amounts directly and doesn't account for group_multiplier.
/datum/gas_mixture/proc/subtract(datum/gas_mixture/right_side)
for(var/g in right_side.gas)
gas[g] -= right_side.gas[g]
update_values()
return 1
//Multiply all gas amounts by a factor.
/datum/gas_mixture/proc/multiply(factor)
for(var/g in gas)
gas[g] *= factor
update_values()
return 1
//Divide all gas amounts by a factor.
/datum/gas_mixture/proc/divide(factor)
for(var/g in gas)
gas[g] /= factor
update_values()
return 1
//Shares gas with another gas_mixture based on the amount of connecting tiles and a fixed lookup table.
/datum/gas_mixture/proc/share_ratio(datum/gas_mixture/other, connecting_tiles, share_size = null, one_way = 0)
var/static/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66)
//Shares a specific ratio of gas between mixtures using simple weighted averages.
var/ratio = sharing_lookup_table[6]
var/size = max(1, group_multiplier)
if(isnull(share_size)) share_size = max(1, other.group_multiplier)
var/full_heat_capacity = heat_capacity()
var/s_full_heat_capacity = other.heat_capacity()
var/list/avg_gas = list()
for(var/g in gas)
avg_gas[g] += gas[g] * size
for(var/g in other.gas)
avg_gas[g] += other.gas[g] * share_size
for(var/g in avg_gas)
avg_gas[g] /= (size + share_size)
var/temp_avg = 0
if(full_heat_capacity + s_full_heat_capacity)
temp_avg = (temperature * full_heat_capacity + other.temperature * s_full_heat_capacity) / (full_heat_capacity + s_full_heat_capacity)
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD.
if(sharing_lookup_table.len >= connecting_tiles) //6 or more interconnecting tiles will max at 42% of air moved per tick.
ratio = sharing_lookup_table[connecting_tiles]
//WOOT WOOT TOUCH THIS AND YOU ARE A RETARD
for(var/g in avg_gas)
gas[g] = max(0, (gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
if(!one_way)
other.gas[g] = max(0, (other.gas[g] - avg_gas[g]) * (1 - ratio) + avg_gas[g])
temperature = max(0, (temperature - temp_avg) * (1-ratio) + temp_avg)
if(!one_way)
other.temperature = max(0, (other.temperature - temp_avg) * (1-ratio) + temp_avg)
update_values()
other.update_values()
if(compare(other)) return 1
else return 0
//A wrapper around share_ratio for spacing gas at the same rate as if it were going into a large airless room.
/datum/gas_mixture/proc/share_space(datum/gas_mixture/unsim_air)
if(!unsim_air)
return 0
var/old_pressure = return_pressure()
share_ratio(unsim_air, unsim_air.group_multiplier, max(1, max(group_multiplier + 3, 1) + unsim_air.group_multiplier), one_way = 1)
return abs(old_pressure - return_pressure())
//Equalizes a list of gas mixtures. Used for pipe networks.
/proc/equalize_gases(datum/gas_mixture/list/gases)
//Calculate totals from individual components
var/total_volume = 0
var/total_thermal_energy = 0
var/total_heat_capacity = 0
var/list/total_gas = list()
for(var/datum/gas_mixture/gasmix in gases)
total_volume += gasmix.volume
var/temp_heatcap = gasmix.heat_capacity()
total_thermal_energy += gasmix.temperature * temp_heatcap
total_heat_capacity += temp_heatcap
for(var/g in gasmix.gas)
total_gas[g] += gasmix.gas[g]
if(total_volume > 0)
//Average out the gases
for(var/g in total_gas)
total_gas[g] /= total_volume
//Calculate temperature
var/temperature = 0
if(total_heat_capacity > 0)
temperature = total_thermal_energy / total_heat_capacity
//Update individual gas_mixtures
for(var/datum/gas_mixture/gasmix in gases)
gasmix.gas = total_gas.Copy()
gasmix.temperature = temperature
gasmix.multiply(gasmix.volume)
return 1
+46
View File
@@ -0,0 +1,46 @@
/var/xgm_gas_data/gas_data
/xgm_gas_data
//Simple list of all the gas IDs.
var/list/gases = list()
//The friendly, human-readable name for the gas.
var/list/name = list()
//Specific heat of the gas. Used for calculating heat capacity.
var/list/specific_heat = list()
//Molar mass of the gas. Used for calculating specific entropy.
var/list/molar_mass = list()
//Tile overlays. /images, created from references to 'icons/effects/tile_effects.dmi'
var/list/tile_overlay = list()
//Overlay limits. There must be at least this many moles for the overlay to appear.
var/list/overlay_limit = list()
//Flags.
var/list/flags = list()
/xgm_gas
var/id = ""
var/name = "Unnamed Gas"
var/specific_heat = 20 // J/(mol*K)
var/molar_mass = 0.032 // kg/mol
var/tile_overlay = null
var/overlay_limit = null
var/flags = 0
/hook/startup/proc/generateGasData()
gas_data = new
for(var/p in (typesof(/xgm_gas) - /xgm_gas))
var/xgm_gas/gas = new p
if(gas.id in gas_data.gases)
error("Duplicate gas id `[gas.id]` in `[p]`")
gas_data.gases += gas.id
gas_data.name[gas.id] = gas.name
gas_data.specific_heat[gas.id] = gas.specific_heat
gas_data.molar_mass[gas.id] = gas.molar_mass
if(gas.tile_overlay) gas_data.tile_overlay[gas.id] = image('icons/effects/tile_effects.dmi', gas.tile_overlay, FLY_LAYER)
if(gas.overlay_limit) gas_data.overlay_limit[gas.id] = gas.overlay_limit
gas_data.flags[gas.id] = gas.flags
return 1
+62 -1
View File
@@ -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)
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(cp<minp)minp=cp
if(cp>maxp)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
+11
View File
@@ -303,3 +303,14 @@ proc/checkhtml(var/t)
for(var/i = length(text); i > 0; i--)
new_text += copytext(text, i, i+1)
return new_text
//Used in preferences' SetFlavorText and human's set_flavor verb
//Previews a string of len or less length
proc/TextPreview(var/string,var/len=40)
if(lentext(string) <= len)
if(!lentext(string))
return "\[...\]"
else
return string
else
return "[copytext(string, 1, 37)]..."
+4 -5
View File
@@ -1306,11 +1306,10 @@ proc/is_hot(obj/item/W as obj)
//check if mob is lying down on something we can operate him on.
/proc/can_operate(mob/living/carbon/M)
return (locate(/obj/machinery/optable, M.loc) && M.resting) || \
(locate(/obj/structure/stool/bed/roller, M.loc) && \
(M.buckled || M.lying || M.weakened || M.stunned || M.paralysis || M.sleeping || M.stat)) && prob(75) || \
(locate(/obj/structure/table/, M.loc) && \
(M.lying || M.weakened || M.stunned || M.paralysis || M.sleeping || M.stat) && prob(66))
return (M.lying && \
locate(/obj/machinery/optable, M.loc) || \
(locate(/obj/structure/stool/bed/roller, M.loc) && prob(75)) || \
(locate(/obj/structure/table/, M.loc) && prob(66)))
/proc/reverse_direction(var/dir)
switch(dir)
+39 -8
View File
@@ -53,6 +53,11 @@
return
next_move = world.time + 9
if(aiCamera.in_camera_mode)
aiCamera.camera_mode_off()
aiCamera.captureimage(A, usr)
return
/*
AI restrained() currently does nothing
if(restrained())
@@ -81,12 +86,15 @@
than anything else in the game, atoms have separate procs
for AI shift, ctrl, and alt clicking.
*/
/mob/living/silicon/ai/ShiftClickOn(var/atom/A)
A.AIShiftClick(src)
/mob/living/silicon/ai/CtrlClickOn(var/atom/A)
A.AICtrlClick(src)
/mob/living/silicon/ai/AltClickOn(var/atom/A)
A.AIAltClick(src)
/mob/living/silicon/ai/MiddleClickOn(var/atom/A)
A.AIMiddleClick(src)
/*
The following criminally helpful code is just the previous code cleaned up;
@@ -103,7 +111,6 @@
Topic("aiDisable=7", list("aiDisable"="7"), 1)
return
/atom/proc/AICtrlClick()
return
@@ -113,18 +120,42 @@
else
Topic("aiDisable=4", list("aiDisable"="4"), 1)
/obj/machinery/power/apc/AICtrlClick() // turns off APCs.
/obj/machinery/power/apc/AICtrlClick() // turns off/on APCs.
Topic("breaker=1", list("breaker"="1"), 0) // 0 meaning no window (consistency! wait...)
/obj/machinery/turretid/AICtrlClick() //turns off/on Turrets
src.enabled = !src.enabled
src.updateTurrets()
/atom/proc/AIAltClick()
return
/atom/proc/AIAltClick(var/atom/A)
AltClick(A)
/obj/machinery/door/airlock/AIAltClick() // Eletrifies doors.
/obj/machinery/door/airlock/AIAltClick() // Electrifies doors.
if(!secondsElectrified)
// permenant shock
// permanent shock
Topic("aiEnable=6", list("aiEnable"="6"), 1) // 1 meaning no window (consistency!)
else
// disable/6 is not in Topic; disable/5 disables both temporary and permenant shock
// disable/6 is not in Topic; disable/5 disables both temporary and permanent shock
Topic("aiDisable=5", list("aiDisable"="5"), 1)
return
return
/obj/machinery/turretid/AIAltClick() //toggles lethal on turrets
src.lethal = !src.lethal
src.updateTurrets()
/atom/proc/AIMiddleClick()
return
/obj/machinery/door/airlock/AIMiddleClick() // Toggles door bolt lights.
if(!src.lights)
Topic("aiEnable=10", list("aiEnable"="10"), 1) // 1 meaning no window (consistency!)
else
Topic("aiDisable=10", list("aiDisable"="10"), 1)
return
//
// Override AdjacentQuick for AltClicking
//
/mob/living/silicon/ai/TurfAdjacent(var/turf/T)
return (cameranet && cameranet.checkTurfVis(T))
+15 -2
View File
@@ -252,7 +252,7 @@
/atom/proc/AltClick(var/mob/user)
var/turf/T = get_turf(src)
if(T && T.AdjacentQuick(user))
if(T && user.TurfAdjacent(T))
if(user.listed_turf == T)
user.listed_turf = null
else
@@ -260,6 +260,9 @@
user.client.statpanel = T.name
return
/mob/proc/TurfAdjacent(var/turf/T)
return T.AdjacentQuick(src)
/*
Misc helpers
@@ -298,7 +301,17 @@
// Simple helper to face what you clicked on, in case it should be needed in more than one place
/mob/proc/face_atom(var/atom/A)
if( stat || (buckled && !buckled.movable) || !A || !x || !y || !A.x || !A.y ) return
// Snowflake for space vines.
var/is_buckled = 0
if(buckled)
if(istype(buckled))
if(!buckled.movable)
is_buckled = 1
else
is_buckled = 0
if( stat || is_buckled || !A || !x || !y || !A.x || !A.y ) return
var/dx = A.x - x
var/dy = A.y - y
if(!dx && !dy) return
+8
View File
@@ -37,6 +37,14 @@
face_atom(A) // change direction to face what you clicked on
if(aiCamera.in_camera_mode)
aiCamera.camera_mode_off()
if(is_component_functioning("camera"))
aiCamera.captureimage(A, usr)
else
src << "<span class='userdanger'>Your camera isn't functional.</span>"
return
/*
cyborg restrained() currently does nothing
if(restrained())
+19 -19
View File
@@ -276,7 +276,7 @@
var/list/nicename = null
var/list/tankcheck = null
var/breathes = "oxygen" //default, we'll check later
var/list/contents = list()
var/list/contents = list()
if(ishuman(C))
var/mob/living/carbon/human/H = C
@@ -284,7 +284,7 @@
nicename = list ("suit", "back", "belt", "right hand", "left hand", "left pocket", "right pocket")
tankcheck = list (H.s_store, C.back, H.belt, C.r_hand, C.l_hand, H.l_store, H.r_store)
else
else
nicename = list("Right Hand", "Left Hand", "Back")
tankcheck = list(C.r_hand, C.l_hand, C.back)
@@ -295,30 +295,30 @@
if (!isnull(t.manipulated_by) && t.manipulated_by != C.real_name && findtext(t.desc,breathes))
contents.Add(t.air_contents.total_moles) //Someone messed with the tank and put unknown gasses
continue //in it, so we're going to believe the tank is what it says it is
switch(breathes)
switch(breathes)
//These tanks we're sure of their contents
if("nitrogen") //So we're a bit more picky about them.
if(t.air_contents.nitrogen && !t.air_contents.oxygen)
contents.Add(t.air_contents.nitrogen)
if(t.air_contents.gas["nitrogen"] && !t.air_contents.gas["oxygen"])
contents.Add(t.air_contents.gas["nitrogen"])
else
contents.Add(0)
contents.Add(0)
if ("oxygen")
if(t.air_contents.oxygen && !t.air_contents.phoron)
contents.Add(t.air_contents.oxygen)
if(t.air_contents.gas["oxygen"] && !t.air_contents.gas["phoron"])
contents.Add(t.air_contents.gas["oxygen"])
else
contents.Add(0)
// No races breath this, but never know about downstream servers.
if ("carbon dioxide")
if(t.air_contents.carbon_dioxide && !t.air_contents.phoron)
contents.Add(t.air_contents.carbon_dioxide)
if(t.air_contents.gas["carbon_dioxide"] && !t.air_contents.gas["phoron"])
contents.Add(t.air_contents.gas["carbon_dioxide"])
else
contents.Add(0)
else
else
//no tank so we set contents to 0
contents.Add(0)
@@ -328,19 +328,19 @@
var/bestcontents = 0
for(var/i=1, i < contents.len + 1 , ++i)
if(!contents[i])
continue
continue
if(contents[i] > bestcontents)
best = i
bestcontents = contents[i]
//We've determined the best container now we set it as our internals
if(best)
C << "<span class='notice'>You are now running on internals from [tankcheck[best]] on your [nicename[best]].</span>"
C.internal = tankcheck[best]
if(C.internal)
if(C.internals)
C.internals.icon_state = "internal1"
+9 -6
View File
@@ -24,15 +24,13 @@
/obj/item/proc/attack(mob/living/M as mob, mob/living/user as mob, def_zone)
if (!istype(M)) // not sure if this is the right thing...
return
return 0
var/messagesource = M
if (can_operate(M)) //Checks if mob is lying down on table for surgery
if (do_surgery(M,user,src))
return
return 0
if (istype(M,/mob/living/carbon/brain))
messagesource = M:container
if (hitsound)
playsound(loc, hitsound, 50, 1, -1)
/////////////////////////
user.lastattacked = M
M.lastattacker = user
@@ -63,7 +61,7 @@
slime.Discipline = 0
if(power >= 3)
if(istype(slime, /mob/living/carbon/slime/adult))
if(slime.is_adult)
if(prob(5 + round(power/2)))
if(slime.Victim)
@@ -140,8 +138,13 @@
if(istype(M, /mob/living/carbon/human))
return M:attacked_by(src, user, def_zone)
var/hit = M:attacked_by(src, user, def_zone)
if (hit && hitsound)
playsound(loc, hitsound, 50, 1, -1)
return hit
else
if (hitsound)
playsound(loc, hitsound, 50, 1, -1)
switch(damtype)
if("brute")
if(istype(src, /mob/living/carbon/slime))
@@ -1,307 +1,294 @@
/*
HOW IT WORKS
The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether".
Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
procs:
add_object(obj/device as obj, var/new_frequency as num, var/filter as text|null = null)
Adds listening object.
parameters:
device - device receiving signals, must have proc receive_signal (see description below).
one device may listen several frequencies, but not same frequency twice.
new_frequency - see possibly frequencies below;
filter - thing for optimization. Optional, but recommended.
All filters should be consolidated in this file, see defines later.
Device without listening filter will receive all signals (on specified frequency).
Device with filter will receive any signals sent without filter.
Device with filter will not receive any signals sent with different filter.
returns:
Reference to frequency object.
remove_object (obj/device, old_frequency)
Obliviously, after calling this proc, device will not receive any signals on old_frequency.
Other frequencies will left unaffected.
return_frequency(var/frequency as num)
returns:
Reference to frequency object. Use it if you need to send and do not need to listen.
radio_frequency is a global object maintaining list of devices that listening specific frequency.
procs:
post_signal(obj/source as obj|null, datum/signal/signal, var/filter as text|null = null, var/range as num|null = null)
Sends signal to all devices that wants such signal.
parameters:
source - object, emitted signal. Usually, devices will not receive their own signals.
signal - see description below.
filter - described above.
range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels.
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.
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.
TRANSMISSION_WIRE is currently unused.
receive_param - for TRANSMISSION_RADIO here comes frequency.
datum/signal
vars:
source
an object that emitted signal. Used for debug and bearing.
data
list with transmitting data. Usual use pattern:
data["msg"] = "hello world"
encryption
Some number symbolizing "encryption key".
Note that game actually do not use any cryptography here.
If receiving object don't know right key, it must ignore encrypted signal in its receive_signal.
*/
/*
Frequency range: 1200 to 1600
Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking)
Radio:
1459 - standard radio chat
1351 - Science
1353 - Command
1355 - Medical
1357 - Engineering
1359 - Security
1441 - death squad
1443 - Confession Intercom
1347 - Cargo techs
Devices:
1451 - tracking implant
1457 - RSD default
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
1439 for air pumps, air scrubbers, atmo control
1441 for atmospherics - supply tanks
1443 for atmospherics - distribution loop/mixed air tank
1445 for bot nav beacons
1447 for mulebot, secbot and ed209 control
1449 for airlock controls, electropack, magnets
1451 for toxin lab access
1453 for engineering access
1455 for AI access
*/
var/list/radiochannels = list(
"Common" = 1459,
"Science" = 1351,
"Command" = 1353,
"Medical" = 1355,
"Engineering" = 1357,
"Security" = 1359,
"Response Team" = 1345,
"Deathsquad" = 1341,
"Syndicate" = 1213,
"Supply" = 1347,
)
//depenging helpers
var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1345, 1341, 1347)
// central command channels, i.e deathsquid & response teams
var/list/CENT_FREQS = list(1345, 1341)
var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/SYND_FREQ = 1213
// department channels
var/const/SEC_FREQ = 1359
var/const/ENG_FREQ = 1357
var/const/SCI_FREQ = 1351
var/const/MED_FREQ = 1355
var/const/SUP_FREQ = 1347
#define TRANSMISSION_WIRE 0
#define TRANSMISSION_RADIO 1
/* filters */
var/const/RADIO_TO_AIRALARM = "1"
var/const/RADIO_FROM_AIRALARM = "2"
var/const/RADIO_CHAT = "3"
var/const/RADIO_ATMOSIA = "4"
var/const/RADIO_NAVBEACONS = "5"
var/const/RADIO_AIRLOCK = "6"
var/const/RADIO_SECBOT = "7"
var/const/RADIO_MULEBOT = "8"
var/const/RADIO_MAGNETS = "9"
var/global/datum/controller/radio/radio_controller
/hook/startup/proc/createRadioController()
radio_controller = new /datum/controller/radio()
return 1
datum/controller/radio
var/list/datum/radio_frequency/frequencies = list()
proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
frequency.add_listener(device, filter)
return frequency
proc/remove_object(obj/device, old_frequency)
var/f_text = num2text(old_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(frequency)
frequency.remove_listener(device)
if(frequency.devices.len == 0)
del(frequency)
frequencies -= f_text
return 1
proc/return_frequency(var/new_frequency as num)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
return frequency
datum/radio_frequency
var/frequency as num
var/list/list/obj/devices = list()
proc
post_signal(obj/source as obj|null, datum/signal/signal, var/filter = null as text|null, var/range = null as num|null)
//log_admin("DEBUG \[[world.timeofday]\]: post_signal {source=\"[source]\", [signal.debug_print()], filter=[filter]}")
// var/N_f=0
// var/N_nf=0
// var/Nt=0
var/turf/start_point
if(range)
start_point = get_turf(source)
if(!start_point)
del(signal)
return 0
if (filter) //here goes some copypasta. It is for optimisation. -rastaf0
for(var/obj/device in devices[filter])
if(device == source)
continue
if(range)
var/turf/end_point = get_turf(device)
if(!end_point)
continue
//if(max(abs(start_point.x-end_point.x), abs(start_point.y-end_point.y)) <= range)
if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range)
continue
device.receive_signal(signal, TRANSMISSION_RADIO, frequency)
for(var/obj/device in devices["_default"])
if(device == source)
continue
if(range)
var/turf/end_point = get_turf(device)
if(!end_point)
continue
//if(max(abs(start_point.x-end_point.x), abs(start_point.y-end_point.y)) <= range)
if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range)
continue
device.receive_signal(signal, TRANSMISSION_RADIO, frequency)
// N_f++
else
for (var/next_filter in devices)
// var/list/obj/DDD = devices[next_filter]
// Nt+=DDD.len
for(var/obj/device in devices[next_filter])
if(device == source)
continue
if(range)
var/turf/end_point = get_turf(device)
if(!end_point)
continue
//if(max(abs(start_point.x-end_point.x), abs(start_point.y-end_point.y)) <= range)
if(start_point.z!=end_point.z || get_dist(start_point, end_point) > range)
continue
device.receive_signal(signal, TRANSMISSION_RADIO, frequency)
// N_nf++
// log_admin("DEBUG: post_signal(source=[source] ([source.x], [source.y], [source.z]),filter=[filter]) frequency=[frequency], N_f=[N_f], N_nf=[N_nf]")
// del(signal)
add_listener(obj/device as obj, var/filter as text|null)
if (!filter)
filter = "_default"
//log_admin("add_listener(device=[device],filter=[filter]) frequency=[frequency]")
var/list/obj/devices_line = devices[filter]
if (!devices_line)
devices_line = new
devices[filter] = devices_line
devices_line+=device
// var/list/obj/devices_line___ = devices[filter_str]
// var/l = devices_line___.len
//log_admin("DEBUG: devices_line.len=[devices_line.len]")
//log_admin("DEBUG: devices(filter_str).len=[l]")
remove_listener(obj/device)
for (var/devices_filter in devices)
var/list/devices_line = devices[devices_filter]
devices_line-=device
while (null in devices_line)
devices_line -= null
if (devices_line.len==0)
devices -= devices_filter
del(devices_line)
obj/proc
receive_signal(datum/signal/signal, receive_method, receive_param)
return null
datum/signal
var/obj/source
var/transmission_method = 0
//0 = wire
//1 = radio transmission
//2 = subspace transmission
var/data = list()
var/encryption
var/frequency = 0
proc/copy_from(datum/signal/model)
source = model.source
transmission_method = model.transmission_method
data = model.data
encryption = model.encryption
frequency = model.frequency
proc/debug_print()
if (source)
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
else
. = "signal = {source = '[source]' ()\n"
for (var/i in data)
. += "data\[\"[i]\"\] = \"[data[i]]\"\n"
if(islist(data[i]))
var/list/L = data[i]
for(var/t in L)
. += "data\[\"[i]\"\] list has: [t]"
/*
HOW IT WORKS
The radio_controller is a global object maintaining all radio transmissions, think about it as about "ether".
Note that walkie-talkie, intercoms and headsets handle transmission using nonstandard way.
procs:
add_object(obj/device as obj, var/new_frequency as num, var/filter as text|null = null)
Adds listening object.
parameters:
device - device receiving signals, must have proc receive_signal (see description below).
one device may listen several frequencies, but not same frequency twice.
new_frequency - see possibly frequencies below;
filter - thing for optimization. Optional, but recommended.
All filters should be consolidated in this file, see defines later.
Device without listening filter will receive all signals (on specified frequency).
Device with filter will receive any signals sent without filter.
Device with filter will not receive any signals sent with different filter.
returns:
Reference to frequency object.
remove_object (obj/device, old_frequency)
Obliviously, after calling this proc, device will not receive any signals on old_frequency.
Other frequencies will left unaffected.
return_frequency(var/frequency as num)
returns:
Reference to frequency object. Use it if you need to send and do not need to listen.
radio_frequency is a global object maintaining list of devices that listening specific frequency.
procs:
post_signal(obj/source as obj|null, datum/signal/signal, var/filter as text|null = null, var/range as num|null = null)
Sends signal to all devices that wants such signal.
parameters:
source - object, emitted signal. Usually, devices will not receive their own signals.
signal - see description below.
filter - described above.
range - radius of regular byond's square circle on that z-level. null means everywhere, on all z-levels.
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.
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.
TRANSMISSION_WIRE is currently unused.
receive_param - for TRANSMISSION_RADIO here comes frequency.
datum/signal
vars:
source
an object that emitted signal. Used for debug and bearing.
data
list with transmitting data. Usual use pattern:
data["msg"] = "hello world"
encryption
Some number symbolizing "encryption key".
Note that game actually do not use any cryptography here.
If receiving object don't know right key, it must ignore encrypted signal in its receive_signal.
*/
/*
Frequency range: 1200 to 1600
Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking)
Radio:
1459 - standard radio chat
1351 - Science
1353 - Command
1355 - Medical
1357 - Engineering
1359 - Security
1441 - death squad
1443 - Confession Intercom
1347 - Cargo techs
Devices:
1451 - tracking implant
1457 - RSD default
On the map:
1311 for prison shuttle console (in fact, it is not used)
1435 for status displays
1437 for atmospherics/fire alerts
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
1445 for bot nav beacons
1447 for mulebot, secbot and ed209 control
1449 for airlock controls, electropack, magnets
1451 for toxin lab access
1453 for engineering access
1455 for AI access
*/
var/list/radiochannels = list(
"Common" = 1459,
"Science" = 1351,
"Command" = 1353,
"Medical" = 1355,
"Engineering" = 1357,
"Security" = 1359,
"Response Team" = 1345,
"Deathsquad" = 1341,
"Syndicate" = 1213,
"Supply" = 1347,
)
//depenging helpers
var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1345, 1341, 1347)
// central command channels, i.e deathsquid & response teams
var/list/CENT_FREQS = list(1345, 1341)
var/const/COMM_FREQ = 1353 //command, colored gold in chat window
var/const/SYND_FREQ = 1213
// department channels
var/const/SEC_FREQ = 1359
var/const/ENG_FREQ = 1357
var/const/SCI_FREQ = 1351
var/const/MED_FREQ = 1355
var/const/SUP_FREQ = 1347
#define TRANSMISSION_WIRE 0
#define TRANSMISSION_RADIO 1
/* filters */
//When devices register with the radio controller, they might register under a certain filter.
//Other devices can then choose to send signals to only those devices that belong to a particular filter.
//This is done for performance, so we don't send signals to lots of machines unnecessarily.
//This filter is special because devices belonging to default also recieve signals sent to any other filter.
var/const/RADIO_DEFAULT = "radio_default"
var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms
var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in recieving signals from air alarms
var/const/RADIO_CHAT = "radio_telecoms"
var/const/RADIO_ATMOSIA = "radio_atmos"
var/const/RADIO_NAVBEACONS = "radio_navbeacon"
var/const/RADIO_AIRLOCK = "radio_airlock"
var/const/RADIO_SECBOT = "radio_secbot"
var/const/RADIO_MULEBOT = "radio_mulebot"
var/const/RADIO_MAGNETS = "radio_magnet"
var/global/datum/controller/radio/radio_controller
/hook/startup/proc/createRadioController()
radio_controller = new /datum/controller/radio()
return 1
//callback used by objects to react to incoming radio signals
/obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
return null
//The global radio controller
/datum/controller/radio
var/list/datum/radio_frequency/frequencies = list()
/datum/controller/radio/proc/add_object(obj/device as obj, var/new_frequency as num, var/filter = null as text|null)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
frequency.add_listener(device, filter)
return frequency
/datum/controller/radio/proc/remove_object(obj/device, old_frequency)
var/f_text = num2text(old_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(frequency)
frequency.remove_listener(device)
if(frequency.devices.len == 0)
del(frequency)
frequencies -= f_text
return 1
/datum/controller/radio/proc/return_frequency(var/new_frequency as num)
var/f_text = num2text(new_frequency)
var/datum/radio_frequency/frequency = frequencies[f_text]
if(!frequency)
frequency = new
frequency.frequency = new_frequency
frequencies[f_text] = frequency
return frequency
/datum/radio_frequency
var/frequency as num
var/list/list/obj/devices = list()
/datum/radio_frequency/proc/post_signal(obj/source as obj|null, datum/signal/signal, var/filter = null as text|null, var/range = null as num|null)
var/turf/start_point
if(range)
start_point = get_turf(source)
if(!start_point)
del(signal)
return 0
if (filter)
send_to_filter(source, signal, filter, start_point, range)
send_to_filter(source, signal, RADIO_DEFAULT, start_point, range)
else
//Broadcast the signal to everyone!
for (var/next_filter in devices)
send_to_filter(source, signal, next_filter, start_point, range)
//Sends a signal to all machines belonging to a given filter. Should be called by post_signal()
/datum/radio_frequency/proc/send_to_filter(obj/source, datum/signal/signal, var/filter, var/turf/start_point = null, var/range = null)
if (range && !start_point)
return
for(var/obj/device in devices[filter])
if(device == source)
continue
if(range)
var/turf/end_point = get_turf(device)
if(!end_point)
continue
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)
/datum/radio_frequency/proc/add_listener(obj/device as obj, var/filter as text|null)
if (!filter)
filter = RADIO_DEFAULT
//log_admin("add_listener(device=[device],filter=[filter]) frequency=[frequency]")
var/list/obj/devices_line = devices[filter]
if (!devices_line)
devices_line = new
devices[filter] = devices_line
devices_line+=device
// var/list/obj/devices_line___ = devices[filter_str]
// var/l = devices_line___.len
//log_admin("DEBUG: devices_line.len=[devices_line.len]")
//log_admin("DEBUG: devices(filter_str).len=[l]")
/datum/radio_frequency/proc/remove_listener(obj/device)
for (var/devices_filter in devices)
var/list/devices_line = devices[devices_filter]
devices_line-=device
while (null in devices_line)
devices_line -= null
if (devices_line.len==0)
devices -= devices_filter
del(devices_line)
/datum/signal
var/obj/source
var/transmission_method = 0 //unused at the moment
//0 = wire
//1 = radio transmission
//2 = subspace transmission
var/data = list()
var/encryption
var/frequency = 0
/datum/signal/proc/copy_from(datum/signal/model)
source = model.source
transmission_method = model.transmission_method
data = model.data
encryption = model.encryption
frequency = model.frequency
/datum/signal/proc/debug_print()
if (source)
. = "signal = {source = '[source]' ([source:x],[source:y],[source:z])\n"
else
. = "signal = {source = '[source]' ()\n"
for (var/i in data)
. += "data\[\"[i]\"\] = \"[data[i]]\"\n"
if(islist(data[i]))
var/list/L = data[i]
for(var/t in L)
. += "data\[\"[i]\"\] list has: [t]"
+22 -8
View File
@@ -98,6 +98,8 @@
//game_options.txt configs
var/atmos_machine_heat = 1.0
var/health_threshold_softcrit = 0
var/health_threshold_crit = 0
var/health_threshold_dead = -100
@@ -112,6 +114,8 @@
var/revival_cloning = 1
var/revival_brain_life = -1
var/use_loyalty_implants = 0
//Used for modifying movement speed for mobs.
//Unversal modifiers
var/run_speed = 0
@@ -521,10 +525,23 @@
config.revival_cloning = value
if("revival_brain_life")
config.revival_brain_life = value
if("organ_health_multiplier")
config.organ_health_multiplier = value / 100
if("organ_regeneration_multiplier")
config.organ_regeneration_multiplier = value / 100
if("bones_can_break")
config.bones_can_break = value
if("limbs_can_break")
config.limbs_can_break = value
if("atmos_machine_heat")
config.atmos_machine_heat = value
if("run_speed")
config.run_speed = value
if("walk_speed")
config.walk_speed = value
if("human_delay")
config.human_delay = value
if("robot_delay")
@@ -537,14 +554,11 @@
config.slime_delay = value
if("animal_delay")
config.animal_delay = value
if("organ_health_multiplier")
config.organ_health_multiplier = value / 100
if("organ_regeneration_multiplier")
config.organ_regeneration_multiplier = value / 100
if("bones_can_break")
config.bones_can_break = value
if("limbs_can_break")
config.limbs_can_break = value
if("use_loyalty_implants")
config.use_loyalty_implants = 1
else
log_misc("Unknown setting in configuration: '[name]'")
+12
View File
@@ -16,6 +16,8 @@ datum/controller/lighting
var/list/changed_turfs = list()
var/changed_turfs_workload_max = 0
var/list/changed_areas = list()
datum/controller/lighting/New()
lighting_states = max( 0, length(icon_states(LIGHTING_ICON))-1 )
if(lighting_controller != src)
@@ -53,9 +55,19 @@ 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.tag = null
A.related -= A
active_areas -= A
all_areas -= A
changed_areas.Cut()
process_cost = (world.timeofday - started)
sleep(processing_interval)
+17 -4
View File
@@ -109,17 +109,24 @@ datum/controller/game_controller/proc/setup_objects()
var/obj/machinery/atmospherics/unary/vent_scrubber/T = U
T.broadcast_status()
//Create the mining ore distribution map.
//Create the mining ore distribution map.
asteroid_ore_map = new /datum/ore_distribution()
asteroid_ore_map.populate_distribution_map()
//Shitty hack to fix mining turf overlays, for some reason New() is not being called.
for(var/turf/simulated/floor/plating/airless/asteroid/T in world)
T.updateMineralOverlays()
T.name = "asteroid"
//Set up spawn points.
populate_spawn_points()
//Set up gear list.
populate_gear_list()
//Set up roundstart seed list.
populate_seed_list()
world << "\red \b Initializations complete."
sleep(-1)
@@ -292,10 +299,16 @@ datum/controller/game_controller/proc/process_machines_power()
var/area/A = active_areas[i]
if(A.powerupdate && A.master == A)
A.powerupdate -= 1
for(var/area/SubArea in A.related)
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)
if(M)
if(M.use_power)
//check if the area has power for M's channel
//this will keep stat updated in case the machine is moved from one area to another.
M.power_change(A) //we've already made sure A is a master area, above.
if(!(M.stat & NOPOWER) && M.use_power)
M.auto_use_power()
if(A.apc.len && A.master == A)
@@ -342,7 +355,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)
+4 -1
View File
@@ -48,7 +48,7 @@
message_admins("Admin [key_name_admin(usr)] has restarted the [controller] controller.")
return
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller"))
/client/proc/debug_controller(controller in list("Master","Failsafe","Ticker","Lighting","Air","Jobs","Sun","Radio","Supply","Shuttles","Emergency Shuttle","Configuration","pAI", "Cameras", "Transfer Controller", "Gas Data"))
set category = "Debug"
set name = "Debug Controller"
set desc = "Debug the various periodic loop controllers for the game (be careful!)"
@@ -100,5 +100,8 @@
if("Transfer Controller")
debug_variables(transfer_controller)
feedback_add_details("admin_verb","DAutovoter")
if("Gas Data")
debug_variables(gas_data)
feedback_add_details("admin_verv","DGasdata")
message_admins("Admin [key_name_admin(usr)] is debugging the [controller] controller.")
return
+12 -19
View File
@@ -510,14 +510,9 @@ datum/mind
I.Del()
break
H << "\blue <Font size =3><B>Your loyalty implant has been deactivated.</B></FONT>"
if("add")
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
L.imp_in = H
L.implanted = 1
var/datum/organ/external/affected = H.organs_by_name["head"]
affected.implants += L
L.part = affected
if("add")
H.implant_loyalty(H, override = TRUE)
H << "\red <Font size =3><B>You somehow have become the recepient of a loyalty transplant, and it just activated!</B></FONT>"
if(src in ticker.mode.revolutionaries)
special_role = null
@@ -541,6 +536,8 @@ datum/mind
special_role = null
current << "\red <FONT size = 3><B>The nanobots in the loyalty implant remove all thoughts about being a traitor to Nanotrasen. Have a nice day!</B></FONT>"
log_admin("[key_name_admin(usr)] has de-traitor'ed [current].")
else
else if (href_list["revolution"])
current.hud_updateflag |= (1 << SPECIALROLE_HUD)
@@ -567,7 +564,7 @@ datum/mind
current << "\red <FONT size = 3><B>Revolution has been disappointed of your leader traits! You are a regular revolutionary now!</B></FONT>"
else if(!(src in ticker.mode.revolutionaries))
current << "\red <FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT>"
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(src)
else
return
ticker.mode.revolutionaries += src
@@ -580,7 +577,7 @@ datum/mind
ticker.mode.revolutionaries -= src
ticker.mode.update_rev_icons_removed(src)
current << "\red <FONT size = 3><B>You have proved your devotion to revoltion! You are a head revolutionary now!</B></FONT>"
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(src)
else if(!(src in ticker.mode.head_revolutionaries))
current << "\blue You are a member of the revolutionaries' leadership now!"
else
@@ -659,11 +656,11 @@ datum/mind
special_role = "Cultist"
current << "<font color=\"purple\"><b><i>You catch a glimpse of the Realm of Nar-Sie, The Geometer of Blood. You now see how flimsy the world is, you see that it should be open to the knowledge of Nar-Sie.</b></i></font>"
current << "<font color=\"purple\"><b><i>Assist your new compatriots in their dark dealings. Their goal is yours, and yours is theirs. You serve the Dark One above all else. Bring It back.</b></i></font>"
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
var/datum/game_mode/cult/cult = ticker.mode
if (istype(cult))
if(!config.objectives_disabled)
cult.memorize_cult_objectives(src)
show_objectives(src)
log_admin("[key_name_admin(usr)] has cult'ed [current].")
if("tome")
var/mob/living/carbon/human/H = current
@@ -704,7 +701,7 @@ datum/mind
special_role = "Wizard"
//ticker.mode.learn_basic_spells(current)
current << "<B>\red You are the Space Wizard!</B>"
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(src)
log_admin("[key_name_admin(usr)] has wizard'ed [current].")
if("lair")
current.loc = pick(wizardstart)
@@ -735,8 +732,7 @@ datum/mind
ticker.mode.grant_changeling_powers(current)
special_role = "Changeling"
current << "<B><font color='red'>Your powers are awoken. A flash of memory returns to us...we are a changeling!</font></B>"
if(config.objectives_disabled)
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(src)
log_admin("[key_name_admin(usr)] has changeling'ed [current].")
if("autoobjectives")
if(!config.objectives_disabled)
@@ -777,10 +773,7 @@ datum/mind
current.real_name = "[syndicate_name()] Operative #[ticker.mode.syndicates.len-1]"
special_role = "Syndicate"
current << "\blue You are a [syndicate_name()] agent!"
if(config.objectives_disabled)
current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
else
ticker.mode.forge_syndicate_objectives(src)
ticker.mode.forge_syndicate_objectives(src)
ticker.mode.greet_syndicate(src)
log_admin("[key_name_admin(usr)] has nuke op'ed [current].")
if("lair")
@@ -832,8 +825,8 @@ datum/mind
special_role = "traitor"
current << "<B>\red You are a traitor!</B>"
log_admin("[key_name_admin(usr)] has traitor'ed [current].")
if (config.objectives_disabled)
current << "<i>You have been turned into an antagonist- <font color=blue>Within the rules,</font> try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonist.</i></b>"
show_objectives()
if(istype(current, /mob/living/silicon))
var/mob/living/silicon/A = current
call(/datum/game_mode/proc/add_law_zero)(A)
-15
View File
@@ -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
+39 -32
View File
@@ -5,7 +5,7 @@
//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle.
//NEW NOTE: Do NOT set the price of any crates below 7 points. Doing so allows infinite points.
var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Medical / Science","Hydroponics", "Supply", "Miscellaneous")
var/list/all_supply_groups = list("Operations","Security","Hospitality","Engineering","Atmospherics","Medical","Science","Hydroponics", "Supply", "Miscellaneous")
/datum/supply_packs
var/name = null
@@ -149,7 +149,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 10
containertype = /obj/structure/closet/crate/internals
containername = "Internals crate"
group = "Engineering"
group = "Atmospherics"
/datum/supply_packs/evacuation
name = "Emergency equipment"
@@ -170,7 +170,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 35
containertype = /obj/structure/closet/crate/internals
containername = "Emergency crate"
group = "Engineering"
group = "Atmospherics"
/datum/supply_packs/inflatable
name = "Inflatable barriers"
@@ -180,7 +180,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 20
containertype = /obj/structure/closet/crate
containername = "Inflatable Barrier Crate"
group = "Engineering"
group = "Atmospherics"
/datum/supply_packs/janitor
name = "Janitorial supplies"
@@ -235,7 +235,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/datum/supply_packs/cargotrain
name = "Cargo Train Tug"
contains = list(/obj/vehicle/train/cargo/engine)
cost = 30
cost = 45
containertype = /obj/structure/largecrate
containername = "Cargo Train Tug Crate"
group = "Operations"
@@ -243,7 +243,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/datum/supply_packs/cargotrailer
name = "Cargo Train Trolley"
contains = list(/obj/vehicle/train/cargo/trolley)
cost = 20
cost = 15
containertype = /obj/structure/largecrate
containername = "Cargo Train Trolley Crate"
group = "Operations"
@@ -266,7 +266,10 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/obj/item/weapon/minihoe,
/obj/item/device/analyzer/plant_analyzer,
/obj/item/clothing/gloves/botanic_leather,
/obj/item/clothing/suit/apron) // Updated with new things
/obj/item/clothing/suit/apron,
/obj/item/weapon/minihoe,
/obj/item/weapon/storage/box/botanydisk
) // Updated with new things
cost = 15
containertype = /obj/structure/closet/crate/hydroponics
containername = "Hydroponics crate"
@@ -380,7 +383,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 10
containertype = /obj/structure/closet/crate/medical
containername = "Medical crate"
group = "Medical / Science"
group = "Medical"
/datum/supply_packs/virus
name = "Virus sample crate"
@@ -404,7 +407,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = "/obj/structure/closet/crate/secure"
containername = "Virus sample crate"
access = access_cmo
group = "Medical / Science"
group = "Science"
/datum/supply_packs/metal50
name = "50 metal sheets"
@@ -486,7 +489,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 16
containertype = /obj/structure/largecrate
containername = "coolant tank crate"
group = "Medical / Science"
group = "Science"
/datum/supply_packs/solar
name = "Solar Pack crate"
@@ -578,7 +581,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = /obj/structure/closet/crate/secure
containername = "APLU \"Ripley\" Circuit Crate"
access = access_robotics
group = "Engineering"
group = "Science"
/datum/supply_packs/mecha_odysseus
name = "Circuit Crate (\"Odysseus\")"
@@ -588,7 +591,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = /obj/structure/closet/crate/secure
containername = "\"Odysseus\" Circuit Crate"
access = access_robotics
group = "Engineering"
group = "Science"
/datum/supply_packs/robotics
@@ -627,7 +630,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = /obj/structure/closet/crate/secure/phoron
containername = "Phoron assembly crate"
access = access_tox_storage
group = "Medical / Science"
group = "Science"
/datum/supply_packs/weapons
name = "Weapons crate"
@@ -697,14 +700,6 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
access = access_armory
group = "Security"
/datum/supply_packs/loyalty
name = "Loyalty implant crate"
contains = list (/obj/item/weapon/storage/lockbox/loyalty)
cost = 60
containertype = /obj/structure/closet/crate/secure
containername = "Loyalty implant crate"
access = access_armory
group = "Security"
/datum/supply_packs/ballistic
name = "Ballistic gear crate"
@@ -741,6 +736,17 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
access = access_armory
group = "Security"
/*
/datum/supply_packs/loyalty
name = "Loyalty implant crate"
contains = list (/obj/item/weapon/storage/lockbox/loyalty)
cost = 60
containertype = /obj/structure/closet/crate/secure
containername = "Loyalty implant crate"
access = access_armory
group = "Security"
*/
/datum/supply_packs/expenergy
name = "Experimental energy gear crate"
contains = list(/obj/item/clothing/suit/armor/laserproof,
@@ -845,6 +851,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "Arts and Crafts crate"
group = "Operations"
/datum/supply_packs/randomised/contraband
num_contained = 5
contains = list(/obj/item/seeds/bloodtomatoseed,
@@ -893,7 +900,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = "/obj/structure/closet/crate/secure"
containername = "Surgery crate"
access = access_medical
group = "Medical / Science"
group = "Medical"
/datum/supply_packs/sterile
name = "Sterile equipment crate"
@@ -904,7 +911,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 15
containertype = "/obj/structure/closet/crate"
containername = "Sterile equipment crate"
group = "Medical / Science"
group = "Medical"
/datum/supply_packs/randomised/pizza
num_contained = 5
@@ -1202,7 +1209,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containertype = /obj/structure/closet/crate/hydroponics
containername = "Hydroponics tray crate"
group = "Hydroponics"
contains = list(/obj/machinery/hydroponics{anchored = 0})
contains = list(/obj/machinery/portable_atmospherics/hydroponics{anchored = 0})
access = access_hydroponics
/datum/supply_packs/canister_empty
@@ -1211,14 +1218,14 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "Empty gas canister crate"
containertype = /obj/structure/largecrate
contains = list(/obj/machinery/portable_atmospherics/canister)
group = "Engineering"
group = "Atmospherics"
/datum/supply_packs/canister_air
name = "Air canister"
cost = 10
containername = "Air canister crate"
containertype = /obj/structure/largecrate
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/air)
/datum/supply_packs/canister_oxygen
@@ -1226,7 +1233,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 15
containername = "Oxygen canister crate"
containertype = /obj/structure/largecrate
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/oxygen)
/datum/supply_packs/canister_nitrogen
@@ -1234,7 +1241,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
cost = 10
containername = "Nitrogen canister crate"
containertype = /obj/structure/largecrate
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/nitrogen)
/datum/supply_packs/canister_phoron
@@ -1243,7 +1250,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "Phoron gas canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/phoron)
/datum/supply_packs/canister_sleeping_agent
@@ -1252,7 +1259,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "N2O gas canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/sleeping_agent)
/datum/supply_packs/canister_carbon_dioxide
@@ -1261,7 +1268,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
containername = "CO2 canister crate"
containertype = /obj/structure/closet/crate/secure/large
access = access_atmospherics
group = "Engineering"
group = "Atmospherics"
contains = list(/obj/machinery/portable_atmospherics/canister/carbon_dioxide)
/datum/supply_packs/pacman_parts
@@ -1276,7 +1283,7 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee
/obj/item/weapon/stock_parts/matter_bin,
/obj/item/weapon/circuitboard/pacman)
/datum/supply_packs/pacman_parts
/datum/supply_packs/super_pacman_parts
name = "Super P.A.C.M.A.N. portable generator parts"
cost = 55
containername = "Super P.A.C.M.A.N. portable generator construction kit"
+4 -2
View File
@@ -52,8 +52,10 @@
icon_state = "soapnt"
/obj/item/weapon/soap/deluxe
desc = "A deluxe Waffle Co. brand bar of soap. Smells of condoms."
icon_state = "soapdeluxe"
/obj/item/weapon/soap/deluxe/New()
desc = "A deluxe Waffle Co. brand bar of soap. Smells of [pick("lavender", "vanilla", "strawberry", "chocolate" ,"space")]."
/obj/item/weapon/soap/syndie
desc = "An untrustworthy bar of soap. Smells of fear."
@@ -162,7 +164,7 @@
icon_state = "beartrap[armed]"
user << "<span class='notice'>[src] is now [armed ? "armed" : "disarmed"]</span>"
/obj/item/weapon/legcuffs/beartrap/HasEntered(AM as mob|obj)
/obj/item/weapon/legcuffs/beartrap/Crossed(AM as mob|obj)
if(armed)
if(ishuman(AM))
if(isturf(src.loc))
+6 -5
View File
@@ -1,5 +1,6 @@
/proc/captain_announce(var/text)
world << "<h1 class='alert'>Priority Announcement</h1>"
world << "<span class='alert'>[html_encode(text)]</span>"
world << "<br>"
/proc/captain_announce(message as text, title = "Priority Announcement", announcer = "")
world << "<h1 class='alert'>[html_encode(title)]</h1>"
world << "<span class='alert'>[html_encode(message)]</span>"
if(announcer)
world << "<span class='alert'> -[html_encode(announcer)]</span>"
world << "<br>"
+50 -14
View File
@@ -22,7 +22,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/poweralm = 1
var/party = null
level = null
name = "Space"
name = "Unknown"
icon = 'icons/turf/areas.dmi'
icon_state = "unknown"
layer = 10
@@ -35,6 +35,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
var/debug = 0
var/powerupdate = 10 //We give everything 10 ticks to settle out it's power usage.
var/requires_power = 1
var/unlimited_power = 0
var/always_unpowered = 0 //this gets overriden to 1 for space in area/New()
var/power_equip = 1
@@ -54,6 +55,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
// var/list/lights // list of all lights on this area
var/list/all_doors = list() //Added by Strumpetplaya - Alarm Change - Contains a list of doors adjacent to this area
var/air_doors_activated = 0
var/list/ambience = list('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
/*Adding a wizard area teleport list because motherfucking lag -- Urist*/
/*I am far too lazy to make it a proper list of areas so I'll just make it run the usual telepot routine at the start of the game*/
@@ -90,9 +92,26 @@ var/list/ghostteleportlocs = list()
return 1
/*-----------------------------------------------------------------------------*/
/area/space
name = "\improper Space"
requires_power = 1
always_unpowered = 1
lighting_use_dynamic = 1
power_light = 0
power_equip = 0
power_environ = 0
ambience = list('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg')
/area/space/firealert()
return
/area/space/readyalert()
return
/area/space/partyalert()
return
/area/engine/
ambience = list('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
/area/turret_protected/
/area/arrival
@@ -361,9 +380,10 @@ 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
/area/syndicate_mothership/control
name = "\improper Syndicate Control Room"
@@ -436,6 +456,7 @@ var/list/ghostteleportlocs = list()
name = "\improper Syndicate Station"
icon_state = "yellow"
requires_power = 0
unlimited_power = 1
/area/syndicate_station/start
name = "\improper Syndicate Forward Operating Base"
@@ -866,6 +887,7 @@ var/list/ghostteleportlocs = list()
/area/chapel/main
name = "\improper Chapel"
icon_state = "chapel"
ambience = list('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg','sound/music/traitor.ogg')
/area/chapel/office
name = "\improper Chapel Office"
@@ -970,6 +992,10 @@ var/list/ghostteleportlocs = list()
name = "\improper Engine Monitoring Room"
icon_state = "engine_monitoring"
engine_waste
name = "\improper Engine Waste Handling"
icon_state = "engine_waste"
engineering_monitoring
name = "\improper Engineering Monitoring Room"
icon_state = "engine_monitoring"
@@ -1022,7 +1048,8 @@ var/list/ghostteleportlocs = list()
//Solars
/area/solar
requires_power = 0
requires_power = 1
always_unpowered = 1
luminosity = 1
lighting_use_dynamic = 0
@@ -1052,7 +1079,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"
@@ -1064,8 +1091,11 @@ 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"
icon_state = "SolarcontrolA"
/area/assembly/chargebay
name = "\improper Mech Bay"
@@ -1102,6 +1132,7 @@ var/list/ghostteleportlocs = list()
name = "\improper AI Satellite Teleporter Room"
icon_state = "teleporter"
music = "signal"
ambience = list('sound/ambience/ambimalf.ogg')
//MedBay
@@ -1177,10 +1208,6 @@ var/list/ghostteleportlocs = list()
name = "\improper Robotics"
icon_state = "medresearch"
/area/medical/research
name = "\improper Medical Research"
icon_state = "medresearch"
/area/medical/virology
name = "\improper Virology"
icon_state = "virology"
@@ -1192,6 +1219,7 @@ var/list/ghostteleportlocs = list()
/area/medical/morgue
name = "\improper Morgue"
icon_state = "morgue"
ambience = list('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/music/main.ogg')
/area/medical/chemistry
name = "\improper Chemistry"
@@ -1378,12 +1406,11 @@ var/list/ghostteleportlocs = list()
icon_state = "garden"
//rnd (Research and Development
/area/rnd/research
name = "\improper Research and Development"
icon_state = "research"
/area/rnd/lab
name = "\improper Research and Development"
icon_state = "toxlab"
/area/rnd/hallway
name = "\improper Research Lab"
icon_state = "toxlab"
@@ -1692,10 +1719,12 @@ var/list/ghostteleportlocs = list()
/area/turret_protected/ai_upload
name = "\improper AI Upload Chamber"
icon_state = "ai_upload"
ambience = list('sound/ambience/ambimalf.ogg')
/area/turret_protected/ai_upload_foyer
name = "AI Upload Access"
icon_state = "ai_foyer"
ambience = list('sound/ambience/ambimalf.ogg')
/area/turret_protected/ai_server_room
name = "AI Server Room"
@@ -1704,6 +1733,7 @@ var/list/ghostteleportlocs = list()
/area/turret_protected/ai
name = "\improper AI Chamber"
icon_state = "ai_chamber"
ambience = list('sound/ambience/ambimalf.ogg')
/area/turret_protected/ai_cyborg_station
name = "\improper Cyborg Station"
@@ -1774,6 +1804,8 @@ var/list/ghostteleportlocs = list()
// Telecommunications Satellite
/area/tcommsat/
ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/tcommsat/entrance
name = "\improper Telecoms Teleporter"
@@ -1786,18 +1818,22 @@ var/list/ghostteleportlocs = list()
/area/turret_protected/tcomsat
name = "\improper Telecoms Satellite"
icon_state = "tcomsatlob"
ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomfoyer
name = "\improper Telecoms Foyer"
icon_state = "tcomsatentrance"
ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomwest
name = "\improper Telecommunications Satellite West Wing"
icon_state = "tcomsatwest"
ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/turret_protected/tcomeast
name = "\improper Telecommunications Satellite East Wing"
icon_state = "tcomsateast"
ambience = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
/area/tcommsat/computer
name = "\improper Telecoms Control Room"
+10 -44
View File
@@ -16,16 +16,6 @@
active_areas += src
all_areas += src
if(type == /area) // override defaults for space. TODO: make space areas of type /area/space rather than /area
requires_power = 1
always_unpowered = 1
lighting_use_dynamic = 1
power_light = 0
power_equip = 0
power_environ = 0
// lighting_state = 4
//has_gravity = 0 // Space has gravity. Because.. because.
if(requires_power)
luminosity = 0
else
@@ -71,18 +61,18 @@
/area/proc/atmosalert(danger_level)
// if(type==/area) //No atmos alarms in space
// return 0 //redudant
//Check all the alarms before lowering atmosalm. Raising is perfectly fine.
for (var/area/RA in related)
for (var/obj/machinery/alarm/AA in RA)
if ( !(AA.stat & (NOPOWER|BROKEN)) && !AA.shorted)
danger_level = max(danger_level, AA.danger_level)
if(danger_level != atmosalm)
if (danger_level < 1 && atmosalm >= 1)
//closing the doors on red and opening on green provides a bit of hysteresis that will hopefully prevent fire doors from opening and closing repeatedly due to noise
air_doors_open()
if (danger_level < 2 && atmosalm >= 2)
for(var/area/RA in related)
for(var/obj/machinery/camera/C in RA)
@@ -91,7 +81,7 @@
aiPlayer.cancelAlarm("Atmosphere", src, src)
for(var/obj/machinery/computer/station_alert/a in machines)
a.cancelAlarm("Atmosphere", src, src)
if (danger_level >= 2 && atmosalm < 2)
var/list/cameras = list()
for(var/area/RA in related)
@@ -104,12 +94,12 @@
for(var/obj/machinery/computer/station_alert/a in machines)
a.triggerAlarm("Atmosphere", src, cameras, src)
air_doors_close()
atmosalm = danger_level
for(var/area/RA in related)
for (var/obj/machinery/alarm/AA in RA)
AA.update_icon()
return 1
return 0
@@ -183,8 +173,6 @@
a.cancelAlarm("Fire", src, src)
/area/proc/readyalert()
if(name == "Space")
return
if(!eject)
eject = 1
updateicon()
@@ -197,8 +185,6 @@
return
/area/proc/partyalert()
if(name == "Space") //no parties in space!!!
return
if (!( party ))
party = 1
updateicon()
@@ -323,32 +309,12 @@
L.client.ambience_playing = 1
L << sound('sound/ambience/shipambience.ogg', repeat = 1, wait = 0, volume = 35, channel = 2)
if(prob(35))
if(src.ambience.len && prob(35))
sound = pick(ambience)
if(istype(src, /area/chapel))
sound = pick('sound/ambience/ambicha1.ogg','sound/ambience/ambicha2.ogg','sound/ambience/ambicha3.ogg','sound/ambience/ambicha4.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/medical/morgue))
sound = pick('sound/ambience/ambimo1.ogg','sound/ambience/ambimo2.ogg','sound/music/main.ogg')
else if(type == /area)
sound = pick('sound/ambience/ambispace.ogg','sound/music/title2.ogg','sound/music/space.ogg','sound/music/main.ogg','sound/music/traitor.ogg')
else if(istype(src, /area/engine))
sound = pick('sound/ambience/ambisin1.ogg','sound/ambience/ambisin2.ogg','sound/ambience/ambisin3.ogg','sound/ambience/ambisin4.ogg')
else if(istype(src, /area/AIsattele) || istype(src, /area/turret_protected/ai) || istype(src, /area/turret_protected/ai_upload) || istype(src, /area/turret_protected/ai_upload_foyer))
sound = pick('sound/ambience/ambimalf.ogg')
else if(istype(src, /area/mine/explored) || istype(src, /area/mine/unexplored))
sound = pick('sound/ambience/ambimine.ogg', 'sound/ambience/song_game.ogg')
musVolume = 25
else if(istype(src, /area/tcommsat) || istype(src, /area/turret_protected/tcomwest) || istype(src, /area/turret_protected/tcomeast) || istype(src, /area/turret_protected/tcomfoyer) || istype(src, /area/turret_protected/tcomsat))
sound = pick('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg')
else
sound = pick('sound/ambience/ambigen1.ogg','sound/ambience/ambigen3.ogg','sound/ambience/ambigen4.ogg','sound/ambience/ambigen5.ogg','sound/ambience/ambigen6.ogg','sound/ambience/ambigen7.ogg','sound/ambience/ambigen8.ogg','sound/ambience/ambigen9.ogg','sound/ambience/ambigen10.ogg','sound/ambience/ambigen11.ogg','sound/ambience/ambigen12.ogg','sound/ambience/ambigen14.ogg')
if(!L.client.played)
if(world.time > L.client.played + 600)
L << sound(sound, repeat = 0, wait = 0, volume = musVolume, channel = 1)
L.client.played = 1
spawn(600) //ewww - this is very very bad
if(L.&& L.client)
L.client.played = 0
L.client.played = world.time
/area/proc/gravitychange(var/gravitystate = 0, var/area/A)
-3
View File
@@ -70,9 +70,6 @@
/atom/proc/CheckExit()
return 1
/atom/proc/HasEntered(atom/movable/AM as mob|obj)
return
/atom/proc/HasProximity(atom/movable/AM as mob|obj)
return
+8 -8
View File
@@ -276,15 +276,15 @@
del(src)
/obj/machinery/computer/scan_consolenew/power_change()
..()
if(stat & BROKEN)
icon_state = "broken"
else if(powered())
icon_state = initial(icon_state)
stat &= ~NOPOWER
else
spawn(rand(0, 15))
src.icon_state = "c_unpowered"
stat |= NOPOWER
if (stat & NOPOWER)
spawn(rand(0, 15))
src.icon_state = "c_unpowered"
else
icon_state = initial(icon_state)
/obj/machinery/computer/scan_consolenew/New()
..()
@@ -345,7 +345,7 @@
*
* @return nothing
*/
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
/obj/machinery/computer/scan_consolenew/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
if(user == connected.occupant || user.stat)
return
@@ -425,7 +425,7 @@
data["beakerVolume"] += R.volume
// update the ui if it exists, returns null if no ui is passed/found
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if (!ui)
// the ui does not exist, so we'll create a new() one
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+6 -16
View File
@@ -136,14 +136,9 @@
newtraitor << "<B>You are now a traitor.</B>"
newtraitor.mind.special_role = "traitor"
newtraitor.hud_updateflag |= 1 << SPECIALROLE_HUD
var/obj_count = 1
newtraitor << "\blue Your current objectives:"
if(!config.objectives_disabled)
for(var/datum/objective/objective in newtraitor.mind.objectives)
newtraitor << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
else
newtraitor << "<i>You have been selected this round as an antagonist- <font color=blue>Within the rules,</font> try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonist.</i></b>"
newtraitor << "<i>You have been selected this round as an antagonist!</i>"
show_objectives(newtraitor.mind)
//else
//message_admins("No new traitor being added.")
//else
@@ -194,14 +189,9 @@
traitors += character.mind
character << "\red <B>You are the traitor.</B>"
character.mind.special_role = "traitor"
if (config.objectives_disabled)
character << "<i>You have been selected this round as an antagonist- <font color=blue>Within the rules,</font> try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonist.</i></b>"
else
var/obj_count = 1
character << "\blue Your current objectives:"
for(var/datum/objective/objective in character.mind.objectives)
character << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
character << "<i>You have been selected this round as an antagonist</i>!"
show_objectives(character.mind)
//else
//message_admins("New traitor roll failed. No new traitor.")
//else
+449
View File
@@ -0,0 +1,449 @@
/*
* This roundtype is a replacement for the meteor round on upstream BS12 - players
* expressed the desire for quick, chaotic and violent rounds, preferrably without
* dependancy on other players.
* I wanted to call it clusterfuck, but I figure that's a bit too overt. Think of
* the children.
* ~ Zuhayr
*/
/datum/game_mode/calamity
name = "calamity"
config_tag = "calamity"
required_players = 1
votable = 0 //Remove after testing.
uplink_welcome = "Syndicate Uplink Console:"
uplink_uses = 10
//Possible roundstart antag types.
var/list/atypes = list("syndi","ling","tater","wiz","ninja","vox","slug","cult")
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/const/waittime_l = 600
var/const/waittime_h = 1800
/datum/game_mode/calamity/announce()
world << "<B>The current game mode is - Calamity!</B>"
world << "<B>This must be a Thursday. You never could get the hang of Thursdays...</B>"
/datum/game_mode/calamity/can_start()
if(!..())
return 0
var/antag_count = player_list.len/antag_type_ratio
if(!antag_count)
return 1
for(var/i=0;i<antag_count;i++)
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.
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
log_debug("Calamity: selected [atype] (possible candidates: [candidates.len])")
chosen_atypes += atype
for(var/j=0;j<max_antags;j++)
var/datum/mind/chosen_candidate = pick(candidates)
//Traitors and lings spawn THEN have roles applied; hence we don't set assigned_role here.
if(atype != "tater" && atype != "ling" && atype != "cult")
chosen_candidate.assigned_role = "MODE"
chosen_candidate.special_role = atype
chosen_candidates += chosen_candidate
if(atypes.len - i <= 0) break //Not enough valid types left to populate the remaining antag slots.
return 1
/datum/game_mode/calamity/post_setup()
if(chosen_atypes)
for(var/atype in chosen_atypes)
var/list/candidates = list()
for(var/datum/mind/player in chosen_candidates)
if(player.special_role == atype)
candidates += player
chosen_candidates -= player
if(!candidates || !candidates.len)
log_debug("No candidates for [atype].")
continue
log_debug("Calamity: spawning [atype].")
for(var/datum/mind/player in candidates)
player.special_role = get_candidate_role_text(atype)
switch(atype)
if("syndi")
spawn_syndicate(candidates)
if("ling")
spawn_changelings(candidates)
if("tater")
spawn_traitors(candidates)
if("wiz")
spawn_cabal(candidates)
if("ninja")
spawn_ninja(candidates)
if("vox")
spawn_vox_raiders(candidates)
if("slug")
spawn_borers(candidates)
if("cult")
spawn_cultists(candidates)
/datum/game_mode/calamity/declare_completion()
var/text = "<FONT size = 3><B>This terrible, terrible day has finally ended!</B></FONT><BR/>"
//Group antag objective completion.
for(var/list/L in list(src.raiders, src.syndicates, src.cult, src.wizards))
if(L.len)
var/datum/mind/M = L[1]
text = "<BR/><FONT size = 2><B>The [M.special_role][L.len == 1 ? " was" : "s were"]:</B></FONT>"
for(var/datum/mind/P in L)
text += "<br>[P.key] was [P.name] ("
if(P.current)
if(P.current.stat == DEAD)
text += "died"
else
text += "survived"
if(P.current.real_name != P.name)
text += " as [P.current.real_name]"
else
text += "body destroyed"
text += ")"
if(M.objectives.len)
text += "<BR/><FONT size = 2>Their objectives were:<FONT>"
var/num = 1
for(var/datum/objective/O in M.objectives)
text += "<BR/><B>Objective [num]:</B> [O.explanation_text]"
num++
//Single antag objective completion.
for(var/list/L in list(src.changelings, src.ninjas, src.borers, src.traitors))
if(L.len)
var/datum/mind/M = L[1]
text = "<BR/><FONT size = 2><B>The [M.special_role][L.len == 1 ? " was" : "s were"]:</B></FONT>"
for(var/datum/mind/P in L)
var/num = 1
text += "<BR/><FONT size = 2>[P.key] was [P.name].<FONT>"
if(P.objectives.len)
for(var/datum/objective/O in P.objectives)
text += "<BR/><B>Objective [num]:</B> [O.explanation_text]"
num++
..()
return 1
//Converts chosen atype to an actual role string.
/datum/game_mode/calamity/proc/get_candidate_role_text(var/role)
var/role_text
switch(role)
if("syndi")
role_text = "Syndicate Operative"
if("ling")
role_text = "Changeling"
if("tater")
role_text = "Traitor"
if("wiz")
role_text = "Cabalist"
if("ninja")
role_text = "Ninja"
if("vox")
role_text = "Vox Raider"
if("slug")
role_text = "Cortical Borer"
if("cult")
role_text = "Cultist"
return role_text
//Grabs candidate lists for various atypes.
/datum/game_mode/calamity/proc/get_role_candidates(var/role)
var/list/possible_antags = list()
switch(role)
if("syndi")
possible_antags = get_players_for_role(BE_OPERATIVE)
if("ling")
possible_antags = get_players_for_role(BE_CHANGELING)
if("tater")
possible_antags = get_players_for_role(BE_TRAITOR)
if("wiz")
possible_antags = get_players_for_role(BE_WIZARD)
if("ninja")
possible_antags = get_players_for_role(BE_NINJA)
if("vox")
possible_antags = get_players_for_role(BE_RAIDER)
if("slug")
possible_antags = get_players_for_role(BE_ALIEN)
if("cult")
possible_antags = get_players_for_role(BE_CULTIST)
var/list/filtered_antags = list()
if(possible_antags)
for(var/datum/mind/candidate in possible_antags)
if(!(candidate in already_assigned_candidates))
filtered_antags |= candidate
already_assigned_candidates |= candidate
if(filtered_antags && islist(filtered_antags))
return filtered_antags
else
return list(filtered_antags)
//Spawning procs for the various antag types.
//A LOT OF THE FOLLOWING IS COPYPASTED FROM OTHER MODES AND NEEDS
//TO BE FIXED UP. NINJA, NUKE AND CULT IN PARTICULAR ARE FUCKING AWFUL. ~ Z
/datum/game_mode/calamity/proc/spawn_syndicate(var/list/candidates)
var/obj/effect/landmark/uplinklocker = locate("landmark*Syndicate-Uplink")
var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")
var/nuke_code = "[rand(10000, 99999)]"
var/leader_selected = 0
var/spawnpos = 1
for(var/datum/mind/player in candidates)
syndicates += player
if(spawnpos > synd_spawn.len)
spawnpos = 1
player.current.loc = synd_spawn[spawnpos]
player.current.real_name = "[syndicate_name()] Operative"
spawn(0)
NukeNameAssign(player)
forge_syndicate_objectives(player)
greet_syndicate(player)
equip_syndicate(player.current)
if(!leader_selected)
prepare_syndicate_leader(player, nuke_code)
leader_selected = 1
spawnpos++
update_synd_icons_added(player)
update_all_synd_icons()
if(uplinklocker)
new /obj/structure/closet/syndicate/nuclear(uplinklocker.loc)
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
/datum/game_mode/calamity/proc/spawn_changelings(var/list/candidates)
for(var/datum/mind/player in candidates)
changelings += player
grant_changeling_powers(player.current)
player.special_role = "Changeling"
if(!config.objectives_disabled)
player.objectives += new /datum/objective/escape()
player.objectives += new /datum/objective/survive()
show_objectives(player)
greet_changeling(player)
/datum/game_mode/calamity/proc/spawn_traitors(var/list/candidates)
for(var/datum/mind/player in candidates)
traitors += player
if(!config.objectives_disabled)
player.objectives += new /datum/objective/escape()
player.objectives += new /datum/objective/survive()
show_objectives(player)
finalize_traitor(player)
greet_traitor(player)
/datum/game_mode/calamity/proc/spawn_cabal(var/list/candidates)
for(var/datum/mind/player in candidates)
wizards += player
if(!config.objectives_disabled)
player.objectives += new /datum/objective/escape()
player.objectives += new /datum/objective/survive()
show_objectives(player)
player.current.loc = pick(wizardstart)
equip_wizard(player.current)
name_wizard(player.current)
greet_wizard(player)
/datum/game_mode/calamity/proc/spawn_ninja(var/list/candidates)
//I hate that this is necessary. ~Z
for(var/obj/effect/landmark/L in landmarks_list)
if(L.name == "carpspawn")
ninjastart.Add(L)
for(var/datum/mind/player in candidates)
ninjas += player
player.current << browse(null, "window=playersetup")
player.current = create_space_ninja(pick(ninjastart))
player.current.ckey = player.key
if(player.current && !(istype(player.current,/mob/living/carbon/human))) return 0
//Ninja intro crawl goes here.
if(!config.objectives_disabled)
player.objectives += new /datum/objective/ninja_highlander()
player.objectives += new /datum/objective/survive()
show_objectives(player)
//Ninja objective announcement goes here.
//Set ninja internals.
var/mob/living/carbon/human/N = player.current
N.internal = N.s_store
N.internals.icon_state = "internal1"
if(N.wear_suit && istype(N.wear_suit,/obj/item/clothing/suit/space/space_ninja))
var/obj/item/clothing/suit/space/space_ninja/S = N.wear_suit
S:randomize_param()
/datum/game_mode/calamity/proc/spawn_vox_raiders(var/list/candidates)
//Create objectives.
var/list/raid_objectives = forge_vox_objectives()
//Create raiders.
for(var/datum/mind/player in candidates)
raiders += player
//Place them on the shuttle.
var/index = 1
if(index > raider_spawn.len)
index = 1
player.current.loc = raider_spawn[index]
index++
if(!config.objectives_disabled)
player.objectives = raid_objectives
//Equip them.
create_vox(player)
greet_vox(player)
player.current << "<b><font color='red'>Your crew is transporting cortical stacks and critical resources back to the Shoal.\
No delay or concession can be tolerated. Even putting holes in the station pales in comparison to failure.</b></font>"
spawn (rand(waittime_l, waittime_h))
send_intercept()
..()
/datum/game_mode/calamity/proc/spawn_borers(var/list/candidates)
var/list/possible_hosts = list()
for(var/mob/living/carbon/human/H in mob_list)
if(!(H.species.flags & IS_SYNTHETIC))
possible_hosts += H
for(var/datum/mind/player in candidates)
if(!possible_hosts || possible_hosts.len)
break
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)
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
var/datum/organ/external/head = target_host.get_organ("head")
head.implants += B
player.current << "\blue <b>You are a cortical borer!</b> 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 <b>say</b>, to other borers with <b>say ;</b>, 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()
show_objectives(player)
/datum/game_mode/calamity/proc/spawn_cultists(var/list/candidates)
//Prune the list.
var/list/jobs_to_skip = list("Chaplain","AI", "Cyborg", "Lawyer", "Head of Security", "Captain")
if(config.protect_roles_from_antagonist)
jobs_to_skip += list("Security Officer", "Warden", "Detective")
//Make cult objectives.
var/cult_objectives = list()
cult_objectives += new /datum/objective/cult_summon()
//Actually spawn cultists.
for(var/datum/mind/player in candidates)
for(var/job in jobs_to_skip)
if(player.assigned_role == job)
continue
cult += player
equip_cultist(player.current)
grant_runeword(player.current)
update_cult_icons_added(player)
player.current << "\blue <b>You are a member of the cult!<b> Your dark masters have sent you forth to serve their vile will."
player.current << "\red <b>This station sails above a weeping tear in the Cosmos. Bring the Geometer of Blood forth.</b>"
if(!config.objectives_disabled)
for(var/datum/objective/O in cult_objectives)
player.objectives += O
player.objectives += new /datum/objective/escape()
player.objectives += new /datum/objective/survive()
show_objectives(player)
player.special_role = "Cultist"
+1 -11
View File
@@ -125,23 +125,13 @@ var/list/possible_changeling_IDs = list("Alpha","Beta","Gamma","Delta","Epsilon"
changeling.current << "<B>\red You are a changeling!</B>"
changeling.current << "<b>\red Use say \":g message\" to communicate with your fellow changelings. Remember: you get all of their absorbed DNA if you absorb them.</b>"
if(config.objectives_disabled)
changeling.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
if (!config.objectives_disabled)
changeling.current << "<B>You must complete the following tasks:</B>"
show_objectives(changeling)
if (changeling.current.mind)
if (changeling.current.mind.assigned_role == "Clown")
changeling.current << "You have evolved beyond your clownish nature, allowing you to wield weapons without harming yourself."
changeling.current.mutations.Remove(CLUMSY)
if (!config.objectives_disabled)
var/obj_count = 1
for(var/datum/objective/objective in changeling.objectives)
changeling.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
return
/*/datum/game_mode/changeling/check_finished()
var/changelings_alive = 0
+1 -2
View File
@@ -100,8 +100,7 @@
cult_mind.current << "\blue You are a member of the cult!"
if(!config.objectives_disabled)
memorize_cult_objectives(cult_mind)
else
cult_mind.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(cult_mind)
cult_mind.special_role = "Cultist"
spawn (rand(waittime_l, waittime_h))
+6 -2
View File
@@ -35,6 +35,7 @@
desc = "A hood worn by the followers of Nar-Sie."
flags_inv = HIDEFACE
flags = FPRINT|TABLEPASS|HEADCOVERSEYES
body_parts_covered = HEAD|EYES
armor = list(melee = 30, bullet = 10, laser = 5,energy = 5, bomb = 0, bio = 0, rad = 0)
cold_protection = HEAD
min_cold_protection_temperature = SPACE_HELMET_MIN_COLD_PROTECTION_TEMPERATURE
@@ -68,6 +69,7 @@
desc = "A helm worn by the followers of Nar-Sie."
flags_inv = HIDEFACE
flags = FPRINT|TABLEPASS|HEADCOVERSEYES|HEADCOVERSMOUTH|BLOCKHAIR
body_parts_covered = HEAD|FACE|EYES
armor = list(melee = 30, bullet = 30, laser = 30,energy = 20, bomb = 0, bio = 0, rad = 0)
siemens_coefficient = 0
@@ -77,7 +79,7 @@
icon_state = "magusred"
item_state = "magusred"
flags = FPRINT | TABLEPASS
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS
allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade)
armor = list(melee = 50, bullet = 30, laser = 50,energy = 20, bomb = 25, bio = 10, rad = 0)
flags_inv = HIDEGLOVES|HIDESHOES|HIDEJUMPSUIT
@@ -91,6 +93,7 @@
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30)
siemens_coefficient = 0
/obj/item/clothing/suit/space/cult
name = "cult armour"
icon_state = "cult_armour"
@@ -100,4 +103,5 @@
allowed = list(/obj/item/weapon/book/tome,/obj/item/weapon/melee/cultblade,/obj/item/weapon/tank/emergency_oxygen,/obj/item/device/suit_cooling_unit)
slowdown = 1
armor = list(melee = 60, bullet = 50, laser = 30,energy = 15, bomb = 30, bio = 30, rad = 30)
siemens_coefficient = 0
siemens_coefficient = 0
body_parts_covered = UPPER_TORSO|LOWER_TORSO|LEGS|ARMS|HANDS
+56 -56
View File
@@ -1,57 +1,57 @@
/obj/structure/cult
density = 1
anchored = 1
icon = 'icons/obj/cult.dmi'
/obj/structure/cult/talisman
name = "Altar"
desc = "A bloodstained altar dedicated to Nar-Sie"
icon_state = "talismanaltar"
/obj/structure/cult/forge
name = "Daemon forge"
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie"
icon_state = "forge"
/obj/structure/cult/pylon
name = "Pylon"
desc = "A floating crystal that hums with an unearthly energy"
icon_state = "pylon"
luminosity = 5
/obj/structure/cult/tome
name = "Desk"
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl"
icon_state = "tomealtar"
// luminosity = 5
//sprites for this no longer exist -Pete
//(they were stolen from another game anyway)
/*
/obj/structure/cult/pillar
name = "Pillar"
desc = "This should not exist"
icon_state = "pillar"
icon = 'magic_pillar.dmi'
*/
/obj/effect/gateway
name = "gateway"
desc = "You're pretty sure that abyss is staring back"
icon = 'icons/obj/cult.dmi'
icon_state = "hole"
density = 1
unacidable = 1
anchored = 1.0
/obj/effect/gateway/Bumped(mob/M as mob|obj)
spawn(0)
return
return
/obj/effect/gateway/HasEntered(AM as mob|obj)
spawn(0)
return
/obj/structure/cult
density = 1
anchored = 1
icon = 'icons/obj/cult.dmi'
/obj/structure/cult/talisman
name = "Altar"
desc = "A bloodstained altar dedicated to Nar-Sie"
icon_state = "talismanaltar"
/obj/structure/cult/forge
name = "Daemon forge"
desc = "A forge used in crafting the unholy weapons used by the armies of Nar-Sie"
icon_state = "forge"
/obj/structure/cult/pylon
name = "Pylon"
desc = "A floating crystal that hums with an unearthly energy"
icon_state = "pylon"
luminosity = 5
/obj/structure/cult/tome
name = "Desk"
desc = "A desk covered in arcane manuscripts and tomes in unknown languages. Looking at the text makes your skin crawl"
icon_state = "tomealtar"
// luminosity = 5
//sprites for this no longer exist -Pete
//(they were stolen from another game anyway)
/*
/obj/structure/cult/pillar
name = "Pillar"
desc = "This should not exist"
icon_state = "pillar"
icon = 'magic_pillar.dmi'
*/
/obj/effect/gateway
name = "gateway"
desc = "You're pretty sure that abyss is staring back"
icon = 'icons/obj/cult.dmi'
icon_state = "hole"
density = 1
unacidable = 1
anchored = 1.0
/obj/effect/gateway/Bumped(mob/M as mob|obj)
spawn(0)
return
return
/obj/effect/gateway/Crossed(AM as mob|obj)
spawn(0)
return
return
+1 -1
View File
@@ -71,7 +71,7 @@
world << sound('sound/AI/commandreport.ogg')
// add an extra law to the AI to make sure it cooperates with the heads
var/extra_law = "Crew authorized to know of pathogen [virus_name]'s existence are: Heads of command, any crew member with loyalty implant. Do not allow unauthorized personnel to gain knowledge of [virus_name]. Aid authorized personnel in quarantining and neutrlizing the outbreak. This law overrides all other laws."
var/extra_law = "Crew authorized to know of pathogen [virus_name]'s existence are: Heads of command. Do not allow unauthorized personnel to gain knowledge of [virus_name]. Aid authorized personnel in quarantining and neutrlizing the outbreak. This law overrides all other laws."
for(var/mob/living/silicon/ai/M in world)
M.add_ion_law(extra_law)
M << "\red " + extra_law
@@ -59,5 +59,6 @@
desc = "A crappy paper hat that you are REQUIRED to wear."
flags_inv = 0
flags = FPRINT|TABLEPASS
body_parts_covered = 0
armor = list(melee = 0, bullet = 0, laser = 0,energy = 0, bomb = 0, bio = 0, rad = 0)
+5 -16
View File
@@ -315,24 +315,15 @@ ________________________________________________________________________________
var/datum/gas_mixture/environment = T.return_air()
var/pressure = environment.return_pressure()
var/total_moles = environment.total_moles()
var/total_moles = environment.total_moles
dat += "Air Pressure: [round(pressure,0.1)] kPa"
if (total_moles)
var/o2_level = environment.oxygen/total_moles
var/n2_level = environment.nitrogen/total_moles
var/co2_level = environment.carbon_dioxide/total_moles
var/phoron_level = environment.phoron/total_moles
var/unknown_level = 1-(o2_level+n2_level+co2_level+phoron_level)
dat += "<ul>"
dat += "<li>Nitrogen: [round(n2_level*100)]%</li>"
dat += "<li>Oxygen: [round(o2_level*100)]%</li>"
dat += "<li>Carbon Dioxide: [round(co2_level*100)]%</li>"
dat += "<li>Phoron: [round(phoron_level*100)]%</li>"
for(var/g in environment.gas)
dat += "<li>[gas_data.name[g]]: [round((environment.gas[g] / total_moles) * 100)]%</li>"
dat += "</ul>"
if(unknown_level > 0.01)
dat += "OTHER: [round(unknown_level)]%<br>"
dat += "Temperature: [round(environment.temperature-T0C)]&deg;C"
if(2)
@@ -1040,8 +1031,7 @@ ________________________________________________________________________________
drain = rand(G.mindrain,G.maxdrain)
var/drained = 0
if(PN&&do_after(U,10))
drained = min(drain, PN.avail)
PN.newload += drained
drained = PN.draw_power(drain)
if(drained < drain)//if no power on net, drain apcs
for(var/obj/machinery/power/terminal/T in PN.nodes)
if(istype(T.master, /obj/machinery/power/apc))
@@ -1092,8 +1082,7 @@ ________________________________________________________________________________
drain = (round((rand(G.mindrain,G.maxdrain))/2))
var/drained = 0
if(PN&&do_after(U,10))
drained = min(drain, PN.avail)
PN.newload += drained
drained = PN.draw_power(drain)
if(drained < drain)//if no power on net, drain apcs
for(var/obj/machinery/power/terminal/T in PN.nodes)
if(istype(T.master, /obj/machinery/power/apc))
+10 -40
View File
@@ -4,8 +4,12 @@
command_alert("Abnormal activity detected in [station_name()]'s powernet. As a precautionary measure, the station's power will be shut off for an indeterminate duration.", "Critical Power Failure")
for(var/mob/M in player_list)
M << sound('sound/AI/poweroff.ogg')
var/list/skipped_areas = list(/area/turret_protected/ai)
for(var/obj/machinery/power/smes/S in world)
if(istype(get_area(S), /area/turret_protected) || S.z != 1)
var/area/current_area = get_area(S)
if(current_area.type in skipped_areas || S.z != 1)
continue
S.last_charge = S.charge
S.last_output = S.output
@@ -16,43 +20,14 @@
S.updateicon()
S.power_change()
var/list/skipped_areas = list(/area/engine/engineering, /area/turret_protected/ai)
for(var/area/A in world)
if( !A.requires_power || A.always_unpowered )
continue
var/skip = 0
for(var/area_type in skipped_areas)
if(istype(A,area_type))
skip = 1
break
if(A.contents)
for(var/atom/AT in A.contents)
if(AT.z != 1) //Only check one, it's enough.
skip = 1
break
if(skip) continue
A.power_light = 0
A.power_equip = 0
A.power_environ = 0
A.power_change()
for(var/obj/machinery/power/apc/C in world)
if(C.cell && C.z == 1)
var/area/A = get_area(C)
var/skip = 0
for(var/area_type in skipped_areas)
if(istype(A,area_type))
skip = 1
break
if(skip) continue
C.cell.charge = 0
/proc/power_restore(var/announce = 1)
var/list/skipped_areas = list(/area/turret_protected/ai)
if(announce)
command_alert("Power has been restored to [station_name()]. We apologize for the inconvenience.", "Power Systems Nominal")
for(var/mob/M in player_list)
@@ -61,19 +36,14 @@
if(C.cell && C.z == 1)
C.cell.charge = C.cell.maxcharge
for(var/obj/machinery/power/smes/S in world)
if(istype(get_area(S), /area/turret_protected) || S.z != 1)
var/area/current_area = get_area(S)
if(current_area.type in skipped_areas || S.z != 1)
continue
S.charge = S.last_charge
S.output = S.last_output
S.online = S.last_online
S.updateicon()
S.power_change()
for(var/area/A in world)
if(A.name != "Space" && A.name != "Engine Walls" && A.name != "Chemical Lab Test Chamber" && A.name != "space" && A.name != "Escape Shuttle" && A.name != "Arrival Area" && A.name != "Arrival Shuttle" && A.name != "start area" && A.name != "Engine Combustion Chamber")
A.power_light = 1
A.power_equip = 1
A.power_environ = 1
A.power_change()
/proc/power_restore_quick(var/announce = 1)
+1 -6
View File
@@ -375,12 +375,7 @@ Malf AIs/silicons aren't added. Monkeys aren't added. Messes with objective comp
var/directive = generate_ninja_directive(side)
new_ninja << "\blue \nYou are an elite mercenary assassin of the Spider Clan, [new_ninja.real_name]. The dreaded \red <B>SPACE NINJA</B>!\blue You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor. Remember your training (initialize your suit by right clicking on it)! \nYour current directive is: \red <B>[directive]</B>"
new_ninja.mind.store_memory("<B>Directive:</B> \red [directive]<br>")
var/obj_count = 1
new_ninja << "\blue Your current objectives:"
for(var/datum/objective/objective in ninja_mind.objectives)
new_ninja << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
show_objectives(new_ninja.mind)
sent_ninja_to_station = 1//And we're done.
return new_ninja//Return the ninja in case we need to reference them later.
+1 -245
View File
@@ -1,247 +1,3 @@
// SPACE VINES (Note that this code is very similar to Biomass code)
/obj/effect/spacevine
name = "space vines"
desc = "An extremely expansionistic species of vine."
icon = 'icons/effects/spacevines.dmi'
icon_state = "Light1"
anchored = 1
density = 0
layer = 5
pass_flags = PASSTABLE | PASSGRILLE
var/energy = 0
var/obj/effect/spacevine_controller/master = null
var/mob/living/buckled_mob
New()
return
Del()
if(master)
master.vines -= src
master.growth_queue -= src
..()
/obj/effect/spacevine/attackby(obj/item/weapon/W as obj, mob/user as mob)
if (!W || !user || !W.type) return
switch(W.type)
if(/obj/item/weapon/circular_saw) del src
if(/obj/item/weapon/kitchen/utensil/knife) del src
if(/obj/item/weapon/scalpel) del src
if(/obj/item/weapon/twohanded/fireaxe) del src
if(/obj/item/weapon/hatchet) del src
if(/obj/item/weapon/melee/energy) del src
//less effective weapons
if(/obj/item/weapon/wirecutters)
if(prob(25)) del src
if(/obj/item/weapon/shard)
if(prob(25)) del src
else //weapons with subtypes
if(istype(W, /obj/item/weapon/melee/energy/sword)) del src
else if(istype(W, /obj/item/weapon/weldingtool))
var/obj/item/weapon/weldingtool/WT = W
if(WT.remove_fuel(0, user)) del src
else
manual_unbuckle(user)
return
//Plant-b-gone damage is handled in its entry in chemistry-reagents.dm
..()
/obj/effect/spacevine/attack_hand(mob/user as mob)
manual_unbuckle(user)
/obj/effect/spacevine/attack_paw(mob/user as mob)
manual_unbuckle(user)
/obj/effect/spacevine/proc/unbuckle()
if(buckled_mob)
if(buckled_mob.buckled == src) //this is probably unneccesary, but it doesn't hurt
buckled_mob.buckled = null
buckled_mob.anchored = initial(buckled_mob.anchored)
buckled_mob.update_canmove()
buckled_mob = null
return
/obj/effect/spacevine/proc/manual_unbuckle(mob/user as mob)
if(buckled_mob)
if(prob(50))
if(buckled_mob.buckled == src)
if(buckled_mob != user)
buckled_mob.visible_message(\
"<span class='notice'>[user.name] frees [buckled_mob.name] from the vines.</span>",\
"<span class='notice'>[user.name] frees you from the vines.</span>",\
"<span class='warning'>You hear shredding and ripping.</span>")
else
buckled_mob.visible_message(\
"<span class='notice'>[buckled_mob.name] struggles free of the vines.</span>",\
"<span class='notice'>You untangle the vines from around yourself.</span>",\
"<span class='warning'>You hear shredding and ripping.</span>")
unbuckle()
else
var/text = pick("rips","tears","pulls")
user.visible_message(\
"<span class='notice'>[user.name] [text] at the vines.</span>",\
"<span class='notice'>You [text] at the vines.</span>",\
"<span class='warning'>You hear shredding and ripping.</span>")
return
/obj/effect/spacevine_controller
var/list/obj/effect/spacevine/vines = list()
var/list/growth_queue = list()
var/reached_collapse_size
var/reached_slowdown_size
//What this does is that instead of having the grow minimum of 1, required to start growing, the minimum will be 0,
//meaning if you get the spacevines' size to something less than 20 plots, it won't grow anymore.
New()
if(!istype(src.loc,/turf/simulated/floor))
del(src)
spawn_spacevine_piece(src.loc)
processing_objects.Add(src)
Del()
processing_objects.Remove(src)
..()
proc/spawn_spacevine_piece(var/turf/location)
var/obj/effect/spacevine/SV = new(location)
growth_queue += SV
vines += SV
SV.master = src
process()
if(!vines)
del(src) //space vines exterminated. Remove the controller
return
if(!growth_queue)
del(src) //Sanity check
return
if(vines.len >= 250 && !reached_collapse_size)
reached_collapse_size = 1
if(vines.len >= 30 && !reached_slowdown_size )
reached_slowdown_size = 1
var/length = 0
if(reached_collapse_size)
length = 0
else if(reached_slowdown_size)
if(prob(25))
length = 1
else
length = 0
else
length = 1
length = min( 30 , max( length , vines.len / 5 ) )
var/i = 0
var/list/obj/effect/spacevine/queue_end = list()
for( var/obj/effect/spacevine/SV in growth_queue )
i++
queue_end += SV
growth_queue -= SV
if(SV.energy < 2) //If tile isn't fully grown
if(prob(20))
SV.grow()
else //If tile is fully grown
SV.buckle_mob()
//if(prob(25))
SV.spread()
if(i >= length)
break
growth_queue = growth_queue + queue_end
//sleep(5)
//src.process()
/obj/effect/spacevine/proc/grow()
if(!energy)
src.icon_state = pick("Med1", "Med2", "Med3")
energy = 1
src.opacity = 1
layer = 5
else
src.icon_state = pick("Hvy1", "Hvy2", "Hvy3")
energy = 2
/obj/effect/spacevine/proc/buckle_mob()
if(!buckled_mob && prob(25))
for(var/mob/living/carbon/V in src.loc)
if((V.stat != DEAD) && (V.buckled != src)) //if mob not dead or captured
V.buckled = src
V.loc = src.loc
V.update_canmove()
src.buckled_mob = V
V << "<span class='danger'>The vines [pick("wind", "tangle", "tighten")] around you!</span>"
break //only capture one mob at a time.
/obj/effect/spacevine/proc/spread()
var/direction = pick(cardinal)
var/step = get_step(src,direction)
if(istype(step,/turf/simulated/floor))
var/turf/simulated/floor/F = step
if(!locate(/obj/effect/spacevine,F))
if(F.Enter(src))
if(master)
master.spawn_spacevine_piece( F )
/*
/obj/effect/spacevine/proc/Life()
if (!src) return
var/Vspread
if (prob(50)) Vspread = locate(src.x + rand(-1,1),src.y,src.z)
else Vspread = locate(src.x,src.y + rand(-1, 1),src.z)
var/dogrowth = 1
if (!istype(Vspread, /turf/simulated/floor)) dogrowth = 0
for(var/obj/O in Vspread)
if (istype(O, /obj/structure/window) || istype(O, /obj/effect/forcefield) || istype(O, /obj/effect/blob) || istype(O, /obj/effect/alien/weeds) || istype(O, /obj/effect/spacevine)) dogrowth = 0
if (istype(O, /obj/machinery/door/))
if(O:p_open == 0 && prob(50)) O:open()
else dogrowth = 0
if (dogrowth == 1)
var/obj/effect/spacevine/B = new /obj/effect/spacevine(Vspread)
B.icon_state = pick("vine-light1", "vine-light2", "vine-light3")
spawn(20)
if(B)
B.Life()
src.growth += 1
if (src.growth == 10)
src.name = "Thick Space Kudzu"
src.icon_state = pick("vine-med1", "vine-med2", "vine-med3")
src.opacity = 1
src.waittime = 80
if (src.growth == 20)
src.name = "Dense Space Kudzu"
src.icon_state = pick("vine-hvy1", "vine-hvy2", "vine-hvy3")
src.density = 1
spawn(src.waittime)
if (src.growth < 20) src.Life()
*/
/obj/effect/spacevine/ex_act(severity)
switch(severity)
if(1.0)
del(src)
return
if(2.0)
if (prob(90))
del(src)
return
if(3.0)
if (prob(50))
del(src)
return
return
/obj/effect/spacevine/fire_act(null, temp, volume) //hotspots kill vines
del src
//Carn: Spacevines random event.
/proc/spacevine_infestation()
@@ -256,5 +12,5 @@
if(turfs.len) //Pick a turf to spawn at if we can
var/turf/simulated/floor/T = pick(turfs)
new/obj/effect/spacevine_controller(T) //spawn a controller at turf
new/obj/effect/plant_controller(T) //spawn a controller at turf
message_admins("\blue Event: Spacevines spawned at [T.loc] ([T.x],[T.y],[T.z])")
+25
View File
@@ -481,3 +481,28 @@ proc/get_nt_opposed()
dudes += man
if(dudes.len == 0) return null
return pick(dudes)
//Announces objectives/generic antag text.
/proc/show_generic_antag_text(var/datum/mind/player)
if(player.current)
player.current << \
"You are an antagonist! <font color=blue>Within the rules,</font> \
try to act as an opposing force to the crew. Further RP and try to make sure \
other players have <i>fun</i>! If you are confused or at a loss, always adminhelp, \
and before taking extreme actions, please try to also contact the administration! \
Think through your actions and make the roleplay immersive! <b>Please remember all \
rules aside from those without explicit exceptions apply to antagonists.</b>"
/proc/show_objectives(var/datum/mind/player)
if(!player || !player.current) return
if(config.objectives_disabled)
show_generic_antag_text(player)
return
var/obj_count = 1
player.current << "\blue Your current objectives:"
for(var/datum/objective/objective in player.objectives)
player.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
+1
View File
@@ -297,6 +297,7 @@ var/global/datum/controller/gameticker/ticker
captainless=0
if(player.mind.assigned_role != "MODE")
job_master.EquipRank(player, player.mind.assigned_role, 0)
UpdateFactionList(player)
EquipCustomItems(player)
if(captainless)
for(var/mob/M in player_list)
+56 -63
View File
@@ -2,8 +2,12 @@
VOX HEIST ROUNDTYPE
*/
var/global/list/raider_spawn = list()
var/global/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective. Clumsy, rewrite sometime.
/datum/game_mode/
var/list/datum/mind/raiders = list() //Antags.
var/list/raid_objectives = list() //Raid objectives
/datum/game_mode/heist
name = "heist"
@@ -16,9 +20,6 @@ VOX HEIST ROUNDTYPE
var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds)
var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)
var/list/raid_objectives = list() //Raid objectives.
var/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective.
/datum/game_mode/heist/announce()
world << "<B>The current game mode is - Heist!</B>"
world << "<B>An unidentified bluespace signature has slipped past the Icarus and is approaching [station_name()]!</B>"
@@ -59,15 +60,6 @@ VOX HEIST ROUNDTYPE
/datum/game_mode/heist/post_setup()
//Build a list of spawn points.
var/list/turf/raider_spawn = list()
for(var/obj/effect/landmark/L in landmarks_list)
if(L.name == "voxstart")
raider_spawn += get_turf(L)
del(L)
continue
//Generate objectives for the group.
if(!config.objectives_disabled)
raid_objectives = forge_vox_objectives()
@@ -83,49 +75,57 @@ VOX HEIST ROUNDTYPE
raider.current.loc = raider_spawn[index]
index++
var/sounds = rand(2,8)
var/i = 0
var/newname = ""
while(i<=sounds)
i++
newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah"))
var/mob/living/carbon/human/vox = raider.current
vox.real_name = capitalize(newname)
vox.name = vox.real_name
raider.name = vox.name
vox.age = rand(12,20)
vox.dna.mutantrace = "vox"
vox.set_species("Vox")
vox.languages = list() // Removing language from chargen.
vox.flavor_text = ""
vox.add_language("Vox-pidgin")
vox.h_style = "Short Vox Quills"
vox.f_style = "Shaved"
for(var/datum/organ/external/limb in vox.organs)
limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT)
//Now apply cortical stack.
var/datum/organ/external/E = vox.get_organ("head")
var/obj/item/weapon/implant/cortical/I = new(vox)
I.imp_in = vox
I.implanted = 1
I.part = E
E.implants += I
cortical_stacks += I
vox.equip_vox_raider()
vox.regenerate_icons()
raider.objectives = raid_objectives
create_vox(raider)
greet_vox(raider)
if(!config.objectives_disabled && raid_objectives)
raider.objectives = raid_objectives
spawn (rand(waittime_l, waittime_h))
send_intercept()
/datum/game_mode/heist/proc/is_raider_crew_safe()
/datum/game_mode/proc/create_vox(var/datum/mind/newraider)
var/sounds = rand(2,8)
var/i = 0
var/newname = ""
while(i<=sounds)
i++
newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah"))
var/mob/living/carbon/human/vox = newraider.current
vox.real_name = capitalize(newname)
vox.name = vox.real_name
newraider.name = vox.name
vox.age = rand(12,20)
vox.dna.mutantrace = "vox"
vox.set_species("Vox")
vox.languages = list() // Removing language from chargen.
vox.flavor_text = ""
vox.add_language("Vox-pidgin")
vox.h_style = "Short Vox Quills"
vox.f_style = "Shaved"
for(var/datum/organ/external/limb in vox.organs)
limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT)
//Generate cortical stack.
var/datum/organ/external/affected = vox.get_organ("head")
var/obj/item/weapon/implant/cortical/I = new(vox)
I.imp_in = vox
I.implanted = 1
affected.implants += I
I.part = affected
cortical_stacks += I
vox.equip_vox_raider()
vox.regenerate_icons()
/datum/game_mode/proc/is_raider_crew_safe()
if(cortical_stacks.len == 0)
return 0
@@ -135,7 +135,7 @@ VOX HEIST ROUNDTYPE
return 0
return 1
/datum/game_mode/heist/proc/is_raider_crew_alive()
/datum/game_mode/proc/is_raider_crew_alive()
for(var/datum/mind/raider in raiders)
if(raider.current)
@@ -143,7 +143,7 @@ VOX HEIST ROUNDTYPE
return 1
return 0
/datum/game_mode/heist/proc/forge_vox_objectives()
/datum/game_mode/proc/forge_vox_objectives()
var/i = 1
var/max_objectives = pick(2,2,2,2,3,3,3,4)
@@ -171,20 +171,13 @@ VOX HEIST ROUNDTYPE
return objs
/datum/game_mode/heist/proc/greet_vox(var/datum/mind/raider)
/datum/game_mode/proc/greet_vox(var/datum/mind/raider)
raider.current << "\blue <B>You are a Vox Raider, fresh from the Shoal!</b>"
raider.current << "\blue The Vox are a race of cunning, sharp-eyed nomadic raiders and traders endemic to the frontier and much of the unexplored galaxy. You and the crew have come to the Exodus for plunder, trade or both."
raider.current << "\blue Vox are cowardly and will flee from larger groups, but corner one or find them en masse and they are vicious."
raider.current << "\blue Use :V to voxtalk, :H to talk on your encrypted channel, and don't forget to turn on your nitrogen internals!"
raider.current << "\red IF YOU HAVE NOT PLAYED A VOX BEFORE, REVIEW THIS THREAD: http://baystation12.net/forums/viewtopic.php?f=6&t=8657."
var/obj_count = 1
if(!config.objectives_disabled)
for(var/datum/objective/objective in raider.objectives)
raider.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
else
raider.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew or come up with other fun ideas. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(raider)
/datum/game_mode/heist/declare_completion()
@@ -292,6 +285,6 @@ datum/game_mode/proc/auto_declare_completion_heist()
var/area/skipjack = locate(/area/shuttle/vox/station)
for (var/mob/living/M in skipjack.contents)
//maybe send the player a message that they've gone home/been kidnapped? Someone responsible for vox lore should write that.
Del(M)
del(M)
for (var/obj/O in skipjack.contents)
Del(O) //no hiding in lockers or anything
del(O) //no hiding in lockers or anything
+1 -5
View File
@@ -131,11 +131,7 @@
/datum/game_mode/proc/greet_meme(var/datum/mind/meme, var/you_are=1)
if (you_are)
meme.current << "<B>\red You are a meme!</B>"
var/obj_count = 1
for(var/datum/objective/objective in meme.objectives)
meme.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
show_objectives(meme)
return
/datum/game_mode/meme/check_finished()
+3 -7
View File
@@ -56,8 +56,8 @@
if(ninja.current && !(istype(ninja.current,/mob/living/carbon/human))) return 0
if(!config.objectives_disabled)
forge_ninja_objectives(ninja)
else
ninja.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(ninja)
var/mob/living/carbon/human/N = ninja.current
N.internal = N.s_store
N.internals.icon_state = "internal1"
@@ -139,11 +139,7 @@
ninja.current << "You are an elite mercenary assassin of the Spider Clan, [ninja.current.real_name]. You have a variety of abilities at your disposal, thanks to your nano-enhanced cyber armor.\nYour current directive is: \red <B>[directive]</B>\n \blue Try your best to adhere to this."
ninja.store_memory("<B>Directive:</B> \red [directive]<br>")
var/obj_count = 1
ninja.current << "\blue Your current objectives:"
for(var/datum/objective/objective in ninja.objectives)
ninja.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
show_objectives(ninja)
/datum/game_mode/proc/auto_declare_completion_ninja()
if(ninjas.len)
+21 -26
View File
@@ -1,3 +1,10 @@
/*
NUCLEAR EMERGENCY ROUNDTYPE
*/
var/global/list/turf/synd_spawn = list()
/datum/game_mode
var/list/datum/mind/syndicates = list()
@@ -116,15 +123,7 @@
/datum/game_mode/nuclear/post_setup()
var/list/turf/synd_spawn = list()
for(var/obj/effect/landmark/A in landmarks_list)
if(A.name == "Syndicate-Spawn")
synd_spawn += get_turf(A)
del(A)
continue
var/obj/effect/landmark/uplinklocker = locate("landmark*Syndicate-Uplink") //i will be rewriting this shortly
var/obj/effect/landmark/uplinkdevice = locate("landmark*Syndicate-Uplink") //i will be rewriting this shortly
var/obj/effect/landmark/nuke_spawn = locate("landmark*Nuclear-Bomb")
var/nuke_code = "[rand(10000, 99999)]"
@@ -139,8 +138,8 @@
synd_mind.current.real_name = "[syndicate_name()] Operative" // placeholder while we get their actual name
spawn(0)
NukeNameAssign(synd_mind)
if(!config.objectives_disabled)
forge_syndicate_objectives(synd_mind)
forge_syndicate_objectives(synd_mind)
greet_syndicate(synd_mind)
equip_syndicate(synd_mind.current)
@@ -153,8 +152,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
@@ -166,6 +166,7 @@
/datum/game_mode/proc/prepare_syndicate_leader(var/datum/mind/synd_mind, var/nuke_code)
var/obj/effect/landmark/code_spawn = locate("landmark*Nuclear-Code")
if (nuke_code)
synd_mind.store_memory("<B>Syndicate Nuclear Bomb Code</B>: [nuke_code]", 0, 0)
synd_mind.current << "The nuclear authorization code is: <B>[nuke_code]</B>"
@@ -173,7 +174,7 @@
P.info = "The nuclear authorization code is: <b>[nuke_code]</b>"
P.name = "nuclear bomb code"
if (ticker.mode.config_tag=="nuclear")
P.loc = synd_mind.current.loc
P.loc = code_spawn.loc
else
var/mob/living/carbon/human/H = synd_mind.current
P.loc = H.loc
@@ -186,25 +187,18 @@
/datum/game_mode/proc/forge_syndicate_objectives(var/datum/mind/syndicate)
if (config.objectives_disabled)
return
var/datum/objective/nuclear/syndobj = new
syndobj.owner = syndicate
syndicate.objectives += syndobj
/datum/game_mode/proc/greet_syndicate(var/datum/mind/syndicate, var/you_are=1)
if (you_are)
syndicate.current << "\blue You are a [syndicate_name()] agent!"
var/obj_count = 1
if(!config.objectives_disabled)
for(var/datum/objective/objective in syndicate.objectives)
syndicate.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
else
syndicate.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
return
show_objectives(syndicate)
/datum/game_mode/proc/random_radio_frequency()
return 1337 // WHY??? -- Doohl
@@ -230,6 +224,7 @@
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)
/* 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)
var/obj/item/clothing/head/helmet/space/rig/syndi/new_helmet = new(synd_mob)
@@ -245,8 +240,8 @@
if("Skrell")
new_suit.species_restricted = list("Skrell")
synd_mob.equip_to_slot_or_del(new_suit, slot_wear_suit)
synd_mob.equip_to_slot_or_del(new_helmet, slot_head)
synd_mob.equip_to_slot_or_del(new_suit, slot_in_backpack)
synd_mob.equip_to_slot_or_del(new_helmet, slot_in_backpack)*/
// var/obj/item/weapon/implant/explosive/E = new/obj/item/weapon/implant/explosive(synd_mob)
// E.imp_in = synd_mob
+40 -2
View File
@@ -557,7 +557,7 @@ datum/objective/steal
for(var/obj/item/I in all_items) //Check for phoron tanks
if(istype(I, steal_target))
found_amount += (target_name=="28 moles of phoron (full tank)" ? (I:air_contents:phoron) : (I:amount))
found_amount += (target_name=="28 moles of phoron (full tank)" ? (I:air_contents:gas["phoron"]) : (I:amount))
return found_amount>=target_amount
if("50 coins (in bag)")
@@ -930,4 +930,42 @@ datum/objective/heist/inviolate_death
explanation_text = "Follow the Inviolate. Minimise death and loss of resources."
check_completion()
if(vox_kills > MAX_VOX_KILLS) return 0
return 1
return 1
//Borer objective(s).
/datum/objective/borer_survive
explanation_text = "Survive in a host until the end of the round."
/datum/objective/borer_survive/check_completion()
if(owner)
var/mob/living/simple_animal/borer/B = owner
if(istype(B) && B.stat < 2 && B.host && B.host.stat < 2) return 1
return 0
/datum/objective/borer_reproduce
explanation_text = "Reproduce at least once."
/datum/objective/borer_reproduce/check_completion()
if(owner && owner.current)
var/mob/living/simple_animal/borer/B = owner.current
if(istype(B) && B.has_reproduced) return 1
return 0
/datum/objective/ninja_highlander
explanation_text = "You aspire to be a Grand Master of the Spider Clan. Kill all of your fellow acolytes."
/datum/objective/ninja_highlander/check_completion()
if(owner)
for(var/datum/mind/ninja in ticker.mode.ninjas)
if(ninja != owner)
if(ninja.current.stat < 2) return 0
return 1
return 0
/datum/objective/cult_summon
explanation_text = "Summon Nar-Sie via the use of the appropriate rune (Hell join self). It will only work if nine cultists stand on and around it."
/datum/objective/cult_summon/check_completion()
if(locate(/obj/machinery/singularity/narsie/large) in machines) return 1
return 0
+6 -10
View File
@@ -118,16 +118,13 @@
rev_mind.objectives += rev_obj
/datum/game_mode/proc/greet_revolutionary(var/datum/mind/rev_mind, var/you_are=1)
var/obj_count = 1
rev_mind.special_role = "Head Revolutionary"
if (you_are)
rev_mind.current << "\blue You are a member of the revolutionaries' leadership!"
if(!config.objectives_disabled)
for(var/datum/objective/objective in rev_mind.objectives)
rev_mind.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
rev_mind.special_role = "Head Revolutionary"
obj_count++
else
rev_mind.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(rev_mind)
/////////////////////////////////////////////////////////////////////////////////
//This are equips the rev heads with their gear, and makes the clown not clumsy//
@@ -198,8 +195,7 @@
revolutionaries += rev_mind
rev_mind.current << "\red <FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill the heads to win the revolution!</FONT>"
rev_mind.special_role = "Revolutionary"
if(config.objectives_disabled)
rev_mind.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(rev_mind)
update_rev_icons_added(rev_mind)
return 1
//////////////////////////////////////////////////////////////////////////////
@@ -87,11 +87,8 @@
update_rev_icons_added(rev_mind)
for(var/datum/mind/rev_mind in head_revolutionaries)
var/obj_count = 1
rev_mind.current << "\blue You are a member of the revolutionaries' leadership!"
for(var/datum/objective/objective in rev_mind.objectives)
rev_mind.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
show_objectives(rev_mind)
spawn (rand(waittime_l, waittime_h))
send_intercept()
@@ -78,16 +78,10 @@
send_intercept()
/datum/game_mode/revolution/rp_revolution/greet_revolutionary(var/datum/mind/rev_mind, var/you_are=1)
var/obj_count = 1
rev_mind.special_role = "Head Revolutionary"
if (you_are)
rev_mind.current << "\blue You are a member of the revolutionaries' leadership!"
if(!config.objectives_disabled)
for(var/datum/objective/objective in rev_mind.objectives)
rev_mind.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
rev_mind.special_role = "Head Revolutionary"
obj_count++
else
rev_mind.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(rev_mind)
// Show each head revolutionary up to 3 candidates
var/list/already_considered = list()
@@ -113,8 +107,7 @@
revolutionaries += rev_mind
rev_mind.current << "\red <FONT size = 3> You are now a revolutionary! Help your cause. Do not harm your fellow freedom fighters. You can identify your comrades by the red \"R\" icons, and your leaders by the blue \"R\" icons. Help them kill, capture or convert the heads to win the revolution!</FONT>"
rev_mind.special_role = "Revolutionary"
if(config.objectives_disabled)
rev_mind.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
show_objectives(rev_mind)
update_rev_icons_added(rev_mind)
H.hud_updateflag |= 1 << SPECIALROLE_HUD
return 1
+1 -8
View File
@@ -135,14 +135,7 @@
/datum/game_mode/proc/greet_traitor(var/datum/mind/traitor)
traitor.current << "<B><font size=3 color=red>You are the traitor.</font></B>"
if (!config.objectives_disabled)
var/obj_count = 1
for(var/datum/objective/objective in traitor.objectives)
traitor.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
else
traitor.current << "<i>You have been selected this round as an antagonist- <font color=blue>Within the rules,</font> try to act as an opposing force to the crew- This can be via corporate payoff, personal motives, or maybe just being a dick. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonist.</i></b>"
return
show_objectives(traitor)
/datum/game_mode/proc/finalize_traitor(var/datum/mind/traitor)
+2 -4
View File
@@ -13,10 +13,8 @@
survive.owner = H.mind
H.mind.objectives += survive
H << "<B>You are the survivor! Your own safety matters above all else, trust no one and kill anyone who gets in your way. However, armed as you are, now would be the perfect time to settle that score or grab that pair of yellow gloves you've been eyeing...</B>"
var/obj_count = 1
for(var/datum/objective/OBJ in H.mind.objectives)
H << "<B>Objective #[obj_count]</B>: [OBJ.explanation_text]"
obj_count++
show_objectives(H.mind)
var/randomize = pick("taser","egun","laser","revolver","detective","smg","nuclear","deagle","gyrojet","pulse","silenced","cannon","doublebarrel","shotgun","combatshotgun","mateba","smg","uzi","crossbow","saw")
switch (randomize)
if("taser")
+1 -10
View File
@@ -135,16 +135,7 @@
/datum/game_mode/proc/greet_wizard(var/datum/mind/wizard, var/you_are=1)
if (you_are)
wizard.current << "<B>\red You are the Space Wizard!</B>"
wizard.current << "<B>The Space Wizards Federation has given you the following tasks:</B>"
if(!config.objectives_disabled)
var/obj_count = 1
for(var/datum/objective/objective in wizard.objectives)
wizard.current << "<B>Objective #[obj_count]</B>: [objective.explanation_text]"
obj_count++
else
wizard.current << "<font color=blue>Within the rules,</font> try to act as an opposing force to the crew. Further RP and try to make sure other players have </i>fun<i>! If you are confused or at a loss, always adminhelp, and before taking extreme actions, please try to also contact the administration! Think through your actions and make the roleplay immersive! <b>Please remember all rules aside from those without explicit exceptions apply to antagonists.</i></b>"
return
show_objectives(wizard)
/*/datum/game_mode/proc/learn_basic_spells(mob/living/carbon/human/wizard_mob)
if (!istype(wizard_mob))

Some files were not shown because too many files have changed in this diff Show More