diff --git a/main-src/Code/!atoms.dm b/main-src/Code/!atoms.dm index 1aa0299..b4e8716 100644 --- a/main-src/Code/!atoms.dm +++ b/main-src/Code/!atoms.dm @@ -31,7 +31,7 @@ #define DRIVABLE 64 // fireable by mass driver #define ONBELT 128 // can be put in belt slot #define FPRINT 256 // takes a fingerprint -#define WINDOW 512 // window or window/door +#define WINDOW 512 // window or window/door (or injector) // channel numbers for power @@ -628,9 +628,10 @@ name = "smoke" icon = 'water.dmi' icon_state = "smoke" - opacity = 1 - var/amount = 6.0 + opacity = 0 + var/amount = 6 anchored = 0.0 + weight = 100 /obj/effects/sparks name = "sparks" icon = 'water.dmi' @@ -649,6 +650,7 @@ var/life = 15.0 flags = 2.0 mouse_opacity = 0 + weight = 1000 /obj/equip_e name = "equip e" var/mob/source = null @@ -1822,6 +1824,17 @@ Total SMES charging rate should not exceed total power generation rate, or an ov /obj/item/weapon/pill_canister/sleep desc = "Sleeping Pills\nAdminister as required to calm person.\nCauses 10 minutes of drowsyness. MAY induce immediate sleep.\nWARNING: Neurodepressant! Do not overdose!\nWarning: Causes drowsiness!If drowsyness persists for over 15 minutes contact medical professional." name = "Pill Canister- 'Sleeping Pills'" + +/obj/item/weapon/pipe + name = "pipe" + icon = 'pipe-item.dmi' + icon_state = "straight" + var/ptype = 0 + flags = TABLEPASS|DRIVABLE|FPRINT + w_class = 4 + s_istate = "pipe" + level = 2 + /obj/item/weapon/prox_sensor name = "Proximity Sensor" icon_state = "motion0" @@ -2195,187 +2208,9 @@ Total SMES charging rate should not exceed total power generation rate, or an ov anchored = 1.0 -/obj/machinery - name = "machinery" - var/p_dir = 0 - var/h_dir = 0 // used for heat-exchange - var/capmult = 0 - var/stat = 0 -/obj/machinery/alarm - name = "alarm" - icon = 'stationobjs.dmi' - icon_state = "alarm:0" - anchored = 1.0 -/obj/machinery/alarm/indicator - name = "indicator" - icon = 'airtunnel.dmi' - icon_state = "indicator" -/obj/machinery/at_indicator - name = "Air Tunnel Indicator" - icon = 'airtunnel.dmi' - icon_state = "reader00" - anchored = 1.0 -/obj/machinery/atmoalter - name = "atmoalter" - var/obj/substance/gas/gas = null - var/maximum - var/t_status - var/t_per - var/c_per - var/c_status - var/obj/item/weapon/tank/holding - var/max_valve = 1e6 -/obj/machinery/atmoalter/canister - name = "canister" - icon = 'canister.dmi' - density = 1 - maximum = 1.3E8 - var/color = "blue" - t_status = 3.0 - t_per = 50.0 - c_per = 50.0 - c_status = 0.0 - holding = null - var/health = 20.0 - var/destroyed = null - flags = 320.0 - weight = 1.0E7 - var/filled = 1 //fractional fullness at spawn -/obj/machinery/atmoalter/canister/anesthcanister - name = "Canister: \[N2O\]" - icon_state = "redws" - color = "redws" -/obj/machinery/atmoalter/canister/n2canister - name = "Canister: \[N2\]" - icon_state = "red" - color = "red" -/obj/machinery/atmoalter/canister/oxygencanister - name = "Canister: \[O2\]" - icon_state = "blue" -/obj/machinery/atmoalter/canister/poisoncanister - name = "Canister \[Plasma (Bio)\]" - icon_state = "orange" - color = "orange" -/obj/machinery/atmoalter/canister/co2canister - name = "Canister \[CO2\]" - icon_state = "black" - color = "black" -/obj/machinery/atmoalter/canister/aircanister - name = "Canister \[Air\]" - icon_state = "grey" - color = "grey" -/obj/machinery/atmoalter/heater - name = "heater" - icon = 'stationobjs.dmi' - icon_state = "heater1" - density = 1 - maximum = 1.3E8 - t_status = 3.0 - var/h_status = 0.0 - t_per = 50.0 - var/h_tar = 20.0 - c_per = 50.0 - c_status = 0.0 - holding = null - anchored = 1.0 - var/heatrate = 1500000.0 -/obj/machinery/atmoalter/siphs - name = "siphs" - density = 1 - var/alterable = 1.0 - var/f_time = 1.0 - var/location = null - maximum = 1.3E8 - holding = null - t_status = 3.0 - t_per = 50.0 - c_per = 50.0 - c_status = 0.0 - weight = 1.0E7 - anchored = 1.0 - var/empty = null -/obj/machinery/atmoalter/siphs/fullairsiphon - name = "Air siphon" - icon = 'turfs.dmi' - icon_state = "siphon:0" -/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent - name = "Air regulator" - icon = 'aircontrol.dmi' - icon_state = "vent2" - t_status = 4.0 - alterable = 0.0 - density = 0 //***** -/obj/machinery/atmoalter/siphs/fullairsiphon/port - name = "Portable Siphon" - icon = 'stationobjs.dmi' - flags = 320.0 - anchored = 0.0 -/obj/machinery/atmoalter/siphs/scrubbers - name = "scrubbers" - icon = 'turfs2.dmi' - icon_state = "siphon:0" -/obj/machinery/atmoalter/siphs/scrubbers/air_filter - name = "air filter" - icon = 'aircontrol.dmi' - icon_state = "vent2" - t_status = 4.0 - alterable = 0.0 - density = 0 //***** -/obj/machinery/atmoalter/siphs/scrubbers/port - name = "Portable Siphon" - icon = 'stationobjs.dmi' - icon_state = "scrubber:0" - flags = 320.0 - anchored = 0.0 -/obj/machinery/autolathe - name = "Autolathe" - icon = 'stationobjs.dmi' - icon_state = "autolathe" - var/m_amount = 0.0 - var/g_amount = 0.0 - var/operating = 0.0 - var/opened = 0.0 - var/temp = null - anchored = 1.0 -/obj/machinery/camera - name = "Security Camera" - icon = 'stationobjs.dmi' - icon_state = "camera" - var/network = "SS13" - var/c_tag = null - var/status = 1.0 - anchored = 1.0 - var/invuln = null - -/obj/machinery/circulator - name = "circulator/heat exchanger" - desc = "A gas circulator pump and heat exchanger." - icon = 'pipes.dmi' - icon_state = "circ1-off" - p_dir = 3 // N & S - var/side = 1 // 1=left 2=right - var/status = 0 - var/rate = 1000000 - var/obj/substance/gas/gas1 = null - var/obj/substance/gas/ngas1 = null - var/obj/substance/gas/gas2 = null - var/obj/substance/gas/ngas2 = null - - var/capacity = 6000000.0 - var/obj/machinery/node1 = null - var/obj/machinery/node2 = null - - var/obj/machinery/vnode1 - var/obj/machinery/vnode2 - - anchored = 1.0 - density = 1 - capmult = 1 - - //var/obj/machinery/power/teg/master = null /obj/machinery/computer name = "computer" @@ -2523,55 +2358,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov var/locked = null var/id = null -/obj/machinery/connector - name = "connector" - icon = 'pipes.dmi' - desc = "A connector for gas canisters." - icon_state = "connector" - anchored = 1.0 - p_dir = 2 - var/obj/machinery/node = null - var/obj/machinery/atmoalter/connected = null - var/obj/machinery/vnode = null - - var/obj/substance/gas/gas = null - var/obj/substance/gas/ngas = null - - //var/obj/substance/gas/agas - - var/capacity = 6000000.0 - capmult = 2 - var/flag = 0 - -/obj/machinery/inlet - name = "inlet" - icon = 'pipes.dmi' - icon_state = "inlet" - desc = "A gas pipe inlet." - anchored = 1 - p_dir = 2 - var/obj/machinery/node - var/obj/machinery/vnode - var/obj/substance/gas/gas - var/obj/substance/gas/ngas - var/capacity = 6000000 - capmult = 2 - - -/obj/machinery/vent - name = "vent" - icon = 'pipes.dmi' - icon_state = "vent" - desc = "A gas pipe outlet vent." - anchored = 1 - p_dir = 2 - var/obj/machinery/node - var/obj/machinery/vnode - var/obj/substance/gas/gas - var/obj/substance/gas/ngas - var/capacity = 6000000 - capmult = 2 /obj/machinery/cryo_cell @@ -2592,15 +2379,6 @@ Total SMES charging rate should not exceed total power generation rate, or an ov var/obj/machinery/vnode = null -/obj/machinery/dispenser - desc = "A simple yet bulky one-way storage device for gas tanks. Holds 10 plasma and 10 oxygen tanks." - name = "Tank Storage Unit" - icon = 'turfs2.dmi' - icon_state = "dispenser" - density = 1 - var/o2tanks = 10.0 - var/pltanks = 10.0 - anchored = 1.0 /obj/machinery/dna_scanner name = "DNA Scanner/Implanter" icon = 'Cryogenic2.dmi' @@ -2654,15 +2432,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov visible = 0.0 flags = 512.0 opacity = 0 -/obj/machinery/firealarm - name = "firealarm" - icon = 'items.dmi' - icon_state = "firealarm" - var/detecting = 1.0 - var/working = 1.0 - var/time = 10.0 - var/timing = 0.0 - anchored = 1.0 + /obj/machinery/freezer name = "freezer" icon = 'Cryogenic2.dmi' @@ -2683,13 +2453,6 @@ Total SMES charging rate should not exceed total power generation rate, or an ov anchored = 1.0 capmult = 1 -/obj/machinery/gas_sensor - name = "gas sensor" - icon = 'stationobjs.dmi' - icon_state = "gsensor" - desc = "A remote sensor for atmospheric gas composition." - var/id - anchored = 1 /obj/machinery/hologram_proj name = "Hologram Projector" @@ -2697,19 +2460,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov icon_state = "hologram0" var/atom/projection = null anchored = 1.0 -/obj/machinery/igniter - name = "igniter" - icon = 'stationobjs.dmi' - icon_state = "igniter1" - var/on = 1.0 - anchored = 1.0 -/obj/machinery/injector - name = "injector" - icon = 'stationobjs.dmi' - icon_state = "injector" - density = 1 - anchored = 1.0 - flags = 512.0 + /obj/machinery/mass_driver name = "mass driver" icon = 'stationobjs.dmi' @@ -2740,123 +2491,12 @@ Total SMES charging rate should not exceed total power generation rate, or an ov var/safety = 1.0 var/obj/item/weapon/disk/nuclear/auth = null flags = 320.0 -/obj/machinery/valve - name = "valve" - icon = 'pipes.dmi' - icon_state = "valve0" - desc = "A gas valve." - var/obj/substance/gas/gas1 = null - var/obj/substance/gas/ngas1 = null - var/obj/substance/gas/gas2 = null - var/obj/substance/gas/ngas2 = null - var/capacity = 6000000.0 - var/obj/machinery/node1 = null - var/obj/machinery/node2 = null - var/obj/machinery/vnode1 = null - var/obj/machinery/vnode2 = null - var/id = "v1" - var/open = 0 - anchored = 1.0 - capmult = 2 - -/obj/machinery/manifold - name = "manifold" - icon = 'pipes.dmi' - icon_state = "manifold" - desc = "A three-port gas manifold." - anchored = 1 - dir = 2 - p_dir = 14 - var/n1dir - var/n2dir - - var/obj/substance/gas/gas = null - var/obj/substance/gas/ngas = null - var/capacity = 6000000.0 - var/obj/machinery/node1 = null - var/obj/machinery/node2 = null - var/obj/machinery/node3 = null - - var/obj/machinery/vnode1 - var/obj/machinery/vnode2 - var/obj/machinery/vnode3 - - - capmult = 3 - - -/obj/machinery/junction - name = "junction" - icon = 'junct-pipe.dmi' - icon_state = "junction" - desc = "A junction between regular and heat-exchanger pipework." - var/capacity = 6000000 - anchored = 1 - dir = 2 - p_dir = 3 - - var/obj/substance/gas/gas = null - var/obj/substance/gas/ngas = null - var/obj/machinery/node1 = null - var/obj/machinery/node2 = null - - var/obj/machinery/vnode1 - var/obj/machinery/vnode2 - - capmult = 2 - - -/obj/machinery/pipes - name = "pipes" - icon = 'reg_pipe.dmi' - icon_state = "12" - var/capacity = 6000000.0 - var/obj/machinery/node1 = null - var/obj/machinery/node2 = null - anchored = 1.0 - var/termination = 0 - var/insulation = NORMPIPERATE - var/plnum = 0 - var/obj/machinery/pipeline/pl -/obj/machinery/pipeline // virtual pipeline consisting of multiple /obj/machinery/pipes - - name = "pipeline" - var/list/nodes = list() - var/numnodes = 0 - var/obj/substance/gas/gas = null - var/obj/substance/gas/ngas = null - - var/obj/machinery/vnode1 - var/obj/machinery/vnode2 - - invisibility = 101 - capmult = 0 - var/flow = 0 -/obj/machinery/pipes/flexipipe - desc = "Flexible hose-like piping." - name = "flexipipe" - icon = 'wire.dmi' - capacity = 10.0 - p_dir = 12.0 -/obj/machinery/pipes/high_capacity - desc = "A large bore pipe with high capacity." - name = "high capacity" - icon = 'hi_pipe.dmi' - density = 1 - capacity = 1.8E7 -/obj/machinery/pipes/regular - desc = "A stretch of pipe." - name = "normal pipe" -/obj/machinery/pipes/heat_exch - icon = 'heat_pipe.dmi' - name = "heat exchange pipe" - desc = "A bundle of small pipes designed for maximum heat transfer." - insulation = HEATPIPERATE + /obj/machinery/pod name = "Escape Pod" @@ -2867,7 +2507,7 @@ Total SMES charging rate should not exceed total power generation rate, or an ov var/speed = 10.0 var/capacity = null flags = 320.0 - anchored = 1.0 + anchored = 1.0 /obj/machinery/recon name = "1-Person Reconaissance Pod" icon = 'escapepod.dmi' @@ -2901,26 +2541,9 @@ Total SMES charging rate should not exceed total power generation rate, or an ov var/temp = null var/obj/machinery/dna_scanner/connected = null anchored = 1.0 -/obj/machinery/sec_lock - name = "Security Pad" - icon = 'stationobjs.dmi' - icon_state = "sec_lock" - var/obj/item/weapon/card/id/scan = null - var/a_type = 0.0 - var/obj/machinery/door/d1 = null - var/obj/machinery/door/d2 = null - anchored = 1.0 - var/access = "5500" - var/allowed = "Prison Security/Prison Warden/Security Officer/Head of Personnel/Captain" //*****RM -/obj/machinery/door_control - name = "Remote Door Control" - icon = 'stationobjs.dmi' - icon_state = "doorctrl0" - desc = "A remote control switch for a door." - var/id = null - anchored = 1.0 + //***** /obj/machinery/shuttle @@ -3139,25 +2762,6 @@ Total SMES charging rate should not exceed total power generation rate, or an ov -/obj/machinery/cell_charger - name = "cell charger" - desc = "A charging unit for power cells." - icon = 'power.dmi' - icon_state = "ccharger0" - var/obj/item/weapon/cell/charging = null - var/chargelevel = -1 - anchored = 1 - -/obj/machinery/light_switch - desc = "A light switch" - name = null - icon = 'power.dmi' - icon_state = "light1" - anchored = 1.0 - var/on = 1 - var/area/area = null - var/otherarea = null - /obj/cable level = 1 anchored =1 diff --git a/main-src/Code/Machinery/Atmoalter/_atmoalter.dm b/main-src/Code/Machinery/Atmoalter/_atmoalter.dm new file mode 100644 index 0000000..dd20038 --- /dev/null +++ b/main-src/Code/Machinery/Atmoalter/_atmoalter.dm @@ -0,0 +1,23 @@ +/* + * Atmoalter - base machine type for gas canisters, siphons, scrubbers, air regulator and filters, and heaters + * + * + */ + + + +obj/machinery/atmoalter + + var + obj/substance/gas/gas = null // the gas contents of the machine + maximum // the maximum capacity of the gas + + t_status // main valve status 1 = release, 2= siphon, 3 = stop, 4 = automatic + t_per // main valve rate + + c_per // pipe valve rate + c_status // pipe vale status 0 = disconnected, 1 = release, 2 = accept, 3 = stop + + obj/item/weapon/tank/holding // the tank item being held (or null) + + max_valve = 1e6 // the maximum setting of both valves \ No newline at end of file diff --git a/main-src/Code/Machinery/Atmoalter/canister.dm b/main-src/Code/Machinery/Atmoalter/canister.dm new file mode 100644 index 0000000..b357ad6 --- /dev/null +++ b/main-src/Code/Machinery/Atmoalter/canister.dm @@ -0,0 +1,440 @@ +/* + * Canister - base gas canister object. Actual placed canister will be one of 6 types defined below + * + * Can release gas into atmosphere, fill or siphon gas from an attached tank, + * or release or accept gas from an attached pipe connector. + * + */ + +obj/machinery/atmoalter/canister + name = "canister" + icon = 'canister.dmi' + density = 1 + + // from atmoalter + maximum = 1.3E8 + t_status = 3.0 + t_per = 50.0 + c_per = 50.0 + c_status = 0.0 + holding = null + + flags = FPRINT|DRIVABLE + weight = 1.0E7 + + var + color = "blue" // used to set icon_state + health = 20.0 // health removed by attacks & fire + destroyed = null // true if the canister has broken + filled = 1.0 //fractional fullness at spawn 0=empty, 1=full + + + // Create a new canister. This is called by all canister types + // Create the gas contents object and set the maximum capacity + + New() + ..() + src.gas = new /obj/substance/gas( src ) + src.gas.maximum = src.maximum + return + + + // Update the icon state and overlays to reflect canister type and fullness + + proc/update_icon() + + var/air_in = src.gas.tot_gas() // the amount of gas in the canister + + src.overlays = 0 + + if (destroyed) + icon_state = "[color]-1" + + else + icon_state = "[color]" + if(holding) + overlays += image('canister.dmi', "can-oT") + + if (air_in < 10) + overlays += image('canister.dmi', "can-o0") + else if (air_in < (src.gas.maximum * 0.2)) + overlays += image('canister.dmi', "can-o1") + else if (air_in < (src.maximum * 0.6)) + overlays += image('canister.dmi', "can-o2") + else + overlays += image('canister.dmi', "can-o3") + return + + + + + // Timed process. Depending on valve state, release or accept gas + + process() + + if (src.destroyed) + return + var/T = src.loc + if (istype(T, /turf)) + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + else + T = null + switch(src.t_status) + if(1.0) // Valve set to release + if (src.holding) // If holding a tank, release the gas into that tank + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.holding.gas.transfer_from(src.gas, t) + else // If not holding a tank, release gas into the turf + if (T) + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.turf_add(T, t) + src.update_icon() + if(2.0) // Valve set to accept + if (src.holding) // Siphon gas from the tank into the canister + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.transfer_from(src.holding.gas, t) + else // If no tank, do nothing + src.t_status = 3 + src.update_icon() + + + // Transfer for pipe valve is handled by /obj/machinery/connector process() proc + + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.update_icon() + return + + + //Returns the gas contents object + + get_gas() + return gas + + + // Called when the turf location is burning + // Reduce health, then check if destroyed + + burn(fi_amount) + src.health -= 1 + healthcheck() + return + + + // Called when attacked by a blob + // Reduce health, then check if destroyed + + blob_act() + src.health -= 1 + healthcheck() + return + + // Called when hit by a meteor + // Destroy the canister + + meteorhit(var/obj/O) + src.health = 0 + healthcheck() + return + + + // Called when hit by a projectile + + las_act(flag) + + if (flag == "bullet") + src.health = 0 + spawn( 0 ) + healthcheck() + return + if (flag) + var/turf/T = src.loc + if (!( istype(T, /turf) )) + return + else + T.firelevel = T.poison + else + src.health = 0 + spawn( 0 ) + healthcheck() + return + return + + + + // If the canister is damaged enough, destroy it and release all gas contained + + proc/healthcheck() + + if (src.health <= 10) + var/T = src.loc + if (!( istype(T, /turf) )) + return + src.gas.turf_add(T, -1.0) + src.destroyed = 1 + src.density = 0 + update_icon() + if (src.holding) + src.holding.loc = src.loc + src.holding = null + if (src.t_status == 2) + src.t_status = 3 + return + + + // Monkey interact same as human + + attack_paw(var/mob/user) + return src.attack_hand(user) + + + // Interact with canister, shows interaction window + + attack_hand(var/mob/user) + + if (src.destroyed) + return + user.machine = src + var/tt + switch(src.t_status) // Main valve + if(1.0) + tt = "Releasing Siphon (only tank) Stop" + if(2.0) + tt = "Release Siphoning (only tank) Stop" + if(3.0) + tt = "Release Siphon (only tank) Stopped" + else + var/ct = null + switch(src.c_status) // Pipe valve + if(1.0) + ct = "Releasing Accept Stop" + if(2.0) + ct = "Release Accepting Stop" + if(3.0) + ct = "Release Accept Stopped" + else + ct = "Disconnected" + + + var/dat = {"Canister Valves
+Contains/Capacity [num2text(src.gas.tot_gas(), 20)] / [num2text(src.maximum, 20)]
+Upper Valve Status: [tt]
+\t[(src.holding ? "Tank ([src.holding.gas.tot_gas()])" : null)]
+\tM - - - - [src.t_per] + + + + M
+Pipe Valve Status: [ct]
+\tM - - - - [src.c_per] + + + + M
+
+Close
+
"} + + user << browse(dat, "window=canister;size=600x300") + return + + + // Process topic link from interaction window + + Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) + usr.machine = src + + if (href_list["c"]) + var/c = text2num(href_list["c"]) + switch(c) + if(1.0) + src.c_status = 1 + if(2.0) + c_status = 2 + if(3.0) + src.c_status = 3 + + else if (href_list["t"]) + var/t = text2num(href_list["t"]) + if (src.t_status == 0) + return + switch(t) + if(1.0) + src.t_status = 1 + if(2.0) + if (src.holding) + src.t_status = 2 + else + src.t_status = 3 + if(3.0) + src.t_status = 3 + + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.t_per += tp + src.t_per = min(max(round(src.t_per), 0), 1000000.0) + + else if (href_list["cp"]) + var/cp = text2num(href_list["cp"]) + src.c_per += cp + src.c_per = min(max(round(src.c_per), 0), 1000000.0) + + else if (href_list["tank"]) + var/cp = text2num(href_list["tank"]) + if ((cp == 1 && src.holding)) + src.holding.loc = src.loc + src.holding = null + if (src.t_status == 2) + src.t_status = 3 + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.add_fingerprint(usr) + update_icon() + + else + usr << browse(null, "window=canister") + + + // Attack by an object + // If a tank, insert the tank + // If a wrench (and a connector is present), attach/unattach canister from pipe connector + // Otherwise, damage the canister + + attackby(var/obj/item/weapon/W, var/mob/user) + + if ((istype(W, /obj/item/weapon/tank) && !( src.destroyed ))) + if (src.holding) + return + var/obj/item/weapon/tank/T = W + user.drop_item() + T.loc = src + src.holding = T + update_icon() + + else if ((istype(W, /obj/item/weapon/wrench))) + var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) + + if (src.c_status) // note: don't check is cansiter is destroyed to allow user to unhook a broken cansiter + src.anchored = 0 + src.c_status = 0 + user.show_message("\blue You have disconnected the canister.", 1) + if(con) + con.connected = null + else + if(con && !con.connected && !destroyed) + src.anchored = 1 + src.c_status = 3 + user.show_message("\blue You have connected the canister.", 1) + con.connected = src + else + user.show_message("\blue There is nothing here with which to connect the canister.", 1) + else + switch(W.damtype) + if("fire") + src.health -= W.force + if("brute") + src.health -= W.force * 0.5 + else + src.healthcheck() + ..() + return + + + /* + * The specific canister types + */ + + // Canister containing plasma + + poisoncanister + name = "Canister \[Plasma (Bio)\]" + icon_state = "orange" + color = "orange" + + New() + ..() + src.update_icon() + src.gas.plasma = 9.0E7*filled + return + + + // Canister containing oxygen + + oxygencanister + name = "Canister: \[O2\]" + icon_state = "blue" + color = "blue" + + New() + ..() + src.gas.oxygen = 1.0E8*filled + return + + + // Canister containing N2O + + anesthcanister + name = "Canister: \[N2O\]" + icon_state = "redws" + color = "redws" + + New() + ..() + src.gas.sl_gas = 1.0E8*filled + return + + + // Canister containing nitrogen + + n2canister + name = "Canister: \[N2\]" + icon_state = "red" + color = "red" + + New() + ..() + src.gas.n2 = 1.0E8*filled + return + + + // Canister containing carbon dioxide + + co2canister + name = "Canister \[CO2\]" + icon_state = "black" + color = "black" + + New() + ..() + src.gas.co2 = 1.0E8*filled + return + + + // Canister containing air mixture (21% O2, 79% N2) + + aircanister + name = "Canister \[Air\]" + icon_state = "grey" + color = "grey" + + New() + ..() + src.gas.oxygen = 2.1e7*filled + src.gas.n2 = 7.9e7*filled + return + + + diff --git a/main-src/Code/Machinery/Atmoalter/heater.dm b/main-src/Code/Machinery/Atmoalter/heater.dm new file mode 100644 index 0000000..5654909 --- /dev/null +++ b/main-src/Code/Machinery/Atmoalter/heater.dm @@ -0,0 +1,254 @@ +/* + * Heater - A machine that allows heating of gases. + * + * Can siphon/fill gas from ab attached tank, or connect to pipe network via a connector. + * + */ + + + +obj/machinery/atmoalter/heater + name = "heater" + icon = 'stationobjs.dmi' + icon_state = "heater1" + density = 1 + + // from atmoalter + maximum = 1.3E8 + anchored = 1.0 + t_status = 3.0 + t_per = 50.0 + c_per = 50.0 + c_status = 0.0 + holding = null // the inserted tank item, or null if none + var + h_tar = 20.0 // the target temperature (degC) + h_status = 0.0 // the heater status 0=off, 1=on + heatrate = 1500000.0 // the rate at which heating takes place + + + // Create a new heater, set gas content & maximum capacity + + New() + + ..() + src.gas = new /obj/substance/gas( src ) + src.gas.maximum = src.maximum + return + + + // Set the heater's icon state depending on status + + proc/setstate() + + if(stat & NOPOWER) + icon_state = "heater-p" + return + + if (src.holding) + src.icon_state = "heater1-h" + else + src.icon_state = "heater1" + return + + + // Timer process. Heat the contained gas towards the target temperature, and flow gas to/from tank is valve open. + + process() + + if(stat & NOPOWER) return + use_power(5) + + var/turf/T = src.loc + if (istype(T, /turf)) + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + else + T = null + + + if (src.h_status) // true if heating on + var/t1 = src.gas.tot_gas() + if ((t1 > 0 && src.gas.temperature < (src.h_tar+T0C))) // note gas.temperature in kelvin but target temp in celcius + var/increase = src.heatrate / t1 + var/n_temp = src.gas.temperature + increase + src.gas.temperature = min(n_temp, (src.h_tar+T0C)) + + use_power( src.h_tar*8) + + switch(src.t_status) // main valve; 1=release, 2=siphon, 3=stop + if(1.0) + if (src.holding) + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.holding.gas.transfer_from(src.gas, t) + else + src.t_status = 3 + if(2.0) + if (src.holding) + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.transfer_from(src.holding.gas, t) + else + src.t_status = 3 + else + + // Pipe valve transfer handled by /obj/machinery/connector process() + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.setstate() + return + + + // monkey interact same as human + + attack_paw(mob/user) + return src.attack_hand(user) + + + // interact, show window + + attack_hand(var/mob/user) + + if(stat & NOPOWER) return + + user.machine = src + var/tt + switch(src.t_status) + if(1.0) + tt = "Releasing Siphon Stop" + if(2.0) + tt = "Release SiphoningStop" + if(3.0) + tt = "Release Siphon Stopped" + else + + var/ht = null + if (src.h_status) + ht = "Heating Stop" + else + ht = "Heat Stopped" + + var/ct = null + switch(src.c_status) + if(1.0) + ct = "Releasing Accept Stop" + if(2.0) + ct = "Release Accepting Stop" + if(3.0) + ct = "Release Accept Stopped" + else + ct = "Disconnected" + + var/dat = text("Canister Valves
\nContains/Capacity [] / []
\nUpper Valve Status: [][]
\n\tM - - - - [] + + + + M
\nHeater Status: [] - []
\n\tTrg Tmp: - - - [] + + +
\n
\nPipe Valve Status: []
\n\tM - - - - [] + + + + M
\n
\nClose
\n
", src.gas.tot_gas(), src.maximum, tt, (src.holding ? text("
Tank ([])", src, src.holding.gas.tot_gas()) : null), src, num2text(1000000.0, 7), src, src, src, src, src.t_per, src, src, src, src, src, num2text(1000000.0, 7), ht, (src.gas.tot_gas() ? (src.gas.temperature-T0C) : 20), src, src, src, src.h_tar, src, src, src, ct, src, num2text(1000000.0, 7), src, src, src, src, src.c_per, src, src, src, src, src, num2text(1000000.0, 7), user) + user << browse(dat, "window=canister;size=600x300") + return + + + // handle topic links from interaction window + + Topic(href, href_list) + ..() + if (usr.stat || usr.restrained()) + return + if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) + usr.machine = src + + if (href_list["c"]) + var/c = text2num(href_list["c"]) + switch(c) + if(1.0) + src.c_status = 1 + if(2.0) + src.c_status = 2 + if(3.0) + src.c_status = 3 + else + else if (href_list["t"]) + var/t = text2num(href_list["t"]) + if (src.t_status == 0) + return + switch(t) + if(1.0) + src.t_status = 1 + if(2.0) + src.t_status = 2 + if(3.0) + src.t_status = 3 + else + else if (href_list["h"]) + var/h = text2num(href_list["h"]) + if (h == 1) + src.h_status = 1 + else + src.h_status = null + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.t_per += tp + src.t_per = min(max(round(src.t_per), 0), 1000000.0) + else if (href_list["cp"]) + var/cp = text2num(href_list["cp"]) + src.c_per += cp + src.c_per = min(max(round(src.c_per), 0), 1000000.0) + else if (href_list["ht"]) + var/cp = text2num(href_list["ht"]) + src.h_tar += cp + src.h_tar = min(max(round(src.h_tar), 0), 500) + else if (href_list["tank"]) + var/cp = text2num(href_list["tank"]) + if ((cp == 1 && src.holding)) + src.holding.loc = src.loc + src.holding = null + if (src.t_status == 2) + src.t_status = 3 + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.add_fingerprint(usr) + else + usr << browse(null, "window=canister") + return + return + + // attack by tank, insert the tank + // attack by wrench, connect to pipe connector (if present) + + attackby(var/obj/item/weapon/W, var/mob/user) + + if (istype(W, /obj/item/weapon/tank)) + if (src.holding) + return + var/obj/item/weapon/tank/T = W + user.drop_item() + T.loc = src + src.holding = T + + else if (istype(W, /obj/item/weapon/wrench)) + var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) + + if (src.c_status) + src.anchored = 0 + src.c_status = 0 + user.show_message("\blue You have disconnected the heater.", 1) + if(con) + con.connected = null + else + if (con && !con.connected) + src.anchored = 1 + src.c_status = 3 + user.show_message("\blue You have connected the heater.", 1) + con.connected = src + else + user.show_message("\blue There is no connector here to attach the heater to.", 1) + return + + diff --git a/main-src/Code/Machinery/Atmoalter/siphs.dm b/main-src/Code/Machinery/Atmoalter/siphs.dm new file mode 100644 index 0000000..f0c6d7c --- /dev/null +++ b/main-src/Code/Machinery/Atmoalter/siphs.dm @@ -0,0 +1,654 @@ +/* + * siphs - base type including siphons, scrubbers, air regulators, and air filters + * + * + * + */ + + // base siph type + +obj/machinery/atmoalter/siphs + name = "siphs" + density = 1 + weight = 1.0E7 + anchored = 1.0 + + // from atmoalter + maximum = 1.3E8 + holding = null + t_status = 3.0 + t_per = 50.0 + c_per = 50.0 + c_status = 0.0 + + var + alterable = 1.0 // false if interface is locked (change with wrench) + f_time = 1.0 // worldtime until automatic mode resumes; set to 30 seconds delay if a fire is present in turf + //location = null // unknown/not used + empty = null // if true, fullairsiphons are spawned without any gas content + // otherwise, filled with air + + +/* There are 6 types of siph objects: + * + * fullairsiphon - Siphon - Can hold a tank. Starts containing air. Automatic process releases air to maintain correct O2/N2 levels + * fullairsiphon/port - Portable Siphon - same as fullairsiphon, but pushable. + * fullairsiphon/air_vent - Air Regulator - Vent on floor, same as fullairsiphon but cannot hold a tank. + * + * scrubbers - Scrubber - Can hold a tank. Starts empty. Automatic process removes toxins from air and stores in gas content. + * scubbers/port - Portable Scrubber - same as scrubbers but pushable. + * scubbers/air_filter - Air Filter - Vent on floor, same as scrubbers but cannot hold a tank. + */ + + // new siphon object, create the gas content and set maximum capacity + // Called by New() proc of all siph types + + New() + ..() + src.gas = new /obj/substance/gas( src ) + src.gas.maximum = src.maximum + + + // Set main valve to release and max setting + + proc/releaseall() + src.t_status = 1 + src.t_per = max_valve + return + + + // Reset the siphon state. If "valve" is negative, main valve is set to release at that rate + // If "valve" is positive, main valve set to siphon at that rate + // If "auto" true, main valve set to automatic status + + proc/reset(valve, auto) + if(c_status!=0) + return + + if (valve < 0) + src.t_per = -valve + src.t_status = 1 + else + if (valve > 0) + src.t_per = valve + src.t_status = 2 + else + src.t_status = 3 + if (auto) + src.t_status = 4 + src.setstate() + return + + + // Release "amount" of gas into the turf + + proc/release(amount, flag) + var/T = src.loc + if (!( istype(T, /turf) )) + return + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + if (!( amount )) + return + if (!( flag )) + amount = min(amount, max_valve) + src.gas.turf_add(T, amount) + return + + + // Siphon "amount" of gas from the turf + + proc/siphon(amount, flag) + + var/T = src.loc + if (!( istype(T, /turf) )) + return + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + if (!( amount )) + return + if (!( flag )) + amount = min(amount, 900000.0) + src.gas.turf_take(T, amount) + return + + + // Set the icon state, depending on status (unpowered, holding a tank, or accepting or releasing gas) + + proc/setstate() + + if(stat & NOPOWER) + icon_state = "siphon:0" + return + + if (src.holding) + src.icon_state = "siphon:T" + else + if (src.t_status != 3) + src.icon_state = "siphon:1" + else + src.icon_state = "siphon:0" + return + + + // Returns true if the siphon/scrubber is a portable type + + proc/portable() + return istype(src, /obj/machinery/atmoalter/siphs/fullairsiphon/port) || istype(src, /obj/machinery/atmoalter/siphs/scrubbers/port) + + + // Called when area power status changes. Siphons use the ENVIRON channel. Portable siphons/scrubbers do not use power. + + power_change() + + if( portable() ) + return + + if(!powered(ENVIRON)) + spawn(rand(0,15)) + stat |= NOPOWER + setstate() + else + stat &= ~NOPOWER + setstate() + + + // Timed process. Note scrubbers/air filters override this. + // Accept or release gas depending on settings + + process() + if(stat & NOPOWER) return + + if (src.t_status != 3) + var/turf/T = src.loc + if (istype(T, /turf)) + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + else + T = null + + switch(src.t_status) // main valve status + if(1.0) // 1 = release + if( !portable() ) use_power(50, ENVIRON) + if (src.holding) // if tank inserted, fill tank + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.holding.gas.transfer_from(src.gas, t) + else // otherwise release into turf + if (T) + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.turf_add(T, t) + + if(2.0) // 2 = siphon + if( !portable() ) use_power(50, ENVIRON) + if (src.holding) // if tank inserted, draw from tank + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.transfer_from(src.holding.gas, t) + else // else take from turf atmosphere + if (T) + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (t > t2) + t = t2 + + src.gas.turf_take(T, t) + // 3 = stopped + if(4.0) // 4 = automatic + if( !portable() ) + use_power(50, ENVIRON) + + if (T) + if (T.firelevel > 900000.0) + src.f_time = world.time + 300 // shut off automatic operation for 30 seconds if fire present + else + if (world.time > src.f_time) + var/difference = CELLSTANDARD - (T.oxygen + T.n2) + if (difference > 0) + var/t1 = src.gas.tot_gas() + if (difference > t1) + difference = t1 + src.gas.turf_add(T, difference) // add gas to turf to maintain standard N2/O2 levels + + // Pipe valve settings handled in /obj/machinery/connector/process() + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.setstate() + return + + + // Monkey interact same as human + + attack_paw(user as mob) + return src.attack_hand(user) + + + // Interact, show window + // Used by siphons and scrubbers, but air regulators and filters override + + attack_hand(var/mob/user) + + if(stat & NOPOWER) return + user.machine = src + var/tt + switch(src.t_status) + if(1.0) + tt = "Releasing Siphon Stop" + if(2.0) + tt = "Release Siphoning Stop" + if(3.0) + tt = "Release Siphon Stopped Automatic" + else + tt = "Automatic equalizers are on!" + + var/ct = null + switch(src.c_status) + if(1.0) + ct = "Releasing Accept Stop" + if(2.0) + ct = "Release Accepting Stop" + if(3.0) + ct = "Release Accept Stopped" + else + ct = "Disconnected" + var/at = null + if (src.t_status == 4) + at = "Automatic On Stop" + var/dat = text("Canister Valves []
\n\tContains/Capacity [] / []
\n\tUpper Valve Status: [] []
\n\t\tM - - - - [] + + + + M
\n\tPipe Valve Status: []
\n\t\tM - - - - [] + + + + M
\n
\n\nClose
\n\t
", (!( src.alterable ) ? "Valves are locked. Unlock with wrench!" : "You can lock this interface with a wrench."), num2text(src.gas.tot_gas(), 10), num2text(src.maximum, 10), (src.t_status == 4 ? text("[]", at) : text("[]", tt)), (src.holding ? text("
(Tank ([])", src, src.holding.gas.tot_gas()) : null), src, num2text(max_valve, 7), src, src, src, src, src.t_per, src, src, src, src, src, num2text(max_valve, 7), ct, src, num2text(max_valve, 7), src, src, src, src, src.c_per, src, src, src, src, src, num2text(max_valve, 7), user) + user << browse(dat, "window=siphon;size=600x300") + return + + + // Handle topic links from interaction window + + Topic(href, href_list) + ..() + + if (usr.stat || usr.restrained()) + return + if (!( src.alterable )) + return + if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) + usr.machine = src + if (href_list["c"]) + var/c = text2num(href_list["c"]) + switch(c) + if(1.0) + src.c_status = 1 + if(2.0) + src.c_status = 2 + if(3.0) + src.c_status = 3 + + else if (href_list["t"]) + var/t = text2num(href_list["t"]) + if (src.t_status == 0) + return + switch(t) + if(1.0) + src.t_status = 1 + if(2.0) + src.t_status = 2 + if(3.0) + src.t_status = 3 + if(4.0) + src.t_status = 4 + src.f_time = 1 + + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.t_per += tp + src.t_per = min(max(round(src.t_per), 0), max_valve) + else if (href_list["cp"]) + var/cp = text2num(href_list["cp"]) + src.c_per += cp + src.c_per = min(max(round(src.c_per), 0), max_valve) + else if (href_list["tank"]) + var/cp = text2num(href_list["tank"]) + if (cp == 1) + src.holding.loc = src.loc + src.holding = null + if (src.t_status == 2) + src.t_status = 3 + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.add_fingerprint(usr) + else + usr << browse(null, "window=canister") + return + return + + + // Attack by item + // Use tank to insert a tank into siphon + // Use screwdriver to attach to a connector (if present) + // Use wrench to lock/unlock the interface + // Note air filters and air regulators override this proc since tanks cannot be inserted + + attackby(var/obj/W as obj, mob/user as mob) + + if (istype(W, /obj/item/weapon/tank)) // insert tank + if (src.holding) + return + var/obj/item/weapon/tank/T = W + user.drop_item() + T.loc = src + src.holding = T + + else if (istype(W, /obj/item/weapon/screwdriver)) // connect/disconnect from connector + var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) + if (src.c_status) + src.anchored = 0 + src.c_status = 0 + user.show_message("\blue You have disconnected the siphon.") + if(con) + con.connected = null + else if (con && !con.connected) + src.anchored = 1 + src.c_status = 3 + user.show_message("\blue You have connected the siphon.") + con.connected = src + else + user.show_message("\blue There is nothing here to connect to the siphon.") + + + else if (istype(W, /obj/item/weapon/wrench)) // lock/unlock the interface + src.alterable = !( src.alterable ) + if (src.alterable) + user << "\blue You unlock the interface!" + else + user << "\blue You lock the interface!" + + + /* + * Fullairsiphons - standard, air regulator, and portable + */ + + fullairsiphon + name = "Air siphon" + icon = 'turfs.dmi' + icon_state = "siphon:0" + + air_vent + name = "Air regulator" + icon = 'aircontrol.dmi' + icon_state = "vent2" + t_status = 4 // air regulator vents start in automatic mode + alterable = 0 // with interface locked + density = 0 + + port + name = "Portable Siphon" + icon = 'stationobjs.dmi' + flags = FPRINT|DRIVABLE + anchored = 0 + + + // Create a new fullairsiphon. Unless empty var is true, fill with 21% O2/79% N2 + + New() + ..() + if(!empty) + src.gas.oxygen = 2.73E7 + src.gas.n2 = 1.027E8 + + + // Reset the protable siphon + + fullairsiphon/port/reset(valve, auto) + if (valve < 0) + src.t_per = -valve + src.t_status = 1 + else + if (valve > 0) + src.t_per = valve + src.t_status = 2 + else + src.t_status = 3 + if (auto) + src.t_status = 4 + src.setstate() + return + + // Attack air regulator with item + // If screwdriver, attach/unattach from connector (if present) + // If wrench, lock/unlock the interface + + fullairsiphon/air_vent/attackby(obj/item/weapon/W, mob/user) + + if (istype(W, /obj/item/weapon/screwdriver)) + if (src.c_status) + src.anchored = 1 + src.c_status = 0 + else + if (locate(/obj/machinery/connector, src.loc)) + src.anchored = 1 + src.c_status = 3 + else + if (istype(W, /obj/item/weapon/wrench)) + src.alterable = !( src.alterable ) + return + + + // Set the icon state of an air regulator vent + + fullairsiphon/air_vent/setstate() + if(stat & NOPOWER) + icon_state = "vent-p" + return + + if (src.t_status == 4) + src.icon_state = "vent2" + else + if (src.t_status == 3) + src.icon_state = "vent0" + else + src.icon_state = "vent1" + return + + + // Reset an air regulator vent. Only set automatic mode; do not change valve settings + + fullairsiphon/air_vent/reset(valve, auto) + + if (auto) + src.t_status = 4 + return + + /* + * Scrubbers - standard, air filter, and portable + */ + + scrubbers + name = "scrubbers" + icon = 'turfs2.dmi' + icon_state = "siphon:0" + + air_filter + name = "air filter" + icon = 'aircontrol.dmi' + icon_state = "vent2" + t_status = 4 // air filter vents start in automatic mode + alterable = 0 // with interface locked + density = 0 + + port + name = "Portable Siphon" + icon = 'stationobjs.dmi' + icon_state = "scrubber:0" + flags = FPRINT|DRIVABLE + anchored = 0.0 + + + // Timed process for scrubbers (overrides standard for siphs) + + process() + + if(stat & NOPOWER) return + + if (src.t_status != 3) // unless stopped + var/turf/T = src.loc // add all oxygen in gas contents to turf + if (istype(T, /turf)) + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + if (T.firelevel < 900000.0) + src.gas.turf_add_all_oxy(T) + + else + T = null + + switch(src.t_status) // main valve status + if(1.0) // 1 = release + if( !portable() ) use_power(50, ENVIRON) + + if (src.holding) // if a tank is inserted, fill tank with gas + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.holding.gas.transfer_from(src.gas, t) + else // otherwise, release gas into turf atmosphere + if (T) + var/t1 = src.gas.tot_gas() + var/t2 = t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.turf_add(T, t) + + if(2.0) // 2 = siphon + if( !portable() ) use_power(50, ENVIRON) + if (src.holding) // if a tank is inserted, draw gas from tank into contents + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (src.t_per > t2) + t = t2 + src.gas.transfer_from(src.holding.gas, t) + else // otherwise, siphon gas from the turf atmosphere + if (T) + var/t1 = src.gas.tot_gas() + var/t2 = src.maximum - t1 + var/t = src.t_per + if (t > t2) + t = t2 + src.gas.turf_take(T, t) + if(4.0) // 4 = automatic mode + if( !portable() ) use_power(50, ENVIRON) + if (T) + if (T.firelevel > 900000.0) + src.f_time = world.time + 300 // disable automatic mode for 30 seconds if a fire present + else + if (world.time > src.f_time) + src.gas.extract_toxs(T) // remove toxins (co2, plasma, n2o) from turf into contents + if( !portable() ) use_power(150, ENVIRON) + var/contain = src.gas.tot_gas() // release excess contents back into turf atmosphere + if (contain > 1.3E8) + src.gas.turf_add(T, 1.3E8 - contain) + + // Pipe valve status handled by /obj/machinery/connector/process() + + src.setstate() + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + //Foreach goto(654) + return + + + // Set icon state of air filter vent depending on status + + scrubbers/air_filter/setstate() + if(stat & NOPOWER) + icon_state = "vent-p" + return + + if (src.t_status == 4) + src.icon_state = "vent2" + else + if (src.t_status == 3) + src.icon_state = "vent0" + else + src.icon_state = "vent1" + return + + + // Attack air filter vent by item + // If screwdriver, attach/unattach from connector (if present) + // If wrench, lock/unlock the interface + + scrubbers/air_filter/attackby(obj/item/weapon/W, mob/user) + + if (istype(W, /obj/item/weapon/screwdriver)) + if (src.c_status) + src.anchored = 1 + src.c_status = 0 + else + if (locate(/obj/machinery/connector, src.loc)) + src.anchored = 1 + src.c_status = 3 + else + if (istype(W, /obj/item/weapon/wrench)) + src.alterable = !( src.alterable ) + return + + // Reset an air filter vent. Only set automatic mode; do not change valve settings + + scrubbers/air_filter/reset(valve, auto) + + if (auto) + src.t_status = 4 + src.setstate() + return + + + // Set icon state for portable scrubber + + scrubbers/port/setstate() + + if(stat & NOPOWER) + icon_state = "scrubber:0" + return + + if (src.holding) + src.icon_state = "scrubber:T" + else + if (src.t_status != 3) + src.icon_state = "scrubber:1" + else + src.icon_state = "scrubber:0" + return + + + // Reset valve status for portable scrubber + + scrubbers/port/reset(valve, auto) + if (valve < 0) + src.t_per = -valve + src.t_status = 1 + else + if (valve > 0) + src.t_per = valve + src.t_status = 2 + else + src.t_status = 3 + if (auto) + src.t_status = 4 + src.setstate() + return diff --git a/main-src/Code/Machinery/_machinery.dm b/main-src/Code/Machinery/_machinery.dm new file mode 100644 index 0000000..bcea21d --- /dev/null +++ b/main-src/Code/Machinery/_machinery.dm @@ -0,0 +1,169 @@ +/* + * The base machinery object + * + * Machines have a process() proc called approximately once per second while a game round is in progress + * Thus they can perform repetative tasks, such as calculating pipe gas flow, power usage, etc. + * + * + */ + + +obj/machinery + + var + p_dir = 0 // directions of regular pipes connected to this machine + // bitwise-OR of cardinal directions to indicate multiple pipes + h_dir = 0 // as above, but for heat-exchange pipes + + capmult = 0 // used for gas flow - a capacity multiplier + + stat = 0 // machinery status bitflags + // currently used values: 1 - BROKEN ; 2 - NOPOWER + + + // New() and Del() add and remove machines from the global "machines" list + // This list is used to call the process() proc for all machines ~1 per second during a round + + New() + ..() + machines += src + + Del() + machines -= src + ..() + + + // Called when an object is in an explosion + // Higher "severity" means the object was further from the centre of the explosion + + ex_act(severity) + + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + del(src) + return + if(3.0) + if (prob(25)) + del(src) + return + + + // Called when attacked by a blob + + blob_act() + if(prob(25)) + del(src) + + + /* + * Prototype procs common to all /obj/machinery objects + */ + + + // Called for all /obj/machinery in the "machines" list, approximately once per second + // by /datum/control/cellular/process() when a game round is active + // Any regular action of the machine is executed by this proc. + // For machines that are part of a pipe network, this routine also calculates the gas flow to/from this machine. + + proc/process() + return + + /* + * Pipe and gas-flow related prototypes + */ + + // Machines needing extra processing for gas flow in pipes place themselves in the "gasflowlist" global list + // All machines in that list have gas_flow() executed after all process() procedures in the world have completed + // Used to avoid order-of-execution problems in pipe flow. + // This routine usually just replaces the current gas levels with the new ones calculated in the process() proc. + + proc/gas_flow() + return + + + // Builds pipe-connections for adjacent machines + // Called after map load, then again whenever a pipeline is altered. + + proc/buildnodes() + return + + + // For pipe-connected machinery, returns self + // For pipe objects, returns the pipeline object containing this. + + proc/getline() + if(p_dir || h_dir) + return src + + + // Returns true if this is a pipe (or h/e pipe) object, false otherwise + + proc/ispipe() + return 0 + + + // Returns the next connected pipe in a pipeline, or null if this is not a pipe object + + proc/next(from) + return null + + + // Returns the "gas val", usually the total gas content divided by the capacty multiplier + // Roughly, this is how full of gas the machine is.Used to calculate gas flow in and out of the machine. + // Argument indicates which node is enequiring, for machines that have more than one gas reservoir + + proc/get_gas_val(from) + return null + + + // Returns the gas reservoir object of a machine (or null if none) + // Used during gas flow calculations + + proc/get_gas(from) + return null + + /* + * Power related prototypes + */ + + + // Returns true if the area has power on given channel (or doesn't require power). + // defaults to equipment channel + + proc/powered(var/chan = EQUIP) + var/area/A = src.loc.loc // make sure it's in an area + if(!A || !isarea(A)) + return 0 // if not, then not powered + + return A.powered(chan) // return power status of the area + + + // Increment the power usage stats for an area + // usually called by a machine in its process() proc + + proc/use_power(var/amount, var/chan=EQUIP) // defaults to Equipment channel + var/area/A = src.loc.loc // make sure it's in an area + if(!A || !isarea(A)) + return + + A.use_power(amount, chan) + + + // Called for all machines in an area whenever power settings of the area change + // By default, sets NOPOWER flag if the equipment channel is off + // Override for other behaviour + + proc/power_change() + + + if(powered()) + stat &= ~NOPOWER + else + + stat |= NOPOWER + return + diff --git a/main-src/Code/Machinery/_pipe_misc.dm b/main-src/Code/Machinery/_pipe_misc.dm new file mode 100644 index 0000000..98be40d --- /dev/null +++ b/main-src/Code/Machinery/_pipe_misc.dm @@ -0,0 +1,170 @@ +/* + * Pipe Misc -- Global procs and support routines used in pipe network calculations. + * + */ + + +// Build the list of pipeline objects. Called after world has loaded. + +/proc/makepipelines() + + + for(var/obj/machinery/pipes/P in machines) // look for a pipe + + if(!P.pl) // if not already part of a line + var/obj/machinery/pipeline/PL = new() // make a new pipeline + plines += PL // add it to the global list + P.buildnodes(PL) // and spread to all connected pipes + + // After the above, all pipes in the world will be associated with a pipeline object + + // Now set pipeline names (so they can be distinguished for debugging). + + for(var/L = 1 to length(plines)) // for count of lines found + var/obj/machinery/pipeline/PL = plines[L] // get the pipeline virtual object + PL.name = "pipeline #[L]" // and set the name + + // Next, find the pipes at the end of each pipeline, and use those to get an ordered list of all pipes in the pipeline + // Then set the pipeline variables + + for(var/obj/machinery/pipes/P in machines) // look for pipes + + if(P.termination) // true if pipe is terminated (ends in blank or a machine) + var/obj/machinery/pipeline/PL = P.pl // get the pipeline from the pipe's pl + + var/list/pipes = pipelist(null, P) // get a list of pipes from P until terminated + + PL.nodes = pipes // pipeline is this list of nodes + PL.numnodes = pipes.len // with this many nodes + PL.capmult = PL.numnodes+1 // with this flow multiplier + + + // Now set the node connections for all machines that connect to pipelines. + + for(var/obj/machinery/M in machines) // for all machines + if(M.p_dir || M.h_dir) // which are pipe-connected + if(!M.ispipe()) // is not a pipe itself + M.buildnodes() // build the nodes, setting the links to the pipelines + // also sets the vnodes for the pipelines + + // Finally, make sure the pipeline nodes point to the terminating machines. + + for(var/obj/machinery/pipeline/PL in plines) // for all lines + PL.setterm() // orient the pipes and set the pipeline vnodes to the terminating machines + + + +// Return a list of pipes, in order of connection +// Starting at startnode, moving away from source + +/proc/pipelist(var/obj/machinery/source, var/obj/machinery/startnode) + + var/list/L = list() + + var/obj/machinery/node = startnode + var/obj/machinery/prev = source + var/obj/machinery/newnode + + while(node) + L += node + newnode = node.next(prev) + prev = node + + if(newnode && newnode.ispipe()) + node = newnode + else + break + + return L + + +// Returns the machine with compatible p_dir and level in 1 step in dir mdir from turf S +// Note: "compatible" means the machine has a p_dir pointing towards S. +// Returns null if no such machine is found + +/proc/get_machine(var/level, var/turf/S, var/mdir) + + var/flip = turn(mdir, 180) + + var/turf/T = get_step(S, mdir) + + for(var/obj/machinery/M in T.contents) + if(M.level == level) + if(M.p_dir & flip) + return M + + return null + + +// Returns the machine with compatible h_dir and level in 1 step in dir mdir from turf S +// Same as routine above, but for h/e rather than standard pipe. + +/proc/get_he_machine(var/level, var/turf/S, mdir) + + var/flip = turn(mdir, 180) + + var/turf/T = get_step(S, mdir) + + for(var/obj/machinery/M in T.contents) + if(M.level == level) + if(M.h_dir & flip) + return M + + return null + + +// The main flow routine +// Calculates the movement of "amount" gas between source and target machines +// If amount is negative, flow is from source to target, and source gas level is reduced +// If amount is positive, flow is from target to source, and source gas level is increased by a fraction of the target gas +// The source's new gas level is stored in "sngas", which replaces the actual gas level in the gas_flow() proc for this machine. +// Note the target's gas level isn't altered here; it will run this proc itself and alter it's own gas levels by the correct amount. + + +/proc/calc_delta(obj/machinery/source, obj/substance/gas/sgas, obj/substance/gas/sngas, obj/machinery/target, amount) + + var/obj/substance/gas/tgas = target.get_gas(source) + + var/obj/substance/gas/ndelta = new() + + if(amount < 0) // then flowing from source to target + + ndelta.set_frac(sgas, -amount) // this is fraction of the gas which will be transfered to other node + sngas.sub_delta(ndelta) // subtract off the fraction which is gone + + else // flowing from target to source + ndelta.set_frac(tgas, amount) // fraction of gas from the other node + sngas.add_delta(ndelta) // add the fraction to the new gas resv + + +// Called by all gas-handling machines when a pipe node is not present. +// Also used by /obj/machinery/inlet +// Calculates a leak between a gas reservoir (sgas, sngas) and turf T +// Gas can flow both ways, if pipe is less full than the turf + + +/obj/machinery/proc/flow_to_turf(var/obj/substance/gas/sgas, var/obj/substance/gas/sngas, var/turf/T) + + + + var/t_tot = T.tot_gas() * 0.2 // partial pressure of turf gas at pipe, for the moment + + var/delta_gt = FLOWFRAC * ( t_tot - sgas.tot_gas() / capmult ) + + + var/obj/substance/gas/ndelta = new() + + if(delta_gt < 0) // flow from pipe to turf + + ndelta.set_frac(sgas, -delta_gt) // ndelta contains gas to transfer to turf + sngas.sub_delta(ndelta) // update new gas to remove the amount transfered + ndelta.turf_add(T, -1) // add all of ndelta to turf + + else // flow from turf to pipe + + sngas.turf_take(T, delta_gt) // grab gas from turf and direcly add it to the new gas + + T.res_vars() // update turf gas vars for both cases + + + diff --git a/main-src/Code/Machinery/alarm.dm b/main-src/Code/Machinery/alarm.dm new file mode 100644 index 0000000..c56ffac --- /dev/null +++ b/main-src/Code/Machinery/alarm.dm @@ -0,0 +1,145 @@ +/** + * Alarm -- Provides a visual indication when air quality is unbreathable (toxins, low pressure, etc.) + * + */ + +obj/machinery/alarm + name = "alarm" + icon = 'stationobjs.dmi' + icon_state = "alarm:0" + anchored = 1.0 + + + // Monitors location air quality and changes icon_state to reflect it + + process() + if(stat & NOPOWER) + icon_state = "alarm-p" + return + + use_power(5, ENVIRON) + + var/safe = 1 + var/turf/T = src.loc + if (!( istype(T, /turf) )) + return + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 + turf_total = max(turf_total, 1) + var/t1 = turf_total / CELLSTANDARD * 100 + if (!( (90 < t1 && t1 < 110) )) + safe = 0 + t1 = T.oxygen / turf_total * 100 + if (!( (20 < t1 && t1 < 30) )) + safe = 0 + src.icon_state = text("alarm:[]", !( safe )) + return + + + // Called when area power status changes. Alarms use the ENVIRON channel + + power_change() + if( powered(ENVIRON) ) + stat &= ~NOPOWER + else + stat |= NOPOWER + + // Examining an alarm provides an air quality readout the same as a handheld air analyzer + + examine() + set src in oview(1) + + if (usr.stat || stat & NOPOWER) + return + if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) + usr << "\red You don't have the dexterity to do this!" + return + var/turf/T = src.loc + if (!( istype(T, /turf) )) + return + + var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 + turf_total = max(turf_total, 1) + usr.show_message("\blue Results:", 1) + var/t = "" + var/t1 = turf_total / CELLSTANDARD * 100 + if ((90 < t1 && t1 < 110)) + usr.show_message(text("\blue Air Pressure: []%", t1), 1) + else + usr.show_message(text("\blue Air Pressure:\red []%", t1), 1) + t1 = T.n2 / turf_total * 100 + t1 = round(t1, 0.0010) + if ((60 < t1 && t1 < 80)) + t += text("Nitrogen: [] ", t1) + else + t += text("Nitrogen: [] ", t1) + t1 = T.oxygen / turf_total * 100 + t1 = round(t1, 0.0010) + if ((20 < t1 && t1 < 24)) + t += text("Oxygen: [] ", t1) + else + t += text("Oxygen: [] ", t1) + t1 = T.poison / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 0.5) + t += text("Plasma: [] ", t1) + else + t += text("Plasma: [] ", t1) + t1 = T.co2 / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 1) + t += text("CO2: [] ", t1) + else + t += text("CO2: [] ", t1) + t1 = T.sl_gas / turf_total * 100 + t1 = round(t1, 0.0010) + if (t1 < 5) + t += text("NO2: []", t1) + else + t += text("NO2: []", t1) + usr.show_message(t, 1) + usr.show_message(text("\blue \t Temperature: []°C", T.temp - T0C), 1) + src.add_fingerprint(usr) + return + + + + +/** + * Indicator -- Subtype of alarm, used to indicated air quality in the airtunnel + * + */ + +obj/machinery/alarm/indicator + name = "indicator" + icon = 'airtunnel.dmi' + icon_state = "indicator" + + + // Monitors location air quality and changes icon_state to reflect it + // Also sets airtunnel datum air status + + process() + + if(stat & NOPOWER) + icon_state = "indicator-p" + return + + var/safe = 1 + var/turf/T = src.loc + if (!( istype(T, /turf) )) + return + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 + turf_total = max(turf_total, 1) + var/t1 = turf_total / CELLSTANDARD * 100 + if (!( (90 < t1 && t1 < 110) )) + safe = 0 + t1 = T.oxygen / turf_total * 100 + if (!( (20 < t1 && t1 < 30) )) + safe = 0 + src.icon_state = text("indicator[]", safe) + SS13_airtunnel.air_stat = safe + return diff --git a/main-src/Code/Machinery/at_indicator.dm b/main-src/Code/Machinery/at_indicator.dm new file mode 100644 index 0000000..fe9bcae --- /dev/null +++ b/main-src/Code/Machinery/at_indicator.dm @@ -0,0 +1,69 @@ +/** + * at_indicator -- Provides a visual indication of airtunnel status + * + */ + +obj/machinery/at_indicator + name = "Air Tunnel Indicator" + icon = 'airtunnel.dmi' + icon_state = "reader00" + anchored = 1.0 + + process() + if(! (stat & (BROKEN|NOPOWER)) ) + use_power(5, ENVIRON) + src.update_icon() + return + + + // update the icon_state, depending on the status of the airtunnel + + proc/update_icon() + + if(stat & (BROKEN|NOPOWER) ) + icon_state = "reader_broken" + return + + var/status = 0 + if (SS13_airtunnel.operating == 1) + status = "r" + else if (SS13_airtunnel.operating == 2) + status = "e" + else + var/obj/move/airtunnel/connector/C = pick(SS13_airtunnel.connectors) + if (C.current == C) + status = 0 + else + if (!( C.current.next )) + status = 2 + else + status = 1 + src.icon_state = text("reader[][]", (SS13_airtunnel.siphon_status == 2 ? "1" : "0"), status) + return + + + // called when object is inside an explosion + + ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + src.icon_state = "reader_broken" + stat |= BROKEN + if(3.0) + if (prob(25)) + src.icon_state = "reader_broken" + stat |= BROKEN + else + return + + // called when object is attacked by a blob + + blob_act() + if (prob(50)) + src.icon_state = "reader_broken" + stat |= BROKEN + diff --git a/main-src/Code/Machinery/autolathe.dm b/main-src/Code/Machinery/autolathe.dm new file mode 100644 index 0000000..aeaa649 --- /dev/null +++ b/main-src/Code/Machinery/autolathe.dm @@ -0,0 +1,173 @@ +/* + * Autolathe - Constructs objects from stocks of metal and glass + * + * Note: Currently only semi-implemented + * + */ + +obj/machinery/autolathe + + name = "Autolathe" + icon = 'stationobjs.dmi' + icon_state = "autolathe" + anchored = 1 + var + m_amount = 0 // amount (cc) of metal loaded + g_amount = 0 // amount (cc) of glass loaded + operating = 0 // true if the machine is operating + opened = 0 // true if the machine is open (not fully implemented?) + temp = null // temporary intaction window text + + + // Feed in metal or glass stock, or open the autolathe + + attackby(obj/item/weapon/O, mob/user) + + if (istype(O, /obj/item/weapon/sheet/metal)) + if (src.m_amount < 150000.0) + src.m_amount += O:height * O:width * O:length * 1000000.0 + O:amount-- + if (O:amount < 1) + del(O) + + else if (istype(O, /obj/item/weapon/sheet/glass)) + if (src.g_amount < 75000.0) + src.g_amount += O:height * O:width * O:length * 1000000.0 + O:amount-- + if (O:amount < 1) + del(O) + + else if (istype(O, /obj/item/weapon/screwdriver)) + if (!( src.operating )) + src.opened = !( src.opened ) + src.icon_state = text("autolathe[]", (src.opened ? "f" : null)) + else + user << "\red The machine is in use. You can not maintain it now." + else + spawn( 0 ) + src.attack_hand(user) + return + + + // Monkey interact same a human + + attack_paw(mob/user) + return src.attack_hand(user) + + + // Open interaction window + // Currenty only pipe pieces can be made + + attack_hand(mob/user) + + if(stat & (BROKEN|NOPOWER)) + return + + var/dat + if (src.temp) + dat = text("[]

Clear Screen", src.temp, src) + else + dat = text("Metal Amount: [] cm3 (MAX: 150,000)
\nGlass Amount: [] cm3 (MAX: 75,000)
", src.m_amount, src.g_amount) + var/list/L = list( ) + + L["pipe"] = "Straight pipe (7500 cc)" + L["bpipe"] = "Bent pipe (7500 cc)" + L["hepipe"] = "Heat-exchange pipe (10000 cc)" + L["bhepipe"] = "Bent heat-exchange pipe (10000 cc)" + L["contr"] = "Pipe connector (10000 cc)" + L["manif"] = "Pipe manifold (15000 cc)" + L["junct"] = "Pipe junction (10000 cc)" + L["vent"] = "Pipe vent (10000 cc)" + /* L["screwdriver"] = "Make Screwdriver {40 cc}" + L["wirecutters"] = "Make Wirecutters {80 cc}" + L["wrench"] = "Make Wrench {150 cc}" + L["crowbar"] = "Make Crowbar {150 cc}" + L["screw"] = "Make Screw (1) {3 cc}" + L["5screws"] = "Make Screws (5) {14 cc}" + L["rod_t"] = "Make Rod (1x20) {20 cc}" + L["rod_l"] = "Make Rod (5x250) {1250 cc}" + L["grille_1"] = "Make Grille (250x250x1) {27345 cc}" + L["sheet_1"] = "Make Sheet (20x10x.01) {2 cc}" + L["sheet_2"] = "Make Sheet (30x10x.01) {3 cc}" + L["sheet_3"] = "Make Sheet (30x20x.01) {6 cc}" + L["sheet_4"] = "Make Sheet (30x30x.01) {9 cc}" + L["sheet_5"] = "Make Sheet (62.5x62.5x4) {15625 cc}" */ + + + for(var/t in L) + dat += "[L["[t]"]]
" + user << browse("Autolathe Control Panel[dat]", "window=autolathe") + return + + // Called by topic links from interaction window + // Make the chosen item + + Topic(href, href_list) + ..() + + + if ((usr.stat || usr.restrained())) + return + if(operating || (stat & NOPOWER)) + return + if ( get_dist(src, usr) <= 1 && istype(src.loc, /turf) ) + usr.machine = src + src.add_fingerprint(usr) + + if (href_list["temp"]) + src.temp = null + + if(href_list["make"]) + + var/list/C = list() + C["pipe"] = 7500 + C["bpipe"] = 7500 + C["hepipe"] = 10000 + C["bhepipe"] = 10000 + C["contr"] = 10000 + C["manif"] = 15000 + C["junct"] = 10000 + C["vent"] = 10000 + + var/item = href_list["make"] + var/cost = C[item] + + if(m_amount >= cost) + m_amount -= cost + operate() + switch(item) + if("pipe") + new /obj/item/weapon/pipe{ ptype = 0 }(src.loc) + if("bpipe") + new /obj/item/weapon/pipe{ ptype = 1 }(src.loc) + if("hepipe") + new /obj/item/weapon/pipe{ ptype = 2 }(src.loc) + if("bhepipe") + new /obj/item/weapon/pipe{ ptype = 3 }(src.loc) + if("contr") + new /obj/item/weapon/pipe{ ptype = 4 }(src.loc) + if("manif") + new /obj/item/weapon/pipe{ ptype = 5 }(src.loc) + if("junct") + new /obj/item/weapon/pipe{ ptype = 6 }(src.loc) + if("vent") + new /obj/item/weapon/pipe{ ptype = 7 }(src.loc) + + + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + return + + // Perform operation animation + + proc/operate() + + use_power(500) + operating = 1 + flick("autolathe_c", src) + sleep(16) + flick("autolathe_o", src) + sleep(8) + operating = 0 diff --git a/main-src/Code/Machinery/camera.dm b/main-src/Code/Machinery/camera.dm new file mode 100644 index 0000000..f292d88 --- /dev/null +++ b/main-src/Code/Machinery/camera.dm @@ -0,0 +1,49 @@ +/** + * camera -- A security camera, allows remote viewing of its location from a security computer + * + * Note: Cameras do not use or need power. + * + */ + +obj/machinery/camera + name = "Security Camera" + icon = 'stationobjs.dmi' + icon_state = "camera" + anchored = 1 + var + network = "SS13" // must match the network var of a security computer to allow viewing from that computer + c_tag = null // the displayed name of the camera when picking from a security computer + status = 1.0 // 0 if camera has been disabled + invuln = null // if true, camera will not be affected by explosions + + + // attacking with wirecutters allows the camera to be disabled/enabled + + attackby(obj/item/weapon/W, mob/user) + + if (istype(W, /obj/item/weapon/wirecutters)) + src.status = !( src.status ) + if (!( src.status )) + for(var/mob/O in viewers(user, null)) + O.show_message("\red [user] has deactivated [src]!", 1) + src.icon_state = "camera1" + else + for(var/mob/O in viewers(user, null)) + O.show_message("\red [user] has reactivated [src]!", 1) + src.icon_state = "camera" + return + + // called when object is in an explosion + // if invuln flag is set, explosion has no effect + + ex_act(severity) + if(src.invuln) + return + else + ..(severity) + return + + // blob attacks have no effect + + blob_act() + return diff --git a/main-src/Code/Machinery/cell_charger.dm b/main-src/Code/Machinery/cell_charger.dm new file mode 100644 index 0000000..b5b1ca9 --- /dev/null +++ b/main-src/Code/Machinery/cell_charger.dm @@ -0,0 +1,100 @@ +/** + * cell_charger -- Allows the charging of power cell (as used in APCs). + * + * Uses an overlay to display the current charge level of the inserted cell + * + */ + +obj/machinery/cell_charger + name = "cell charger" + desc = "A charging unit for power cells." + icon = 'power.dmi' + icon_state = "ccharger0" + anchored = 1 + var + obj/item/weapon/cell/charging = null // the cell inserted for charging (or null if none) + chargelevel = -1 // the (cached) charge indicator level (0-4) + // set -1 to force the indicator to be updated + + // insert a cell into the charger, unless there is already one inside + + attackby(obj/item/weapon/W, mob/user) + + if(stat & BROKEN) return + + if(istype(W, /obj/item/weapon/cell)) + if(charging) + user << "There is already a cell in the charger." + return + else + user.drop_item() + W.loc = src + charging = W + user << "You insert the cell into the charger." + chargelevel = -1 + + + updateicon() + + + // updates the icon_state and overlays to reflect a whether a cell is inserted and the charge state + + proc/updateicon() + + icon_state = "ccharger[charging ? 1 : 0]" + + if(charging && !(stat & (BROKEN|NOPOWER)) ) + + var/newlevel = round( charging.percent() * 4.0 / 99 ) + + if(chargelevel != newlevel) // displayed charge level is cached, so as to only update the overlay when needed + + overlays = null + overlays += image('power.dmi', "ccharger-o[newlevel]") + + chargelevel = newlevel + + else + overlays = null + + + // removes the cell from the charger (if a cell is inserted) + + attack_hand(mob/user) + + add_fingerprint(user) + + if(stat & BROKEN) return + + if(charging) + charging.loc = usr + charging.layer = 20 + if (user.hand ) + user.l_hand = charging + else + user.r_hand = charging + + charging.add_fingerprint(user) + charging.updateicon() + + src.charging = null + user << "You remove the cell from the charger." + chargelevel = -1 + updateicon() + + // every cycle, increase the charge level of cell if inserted + + process() + + if(!charging || (stat & (BROKEN|NOPOWER)) ) + return + + var/newch = charging.charge + 5 + newch = min(newch, charging.maxcharge) // limit to maximum charge capacity of the cell + + use_power((newch - charging.charge) / CELLRATE) + charging.charge = newch + updateicon() + + + diff --git a/main-src/Code/Machinery/circulator.dm b/main-src/Code/Machinery/circulator.dm new file mode 100644 index 0000000..03ae634 --- /dev/null +++ b/main-src/Code/Machinery/circulator.dm @@ -0,0 +1,217 @@ +/* + * Circulator - A gas pump and heat-exchanger + * Part of the main engine generator system + * + * Machine contains two gas reservoirs. Gas flows from the pipe to the south into the first + * Is pumped from the first reservoir to the second at "rate" + * Then flows out of the second reservoir into the pipe at the north + */ + +obj/machinery/circulator + name = "circulator/heat exchanger" + desc = "A gas circulator pump and heat exchanger." + icon = 'pipes.dmi' + icon_state = "circ1-off" + p_dir = 3 // pipes connect to north & south directions + anchored = 1.0 + density = 1 + capmult = 1 // Since we have a separate reservoir connected to each node, capmult is 1 + + var + side = 1 // Ciculators can be to the left or to the right of a generator. 1=left 2=right + status = 0 // 0 = off, 1 = on, 2 = slow + rate = 0 // the gas transfer rate between the two internal reservoirs + maxrate = 400000 // the maximum transfer rate + + obj/substance/gas/gas1 = null // the first gas reservoir, connected to node1 (south) + obj/substance/gas/ngas1 = null + + obj/substance/gas/gas2 = null // the second gas reservoir, connected to node 2 (north) + obj/substance/gas/ngas2 = null + + capacity = 6000000.0 // the maximum gas capacity of each reservoir + + obj/machinery/node1 = null // the physical pipe object to the south + obj/machinery/node2 = null // the physical pipe object to the north + + obj/machinery/vnode1 // the pipeline object to the south + obj/machinery/vnode2 // the pipeline object to the north + + + + + // Create a new circulator object + + New() + ..() + gas1 = new/obj/substance/gas(src) + gas1.maximum = capacity + gas2 = new/obj/substance/gas(src) + gas2.maximum = capacity + + ngas1 = new/obj/substance/gas() + ngas2 = new/obj/substance/gas() + + gasflowlist += src + + updateicon() + + + // Find the pipe connections to the north and south + // Set the node & vnode values + + buildnodes() + + var/turf/TS = get_step(src, SOUTH) + var/turf/TN = get_step(src, NORTH) + + for(var/obj/machinery/M in TS) + + if(M && (M.p_dir & 1)) + node1 = M + break + + for(var/obj/machinery/M in TN) + + if(M && (M.p_dir & 2)) + node2 = M + break + + + if(node1) vnode1 = node1.getline() + + if(node2) vnode2 = node2.getline() + + + // Set the current status and pumping rate (as a percentage) + // Called by the generator object + + proc/control(var/on, var/prate) + + rate = prate/100*maxrate + + if(status == 1) + if(!on) + status = 2 // switching from on to off makes the generator slow down for 3 seconds + spawn(30) + if(status == 2) // then switch to off + status = 0 + updateicon() + else if(status == 0) + if(on) + status = 1 + else // status ==2 + if(on) + status = 1 + + updateicon() + + + // Update the icon state, depending on the circulator settings + + proc/updateicon() + + if(stat & NOPOWER) + icon_state = "circ[side]-p" + return + + var/is + switch(status) + if(0) + is = "off" + if(1) + is = "run" + if(2) + is = "slow" + + icon_state = "circ[side]-[is]" + + + // When the power of the area changes, to standard processing then update the icon state + + power_change() + ..() + updateicon() + + + // Gas flow - update the gas reservoirs with the new values as set in process() + + gas_flow() + + gas1.replace_by(ngas1) + gas2.replace_by(ngas2) + + + // Main process. Pump gas between the reservoirs, then do standard gas flow to the connected nodes + + process() + + // if operating, pump from resv1 to resv2 + + if(! (stat & NOPOWER) ) // only do circulator step if powered; still do rest of gas flow at all times + if(status==1 || status==2) + gas2.transfer_from(gas1, status==1? rate : rate/2) + use_power(rate/capacity * 100) + ngas1.replace_by(gas1) + ngas2.replace_by(gas2) + + + // now do standard gas flow process + + var/delta_gt + + if(vnode1) + delta_gt = FLOWFRAC * ( vnode1.get_gas_val(src) - gas1.tot_gas() / capmult) + calc_delta( src, gas1, ngas1, vnode1, delta_gt) + else + leak_to_turf(1) + + if(vnode2) + delta_gt = FLOWFRAC * ( vnode2.get_gas_val(src) - gas2.tot_gas() / capmult) + calc_delta( src, gas2, ngas2, vnode2, delta_gt) + else + leak_to_turf(2) + + + // If nothing connected to either pipe node, leak the gas to the turf instead + + proc/leak_to_turf(var/port) + + var/turf/T + + switch(port) + if(1) + T = get_step(src, SOUTH) + if(2) + T = get_step(src, NORTH) + + if(T.density) + T = src.loc + if(T.density) + return + + switch(port) + if(1) + flow_to_turf(gas1, ngas1, T) + if(2) + flow_to_turf(gas2, ngas2, T) + + + // Get the current gas fill level. Note since we have two reservoirs, value depends on which node is enquiring + + get_gas_val(from) + + if(from == vnode1) + return gas1.tot_gas()/capmult + else + return gas2.tot_gas()/capmult + + + // Get the gas reservoir object connected to node "from" + + get_gas(from) + + if(from == vnode1) + return gas1 + else + return gas2 diff --git a/main-src/Code/Machinery/connector.dm b/main-src/Code/Machinery/connector.dm new file mode 100644 index 0000000..bd424a0 --- /dev/null +++ b/main-src/Code/Machinery/connector.dm @@ -0,0 +1,137 @@ +/* + * Connector -- Machine that links atmoalter machines (canisters, siphons, heaters) to a pipe network. + * + * Connection is performed by attacking the device to be connected with a wrench (or screwdriver) + */ + + +/obj/machinery/connector + name = "connector" + icon = 'pipes.dmi' + desc = "A connector for gas canisters." + icon_state = "connector" + anchored = 1 + p_dir = 2 + capmult = 2 + + var + obj/machinery/node = null // the pipe-connected machine or pipe + obj/machinery/vnode = null // the pipe-connected pipeline, if node is a pipe + + obj/machinery/atmoalter/connected = null // the connected device (canister, etc.), or null if none + + obj/substance/gas/gas = null // the gas reservoir + obj/substance/gas/ngas = null + + capacity = 6000000.0 // the capacity of the gas reservoir. This value is actually used, + // unlike most pipe-related objects + + + // Create a new connector, create gas reservoir. + // Pipe direction (p_dir) is same as icon dir + //If a compatible machine is at the same location, and its c_status (pipe valve) is not 0, set the machine as connected + + New() + ..() + + p_dir = dir + + gas = new/obj/substance/gas(src) + gas.maximum = capacity + ngas = new/obj/substance/gas() + + gasflowlist += src + spawn(5) // wait until world has finished loading + var/obj/machinery/atmoalter/A = locate(/obj/machinery/atmoalter, src.loc) // find compatible machine in same loc + + if(A && A.c_status != 0) // c_status=0 -> disconnected + connected = A + A.anchored = 1 // ensure canister etc. is anchored if connected + + + // Find the machine/pipe that connects to this one + + buildnodes() + + var/turf/T = get_step(src.loc, src.dir) + var/fdir = turn(src.p_dir, 180) + + for(var/obj/machinery/M in T) + if(M.p_dir & fdir) + src.node = M + break + + if(node) vnode = node.getline() + + + return + + // Examine verb for the connector + + examine() + set src in oview(1) + + if (usr.stat) + return + + if(connected) + usr << "A pipe connector for gas equipment. It is connected to \an [connected.name]." + else + usr << "A pipe connector for gas equipment. It is unconnected." + + + + // Return the gas fullness value + + get_gas_val(from) + return gas.tot_gas()/capmult + + + // Return the gas reservoir + + get_gas(from) + return gas + + + // Update gas values with the new ones calculated in process() + + gas_flow() + gas.replace_by(ngas) + + + // Timed process. Calculate gas flow to connected node. + // If a device is connected (canister etc.), transfer gas to/from reservoir depending on device valve settings. + + process() + var/delta_gt + + if(vnode) + + delta_gt = FLOWFRAC * ( vnode.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode, delta_gt)//, dbg) + else + leak_to_turf() + + if(connected) + var/amount + if(connected.c_status == 1) // canister set to release + + amount = min(connected.c_per, capacity - gas.tot_gas() ) // limit to space in connector + amount = max(0, min(amount, connected.gas.tot_gas() ) ) // limit to amount in canister, or 0 + ngas.transfer_from( connected.gas, amount) + else if(connected.c_status == 2) // canister set to accept + + amount = min(connected.c_per, connected.gas.maximum - connected.gas.tot_gas()) //limit to space in canister + amount = max(0, min(amount, gas.tot_gas() ) ) // limit to amount in connector, or 0 + + connected.gas.transfer_from( ngas, amount) + + + // If pipe-connected node is missing, leak the gas to turf + + proc/leak_to_turf() + var/turf/T = get_step(src, dir) + + if(T && !T.density) + flow_to_turf(gas, ngas, T) + diff --git a/main-src/Code/Machinery/dispenser.dm b/main-src/Code/Machinery/dispenser.dm new file mode 100644 index 0000000..95675d6 --- /dev/null +++ b/main-src/Code/Machinery/dispenser.dm @@ -0,0 +1,124 @@ +/* + * dispenser - A dispenser unit for oxygen and plasma tanks. + * + * Note: tanks cannot be reinserted. + */ + +obj/machinery/dispenser + desc = "A simple yet bulky one-way storage device for gas tanks. Holds 10 plasma and 10 oxygen tanks." + name = "Tank Storage Unit" + icon = 'turfs2.dmi' + icon_state = "dispenser" + density = 1 + anchored = 1 + var + o2tanks = 10.0 // number of oxygen tanks + pltanks = 10.0 // number of plasma tanks + + + // if unit powered, use a small amount of power + + process() + if(stat & NOPOWER) + return + use_power(5) + + + // attack by monkey same as attack by human + + attack_paw(mob/user) + return src.attack_hand(user) + + // attack by human - show window to dispense a tank of either kind + + attack_hand(mob/user) + + user.machine = src + var/dat = text("Loaded Tank Dispensing Unit
\nOxygen: [] []
\nPlasma: [] []
\n
", src.o2tanks, (src.o2tanks ? text("
Dispense", src) : "empty"), src.pltanks, (src.pltanks ? text("Dispense", src) : "empty")) + user << browse(dat, "window=dispenser") + return + + // dispense a tank when topic link is clicked on from interaction window + + Topic(href, href_list) + ..() + if (usr.stat || usr.restrained() ) + return + if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) + usr << "\red You don't have the dexterity to do this!" + return + if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) + usr.machine = src + + if (href_list["oxygen"]) + if (text2num(href_list["oxygen"])) + if (src.o2tanks > 0) + use_power(5) + new /obj/item/weapon/tank/oxygentank( src.loc ) + src.o2tanks-- + if (istype(src.loc, /mob)) + attack_hand(src.loc) + + else if (href_list["plasma"]) + if (text2num(href_list["plasma"])) + if (src.pltanks > 0) + use_power(5) + new /obj/item/weapon/tank/plasmatank( src.loc ) + src.pltanks-- + if (istype(src.loc, /mob)) + attack_hand(src.loc) + + src.add_fingerprint(usr) + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + + usr << browse(null, "window=dispenser") + return + return + + + // explosion, blob and meteor-hit actions - have a chance to dump all held tanks + + ex_act(severity) + switch(severity) + if(1.0) + del(src) + return + if(2.0) + if (prob(50)) + del(src) + return + if(3.0) + if (prob(25)) + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygentank( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasmatank( src.loc ) + src.pltanks-- + else + return + + blob_act() + + if (prob(25)) + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygentank( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasmatank( src.loc ) + src.pltanks-- + del(src) + + meteorhit() + + while(src.o2tanks > 0) + new /obj/item/weapon/tank/oxygentank( src.loc ) + src.o2tanks-- + while(src.pltanks > 0) + new /obj/item/weapon/tank/plasmatank( src.loc ) + src.pltanks-- + del(src) + return diff --git a/main-src/Code/Machinery/door_control.dm b/main-src/Code/Machinery/door_control.dm new file mode 100644 index 0000000..83a39b6 --- /dev/null +++ b/main-src/Code/Machinery/door_control.dm @@ -0,0 +1,61 @@ +/* + * Door_control -- A remote control for opening/closing poddoors + * + * + */ + +obj/machinery/door_control + name = "remote door control" + icon = 'stationobjs.dmi' + icon_state = "doorctrl0" + desc = "A remote control switch for a door." + anchored = 1.0 + var + id = null // id must match that of the poddoor to operate + + + // attack by monkey same as human + + attack_paw(mob/user) + return src.attack_hand(user) + + + // attack by an item same as empty hand + + attackby(nothing, mob/user) + return src.attack_hand(user) + + // attack by hand, toggle all poddoors with same id + + attack_hand(mob/user) + + if(stat & NOPOWER) + return + use_power(5) + icon_state = "doorctrl1" + + for(var/obj/machinery/door/poddoor/M in machines) + if (M.id == src.id) + if (M.density) + spawn( 0 ) + M.openpod() + return + else + spawn( 0 ) + M.closepod() + return + + spawn(15) + if(!(stat & NOPOWER)) + icon_state = "doorctrl0" + + + // area power changed, set the icon_state to unpowered + + power_change() + ..() + if(stat & NOPOWER) + icon_state = "doorctrl-p" + else + icon_state = "doorctrl0" + diff --git a/main-src/Code/Machinery/firealarm.dm b/main-src/Code/Machinery/firealarm.dm new file mode 100644 index 0000000..d7771f9 --- /dev/null +++ b/main-src/Code/Machinery/firealarm.dm @@ -0,0 +1,188 @@ +/* + * Firealarm - Machine that controls firealarm triggering in an area + * + * When fire present, triggers flashing area icon and closes firedoors. + */ + +obj/machinery/firealarm + name = "firealarm" + icon = 'items.dmi' + icon_state = "firealarm" + anchored = 1 + var + detecting = 1 // true if the alarm is working, false if disabled + //working = 1 // unused + time = 10.0 // seconds left until alarm triggered + timing = 0 // true if counting down timer + + + // Called if the location turf is on fire; triggers the alarm if so + + burn(fi_amount) + if(stat & NOPOWER) + return + if(src.detecting) src.alarm() + return + + + // Attack with item, if wirecutters connect/disconnect fire detector + // Otherwise, trigger the alarm + + attackby(obj/item/weapon/W, mob/user) + if (istype(W, /obj/item/weapon/wirecutters)) + src.detecting = !( src.detecting ) + if (src.detecting) + viewers(user, null) << "\red [user] has reconnected [src]'s detecting unit!" + else + viewers(user, null) << "\red [user] has disconnected [src]'s detecting unit!" + else + src.alarm() + src.add_fingerprint(user) + return + + + // Timed process. Countdown if set to trigger after time. + + process() + + if(stat & NOPOWER) + return + + use_power(10, ENVIRON) + + if (src.timing) + if (src.time > 0) + src.time = round(src.time) - 1 + else + alarm() + src.time = 0 + src.timing = 0 + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + return + + + // When area power state changes, disable alarm if no power in ENVIRON channel + + power_change() + if(powered(ENVIRON)) + stat &= ~NOPOWER + icon_state = "firealarm" + else + spawn(rand(0,15)) + stat |= NOPOWER + icon_state = "firealarm-p" + + // Monkey interact same as human + + attack_paw(mob/user) + return src.attack_hand(user) + + + // Interact and show window + // Garbled text if a monkey + + attack_hand(mob/user) + + if(user.stat || stat&NOPOWER) return + + user.machine = src + var/area/A = src.loc + var/d1 + var/d2 + if (istype(user, /mob/human)) + A = A.loc + + if (A.fire) + d1 = "Reset - Lockdown" + else + d1 = "Alarm - Lockdown" + if (src.timing) + d2 = "Stop Time Lock" + else + d2 = "Initiate Time Lock" + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("Fire alarm []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=firealarm") + else + A = A.loc + if (A.fire) + d1 = text("[]", src, stars("Reset - Lockdown")) + else + d1 = text("[]", src, stars("Alarm - Lockdown")) + if (src.timing) + d2 = text("[]", src, stars("Stop Time Lock")) + else + d2 = text("[]", src, stars("Initiate Time Lock")) + var/second = src.time % 60 + var/minute = (src.time - second) / 60 + var/dat = text("[] []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", stars("Fire alarm"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) + user << browse(dat, "window=firealarm") + return + + + // Handle topic links from interaction window + + Topic(href, href_list) + ..() + if (usr.stat || stat&NOPOWER) + return + + if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) + usr.machine = src + + if (href_list["reset"]) + src.reset() + + else if (href_list["alarm"]) + src.alarm() + + else if (href_list["time"]) + src.timing = text2num(href_list["time"]) + + else if (href_list["tp"]) + var/tp = text2num(href_list["tp"]) + src.time += tp + src.time = min(max(round(src.time), 0), 120) + + for(var/mob/M in viewers(1, src)) + if ((M.client && M.machine == src)) + src.attack_hand(M) + src.add_fingerprint(usr) + else + usr << browse(null, "window=firealarm") + return + return + + + // Reset the alarm. Area icon updated, all firedoors in area opened. + + proc/reset() + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + A.fire = 0 + A.mouse_opacity = 0 + A.updateicon() + + for(var/obj/machinery/door/firedoor/D in A) + if (D.density) + spawn( 0 ) + D.openfire() + return + return + + + // Trigger the alarm. Calls area/firealert() + + proc/alarm() + var/area/A = src.loc + A = A.loc + if (!( istype(A, /area) )) + return + A.firealert() + return diff --git a/main-src/Code/Machinery/gas_sensor.dm b/main-src/Code/Machinery/gas_sensor.dm new file mode 100644 index 0000000..d69e53a --- /dev/null +++ b/main-src/Code/Machinery/gas_sensor.dm @@ -0,0 +1,55 @@ +/* + * Gas_sensor - Provides remote reading of the current gas conditions at location + * Read from engine computers. + * + */ + +obj/machinery/gas_sensor + name = "gas sensor" + icon = 'stationobjs.dmi' + icon_state = "gsensor" + desc = "A remote sensor for atmospheric gas composition." + anchored = 1 + var + id // Engine computer must have matching id + + + // Return a string showing gas values & temperature at object location + + proc/sense_string() + + var/t = "" + + var/turf/T = src.loc + + var/turf_total = T.tot_gas() + + var/t1 = add_tspace("[round(turf_total / CELLSTANDARD * 100, 0.1)]%",6) + t += "
Pressure: [t1] Temperature: [round(T.temp - T0C,0.1)]°C
" + + if(turf_total == 0) + t+="O2: 0 N2: 0 CO2: 0>
Plasma: 0 N20: 0" + else + t1 = add_tspace(round(T.oxygen/turf_total * 100, 0.1),5) + + t += "O2: [t1] " + + t1 = add_tspace(round(T.n2/turf_total * 100, 0.1),5) + + t += "N2: [t1] " + + t1 = add_tspace(round(T.co2/turf_total * 100, 0.01),5) + + t += "CO2: [t1]
" + + t1 = add_tspace(round(T.poison/turf_total * 100, 0.001),5) + + t += "Plasma: [t1] " + + t1 = add_tspace(round(T.sl_gas/turf_total * 100, 0.001),5) + + t += "N2O: [t1]" + + t += "
" + + return t diff --git a/main-src/Code/Machinery/igniter.dm b/main-src/Code/Machinery/igniter.dm new file mode 100644 index 0000000..29a1309 --- /dev/null +++ b/main-src/Code/Machinery/igniter.dm @@ -0,0 +1,68 @@ +/* + * Igniter -- Togglable igniter, as used in the engine. + * + * Sets turf location on fire if enough plasma is present + * + */ + +obj/machinery/igniter + + name = "igniter" + icon = 'stationobjs.dmi' + icon_state = "igniter1" + anchored = 1.0 + var + on = 1.0 // true if the igniter is turned on + + + // Initializes the icon state + + New() + ..() + icon_state = "igniter[on]" + + + // Called if area loses/gains power + // sets the icon_state off if no power available + + power_change() + ..() + if(!( stat & NOPOWER) ) + icon_state = "igniter[src.on]" + else + icon_state = "igniter0" + + + // monkey attack same as human if in monkey mode + + attack_paw(mob/user as mob) + if ((ticker && ticker.mode == "monkey")) + return src.attack_hand(user) + + + // When attacked, toggle the igniter on/off + + attack_hand(mob/user as mob) + + ..() + add_fingerprint(user) + if(stat & NOPOWER) return + + use_power(50) + src.on = !( src.on ) + src.icon_state = text("igniter[]", src.on) + return + + + // if turned on (and powered), ignite the turf if enough plasma present + + process() + + if (src.on && !(stat & NOPOWER) ) + var/turf/T = src.loc + if (locate(/obj/move, T)) + T = locate(/obj/move, T) + if (T.firelevel < 900000.0) + T.firelevel = T.poison + + diff --git a/main-src/Code/Machinery/injector.dm b/main-src/Code/Machinery/injector.dm new file mode 100644 index 0000000..9e3a361 --- /dev/null +++ b/main-src/Code/Machinery/injector.dm @@ -0,0 +1,32 @@ +/* + * Injector -- allows transfer of gas across a wall when attacked by a gas tank + * + * + */ + +obj/machinery/injector + name = "injector" + icon = 'stationobjs.dmi' + icon_state = "injector" + density = 1 + anchored = 1 + flags = WINDOW // Unsure why flagged as a window + + + // When attacked by a tank item, transfer the tank's gas contents to the turf behind the injector + + attackby(var/obj/item/weapon/W, var/mob/user) + + if(stat & NOPOWER) + return + use_power(25) + + var/obj/item/weapon/tank/ptank = W + if (!( istype(ptank, /obj/item/weapon/tank) )) + return + + var/turf/T = get_step(src.loc, get_dir(user, src)) + ptank.gas.turf_add(T, -1.0) + src.add_fingerprint(user) + return + diff --git a/main-src/Code/Machinery/inlet.dm b/main-src/Code/Machinery/inlet.dm new file mode 100644 index 0000000..2cc18cd --- /dev/null +++ b/main-src/Code/Machinery/inlet.dm @@ -0,0 +1,103 @@ +/* + * Inlet -- Pipe inlet object + * Equalizes gas content between its turf and the pipe. + * Thus can also act as an outlet if the pipe has more gas in it than the turf. + * + * Similar to /obj/machinery/vent, except that vents flow only one way (from pipe to the turf) + */ + +obj/machinery/inlet + name = "inlet" + icon = 'pipes.dmi' + icon_state = "inlet" + desc = "A gas pipe inlet." + anchored = 1 + p_dir = 2 // default pipe direction is south + capmult = 2 + + var + obj/machinery/node // the connected object + obj/machinery/vnode // the connected pipeline object (if node is a pipe) + + obj/substance/gas/gas // the gas reservoir + obj/substance/gas/ngas // the new gas reservoir (as calculated in process()) + + capacity = 6000000 // nominal gas capacity; not actually used + + + // Create a new inlet. Pipe connection direction is set same as icon direction, thus p_dir does not need to be set + // when placing inlet on map. Create gas reservoir and register self with the gasflowlist + + New() + + ..() + p_dir = dir + gas = new/obj/substance/gas(src) + gas.maximum = capacity + ngas = new/obj/substance/gas() + gasflowlist += src + + + // Find the connected pipe or machine + + buildnodes() + + var/turf/T = get_step(src.loc, src.dir) + var/fdir = turn(src.p_dir, 180) + + for(var/obj/machinery/M in T) + if(M.p_dir & fdir) + src.node = M + break + + if(node) vnode = node.getline() + + return + + + // Returns the gas fullness value. Capmult is 2 for inlets because they in effect have two connections: the pipe, and the turf + + get_gas_val(from) + return gas.tot_gas()/capmult + + + // Return the internal gas reservoir + + get_gas(from) + return gas + + + // After all machine process()es in world are complete, update the current gas levels with the new calculated levels + + gas_flow() + gas.replace_by(ngas) + + + // Timed process. Calculate gas flow to and from the turf, and to and from the connected pipe + + process() + var/delta_gt + + var/turf/T = src.loc + + if(T && !T.density) + flow_to_turf(gas, ngas, T) // act as gas leak at the turf we are located on + + if(vnode) + delta_gt = FLOWFRAC * ( vnode.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode, delta_gt) + else + leak_to_turf() + + + // If no node is present, leak the contents to the turf position the node would be. + // note this is a leak from the node, not the inlet itself + // thus acts as a link between the inlet turf and the turf in step(dir) + + proc/leak_to_turf() + + var/turf/T = get_step(src, dir) + if(T && !T.density) + flow_to_turf(gas, ngas, T) + + diff --git a/main-src/Code/Machinery/junction.dm b/main-src/Code/Machinery/junction.dm new file mode 100644 index 0000000..5fa13a0 --- /dev/null +++ b/main-src/Code/Machinery/junction.dm @@ -0,0 +1,113 @@ +/* + * Junction - a junction between standard and heat-exchanger pipe. + * + */ + +obj/machinery/junction + name = "junction" + icon = 'junct-pipe.dmi' + icon_state = "junction" + desc = "A junction between regular and heat-exchanger pipework." + anchored = 1 + dir = 2 + p_dir = 1 // junctions are unique in that the have both p_dir (standard pipe) and h_dir (h/e pipe) set + h_dir = 2 // + capmult = 2 + + var/obj/substance/gas/gas = null // the gas reservoir + var/obj/substance/gas/ngas = null + + var/obj/machinery/node1 = null // the node connecting to the h/e pipe + var/obj/machinery/node2 = null // the node connecting to the standard pipe + + var/obj/machinery/vnode1 // the pipeline object of the h/e pipe + var/obj/machinery/vnode2 // the pipeline object of the standard pipe + + var/capacity = 6000000 // nominal gas capacity + + + // Create a new junction, create gas reservoir + // Calculated p_dir and h_dir from the icon dir + + New() + ..() + gas = new/obj/substance/gas(src) + ngas = new/obj/substance/gas() + gasflowlist += src + + h_dir = dir // the h/e pipe is in icon dir + p_dir = turn(dir, 180) // the reg pipe is in opposite dir + + + // Find the connected machines or pipes + + buildnodes() + + var/turf/T = src.loc + + node1 = get_he_machine(level, T, h_dir ) // the h/e pipe + + node2 = get_machine(level, T , p_dir ) // the regular pipe + + if(node1) vnode1 = node1.getline() + if(node2) vnode2 = node2.getline() + + return + + + // Replace gas levels with the newly calculated values + + gas_flow() + gas.replace_by(ngas) + + + // Calculate the flow through the junction + + process() + var/delta_gt + + if(vnode1) + delta_gt = FLOWFRAC * ( vnode1.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode1, delta_gt) + else + leak_to_turf(1) + + if(vnode2) + delta_gt = FLOWFRAC * ( vnode2.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode2, delta_gt) + + else + leak_to_turf(2) + + + // Return the gas fullness value + + get_gas_val(from) + return gas.tot_gas()/capmult + + + // Return the gas reservoir + + get_gas(from) + return gas + + + // If a node is not connected, leak gas to the turf location + + proc/leak_to_turf(var/port) + var/turf/T + + switch(port) + if(1) + T = get_step(src, dir) + if(2) + T = get_step(src, turn(dir, 180) ) + + if(T.density) + T = src.loc + if(T.density) + return + + flow_to_turf(gas, ngas, T) + + diff --git a/main-src/Code/Machinery/light_switch.dm b/main-src/Code/Machinery/light_switch.dm new file mode 100644 index 0000000..4a8063b --- /dev/null +++ b/main-src/Code/Machinery/light_switch.dm @@ -0,0 +1,94 @@ +/* + * Light_switch - Controls the lighting of an area + * Can have multiple switches per area, they will interact correctly + * Set the "otherarea" var to control the lighting of a remote area (non-loc) + */ + + +obj/machinery/light_switch + desc = "A light switch" + name = null + icon = 'power.dmi' + icon_state = "light1" + anchored = 1.0 + var + on = 1 // true if currently switched on + area/area = null // holds the area object that this switch controls + otherarea = null // By default, the switch controls the area it is located in. + // By setting this string, the switch will control the area + // matching the path "/area/(otherarea)" + // this allows remote light switches located outside the area controlled (e.g. brig) + + + // Create a new switch + + New() + ..() + spawn(5) // wait for world to completely load + src.area = src.loc.loc // by default, switch contains the area it is in + + if(otherarea) // setting this var to control a different area + src.area = locate(text2path("/area/[otherarea]")) + + if(!name) + name = "light switch ([area.name])" + + src.on = src.area.lightswitch // default on/off state is set by the area vars + updateicon() + + + // Update the icon state to on, off, or unpowered + + proc/updateicon() + if(stat & NOPOWER) + icon_state = "light-p" + else + if(on) + icon_state = "light1" + else + icon_state = "light0" + + + // Examine verb + + examine() + set src in oview(1) + if(usr && !usr.stat) + usr << "A light switch. It is [on? "on" : "off"]." + + + // Monkey interact same as human + + attack_paw(mob/user) + src.attack_hand(user) + + + // Interact, switch the switch + + attack_hand(mob/user) + + on = !on + + area.lightswitch = on + updateicon() + + // Update all other light switches in this area to same state + + for(var/obj/machinery/light_switch/L in area) + L.on = on + L.updateicon() + + area.updateicon() // update the area icon_state to set the darkness overlay + + + // When area power status of the lighting channel changes, update the switch status + + power_change() + + if(!otherarea) + if(powered(LIGHT)) + stat &= ~NOPOWER + else + stat |= NOPOWER + + updateicon() diff --git a/main-src/Code/Machinery/manifold.dm b/main-src/Code/Machinery/manifold.dm new file mode 100644 index 0000000..eddf200 --- /dev/null +++ b/main-src/Code/Machinery/manifold.dm @@ -0,0 +1,148 @@ +/* + * Manifold - Machine that allows three gas lines to be connected together. + * + */ + + +obj/machinery/manifold + name = "manifold" + icon = 'pipes.dmi' + icon_state = "manifold" + desc = "A three-port gas manifold." + anchored = 1 + dir = 2 + p_dir = 14 + capmult = 3 + + var + n1dir // direction of node1 + n2dir // direction of node2 + // "dir" is the direction of node3 + + obj/substance/gas/gas = null // the gas reservoir + obj/substance/gas/ngas = null + capacity = 6000000.0 // nominal gas capacity + + obj/machinery/node1 = null // } + obj/machinery/node2 = null // } the machine connected to each port + obj/machinery/node3 = null // } + + obj/machinery/vnode1 // } + obj/machinery/vnode2 // } the pipeline connected to each port, if nodeX is a pipe object + obj/machinery/vnode3 // } + + + + // Create a new manifold. Pipe p_dir is calculated from the icon dir, so p_dir does not need to be set on map. + + New() + ..() + switch(dir) + if(NORTH) + p_dir = 13 //NORTH|EAST|WEST + + if(SOUTH) + p_dir = 14 //SOUTH|EAST|WEST + + if(EAST) + p_dir = 7 //EAST|NORTH|SOUTH + + if(WEST) + p_dir = 11 //WEST|NORTH|SOUTH + + + + src.gas = new /obj/substance/gas( src ) + src.gas.maximum = src.capacity + src.ngas = new /obj/substance/gas() + gasflowlist += src + + + // Find the connected machines/pipelines for each port + + buildnodes() + var/turf/T = src.loc + + node3 = get_machine( level, T, dir ) // the side port + + n1dir = turn(dir, 90) + n2dir = turn(dir,-90) + + node1 = get_machine( level, T , n1dir ) // the main flow dir + + + node2 = get_machine( level, T , n2dir ) + + + if(node1) vnode1 = node1.getline() + if(node2) vnode2 = node2.getline() + if(node3) vnode3 = node3.getline() + + return + + + // Replace the gas levels with the new levels calculated in process() + + gas_flow() + gas.replace_by(ngas) + + + // Calculate the gas flow to/from each port + + process() + var/delta_gt + + if(vnode1) + delta_gt = FLOWFRAC * ( vnode1.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode1, delta_gt) + else + leak_to_turf(1) + + if(vnode2) + delta_gt = FLOWFRAC * ( vnode2.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode2, delta_gt) + else + leak_to_turf(2) + + if(vnode3) + delta_gt = FLOWFRAC * ( vnode3.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode3, delta_gt) + else + leak_to_turf(3) + + + // Return the gas fullness value + + get_gas_val(from) + return gas.tot_gas()/capmult + + + // Return the gas reservoir + + get_gas(from) + return gas + + + // If a node is not connected, leak the gas into the turf in that direction + + proc/leak_to_turf(var/port) + + var/turf/T + + switch(port) + if(1) + T = get_step(src, n1dir) + if(2) + T = get_step(src, n2dir) + if(3) + T = get_step(src, dir) + + if(T.density) + T = src.loc + if(T.density) + return + + flow_to_turf(gas, ngas, T) + + + diff --git a/main-src/Code/Machinery/pipeline.dm b/main-src/Code/Machinery/pipeline.dm new file mode 100644 index 0000000..0184228 --- /dev/null +++ b/main-src/Code/Machinery/pipeline.dm @@ -0,0 +1,183 @@ +/* + * Pipeline -- The pipeline machine responsible for gas flow through pipes. + * + * Pipelines are logical, not physical objects, and do not exist at a location in the world. + * They are collections of /obj/machinery/pipes objects that form an unbroken connection. + * + * By consolidating the gas content of a series of pipes into one pipeline, the number of gas flow calculations is reduced. + * This also allows faster flow of gas through long lines. + * For instance, if each pipe segment performed as an independent object, it would take at least 10 seconds for any gas + * to flow through a 10-segment pipe, + */ + + +obj/machinery/pipeline // logical pipeline consisting of multiple /obj/machinery/pipes + + name = "pipeline" + invisibility = 101 // since pipelines do not exist as tangible objects, they are set invisible + capmult = 0 // actual capmult will be the number of pipe segments + 1 + + var + list/nodes = list() // the list of /obj/machinery/pipes objects in this pipeline + // nodes will be sorted during creation so that adjacent pipes are adjacent in the list + numnodes = 0 // the number of nodes + + obj/substance/gas/gas = null // the gas reservoir for this pipeline + obj/substance/gas/ngas = null // the new calculated gas levels + + obj/machinery/vnode1 // the machine connected to the start of this pipeline (or null if none) + obj/machinery/vnode2 // the machine connected to the end of this pipeline (or null if none) + + flow = 0 // flow rate through this pipe, calculated from the gas flowing into or out of each end. + // can be negative if flowing backwards. + + + // Create a new pipeline. Create gas reservoir + // Register self with gasflowlist since this object has a gas_flow() proc. + + New() + ..() + + gas = new/obj/substance/gas(src) + ngas = new/obj/substance/gas() + + gasflowlist += src + + + // Sets the vnode1 & vnode2 values to the machines connected at each end of the pipe + // Also orientates the pipes in the node list so that for each pipe, node1 points to previous entry, and node2 points to next + + proc/setterm() + //first make sure pipes are oriented correctly + + var/obj/machinery/M = null + + for(var/obj/machinery/pipes/P in nodes) + if(!M) // special case for 1st pipe + if(P.node1 && P.node1.ispipe()) + + P.flip() // flip if node1 is a pipe + + else + if(P.node1 != M) //other cases, flip if node1 doesn't point to previous node + P.flip() // (including if it is null) + + P.updateicon() + + M = P // the previous node + + + + // pipes are now ordered so that n1/n2 is in same order as pipeline list + + var/obj/machinery/pipes/P = nodes[1] // 1st node in list + vnode1 = P.node1 // n1 points to 1st machine + P = nodes[nodes.len] // last node in list + vnode2 = P.node2 // n2 points to last machine + + + // confirm node connections are valid for the machines at each end of the pipeline + // not needed in initial makepipelines, but may be if new pipeline is constructed + + if(vnode1) + vnode1.buildnodes() + if(vnode2) + vnode2.buildnodes() + + return + + + // Return the gas fullness value + // For pipelines, capmult is set to (number of pipe segements)+1 + // Thus the longer the pipeline, the bigger the gas reservoir appears + + get_gas_val(from) + return gas.tot_gas()/capmult + + + // Return the gas reservoir for the pipeline + + get_gas(from) + return gas + + + // Update the current gas levels to that calculated in process() + + gas_flow() + gas.replace_by(ngas) + + + // Timed process for the pipeline. + // First do heat-exchange for every node in this pipeline + // The do standard gas flow from each end of the pipeline. + // Also update "flow" variable to show rate of flow through the complete pipeline. + + process() + + if(!numnodes) // check to see if there are any nodes in the pipeline + return // if none, skip it. Used because some PLs may get zero lengthed during pipe laying + + // heat exchange for whole pipeline + + var/gtemp = ngas.temperature // cached current temperature for heat exch calc + var/tot_node = ngas.tot_gas() / numnodes // fraction of gas in this node + + + if(tot_node>0.1) // no pipe contents, don't heat + for(var/obj/machinery/pipes/P in src.nodes) // for each segment of pipe + P.heat_exchange(ngas, tot_node, numnodes, gtemp) // exchange heat with its turf + + + // now do standard gas flow proc + + var/delta_gt + + if(vnode1) + delta_gt = FLOWFRAC * ( vnode1.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode1, delta_gt) + + flow = delta_gt + else + leak_to_turf(1) + + if(vnode2) + delta_gt = FLOWFRAC * ( vnode2.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode2, delta_gt) + + flow -= delta_gt + else + leak_to_turf(2) + + + // Depending on which end is leaking, vent gas contents into turf + + // Note: added some temporary error-checking to fix runtime errors when blob destroys pipes + // full pipe damage system will remove the need for this + + proc/leak_to_turf(var/port) + + var/turf/T + var/obj/machinery/pipes/P + var/list/ndirs + + switch(port) + if(1) + P = nodes[1] // 1st node in list + + if(P) + ndirs = P.get_node_dirs() + T = get_step(P, ndirs[1]) + + + if(2) + P = nodes[nodes.len] // last node in list + + if(P) + ndirs = P.get_node_dirs() + T = get_step(P, ndirs[2]) + + if(!T || T.density) + return + + flow_to_turf(gas, ngas, T) + diff --git a/main-src/Code/Machinery/pipes.dm b/main-src/Code/Machinery/pipes.dm new file mode 100644 index 0000000..6700706 --- /dev/null +++ b/main-src/Code/Machinery/pipes.dm @@ -0,0 +1,391 @@ +/* + * Pipes -- the basic object in the pipe network + * + * Pipes do not directly contain gas, but unbroken chains of pipes are assembled into /obj/machinery/pipeline objects + * Pipelines contain a single gas reservoir that encompass all the gas that would be each individual pipe. + * + * TODO: Complete routines for pipe disassembly, damage, and exploding under pressure. + * TODO: Finalize method of showing broken pipes & pipe ends. + * TODO: Implement some method of capacity regulation + */ + +obj/machinery/pipes + name = "pipes" + icon = 'reg_pipe.dmi' + icon_state = "12" + anchored = 1 + + /* var/p_dir - inherited from /obj/machinery, is a bitfield of directions of pipe connections from this one */ + + var + capacity = 6000000.0 // nominal gas capacity of each pipe segment - not actually used + obj/machinery/node1 = null // the 1st connected node + obj/machinery/node2 = null // the 2nd connected node + termination = 0 // >0 if this is an end pipe in a pipeline + insulation = NORMPIPERATE // lower insulation value means pipe temperature is exchanged with turf at a faster rate + + obj/machinery/pipeline/pl // the pipeline object which contains this pipe + health = 10 // the health of the pipe (not yet implemented) + + + // Create a new pipe, and update the p_dir according to the icon_state. + + New() + ..() + update() + + + // Update the p_dir bitfield according to the current icon state + // Icons_states for each pipe state match the correct p_dir value, so pipes placed on the map + // do not need the p_dir state set at compile time, since it is calculated at spawn. + + proc/update() + p_dir = text2num(icon_state) + + + // Return true as this is a pipe. All other machines return false. + + ispipe() + return 1 + + + // Find the machines or pipes which connect to this one + // Argument is the current pipeline object being built + // If another pipe segment is found, call this routine for that pipe to propagate the connection + + buildnodes(var/obj/machinery/pipeline/line) + + // First find the machines/pipes that connect to this pipe + + var/list/dirs = get_dirs() + + node1 = get_machine(level, src.loc, dirs[1]) + node2 = get_machine(level, src.loc, dirs[2]) + + if(pl) // If the pipeline is already set, there is no need to propagate anymore + return + + updateicon() // Update the icon_state according to p_dir and other states + + pl = line // Set the pipeline of the pipe segment + + termination = 0 + + if(node1 && node1.ispipe() ) // If node1 is a pipe, propagate this pipeline object to it + + node1.buildnodes(line) + else + termination++ // Otherwise we are at an end of the pipeline + + if(node2 && node2.ispipe() ) // If node2 is a pipe, propagate this pipeline object to it + node2.buildnodes(line) + else + termination++ // Otherwise we are at the end of the pipeline + + + + // Flip the node order of a pipe + + proc/flip() + + var/obj/machinery/tempnode = node1 + node1 = node2 + node2 = tempnode + return + + + // Return the next pipe object in the node chain + // Argument "from" is the node we are approaching from; if null, returns the first actual pipe found + + next(var/obj/machinery/from) + + if(from == null) // if from null, then return the next actual pipe + if(node1 && node1.ispipe() ) + return node1 + if(node2 && node2.ispipe() ) + return node2 + return null // else return null if no real pipe connected + + else if(from == node1) // otherwise, return the node opposite the incoming one + return node2 + else + return node1 + + + // Returns the pipeline object that this pipe is in + + getline() + return pl + + + // Finds the actual directions corresponding to the p_dir bitfield + // Returns as a list (dir1, dir2, p_dir) + // Note this direction order is not guaranteed to be the same order as node1 & node2 + // For that, use get_node_dirs() + + proc/get_dirs() + var/b1 + var/b2 + + for(var/d in cardinal) + if(p_dir & d) + if(!b1) + b1 = d + else if(!b2) + b2 = d + + return list(b1, b2, p_dir) + + + // Returns a list of the directions of a pipe, matched to nodes (if present) + // Note unlike get_dirs(), 1st direction on list is always the direction of node1, 2nd is node2 + + proc/get_node_dirs() + var/list/dirs = get_dirs() + + + if(!node1 && !node2) // no nodes - just return the standard dirs + return dirs // note extra p_dir on end of list is unimportant + else + if(node1) + var/d1 = get_dir(src, node1) // find the direction of node1 + if(d1==dirs[1]) // if it matches + return dirs // then dirs list is correct + else + return list(dirs[2], dirs[1]) // otherwise return the list swapped + + else // node2 must be valid + var/d2 = get_dir(src, node2) // direction of node2 + if(d2==dirs[2]) // matches + return dirs // dirs list is correct + else + return list(dirs[2], dirs[1]) // otherwise swap order + + + // Update the icon_state and overlays + // Depends on pipe level and visibility, broken status, and whether this is an unterminated end of a pipe + + proc/updateicon() + + var/turf/T = src.loc + + var/is = "[p_dir]" + + if(stat & BROKEN) + is += "-b" + + // Set invisibility status depending on whether this pipe is below floor level + // Also sets a faded (alpha blended) icon_state for the pipe so it can be shown with a T-scanner + + if ((src.level == 1 && isturf(src.loc) && T.intact)) + src.invisibility = 101 + is += "-f" + + else + src.invisibility = null + + src.icon_state = is + + // If either node is null, this is an unterminated pipe + // Show special overlays to indicate this + + var/list/dirs = get_node_dirs() + + overlays = null + if(!node1 && !node2) // neither end of pipe is connected + overlays += image('pipes.dmi', "discon", FLY_LAYER, dirs[1]) + overlays += image('pipes.dmi', "discon", FLY_LAYER, dirs[2]) + + else if(!node1) // node1 is not connected + overlays += image('pipes.dmi', "discon", FLY_LAYER, dirs[1]) + + else if(!node2) // node2 is not connected + overlays += image('pipes.dmi', "discon", FLY_LAYER, dirs[2]) + + return + + + // Called when a pipe is revealed or hidden when a floor tile is removed, etc. + // Just call updateicon(), since all is handled there already + + hide(var/i) + updateicon() + + + + // Exchange heat between a pipe and the turf it is on + // Called by /obj/machinery/pipeline/process() + // + + proc/heat_exchange(var/obj/substance/gas/gas, var/tot_node, var/numnodes, var/temp) + + var/turf/T = src.loc // turf location of pipe + if(T.density) return + + if( level != 1) // no heat exchange for under-floor pipes + if(istype(T,/turf/space)) // heat exchange less efficient in space (no conduction) + gas.temperature += ( T.temp - temp) / (3.0 * insulation * numnodes) + else + + var/delta_T = (T.temp - temp) / (insulation) // normal turf + + gas.temperature += delta_T / numnodes // heat the pipe due to turf temperature + + var/tot_turf = max(1, T.tot_gas()) + T.temp -= delta_T*min(10,tot_node/tot_turf) // also heat the turf due to pipe temp + T.res_vars() // ensure turf tmp vars are updated + + else // if level 1 but in space, perform cooling anyway - exposed pipes + if(istype(T,/turf/space)) + gas.temperature += ( T.temp - temp) / (3.0 * insulation * numnodes) + + + + + // Routines to allow cutting and damage of pipes + // Not yet implemented + + /* + attackby(obj/item/weapon/W, mob/user) + + if (istype(W, /obj/item/weapon/weldingtool)) + var/obj/item/weapon/weldingtool/WT = W + if(WT.welding && WT.weldfuel > 3) + WT.weldfuel -=3 + + user << "\blue Cutting the pipe. Stand still as this takes some time." + var/turf/T = user.loc + sleep(50) + + if ((user.loc == T && user.equipped() == W)) + + // make pipe fitting + sleep(1) + + else + var/aforce = W.force + + src.health = max(0, src.health - aforce) + + healthcheck() + + return + + proc/healthcheck() + //if(health<1) + */ + + + /* + * Heat_exch - Heat-exchange pipe subtype. Same as a standard pipe, but uses different icon, has lower insulation value + * Also uses h_dir for connection direction bitfield instead of p_dir + */ + + heat_exch + icon = 'heat_pipe.dmi' + name = "heat exchange pipe" + desc = "A bundle of small pipes designed for maximum heat transfer." + insulation = HEATPIPERATE + + /* h_dir - inherited from /obj/machinery */ + + + // Update h_dir from the icon state + + update() + h_dir = text2num(icon_state) + + + // Update icon_state and overlays depending in h_dir connections and whether nodes are present + + updateicon() + + var/list/dirs = get_node_dirs() + + var/is = "[h_dir]" + + if(stat & BROKEN) + is += "-b" + + src.icon_state = is + + overlays = null + + if(!node1 && !node2) + overlays += image('pipes.dmi', "discon-he", FLY_LAYER, dirs[1]) + overlays += image('pipes.dmi', "discon-he", FLY_LAYER, dirs[2]) + else if(!node1) + overlays += image('pipes.dmi', "discon-he", FLY_LAYER, dirs[1]) + else if(!node2) + overlays += image('pipes.dmi', "discon-he", FLY_LAYER, dirs[2]) + return + + + // Return list of directions corresponding to h_dir bitflags + + get_dirs() + var/b1 + var/b2 + + for(var/d in cardinal) + if(h_dir & d) + if(!b1) + b1 = d + else if(!b2) + b2 = d + + return list(b1, b2, h_dir) + + + // Find the nodes that connect to this pipe + // If they are pipes themselves, propagate the set pipeline object to them + + buildnodes(var/obj/machinery/pipeline/line) + + src.level = 2 // h/e pipe cannot be put underfloor + + var/list/dirs = get_dirs() + + node1 = get_he_machine(level, src.loc, dirs[1]) + node2 = get_he_machine(level, src.loc, dirs[2]) + + if(pl) + return + + updateicon() + + pl = line + + termination = 0 + + if(node1 && node1.ispipe() ) + + node1.buildnodes(line) + else + termination++ + + if(node2 && node2.ispipe() ) + node2.buildnodes(line) + else + termination++ + + + // Flexpipe sub-type. Identical to standard pipe except for appearance, since capacity differences are not implemented + // Currently only used between freezer/cryocell + + flexipipe + desc = "Flexible hose-like piping." + name = "flexipipe" + icon = 'wire.dmi' + capacity = 10.0 + p_dir = 12.0 + + + // High-capacity pipe subtype. Not implemented. + + high_capacity + desc = "A large bore pipe with high capacity." + name = "high capacity" + icon = 'hi_pipe.dmi' + density = 1 + capacity = 1.8E7 diff --git a/main-src/Code/Machinery/recharger.dm b/main-src/Code/Machinery/recharger.dm index 819bd25..0e33313 100644 --- a/main-src/Code/Machinery/recharger.dm +++ b/main-src/Code/Machinery/recharger.dm @@ -5,43 +5,49 @@ * variables seem to live elsewhere, need a project decision on how these cases * get documented and referenced. */ -obj - machinery - recharger - anchored = 1.0 - icon = 'stationobjs.dmi' - icon_state = "recharger0" - name = "recharger" - - var - obj/item/weapon/gun/energy/charging = null - - attackby(obj/item/weapon/G as obj, mob/user as mob) - if (src.charging) - return - if (istype(G, /obj/item/weapon/gun/energy)) - user.drop_item() - G.loc = src - src.charging = G +obj/machinery/recharger + anchored = 1.0 + icon = 'stationobjs.dmi' + icon_state = "recharger0" + name = "recharger" - attack_hand(mob/user as mob) - src.add_fingerprint(user) - if (src.charging) - src.charging.update_icon() - src.charging.loc = src.loc - src.charging = null + var + obj/item/weapon/gun/energy/charging = null // the weapon being charged, or null if none - attack_paw(mob/user as mob) - if ((ticker && ticker.mode == "monkey")) - return src.attack_hand(user) + // attacking with a gun inserts the gun into the charger - process() - if (src.charging && ! (stat & NOPOWER) ) - if (src.charging.charges < 10) - src.charging.charges++ - src.icon_state = "recharger1" - use_power(250) - else - src.icon_state = "recharger2" - else - src.icon_state = "recharger0" + attackby(obj/item/weapon/G, mob/user) + if (src.charging) + return + if (istype(G, /obj/item/weapon/gun/energy)) + user.drop_item() + G.loc = src + src.charging = G + + // hand attack removes the gun from the charger (and leaves it on the same turf) + + attack_hand(mob/user) + src.add_fingerprint(user) + if (src.charging) + src.charging.update_icon() + src.charging.loc = src.loc + src.charging = null + + // monkey attack same as human if in monkey mode + + attack_paw(mob/user) + if ((ticker && ticker.mode == "monkey")) + return src.attack_hand(user) + + // if a gun is inserted, recharge once per second until fully charged + + process() + if (src.charging && ! (stat & NOPOWER) ) + if (src.charging.charges < 10) + src.charging.charges++ + src.icon_state = "recharger1" + use_power(250) + else + src.icon_state = "recharger2" + else + src.icon_state = "recharger0" diff --git a/main-src/Code/Machinery/sec_lock.dm b/main-src/Code/Machinery/sec_lock.dm new file mode 100644 index 0000000..15bc5b7 --- /dev/null +++ b/main-src/Code/Machinery/sec_lock.dm @@ -0,0 +1,160 @@ +/* + * Sec_lock -- Control for opening paired security doors + * As used in brig, prision station, etc. + * Requires ID card to operate + * + * TODO: Merge security checks in Topic() proc + */ + +obj/machinery/sec_lock + name = "Security Pad" + icon = 'stationobjs.dmi' + icon_state = "sec_lock" + anchored = 1.0 + + var + obj/item/weapon/card/id/scan = null // the inserted ID card + a_type = 0 // position of the controlled doors + //0 = doors S/SE, 1 = SW/(SW+W), 2 = NW/(NW+W) + obj/machinery/door/d1 = null // the 1st door to control + obj/machinery/door/d2 = null // the 2nd door to control + access = "5500" // ID access level required to operate lock + allowed = "Prison Security/Prison Warden/Security Officer/Head of Personnel/Captain" + // Job titles required to operate lock + + // Create a new sec_lock + // Looks for 1st & 2nd controlled doors at positions determined by a_type + + New() + ..() + spawn( 2 ) // wait for world to finished loading + if (src.a_type == 1) + src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y - 1, src.z)) + src.d1 = locate(/obj/machinery/door, get_step(src, SOUTHWEST)) + else + if (src.a_type == 2) + src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y + 1, src.z)) + src.d1 = locate(/obj/machinery/door, get_step(src, NORTHWEST)) + else + src.d1 = locate(/obj/machinery/door, get_step(src, SOUTH)) + src.d2 = locate(/obj/machinery/door, get_step(src, SOUTHEAST)) + return + return + + + + // Monkey interact same as human + + attack_paw(mob/user) + return src.attack_hand(user) + + + // Interact, show window + + attack_hand(mob/user) + + if(stat & NOPOWER) + return + use_power(10) + + if (src.loc == user.loc) + var/dat = {"Security Pad:
+Keycard: [src.scan ? "[src.scan.name]" : "-----"]
+Toggle Outer Door
+Toggle Inner Door
+
+Emergency Close
+Emergency Open
"} + + user << browse(dat, "window=sec_lock") + return + + + // Attack by item, same as attack with empty hand + + attackby(nothing, mob/user) + return src.attack_hand(user) + + + // Handle topic links from interction window + // Note: user can insert an ID card by attacking the 'card' link with a card equipped + + Topic(href, href_list) + ..() + + + if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) + usr << "\red You don't have the dexterity to do this!" + return + if ((usr.stat || usr.restrained())) + return + if ((!( src.d1 ) || !( src.d2 ))) + usr << "\red Error: Cannot interface with door security!" + return + if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) + usr.machine = src + if (href_list["card"]) // clicked card link + if (src.scan) // if card already present, remove the card + src.scan.loc = src.loc + src.scan = null + else // otherwise + var/obj/item/weapon/card/id/I = usr.equipped() // check to see if an ID card is equipped + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + src.scan = I // and insert the ID card + if (href_list["door1"]) + if (src.scan) + if (scan.check_access(access, allowed)) + if (src.d1.density) + spawn( 0 ) + src.d1.open() + return + else + spawn( 0 ) + src.d1.close() + return + if (href_list["door2"]) + if (src.scan) + if (scan.check_access(access, allowed)) + if (src.d2.density) + spawn( 0 ) + src.d2.open() + return + else + spawn( 0 ) + src.d2.close() + return + if (href_list["em_cl"]) + if (src.scan) + if (scan.check_access(access, allowed)) + if (!( src.d1.density )) + src.d1.close() + return + sleep(1) + spawn( 0 ) + if (!( src.d2.density )) + src.d2.close() + return + if (href_list["em_op"]) + if (src.scan) + if (scan.check_access(access, allowed)) + spawn( 0 ) + if (src.d1.density) + src.d1.open() + return + sleep(1) + spawn( 0 ) + if (src.d2.density) + src.d2.open() + return + src.add_fingerprint(usr) + + for(var/mob/M in src.loc) + if ((M.client && M.machine == src)) + spawn( 0 ) + src.attack_hand(M) + return + return + + diff --git a/main-src/Code/Machinery/valve.dm b/main-src/Code/Machinery/valve.dm new file mode 100644 index 0000000..baba7a4 --- /dev/null +++ b/main-src/Code/Machinery/valve.dm @@ -0,0 +1,185 @@ +/* + * Valve - on/off valve machine, prevents gas flow through a pipe when off + * + * Valves work by having two internal gas reservoirs, and flowing between them only when open. + */ + +obj/machinery/valve + name = "valve" + icon = 'pipes.dmi' + icon_state = "valve0" + desc = "A gas valve." + anchored = 1 + capmult = 2 + var + obj/substance/gas/gas1 = null // gas reservoir connected to node1 + obj/substance/gas/ngas1 = null + + obj/substance/gas/gas2 = null // gas reservoir connected to node2 + obj/substance/gas/ngas2 = null + + capacity = 6000000.0 + + obj/machinery/node1 = null // pipe/machine connected to gas1 + obj/machinery/node2 = null // pipe/machine connected to gas2 + obj/machinery/vnode1 = null // pipeline of node1 + obj/machinery/vnode2 = null // pipeline of node2 + id = "v1" // Not implemented: planned id to control valves remotely + open = 0 // true if the valve is open + + + // Create a valve, create gas reservoirs. + // p_dir calculated from icon direction + + New() + ..() + gas1 = new/obj/substance/gas(src) + ngas1 = new/obj/substance/gas() + gas2 = new/obj/substance/gas(src) + ngas2 = new/obj/substance/gas() + + gasflowlist += src + switch(dir) + if(1, 2) + p_dir = 3 + if(4,8) + p_dir = 12 + + icon_state = "valve[open]" + + // Examine verb + + examine() + set src in oview(1) + if(usr.stat) + return + + usr << "[desc] It is [ open? "open" : "closed"]." + + + // Find the connected nodes + + buildnodes() + + var/turf/T = src.loc + + node1 = get_machine(level, T, dir ) // the h/e pipe + + node2 = get_machine(level, T , turn(dir, 180) ) // the regular pipe + + if(node1) vnode1 = node1.getline() + if(node2) vnode2 = node2.getline() + + return + + + // Update the gas values with the newly calculated values + + gas_flow() + + gas1.replace_by(ngas1) + gas2.replace_by(ngas2) + + + // Perform flow into and out of the valve, and if open, between the two reservoirs + + process() + + var/delta_gt + + if(vnode1) + delta_gt = FLOWFRAC * ( vnode1.get_gas_val(src) - gas1.tot_gas() / capmult) + calc_delta( src, gas1, ngas1, vnode1, delta_gt) + + else + leak_to_turf(1) + + if(vnode2) + delta_gt = FLOWFRAC * ( vnode2.get_gas_val(src) - gas2.tot_gas() / capmult) + calc_delta( src, gas2, ngas2, vnode2, delta_gt) + + else + leak_to_turf(2) + + + if(open) // valve operating, so transfer btwen resv1 & 2 + + delta_gt = FLOWFRAC * (gas1.tot_gas() / capmult - gas2.tot_gas() / capmult) + + var/obj/substance/gas/ndelta = new() + + if(delta_gt < 0) // then flowing from R2 to R1 + + ndelta.set_frac(gas2, -delta_gt) + + ngas2.sub_delta(ndelta) + ngas1.add_delta(ndelta) + + else // flowing from R1 to R2 + ndelta.set_frac(gas1, delta_gt) + ngas2.add_delta(ndelta) + ngas1.sub_delta(ndelta) + + + // Return the gas fullness value. Two reservoirs, so which value returned depends on who's asking + + get_gas_val(from) + if(from == vnode2) + return gas2.tot_gas()/capmult + else + return gas1.tot_gas()/capmult + + // Return the corresponding gas resevoir connected to the given node + + get_gas(from) + if(from == vnode2) + return gas2 + return gas1 + + // Leak gas to turf if either node is null + + proc/leak_to_turf(var/port) + var/turf/T + + + switch(port) + if(1) + T = get_step(src, dir) + if(2) + T = get_step(src, turn(dir, 180) ) + + if(T.density) + T = src.loc + if(T.density) + return + + if(port==1) + flow_to_turf(gas1, ngas1, T) + else + flow_to_turf(gas2, ngas2, T) + + // Monkey interact same as human + + attack_paw(mob/user) + attack_hand(user) + + + // Interact, toggle open/closed state, show correct animation, set correct final icon state + + attack_hand(mob/user) + ..() + add_fingerprint(user) + // if(stat & NOPOWER) return + + // use_power(5) + + if(!open) // now opening + flick("valve01", src) + icon_state = "valve1" + sleep(10) + else // now closing + flick("valve10", src) + icon_state = "valve0" + sleep(10) + open = !open + diff --git a/main-src/Code/Machinery/vent.dm b/main-src/Code/Machinery/vent.dm new file mode 100644 index 0000000..a5fcaab --- /dev/null +++ b/main-src/Code/Machinery/vent.dm @@ -0,0 +1,95 @@ +/* + * Vent - Machine which dumps pipe gas contents into turf + * + * Similar to an inlet, except only works one way (pipe->turf) + */ + + +obj/machinery/vent + name = "vent" + icon = 'pipes.dmi' + icon_state = "vent" + desc = "A gas pipe outlet vent." + anchored = 1 + p_dir = 2 + capmult = 2 + + var + obj/machinery/node // the connected object + obj/machinery/vnode // the connected pipeline (if node is a pipe) + obj/substance/gas/gas // the gas reservoir + obj/substance/gas/ngas // the new gas reservoir after calculating flow + capacity = 6000000 // nominal gas capacity + + + // Create a new vent. Pipe connection p_dir is calculated from icon dir, so p_dir does not need to be set on map. + // Create the gas reservoir and register with the gasflowlist. + + New() + ..() + p_dir = dir + gas = new/obj/substance/gas(src) + gas.maximum = capacity + ngas = new/obj/substance/gas() + gasflowlist += src + + + // Find the connected machine or pipe to the vent pipe. + + buildnodes() + var/turf/T = get_step(src.loc, src.dir) + var/fdir = turn(src.p_dir, 180) + + for(var/obj/machinery/M in T) + if(M.p_dir & fdir) + src.node = M + break + + if(node) vnode = node.getline() + + return + + + // Get the gas fullness value. + + get_gas_val(from) + return gas.tot_gas()/2 + + // Get the gas reservoir object + + get_gas(from) + return gas + + + // Replace the gas level by the new level calculated in process() + + gas_flow() + gas.replace_by(ngas) + + + // Timed process. Dump gas into turf, then do standard flow calc for connected pipe. + + process() + var/delta_gt + + var/turf/T = src.loc + + delta_gt = FLOWFRAC * (gas.tot_gas() / capmult) + ngas.turf_add(T, delta_gt) + if(vnode) + delta_gt = FLOWFRAC * ( vnode.get_gas_val(src) - gas.tot_gas() / capmult) + calc_delta( src, gas, ngas, vnode, delta_gt)//, dbg) + else + leak_to_turf() + + + // Leak from pipe to turf if no node connected + + proc/leak_to_turf() + + var/turf/T = get_step(src, dir) + if(T && !T.density) + flow_to_turf(gas, ngas, T) + + + diff --git a/main-src/Code/_debug.dm b/main-src/Code/_debug.dm index c83696c..b9a5882 100644 --- a/main-src/Code/_debug.dm +++ b/main-src/Code/_debug.dm @@ -153,7 +153,7 @@ if(istype(M, /obj/machinery/pipes)) var/obj/machinery/pipes/P = M - O.overlays += numbericon("[P.plnum] ", -20) + O.overlays += numbericon("[plines.Find(P.pl)] ", -20) M = P.pl @@ -447,3 +447,28 @@ O.dir = pick(NORTH, SOUTH, EAST, WEST) spawn( 0 ) O.Life() + +/proc/Plasma() + + var/mplas = 0 + + for(var/obj/machinery/M in machines) + if(M.suffix=="dbgp") + + var/obj/substance/gas/G = M.get_gas() + var/p = G.plasma + + mplas += p + + world.log << "[M]=[num2text(p, 10)] \..." + + + var/tplas = 0 + + for(var/turf/station/engine/floor/T in world) + tplas += T.poison + + world.log << "\nTotals: M=[num2text(mplas, 10)] T=[num2text(tplas, 10)], all = [num2text(mplas+tplas, 10)]" + + + diff --git a/main-src/Code/aaaDefines.dm b/main-src/Code/aaaDefines.dm index 616c863..9971fd7 100644 --- a/main-src/Code/aaaDefines.dm +++ b/main-src/Code/aaaDefines.dm @@ -184,7 +184,7 @@ //world << "Returning mode [M]" return M - world << "Failed to pick gamemode in config/pickmode()" + //world << "Failed to pick gamemode in config/pickmode()" return null diff --git a/main-src/Code/airtunnel.dm b/main-src/Code/airtunnel.dm index 68730a8..f7a65fa 100644 --- a/main-src/Code/airtunnel.dm +++ b/main-src/Code/airtunnel.dm @@ -97,66 +97,7 @@ return return -/obj/machinery/at_indicator/ex_act(severity) - switch(severity) - if(1.0) - //SN src = null - del(src) - return - if(2.0) - if (prob(50)) - for(var/x in src.verbs) - src.verbs -= x - //Foreach goto(58) - src.icon_state = "reader_broken" - stat |= BROKEN - if(3.0) - if (prob(25)) - for(var/x in src.verbs) - src.verbs -= x - //Foreach goto(109) - src.icon_state = "reader_broken" - stat |= BROKEN - else - return - -/obj/machinery/at_indicator/blob_act() - - if (prob(50)) - for(var/x in src.verbs) - src.verbs -= x - src.icon_state = "reader_broken" - stat |= BROKEN - -/obj/machinery/at_indicator/proc/update_icon() - - if(stat & (BROKEN|NOPOWER) ) - icon_state = "reader_broken" - - var/status = 0 - if (SS13_airtunnel.operating == 1) - status = "r" - else - if (SS13_airtunnel.operating == 2) - status = "e" - else - var/obj/move/airtunnel/connector/C = pick(SS13_airtunnel.connectors) - if (C.current == C) - status = 0 - else - if (!( C.current.next )) - status = 2 - else - status = 1 - src.icon_state = text("reader[][]", (SS13_airtunnel.siphon_status == 2 ? "1" : "0"), status) - return - -/obj/machinery/at_indicator/process() - - use_power(5, ENVIRON) - src.update_icon() - return /obj/machinery/computer/airtunnel/ex_act(severity) @@ -309,428 +250,12 @@ //Foreach goto(346) return -/obj/machinery/camera/attackby(W as obj, user as mob) - if (istype(W, /obj/item/weapon/wirecutters)) - src.status = !( src.status ) - if (!( src.status )) - for(var/mob/O in viewers(user, null)) - O.show_message(text("\red [] has deactivated []!", user, src), 1) - //Foreach goto(49) - src.icon_state = "camera1" - else - for(var/mob/O in viewers(user, null)) - O.show_message(text("\red [] has reactivated []!", user, src), 1) - //Foreach goto(106) - src.icon_state = "camera" - return -//*****RM -/obj/machinery/camera/ex_act(severity) - if(src.invuln) - return - else - ..(severity) - return -/obj/machinery/camera/blob_act() - return - - -obj/machinery/door_control/attack_paw(mob/user as mob) - return src.attack_hand(user) - -obj/machinery/door_control/attackby(nothing, mob/user as mob) - return src.attack_hand(user) - -obj/machinery/door_control/attack_hand(mob/user as mob) - - if(stat & NOPOWER) - return - use_power(5) - icon_state = "doorctrl1" - - for(var/obj/machinery/door/poddoor/M in machines) - if (M.id == src.id) - if (M.density) - spawn( 0 ) - M.openpod() - return - else - spawn( 0 ) - M.closepod() - return - - spawn(15) - if(!(stat & NOPOWER)) - icon_state = "doorctrl0" - -//***** - -/obj/machinery/door_control/power_change() - ..() - if(stat & NOPOWER) - icon_state = "doorctrl-p" - else - icon_state = "doorctrl0" - -/obj/machinery/sec_lock/attack_paw(user as mob) - - return src.attack_hand(user) - - -/obj/machinery/sec_lock/attack_hand(var/mob/user as mob) - - if(stat & NOPOWER) - return - use_power(10) - - if (src.loc == user.loc) - var/dat = text("Security Pad:
\nKeycard: []
\nToggle Outer Door
\nToggle Inner Door
\n
\nEmergency Close
\nEmergency Open
", (src.scan ? text("[]", src, src.scan.name) : text("-----", src)), src, src, src, src) - user << browse(dat, "window=sec_lock") - return - -/obj/machinery/sec_lock/attackby(nothing, user as mob) - - return src.attack_hand(user) - - -/obj/machinery/sec_lock/New() - - ..() - spawn( 2 ) - if (src.a_type == 1) - src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y - 1, src.z)) - src.d1 = locate(/obj/machinery/door, get_step(src, SOUTHWEST)) - else - if (src.a_type == 2) - src.d2 = locate(/obj/machinery/door, locate(src.x - 2, src.y + 1, src.z)) - src.d1 = locate(/obj/machinery/door, get_step(src, NORTHWEST)) - else - src.d1 = locate(/obj/machinery/door, get_step(src, SOUTH)) - src.d2 = locate(/obj/machinery/door, get_step(src, SOUTHEAST)) - return - return - -/obj/machinery/sec_lock/Topic(href, href_list) - ..() - - - if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) - usr << "\red You don't have the dexterity to do this!" - return - if ((usr.stat || usr.restrained())) - return - if ((!( src.d1 ) || !( src.d2 ))) - usr << "\red Error: Cannot interface with door security!" - return - if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) - usr.machine = src - if (href_list["card"]) - if (src.scan) - src.scan.loc = src.loc - src.scan = null - else - var/obj/item/weapon/card/id/I = usr.equipped() - if (istype(I, /obj/item/weapon/card/id)) - usr.drop_item() - I.loc = src - src.scan = I - if (href_list["door1"]) - if (src.scan) - - - - if (scan.check_access(access, allowed)) - if (src.d1.density) - spawn( 0 ) - src.d1.open() - return - else - spawn( 0 ) - src.d1.close() - return - if (href_list["door2"]) - if (src.scan) - if (scan.check_access(access, allowed)) - if (src.d2.density) - spawn( 0 ) - src.d2.open() - return - else - spawn( 0 ) - src.d2.close() - return - if (href_list["em_cl"]) - if (src.scan) - if (scan.check_access(access, allowed)) - if (!( src.d1.density )) - src.d1.close() - return - sleep(1) - spawn( 0 ) - if (!( src.d2.density )) - src.d2.close() - return - if (href_list["em_op"]) - if (src.scan) - if (scan.check_access(access, allowed)) - spawn( 0 ) - if (src.d1.density) - src.d1.open() - return - sleep(1) - spawn( 0 ) - if (src.d2.density) - src.d2.open() - return - src.add_fingerprint(usr) - for(var/mob/M in src.loc) - if ((M.client && M.machine == src)) - spawn( 0 ) - src.attack_hand(M) - return - //Foreach goto(737) - return - -/obj/machinery/autolathe/attackby(var/obj/item/weapon/O as obj, var/mob/user as mob) - - if (istype(O, /obj/item/weapon/sheet/metal)) - if (src.m_amount < 150000.0) - src.m_amount += O:height * O:width * O:length * 1000000.0 - O:amount-- - if (O:amount < 1) - //O = null - del(O) - else - if (istype(O, /obj/item/weapon/sheet/glass)) - if (src.g_amount < 75000.0) - src.g_amount += O:height * O:width * O:length * 1000000.0 - O:amount-- - if (O:amount < 1) - //O = null - del(O) - else - if (istype(O, /obj/item/weapon/screwdriver)) - if (!( src.operating )) - src.opened = !( src.opened ) - src.icon_state = text("autolathe[]", (src.opened ? "f" : null)) - else - user << "\red The machine is in use. You can not maintain it now." - else - spawn( 0 ) - src.attack_hand(user) - return - return - -/obj/machinery/autolathe/attack_paw(user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/autolathe/attack_hand(user as mob) - - var/dat - if (src.temp) - dat = text("[]

Clear Screen", src.temp, src) - else - dat = text("Metal Amount: [] cm3 (MAX: 150,000)
\nGlass Amount: [] cm3 (MAX: 75,000)
", src.m_amount, src.g_amount) - var/list/L = list( ) -/* L["screwdriver"] = "Make Screwdriver {40 cc}" - L["wirecutters"] = "Make Wirecutters {80 cc}" - L["wrench"] = "Make Wrench {150 cc}" - L["crowbar"] = "Make Crowbar {150 cc}" - L["screw"] = "Make Screw (1) {3 cc}" - L["5screws"] = "Make Screws (5) {14 cc}" - L["rod_t"] = "Make Rod (1x20) {20 cc}" - L["rod_l"] = "Make Rod (5x250) {1250 cc}" - L["grille_1"] = "Make Grille (250x250x1) {27345 cc}" - L["sheet_1"] = "Make Sheet (20x10x.01) {2 cc}" - L["sheet_2"] = "Make Sheet (30x10x.01) {3 cc}" - L["sheet_3"] = "Make Sheet (30x20x.01) {6 cc}" - L["sheet_4"] = "Make Sheet (30x30x.01) {9 cc}" - L["sheet_5"] = "Make Sheet (62.5x62.5x4) {15625 cc}" */ - - - for(var/t in L) - dat += "[L["[t]"]]
" - //Foreach goto(230) - user << browse("Autolathe Control Panel[dat]", "window=autolathe") - return - -/obj/machinery/autolathe/Topic(href, href_list) - ..() - if ((usr.stat || usr.restrained())) - return - if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) - usr.machine = src - src.add_fingerprint(usr) - - if (href_list["temp"]) - src.temp = null - - - - - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(108) - return - -/obj/machinery/ex_act(severity) - - switch(severity) - if(1.0) - //SN src = null - del(src) - return - if(2.0) - if (prob(50)) - //SN src = null - del(src) - return - if(3.0) - if (prob(25)) - //SN src = null - del(src) - return - else - return - -/obj/machinery/blob_act() - if(prob(25)) - del(src) - -/obj/machinery/injector/attackby(var/obj/item/weapon/tank/W as obj, var/mob/user as mob) - - if(stat & NOPOWER) - return - use_power(25) - - var/obj/item/weapon/tank/ptank = W - if (!( istype(ptank, /obj/item/weapon/tank) )) - return - var/turf/T = get_step(src.loc, get_dir(user, src)) - ptank.gas.turf_add(T, -1.0) - src.add_fingerprint(user) - return - -/obj/machinery/alarm/process() - - if(stat & NOPOWER) - icon_state = "alarm-p" - return - - use_power(5, ENVIRON) - - var/safe = 1 - var/turf/T = src.loc - if (!( istype(T, /turf) )) - return - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 - turf_total = max(turf_total, 1) - var/t1 = turf_total / CELLSTANDARD * 100 - if (!( (90 < t1 && t1 < 110) )) - safe = 0 - t1 = T.oxygen / turf_total * 100 - if (!( (20 < t1 && t1 < 30) )) - safe = 0 - src.icon_state = text("alarm:[]", !( safe )) - return - -/obj/machinery/alarm/power_change() - if( powered(ENVIRON) ) - stat &= ~NOPOWER - else - stat |= NOPOWER - - -/obj/machinery/alarm/examine() - set src in oview(1) - - if (usr.stat || stat & NOPOWER) - return - if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) - usr << "\red You don't have the dexterity to do this!" - return - var/turf/T = src.loc - if (!( istype(T, /turf) )) - return - - var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 - turf_total = max(turf_total, 1) - usr.show_message("\blue Results:", 1) - var/t = "" - var/t1 = turf_total / CELLSTANDARD * 100 - if ((90 < t1 && t1 < 110)) - usr.show_message(text("\blue Air Pressure: []%", t1), 1) - else - usr.show_message(text("\blue Air Pressure:\red []%", t1), 1) - t1 = T.n2 / turf_total * 100 - t1 = round(t1, 0.0010) - if ((60 < t1 && t1 < 80)) - t += text("Nitrogen: [] ", t1) - else - t += text("Nitrogen: [] ", t1) - t1 = T.oxygen / turf_total * 100 - t1 = round(t1, 0.0010) - if ((20 < t1 && t1 < 24)) - t += text("Oxygen: [] ", t1) - else - t += text("Oxygen: [] ", t1) - t1 = T.poison / turf_total * 100 - t1 = round(t1, 0.0010) - if (t1 < 0.5) - t += text("Plasma: [] ", t1) - else - t += text("Plasma: [] ", t1) - t1 = T.co2 / turf_total * 100 - t1 = round(t1, 0.0010) - if (t1 < 1) - t += text("CO2: [] ", t1) - else - t += text("CO2: [] ", t1) - t1 = T.sl_gas / turf_total * 100 - t1 = round(t1, 0.0010) - if (t1 < 5) - t += text("NO2: []", t1) - else - t += text("NO2: []", t1) - usr.show_message(t, 1) - usr.show_message(text("\blue \t Temperature: []°C", T.temp - T0C), 1) - src.add_fingerprint(usr) - return - - -/obj/machinery/alarm/indicator/process() - - if(stat & NOPOWER) - icon_state = "indicator-p" - return - - var/safe = 1 - var/turf/T = src.loc - if (!( istype(T, /turf) )) - return - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - var/turf_total = T.co2 + T.oxygen + T.poison + T.sl_gas + T.n2 - turf_total = max(turf_total, 1) - var/t1 = turf_total / CELLSTANDARD * 100 - if (!( (90 < t1 && t1 < 110) )) - safe = 0 - t1 = T.oxygen / turf_total * 100 - if (!( (20 < t1 && t1 < 30) )) - safe = 0 - src.icon_state = text("indicator[]", safe) - SS13_airtunnel.air_stat = safe - return /datum/air_tunnel/air_tunnel1/New() diff --git a/main-src/Code/atmo_control.dm b/main-src/Code/atmo_control.dm index 31e3f0e..ee6d816 100644 --- a/main-src/Code/atmo_control.dm +++ b/main-src/Code/atmo_control.dm @@ -1,48 +1,4 @@ -/obj/machinery/proc/process() - - return - -/obj/machinery/proc/gas_flow() - - return - -/obj/machinery/proc/orient_pipe(source as obj) - - return - -/obj/machinery/proc/cut_pipes() - - return - -/obj/machinery/proc/disc_pipe(target as obj) - - return - - -/obj/machinery/proc/buildnodes() - - return - -/obj/machinery/proc/getline() - if(p_dir) - return src - -/obj/machinery/proc/setline() - return - -/obj/machinery/proc/ispipe() - return 0 - -/obj/machinery/proc/next() - - return null - -/obj/machinery/proc/get_gas_val(from) - return null - -/obj/machinery/proc/get_gas(from) - return null /obj/machinery/meter/New() @@ -121,541 +77,3 @@ - - -/obj/machinery/atmoalter/siphs/New() - - ..() - src.gas = new /obj/substance/gas( src ) - src.gas.maximum = src.maximum - - return - -/obj/machinery/atmoalter/siphs/proc/releaseall() - - src.t_status = 1 - src.t_per = max_valve - return - -/obj/machinery/atmoalter/siphs/proc/reset(valve, auto) - - if(c_status!=0) - return - - if (valve < 0) - src.t_per = -valve - src.t_status = 1 - else - if (valve > 0) - src.t_per = valve - src.t_status = 2 - else - src.t_status = 3 - if (auto) - src.t_status = 4 - src.setstate() - return - -/obj/machinery/atmoalter/siphs/proc/release(amount, flag) - - var/T = src.loc - if (!( istype(T, /turf) )) - return - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - if (!( amount )) - return - if (!( flag )) - amount = min(amount, max_valve) - src.gas.turf_add(T, amount) - return - -/obj/machinery/atmoalter/siphs/proc/siphon(amount, flag) - - var/T = src.loc - if (!( istype(T, /turf) )) - return - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - if (!( amount )) - return - if (!( flag )) - amount = min(amount, 900000.0) - src.gas.turf_take(T, amount) - return - -/obj/machinery/atmoalter/siphs/proc/setstate() - - if(stat & NOPOWER) - icon_state = "siphon:0" - return - - if (src.holding) - src.icon_state = "siphon:T" - else - if (src.t_status != 3) - src.icon_state = "siphon:1" - else - src.icon_state = "siphon:0" - return - -/obj/machinery/atmoalter/siphs/fullairsiphon/New() - - ..() - if(!empty) - src.gas.oxygen = 2.73E7 - src.gas.n2 = 1.027E8 - return - -/obj/machinery/atmoalter/siphs/fullairsiphon/port/reset(valve, auto) - - if (valve < 0) - src.t_per = -valve - src.t_status = 1 - else - if (valve > 0) - src.t_per = valve - src.t_status = 2 - else - src.t_status = 3 - if (auto) - src.t_status = 4 - src.setstate() - return - -/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent/attackby(W as obj, user as mob) - - if (istype(W, /obj/item/weapon/screwdriver)) - if (src.c_status) - src.anchored = 1 - src.c_status = 0 - else - if (locate(/obj/machinery/connector, src.loc)) - src.anchored = 1 - src.c_status = 3 - else - if (istype(W, /obj/item/weapon/wrench)) - src.alterable = !( src.alterable ) - return - -/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent/setstate() - - - if(stat & NOPOWER) - icon_state = "vent-p" - return - - if (src.t_status == 4) - src.icon_state = "vent2" - else - if (src.t_status == 3) - src.icon_state = "vent0" - else - src.icon_state = "vent1" - return - -/obj/machinery/atmoalter/siphs/fullairsiphon/air_vent/reset(valve, auto) - - if (auto) - src.t_status = 4 - return - -/obj/machinery/atmoalter/siphs/scrubbers/process() - - if(stat & NOPOWER) return - - if (src.t_status != 3) - var/turf/T = src.loc - if (istype(T, /turf)) - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - if (T.firelevel < 900000.0) - src.gas.turf_add_all_oxy(T) - - else - T = null - switch(src.t_status) - if(1.0) - if( !portable() ) use_power(50, ENVIRON) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.holding.gas.transfer_from(src.gas, t) - else - if (T) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.turf_add(T, t) - if(2.0) - if( !portable() ) use_power(50, ENVIRON) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.transfer_from(src.holding.gas, t) - else - if (T) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (t > t2) - t = t2 - src.gas.turf_take(T, t) - if(4.0) - if( !portable() ) use_power(50, ENVIRON) - if (T) - if (T.firelevel > 900000.0) - src.f_time = world.time + 400 - else - if (world.time > src.f_time) - src.gas.extract_toxs(T) - if( !portable() ) use_power(150, ENVIRON) - var/contain = src.gas.tot_gas() - if (contain > 1.3E8) - src.gas.turf_add(T, 1.3E8 - contain) - - /*if (src.c_status == 1) - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C) - var/obj/substance/gas/G = new /obj/substance/gas( ) - G.transfer_from(src.gas, src.c_per) - spawn( 0 ) - C.receive_gas(G, src) - return - else - src.c_status = 0 - */ - src.setstate() - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(654) - return - -/obj/machinery/atmoalter/siphs/scrubbers/air_filter/setstate() - - if(stat & NOPOWER) - icon_state = "vent-p" - return - - if (src.t_status == 4) - src.icon_state = "vent2" - else - if (src.t_status == 3) - src.icon_state = "vent0" - else - src.icon_state = "vent1" - return - -/obj/machinery/atmoalter/siphs/scrubbers/air_filter/attackby(W as obj, user as mob) - - if (istype(W, /obj/item/weapon/screwdriver)) - if (src.c_status) - src.anchored = 1 - src.c_status = 0 - else - if (locate(/obj/machinery/connector, src.loc)) - src.anchored = 1 - src.c_status = 3 - else - if (istype(W, /obj/item/weapon/wrench)) - src.alterable = !( src.alterable ) - return - -/obj/machinery/atmoalter/siphs/scrubbers/air_filter/reset(valve, auto) - - if (auto) - src.t_status = 4 - src.setstate() - return - -/obj/machinery/atmoalter/siphs/scrubbers/port/setstate() - - if(stat & NOPOWER) - icon_state = "scrubber:0" - return - - if (src.holding) - src.icon_state = "scrubber:T" - else - if (src.t_status != 3) - src.icon_state = "scrubber:1" - else - src.icon_state = "scrubber:0" - return - -/obj/machinery/atmoalter/siphs/scrubbers/port/reset(valve, auto) - - if (valve < 0) - src.t_per = -valve - src.t_status = 1 - else - if (valve > 0) - src.t_per = valve - src.t_status = 2 - else - src.t_status = 3 - if (auto) - src.t_status = 4 - src.setstate() - return - -//true if the siphon is portable (therfore no power needed) - -/obj/machinery/proc/portable() - return istype(src, /obj/machinery/atmoalter/siphs/fullairsiphon/port) || istype(src, /obj/machinery/atmoalter/siphs/scrubbers/port) - -/obj/machinery/atmoalter/siphs/power_change() - - if( portable() ) - return - - if(!powered(ENVIRON)) - spawn(rand(0,15)) - stat |= NOPOWER - setstate() - else - stat &= ~NOPOWER - setstate() - - -/obj/machinery/atmoalter/siphs/process() - -// var/dbg = (suffix=="d") && Debug - - if(stat & NOPOWER) return - - if (src.t_status != 3) - var/turf/T = src.loc - if (istype(T, /turf)) - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - else - T = null - switch(src.t_status) - if(1.0) - if( !portable() ) use_power(50, ENVIRON) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.holding.gas.transfer_from(src.gas, t) - else - if (T) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.turf_add(T, t) - if(2.0) - if( !portable() ) use_power(50, ENVIRON) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.transfer_from(src.holding.gas, t) - else - if (T) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (t > t2) - t = t2 - //var/g = gas.tot_gas() - //if(dbg) world.log << "VP0 : [t] from turf: [gas.tot_gas()]" - //if(dbg) Air() - - src.gas.turf_take(T, t) - //if(dbg) world.log << "VP1 : now [gas.tot_gas()]" - - //if(dbg) world.log << "[gas.tot_gas()-g] ([t]) from turf to siph" - - //if(dbg) Air() - if(4.0) - if( !portable() ) - use_power(50, ENVIRON) - - if (T) - if (T.firelevel > 900000.0) - src.f_time = world.time + 300 - else - if (world.time > src.f_time) - var/difference = CELLSTANDARD - (T.oxygen + T.n2) - if (difference > 0) - var/t1 = src.gas.tot_gas() - if (difference > t1) - difference = t1 - src.gas.turf_add(T, difference) - - /*if (src.c_status == 1) // 1 = release - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.receive_gas(gas, c_per) - return - else - src.c_status = 0 - else if(src.c_status == 2) // 2 = accept - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.send_gas(gas, c_per) // connector will send case to canister - return - */ - - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(632) - src.setstate() - return - -/obj/machinery/atmoalter/siphs/attack_paw(user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/atmoalter/siphs/attack_hand(var/mob/user as mob) - - if(stat & NOPOWER) return - user.machine = src - var/tt - switch(src.t_status) - if(1.0) - tt = text("Releasing
Siphon Stop", src, src) - if(2.0) - tt = text("Release Siphoning Stop", src, src) - if(3.0) - tt = text("Release Siphon Stopped Automatic", src, src, src) - else - tt = "Automatic equalizers are on!" - var/ct = null - switch(src.c_status) - if(1.0) - ct = text("Releasing Accept Stop", src, src) - if(2.0) - ct = text("Release Accepting Stop", src, src) - if(3.0) - ct = text("Release Accept Stopped", src, src) - else - ct = "Disconnected" - var/at = null - if (src.t_status == 4) - at = text("Automatic On Stop", src) - var/dat = text("Canister Valves []
\n\tContains/Capacity [] / []
\n\tUpper Valve Status: [] []
\n\t\tM - - - - [] + + + + M
\n\tPipe Valve Status: []
\n\t\tM - - - - [] + + + + M
\n
\n\nClose
\n\t
", (!( src.alterable ) ? "Valves are locked. Unlock with wrench!" : "You can lock this interface with a wrench."), num2text(src.gas.tot_gas(), 10), num2text(src.maximum, 10), (src.t_status == 4 ? text("[]", at) : text("[]", tt)), (src.holding ? text("
(Tank ([])", src, src.holding.gas.tot_gas()) : null), src, num2text(max_valve, 7), src, src, src, src, src.t_per, src, src, src, src, src, num2text(max_valve, 7), ct, src, num2text(max_valve, 7), src, src, src, src, src.c_per, src, src, src, src, src, num2text(max_valve, 7), user) - user << browse(dat, "window=siphon;size=600x300") - return - -/obj/machinery/atmoalter/siphs/Topic(href, href_list) - ..() - - if (usr.stat || usr.restrained()) - return - if (!( src.alterable )) - return - if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) - usr.machine = src - if (href_list["c"]) - var/c = text2num(href_list["c"]) - switch(c) - if(1.0) - src.c_status = 1 - if(2.0) - src.c_status = 2 - if(3.0) - src.c_status = 3 - else - else - if (href_list["t"]) - var/t = text2num(href_list["t"]) - if (src.t_status == 0) - return - switch(t) - if(1.0) - src.t_status = 1 - if(2.0) - src.t_status = 2 - if(3.0) - src.t_status = 3 - if(4.0) - src.t_status = 4 - src.f_time = 1 - else - else - if (href_list["tp"]) - var/tp = text2num(href_list["tp"]) - src.t_per += tp - src.t_per = min(max(round(src.t_per), 0), max_valve) - else - if (href_list["cp"]) - var/cp = text2num(href_list["cp"]) - src.c_per += cp - src.c_per = min(max(round(src.c_per), 0), max_valve) - else - if (href_list["tank"]) - var/cp = text2num(href_list["tank"]) - if (cp == 1) - src.holding.loc = src.loc - src.holding = null - if (src.t_status == 2) - src.t_status = 3 - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(433) - src.add_fingerprint(usr) - else - usr << browse(null, "window=canister") - return - return - -/obj/machinery/atmoalter/siphs/attackby(var/obj/W as obj, mob/user as mob) - - if (istype(W, /obj/item/weapon/tank)) - if (src.holding) - return - var/obj/item/weapon/tank/T = W - user.drop_item() - T.loc = src - src.holding = T - else - if (istype(W, /obj/item/weapon/screwdriver)) - var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) - if (src.c_status) - src.anchored = 0 - src.c_status = 0 - user.show_message("\blue You have disconnected the siphon.") - if(con) - con.connected = null - else - if (con && !con.connected) - src.anchored = 1 - src.c_status = 3 - user.show_message("\blue You have connected the siphon.") - con.connected = src - else - user.show_message("\blue There is nothing here to connect to the siphon.") - - - else - if (istype(W, /obj/item/weapon/wrench)) - src.alterable = !( src.alterable ) - if (src.alterable) - user << "\blue You unlock the interface!" - else - user << "\blue You lock the interface!" - return - diff --git a/main-src/Code/blob.dm b/main-src/Code/blob.dm index b233c8a..357c76f 100644 --- a/main-src/Code/blob.dm +++ b/main-src/Code/blob.dm @@ -48,7 +48,7 @@ var/p = health * (U.n2/11376000 + U.oxygen/1008000 + U.co2/200) if(!istype(U, /turf/space)) - p+=3 + p+=2 if(!prob(p)) return diff --git a/main-src/Code/cell_process.dm b/main-src/Code/cell_process.dm index d60a87f..50c21b0 100644 --- a/main-src/Code/cell_process.dm +++ b/main-src/Code/cell_process.dm @@ -148,7 +148,7 @@ //***** Label_299: - if ((locate(/obj/move, T) && T in L)) + if ((locate(/obj/move, T) && (T in L))) L -= T var/obj/move/O = locate(/obj/move, T) if (O.updatecell) diff --git a/main-src/Code/chemical.dm b/main-src/Code/chemical.dm index c3c7e33..061f247 100644 --- a/main-src/Code/chemical.dm +++ b/main-src/Code/chemical.dm @@ -618,6 +618,14 @@ heat is conserved between exchanges return 2*co2 + 1.5*n2 + oxygen + 0.5*sl_gas + 1.2*plasma +/obj/substance/gas/proc/tostring() + return "Tot: [src.tot_gas()] ; [oxygen]/[n2]/#[plasma]/[co2]/[sl_gas] ; Temp:[temperature]" + + +/turf/proc/tostring() + var/obj/substance/gas/G = src.get_gas() + return G.tostring() + /datum/chemical/pathogen/proc/process(source as obj) return diff --git a/main-src/Code/computer.dm b/main-src/Code/computer.dm index 126d91c..987540c 100644 --- a/main-src/Code/computer.dm +++ b/main-src/Code/computer.dm @@ -30,6 +30,7 @@ user.machine = null return 0 if ((get_dist(user, src) > 1 || user.machine != src || user.blinded || !( user.canmove ) || !( C.status ))) + user.machine = null return 0 else src.current = C diff --git a/main-src/Code/cryo.dm b/main-src/Code/cryo.dm index 906659a..2a60873 100644 --- a/main-src/Code/cryo.dm +++ b/main-src/Code/cryo.dm @@ -1089,7 +1089,7 @@ flow_to_turf(gas, ngas, T) - +/* /obj/machinery/freezer/orient_pipe(P as obj) if (!( src.line_out )) @@ -1098,7 +1098,7 @@ return 0 return 1 return - +*/ /obj/machinery/freezer/New() ..() @@ -1399,7 +1399,7 @@ src.verbs -= x src.icon_state = "broken" src.density = 0 - +/* /obj/machinery/cryo_cell/orient_pipe(P as obj) if (!( src.line_in )) @@ -1408,7 +1408,7 @@ return 0 return 1 return - +*/ /obj/machinery/cryo_cell/allow_drop() return 0 diff --git a/main-src/Code/demo.dm b/main-src/Code/demo.dm index 3a84550..a028cae 100644 --- a/main-src/Code/demo.dm +++ b/main-src/Code/demo.dm @@ -1,10 +1,3 @@ -/obj/machinery/New() - ..() - machines += src - -/obj/machinery/Del() - machines -= src - ..() /obj/machinery/door/meteorhit(obj/M as obj) @@ -507,294 +500,10 @@ src.operating = 0 return -/obj/machinery/igniter/attack_paw(mob/user as mob) - if ((ticker && ticker.mode == "monkey")) - return src.attack_hand(user) - return -/obj/machinery/igniter/attack_hand(mob/user as mob) - ..() - add_fingerprint(user) - if(stat & NOPOWER) return - use_power(50) - src.on = !( src.on ) - src.icon_state = text("igniter[]", src.on) - return - -/obj/machinery/igniter/process() - - if (src.on && !(stat & NOPOWER) ) - var/turf/T = src.loc - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - if (T.firelevel < 900000.0) - T.firelevel = T.poison - - return - -/obj/machinery/igniter/New() - ..() - icon_state = "igniter[on]" - -/obj/machinery/igniter/power_change() - if(!( stat & NOPOWER) ) - icon_state = "igniter[src.on]" - else - icon_state = "igniter0" - -/obj/machinery/firealarm/burn(fi_amount) - - if(src.detecting) src.alarm() // added check of detector status here - return - -/obj/machinery/firealarm/attack_paw(mob/user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/firealarm/attackby(obj/item/weapon/W as obj, mob/user as mob) - - if (istype(W, /obj/item/weapon/wirecutters)) - src.detecting = !( src.detecting ) - if (src.detecting) - viewers(user, null) << text("\red [] has reconnected []'s detecting unit!", user, src) - else - viewers(user, null) << text("\red [] has disconnected []'s detecting unit!", user, src) - else - src.alarm() - src.add_fingerprint(user) - return - -/obj/machinery/firealarm/process() - - if(stat & NOPOWER) - return - - use_power(10, ENVIRON) - - if (src.timing) - if (src.time > 0) - src.time = round(src.time) - 1 - else - alarm() - src.time = 0 - src.timing = 0 - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(68) - return - -/obj/machinery/firealarm/power_change() - if(powered(ENVIRON)) - stat &= ~NOPOWER - icon_state = "firealarm" - else - spawn(rand(0,15)) - stat |= NOPOWER - icon_state = "firealarm-p" - -/obj/machinery/firealarm/attack_hand(mob/user as mob) - - if(user.stat || stat&NOPOWER) return - - user.machine = src - var/area/A = src.loc - var/d1 - var/d2 - if (istype(user, /mob/human)) - A = A.loc - - if (A.fire) - d1 = text("Reset - Lockdown", src) - else - d1 = text("Alarm - Lockdown", src) - if (src.timing) - d2 = text("Stop Time Lock", src) - else - d2 = text("Initiate Time Lock", src) - var/second = src.time % 60 - var/minute = (src.time - second) / 60 - var/dat = text("Fire alarm []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) - user << browse(dat, "window=firealarm") - else - A = A.loc - if (A.fire) - d1 = text("[]", src, stars("Reset - Lockdown")) - else - d1 = text("[]", src, stars("Alarm - Lockdown")) - if (src.timing) - d2 = text("[]", src, stars("Stop Time Lock")) - else - d2 = text("[]", src, stars("Initiate Time Lock")) - var/second = src.time % 60 - var/minute = (src.time - second) / 60 - var/dat = text("[] []\n
\nTimer System: []
\nTime Left: [][] - - + +\n
", stars("Fire alarm"), d1, d2, (minute ? text("[]:", minute) : null), second, src, src, src, src) - user << browse(dat, "window=firealarm") - return - -/obj/machinery/firealarm/Topic(href, href_list) - ..() - if (usr.stat || stat&NOPOWER) - return - if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) - usr.machine = src - if (href_list["reset"]) - src.reset() - else - if (href_list["alarm"]) - src.alarm() - else - if (href_list["time"]) - src.timing = text2num(href_list["time"]) - else - if (href_list["tp"]) - var/tp = text2num(href_list["tp"]) - src.time += tp - src.time = min(max(round(src.time), 0), 120) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(194) - src.add_fingerprint(usr) - else - usr << browse(null, "window=firealarm") - return - return - -/obj/machinery/firealarm/proc/reset() - - if (!( src.working )) - return - var/area/A = src.loc - A = A.loc - if (!( istype(A, /area) )) - return - A.fire = 0 - A.mouse_opacity = 0 - A.updateicon() - - for(var/obj/machinery/door/firedoor/D in A) - if (D.density) - spawn( 0 ) - D.openfire() - return - //Foreach goto(93) - return - -/obj/machinery/firealarm/proc/alarm() - - if (!( src.working )) - return - var/area/A = src.loc - A = A.loc - if (!( istype(A, /area) )) - return - A.firealert() - return - -/obj/machinery/dispenser/ex_act(severity) - - switch(severity) - if(1.0) - //SN src = null - del(src) - return - if(2.0) - if (prob(50)) - //SN src = null - del(src) - return - if(3.0) - if (prob(25)) - while(src.o2tanks > 0) - new /obj/item/weapon/tank/oxygentank( src.loc ) - src.o2tanks-- - while(src.pltanks > 0) - new /obj/item/weapon/tank/plasmatank( src.loc ) - src.pltanks-- - else - return - -/obj/machinery/dispenser/blob_act() - - if (prob(25)) - while(src.o2tanks > 0) - new /obj/item/weapon/tank/oxygentank( src.loc ) - src.o2tanks-- - while(src.pltanks > 0) - new /obj/item/weapon/tank/plasmatank( src.loc ) - src.pltanks-- - del(src) - -/obj/machinery/dispenser/meteorhit() - - while(src.o2tanks > 0) - new /obj/item/weapon/tank/oxygentank( src.loc ) - src.o2tanks-- - while(src.pltanks > 0) - new /obj/item/weapon/tank/plasmatank( src.loc ) - src.pltanks-- - //SN src = null - del(src) - return - return - -/obj/machinery/dispenser/process() - if(stat & NOPOWER) - return - use_power(5) - -/obj/machinery/dispenser/attack_paw(mob/user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/dispenser/attack_hand(mob/user as mob) - - user.machine = src - var/dat = text("Loaded Tank Dispensing Unit
\nOxygen: [] []
\nPlasma: [] []
\n
", src.o2tanks, (src.o2tanks ? text("Dispense", src) : "empty"), src.pltanks, (src.pltanks ? text("Dispense", src) : "empty")) - user << browse(dat, "window=dispenser") - return - -/obj/machinery/dispenser/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained() ) - return - if ((!( istype(usr, /mob/human) ) && (!( ticker ) || (ticker && ticker.mode != "monkey")))) - usr << "\red You don't have the dexterity to do this!" - return - if ((usr.contents.Find(src) || (get_dist(src, usr) <= 1 && istype(src.loc, /turf)))) - usr.machine = src - if (href_list["oxygen"]) - if (text2num(href_list["oxygen"])) - if (src.o2tanks > 0) - use_power(5) - new /obj/item/weapon/tank/oxygentank( src.loc ) - src.o2tanks-- - if (istype(src.loc, /mob)) - attack_hand(src.loc) - else - if (href_list["plasma"]) - if (text2num(href_list["plasma"])) - if (src.pltanks > 0) - use_power(5) - new /obj/item/weapon/tank/plasmatank( src.loc ) - src.pltanks-- - if (istype(src.loc, /mob)) - attack_hand(src.loc) - src.add_fingerprint(usr) - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(275) - else - usr << browse(null, "window=dispenser") - return - return /obj/item/weapon/clothing/burn(fi_amount) diff --git a/main-src/Code/demo2.dm b/main-src/Code/demo2.dm index ebdbf81..fbdd560 100644 --- a/main-src/Code/demo2.dm +++ b/main-src/Code/demo2.dm @@ -107,585 +107,3 @@ return world return -/obj/machinery/atmoalter/heater/proc/setstate() - - if(stat & NOPOWER) - icon_state = "heater-p" - return - - if (src.holding) - src.icon_state = "heater1-h" - else - src.icon_state = "heater1" - return - -/obj/machinery/atmoalter/heater/process() - - if(stat & NOPOWER) return - use_power(5) - - var/turf/T = src.loc - if (istype(T, /turf)) - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - else - T = null - if (src.h_status) - var/t1 = src.gas.tot_gas() - if ((t1 > 0 && src.gas.temperature < (src.h_tar+T0C))) - var/increase = src.heatrate / t1 - var/n_temp = src.gas.temperature + increase - src.gas.temperature = min(n_temp, (src.h_tar+T0C)) - use_power( src.h_tar*8) - switch(src.t_status) - if(1.0) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.holding.gas.transfer_from(src.gas, t) - else - src.t_status = 3 - if(2.0) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.transfer_from(src.holding.gas, t) - else - src.t_status = 3 - else - - /* - if(src.c_status == 1) // 1 = release - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.receive_gas(gas, c_per ) - return - - else - src.c_status = 0 - else if(src.c_status == 2) // 2 = accept - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.send_gas(gas, c_per) // connector will send gas to canister - return - */ - - - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(432) - src.setstate() - return - -/obj/machinery/atmoalter/heater/New() - - ..() - src.gas = new /obj/substance/gas( src ) - src.gas.maximum = src.maximum - return - -/obj/machinery/atmoalter/heater/attack_paw(mob/user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/atmoalter/heater/attack_hand(var/mob/user as mob) - - if(stat & NOPOWER) return - - user.machine = src - var/tt - switch(src.t_status) - if(1.0) - tt = text("Releasing Siphon Stop", src, src) - if(2.0) - tt = text("Release SiphoningStop", src, src) - if(3.0) - tt = text("Release Siphon Stopped", src, src) - else - var/ht = null - if (src.h_status) - ht = text("Heating Stop", src) - else - ht = text("Heat Stopped", src) - var/ct = null - switch(src.c_status) - if(1.0) - ct = text("Releasing Accept Stop", src, src) - if(2.0) - ct = text("Release Accepting Stop", src, src) - if(3.0) - ct = text("Release Accept Stopped", src, src) - else - ct = "Disconnected" - var/dat = text("Canister Valves
\nContains/Capacity [] / []
\nUpper Valve Status: [][]
\n\tM - - - - [] + + + + M
\nHeater Status: [] - []
\n\tTrg Tmp: - - - [] + + +
\n
\nPipe Valve Status: []
\n\tM - - - - [] + + + + M
\n
\nClose
\n
", src.gas.tot_gas(), src.maximum, tt, (src.holding ? text("
Tank ([])", src, src.holding.gas.tot_gas()) : null), src, num2text(1000000.0, 7), src, src, src, src, src.t_per, src, src, src, src, src, num2text(1000000.0, 7), ht, (src.gas.tot_gas() ? (src.gas.temperature-T0C) : 20), src, src, src, src.h_tar, src, src, src, ct, src, num2text(1000000.0, 7), src, src, src, src, src.c_per, src, src, src, src, src, num2text(1000000.0, 7), user) - user << browse(dat, "window=canister;size=600x300") - return - -/obj/machinery/atmoalter/heater/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained()) - return - if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) - usr.machine = src - if (href_list["c"]) - var/c = text2num(href_list["c"]) - switch(c) - if(1.0) - src.c_status = 1 - if(2.0) - src.c_status = 2 - if(3.0) - src.c_status = 3 - else - else - if (href_list["t"]) - var/t = text2num(href_list["t"]) - if (src.t_status == 0) - return - switch(t) - if(1.0) - src.t_status = 1 - if(2.0) - src.t_status = 2 - if(3.0) - src.t_status = 3 - else - else - if (href_list["h"]) - var/h = text2num(href_list["h"]) - if (h == 1) - src.h_status = 1 - else - src.h_status = null - else - if (href_list["tp"]) - var/tp = text2num(href_list["tp"]) - src.t_per += tp - src.t_per = min(max(round(src.t_per), 0), 1000000.0) - else - if (href_list["cp"]) - var/cp = text2num(href_list["cp"]) - src.c_per += cp - src.c_per = min(max(round(src.c_per), 0), 1000000.0) - else - if (href_list["ht"]) - var/cp = text2num(href_list["ht"]) - src.h_tar += cp - src.h_tar = min(max(round(src.h_tar), 0), 500) - else - if (href_list["tank"]) - var/cp = text2num(href_list["tank"]) - if ((cp == 1 && src.holding)) - src.holding.loc = src.loc - src.holding = null - if (src.t_status == 2) - src.t_status = 3 - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(515) - src.add_fingerprint(usr) - else - usr << browse(null, "window=canister") - return - return - -/obj/machinery/atmoalter/heater/attackby(var/obj/W as obj, var/mob/user as mob) - - if (istype(W, /obj/item/weapon/tank)) - if (src.holding) - return - var/obj/item/weapon/tank/T = W - user.drop_item() - T.loc = src - src.holding = T - else - if (istype(W, /obj/item/weapon/wrench)) - var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) - - if (src.c_status) - src.anchored = 0 - src.c_status = 0 - user.show_message("\blue You have disconnected the heater.", 1) - if(con) - con.connected = null - else - if (con && !con.connected) - src.anchored = 1 - src.c_status = 3 - user.show_message("\blue You have connected the heater.", 1) - con.connected = src - else - user.show_message("\blue There is no connector here to attach the heater to.", 1) - return - - -/obj/machinery/atmoalter/canister/proc/update_icon() - - var/air_in = src.gas.tot_gas() - - src.overlays = 0 - - if (src.destroyed) - src.icon_state = text("[]-1", src.color) - - else - icon_state = "[color]" - if(holding) - overlays += image('canister.dmi', "can-oT") - - if (air_in < 10) - overlays += image('canister.dmi', "can-o0") - else if (air_in < (src.gas.maximum * 0.2)) - overlays += image('canister.dmi', "can-o1") - else if (air_in < (src.maximum * 0.6)) - overlays += image('canister.dmi', "can-o2") - else - overlays += image('canister.dmi', "can-o3") - return - -/obj/machinery/atmoalter/canister/proc/healthcheck() - - if (src.health <= 10) - var/T = src.loc - if (!( istype(T, /turf) )) - return - src.gas.turf_add(T, -1.0) - src.destroyed = 1 - src.density = 0 - update_icon() - if (src.holding) - src.holding.loc = src.loc - src.holding = null - if (src.t_status == 2) - src.t_status = 3 - return - -/obj/machinery/atmoalter/canister/process() - - if (src.destroyed) - return - var/T = src.loc - if (istype(T, /turf)) - if (locate(/obj/move, T)) - T = locate(/obj/move, T) - else - T = null - switch(src.t_status) - if(1.0) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.holding.gas.transfer_from(src.gas, t) - else - if (T) - var/t1 = src.gas.tot_gas() - var/t2 = t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.turf_add(T, t) - src.update_icon() - if(2.0) - if (src.holding) - var/t1 = src.gas.tot_gas() - var/t2 = src.maximum - t1 - var/t = src.t_per - if (src.t_per > t2) - t = t2 - src.gas.transfer_from(src.holding.gas, t) - else - src.t_status = 3 - src.update_icon() - else - - -// new method does all transfers in connector ptick - -/* if(src.c_status == 1) // 1 = release - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.receive_gas(gas, c_per ) - return - src.update_icon() - else - src.c_status = 0 - else if(src.c_status == 2) // 2 = accept - var/obj/machinery/connector/C = locate(/obj/machinery/connector, src.loc) - if (C && C.connected == src) - spawn( 0 ) - C.send_gas(gas, c_per) // connector will send gas to canister - return - src.update_icon() -*/ - - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(450) - src.update_icon() - return - -/obj/machinery/atmoalter/canister/New() - - ..() - src.gas = new /obj/substance/gas( src ) - src.gas.maximum = src.maximum - return - -/obj/machinery/atmoalter/canister/get_gas() - return gas - - -/obj/machinery/atmoalter/canister/burn(fi_amount) - - src.health -= 1 - healthcheck() - return - -/obj/machinery/atmoalter/canister/blob_act() - - src.health -= 1 - healthcheck() - return - - -/obj/machinery/atmoalter/canister/meteorhit(var/obj/O as obj) - - src.health = 0 - healthcheck() - return - -/obj/machinery/atmoalter/canister/attack_paw(var/mob/user as mob) - - return src.attack_hand(user) - return - -/obj/machinery/atmoalter/canister/attack_hand(var/mob/user as mob) - - if (src.destroyed) - return - user.machine = src - var/tt - switch(src.t_status) - if(1.0) - tt = text("Releasing Siphon (only tank) Stop", src, src) - if(2.0) - tt = text("Release Siphoning (only tank) Stop", src, src) - if(3.0) - tt = text("Release Siphon (only tank) Stopped", src, src) - else - var/ct = null - switch(src.c_status) - if(1.0) - ct = text("Releasing Accept Stop", src, src) - if(2.0) - ct = text("Release Accepting Stop", src, src) - if(3.0) - ct = text("Release Accept Stopped", src, src) - else - ct = "Disconnected" - - - var/dat = {"Canister Valves
-Contains/Capacity [num2text(src.gas.tot_gas(), 20)] / [num2text(src.maximum, 20)]
-Upper Valve Status: [tt]
-\t[(src.holding ? "Tank ([src.holding.gas.tot_gas()])" : null)]
-\tM - - - - [src.t_per] + + + + M
-Pipe Valve Status: [ct]
-\tM - - - - [src.c_per] + + + + M
-
-Close
-
"} - - - - /* - - var/dat = text({"Canister Valves
-Contains/Capacity [] / []
-Upper Valve Status: []
-\t[]
-\tM - - - - [] + + + + M
-Pipe Valve Status: []
-\tM - - - - [] + + + + M
-
-Close
-
"}, num2text(src.gas.tot_gas(), 20), num2text(src.maximum, 20), tt, (src.holding ? text("Tank ([])", src, src.holding.gas.tot_gas()) : null), src, num2text(1000000.0, 7), src, src, src, src, src.t_per, src, src, src, src, src, num2text(1000000.0, 7), ct, src, num2text(1000000.0, 7), src, src, src, src, src.c_per, src, src, src, src, src, num2text(1000000.0, 7), user) - -*/ - user << browse(dat, "window=canister;size=600x300") - return - -/obj/machinery/atmoalter/canister/Topic(href, href_list) - ..() - if (usr.stat || usr.restrained()) - return - if ((get_dist(src, usr) <= 1 && istype(src.loc, /turf))) - usr.machine = src - if (href_list["c"]) - var/c = text2num(href_list["c"]) - switch(c) - if(1.0) - src.c_status = 1 - if(2.0) - c_status = 2 - if(3.0) - src.c_status = 3 - else - if (href_list["t"]) - var/t = text2num(href_list["t"]) - if (src.t_status == 0) - return - switch(t) - if(1.0) - src.t_status = 1 - if(2.0) - if (src.holding) - src.t_status = 2 - else - src.t_status = 3 - if(3.0) - src.t_status = 3 - else - if (href_list["tp"]) - var/tp = text2num(href_list["tp"]) - src.t_per += tp - src.t_per = min(max(round(src.t_per), 0), 1000000.0) - else - if (href_list["cp"]) - var/cp = text2num(href_list["cp"]) - src.c_per += cp - src.c_per = min(max(round(src.c_per), 0), 1000000.0) - else - if (href_list["tank"]) - var/cp = text2num(href_list["tank"]) - if ((cp == 1 && src.holding)) - src.holding.loc = src.loc - src.holding = null - if (src.t_status == 2) - src.t_status = 3 - for(var/mob/M in viewers(1, src)) - if ((M.client && M.machine == src)) - src.attack_hand(M) - //Foreach goto(423) - src.add_fingerprint(usr) - update_icon() - else - usr << browse(null, "window=canister") - return - return - -/obj/machinery/atmoalter/canister/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob) - - if ((istype(W, /obj/item/weapon/tank) && !( src.destroyed ))) - if (src.holding) - return - var/obj/item/weapon/tank/T = W - user.drop_item() - T.loc = src - src.holding = T - update_icon() - else - if ((istype(W, /obj/item/weapon/wrench))) - var/obj/machinery/connector/con = locate(/obj/machinery/connector, src.loc) - - - if (src.c_status) - src.anchored = 0 - src.c_status = 0 - user.show_message("\blue You have disconnected the canister.", 1) - if(con) - con.connected = null - else - if(con && !con.connected && !destroyed) - src.anchored = 1 - src.c_status = 3 - user.show_message("\blue You have connected the canister.", 1) - con.connected = src - else - user.show_message("\blue There is nothing here with which to connect the canister.", 1) - else - switch(W.damtype) - if("fire") - src.health -= W.force - if("brute") - src.health -= W.force * 0.5 - else - src.healthcheck() - ..() - return - -/obj/machinery/atmoalter/canister/las_act(flag) - - if (flag == "bullet") - src.health = 0 - spawn( 0 ) - healthcheck() - return - if (flag) - var/turf/T = src.loc - if (!( istype(T, /turf) )) - return - else - T.firelevel = T.poison - else - src.health = 0 - spawn( 0 ) - healthcheck() - return - return - -/obj/machinery/atmoalter/canister/poisoncanister/New() - - ..() - src.update_icon() - src.gas.plasma = 9.0E7*filled - return - -/obj/machinery/atmoalter/canister/oxygencanister/New() - - ..() - src.gas.oxygen = 1.0E8*filled - return - -/obj/machinery/atmoalter/canister/anesthcanister/New() - - ..() - src.gas.sl_gas = 1.0E8*filled - return - -/obj/machinery/atmoalter/canister/n2canister/New() - - ..() - src.gas.n2 = 1.0E8*filled - return - -/obj/machinery/atmoalter/canister/co2canister/New() - - ..() - src.gas.co2 = 1.0E8*filled - return - - -/obj/machinery/atmoalter/canister/aircanister/New() - - ..() - src.gas.oxygen = 2.1e7*filled - src.gas.n2 = 7.9e7*filled - return - diff --git a/main-src/Code/engine.dm b/main-src/Code/engine.dm index 4f64314..4a82927 100644 --- a/main-src/Code/engine.dm +++ b/main-src/Code/engine.dm @@ -154,6 +154,12 @@ step(user.pulling, get_dir(user.pulling.loc, src)) return +/turf/station/engine/attackby(obj/item/weapon/C as obj, mob/user as mob) + + if (istype(C, /obj/item/weapon/pipe) ) + var/obj/item/weapon/pipe/P = C + P.turf_place(src, user) + /turf/station/engine/floor/ex_act(severity) switch(severity) @@ -250,6 +256,7 @@ S.temp = T.temp S.ttemp = T.ttemp S.otemp = T.otemp + S.firelevel = T.firelevel //Foreach goto(100) S.buildlinks() @@ -324,40 +331,3 @@ -/obj/machinery/gas_sensor/proc/sense_string() - - var/t = "" - - var/turf/T = src.loc - - var/turf_total = T.tot_gas() - - var/t1 = add_tspace("[round(turf_total / CELLSTANDARD * 100, 0.1)]%",6) - t += "
Pressure: [t1] Temperature: [round(T.temp - T0C,0.1)]°C
" - - if(turf_total == 0) - t+="O2: 0 N2: 0 CO2: 0>
Plasma: 0 N20: 0" - else - t1 = add_tspace(round(T.oxygen/turf_total * 100, 0.1),5) - - t += "O2: [t1] " - - t1 = add_tspace(round(T.n2/turf_total * 100, 0.1),5) - - t += "N2: [t1] " - - t1 = add_tspace(round(T.co2/turf_total * 100, 0.01),5) - - t += "CO2: [t1]
" - - t1 = add_tspace(round(T.poison/turf_total * 100, 0.001),5) - - t += "Plasma: [t1] " - - t1 = add_tspace(round(T.sl_gas/turf_total * 100, 0.001),5) - - t += "N2O: [t1]" - - t += "
" - - return t diff --git a/main-src/Code/globals.dm b/main-src/Code/globals.dm index 09dfd7c..1b6839e 100644 --- a/main-src/Code/globals.dm +++ b/main-src/Code/globals.dm @@ -1,64 +1,67 @@ +/* Most recent changes (Since H9.5) + + Started pipelaying system, /obj/item/weapon/pipe. + + Added burning icon for labcoat + Fixed a minor airsystem bug for /obj/moves + Fixed admin toggle of mode-voting message (now reports state of allowvotemode correctly) + Engine ejection now carries over firelevel of turfs + Fixed bug with aux engine not working if started too quickly. + + Converted pipelines to use list exclusively, rather than numbers (so that list can be modified) + Continues pipe laying - some checking of new lines now done, needs 2-pipe case + + Finished pipe laying - needs checking for all cases + + Updated autolathe to make pipe fittings + + Changed maximum circulator rates to give a better range of working values. + Fixed firealarm triggering when unpowered. + Made a temporary fix to runtime errors when blob attacks pipes (until full pipe damage system implemented). + + Code reorganization of obj/machinery continued. + +*/ + + + /* To-do list Bugs: hearing inside closets/pods check head protection when hit by tank etc. - //gas propagation on obj/move cells? plasma doesn't leak. + Double message at end of round. + + gas progagation btwen obj/move & turfs - no flow + due to turf/updatecell not counting /obj/moves as sources + //firelevel lost when ejecting engine - //turf-proc to reveal hidden (invis) pipes/wire/etc. when turf.intact variable is changed. - //(Check also build/remove for walls etc.) bug with two single-length pipes overlaying - pipeline ends up with no members - //cable under wall/rwall when deconstructed - run levelupdate - //making rglass with toolbox in r-hand - spawn on ground instead? - //also single rod in hand, make it just use 1 of rod with 1 of glass - - //gas in heater loop - can accept infinite amount into canister - //valves need power to switch, even manually - //heater connection - alarm continuing when power out? - //can't connect new cable to directconnect power machines - //cable - lay in dirn of mob facing when click on same turf + New: - //add/check all cameras & tags + recode obj/move stuff to use turfs exclusively? - //prison warden gets grey jumpsuit - - //power/engine - make useful? Needs local power DU, check for all machines. Power reserve. Engine generator. make regular glass melt in fire Blood splatters, can sample DNA & analyze also blood stains on clothing - attacker & defender whole body anaylzer in medbay - shows damage areas in popup? - //special closet for captain - spare ID, special uniform? - try station map maximizing use of image rather than icon useful world/Topic commands - //examine object flags flow rate maximum for pipes - slowest of two connected notes system for breaking / making pipes, handle deletion, pipeline spliting/rejoining etc. - ?give nominal values to all gas.maximum since turf_take depends on them - - //integrate vote system with admin system - allow admin to start vote even if disabled, etc. - - //update canister icons to use overlays for status - //impliment other canister colours, e.g. air (O2+N2), new one for N2O - - //add pipe/cable revealing detector a-la infra-sensor - - //add fingerprints to wire/cable actions - add power-off mode for computers & other equipment (with reboot time) @@ -66,11 +69,6 @@ for prison warden/sec - baton allows precise targeting - //recharger for batteries - - //secret - spawn wave of meteors - //limit rate of spawn (timer) - portable generator - hook to wire system modular repair/construction system @@ -80,16 +78,10 @@ hats/caps - //labcoat suit? - //voting while dead, voting defaults - - //admin PM - able to reply - move to mob topic? build/unbuild engine floor with rf sheet - finish compressor/turbine - think about control system, throttle, etc. - crowbar opens airlocks when no power */ @@ -99,9 +91,23 @@ var world_message = "Welcome to SS13!" savefile_ver = "3" - SS13_version = "40.93.2H9.5" + SS13_version = "40.93.2H9.6" changes = {"Changes from base version 40.93.2

+

Version 40.93.2H9.6 +

Version 40.93.2H9.5