diff --git a/README.md b/README.md index 661c7de6fde..67e5156428c 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Click [here](https://github.com/Baystation12/Baystation12/archive/master.zip) to The more complicated and easier to update method is using git. You'll need to download git or some client from [here](http://git-scm.com/). When that's installed, right click in any folder and click on "Git Bash". When that opens, type in: - git clone git@github.com:Baystation12/Baystation12.git + git clone https://github.com/Baystation12/Baystation12.git (hint: hold down ctrl and press insert to paste into git bash) diff --git a/baystation12.dme b/baystation12.dme index 802413560a2..9348f106ce0 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -216,8 +216,6 @@ #include "code\game\gamemodes\setupgame.dm" #include "code\game\gamemodes\autotraitor\autotraitor.dm" #include "code\game\gamemodes\blob\blob.dm" -#include "code\game\gamemodes\blob\blob_finish.dm" -#include "code\game\gamemodes\blob\blob_report.dm" #include "code\game\gamemodes\blob\theblob.dm" #include "code\game\gamemodes\blob\blobs\core.dm" #include "code\game\gamemodes\blob\blobs\factory.dm" @@ -248,6 +246,7 @@ #include "code\game\gamemodes\events\holidays\Holidays.dm" #include "code\game\gamemodes\events\holidays\Other.dm" #include "code\game\gamemodes\extended\extended.dm" +#include "code\game\gamemodes\heist\heist.dm" #include "code\game\gamemodes\malfunction\Malf_Modules.dm" #include "code\game\gamemodes\malfunction\malfunction.dm" #include "code\game\gamemodes\meteor\meteor.dm" @@ -313,6 +312,7 @@ #include "code\game\machinery\newscaster.dm" #include "code\game\machinery\OpTable.dm" #include "code\game\machinery\overview.dm" +#include "code\game\machinery\podmen.dm" #include "code\game\machinery\portable_turret.dm" #include "code\game\machinery\recharger.dm" #include "code\game\machinery\rechargestation.dm" @@ -375,10 +375,12 @@ #include "code\game\machinery\computer\robot.dm" #include "code\game\machinery\computer\security.dm" #include "code\game\machinery\computer\shuttle.dm" +#include "code\game\machinery\computer\skills.dm" #include "code\game\machinery\computer\specops_shuttle.dm" #include "code\game\machinery\computer\station_alert.dm" #include "code\game\machinery\computer\syndicate_shuttle.dm" #include "code\game\machinery\computer\syndicate_specops_shuttle.dm" +#include "code\game\machinery\computer\vox_shuttle.dm" #include "code\game\machinery\doors\airlock.dm" #include "code\game\machinery\doors\airlock_electronics.dm" #include "code\game\machinery\doors\alarmlock.dm" @@ -486,6 +488,7 @@ #include "code\game\objects\items\devices\lightreplacer.dm" #include "code\game\objects\items\devices\multitool.dm" #include "code\game\objects\items\devices\paicard.dm" +#include "code\game\objects\items\devices\pipe_painter.dm" #include "code\game\objects\items\devices\powersink.dm" #include "code\game\objects\items\devices\scanners.dm" #include "code\game\objects\items\devices\taperecorder.dm" @@ -846,6 +849,7 @@ #include "code\modules\mob\death.dm" #include "code\modules\mob\emote.dm" #include "code\modules\mob\inventory.dm" +#include "code\modules\mob\language.dm" #include "code\modules\mob\login.dm" #include "code\modules\mob\logout.dm" #include "code\modules\mob\mob.dm" @@ -876,6 +880,7 @@ #include "code\modules\mob\living\carbon\carbon_defines.dm" #include "code\modules\mob\living\carbon\give.dm" #include "code\modules\mob\living\carbon\shock.dm" +#include "code\modules\mob\living\carbon\species.dm" #include "code\modules\mob\living\carbon\alien\alien.dm" #include "code\modules\mob\living\carbon\alien\death.dm" #include "code\modules\mob\living\carbon\alien\login.dm" @@ -1321,7 +1326,6 @@ #include "code\WorkInProgress\Cael_Aislinn\Supermatter\ZeroPointLaser.dm" #include "code\WorkInProgress\Chinsky\ashtray.dm" #include "code\WorkInProgress\Cib\MedicalSideEffects.dm" -#include "code\WorkInProgress\kilakk\responseteam.dm" #include "code\WorkInProgress\Mini\ATM.dm" #include "code\WorkInProgress\Mini\atmos_control.dm" #include "code\WorkInProgress\Ported\policetape.dm" diff --git a/code/ATMOSPHERICS/pipes.dm b/code/ATMOSPHERICS/pipes.dm index c9e763e8390..5baffbcb615 100644 --- a/code/ATMOSPHERICS/pipes.dm +++ b/code/ATMOSPHERICS/pipes.dm @@ -527,7 +527,7 @@ obj/machinery/atmospherics/pipe var/build_killswitch = 1 var/obj/machinery/atmospherics/node1 - New() + New() initialize_directions = dir ..() @@ -722,7 +722,7 @@ obj/machinery/atmospherics/pipe icon_state = "manifold_[connected]_[unconnected]" - if(!connected) + if(!connected) del(src) return @@ -951,7 +951,7 @@ obj/machinery/atmospherics/pipe return initialize() - + for(var/obj/machinery/atmospherics/target in get_step(src,1)) if(target.initialize_directions & 2) node1 = target @@ -1028,7 +1028,7 @@ obj/machinery/atmospherics/pipe manifold4w/general/hidden level = 1 icon_state = "manifold4w-f" - + cap name = "pipe endcap" desc = "An endcap for pipes" @@ -1117,28 +1117,9 @@ obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/u if (istype(src, /obj/machinery/atmospherics/pipe/vent)) return ..() - // ===== Handle paints ===== - if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/red)) - src.color = "red" - user << "\red You paint the pipe red." - update_icon() + if(istype(W,/obj/item/device/pipe_painter)) return 1 - if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/blue)) - src.color = "blue" - user << "\red You paint the pipe blue." - update_icon() - return 1 - if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/green)) - src.color = "green" - user << "\red You paint the pipe green." - update_icon() - return 1 - if(istype(W, /obj/item/weapon/reagent_containers/glass/paint/yellow)) - src.color = "yellow" - user << "\red You paint the pipe yellow." - update_icon() - return 1 - + if (!istype(W, /obj/item/weapon/wrench)) return ..() var/turf/T = src.loc diff --git a/code/WorkInProgress/Cael_Aislinn/Economy/EFTPOS.dm b/code/WorkInProgress/Cael_Aislinn/Economy/EFTPOS.dm index f3160a3f8a5..7a00499be4f 100644 --- a/code/WorkInProgress/Cael_Aislinn/Economy/EFTPOS.dm +++ b/code/WorkInProgress/Cael_Aislinn/Economy/EFTPOS.dm @@ -70,7 +70,7 @@ D.name = "small parcel - 'EFTPOS access code'" /obj/item/device/eftpos/proc/reconnect_database() - for(var/obj/machinery/account_database/DB in machines) + for(var/obj/machinery/account_database/DB in world) //Hotfix until someone finds out why it isn't in 'machines' if(DB.z == src.z) linked_db = DB break diff --git a/code/WorkInProgress/Mini/ATM.dm b/code/WorkInProgress/Mini/ATM.dm index a7c0544591b..97b056a2ca6 100644 --- a/code/WorkInProgress/Mini/ATM.dm +++ b/code/WorkInProgress/Mini/ATM.dm @@ -70,7 +70,7 @@ log transactions break /obj/machinery/atm/proc/reconnect_database() - for(var/obj/machinery/account_database/DB in machines) + for(var/obj/machinery/account_database/DB in world) //Hotfix until someone finds out why it isn't in 'machines' if( DB.z == src.z && !(DB.stat & NOPOWER) && DB.activated ) linked_db = DB break diff --git a/code/WorkInProgress/kilakk/responseteam.dm b/code/WorkInProgress/kilakk/responseteam.dm index bf237d60420..6faafad342f 100644 --- a/code/WorkInProgress/kilakk/responseteam.dm +++ b/code/WorkInProgress/kilakk/responseteam.dm @@ -119,6 +119,7 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams break spawn(0) + switch(alert(new_member, "You are an Emergency Response Team member! Are you a boy or a girl?",,"Male","Female")) if("Male") new_member.gender = MALE @@ -130,9 +131,12 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams if(!new_name) new_member.real_name = "Agent [pick("Red","Yellow","Orange","Silver","Gold", "Pink", "Purple", "Rainbow")]" // Choose a "random" agent name new_member.name = usr.real_name + new_member.mind.name = usr.real_name + else new_member.real_name = new_name new_member.name = new_name + new_member.mind.name = new_name // -- CHANGE APPEARANCE -- var/new_tone = input(new_member, "Please select your new skin tone: 1-220 (1=albino, 35=caucasian, 150=black, 220='very' black)", "Character Generation") as num @@ -179,9 +183,10 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams new_member.update_hair(1) new_member.mind_initialize() + new_member.mind.assigned_role = "Emergency Response Team" new_member.mind.special_role = "Emergency Response Team" - ticker.mode.traitors += new_member.mind // ERTs will show up at the end of the round on the "traitor" list + ticker.mode.traitors |= new_member.mind // ERTs will show up at the end of the round on the "traitor" list // Join message new_member << "\blue You are the Emergency Response Team[!leader_selected?"!":" Leader!"] \nAs a response team [!leader_selected?"member":"leader"] you answer directly to [!leader_selected?"your team leader.":"Central Command."] \nYou have been deployed by NanoTrasen Central Command in Tau Ceti to resolve a Code Red alert aboard [station_name()], and have been provided with the following instructions and information regarding your mission: \red [situation]" @@ -223,7 +228,7 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams // Put stuff into their backpacks equip_to_slot_or_del(new /obj/item/weapon/storage/box/engineer(src), slot_in_backpack) - equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid(src), slot_in_backpack) // Not sure about this + // equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(src), slot_in_backpack) // Regular medkit // Loyalty implants var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(src) @@ -245,5 +250,7 @@ var/global/admin_emergency_team = 0 // Used for admin-spawned response teams E.registered_name = real_name equip_to_slot_or_del(E, slot_wear_id) + update_icons() + return 1 diff --git a/code/ZAS/Airflow.dm b/code/ZAS/Airflow.dm index a2506bb2d92..894dc92c72b 100644 --- a/code/ZAS/Airflow.dm +++ b/code/ZAS/Airflow.dm @@ -225,142 +225,142 @@ proc/AirflowSpace(zone/A) if(M) M.GotoAirflowDest(n/10) //Sometimes shit breaks, and M isn't there after the spawn. -atom/movable - var/tmp/turf/airflow_dest - var/tmp/airflow_speed = 0 - var/tmp/airflow_time = 0 - var/tmp/last_airflow = 0 - proc/GotoAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) +/atom/movable/var/tmp/turf/airflow_dest +/atom/movable/var/tmp/airflow_speed = 0 +/atom/movable/var/tmp/airflow_time = 0 +/atom/movable/var/tmp/last_airflow = 0 + +/atom/movable/proc/GotoAirflowDest(n) + if(!airflow_dest) return + if(airflow_speed < 0) return + if(last_airflow > world.time - vsc.airflow_delay) return + if(airflow_speed) + airflow_speed = n/max(get_dist(src,airflow_dest),1) + return + last_airflow = world.time + if(airflow_dest == loc) + step_away(src,loc) + if(ismob(src)) + if(src:status_flags & GODMODE) return - last_airflow = world.time - if(airflow_dest == loc) - step_away(src,loc) - if(ismob(src)) - if(src:status_flags & GODMODE) + if(istype(src, /mob/living/carbon/human)) + if(src:buckled) return - if(istype(src, /mob/living/carbon/human)) - if(src:buckled) - return - if(src:shoes) - if(istype(src:shoes, /obj/item/clothing/shoes/magboots)) - if(src:shoes:magpulse) - return - src << "\red You are sucked away by airflow!" - var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful. - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = airflow_dest.x - src.x - yo = airflow_dest.y - src.y - od = 0 + if(src:shoes) + if(istype(src:shoes, /obj/item/clothing/shoes/magboots)) + if(src:shoes:magpulse) + return + src << "\red You are sucked away by airflow!" + var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful. + if(airflow_falloff < 1) airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) return - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - if(od) - density = 0 - sleep(1 * tick_multiplier) - else + return + airflow_speed = min(max(n * (9/airflow_falloff),1),9) + var + xo = airflow_dest.x - src.x + yo = airflow_dest.y - src.y + od = 0 + airflow_dest = null + if(!density) + density = 1 + od = 1 + while(airflow_speed > 0) + if(airflow_speed <= 0) return + airflow_speed = min(airflow_speed,15) + airflow_speed -= vsc.airflow_speed_decay + if(airflow_speed > 7) + if(airflow_time++ >= airflow_speed - 7) if(od) density = 0 - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if(od) - density = 1 - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - return - if(!istype(loc, /turf)) - return - step_towards(src, src.airflow_dest) - if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - - - proc/RepelAirflowDest(n) - if(!airflow_dest) return - if(airflow_speed < 0) return - if(last_airflow > world.time - vsc.airflow_delay) return - if(airflow_speed) - airflow_speed = n/max(get_dist(src,airflow_dest),1) - return - if(airflow_dest == loc) - step_away(src,loc) - if(ismob(src)) - if(src:status_flags & GODMODE) - return - if(istype(src, /mob/living/carbon/human)) - if(src:buckled) - return - if(src:shoes) - if(src:shoes.type == /obj/item/clothing/shoes/magboots) - if(src:shoes.flags & NOSLIP) - return - src << "\red You are pushed away by airflow!" - last_airflow = world.time - var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful. - if(airflow_falloff < 1) - airflow_dest = null - return - airflow_speed = min(max(n * (9/airflow_falloff),1),9) - var - xo = -(airflow_dest.x - src.x) - yo = -(airflow_dest.y - src.y) - od = 0 - airflow_dest = null - if(!density) - density = 1 - od = 1 - while(airflow_speed > 0) - if(airflow_speed <= 0) return - airflow_speed = min(airflow_speed,15) - airflow_speed -= vsc.airflow_speed_decay - if(airflow_speed > 7) - if(airflow_time++ >= airflow_speed - 7) - sleep(1 * tick_multiplier) - else - sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) - if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) - src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) - if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) - return - if(!istype(loc, /turf)) - return - step_towards(src, src.airflow_dest) - if(ismob(src) && src:client) - src:client:move_delay = world.time + vsc.airflow_mob_slowdown - airflow_dest = null - airflow_speed = 0 - airflow_time = 0 - if(od) - density = 0 - - Bump(atom/A) - if(airflow_speed > 0 && airflow_dest) - airflow_hit(A) + sleep(1 * tick_multiplier) else - airflow_speed = 0 - airflow_time = 0 - . = ..() + if(od) + density = 0 + sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) + if(od) + density = 1 + if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) + src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) + if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) + return + if(!istype(loc, /turf)) + return + step_towards(src, src.airflow_dest) + if(ismob(src) && src:client) + src:client:move_delay = world.time + vsc.airflow_mob_slowdown + airflow_dest = null + airflow_speed = 0 + airflow_time = 0 + if(od) + density = 0 + + +/atom/movable/proc/RepelAirflowDest(n) + if(!airflow_dest) return + if(airflow_speed < 0) return + if(last_airflow > world.time - vsc.airflow_delay) return + if(airflow_speed) + airflow_speed = n/max(get_dist(src,airflow_dest),1) + return + if(airflow_dest == loc) + step_away(src,loc) + if(ismob(src)) + if(src:status_flags & GODMODE) + return + if(istype(src, /mob/living/carbon/human)) + if(src:buckled) + return + if(src:shoes) + if(istype(src:shoes, /obj/item/clothing/shoes/magboots)) + if(src:shoes.flags & NOSLIP) + return + src << "\red You are pushed away by airflow!" + last_airflow = world.time + var/airflow_falloff = 9 - ul_FalloffAmount(airflow_dest) //It's a fast falloff calc. Very useful. + if(airflow_falloff < 1) + airflow_dest = null + return + airflow_speed = min(max(n * (9/airflow_falloff),1),9) + var + xo = -(airflow_dest.x - src.x) + yo = -(airflow_dest.y - src.y) + od = 0 + airflow_dest = null + if(!density) + density = 1 + od = 1 + while(airflow_speed > 0) + if(airflow_speed <= 0) return + airflow_speed = min(airflow_speed,15) + airflow_speed -= vsc.airflow_speed_decay + if(airflow_speed > 7) + if(airflow_time++ >= airflow_speed - 7) + sleep(1 * tick_multiplier) + else + sleep(max(1,10-(airflow_speed+3)) * tick_multiplier) + if ((!( src.airflow_dest ) || src.loc == src.airflow_dest)) + src.airflow_dest = locate(min(max(src.x + xo, 1), world.maxx), min(max(src.y + yo, 1), world.maxy), src.z) + if ((src.x == 1 || src.x == world.maxx || src.y == 1 || src.y == world.maxy)) + return + if(!istype(loc, /turf)) + return + step_towards(src, src.airflow_dest) + if(ismob(src) && src:client) + src:client:move_delay = world.time + vsc.airflow_mob_slowdown + airflow_dest = null + airflow_speed = 0 + airflow_time = 0 + if(od) + density = 0 + +/atom/movable/Bump(atom/A) + if(airflow_speed > 0 && airflow_dest) + airflow_hit(A) + else + airflow_speed = 0 + airflow_time = 0 + . = ..() atom/movable/proc/airflow_hit(atom/A) airflow_speed = 0 diff --git a/code/ZAS/Connection.dm b/code/ZAS/Connection.dm index f9697207c60..8a919d50435 100644 --- a/code/ZAS/Connection.dm +++ b/code/ZAS/Connection.dm @@ -6,393 +6,396 @@ Indirect connections will not merge the two zones after they reach equilibrium. #define CONNECTION_INDIRECT 1 #define CONNECTION_CLOSED 0 +/connection + var/turf/simulated/A + var/turf/simulated/B -connection - var - turf/simulated //The turfs involved in the connection. - A - B - zone - zone_A - zone_B - ref_A - ref_B - indirect = CONNECTION_DIRECT //If the connection is purely indirect, the zones should not join. - last_updated //The tick at which this was last updated. - no_zone_count = 0 + var/zone/zone_A + var/zone/zone_B + + var/ref_A + var/ref_B + + var/indirect = CONNECTION_DIRECT //If the connection is purely indirect, the zones should not join. + + var/last_updated //The tick at which this was last updated. + + var/no_zone_count = 0 - New(turf/T,turf/O) - A = T - B = O - if(A.zone && B.zone) - if(!A.zone.connections) A.zone.connections = list() - A.zone.connections += src - zone_A = A.zone - ref_A = "\ref[A]" - if(!B.zone.connections) B.zone.connections = list() - B.zone.connections += src - zone_B = B.zone - ref_B = "\ref[B]" +/connection/New(turf/T,turf/O) + A = T + B = O + if(A.zone && B.zone) + if(!A.zone.connections) A.zone.connections = list() + A.zone.connections += src + zone_A = A.zone + ref_A = "\ref[A]" - if(ref_A in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_A] - connections.Add(src) - else - air_master.turfs_with_connections[ref_A] = list(src) - - if(ref_B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_B] - connections.Add(src) - else - air_master.turfs_with_connections[ref_B] = list(src) - - if(A.CanPass(null, B, 0, 0)) - - ConnectZones(A.zone, B.zone, 1) - - if(A.HasDoor(B) || B.HasDoor(A)) - indirect = CONNECTION_INDIRECT - - else - ConnectZones(A.zone, B.zone) - indirect = CONNECTION_CLOSED - - - else - world.log << "Attempted to create connection object for non-zone tiles: [T] ([T.x],[T.y],[T.z]) -> [O] ([O.x],[O.y],[O.z])" - del(src) - - - Del() - //remove connections from master lists. - if(ref_B in air_master.turfs_with_connections) - var/list/connections = air_master.turfs_with_connections[ref_B] - connections.Remove(src) + if(!B.zone.connections) B.zone.connections = list() + B.zone.connections += src + zone_B = B.zone + ref_B = "\ref[B]" if(ref_A in air_master.turfs_with_connections) var/list/connections = air_master.turfs_with_connections[ref_A] - connections.Remove(src) + connections.Add(src) + else + air_master.turfs_with_connections[ref_A] = list(src) - //Remove connection from zones. - if(A) - if(A.zone && A.zone.connections) - A.zone.connections.Remove(src) - if(!A.zone.connections.len) - A.zone.connections = null + if(ref_B in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[ref_B] + connections.Add(src) + else + air_master.turfs_with_connections[ref_B] = list(src) - if(istype(zone_A) && (!A || A.zone != zone_A)) + if(A.CanPass(null, B, 0, 0)) + + ConnectZones(A.zone, B.zone, 1) + + if(A.HasDoor(B) || B.HasDoor(A)) + indirect = CONNECTION_INDIRECT + + else + ConnectZones(A.zone, B.zone) + indirect = CONNECTION_CLOSED + + + else + world.log << "Attempted to create connection object for non-zone tiles: [T] ([T.x],[T.y],[T.z]) -> [O] ([O.x],[O.y],[O.z])" + del(src) + + +/connection/Del() + //remove connections from master lists. + if(ref_B in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[ref_B] + connections.Remove(src) + + if(ref_A in air_master.turfs_with_connections) + var/list/connections = air_master.turfs_with_connections[ref_A] + connections.Remove(src) + + //Remove connection from zones. + if(A) + if(A.zone && A.zone.connections) + A.zone.connections.Remove(src) + if(!A.zone.connections.len) + A.zone.connections = null + + if(istype(zone_A) && (!A || A.zone != zone_A)) + if(zone_A.connections) + zone_A.connections.Remove(src) + if(!zone_A.connections.len) + zone_A.connections = null + + if(B) + if(B.zone && B.zone.connections) + B.zone.connections.Remove(src) + if(!B.zone.connections.len) + B.zone.connections = null + + if(istype(zone_B) && (!B || B.zone != zone_B)) + if(zone_B.connections) + zone_B.connections.Remove(src) + if(!zone_B.connections.len) + zone_B.connections = null + + //Disconnect zones while handling unusual conditions. + // e.g. loss of a zone on a turf + if(A && A.zone && B && B.zone) + DisconnectZones(A.zone, B.zone) + + //Finally, preform actual deletion. + . = ..() + + +/connection/proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0) + + //Sanity checking + if(!istype(zone_1) || !istype(zone_2)) + return + + //Handle zones connecting indirectly/directly. + if(open) + + //Create the lists if necessary. + if(!zone_1.connected_zones) + zone_1.connected_zones = list() + + if(!zone_2.connected_zones) + zone_2.connected_zones = list() + + //Increase the number of connections between zones. + if(zone_2 in zone_1.connected_zones) + zone_1.connected_zones[zone_2]++ + else + zone_1.connected_zones += zone_2 + zone_1.connected_zones[zone_2] = 1 + + if(zone_1 in zone_2.connected_zones) + zone_2.connected_zones[zone_1]++ + else + zone_2.connected_zones += zone_1 + zone_2.connected_zones[zone_1] = 1 + + //Handle closed connections. + else + + //Create the lists + if(!zone_1.closed_connection_zones) + zone_1.closed_connection_zones = list() + + if(!zone_2.closed_connection_zones) + zone_2.closed_connection_zones = list() + + //Increment the connections. + if(zone_2 in zone_1.closed_connection_zones) + zone_1.closed_connection_zones[zone_2]++ + else + zone_1.closed_connection_zones += zone_2 + zone_1.closed_connection_zones[zone_2] = 1 + + if(zone_1 in zone_2.closed_connection_zones) + zone_2.closed_connection_zones[zone_1]++ + else + zone_2.closed_connection_zones += zone_1 + zone_2.closed_connection_zones[zone_1] = 1 + + +/connection/proc/DisconnectZones(var/zone/zone_1, var/zone/zone_2) + //Sanity checking + if(!istype(zone_1) || !istype(zone_2)) + return + + if(indirect != CONNECTION_CLOSED) + //Handle disconnection of indirectly or directly connected zones. + if( (zone_1 in zone_2.connected_zones) || (zone_2 in zone_1.connected_zones) ) + + //If there are more than one connection, decrement the number of connections + //Otherwise, remove all connections between the zones. + if(zone_2 in zone_1.connected_zones) + if(zone_1.connected_zones[zone_2] > 1) + zone_1.connected_zones[zone_2]-- + else + zone_1.connected_zones -= zone_2 + //remove the list if it is empty + if(!zone_1.connected_zones.len) + zone_1.connected_zones = null + + //Then do the same for the other zone. + if(zone_1 in zone_2.connected_zones) + if(zone_2.connected_zones[zone_1] > 1) + zone_2.connected_zones[zone_1]-- + else + zone_2.connected_zones -= zone_1 + if(!zone_2.connected_zones.len) + zone_2.connected_zones = null + + else + //Handle disconnection of closed zones. + if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) ) + + //If there are more than one connection, decrement the number of connections + //Otherwise, remove all connections between the zones. + if(zone_2 in zone_1.closed_connection_zones) + if(zone_1.closed_connection_zones[zone_2] > 1) + zone_1.closed_connection_zones[zone_2]-- + else + zone_1.closed_connection_zones -= zone_2 + //remove the list if it is empty + if(!zone_1.closed_connection_zones.len) + zone_1.closed_connection_zones = null + + //Then do the same for the other zone. + if(zone_1 in zone_2.closed_connection_zones) + if(zone_2.closed_connection_zones[zone_1] > 1) + zone_2.closed_connection_zones[zone_1]-- + else + zone_2.closed_connection_zones -= zone_1 + if(!zone_2.closed_connection_zones.len) + zone_2.closed_connection_zones = null + + +/connection/proc/Cleanup() + + //Check sanity: existance of turfs + if(!A || !B) + del src + + //Check sanity: zones are different + if(A.zone == B.zone) + del src + + //Check sanity: same turfs as before. + if(ref_A != "\ref[A]" || ref_B != "\ref[B]") + del src + + //Handle zones changing on a turf. + if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B)) + Sanitize() + + //Manage sudden loss of a turfs zone. (e.g. a wall being built) + if(!A.zone || !B.zone) + no_zone_count++ + if(no_zone_count >= 5) + //world.log << "Connection removed: [A] or [B] missing a zone." + del src + return 0 + + return 1 + + +/connection/proc/CheckPassSanity() + //Sanity check, first. + Cleanup() + + if(A.zone && B.zone) + + //If no walls are blocking us... + if(A.ZAirPass(B)) + //...we check to see if there is a door in the way... + var/door_pass = A.CanPass(null,B,1.5,1) + //...and if it is opened. + if(door_pass || A.CanPass(null,B,0,0)) + + //Make and remove connections to let air pass. + if(indirect == CONNECTION_CLOSED) + DisconnectZones(A.zone, B.zone) + ConnectZones(A.zone, B.zone, 1) + + if(door_pass) + indirect = CONNECTION_DIRECT + else if(!door_pass) + indirect = CONNECTION_INDIRECT + + //The door is instead closed. + else if(indirect > CONNECTION_CLOSED) + DisconnectZones(A.zone, B.zone) + indirect = CONNECTION_CLOSED + ConnectZones(A.zone, B.zone) + + //If I can no longer pass air, better delete + else + del src + +/connection/proc/Sanitize() + //If the zones change on connected turfs, update it. + + //Both zones changed (wat) + if(A.zone && A.zone != zone_A && B.zone && B.zone != zone_B) + + //If the zones have gotten swapped + // (do not ask me how, I am just being anal retentive about sanity) + if(A.zone == zone_B && B.zone == zone_A) + var/turf/temp = B + B = A + A = temp + zone_B = B.zone + zone_A = A.zone + var/temp_ref = ref_A + ref_A = ref_B + ref_B = temp_ref + return + + //Handle removal of connections from archived zones. + if(zone_A && zone_A.connections) + zone_A.connections.Remove(src) + if(!zone_A.connections.len) + zone_A.connections = null + + if(zone_B && zone_B.connections) + zone_B.connections.Remove(src) + if(!zone_B.connections.len) + zone_B.connections = null + + if(A.zone) + if(!A.zone.connections) + A.zone.connections = list() + A.zone.connections |= src + + if(B.zone) + if(!B.zone.connections) + B.zone.connections = list() + B.zone.connections |= src + + //If either zone is null, we disconnect the archived ones after cleaning up the connections. + if(!A.zone || !B.zone) + if(zone_A && zone_B) + DisconnectZones(zone_B, zone_A) + + if(!A.zone) + zone_A = A.zone + + if(!B.zone) + zone_B = B.zone + return + + //Handle diconnection and reconnection of zones. + if(zone_A && zone_B) + DisconnectZones(zone_A, zone_B) + ConnectZones(A.zone, B.zone, indirect) + + //resetting values of archived values. + zone_B = B.zone + zone_A = A.zone + + //The "A" zone changed. + else if(A.zone && A.zone != zone_A) + + //Handle connection cleanup + if(zone_A) if(zone_A.connections) zone_A.connections.Remove(src) if(!zone_A.connections.len) zone_A.connections = null - if(B) - if(B.zone && B.zone.connections) - B.zone.connections.Remove(src) - if(!B.zone.connections.len) - B.zone.connections = null + if(A.zone) + if(!A.zone.connections) + A.zone.connections = list() + A.zone.connections |= src - if(istype(zone_B) && (!B || B.zone != zone_B)) + //If the "A" zone is null, we disconnect the archived ones after cleaning up the connections. + if(!A.zone) + if(zone_A && zone_B) + DisconnectZones(zone_A, zone_B) + zone_A = A.zone + return + + //Handle diconnection and reconnection of zones. + if(zone_A && zone_B) + DisconnectZones(zone_A, zone_B) + ConnectZones(A.zone, B.zone, indirect) + zone_A = A.zone + + //The "B" zone changed. + else if(B.zone && B.zone != zone_B) + + //Handle connection cleanup + if(zone_B) if(zone_B.connections) zone_B.connections.Remove(src) if(!zone_B.connections.len) zone_B.connections = null - //Disconnect zones while handling unusual conditions. - // e.g. loss of a zone on a turf - if(A && A.zone && B && B.zone) - DisconnectZones(A.zone, B.zone) + if(B.zone) + if(!B.zone.connections) + B.zone.connections = list() + B.zone.connections |= src - //Finally, preform actual deletion. - . = ..() - - - proc/ConnectZones(var/zone/zone_1, var/zone/zone_2, open = 0) - - //Sanity checking - if(!istype(zone_1) || !istype(zone_2)) - return - - //Handle zones connecting indirectly/directly. - if(open) - - //Create the lists if necessary. - if(!zone_1.connected_zones) - zone_1.connected_zones = list() - - if(!zone_2.connected_zones) - zone_2.connected_zones = list() - - //Increase the number of connections between zones. - if(zone_2 in zone_1.connected_zones) - zone_1.connected_zones[zone_2]++ - else - zone_1.connected_zones += zone_2 - zone_1.connected_zones[zone_2] = 1 - - if(zone_1 in zone_2.connected_zones) - zone_2.connected_zones[zone_1]++ - else - zone_2.connected_zones += zone_1 - zone_2.connected_zones[zone_1] = 1 - - //Handle closed connections. - else - - //Create the lists - if(!zone_1.closed_connection_zones) - zone_1.closed_connection_zones = list() - - if(!zone_2.closed_connection_zones) - zone_2.closed_connection_zones = list() - - //Increment the connections. - if(zone_2 in zone_1.closed_connection_zones) - zone_1.closed_connection_zones[zone_2]++ - else - zone_1.closed_connection_zones += zone_2 - zone_1.closed_connection_zones[zone_2] = 1 - - if(zone_1 in zone_2.closed_connection_zones) - zone_2.closed_connection_zones[zone_1]++ - else - zone_2.closed_connection_zones += zone_1 - zone_2.closed_connection_zones[zone_1] = 1 - - - proc/DisconnectZones(var/zone/zone_1, var/zone/zone_2) - - //Sanity checking - if(!istype(zone_1) || !istype(zone_2)) - return - - if(indirect != CONNECTION_CLOSED) - //Handle disconnection of indirectly or directly connected zones. - if( (zone_1 in zone_2.connected_zones) || (zone_2 in zone_1.connected_zones) ) - - //If there are more than one connection, decrement the number of connections - //Otherwise, remove all connections between the zones. - if(zone_2 in zone_1.connected_zones) - if(zone_1.connected_zones[zone_2] > 1) - zone_1.connected_zones[zone_2]-- - else - zone_1.connected_zones -= zone_2 - //remove the list if it is empty - if(!zone_1.connected_zones.len) - zone_1.connected_zones = null - - //Then do the same for the other zone. - if(zone_1 in zone_2.connected_zones) - if(zone_2.connected_zones[zone_1] > 1) - zone_2.connected_zones[zone_1]-- - else - zone_2.connected_zones -= zone_1 - if(!zone_2.connected_zones.len) - zone_2.connected_zones = null - - else - //Handle disconnection of closed zones. - if( (zone_1 in zone_2.closed_connection_zones) || (zone_2 in zone_1.closed_connection_zones) ) - - //If there are more than one connection, decrement the number of connections - //Otherwise, remove all connections between the zones. - if(zone_2 in zone_1.closed_connection_zones) - if(zone_1.closed_connection_zones[zone_2] > 1) - zone_1.closed_connection_zones[zone_2]-- - else - zone_1.closed_connection_zones -= zone_2 - //remove the list if it is empty - if(!zone_1.closed_connection_zones.len) - zone_1.closed_connection_zones = null - - //Then do the same for the other zone. - if(zone_1 in zone_2.closed_connection_zones) - if(zone_2.closed_connection_zones[zone_1] > 1) - zone_2.closed_connection_zones[zone_1]-- - else - zone_2.closed_connection_zones -= zone_1 - if(!zone_2.closed_connection_zones.len) - zone_2.closed_connection_zones = null - - - proc/Cleanup() - - //Check sanity: existance of turfs - if(!A || !B) - del src - - //Check sanity: zones are different - if(A.zone == B.zone) - del src - - //Check sanity: same turfs as before. - if(ref_A != "\ref[A]" || ref_B != "\ref[B]") - del src - - //Handle zones changing on a turf. - if((A.zone && A.zone != zone_A) || (B.zone && B.zone != zone_B)) - Sanitize() - - //Manage sudden loss of a turfs zone. (e.g. a wall being built) - if(!A.zone || !B.zone) - no_zone_count++ - if(no_zone_count >= 5) - //world.log << "Connection removed: [A] or [B] missing a zone." - del src - return 0 - - return 1 - - - proc/CheckPassSanity() - //Sanity check, first. - Cleanup() - - if(A.zone && B.zone) - - //If no walls are blocking us... - if(A.ZAirPass(B)) - //...we check to see if there is a door in the way... - var/door_pass = A.CanPass(null,B,1.5,1) - //...and if it is opened. - if(door_pass || A.CanPass(null,B,0,0)) - - //Make and remove connections to let air pass. - if(indirect == CONNECTION_CLOSED) - DisconnectZones(A.zone, B.zone) - ConnectZones(A.zone, B.zone, 1) - - if(door_pass) - indirect = CONNECTION_DIRECT - else if(!door_pass) - indirect = CONNECTION_INDIRECT - - //The door is instead closed. - else if(indirect > CONNECTION_CLOSED) - DisconnectZones(A.zone, B.zone) - indirect = CONNECTION_CLOSED - ConnectZones(A.zone, B.zone) - - //If I can no longer pass air, better delete - else - del src - - proc/Sanitize() - //If the zones change on connected turfs, update it. - - //Both zones changed (wat) - if(A.zone && A.zone != zone_A && B.zone && B.zone != zone_B) - - //If the zones have gotten swapped - // (do not ask me how, I am just being anal retentive about sanity) - if(A.zone == zone_B && B.zone == zone_A) - var/turf/temp = B - B = A - A = temp - zone_B = B.zone - zone_A = A.zone - var/temp_ref = ref_A - ref_A = ref_B - ref_B = temp_ref - return - - //Handle removal of connections from archived zones. - if(zone_A && zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null - - if(zone_B && zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - if(A.zone) - if(!A.zone.connections) - A.zone.connections = list() - A.zone.connections |= src - - if(B.zone) - if(!B.zone.connections) - B.zone.connections = list() - B.zone.connections |= src - - //If either zone is null, we disconnect the archived ones after cleaning up the connections. - if(!A.zone || !B.zone) - if(zone_A && zone_B) - DisconnectZones(zone_B, zone_A) - - if(!A.zone) - zone_A = A.zone - - if(!B.zone) - zone_B = B.zone - return - - //Handle diconnection and reconnection of zones. + //If the "B" zone is null, we disconnect the archived ones after cleaning up the connections. + if(!B.zone) if(zone_A && zone_B) DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) - - //resetting values of archived values. zone_B = B.zone - zone_A = A.zone + return - //The "A" zone changed. - else if(A.zone && A.zone != zone_A) - - //Handle connection cleanup - if(zone_A) - if(zone_A.connections) - zone_A.connections.Remove(src) - if(!zone_A.connections.len) - zone_A.connections = null - - if(A.zone) - if(!A.zone.connections) - A.zone.connections = list() - A.zone.connections |= src - - //If the "A" zone is null, we disconnect the archived ones after cleaning up the connections. - if(!A.zone) - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - zone_A = A.zone - return - - //Handle diconnection and reconnection of zones. - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) - - //The "B" zone changed. - else if(B.zone && B.zone != zone_B) - - //Handle connection cleanup - if(zone_B) - if(zone_B.connections) - zone_B.connections.Remove(src) - if(!zone_B.connections.len) - zone_B.connections = null - - if(B.zone) - if(!B.zone.connections) - B.zone.connections = list() - B.zone.connections |= src - - //If the "B" zone is null, we disconnect the archived ones after cleaning up the connections. - if(!B.zone) - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - zone_B = B.zone - return - - //Handle diconnection and reconnection of zones. - if(zone_A && zone_B) - DisconnectZones(zone_A, zone_B) - ConnectZones(A.zone, B.zone, indirect) + //Handle diconnection and reconnection of zones. + if(zone_A && zone_B) + DisconnectZones(zone_A, zone_B) + ConnectZones(A.zone, B.zone, indirect) + zone_B = B.zone #undef CONNECTION_DIRECT diff --git a/code/ZAS/Debug.dm b/code/ZAS/Debug.dm index b3f069a5540..807208a5a3e 100644 --- a/code/ZAS/Debug.dm +++ b/code/ZAS/Debug.dm @@ -8,7 +8,8 @@ client/proc/Zone_Info(turf/T as null|turf) mob << "No zone here." else if(zone_debug_images) - images -= zone_debug_images + for(var/zone in zone_debug_images) + images -= zone_debug_images[zone] zone_debug_images = null client/var/list/zone_debug_images @@ -23,12 +24,12 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf) "South" = SOUTH,\ "East" = EAST,\ "West" = WEST,\ - "None" = null) + "N/A" = null) var/direction = input("What direction do you wish to test?","Set direction") as null|anything in direction_list if(!direction) return - if(direction == "None") + if(direction == "N/A") if(T.CanPass(null, T, 0,0)) mob << "The turf can pass air! :D" else @@ -55,61 +56,67 @@ client/proc/Test_ZAS_Connection(var/turf/simulated/T as turf) mob << "Both turfs can connect! :)" -zone/proc - DebugDisplay(client/client) - if(!istype(client)) - return +zone/proc/DebugDisplay(client/client) + if(!istype(client)) + return - if(!dbg_output) - dbg_output = 1 //Don't want to be spammed when someone investigates a zone... + if(!dbg_output) + dbg_output = 1 //Don't want to be spammed when someone investigates a zone... - if(!client.zone_debug_images) - client.zone_debug_images = list() - for(var/turf/T in contents) - client.zone_debug_images += image('debug_group.dmi', T) + if(!client.zone_debug_images) + client.zone_debug_images = list() - for(var/turf/space/S in unsimulated_tiles) - client.zone_debug_images += image('debug_space.dmi', S) + var/list/current_zone_images = list() - client << "Zone Air Contents" - client << "Oxygen: [air.oxygen]" - client << "Nitrogen: [air.nitrogen]" - client << "Plasma: [air.toxins]" - client << "Carbon Dioxide: [air.carbon_dioxide]" - client << "Temperature: [air.temperature] K" - client << "Heat Energy: [air.temperature * air.heat_capacity()] J" - client << "Pressure: [air.return_pressure()] KPa" - client << "" - client << "Space Tiles: [length(unsimulated_tiles)]" - client << "Movable Objects: [length(movables())]" - client << "Connections: [length(connections)]" + for(var/turf/T in contents) + current_zone_images += image('debug_group.dmi', T, null, TURF_LAYER) - for(var/connection/C in connections) - client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]" - client.zone_debug_images += image('debug_connect.dmi', C.A) - client.zone_debug_images += image('debug_connect.dmi', C.B) + for(var/turf/space/S in unsimulated_tiles) + current_zone_images += image('debug_space.dmi', S, null, TURF_LAYER) - client << "Connected Zones:" - for(var/zone/zone in connected_zones) - client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)" + client << "Zone Air Contents" + client << "Oxygen: [air.oxygen]" + client << "Nitrogen: [air.nitrogen]" + client << "Plasma: [air.toxins]" + client << "Carbon Dioxide: [air.carbon_dioxide]" + client << "Temperature: [air.temperature] K" + client << "Heat Energy: [air.temperature * air.heat_capacity()] J" + client << "Pressure: [air.return_pressure()] KPa" + client << "" + client << "Space Tiles: [length(unsimulated_tiles)]" + client << "Movable Objects: [length(movables())]" + client << "Connections: [length(connections)]" - for(var/zone/zone in closed_connection_zones) - client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)" + for(var/connection/C in connections) + client << "\ref[C] [C.A] --> [C.B] [(C.indirect?"Open":"Closed")]" + current_zone_images += image('debug_connect.dmi', C.A, null, TURF_LAYER) + current_zone_images += image('debug_connect.dmi', C.B, null, TURF_LAYER) - for(var/C in connections) - if(!istype(C,/connection)) - client << "[C] (Not Connection!)" + client << "Connected Zones:" + for(var/zone/zone in connected_zones) + client << "\ref[zone] [zone] - [connected_zones[zone]] (Connected)" - client.images += client.zone_debug_images + for(var/zone/zone in closed_connection_zones) + client << "\ref[zone] [zone] - [closed_connection_zones[zone]] (Unconnected)" - else - dbg_output = 0 + for(var/C in connections) + if(!istype(C,/connection)) + client << "[C] (Not Connection!)" - client.images -= client.zone_debug_images - client.zone_debug_images = null + if(!client.zone_debug_images) + client.zone_debug_images = list() + client.zone_debug_images[src] = current_zone_images - for(var/zone/Z in zones) - if(Z.air == air && Z != src) - var/turf/zloc = pick(Z.contents) - client << "\red Illegal air datum shared by: [zloc.loc.name]" + client.images += client.zone_debug_images[src] + + else + dbg_output = 0 + + client.images -= client.zone_debug_images[src] + client.zone_debug_images.Remove(src) + + for(var/zone/Z in zones) + if(Z.air == air && Z != src) + var/turf/zloc = pick(Z.contents) + client << "\red Illegal air datum shared by: [zloc.loc.name]" diff --git a/code/ZAS/FEA_gas_mixture.dm b/code/ZAS/FEA_gas_mixture.dm index a4104ab01c7..8b7ab992c93 100644 --- a/code/ZAS/FEA_gas_mixture.dm +++ b/code/ZAS/FEA_gas_mixture.dm @@ -14,141 +14,135 @@ What are the archived variables for? #define QUANTIZE(variable) (round(variable,0.0001)) #define TRANSFER_FRACTION 5 //What fraction (1/#) of the air difference to try and transfer -datum - gas //These are used for the "Trace Gases" stuff, but is buggy. - sleeping_agent - specific_heat = 40 +/datum/gas/sleeping_agent/specific_heat = 40 //These are used for the "Trace Gases" stuff, but is buggy. - oxygen_agent_b - specific_heat = 300 +/datum/gas/oxygen_agent_b/specific_heat = 300 - volatile_fuel - specific_heat = 30 +/datum/gas/volatile_fuel/specific_heat = 30 - var - moles = 0 - specific_heat = 0 +/datum/gas + var/moles = 0 - moles_archived = 0 + var/specific_heat = 0 - gas_mixture - var //Holds the "moles" of each of the four gases. - oxygen = 0 - carbon_dioxide = 0 - nitrogen = 0 - toxins = 0 - total_moles = 0 //Updated when a reaction occurs. + var/moles_archived = 0 - volume = CELL_VOLUME +/datum/gas_mixture/ + var/oxygen = 0 //Holds the "moles" of each of the four gases. + var/carbon_dioxide = 0 + var/nitrogen = 0 + var/toxins = 0 - temperature = 0 //in Kelvin, use calculate_temperature() to modify + var/total_moles = 0 //Updated when a reaction occurs. - group_multiplier = 1 + var/volume = CELL_VOLUME + + var/temperature = 0 //in Kelvin, use calculate_temperature() to modify + + var/group_multiplier = 1 //Size of the group this gas_mixture is representing. //=1 for singletons - graphic + var/graphic - list/datum/gas/trace_gases = list() //Seemed to be a good idea that was abandoned + var/list/datum/gas/trace_gases = list() //Seemed to be a good idea that was abandoned - tmp //These are variables for use with the archived data - oxygen_archived - carbon_dioxide_archived - nitrogen_archived - toxins_archived + var/tmp/oxygen_archived //These are variables for use with the archived data + var/tmp/carbon_dioxide_archived + var/tmp/nitrogen_archived + var/tmp/toxins_archived - temperature_archived + var/tmp/temperature_archived - graphic_archived = 0 - fuel_burnt = 0 + var/tmp/graphic_archived = 0 + var/tmp/fuel_burnt = 0 //FOR THE LOVE OF GOD PLEASE USE THIS PROC //Call it with negative numbers to remove gases. - proc/adjust(o2 = 0, co2 = 0, n2 = 0, tx = 0, list/datum/gas/traces = list()) - //Purpose: Adjusting the gases within a airmix - //Called by: Nothing, yet! - //Inputs: The values of the gases to adjust - //Outputs: null +/datum/gas_mixture/proc/adjust(o2 = 0, co2 = 0, n2 = 0, tx = 0, list/datum/gas/traces = list()) + //Purpose: Adjusting the gases within a airmix + //Called by: Nothing, yet! + //Inputs: The values of the gases to adjust + //Outputs: null - oxygen = max(0, oxygen + o2) - carbon_dioxide = max(0, carbon_dioxide + co2) - nitrogen = max(0, nitrogen + n2) - toxins = max(0, toxins + tx) + oxygen = max(0, oxygen + o2) + carbon_dioxide = max(0, carbon_dioxide + co2) + nitrogen = max(0, nitrogen + n2) + toxins = max(0, toxins + tx) - //handle trace gasses - for(var/datum/gas/G in traces) - var/datum/gas/T = locate(G.type) in trace_gases - if(T) - T.moles = max(G.moles + T.moles, 0) - else if(G.moles > 0) - trace_gases |= G - update_values() - return + //handle trace gasses + for(var/datum/gas/G in traces) + var/datum/gas/T = locate(G.type) in trace_gases + if(T) + T.moles = max(G.moles + T.moles, 0) + else if(G.moles > 0) + trace_gases |= G + update_values() + return //tg seems to like using these a lot - proc/return_temperature() - return temperature +/datum/gas_mixture/proc/return_temperature() + return temperature - proc/return_volume() - return max(0, volume) +/datum/gas_mixture/proc/return_volume() + return max(0, volume) - proc/thermal_energy() - return temperature*heat_capacity() +/datum/gas_mixture/proc/thermal_energy() + return temperature*heat_capacity() /////////////////////////////// //PV=nRT - related procedures// /////////////////////////////// +/datum/gas_mixture/proc/heat_capacity() + //Purpose: Returning the heat capacity of the gas mix + //Called by: UNKNOWN + //Inputs: None + //Outputs: Heat capacity - proc/heat_capacity() - //Purpose: Returning the heat capacity of the gas mix - //Called by: UNKNOWN - //Inputs: None - //Outputs: Heat capacity + var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) - var/heat_capacity = HEAT_CAPACITY_CALCULATION(oxygen,carbon_dioxide,nitrogen,toxins) + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + heat_capacity += trace_gas.moles*trace_gas.specific_heat - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - heat_capacity += trace_gas.moles*trace_gas.specific_heat + return max(MINIMUM_HEAT_CAPACITY,heat_capacity) - return max(MINIMUM_HEAT_CAPACITY,heat_capacity) +/datum/gas_mixture/proc/heat_capacity_archived() + //Purpose: Returning the archived heat capacity of the gas mix + //Called by: UNKNOWN + //Inputs: None + //Outputs: Archived heat capacity - proc/heat_capacity_archived() - //Purpose: Returning the archived heat capacity of the gas mix - //Called by: UNKNOWN - //Inputs: None - //Outputs: Archived heat capacity + var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived) - var/heat_capacity_archived = HEAT_CAPACITY_CALCULATION(oxygen_archived,carbon_dioxide_archived,nitrogen_archived,toxins_archived) + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - heat_capacity_archived += trace_gas.moles_archived*trace_gas.specific_heat + return max(MINIMUM_HEAT_CAPACITY,heat_capacity_archived) - return max(MINIMUM_HEAT_CAPACITY,heat_capacity_archived) +/datum/gas_mixture/proc/total_moles() + return total_moles + /*var/moles = oxygen + carbon_dioxide + nitrogen + toxins - proc/total_moles() - return total_moles - /*var/moles = oxygen + carbon_dioxide + nitrogen + toxins + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + moles += trace_gas.moles + return moles*/ - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - moles += trace_gas.moles - return moles*/ +/datum/gas_mixture/proc/return_pressure() + //Purpose: Calculating Current Pressure + //Called by: + //Inputs: None + //Outputs: Gas pressure. - proc/return_pressure() - //Purpose: Calculating Current Pressure - //Called by: - //Inputs: None - //Outputs: Gas pressure. - - if(volume>0) - return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume - return 0 + if(volume>0) + return total_moles()*R_IDEAL_GAS_EQUATION*temperature/volume + return 0 // proc/return_temperature() //Purpose: @@ -171,868 +165,865 @@ datum // return temperature*heat_capacity() - proc/update_values() - //Purpose: Calculating and storing values which were normally called CONSTANTLY - //Called by: Anything that changes values within a gas mix. - //Inputs: None - //Outputs: None +/datum/gas_mixture/proc/update_values() + //Purpose: Calculating and storing values which were normally called CONSTANTLY + //Called by: Anything that changes values within a gas mix. + //Inputs: None + //Outputs: None - total_moles = oxygen + carbon_dioxide + nitrogen + toxins + total_moles = oxygen + carbon_dioxide + nitrogen + toxins - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - total_moles += trace_gas.moles + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + total_moles += trace_gas.moles - return + return //////////////////////////////////////////// //Procedures used for very specific events// //////////////////////////////////////////// +/datum/gas_mixture/proc/check_tile_graphic() + //Purpose: Calculating the graphic for a tile + //Called by: Turfs updating + //Inputs: None + //Outputs: 1 if graphic changed, 0 if unchanged - proc/check_tile_graphic() - //Purpose: Calculating the graphic for a tile - //Called by: Turfs updating - //Inputs: None - //Outputs: 1 if graphic changed, 0 if unchanged - + graphic = 0 + if(toxins > MOLES_PLASMA_VISIBLE) + graphic = 1 + else if(length(trace_gases)) + var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases + if(sleeping_agent && (sleeping_agent.moles > 1)) + graphic = 2 + else graphic = 0 - if(toxins > MOLES_PLASMA_VISIBLE) - graphic = 1 - else if(length(trace_gases)) - var/datum/gas/sleeping_agent = locate(/datum/gas/sleeping_agent) in trace_gases - if(sleeping_agent && (sleeping_agent.moles > 1)) - graphic = 2 - else - graphic = 0 - return graphic != graphic_archived + return graphic != graphic_archived - proc/react(atom/dump_location) - //Purpose: Calculating if it is possible for a fire to occur in the airmix - //Called by: Air mixes updating? - //Inputs: None - //Outputs: If a fire occured +/datum/gas_mixture/proc/react(atom/dump_location) + //Purpose: Calculating if it is possible for a fire to occur in the airmix + //Called by: Air mixes updating? + //Inputs: None + //Outputs: If a fire occured - var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network) + var/reacting = 0 //set to 1 if a notable reaction occured (used by pipe_network) - if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) - if(zburn(null) > 0) - reacting = 1 + if(temperature > FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + if(zburn(null) > 0) + reacting = 1 - return reacting + return reacting - proc/fire() - //Purpose: Calculating any fire reactions. - //Called by: react() (See above) - //Inputs: None - //Outputs: How much fuel burned +/datum/gas_mixture/proc/fire() + //Purpose: Calculating any fire reactions. + //Called by: react() (See above) + //Inputs: None + //Outputs: How much fuel burned - return zburn(null) + return zburn(null) - /*var/energy_released = 0 - var/old_heat_capacity = heat_capacity() + /*var/energy_released = 0 + var/old_heat_capacity = heat_capacity() - var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel) in trace_gases - if(fuel_store) //General volatile gas burn - var/burned_fuel = 0 + var/datum/gas/volatile_fuel/fuel_store = locate(/datum/gas/volatile_fuel) in trace_gases + if(fuel_store) //General volatile gas burn + var/burned_fuel = 0 - if(oxygen < fuel_store.moles) - burned_fuel = oxygen - fuel_store.moles -= burned_fuel - oxygen = 0 - else - burned_fuel = fuel_store.moles - oxygen -= fuel_store.moles - del(fuel_store) + if(oxygen < fuel_store.moles) + burned_fuel = oxygen + fuel_store.moles -= burned_fuel + oxygen = 0 + else + burned_fuel = fuel_store.moles + oxygen -= fuel_store.moles + del(fuel_store) - energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel - carbon_dioxide += burned_fuel - fuel_burnt += burned_fuel + energy_released += FIRE_CARBON_ENERGY_RELEASED * burned_fuel + carbon_dioxide += burned_fuel + fuel_burnt += burned_fuel - //Handle plasma burning - if(toxins > MINIMUM_HEAT_CAPACITY) - var/plasma_burn_rate = 0 - var/oxygen_burn_rate = 0 - //more plasma released at higher temperatures - var/temperature_scale - if(temperature > PLASMA_UPPER_TEMPERATURE) - temperature_scale = 1 - else - temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE) - if(temperature_scale > 0) - oxygen_burn_rate = 1.4 - temperature_scale - if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN) - plasma_burn_rate = (toxins*temperature_scale)/4 - else - plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4 - if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY) - toxins -= plasma_burn_rate - oxygen -= plasma_burn_rate*oxygen_burn_rate - carbon_dioxide += plasma_burn_rate + //Handle plasma burning + if(toxins > MINIMUM_HEAT_CAPACITY) + var/plasma_burn_rate = 0 + var/oxygen_burn_rate = 0 + //more plasma released at higher temperatures + var/temperature_scale + if(temperature > PLASMA_UPPER_TEMPERATURE) + temperature_scale = 1 + else + temperature_scale = (temperature-PLASMA_MINIMUM_BURN_TEMPERATURE)/(PLASMA_UPPER_TEMPERATURE-PLASMA_MINIMUM_BURN_TEMPERATURE) + if(temperature_scale > 0) + oxygen_burn_rate = 1.4 - temperature_scale + if(oxygen > toxins*PLASMA_OXYGEN_FULLBURN) + plasma_burn_rate = (toxins*temperature_scale)/4 + else + plasma_burn_rate = (temperature_scale*(oxygen/PLASMA_OXYGEN_FULLBURN))/4 + if(plasma_burn_rate > MINIMUM_HEAT_CAPACITY) + toxins -= plasma_burn_rate + oxygen -= plasma_burn_rate*oxygen_burn_rate + carbon_dioxide += plasma_burn_rate - energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate) + energy_released += FIRE_PLASMA_ENERGY_RELEASED * (plasma_burn_rate) - fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate) + fuel_burnt += (plasma_burn_rate)*(1+oxygen_burn_rate) - if(energy_released > 0) - var/new_heat_capacity = heat_capacity() - if(new_heat_capacity > MINIMUM_HEAT_CAPACITY) - temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity - update_values() + if(energy_released > 0) + var/new_heat_capacity = heat_capacity() + if(new_heat_capacity > MINIMUM_HEAT_CAPACITY) + temperature = (temperature*old_heat_capacity + energy_released)/new_heat_capacity + update_values() - return fuel_burnt*/ + return fuel_burnt*/ ////////////////////////////////////////////// //Procs for general gas spread calculations.// ////////////////////////////////////////////// - proc/archive() - //Purpose: Archives the current gas values - //Called by: UNKNOWN - //Inputs: None - //Outputs: 1 +/datum/gas_mixture/proc/archive() + //Purpose: Archives the current gas values + //Called by: UNKNOWN + //Inputs: None + //Outputs: 1 - oxygen_archived = oxygen - carbon_dioxide_archived = carbon_dioxide - nitrogen_archived = nitrogen - toxins_archived = toxins + oxygen_archived = oxygen + carbon_dioxide_archived = carbon_dioxide + nitrogen_archived = nitrogen + toxins_archived = toxins - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - trace_gas.moles_archived = trace_gas.moles + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + trace_gas.moles_archived = trace_gas.moles - temperature_archived = temperature + temperature_archived = temperature - graphic_archived = graphic + graphic_archived = graphic - return 1 + return 1 - proc/check_then_merge(datum/gas_mixture/giver) - //Purpose: Similar to merge(...) but first checks to see if the amount of air assumed is small enough - // that group processing is still accurate for source (aborts if not) - //Called by: airgroups/machinery expelling air, ? - //Inputs: The gas to try and merge - //Outputs: 1 on successful merge. 0 otherwise. +/datum/gas_mixture/proc/check_then_merge(datum/gas_mixture/giver) + //Purpose: Similar to merge(...) but first checks to see if the amount of air assumed is small enough + // that group processing is still accurate for source (aborts if not) + //Called by: airgroups/machinery expelling air, ? + //Inputs: The gas to try and merge + //Outputs: 1 on successful merge. 0 otherwise. - if(!giver) - return 0 - if(((giver.oxygen > MINIMUM_AIR_TO_SUSPEND) && (giver.oxygen >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((giver.carbon_dioxide > MINIMUM_AIR_TO_SUSPEND) && (giver.carbon_dioxide >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((giver.nitrogen > MINIMUM_AIR_TO_SUSPEND) && (giver.nitrogen >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((giver.toxins > MINIMUM_AIR_TO_SUSPEND) && (giver.toxins >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND))) - return 0 - if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + if(!giver) + return 0 + if(((giver.oxygen > MINIMUM_AIR_TO_SUSPEND) && (giver.oxygen >= oxygen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((giver.carbon_dioxide > MINIMUM_AIR_TO_SUSPEND) && (giver.carbon_dioxide >= carbon_dioxide*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((giver.nitrogen > MINIMUM_AIR_TO_SUSPEND) && (giver.nitrogen >= nitrogen*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((giver.toxins > MINIMUM_AIR_TO_SUSPEND) && (giver.toxins >= toxins*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return 0 + if(abs(giver.temperature - temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(giver.trace_gases.len) + for(var/datum/gas/trace_gas in giver.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if((trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) && (!corresponding || (trace_gas.moles >= corresponding.moles*MINIMUM_AIR_RATIO_TO_SUSPEND))) return 0 - if(giver.trace_gases.len) - for(var/datum/gas/trace_gas in giver.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if((trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) && (!corresponding || (trace_gas.moles >= corresponding.moles*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return merge(giver) + +/datum/gas_mixture/proc/merge(datum/gas_mixture/giver) + //Purpose: Merges all air from giver into self. Deletes giver. + //Called by: Machinery expelling air, check_then_merge, ? + //Inputs: The gas to merge. + //Outputs: 1 + + if(!giver) + return 0 + + if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()*group_multiplier + var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier + var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity + if(combined_heat_capacity != 0) + temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity + + if((group_multiplier>1)||(giver.group_multiplier>1)) + oxygen += giver.oxygen*giver.group_multiplier/group_multiplier + carbon_dioxide += giver.carbon_dioxide*giver.group_multiplier/group_multiplier + nitrogen += giver.nitrogen*giver.group_multiplier/group_multiplier + toxins += giver.toxins*giver.group_multiplier/group_multiplier + else + oxygen += giver.oxygen + carbon_dioxide += giver.carbon_dioxide + nitrogen += giver.nitrogen + toxins += giver.toxins + + if(giver.trace_gases.len) + for(var/datum/gas/trace_gas in giver.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + trace_gases += corresponding + corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier + update_values() + + // Let the garbage collector handle it, faster according to /tg/ testers + //del(giver) + return 1 + +/datum/gas_mixture/proc/remove(amount) + //Purpose: Removes a certain number of moles from the air. + //Called by: ? + //Inputs: How many moles to remove. + //Outputs: Removed air. + + var/sum = total_moles() + amount = min(amount,sum) //Can not take more air than tile has! + if(amount <= 0) + return null + + var/datum/gas_mixture/removed = new + + + removed.oxygen = QUANTIZE((oxygen/sum)*amount) + removed.nitrogen = QUANTIZE((nitrogen/sum)*amount) + removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount) + removed.toxins = QUANTIZE((toxins/sum)*amount) + + oxygen -= removed.oxygen/group_multiplier + nitrogen -= removed.nitrogen/group_multiplier + carbon_dioxide -= removed.carbon_dioxide/group_multiplier + toxins -= removed.toxins/group_multiplier + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + removed.trace_gases += corresponding + + corresponding.moles = (trace_gas.moles/sum)*amount + trace_gas.moles -= corresponding.moles/group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +/datum/gas_mixture/proc/remove_ratio(ratio) + //Purpose: Removes a certain ratio of the air. + //Called by: ? + //Inputs: Percentage to remove. + //Outputs: Removed air. + + if(ratio <= 0) + return null + + ratio = min(ratio, 1) + + var/datum/gas_mixture/removed = new + + removed.oxygen = QUANTIZE(oxygen*ratio) + removed.nitrogen = QUANTIZE(nitrogen*ratio) + removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio) + removed.toxins = QUANTIZE(toxins*ratio) + + oxygen -= removed.oxygen/group_multiplier + nitrogen -= removed.nitrogen/group_multiplier + carbon_dioxide -= removed.carbon_dioxide/group_multiplier + toxins -= removed.toxins/group_multiplier + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + removed.trace_gases += corresponding + + corresponding.moles = trace_gas.moles*ratio + trace_gas.moles -= corresponding.moles/group_multiplier + + removed.temperature = temperature + update_values() + removed.update_values() + + return removed + +/datum/gas_mixture/proc/check_then_remove(amount) + //Purpose: Similar to remove(...) but first checks to see if the amount of air removed is small enough + // that group processing is still accurate for source (aborts if not) + //Called by: ? + //Inputs: Number of moles to remove + //Outputs: Removed air or 0 if it can remove air or not. + + amount = min(amount,total_moles()) //Can not take more air than tile has! + + if((amount > MINIMUM_AIR_RATIO_TO_SUSPEND) && (amount > total_moles()*MINIMUM_AIR_RATIO_TO_SUSPEND)) + return 0 + + return remove(amount) + +/datum/gas_mixture/proc/copy_from(datum/gas_mixture/sample) + //Purpose: Duplicates the sample air mixture. + //Called by: airgroups splitting, ? + //Inputs: Gas to copy + //Outputs: 1 + + oxygen = sample.oxygen + carbon_dioxide = sample.carbon_dioxide + nitrogen = sample.nitrogen + toxins = sample.toxins + total_moles = sample.total_moles() + + trace_gases.len=null + if(sample.trace_gases.len > 0) + for(var/datum/gas/trace_gas in sample.trace_gases) + var/datum/gas/corresponding = new trace_gas.type() + trace_gases += corresponding + + corresponding.moles = trace_gas.moles + + temperature = sample.temperature + + return 1 + +/datum/gas_mixture/proc/check_gas_mixture(datum/gas_mixture/sharer) + //Purpose: Telling if one or both airgroups needs to disable group processing. + //Called by: Airgroups sharing air, checking if group processing needs disabled. + //Inputs: Gas to compare from other airgroup + //Outputs: 0 if the self-check failed (local airgroup breaks?) + // then -1 if sharer-check failed (sharing airgroup breaks?) + // then 1 if both checks pass (share succesful?) + if(!istype(sharer)) + return + + var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION + var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION + var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION + var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION + + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(sharer.trace_gases.len) + for(var/datum/gas/trace_gas in sharer.trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) return 0 - - return merge(giver) - - proc/merge(datum/gas_mixture/giver) - //Purpose: Merges all air from giver into self. Deletes giver. - //Called by: Machinery expelling air, check_then_merge, ? - //Inputs: The gas to merge. - //Outputs: 1 - - if(!giver) - return 0 - - if(abs(temperature-giver.temperature)>MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity()*group_multiplier - var/giver_heat_capacity = giver.heat_capacity()*giver.group_multiplier - var/combined_heat_capacity = giver_heat_capacity + self_heat_capacity - if(combined_heat_capacity != 0) - temperature = (giver.temperature*giver_heat_capacity + temperature*self_heat_capacity)/combined_heat_capacity - - if((group_multiplier>1)||(giver.group_multiplier>1)) - oxygen += giver.oxygen*giver.group_multiplier/group_multiplier - carbon_dioxide += giver.carbon_dioxide*giver.group_multiplier/group_multiplier - nitrogen += giver.nitrogen*giver.group_multiplier/group_multiplier - toxins += giver.toxins*giver.group_multiplier/group_multiplier - else - oxygen += giver.oxygen - carbon_dioxide += giver.carbon_dioxide - nitrogen += giver.nitrogen - toxins += giver.toxins - - if(giver.trace_gases.len) - for(var/datum/gas/trace_gas in giver.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - trace_gases += corresponding - corresponding.moles += trace_gas.moles*giver.group_multiplier/group_multiplier - update_values() - - // Let the garbage collector handle it, faster according to /tg/ testers - //del(giver) - return 1 - - proc/remove(amount) - //Purpose: Removes a certain number of moles from the air. - //Called by: ? - //Inputs: How many moles to remove. - //Outputs: Removed air. - - var/sum = total_moles() - amount = min(amount,sum) //Can not take more air than tile has! - if(amount <= 0) - return null - - var/datum/gas_mixture/removed = new - - - removed.oxygen = QUANTIZE((oxygen/sum)*amount) - removed.nitrogen = QUANTIZE((nitrogen/sum)*amount) - removed.carbon_dioxide = QUANTIZE((carbon_dioxide/sum)*amount) - removed.toxins = QUANTIZE((toxins/sum)*amount) - - oxygen -= removed.oxygen/group_multiplier - nitrogen -= removed.nitrogen/group_multiplier - carbon_dioxide -= removed.carbon_dioxide/group_multiplier - toxins -= removed.toxins/group_multiplier - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - var/datum/gas/corresponding = new trace_gas.type() - removed.trace_gases += corresponding - - corresponding.moles = (trace_gas.moles/sum)*amount - trace_gas.moles -= corresponding.moles/group_multiplier - - removed.temperature = temperature - update_values() - removed.update_values() - - return removed - - proc/remove_ratio(ratio) - //Purpose: Removes a certain ratio of the air. - //Called by: ? - //Inputs: Percentage to remove. - //Outputs: Removed air. - - if(ratio <= 0) - return null - - ratio = min(ratio, 1) - - var/datum/gas_mixture/removed = new - - removed.oxygen = QUANTIZE(oxygen*ratio) - removed.nitrogen = QUANTIZE(nitrogen*ratio) - removed.carbon_dioxide = QUANTIZE(carbon_dioxide*ratio) - removed.toxins = QUANTIZE(toxins*ratio) - - oxygen -= removed.oxygen/group_multiplier - nitrogen -= removed.nitrogen/group_multiplier - carbon_dioxide -= removed.carbon_dioxide/group_multiplier - toxins -= removed.toxins/group_multiplier - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - var/datum/gas/corresponding = new trace_gas.type() - removed.trace_gases += corresponding - - corresponding.moles = trace_gas.moles*ratio - trace_gas.moles -= corresponding.moles/group_multiplier - - removed.temperature = temperature - update_values() - removed.update_values() - - return removed - - proc/check_then_remove(amount) - //Purpose: Similar to remove(...) but first checks to see if the amount of air removed is small enough - // that group processing is still accurate for source (aborts if not) - //Called by: ? - //Inputs: Number of moles to remove - //Outputs: Removed air or 0 if it can remove air or not. - - amount = min(amount,total_moles()) //Can not take more air than tile has! - - if((amount > MINIMUM_AIR_RATIO_TO_SUSPEND) && (amount > total_moles()*MINIMUM_AIR_RATIO_TO_SUSPEND)) - return 0 - - return remove(amount) - - proc/copy_from(datum/gas_mixture/sample) - //Purpose: Duplicates the sample air mixture. - //Called by: airgroups splitting, ? - //Inputs: Gas to copy - //Outputs: 1 - - oxygen = sample.oxygen - carbon_dioxide = sample.carbon_dioxide - nitrogen = sample.nitrogen - toxins = sample.toxins - total_moles = sample.total_moles() - - trace_gases.len=null - if(sample.trace_gases.len > 0) - for(var/datum/gas/trace_gas in sample.trace_gases) - var/datum/gas/corresponding = new trace_gas.type() - trace_gases += corresponding - - corresponding.moles = trace_gas.moles - - temperature = sample.temperature - - return 1 - - proc/check_gas_mixture(datum/gas_mixture/sharer) - //Purpose: Telling if one or both airgroups needs to disable group processing. - //Called by: Airgroups sharing air, checking if group processing needs disabled. - //Inputs: Gas to compare from other airgroup - //Outputs: 0 if the self-check failed (local airgroup breaks?) - // then -1 if sharer-check failed (sharing airgroup breaks?) - // then 1 if both checks pass (share succesful?) - if(!istype(sharer)) - return - - var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION - var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION - var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION - - var/delta_temperature = (temperature_archived - sharer.temperature_archived) - - if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) - return 0 - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) - return 0 - - if(sharer.trace_gases.len) - for(var/datum/gas/trace_gas in sharer.trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(corresponding) - if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) - return 0 - else - return 0 - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) - if(!locate(trace_gas.type) in sharer.trace_gases) - return 0 - - if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= sharer.oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= sharer.carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= sharer.nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= sharer.toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) - return -1 - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) - var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases - if(corresponding) - if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) - return -1 - else - return -1 - - return 1 - - proc/check_turf(turf/model) - //Purpose: Used to compare the gases in an unsimulated turf with the gas in a simulated one. - //Called by: Sharing air (mimicing) with adjacent unsimulated turfs - //Inputs: Unsimulated turf - //Outputs: 1 if safe to mimic, 0 if needs to break airgroup. - - var/delta_oxygen = (oxygen_archived - model.oxygen)/TRANSFER_FRACTION - var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION - var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION - var/delta_toxins = (toxins_archived - model.toxins)/TRANSFER_FRACTION - - var/delta_temperature = (temperature_archived - model.temperature) - - if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ - || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) - return 0 - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) - return 0 - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) - return 0 - - return 1 - - proc/share(datum/gas_mixture/sharer) - //Purpose: Used to transfer gas from a more pressurised tile to a less presurised tile - // (Two directional, if the other tile is more pressurised, air travels to current tile) - //Called by: Sharing air with adjacent simulated turfs - //Inputs: Air datum to share with - //Outputs: Amount of gas exchanged (Negative if lost air, positive if gained.) - - - if(!istype(sharer)) - return - - var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION - var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION - var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION - - var/delta_temperature = (temperature_archived - sharer.temperature_archived) - - var/old_self_heat_capacity = 0 - var/old_sharer_heat_capacity = 0 - - var/heat_self_to_sharer = 0 - var/heat_capacity_self_to_sharer = 0 - var/heat_sharer_to_self = 0 - var/heat_capacity_sharer_to_self = 0 - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - - var/delta_air = delta_oxygen+delta_nitrogen - if(delta_air) - var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air - if(delta_air > 0) - heat_self_to_sharer += air_heat_capacity*temperature_archived - heat_capacity_self_to_sharer += air_heat_capacity - else - heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self -= air_heat_capacity - - if(delta_carbon_dioxide) - var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide - if(delta_carbon_dioxide > 0) - heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived - heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity - else - heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity - - if(delta_toxins) - var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins - if(delta_toxins > 0) - heat_self_to_sharer += toxins_heat_capacity*temperature_archived - heat_capacity_self_to_sharer += toxins_heat_capacity - else - heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self -= toxins_heat_capacity - - old_self_heat_capacity = heat_capacity()*group_multiplier - old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier - - oxygen -= delta_oxygen/group_multiplier - sharer.oxygen += delta_oxygen/sharer.group_multiplier - - carbon_dioxide -= delta_carbon_dioxide/group_multiplier - sharer.carbon_dioxide += delta_carbon_dioxide/sharer.group_multiplier - - nitrogen -= delta_nitrogen/group_multiplier - sharer.nitrogen += delta_nitrogen/sharer.group_multiplier - - toxins -= delta_toxins/group_multiplier - sharer.toxins += delta_toxins/sharer.group_multiplier - - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) - - var/list/trace_types_considered = list() - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - - var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases - var/delta = 0 - - if(corresponding) - delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/TRANSFER_FRACTION - else - corresponding = new trace_gas.type() - sharer.trace_gases += corresponding - - delta = trace_gas.moles_archived/TRANSFER_FRACTION - - trace_gas.moles -= delta/group_multiplier - corresponding.moles += delta/sharer.group_multiplier - - if(delta) - var/individual_heat_capacity = trace_gas.specific_heat*delta - if(delta > 0) - heat_self_to_sharer += individual_heat_capacity*temperature_archived - heat_capacity_self_to_sharer += individual_heat_capacity - else - heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self -= individual_heat_capacity - - moved_moles += delta - - trace_types_considered += trace_gas.type - - - if(sharer.trace_gases.len) - for(var/datum/gas/trace_gas in sharer.trace_gases) - if(trace_gas.type in trace_types_considered) continue - else - var/datum/gas/corresponding - var/delta = 0 - - corresponding = new trace_gas.type() - trace_gases += corresponding - - delta = trace_gas.moles_archived/TRANSFER_FRACTION - - trace_gas.moles -= delta/sharer.group_multiplier - corresponding.moles += delta/group_multiplier - - //Guaranteed transfer from sharer to self - var/individual_heat_capacity = trace_gas.specific_heat*delta - heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived - heat_capacity_sharer_to_self += individual_heat_capacity - - moved_moles += -delta - update_values() - sharer.update_values() - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer - var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self - - if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) - temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity - - if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) - sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity - - if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY) - if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity - temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT) - - if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) - var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles) - return delta_pressure*R_IDEAL_GAS_EQUATION/volume - - else - return 0 - - proc/mimic(turf/model, border_multiplier) - //Purpose: Used transfer gas from a more pressurised tile to a less presurised unsimulated tile. - //Called by: "sharing" from unsimulated to simulated turfs. - //Inputs: Unsimulated turf, Multiplier for gas transfer (optional) - //Outputs: Amount of gas exchanged - - var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/TRANSFER_FRACTION - var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION - var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION - var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/TRANSFER_FRACTION - - var/delta_temperature = (temperature_archived - model.temperature) - - var/heat_transferred = 0 - var/old_self_heat_capacity = 0 - var/heat_capacity_transferred = 0 - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - - var/delta_air = delta_oxygen+delta_nitrogen - if(delta_air) - var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air - heat_transferred -= air_heat_capacity*model.temperature - heat_capacity_transferred -= air_heat_capacity - - if(delta_carbon_dioxide) - var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide - heat_transferred -= carbon_dioxide_heat_capacity*model.temperature - heat_capacity_transferred -= carbon_dioxide_heat_capacity - - if(delta_toxins) - var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins - heat_transferred -= toxins_heat_capacity*model.temperature - heat_capacity_transferred -= toxins_heat_capacity - - old_self_heat_capacity = heat_capacity()*group_multiplier - - if(border_multiplier) - oxygen -= delta_oxygen*border_multiplier/group_multiplier - carbon_dioxide -= delta_carbon_dioxide*border_multiplier/group_multiplier - nitrogen -= delta_nitrogen*border_multiplier/group_multiplier - toxins -= delta_toxins*border_multiplier/group_multiplier - else - oxygen -= delta_oxygen/group_multiplier - carbon_dioxide -= delta_carbon_dioxide/group_multiplier - nitrogen -= delta_nitrogen/group_multiplier - toxins -= delta_toxins/group_multiplier - - var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) - - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - var/delta = 0 - - delta = trace_gas.moles_archived/TRANSFER_FRACTION - - if(border_multiplier) - trace_gas.moles -= delta*border_multiplier/group_multiplier - else - trace_gas.moles -= delta/group_multiplier - - var/heat_cap_transferred = delta*trace_gas.specific_heat - heat_transferred += heat_cap_transferred*temperature_archived - heat_capacity_transferred += heat_cap_transferred - moved_moles += delta - update_values() - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred - if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) - if(border_multiplier) - temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity - else - temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity - - temperature_mimic(model, model.thermal_conductivity, border_multiplier) - - if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) - var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins) - return delta_pressure*R_IDEAL_GAS_EQUATION/volume - else - return 0 - - proc/check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) - var/delta_temperature = (temperature_archived - sharer.temperature_archived) - - var/self_heat_capacity = heat_capacity_archived() - var/sharer_heat_capacity = sharer.heat_capacity_archived() - - var/self_temperature_delta = 0 - var/sharer_temperature_delta = 0 - - if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) - - self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) - sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) - else - return 1 - - if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ - && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) - return 0 - - if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ - && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*sharer.temperature_archived)) - return -1 - - temperature += self_temperature_delta - sharer.temperature += sharer_temperature_delta - - return 1 - //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency - - proc/check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) - var/delta_temperature = (temperature_archived - sharer.temperature_archived) - - var/self_heat_capacity = heat_capacity_archived() - var/sharer_heat_capacity = sharer.heat_capacity_archived() - - var/self_temperature_delta = 0 - var/sharer_temperature_delta = 0 - - if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) - - self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) - sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) - else - return 1 - - if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ - && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) - return 0 - - temperature += self_temperature_delta - sharer.temperature += sharer_temperature_delta - - return 1 - //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency - - proc/check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient) - var/delta_temperature = (temperature_archived - sharer.temperature) - - var/self_temperature_delta = 0 - var/sharer_temperature_delta = 0 - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity_archived() - - if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) - - self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) - sharer_temperature_delta = heat/sharer.heat_capacity - else - return 1 - - if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ - && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) - return 0 - - temperature += self_temperature_delta - sharer.temperature += sharer_temperature_delta - - return 1 - //Logic integrated from: temperature_turf_share(sharer, conduction_coefficient) for efficiency - - proc/check_me_then_temperature_mimic(turf/model, conduction_coefficient) - var/delta_temperature = (temperature_archived - model.temperature) - var/self_temperature_delta = 0 - - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity_archived() - - if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) - - self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) - - if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ - && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) - return 0 - - temperature += self_temperature_delta - - return 1 - //Logic integrated from: temperature_mimic(model, conduction_coefficient) for efficiency - - proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient) - - var/delta_temperature = (temperature_archived - sharer.temperature_archived) - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity_archived() - var/sharer_heat_capacity = sharer.heat_capacity_archived() - if(!group_multiplier) - message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!") - return - - if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) - - temperature -= heat/(self_heat_capacity*group_multiplier) - sharer.temperature += heat/(sharer_heat_capacity*sharer.group_multiplier) - - proc/temperature_mimic(turf/model, conduction_coefficient, border_multiplier) - var/delta_temperature = (temperature - model.temperature) - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity()//_archived() - if(!group_multiplier) - message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!") - return - - if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) - - if(border_multiplier) - temperature -= heat*border_multiplier/(self_heat_capacity*group_multiplier) - else - temperature -= heat/(self_heat_capacity*group_multiplier) - - proc/temperature_turf_share(turf/simulated/sharer, conduction_coefficient) - var/delta_temperature = (temperature_archived - sharer.temperature) - if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) - var/self_heat_capacity = heat_capacity() - - if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) - var/heat = conduction_coefficient*delta_temperature* \ - (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) - - temperature -= heat/(self_heat_capacity*group_multiplier) - sharer.temperature += heat/sharer.heat_capacity - - proc/compare(datum/gas_mixture/sample) - //Purpose: Compares sample to self to see if within acceptable ranges that group processing may be enabled - //Called by: Airgroups trying to rebuild - //Inputs: Gas mix to compare - //Outputs: 1 if can rebuild, 0 if not. - if(!sample) return 0 - - if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \ - ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen))) - return 0 - if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \ - ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen))) - return 0 - if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ - ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) - return 0 - if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \ - ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins))) - return 0 - - if(total_moles() > MINIMUM_AIR_TO_SUSPEND) - if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ - ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) - //world << "temp fail [temperature] & [sample.temperature]" + else return 0 - if(sample.trace_gases.len) - for(var/datum/gas/trace_gas in sample.trace_gases) - if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(corresponding) - if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ - ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles))) - return 0 - else - return 0 + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + if(!locate(trace_gas.type) in sharer.trace_gases) + return 0 - if(trace_gases.len) - for(var/datum/gas/trace_gas in trace_gases) - if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) - var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases - if(corresponding) - if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ - ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles))) - return 0 - else - return 0 - return 1 + if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= sharer.oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= sharer.carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= sharer.nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= sharer.toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return -1 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases + if(corresponding) + if(trace_gas.moles_archived >= corresponding.moles_archived*MINIMUM_AIR_RATIO_TO_SUSPEND*4) + return -1 + else + return -1 + + return 1 + +/datum/gas_mixture/proc/check_turf(turf/model) + //Purpose: Used to compare the gases in an unsimulated turf with the gas in a simulated one. + //Called by: Sharing air (mimicing) with adjacent unsimulated turfs + //Inputs: Unsimulated turf + //Outputs: 1 if safe to mimic, 0 if needs to break airgroup. + + var/delta_oxygen = (oxygen_archived - model.oxygen)/TRANSFER_FRACTION + var/delta_carbon_dioxide = (carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION + var/delta_nitrogen = (nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION + var/delta_toxins = (toxins_archived - model.toxins)/TRANSFER_FRACTION + + var/delta_temperature = (temperature_archived - model.temperature) + + if(((abs(delta_oxygen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_oxygen) >= oxygen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_carbon_dioxide) >= carbon_dioxide_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_nitrogen) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_nitrogen) >= nitrogen_archived*MINIMUM_AIR_RATIO_TO_SUSPEND)) \ + || ((abs(delta_toxins) > MINIMUM_AIR_TO_SUSPEND) && (abs(delta_toxins) >= toxins_archived*MINIMUM_AIR_RATIO_TO_SUSPEND))) + return 0 + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) + return 0 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND*4) + return 0 + + return 1 + +/datum/gas_mixture/proc/share(datum/gas_mixture/sharer) + //Purpose: Used to transfer gas from a more pressurised tile to a less presurised tile + // (Two directional, if the other tile is more pressurised, air travels to current tile) + //Called by: Sharing air with adjacent simulated turfs + //Inputs: Air datum to share with + //Outputs: Amount of gas exchanged (Negative if lost air, positive if gained.) - proc/subtract(datum/gas_mixture/right_side) - //Purpose: Subtracts right_side from air_mixture. Used to help turfs mingle - //Called by: Pipelines ending in a break (or something) - //Inputs: Gas mix to remove - //Outputs: 1 + if(!istype(sharer)) + return - oxygen -= right_side.oxygen - carbon_dioxide -= right_side.carbon_dioxide - nitrogen -= right_side.nitrogen - toxins -= right_side.toxins + var/delta_oxygen = QUANTIZE(oxygen_archived - sharer.oxygen_archived)/TRANSFER_FRACTION + var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - sharer.carbon_dioxide_archived)/TRANSFER_FRACTION + var/delta_nitrogen = QUANTIZE(nitrogen_archived - sharer.nitrogen_archived)/TRANSFER_FRACTION + var/delta_toxins = QUANTIZE(toxins_archived - sharer.toxins_archived)/TRANSFER_FRACTION - if((trace_gases.len > 0)||(right_side.trace_gases.len > 0)) - for(var/datum/gas/trace_gas in right_side.trace_gases) - var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases - if(!corresponding) - corresponding = new trace_gas.type() - trace_gases += corresponding + var/delta_temperature = (temperature_archived - sharer.temperature_archived) - corresponding.moles -= trace_gas.moles - update_values() - return 1 \ No newline at end of file + var/old_self_heat_capacity = 0 + var/old_sharer_heat_capacity = 0 + + var/heat_self_to_sharer = 0 + var/heat_capacity_self_to_sharer = 0 + var/heat_sharer_to_self = 0 + var/heat_capacity_sharer_to_self = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + + var/delta_air = delta_oxygen+delta_nitrogen + if(delta_air) + var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air + if(delta_air > 0) + heat_self_to_sharer += air_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += air_heat_capacity + else + heat_sharer_to_self -= air_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= air_heat_capacity + + if(delta_carbon_dioxide) + var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide + if(delta_carbon_dioxide > 0) + heat_self_to_sharer += carbon_dioxide_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += carbon_dioxide_heat_capacity + else + heat_sharer_to_self -= carbon_dioxide_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= carbon_dioxide_heat_capacity + + if(delta_toxins) + var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins + if(delta_toxins > 0) + heat_self_to_sharer += toxins_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += toxins_heat_capacity + else + heat_sharer_to_self -= toxins_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= toxins_heat_capacity + + old_self_heat_capacity = heat_capacity()*group_multiplier + old_sharer_heat_capacity = sharer.heat_capacity()*sharer.group_multiplier + + oxygen -= delta_oxygen/group_multiplier + sharer.oxygen += delta_oxygen/sharer.group_multiplier + + carbon_dioxide -= delta_carbon_dioxide/group_multiplier + sharer.carbon_dioxide += delta_carbon_dioxide/sharer.group_multiplier + + nitrogen -= delta_nitrogen/group_multiplier + sharer.nitrogen += delta_nitrogen/sharer.group_multiplier + + toxins -= delta_toxins/group_multiplier + sharer.toxins += delta_toxins/sharer.group_multiplier + + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + + var/list/trace_types_considered = list() + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + + var/datum/gas/corresponding = locate(trace_gas.type) in sharer.trace_gases + var/delta = 0 + + if(corresponding) + delta = QUANTIZE(trace_gas.moles_archived - corresponding.moles_archived)/TRANSFER_FRACTION + else + corresponding = new trace_gas.type() + sharer.trace_gases += corresponding + + delta = trace_gas.moles_archived/TRANSFER_FRACTION + + trace_gas.moles -= delta/group_multiplier + corresponding.moles += delta/sharer.group_multiplier + + if(delta) + var/individual_heat_capacity = trace_gas.specific_heat*delta + if(delta > 0) + heat_self_to_sharer += individual_heat_capacity*temperature_archived + heat_capacity_self_to_sharer += individual_heat_capacity + else + heat_sharer_to_self -= individual_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self -= individual_heat_capacity + + moved_moles += delta + + trace_types_considered += trace_gas.type + + + if(sharer.trace_gases.len) + for(var/datum/gas/trace_gas in sharer.trace_gases) + if(trace_gas.type in trace_types_considered) continue + else + var/datum/gas/corresponding + var/delta = 0 + + corresponding = new trace_gas.type() + trace_gases += corresponding + + delta = trace_gas.moles_archived/TRANSFER_FRACTION + + trace_gas.moles -= delta/sharer.group_multiplier + corresponding.moles += delta/group_multiplier + + //Guaranteed transfer from sharer to self + var/individual_heat_capacity = trace_gas.specific_heat*delta + heat_sharer_to_self += individual_heat_capacity*sharer.temperature_archived + heat_capacity_sharer_to_self += individual_heat_capacity + + moved_moles += -delta + update_values() + sharer.update_values() + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/new_self_heat_capacity = old_self_heat_capacity + heat_capacity_sharer_to_self - heat_capacity_self_to_sharer + var/new_sharer_heat_capacity = old_sharer_heat_capacity + heat_capacity_self_to_sharer - heat_capacity_sharer_to_self + + if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) + temperature = (old_self_heat_capacity*temperature - heat_capacity_self_to_sharer*temperature_archived + heat_capacity_sharer_to_self*sharer.temperature_archived)/new_self_heat_capacity + + if(new_sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) + sharer.temperature = (old_sharer_heat_capacity*sharer.temperature-heat_capacity_sharer_to_self*sharer.temperature_archived + heat_capacity_self_to_sharer*temperature_archived)/new_sharer_heat_capacity + + if(abs(old_sharer_heat_capacity) > MINIMUM_HEAT_CAPACITY) + if(abs(new_sharer_heat_capacity/old_sharer_heat_capacity - 1) < 0.10) // <10% change in sharer heat capacity + temperature_share(sharer, OPEN_HEAT_TRANSFER_COEFFICIENT) + + if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) + var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - sharer.temperature_archived*(sharer.total_moles() - moved_moles) + return delta_pressure*R_IDEAL_GAS_EQUATION/volume + + else + return 0 + +/datum/gas_mixture/proc/mimic(turf/model, border_multiplier) + //Purpose: Used transfer gas from a more pressurised tile to a less presurised unsimulated tile. + //Called by: "sharing" from unsimulated to simulated turfs. + //Inputs: Unsimulated turf, Multiplier for gas transfer (optional) + //Outputs: Amount of gas exchanged + + var/delta_oxygen = QUANTIZE(oxygen_archived - model.oxygen)/TRANSFER_FRACTION + var/delta_carbon_dioxide = QUANTIZE(carbon_dioxide_archived - model.carbon_dioxide)/TRANSFER_FRACTION + var/delta_nitrogen = QUANTIZE(nitrogen_archived - model.nitrogen)/TRANSFER_FRACTION + var/delta_toxins = QUANTIZE(toxins_archived - model.toxins)/TRANSFER_FRACTION + + var/delta_temperature = (temperature_archived - model.temperature) + + var/heat_transferred = 0 + var/old_self_heat_capacity = 0 + var/heat_capacity_transferred = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + + var/delta_air = delta_oxygen+delta_nitrogen + if(delta_air) + var/air_heat_capacity = SPECIFIC_HEAT_AIR*delta_air + heat_transferred -= air_heat_capacity*model.temperature + heat_capacity_transferred -= air_heat_capacity + + if(delta_carbon_dioxide) + var/carbon_dioxide_heat_capacity = SPECIFIC_HEAT_CDO*delta_carbon_dioxide + heat_transferred -= carbon_dioxide_heat_capacity*model.temperature + heat_capacity_transferred -= carbon_dioxide_heat_capacity + + if(delta_toxins) + var/toxins_heat_capacity = SPECIFIC_HEAT_TOXIN*delta_toxins + heat_transferred -= toxins_heat_capacity*model.temperature + heat_capacity_transferred -= toxins_heat_capacity + + old_self_heat_capacity = heat_capacity()*group_multiplier + + if(border_multiplier) + oxygen -= delta_oxygen*border_multiplier/group_multiplier + carbon_dioxide -= delta_carbon_dioxide*border_multiplier/group_multiplier + nitrogen -= delta_nitrogen*border_multiplier/group_multiplier + toxins -= delta_toxins*border_multiplier/group_multiplier + else + oxygen -= delta_oxygen/group_multiplier + carbon_dioxide -= delta_carbon_dioxide/group_multiplier + nitrogen -= delta_nitrogen/group_multiplier + toxins -= delta_toxins/group_multiplier + + var/moved_moles = (delta_oxygen + delta_carbon_dioxide + delta_nitrogen + delta_toxins) + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + var/delta = 0 + + delta = trace_gas.moles_archived/TRANSFER_FRACTION + + if(border_multiplier) + trace_gas.moles -= delta*border_multiplier/group_multiplier + else + trace_gas.moles -= delta/group_multiplier + + var/heat_cap_transferred = delta*trace_gas.specific_heat + heat_transferred += heat_cap_transferred*temperature_archived + heat_capacity_transferred += heat_cap_transferred + moved_moles += delta + update_values() + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/new_self_heat_capacity = old_self_heat_capacity - heat_capacity_transferred + if(new_self_heat_capacity > MINIMUM_HEAT_CAPACITY) + if(border_multiplier) + temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity + else + temperature = (old_self_heat_capacity*temperature - heat_capacity_transferred*border_multiplier*temperature_archived)/new_self_heat_capacity + + temperature_mimic(model, model.thermal_conductivity, border_multiplier) + + if((delta_temperature > MINIMUM_TEMPERATURE_TO_MOVE) || abs(moved_moles) > MINIMUM_MOLES_DELTA_TO_MOVE) + var/delta_pressure = temperature_archived*(total_moles() + moved_moles) - model.temperature*(model.oxygen+model.carbon_dioxide+model.nitrogen+model.toxins) + return delta_pressure*R_IDEAL_GAS_EQUATION/volume + else + return 0 + +/datum/gas_mixture/proc/check_both_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + if((abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(sharer_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*sharer.temperature_archived)) + return -1 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency + +/datum/gas_mixture/proc/check_me_then_temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/(sharer_heat_capacity*sharer.group_multiplier) + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_share(sharer, conduction_coefficient) for efficiency + +/datum/gas_mixture/proc/check_me_then_temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature) + + var/self_temperature_delta = 0 + var/sharer_temperature_delta = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + + if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + sharer_temperature_delta = heat/sharer.heat_capacity + else + return 1 + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + sharer.temperature += sharer_temperature_delta + + return 1 + //Logic integrated from: temperature_turf_share(sharer, conduction_coefficient) for efficiency + +/datum/gas_mixture/proc/check_me_then_temperature_mimic(turf/model, conduction_coefficient) + var/delta_temperature = (temperature_archived - model.temperature) + var/self_temperature_delta = 0 + + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + + if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) + + self_temperature_delta = -heat/(self_heat_capacity*group_multiplier) + + if((abs(self_temperature_delta) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) \ + && (abs(self_temperature_delta) > MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND*temperature_archived)) + return 0 + + temperature += self_temperature_delta + + return 1 + //Logic integrated from: temperature_mimic(model, conduction_coefficient) for efficiency + +/datum/gas_mixture/proc/temperature_share(datum/gas_mixture/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature_archived) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity_archived() + var/sharer_heat_capacity = sharer.heat_capacity_archived() + if(!group_multiplier) + message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!") + return + + if((sharer_heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer_heat_capacity/(self_heat_capacity+sharer_heat_capacity)) + + temperature -= heat/(self_heat_capacity*group_multiplier) + sharer.temperature += heat/(sharer_heat_capacity*sharer.group_multiplier) + +/datum/gas_mixture/proc/temperature_mimic(turf/model, conduction_coefficient, border_multiplier) + var/delta_temperature = (temperature - model.temperature) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity()//_archived() + if(!group_multiplier) + message_admins("Error! The gas mixture (ref \ref[src]) has no group multiplier!") + return + + if((model.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*model.heat_capacity/(self_heat_capacity+model.heat_capacity)) + + if(border_multiplier) + temperature -= heat*border_multiplier/(self_heat_capacity*group_multiplier) + else + temperature -= heat/(self_heat_capacity*group_multiplier) + +/datum/gas_mixture/proc/temperature_turf_share(turf/simulated/sharer, conduction_coefficient) + var/delta_temperature = (temperature_archived - sharer.temperature) + if(abs(delta_temperature) > MINIMUM_TEMPERATURE_DELTA_TO_CONSIDER) + var/self_heat_capacity = heat_capacity() + + if((sharer.heat_capacity > MINIMUM_HEAT_CAPACITY) && (self_heat_capacity > MINIMUM_HEAT_CAPACITY)) + var/heat = conduction_coefficient*delta_temperature* \ + (self_heat_capacity*sharer.heat_capacity/(self_heat_capacity+sharer.heat_capacity)) + + temperature -= heat/(self_heat_capacity*group_multiplier) + sharer.temperature += heat/sharer.heat_capacity + +/datum/gas_mixture/proc/compare(datum/gas_mixture/sample) + //Purpose: Compares sample to self to see if within acceptable ranges that group processing may be enabled + //Called by: Airgroups trying to rebuild + //Inputs: Gas mix to compare + //Outputs: 1 if can rebuild, 0 if not. + if(!sample) return 0 + + if((abs(oxygen-sample.oxygen) > MINIMUM_AIR_TO_SUSPEND) && \ + ((oxygen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.oxygen))) + return 0 + if((abs(nitrogen-sample.nitrogen) > MINIMUM_AIR_TO_SUSPEND) && \ + ((nitrogen < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen) || (nitrogen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.nitrogen))) + return 0 + if((abs(carbon_dioxide-sample.carbon_dioxide) > MINIMUM_AIR_TO_SUSPEND) && \ + ((carbon_dioxide < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide) || (oxygen > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.carbon_dioxide))) + return 0 + if((abs(toxins-sample.toxins) > MINIMUM_AIR_TO_SUSPEND) && \ + ((toxins < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins) || (toxins > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*sample.toxins))) + return 0 + + if(total_moles() > MINIMUM_AIR_TO_SUSPEND) + if((abs(temperature-sample.temperature) > MINIMUM_TEMPERATURE_DELTA_TO_SUSPEND) && \ + ((temperature < (1-MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature) || (temperature > (1+MINIMUM_TEMPERATURE_RATIO_TO_SUSPEND)*sample.temperature))) + //world << "temp fail [temperature] & [sample.temperature]" + return 0 + + if(sample.trace_gases.len) + for(var/datum/gas/trace_gas in sample.trace_gases) + if(trace_gas.moles_archived > MINIMUM_AIR_TO_SUSPEND) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(corresponding) + if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((corresponding.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles) || (corresponding.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*trace_gas.moles))) + return 0 + else + return 0 + + if(trace_gases.len) + for(var/datum/gas/trace_gas in trace_gases) + if(trace_gas.moles > MINIMUM_AIR_TO_SUSPEND) + var/datum/gas/corresponding = locate(trace_gas.type) in sample.trace_gases + if(corresponding) + if((abs(trace_gas.moles - corresponding.moles) > MINIMUM_AIR_TO_SUSPEND) && \ + ((trace_gas.moles < (1-MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles) || (trace_gas.moles > (1+MINIMUM_AIR_RATIO_TO_SUSPEND)*corresponding.moles))) + return 0 + else + return 0 + return 1 + +/datum/gas_mixture/proc/subtract(datum/gas_mixture/right_side) + //Purpose: Subtracts right_side from air_mixture. Used to help turfs mingle + //Called by: Pipelines ending in a break (or something) + //Inputs: Gas mix to remove + //Outputs: 1 + + oxygen -= right_side.oxygen + carbon_dioxide -= right_side.carbon_dioxide + nitrogen -= right_side.nitrogen + toxins -= right_side.toxins + + if((trace_gases.len > 0)||(right_side.trace_gases.len > 0)) + for(var/datum/gas/trace_gas in right_side.trace_gases) + var/datum/gas/corresponding = locate(trace_gas.type) in trace_gases + if(!corresponding) + corresponding = new trace_gas.type() + trace_gases += corresponding + + corresponding.moles -= trace_gas.moles + update_values() + return 1 \ No newline at end of file diff --git a/code/ZAS/FEA_system.dm b/code/ZAS/FEA_system.dm index 94b7c5cf6d1..c2a33ad99db 100644 --- a/code/ZAS/FEA_system.dm +++ b/code/ZAS/FEA_system.dm @@ -64,49 +64,46 @@ atom/proc/CanPass(atom/movable/mover, turf/target, height=1.5, air_group = 0) return (!density || !height || air_group) -turf - CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0) - if(!target) return 0 +/turf/CanPass(atom/movable/mover, turf/target, height=1.5,air_group=0) + if(!target) return 0 - if(istype(mover)) // turf/Enter(...) will perform more advanced checks - return !density + if(istype(mover)) // turf/Enter(...) will perform more advanced checks + return !density - else // Now, doing more detailed checks for air movement and air group formation - if(target.blocks_air||blocks_air) + else // Now, doing more detailed checks for air movement and air group formation + if(target.blocks_air||blocks_air) + return 0 + + for(var/obj/obstacle in src) + if(!obstacle.CanPass(mover, target, height, air_group)) return 0 - - for(var/obj/obstacle in src) - if(!obstacle.CanPass(mover, target, height, air_group)) + if(target != src) + for(var/obj/obstacle in target) + if(!obstacle.CanPass(mover, src, height, air_group)) return 0 - if(target != src) - for(var/obj/obstacle in target) - if(!obstacle.CanPass(mover, src, height, air_group)) - return 0 - return 1 + return 1 -var/global/datum/controller/air_system/air_master +var/datum/controller/air_system/air_master -datum - controller - air_system - //Geoemetry lists - var/list/turfs_with_connections = list() - var/list/active_hotspots = list() +/datum/controller/air_system/ + //Geoemetry lists + var/list/turfs_with_connections = list() + var/list/active_hotspots = list() - //Special functions lists - var/list/tiles_to_reconsider_zones = list() + //Special functions lists + var/list/tiles_to_reconsider_zones = list() - //Geometry updates lists - var/list/tiles_to_update = list() - var/list/connections_to_check = list() + //Geometry updates lists + var/list/tiles_to_update = list() + var/list/connections_to_check = list() - var/current_cycle = 0 - var/update_delay = 5 //How long between check should it try to process atmos again. - var/failed_ticks = 0 //How many ticks have runtimed? + var/current_cycle = 0 + var/update_delay = 5 //How long between check should it try to process atmos again. + var/failed_ticks = 0 //How many ticks have runtimed? - var/tick_progress = 0 + var/tick_progress = 0 /* process() @@ -122,97 +119,103 @@ datum */ - proc/setup() - //Purpose: Call this at the start to setup air groups geometry - // (Warning: Very processor intensive but only must be done once per round) - //Called by: Gameticker/Master controller - //Inputs: None. - //Outputs: None. +/datum/controller/air_system/proc/setup() + //Purpose: Call this at the start to setup air groups geometry + // (Warning: Very processor intensive but only must be done once per round) + //Called by: Gameticker/Master controller + //Inputs: None. + //Outputs: None. - set background = 1 - world << "\red \b Processing Geometry..." - sleep(-1) + set background = 1 + world << "\red \b Processing Geometry..." + sleep(-1) - var/start_time = world.timeofday + var/start_time = world.timeofday - var/simulated_turf_count = 0 + var/simulated_turf_count = 0 - for(var/turf/simulated/S in world) - simulated_turf_count++ - if(!S.zone && !S.blocks_air) - if(S.CanPass(null, S, 0, 0)) - new/zone(S) + for(var/turf/simulated/S in world) + simulated_turf_count++ + if(!S.zone && !S.blocks_air) + if(S.CanPass(null, S, 0, 0)) + new/zone(S) - for(var/turf/simulated/S in world) - S.update_air_properties() + for(var/turf/simulated/S in world) + S.update_air_properties() - world << {"Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds. - Total Simulated Turfs: [simulated_turf_count] - Total Zones: [zones.len] - Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]"} - /* - spawn start() + world << {"Geometry initialized in [round(0.1*(world.timeofday-start_time),0.1)] seconds. +Total Simulated Turfs: [simulated_turf_count] +Total Zones: [zones.len] +Total Unsimulated Turfs: [world.maxx*world.maxy*world.maxz - simulated_turf_count]"} + /* + spawn start() - proc/start() - //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. - //Called by: Master controller - //Inputs: None. - //Outputs: None. +/datum/controller/air_system/proc/start() + //Purpose: This is kicked off by the master controller, and controls the processing of all atmosphere. + //Called by: Master controller + //Inputs: None. + //Outputs: None. - set background = 1 + set background = 1 - while(1) - if(!kill_air) - current_cycle++ - var/success = tick() //Changed so that a runtime does not crash the ticker. - if(!success) //Runtimed. - failed_ticks++ - if(failed_ticks > 20) - world << "ERROR IN ATMOS TICKER. Killing air simulation!" - kill_air = 1 - sleep(max(5,update_delay*tick_multiplier)) - */ + while(1) + if(!kill_air) + current_cycle++ + var/success = tick() //Changed so that a runtime does not crash the ticker. + if(!success) //Runtimed. + failed_ticks++ + if(failed_ticks > 20) + world << "ERROR IN ATMOS TICKER. Killing air simulation!" + kill_air = 1 + sleep(max(5,update_delay*tick_multiplier)) + */ - proc/tick() - . = 1 //Set the default return value, for runtime detection. +/datum/controller/air_system/proc/tick() + . = 1 //Set the default return value, for runtime detection. - tick_progress = "update_air_properties" - if(tiles_to_update.len) //If there are tiles to update, do so. - for(var/turf/simulated/T in tiles_to_update) - if(. && T && !T.update_air_properties()) - . = 0 //If a runtime occured, make sure we can sense it. - //message_admins("ZASALERT: Unable run turf/simualted/update_air_properties()") - tiles_to_update = list() + tick_progress = "update_air_properties" + if(tiles_to_update.len) //If there are tiles to update, do so. + for(var/turf/simulated/T in tiles_to_update) + if(. && T && !T.update_air_properties()) + . = 0 //If a runtime occured, make sure we can sense it. + //message_admins("ZASALERT: Unable run turf/simualted/update_air_properties()") + if(.) + tiles_to_update = list() - //Check sanity on connection objects. - tick_progress = "connections_to_check" - if(connections_to_check.len) - for(var/connection/C in connections_to_check) - C.CheckPassSanity() - connections_to_check = list() + //Check sanity on connection objects. + if(.) + tick_progress = "connections_to_check" + if(connections_to_check.len) + for(var/connection/C in connections_to_check) + C.CheckPassSanity() + connections_to_check = list() - //Ensure tiles still have zones. - tick_progress = "tiles_to_reconsider_zones" - if(tiles_to_reconsider_zones.len) - for(var/turf/simulated/T in tiles_to_reconsider_zones) - if(!T.zone) - new /zone(T) - tiles_to_reconsider_zones = list() + //Ensure tiles still have zones. + if(.) + tick_progress = "tiles_to_reconsider_zones" + if(tiles_to_reconsider_zones.len) + for(var/turf/simulated/T in tiles_to_reconsider_zones) + if(!T.zone) + new /zone(T) + tiles_to_reconsider_zones = list() - //Process zones. - tick_progress = "zone/process()" - for(var/zone/Z in zones) - if(Z.last_update < current_cycle) - var/output = Z.process() - if(Z) - Z.last_update = current_cycle - if(. && Z && !output) - . = 0 - //Process fires. - tick_progress = "active_hotspots (fire)" - for(var/obj/fire/F in active_hotspots) - if(. && F && !F.process()) - . = 0 + //Process zones. + if(.) + tick_progress = "zone/process()" + for(var/zone/Z in zones) + if(Z.last_update < current_cycle) + var/output = Z.process() + if(Z) + Z.last_update = current_cycle + if(. && Z && !output) + . = 0 + //Process fires. + if(.) + tick_progress = "active_hotspots (fire)" + for(var/obj/fire/F in active_hotspots) + if(. && F && !F.process()) + . = 0 - tick_progress = "success" \ No newline at end of file + if(.) + tick_progress = "success" \ No newline at end of file diff --git a/code/ZAS/Fire.dm b/code/ZAS/Fire.dm index 023d60acf08..8973b3794b2 100644 --- a/code/ZAS/Fire.dm +++ b/code/ZAS/Fire.dm @@ -30,7 +30,7 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) var/igniting = 0 var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in src - + if(air_contents.check_combustability(liquid)) igniting = 1 @@ -43,132 +43,130 @@ turf/simulated/hotspot_expose(exposed_temperature, exposed_volume, soh) return igniting -obj - fire - //Icon for fire on turfs. +/obj/fire + //Icon for fire on turfs. - anchored = 1 - mouse_opacity = 0 + anchored = 1 + mouse_opacity = 0 - //luminosity = 3 + //luminosity = 3 - icon = 'fire.dmi' + icon = 'fire.dmi' + icon_state = "1" + + layer = TURF_LAYER + + var/firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel() + +/obj/fire/process() + . = 1 + + //get location and check if it is in a proper ZAS zone + var/turf/simulated/floor/S = loc + if(!S.zone) + del src + + if(!istype(S)) + del src + + var/datum/gas_mixture/air_contents = S.return_air() + //get liquid fuels on the ground. + var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S + //and the volatile stuff from the air + var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases + + //since the air is processed in fractions, we need to make sure not to have any minuscle residue or + //the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour + if(air_contents.oxygen < 0.001) + air_contents.oxygen = 0 + if(air_contents.toxins < 0.001) + air_contents.toxins = 0 + if(fuel) + if(fuel.moles < 0.001) + air_contents.trace_gases.Remove(fuel) + + //check if there is something to combust + if(!air_contents.check_combustability(liquid)) + del src + + //get a firelevel and set the icon + firelevel = air_contents.calculate_firelevel(liquid) + + if(firelevel > 6) + icon_state = "3" + SetLuminosity(7) + else if(firelevel > 2.5) + icon_state = "2" + SetLuminosity(5) + else icon_state = "1" + SetLuminosity(3) - layer = TURF_LAYER + //im not sure how to implement a version that works for every creature so for now monkeys are firesafe + for(var/mob/living/carbon/human/M in loc) + M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans! - var - firelevel = 10000 //Calculated by gas_mixture.calculate_firelevel() - process() - . = 1 - - //get location and check if it is in a proper ZAS zone - var/turf/simulated/floor/S = loc - if(!S.zone) - del src - - if(!istype(S)) - del src - - var/datum/gas_mixture/air_contents = S.return_air() - //get liquid fuels on the ground. - var/obj/effect/decal/cleanable/liquid_fuel/liquid = locate() in S - //and the volatile stuff from the air - var/datum/gas/volatile_fuel/fuel = locate() in air_contents.trace_gases - - //since the air is processed in fractions, we need to make sure not to have any minuscle residue or - //the amount of moles might get to low for some functions to catch them and thus result in wonky behaviour - if(air_contents.oxygen < 0.001) - air_contents.oxygen = 0 - if(air_contents.toxins < 0.001) - air_contents.toxins = 0 - if(fuel) - if(fuel.moles < 0.001) - air_contents.trace_gases.Remove(fuel) - - //check if there is something to combust - if(!air_contents.check_combustability(liquid)) - del src - - //get a firelevel and set the icon - firelevel = air_contents.calculate_firelevel(liquid) - - if(firelevel > 6) - icon_state = "3" - SetLuminosity(7) - else if(firelevel > 2.5) - icon_state = "2" - SetLuminosity(5) - else - icon_state = "1" - SetLuminosity(3) - - //im not sure how to implement a version that works for every creature so for now monkeys are firesafe - for(var/mob/living/carbon/human/M in loc) - M.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure() ) //Burn the humans! + //spread! + for(var/direction in cardinal) + if(S.air_check_directions&direction) //Grab all valid bordering tiles - - //spread! - for(var/direction in cardinal) - if(S.air_check_directions&direction) //Grab all valid bordering tiles + var/turf/simulated/enemy_tile = get_step(S, direction) - var/turf/simulated/enemy_tile = get_step(S, direction) + if(istype(enemy_tile)) + //If extinguisher mist passed over the turf it's trying to spread to, don't spread and + //reduce firelevel. + if(enemy_tile.fire_protection > world.time-30) + firelevel -= 1.5 + continue - if(istype(enemy_tile)) - //If extinguisher mist passed over the turf it's trying to spread to, don't spread and - //reduce firelevel. - if(enemy_tile.fire_protection > world.time-30) - firelevel -= 1.5 - continue + //Spread the fire. + if(!(locate(/obj/fire) in enemy_tile)) + if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) + new/obj/fire(enemy_tile,firelevel) + + //seperate part of the present gas + //this is done to prevent the fire burning all gases in a single pass + var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate) - //Spread the fire. - if(!(locate(/obj/fire) in enemy_tile)) - if( prob( 50 + 50 * (firelevel/vsc.fire_firelevel_multiplier) ) && S.CanPass(null, enemy_tile, 0,0) && enemy_tile.CanPass(null, S, 0,0)) - new/obj/fire(enemy_tile,firelevel) - - //seperate part of the present gas - //this is done to prevent the fire burning all gases in a single pass - var/datum/gas_mixture/flow = air_contents.remove_ratio(vsc.fire_consuption_rate) - ///////////////////////////////// FLOW HAS BEEN CREATED /// DONT DELETE THE FIRE UNTIL IT IS MERGED BACK OR YOU WILL DELETE AIR /////////////////////////////////////////////// - - if(flow) - if(flow.check_combustability(liquid)) - //Ensure flow temperature is higher than minimum fire temperatures. - //this creates some energy ex nihilo but is necessary to get a fire started - //lets just pretend this energy comes from the ignition source and dont mention this again - //flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) - - //burn baby burn! - flow.zburn(liquid,1) - - //merge the air back - S.assume_air(flow) + + if(flow) + if(flow.check_combustability(liquid)) + //Ensure flow temperature is higher than minimum fire temperatures. + //this creates some energy ex nihilo but is necessary to get a fire started + //lets just pretend this energy comes from the ignition source and dont mention this again + //flow.temperature = max(PLASMA_MINIMUM_BURN_TEMPERATURE+0.1,flow.temperature) + + //burn baby burn! + flow.zburn(liquid,1) + + //merge the air back + S.assume_air(flow) ///////////////////////////////// FLOW HAS BEEN REMERGED /// feel free to delete the fire again from here on ////////////////////////////////////////////////////////////////// - - New(newLoc,fl) - ..() - if(!istype(loc, /turf)) - del src +/obj/fire/New(newLoc,fl) + ..() - dir = pick(cardinal) - SetLuminosity(3) - firelevel = fl - air_master.active_hotspots.Add(src) + if(!istype(loc, /turf)) + del src + + dir = pick(cardinal) + SetLuminosity(3) + firelevel = fl + air_master.active_hotspots.Add(src) - Del() - if (istype(loc, /turf/simulated)) - SetLuminosity(0) +/obj/fire/Del() + if (istype(loc, /turf/simulated)) + SetLuminosity(0) - loc = null - air_master.active_hotspots.Remove(src) + loc = null + air_master.active_hotspots.Remove(src) - ..() + ..() @@ -180,13 +178,13 @@ turf/simulated/apply_fire_protection() datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid,force_burn) var/value = 0 - + if((temperature > PLASMA_MINIMUM_BURN_TEMPERATURE || force_burn) && check_combustability(liquid) ) - var/total_fuel = 0 + var/total_fuel = 0 var/datum/gas/volatile_fuel/fuel = locate() in trace_gases total_fuel += toxins - + if(fuel) //Volatile Fuel total_fuel += fuel.moles @@ -207,7 +205,7 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid,force //determine the amount of oxygen used var/total_oxygen = min(oxygen, 2 * total_fuel) - + //determine the amount of fuel actually used var/used_fuel_ratio = min(oxygen / 2 , total_fuel) / total_fuel total_fuel = total_fuel * used_fuel_ratio @@ -234,31 +232,31 @@ datum/gas_mixture/proc/zburn(obj/effect/decal/cleanable/liquid_fuel/liquid,force //calculate the energy produced by the reaction and then set the new temperature of the mix temperature = (starting_energy + vsc.fire_fuel_energy_release * total_fuel) / heat_capacity() - + update_values() value = total_reactants * used_reactants_ratio return value datum/gas_mixture/proc/check_combustability(obj/effect/decal/cleanable/liquid_fuel/liquid) //this check comes up very often and is thus centralized here to ease adding stuff - - var/datum/gas/volatile_fuel/fuel = locate() in trace_gases + + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases var/value = 0 - + if(oxygen && (toxins || fuel || liquid)) value = 1 - + return value datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fuel/liquid) //Calculates the firelevel based on one equation instead of having to do this multiple times in different areas. - + var/datum/gas/volatile_fuel/fuel = locate() in trace_gases var/total_fuel = 0 var/firelevel = 0 - + if(check_combustability(liquid)) - + total_fuel += toxins if(liquid) @@ -268,16 +266,16 @@ datum/gas_mixture/proc/calculate_firelevel(obj/effect/decal/cleanable/liquid_fue total_fuel += fuel.moles var/total_combustables = (total_fuel + oxygen) - + if(total_fuel > 0 && oxygen > 0) - + //slows down the burning when the concentration of the reactants is low var/dampening_multiplier = total_combustables / (total_combustables + nitrogen + carbon_dioxide) //calculates how close the mixture of the reactants is to the optimum var/mix_multiplier = 1 / (1 + (5 * ((oxygen / total_combustables) ^2))) //toss everything together firelevel = vsc.fire_firelevel_multiplier * mix_multiplier * dampening_multiplier - + return max( 0, firelevel) diff --git a/code/ZAS/Plasma.dm b/code/ZAS/Plasma.dm index 3196d93db92..9f0e95f6617 100644 --- a/code/ZAS/Plasma.dm +++ b/code/ZAS/Plasma.dm @@ -1,61 +1,61 @@ var/image/contamination_overlay = image('icons/effects/contamination.dmi') -pl_control/var - PLASMA_DMG = 3 - PLASMA_DMG_NAME = "Plasma Damage Amount" - PLASMA_DMG_DESC = "Self Descriptive" +/pl_control + var/PLASMA_DMG = 3 + var/PLASMA_DMG_NAME = "Plasma Damage Amount" + var/PLASMA_DMG_DESC = "Self Descriptive" - CLOTH_CONTAMINATION = 1 - CLOTH_CONTAMINATION_NAME = "Cloth Contamination" - CLOTH_CONTAMINATION_DESC = "If this is on, plasma does damage by getting into cloth." + var/CLOTH_CONTAMINATION = 1 + var/CLOTH_CONTAMINATION_NAME = "Cloth Contamination" + var/CLOTH_CONTAMINATION_DESC = "If this is on, plasma does damage by getting into cloth." - PLASMAGUARD_ONLY = 0 - PLASMAGUARD_ONLY_NAME = "\"PlasmaGuard Only\"" - PLASMAGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." + var/PLASMAGUARD_ONLY = 0 + var/PLASMAGUARD_ONLY_NAME = "\"PlasmaGuard Only\"" + var/PLASMAGUARD_ONLY_DESC = "If this is on, only biosuits and spacesuits protect against contamination and ill effects." - GENETIC_CORRUPTION = 0 - GENETIC_CORRUPTION_NAME = "Genetic Corruption Chance" - GENETIC_CORRUPTION_DESC = "Chance of genetic corruption as well as toxic damage, X in 10,000." + var/GENETIC_CORRUPTION = 0 + var/GENETIC_CORRUPTION_NAME = "Genetic Corruption Chance" + var/GENETIC_CORRUPTION_DESC = "Chance of genetic corruption as well as toxic damage, X in 10,000." - SKIN_BURNS = 0 - SKIN_BURNS_DESC = "Plasma has an effect similar to mustard gas on the un-suited." - SKIN_BURNS_NAME = "Skin Burns" + var/SKIN_BURNS = 0 + var/SKIN_BURNS_DESC = "Plasma has an effect similar to mustard gas on the un-suited." + var/SKIN_BURNS_NAME = "Skin Burns" - EYE_BURNS = 1 - EYE_BURNS_NAME = "Eye Burns" - EYE_BURNS_DESC = "Plasma burns the eyes of anyone not wearing eye protection." + var/EYE_BURNS = 1 + var/EYE_BURNS_NAME = "Eye Burns" + var/EYE_BURNS_DESC = "Plasma burns the eyes of anyone not wearing eye protection." - CONTAMINATION_LOSS = 0.02 - CONTAMINATION_LOSS_NAME = "Contamination Loss" - CONTAMINATION_LOSS_DESC = "How much toxin damage is dealt from contaminated clothing" //Per tick? ASK ARYN + var/CONTAMINATION_LOSS = 0.02 + var/CONTAMINATION_LOSS_NAME = "Contamination Loss" + var/CONTAMINATION_LOSS_DESC = "How much toxin damage is dealt from contaminated clothing" //Per tick? ASK ARYN - PLASMA_HALLUCINATION = 0 - PLASMA_HALLUCINATION_NAME = "Plasma Hallucination" - PLASMA_HALLUCINATION_DESC = "Does being in plasma cause you to hallucinate?" + var/PLASMA_HALLUCINATION = 0 + var/PLASMA_HALLUCINATION_NAME = "Plasma Hallucination" + var/PLASMA_HALLUCINATION_DESC = "Does being in plasma cause you to hallucinate?" - N2O_HALLUCINATION = 1 - N2O_HALLUCINATION_NAME = "N2O Hallucination" - N2O_HALLUCINATION_DESC = "Does being in sleeping gas cause you to hallucinate?" + var/N2O_HALLUCINATION = 1 + var/N2O_HALLUCINATION_NAME = "N2O Hallucination" + var/N2O_HALLUCINATION_DESC = "Does being in sleeping gas cause you to hallucinate?" obj/var/contaminated = 0 -obj/item/proc - can_contaminate() - //Clothing and backpacks can be contaminated. - if(flags & PLASMAGUARD) return 0 - else if(istype(src,/obj/item/weapon/storage/backpack)) return 0 //Cannot be washed :( - else if(istype(src,/obj/item/clothing)) return 1 - contaminate() - //Do a contamination overlay? Temporary measure to keep contamination less deadly than it was. - if(!contaminated) - contaminated = 1 - overlays += contamination_overlay +/obj/item/proc/can_contaminate() + //Clothing and backpacks can be contaminated. + if(flags & PLASMAGUARD) return 0 + else if(istype(src,/obj/item/weapon/storage/backpack)) return 0 //Cannot be washed :( + else if(istype(src,/obj/item/clothing)) return 1 - decontaminate() - contaminated = 0 - overlays -= contamination_overlay +/obj/item/proc/contaminate() + //Do a contamination overlay? Temporary measure to keep contamination less deadly than it was. + if(!contaminated) + contaminated = 1 + overlays += contamination_overlay + +/obj/item/proc/decontaminate() + contaminated = 0 + overlays -= contamination_overlay /mob/proc/contaminate() diff --git a/code/ZAS/Variable Settings.dm b/code/ZAS/Variable Settings.dm index dd22765e99c..80e243e3c58 100644 --- a/code/ZAS/Variable Settings.dm +++ b/code/ZAS/Variable Settings.dm @@ -1,322 +1,332 @@ var/global/vs_control/vsc = new -vs_control/var - fire_consuption_rate = 0.25 - fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" - fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." +/vs_control + var/fire_consuption_rate = 0.25 + var/fire_consuption_rate_NAME = "Fire - Air Consumption Ratio" + var/fire_consuption_rate_DESC = "Ratio of air removed and combusted per tick." - fire_firelevel_multiplier = 25 - fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" - fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." + var/fire_firelevel_multiplier = 25 + var/fire_firelevel_multiplier_NAME = "Fire - Firelevel Constant" + var/fire_firelevel_multiplier_DESC = "Multiplied by the equation for firelevel, affects mainly the extingiushing of fires." - fire_fuel_energy_release = 397000 - fire_fuel_energy_release_NAME = "Fire - Fuel energy release" - fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" - - - airflow_lightest_pressure = 20 - airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" - airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." - - airflow_light_pressure = 35 - airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" - airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." - - airflow_medium_pressure = 50 - airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" - airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." - - airflow_heavy_pressure = 65 - airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" - airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." - - airflow_dense_pressure = 85 - airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" - airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." - - airflow_stun_pressure = 60 - airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" - airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." - - airflow_stun_cooldown = 60 - airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" - airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." - - airflow_stun = 1 - airflow_stun_NAME = "Airflow Impact - Stunning" - airflow_stun_DESC = "How much a mob is stunned when hit by an object." - - airflow_damage = 2 - airflow_damage_NAME = "Airflow Impact - Damage" - airflow_damage_DESC = "Damage from airflow impacts." - - airflow_speed_decay = 1.5 - airflow_speed_decay_NAME = "Airflow Speed Decay" - airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." - - airflow_delay = 30 - airflow_delay_NAME = "Airflow Retrigger Delay" - airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." - - airflow_mob_slowdown = 1 - airflow_mob_slowdown_NAME = "Airflow Slowdown" - airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + var/fire_fuel_energy_release = 397000 + var/fire_fuel_energy_release_NAME = "Fire - Fuel energy release" + var/fire_fuel_energy_release_DESC = "The energy in joule released when burning one mol of a burnable substance" -vs_control - var - list/settings = list() - list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") - pl_control/plc = new() + var/airflow_lightest_pressure = 20 + var/airflow_lightest_pressure_NAME = "Airflow - Small Movement Threshold %" + var/airflow_lightest_pressure_DESC = "Percent of 1 Atm. at which items with the small weight classes will move." - New() - . = ..() - settings = vars.Copy() + var/airflow_light_pressure = 35 + var/airflow_light_pressure_NAME = "Airflow - Medium Movement Threshold %" + var/airflow_light_pressure_DESC = "Percent of 1 Atm. at which items with the medium weight classes will move." - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) + var/airflow_medium_pressure = 50 + var/airflow_medium_pressure_NAME = "Airflow - Heavy Movement Threshold %" + var/airflow_medium_pressure_DESC = "Percent of 1 Atm. at which items with the largest weight classes will move." + + var/airflow_heavy_pressure = 65 + var/airflow_heavy_pressure_NAME = "Airflow - Mob Movement Threshold %" + var/airflow_heavy_pressure_DESC = "Percent of 1 Atm. at which mobs will move." + + var/airflow_dense_pressure = 85 + var/airflow_dense_pressure_NAME = "Airflow - Dense Movement Threshold %" + var/airflow_dense_pressure_DESC = "Percent of 1 Atm. at which items with canisters and closets will move." + + var/airflow_stun_pressure = 60 + var/airflow_stun_pressure_NAME = "Airflow - Mob Stunning Threshold %" + var/airflow_stun_pressure_DESC = "Percent of 1 Atm. at which mobs will be stunned by airflow." + + var/airflow_stun_cooldown = 60 + var/airflow_stun_cooldown_NAME = "Aiflow Stunning - Cooldown" + var/airflow_stun_cooldown_DESC = "How long, in tenths of a second, to wait before stunning them again." + + var/airflow_stun = 1 + var/airflow_stun_NAME = "Airflow Impact - Stunning" + var/airflow_stun_DESC = "How much a mob is stunned when hit by an object." + + var/airflow_damage = 2 + var/airflow_damage_NAME = "Airflow Impact - Damage" + var/airflow_damage_DESC = "Damage from airflow impacts." + + var/airflow_speed_decay = 1.5 + var/airflow_speed_decay_NAME = "Airflow Speed Decay" + var/airflow_speed_decay_DESC = "How rapidly the speed gained from airflow decays." + + var/airflow_delay = 30 + var/airflow_delay_NAME = "Airflow Retrigger Delay" + var/airflow_delay_DESC = "Time in deciseconds before things can be moved by airflow again." + + var/airflow_mob_slowdown = 1 + var/airflow_mob_slowdown_NAME = "Airflow Slowdown" + var/airflow_mob_slowdown_DESC = "Time in tenths of a second to add as a delay to each movement by a mob if they are fighting the pull of the airflow." + + var/connection_insulation = 0.4 + var/connection_insulation_NAME = "Connections - Insulation" + var/connection_insulation_DESC = "How insulative a connection is, in terms of heat transfer. 1 is perfectly insulative, and 0 is perfectly conductive." + + var/connection_temperature_delta = 10 + var/connection_temperature_delta_NAME = "Connections - Temperature Difference" + var/connection_temperature_delta_DESC = "The smallest temperature difference which will cause heat to travel through doors." + + +/vs_control/var/list/settings = list() +/vs_control/var/list/bitflags = list("1","2","4","8","16","32","64","128","256","512","1024") +/vs_control/var/pl_control/plc = new() + +/vs_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) settings -= V - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC") || findtextEx(V,"_METHOD")) - settings -= V + settings -= "settings" + settings -= "bitflags" + settings -= "plc" - settings -= "settings" - settings -= "bitflags" - settings -= "plc" - - proc/ChangeSettingsDialog(mob/user,list/L) - //var/which = input(user,"Choose a setting:") in L - var/dat = "" - for(var/ch in L) - if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue - var/vw - var/vw_desc = "No Description." - var/vw_name = ch - if(ch in plc.settings) - vw = plc.vars[ch] - if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"] - if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"] - else - vw = vars[ch] - if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] - if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] - dat += "[vw_name] = [vw] \[Change\]
" - dat += "[vw_desc]

" - user << browse(dat,"window=settings") - Topic(href,href_list) - if("changevar" in href_list) - ChangeSetting(usr,href_list["changevar"]) - proc/ChangeSetting(mob/user,ch) +/vs_control/proc/ChangeSettingsDialog(mob/user,list/L) + //var/which = input(user,"Choose a setting:") in L + var/dat = "" + for(var/ch in L) + if(findtextEx(ch,"_RANDOM") || findtextEx(ch,"_DESC") || findtextEx(ch,"_METHOD") || findtextEx(ch,"_NAME")) continue var/vw - var/how = "Text" - var/display_description = ch + var/vw_desc = "No Description." + var/vw_name = ch if(ch in plc.settings) vw = plc.vars[ch] - if("[ch]_NAME" in plc.vars) - display_description = plc.vars["[ch]_NAME"] - if("[ch]_METHOD" in plc.vars) - how = plc.vars["[ch]_METHOD"] - else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" + if("[ch]_DESC" in plc.vars) vw_desc = plc.vars["[ch]_DESC"] + if("[ch]_NAME" in plc.vars) vw_name = plc.vars["[ch]_NAME"] else vw = vars[ch] - if("[ch]_NAME" in vars) - display_description = vars["[ch]_NAME"] - if("[ch]_METHOD" in vars) - how = vars["[ch]_METHOD"] + if("[ch]_DESC" in vars) vw_desc = vars["[ch]_DESC"] + if("[ch]_NAME" in vars) vw_name = vars["[ch]_NAME"] + dat += "[vw_name] = [vw] \[Change\]
" + dat += "[vw_desc]

" + user << browse(dat,"window=settings") + +/vs_control/Topic(href,href_list) + if("changevar" in href_list) + ChangeSetting(usr,href_list["changevar"]) + +/vs_control/proc/ChangeSetting(mob/user,ch) + var/vw + var/how = "Text" + var/display_description = ch + if(ch in plc.settings) + vw = plc.vars[ch] + if("[ch]_NAME" in plc.vars) + display_description = plc.vars["[ch]_NAME"] + if("[ch]_METHOD" in plc.vars) + how = plc.vars["[ch]_METHOD"] + else + if(isnum(vw)) + how = "Numeric" else - if(isnum(vw)) - how = "Numeric" - else - how = "Text" - var/newvar = vw - switch(how) - if("Numeric") - newvar = input(user,"Enter a number:","Settings",newvar) as num - if("Bit Flag") - var/flag = input(user,"Toggle which bit?","Settings") in bitflags - flag = text2num(flag) - if(newvar & flag) - newvar &= ~flag - else - newvar |= flag - if("Toggle") - newvar = !newvar - if("Text") - newvar = input(user,"Enter a string:","Settings",newvar) as text - if("Long Text") - newvar = input(user,"Enter text:","Settings",newvar) as message - vw = newvar - if(ch in plc.settings) - plc.vars[ch] = vw + how = "Text" + else + vw = vars[ch] + if("[ch]_NAME" in vars) + display_description = vars["[ch]_NAME"] + if("[ch]_METHOD" in vars) + how = vars["[ch]_METHOD"] else - vars[ch] = vw - if(how == "Toggle") - newvar = (newvar?"ON":"OFF") - world << "\blue [key_name(user)] changed the setting [display_description] to [newvar]." - if(ch in plc.settings) - ChangeSettingsDialog(user,plc.settings) - else - ChangeSettingsDialog(user,settings) - proc/RandomizeWithProbability() - for(var/V in settings) - var/newvalue - if("[V]_RANDOM" in vars) - if(isnum(vars["[V]_RANDOM"])) - newvalue = prob(vars["[V]_RANDOM"]) - else if(istext(vars["[V]_RANDOM"])) - newvalue = roll(vars["[V]_RANDOM"]) - else - newvalue = vars[V] - V = newvalue + if(isnum(vw)) + how = "Numeric" + else + how = "Text" + var/newvar = vw + switch(how) + if("Numeric") + newvar = input(user,"Enter a number:","Settings",newvar) as num + if("Bit Flag") + var/flag = input(user,"Toggle which bit?","Settings") in bitflags + flag = text2num(flag) + if(newvar & flag) + newvar &= ~flag + else + newvar |= flag + if("Toggle") + newvar = !newvar + if("Text") + newvar = input(user,"Enter a string:","Settings",newvar) as text + if("Long Text") + newvar = input(user,"Enter text:","Settings",newvar) as message + vw = newvar + if(ch in plc.settings) + plc.vars[ch] = vw + else + vars[ch] = vw + if(how == "Toggle") + newvar = (newvar?"ON":"OFF") + world << "\blue [key_name(user)] changed the setting [display_description] to [newvar]." + if(ch in plc.settings) + ChangeSettingsDialog(user,plc.settings) + else + ChangeSettingsDialog(user,settings) - proc/ChangePlasma() - for(var/V in plc.settings) - plc.Randomize(V) - - proc/SetDefault(var/mob/user) - var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\ - "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") - var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices - if(!def) - return - switch(def) - if("Plasma - Standard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 - plc.CONTAMINATION_LOSS = 0.02 - - if("Plasma - Low Hazard") - plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 - plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 0 - plc.CONTAMINATION_LOSS = 0.01 - - if("Plasma - High Hazard") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 0 - plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 - plc.CONTAMINATION_LOSS = 0.05 - - if("Plasma - Oh Shit!") - plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. - plc.PLASMAGUARD_ONLY = 1 - plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. - plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. - plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. - plc.PLASMA_HALLUCINATION = 1 - plc.CONTAMINATION_LOSS = 0.075 - - if("ZAS - Normal") - airflow_lightest_pressure = 20 - airflow_light_pressure = 35 - airflow_medium_pressure = 50 - airflow_heavy_pressure = 65 - airflow_dense_pressure = 85 - airflow_stun_pressure = 60 - airflow_stun_cooldown = 60 - airflow_stun = 1 - airflow_damage = 2 - airflow_speed_decay = 1.5 - airflow_delay = 30 - airflow_mob_slowdown = 1 - - if("ZAS - Forgiving") - airflow_lightest_pressure = 45 - airflow_light_pressure = 60 - airflow_medium_pressure = 120 - airflow_heavy_pressure = 110 - airflow_dense_pressure = 200 - airflow_stun_pressure = 150 - airflow_stun_cooldown = 90 - airflow_stun = 0.15 - airflow_damage = 0.15 - airflow_speed_decay = 1.5 - airflow_delay = 50 - airflow_mob_slowdown = 0 - - if("ZAS - Dangerous") - airflow_lightest_pressure = 15 - airflow_light_pressure = 30 - airflow_medium_pressure = 45 - airflow_heavy_pressure = 55 - airflow_dense_pressure = 70 - airflow_stun_pressure = 50 - airflow_stun_cooldown = 50 - airflow_stun = 2 - airflow_damage = 3 - airflow_speed_decay = 1.2 - airflow_delay = 25 - airflow_mob_slowdown = 2 - - if("ZAS - Hellish") - airflow_lightest_pressure = 20 - airflow_light_pressure = 30 - airflow_medium_pressure = 40 - airflow_heavy_pressure = 50 - airflow_dense_pressure = 60 - airflow_stun_pressure = 40 - airflow_stun_cooldown = 40 - airflow_stun = 3 - airflow_damage = 4 - airflow_speed_decay = 1 - airflow_delay = 20 - airflow_mob_slowdown = 3 - - - world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\"" - -pl_control - var/list/settings = list() - New() - . = ..() - settings = vars.Copy() - - var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. - for(var/V in D.vars) - settings -= V - - for(var/V in settings) - if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) - settings -= V - - settings -= "settings" - proc/Randomize(V) +/vs_control/proc/RandomizeWithProbability() + for(var/V in settings) var/newvalue if("[V]_RANDOM" in vars) if(isnum(vars["[V]_RANDOM"])) newvalue = prob(vars["[V]_RANDOM"]) else if(istext(vars["[V]_RANDOM"])) - var/txt = vars["[V]_RANDOM"] - if(findtextEx(txt,"PROB")) - txt = text2list(txt,"/") - txt[1] = replacetext(txt[1],"PROB","") - var/p = text2num(txt[1]) - var/r = txt[2] - if(prob(p)) - newvalue = roll(r) - else - newvalue = vars[V] - else if(findtextEx(txt,"PICK")) - txt = replacetext(txt,"PICK","") - txt = text2list(txt,",") - newvalue = pick(txt) - else - newvalue = roll(txt) + newvalue = roll(vars["[V]_RANDOM"]) else newvalue = vars[V] - vars[V] = newvalue + V = newvalue + +/vs_control/proc/ChangePlasma() + for(var/V in plc.settings) + plc.Randomize(V) + +/vs_control/proc/SetDefault(var/mob/user) + var/list/setting_choices = list("Plasma - Standard", "Plasma - Low Hazard", "Plasma - High Hazard", "Plasma - Oh Shit!",\ + "ZAS - Normal", "ZAS - Forgiving", "ZAS - Dangerous", "ZAS - Hellish") + var/def = input(user, "Which of these presets should be used?") as null|anything in setting_choices + if(!def) + return + switch(def) + if("Plasma - Standard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.02 + + if("Plasma - Low Hazard") + plc.CLOTH_CONTAMINATION = 0 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000 + plc.SKIN_BURNS = 0 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 0 + plc.CONTAMINATION_LOSS = 0.01 + + if("Plasma - High Hazard") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 0 + plc.GENETIC_CORRUPTION = 0 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.05 + + if("Plasma - Oh Shit!") + plc.CLOTH_CONTAMINATION = 1 //If this is on, plasma does damage by getting into cloth. + plc.PLASMAGUARD_ONLY = 1 + plc.GENETIC_CORRUPTION = 5 //Chance of genetic corruption as well as toxic damage, X in 1000. + plc.SKIN_BURNS = 1 //Plasma has an effect similar to mustard gas on the un-suited. + plc.EYE_BURNS = 1 //Plasma burns the eyes of anyone not wearing eye protection. + plc.PLASMA_HALLUCINATION = 1 + plc.CONTAMINATION_LOSS = 0.075 + + if("ZAS - Normal") + airflow_lightest_pressure = 20 + airflow_light_pressure = 35 + airflow_medium_pressure = 50 + airflow_heavy_pressure = 65 + airflow_dense_pressure = 85 + airflow_stun_pressure = 60 + airflow_stun_cooldown = 60 + airflow_stun = 1 + airflow_damage = 2 + airflow_speed_decay = 1.5 + airflow_delay = 30 + airflow_mob_slowdown = 1 + + if("ZAS - Forgiving") + airflow_lightest_pressure = 45 + airflow_light_pressure = 60 + airflow_medium_pressure = 120 + airflow_heavy_pressure = 110 + airflow_dense_pressure = 200 + airflow_stun_pressure = 150 + airflow_stun_cooldown = 90 + airflow_stun = 0.15 + airflow_damage = 0.15 + airflow_speed_decay = 1.5 + airflow_delay = 50 + airflow_mob_slowdown = 0 + + if("ZAS - Dangerous") + airflow_lightest_pressure = 15 + airflow_light_pressure = 30 + airflow_medium_pressure = 45 + airflow_heavy_pressure = 55 + airflow_dense_pressure = 70 + airflow_stun_pressure = 50 + airflow_stun_cooldown = 50 + airflow_stun = 2 + airflow_damage = 3 + airflow_speed_decay = 1.2 + airflow_delay = 25 + airflow_mob_slowdown = 2 + + if("ZAS - Hellish") + airflow_lightest_pressure = 20 + airflow_light_pressure = 30 + airflow_medium_pressure = 40 + airflow_heavy_pressure = 50 + airflow_dense_pressure = 60 + airflow_stun_pressure = 40 + airflow_stun_cooldown = 40 + airflow_stun = 3 + airflow_damage = 4 + airflow_speed_decay = 1 + airflow_delay = 20 + airflow_mob_slowdown = 3 + + + world << "\blue [key_name(user)] changed the global plasma/ZAS settings to \"[def]\"" + +/pl_control/var/list/settings = list() + +/pl_control/New() + . = ..() + settings = vars.Copy() + + var/datum/D = new() //Ensure only unique vars are put through by making a datum and removing all common vars. + for(var/V in D.vars) + settings -= V + + for(var/V in settings) + if(findtextEx(V,"_RANDOM") || findtextEx(V,"_DESC")) + settings -= V + + settings -= "settings" + +/pl_control/proc/Randomize(V) + var/newvalue + if("[V]_RANDOM" in vars) + if(isnum(vars["[V]_RANDOM"])) + newvalue = prob(vars["[V]_RANDOM"]) + else if(istext(vars["[V]_RANDOM"])) + var/txt = vars["[V]_RANDOM"] + if(findtextEx(txt,"PROB")) + txt = text2list(txt,"/") + txt[1] = replacetext(txt[1],"PROB","") + var/p = text2num(txt[1]) + var/r = txt[2] + if(prob(p)) + newvalue = roll(r) + else + newvalue = vars[V] + else if(findtextEx(txt,"PICK")) + txt = replacetext(txt,"PICK","") + txt = text2list(txt,",") + newvalue = pick(txt) + else + newvalue = roll(txt) + else + newvalue = vars[V] + vars[V] = newvalue diff --git a/code/ZAS/ZAS_Turfs.dm b/code/ZAS/ZAS_Turfs.dm index 2ed0478aba6..0070a19c5d2 100644 --- a/code/ZAS/ZAS_Turfs.dm +++ b/code/ZAS/ZAS_Turfs.dm @@ -1,278 +1,266 @@ -atom/var/pressure_resistance = ONE_ATMOSPHERE -turf +/atom/var/pressure_resistance = ONE_ATMOSPHERE - var/zone/zone +/turf/var/zone/zone - assume_air(datum/gas_mixture/giver) //use this for machines to adjust air - del(giver) - return 0 +/turf/assume_air(datum/gas_mixture/giver) //use this for machines to adjust air + del(giver) + return 0 - return_air() - //Create gas mixture to hold data for passing - var/datum/gas_mixture/GM = new +/turf/return_air() + //Create gas mixture to hold data for passing + var/datum/gas_mixture/GM = new - GM.oxygen = oxygen - GM.carbon_dioxide = carbon_dioxide - GM.nitrogen = nitrogen - GM.toxins = toxins + GM.oxygen = oxygen + GM.carbon_dioxide = carbon_dioxide + GM.nitrogen = nitrogen + GM.toxins = toxins - GM.temperature = temperature - GM.update_values() + GM.temperature = temperature + GM.update_values() - return GM + return GM - remove_air(amount as num) - var/datum/gas_mixture/GM = new +/turf/remove_air(amount as num) + var/datum/gas_mixture/GM = new - var/sum = oxygen + carbon_dioxide + nitrogen + toxins - if(sum>0) - GM.oxygen = (oxygen/sum)*amount - GM.carbon_dioxide = (carbon_dioxide/sum)*amount - GM.nitrogen = (nitrogen/sum)*amount - GM.toxins = (toxins/sum)*amount + var/sum = oxygen + carbon_dioxide + nitrogen + toxins + if(sum>0) + GM.oxygen = (oxygen/sum)*amount + GM.carbon_dioxide = (carbon_dioxide/sum)*amount + GM.nitrogen = (nitrogen/sum)*amount + GM.toxins = (toxins/sum)*amount - GM.temperature = temperature - GM.update_values() + GM.temperature = temperature + GM.update_values() - return GM + return GM -turf - simulated +/turf/simulated/var/current_graphic = null - var/current_graphic = null +/turf/simulated/var/tmp/datum/gas_mixture/air - var/tmp - datum/gas_mixture/air +/turf/simulated/var/tmp/processing = 1 - processing = 1 +/turf/simulated/var/tmp/air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update - air_check_directions = 0 //Do not modify this, just add turf to air_master.tiles_to_update +/turf/simulated/var/tmp/obj/fire/active_hotspot - obj/fire/active_hotspot +/turf/simulated/proc/update_visuals() + overlays = null + var/siding_icon_state = return_siding_icon_state() + if(siding_icon_state) + overlays += image('floors.dmi',siding_icon_state) + var/datum/gas_mixture/model = return_air() + switch(model.graphic) + if(1) + overlays.Add(plmaster) //TODO: Make invisible plasma an option + if(2) + overlays.Add(slmaster) - proc/update_visuals() - overlays = null +/turf/simulated/New() + ..() - var/siding_icon_state = return_siding_icon_state() - if(siding_icon_state) - overlays += image('floors.dmi',siding_icon_state) - var/datum/gas_mixture/model = return_air() - switch(model.graphic) - if(1) - overlays.Add(plmaster) //TODO: Make invisible plasma an option - if(2) - overlays.Add(slmaster) + if(!blocks_air) + air = new + air.oxygen = oxygen + air.carbon_dioxide = carbon_dioxide + air.nitrogen = nitrogen + air.toxins = toxins + air.temperature = temperature + air.update_values() - New() - ..() - - if(!blocks_air) - air = new - - air.oxygen = oxygen - air.carbon_dioxide = carbon_dioxide - air.nitrogen = nitrogen - air.toxins = toxins - - air.temperature = temperature - air.update_values() - - if(air_master) - air_master.tiles_to_update.Add(src) - - else - if(air_master) - for(var/direction in cardinal) - var/turf/simulated/floor/target = get_step(src,direction) - if(istype(target)) - air_master.tiles_to_update |= target - - Del() - if(active_hotspot) - del(active_hotspot) - if(blocks_air) - for(var/direction in list(NORTH, SOUTH, EAST, WEST)) - var/turf/simulated/tile = get_step(src,direction) - if(istype(tile) && !tile.blocks_air) - air_master.tiles_to_update.Add(tile) - ..() - - assume_air(datum/gas_mixture/giver) - if(!giver) return 0 - if(zone) - zone.air.merge(giver) - return 1 - else - return ..() - - return_air() - if(zone) - return zone.air - else if(air) - return air - - else - return ..() - - remove_air(amount as num) - if(zone) - var/datum/gas_mixture/removed = null - removed = zone.air.remove(amount) - return removed - else if(air) - var/datum/gas_mixture/removed = null - removed = air.remove(amount) - - if(air.check_tile_graphic()) - update_visuals(air) - return removed - - else - return ..() - - proc/update_air_properties() - var/air_directions_archived = air_check_directions - air_check_directions = 0 + if(air_master) + air_master.tiles_to_update.Add(src) + else + if(air_master) for(var/direction in cardinal) - if(ZAirPass(get_step(src,direction))) - air_check_directions |= direction + var/turf/simulated/floor/target = get_step(src,direction) + if(istype(target)) + air_master.tiles_to_update |= target - if(!zone && !blocks_air) //No zone, but not a wall. - for(var/direction in DoorDirections) //Check door directions first. - if(air_check_directions&direction) - var/turf/simulated/T = get_step(src,direction) - if(!istype(T)) - continue - if(T.zone) - T.zone.AddTurf(src) - break - if(!zone) //Still no zone - for(var/direction in CounterDoorDirections) //Check the others second. - if(air_check_directions&direction) - var/turf/simulated/T = get_step(src,direction) - if(!istype(T)) - continue - if(T.zone) - T.zone.AddTurf(src) - break - if(!zone) //No zone found, new zone! - new/zone(src) - if(!zone) //Still no zone, the floodfill determined it is not part of a larger zone. Force a zone on it. - new/zone(list(src)) +/turf/simulated/Del() + if(active_hotspot) + del(active_hotspot) + if(blocks_air) + for(var/direction in list(NORTH, SOUTH, EAST, WEST)) + var/turf/simulated/tile = get_step(src,direction) + if(istype(tile) && !tile.blocks_air) + air_master.tiles_to_update.Add(tile) + ..() - //Check pass sanity of the connections. - if("\ref[src]" in air_master.turfs_with_connections) - for(var/connection/C in air_master.turfs_with_connections["\ref[src]"]) - air_master.connections_to_check |= C +/turf/simulated/assume_air(datum/gas_mixture/giver) + if(!giver) return 0 + if(zone) + zone.air.merge(giver) + return 1 + else + return ..() - if(zone && !zone.rebuild) - for(var/direction in cardinal) - var/turf/T = get_step(src,direction) +/turf/simulated/return_air() + if(zone) + return zone.air + else if(air) + return air + + else + return ..() + +/turf/simulated/remove_air(amount as num) + if(zone) + var/datum/gas_mixture/removed = null + removed = zone.air.remove(amount) + return removed + else if(air) + var/datum/gas_mixture/removed = null + removed = air.remove(amount) + + if(air.check_tile_graphic()) + update_visuals(air) + return removed + + else + return ..() + +/turf/simulated/proc/update_air_properties() + var/air_directions_archived = air_check_directions + air_check_directions = 0 + + for(var/direction in cardinal) + if(ZAirPass(get_step(src,direction))) + air_check_directions |= direction + + if(!zone && !blocks_air) //No zone, but not a wall. + for(var/direction in DoorDirections) //Check door directions first. + if(air_check_directions&direction) + var/turf/simulated/T = get_step(src,direction) + if(!istype(T)) + continue + if(T.zone) + T.zone.AddTurf(src) + break + if(!zone) //Still no zone + for(var/direction in CounterDoorDirections) //Check the others second. + if(air_check_directions&direction) + var/turf/simulated/T = get_step(src,direction) if(!istype(T)) continue + if(T.zone) + T.zone.AddTurf(src) + break + if(!zone) //No zone found, new zone! + new/zone(src) + if(!zone) //Still no zone, the floodfill determined it is not part of a larger zone. Force a zone on it. + new/zone(list(src)) - //I can connect to air in this direction - if(air_check_directions&direction) + //Check pass sanity of the connections. + if("\ref[src]" in air_master.turfs_with_connections) + for(var/connection/C in air_master.turfs_with_connections["\ref[src]"]) + air_master.connections_to_check |= C - //If either block air, we must look to see if the adjacent turfs need rebuilt. - if(!CanPass(null, T, 0, 0)) + if(zone && !zone.rebuild) + for(var/direction in cardinal) + var/turf/T = get_step(src,direction) + if(!istype(T)) + continue - //Target blocks air - if(!T.CanPass(null, T, 0, 0)) - var/turf/NT = get_step(T, direction) + //I can connect to air in this direction + if(air_check_directions&direction) - //If that turf is in my zone still, rebuild. - if(istype(NT,/turf/simulated) && NT in zone.contents) - zone.rebuild = 1 + //If either block air, we must look to see if the adjacent turfs need rebuilt. + if(!CanPass(null, T, 0, 0)) - //If that is an unsimulated tile in my zone, see if we need to rebuild or just remove. - else if(istype(NT) && NT in zone.unsimulated_tiles) - var/consider_rebuild = 0 - for(var/d in cardinal) - var/turf/UT = get_step(NT,d) - if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild - consider_rebuild = 1 - break - if(consider_rebuild) - zone.rebuild = 1 //Gotta check if we need to rebuild, dammit - else - zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~ - - //To make a closed connection through closed door. - ZConnect(T, src) - - //If I block air. - else if(T.zone && !T.zone.rebuild) - var/turf/NT = get_step(src, reverse_direction(direction)) - - //If I am splitting a zone, rebuild. - if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents))) - T.zone.rebuild = 1 - - //If NT is unsimulated, parse if I should remove it or rebuild. - else if(istype(NT) && NT in T.zone.unsimulated_tiles) - var/consider_rebuild = 0 - for(var/d in cardinal) - var/turf/UT = get_step(NT,d) - if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild - consider_rebuild = 1 - break - - //Needs rebuilt. - if(consider_rebuild) - T.zone.rebuild = 1 - - //Not adjacent to anything, and unsimulated. Goodbye~ - else - T.zone.RemoveTurf(NT) - - else - //Produce connection through open door. - ZConnect(src,T) - - //Something like a wall was built, changing the geometry. - else if(air_directions_archived&direction) + //Target blocks air + if(!T.CanPass(null, T, 0, 0)) var/turf/NT = get_step(T, direction) - //If the tile is in our own zone, and we cannot connect to it, better rebuild. + //If that turf is in my zone still, rebuild. if(istype(NT,/turf/simulated) && NT in zone.contents) zone.rebuild = 1 - //Parse if we need to remove the tile, or rebuild the zone. + //If that is an unsimulated tile in my zone, see if we need to rebuild or just remove. else if(istype(NT) && NT in zone.unsimulated_tiles) var/consider_rebuild = 0 - - //Loop through all neighboring turfs to see if we should remove the turf or just rebuild. for(var/d in cardinal) var/turf/UT = get_step(NT,d) + if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild + consider_rebuild = 1 + break + if(consider_rebuild) + zone.rebuild = 1 //Gotta check if we need to rebuild, dammit + else + zone.RemoveTurf(NT) //Not adjacent to anything, and unsimulated. Goodbye~ - //If we find a neighboring tile that is in the same zone, rebuild - if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) + //To make a closed connection through closed door. + ZConnect(T, src) + + //If I block air. + else if(T.zone && !T.zone.rebuild) + var/turf/NT = get_step(src, reverse_direction(direction)) + + //If I am splitting a zone, rebuild. + if(istype(NT,/turf/simulated) && (NT in T.zone.contents || (NT.zone && T in NT.zone.contents))) + T.zone.rebuild = 1 + + //If NT is unsimulated, parse if I should remove it or rebuild. + else if(istype(NT) && NT in T.zone.unsimulated_tiles) + var/consider_rebuild = 0 + for(var/d in cardinal) + var/turf/UT = get_step(NT,d) + if(istype(UT, /turf/simulated) && UT.zone == T.zone && UT.CanPass(null, NT, 0, 0)) //If we find a neighboring tile that is in the same zone, check if we need to rebuild consider_rebuild = 1 break - //The unsimulated turf is adjacent to another one of our zone's turfs, - // better rebuild to be sure we didn't get cut in twain + //Needs rebuilt. if(consider_rebuild) - zone.rebuild = 1 + T.zone.rebuild = 1 //Not adjacent to anything, and unsimulated. Goodbye~ else - zone.RemoveTurf(NT) + T.zone.RemoveTurf(NT) - if(air_check_directions) - processing = 1 - else - processing = 0 - return 1 + else + //Produce connection through open door. + ZConnect(src,T) + //Something like a wall was built, changing the geometry. + else if(air_directions_archived&direction) + var/turf/NT = get_step(T, direction) + //If the tile is in our own zone, and we cannot connect to it, better rebuild. + if(istype(NT,/turf/simulated) && NT in zone.contents) + zone.rebuild = 1 + //Parse if we need to remove the tile, or rebuild the zone. + else if(istype(NT) && NT in zone.unsimulated_tiles) + var/consider_rebuild = 0 + //Loop through all neighboring turfs to see if we should remove the turf or just rebuild. + for(var/d in cardinal) + var/turf/UT = get_step(NT,d) + + //If we find a neighboring tile that is in the same zone, rebuild + if(istype(UT, /turf/simulated) && UT.zone == zone && UT.CanPass(null, NT, 0, 0)) + consider_rebuild = 1 + break + + //The unsimulated turf is adjacent to another one of our zone's turfs, + // better rebuild to be sure we didn't get cut in twain + if(consider_rebuild) + zone.rebuild = 1 + + //Not adjacent to anything, and unsimulated. Goodbye~ + else + zone.RemoveTurf(NT) + + if(air_check_directions) + processing = 1 + else + processing = 0 + return 1 /turf/proc/HasDoor(turf/O) //Checks for the presence of doors, used for zone spreading and connection. @@ -289,7 +277,7 @@ turf else return 1 -turf/proc/ZCanPass(turf/simulated/T, var/include_space = 0) +/turf/proc/ZCanPass(turf/simulated/T, var/include_space = 0) //Fairly standard pass checks for turfs, objects and directional windows. Also stops at the edge of space. if(!istype(T)) return 0 @@ -314,7 +302,7 @@ turf/proc/ZCanPass(turf/simulated/T, var/include_space = 0) return 1 -turf/proc/ZAirPass(turf/T) +/turf/proc/ZAirPass(turf/T) //Fairly standard pass checks for turfs, objects and directional windows. if(!istype(T)) return 0 @@ -336,7 +324,6 @@ turf/proc/ZAirPass(turf/T) return 1 - /*UNUSED /turf/proc/check_connections() //Checks for new connections that can be made. diff --git a/code/ZAS/ZAS_Zones.dm b/code/ZAS/ZAS_Zones.dm index 2f5d564b3b4..bc432289821 100644 --- a/code/ZAS/ZAS_Zones.dm +++ b/code/ZAS/ZAS_Zones.dm @@ -2,129 +2,126 @@ var/list/zones = list() var/list/DoorDirections = list(NORTH,WEST) //Which directions doors turfs can connect to zones var/list/CounterDoorDirections = list(SOUTH,EAST) //Which directions doors turfs can connect to zones -zone - - var - dbg_output = 0 //Enables debug output. - rebuild = 0 //If 1, zone will be rebuilt on next process. Not sure if used. - datum/gas_mixture/air //The air contents of the zone. - list/contents //All the tiles that are contained in this zone. - list/connections // /connection objects which refer to connections with other zones, e.g. through a door. - list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number +/zone + var/dbg_output = 0 //Enables debug output. + var/rebuild = 0 //If 1, zone will be rebuilt on next process. Not sure if used. + var/datum/gas_mixture/air //The air contents of the zone. + var/list/contents //All the tiles that are contained in this zone. + var/list/connections // /connection objects which refer to connections with other zones, e.g. through a door. + var/list/connected_zones //Parallels connections, but lists zones to which this one is connected and the number //of points they're connected at. - list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed. - list/unsimulated_tiles // Any space tiles in this list will cause air to flow out. - last_update = 0 - progress = "nothing" - - // To make sure you're not spammed to death by airflow sound effects - tmp/playsound_cooldown = 0 + var/list/closed_connection_zones //Same as connected_zones, but for zones where the door or whatever is closed. + var/list/unsimulated_tiles // Any space tiles in this list will cause air to flow out. + var/last_update = 0 + var/progress = "nothing" //CREATION AND DELETION - New(turf/start) - . = ..() - //Get the turfs that are part of the zone using a floodfill method - if(istype(start,/list)) - contents = start - else - contents = FloodFill(start) +/zone/New(turf/start) + . = ..() + //Get the turfs that are part of the zone using a floodfill method + if(istype(start,/list)) + contents = start + else + contents = FloodFill(start) - //Change all the zone vars of the turfs, check for space to be added to unsimulated_tiles. - for(var/turf/T in contents) - if(T.zone && T.zone != src) - T.zone.RemoveTurf(T) - T.zone = src - if(!istype(T,/turf/simulated)) - AddTurf(T) + //Change all the zone vars of the turfs, check for space to be added to unsimulated_tiles. + for(var/turf/T in contents) + if(T.zone && T.zone != src) + T.zone.RemoveTurf(T) + T.zone = src + if(!istype(T,/turf/simulated)) + AddTurf(T) - //Generate the gas_mixture for use in txhis zone by using the average of the gases - //defined at startup. - air = new - var/members = contents.len - for(var/turf/simulated/T in contents) - air.oxygen += T.oxygen / members - air.nitrogen += T.nitrogen / members - air.carbon_dioxide += T.carbon_dioxide / members - air.toxins += T.toxins / members - air.temperature += T.temperature / members - air.group_multiplier = contents.len - air.update_values() + //Generate the gas_mixture for use in txhis zone by using the average of the gases + //defined at startup. + air = new + air.group_multiplier = contents.len + for(var/turf/simulated/T in contents) + air.oxygen += T.oxygen / air.group_multiplier + air.nitrogen += T.nitrogen / air.group_multiplier + air.carbon_dioxide += T.carbon_dioxide / air.group_multiplier + air.toxins += T.toxins / air.group_multiplier + air.temperature += T.temperature / air.group_multiplier + air.update_values() - //Add this zone to the global list. - zones.Add(src) + //Add this zone to the global list. + zones.Add(src) //LEGACY, DO NOT USE. Use the SoftDelete proc. - Del() - //Ensuring the zone list doesn't get clogged with null values. - for(var/turf/simulated/T in contents) - RemoveTurf(T) - air_master.tiles_to_reconsider_zones += T - for(var/zone/Z in connected_zones) - if(src in Z.connected_zones) - Z.connected_zones.Remove(src) - for(var/connection/C in connections) - air_master.connections_to_check += C - zones.Remove(src) - air = null - . = ..() +/zone/Del() + //Ensuring the zone list doesn't get clogged with null values. + for(var/turf/simulated/T in contents) + RemoveTurf(T) + air_master.tiles_to_reconsider_zones += T + for(var/zone/Z in connected_zones) + if(src in Z.connected_zones) + Z.connected_zones.Remove(src) + for(var/connection/C in connections) + air_master.connections_to_check += C + zones.Remove(src) + air = null + . = ..() //Handles deletion via garbage collection. - proc/SoftDelete() - zones.Remove(src) - air = null +/zone/proc/SoftDelete() + zones.Remove(src) + air = null - //Ensuring the zone list doesn't get clogged with null values. - for(var/turf/simulated/T in contents) - RemoveTurf(T) - air_master.tiles_to_reconsider_zones += T + //Ensuring the zone list doesn't get clogged with null values. + for(var/turf/simulated/T in contents) + RemoveTurf(T) + air_master.tiles_to_reconsider_zones += T - //Removing zone connections and scheduling connection cleanup - for(var/zone/Z in connected_zones) - if(src in Z.connected_zones) - Z.connected_zones.Remove(src) - for(var/connection/C in connections) - air_master.connections_to_check += C + //Removing zone connections and scheduling connection cleanup + for(var/zone/Z in connected_zones) + if(src in Z.connected_zones) + Z.connected_zones.Remove(src) + connected_zones = null - return 1 + for(var/connection/C in connections) + air_master.connections_to_check += C + connections = null + + return 1 //ZONE MANAGEMENT FUNCTIONS - proc/AddTurf(turf/T) - //Adds the turf to contents, increases the size of the zone, and sets the zone var. - if(istype(T, /turf/simulated)) - if(T in contents) - return - if(T.zone) - T.zone.RemoveTurf(T) - contents += T - if(air) - air.group_multiplier++ - T.zone = src - else - if(!unsimulated_tiles) - unsimulated_tiles = list() - else if(T in unsimulated_tiles) - return - unsimulated_tiles += T - contents -= T +/zone/proc/AddTurf(turf/T) + //Adds the turf to contents, increases the size of the zone, and sets the zone var. + if(istype(T, /turf/simulated)) + if(T in contents) + return + if(T.zone) + T.zone.RemoveTurf(T) + contents += T + if(air) + air.group_multiplier++ + T.zone = src + else + if(!unsimulated_tiles) + unsimulated_tiles = list() + else if(T in unsimulated_tiles) + return + unsimulated_tiles += T + contents -= T - proc/RemoveTurf(turf/T) - //Same, but in reverse. - if(istype(T, /turf/simulated)) - if(!(T in contents)) - return - contents -= T - if(air) - air.group_multiplier-- - if(T.zone == src) - T.zone = null - else if(unsimulated_tiles) - unsimulated_tiles -= T - if(!unsimulated_tiles.len) - unsimulated_tiles = null +/zone/proc/RemoveTurf(turf/T) + //Same, but in reverse. + if(istype(T, /turf/simulated)) + if(!(T in contents)) + return + contents -= T + if(air) + air.group_multiplier-- + if(T.zone == src) + T.zone = null + else if(unsimulated_tiles) + unsimulated_tiles -= T + if(!unsimulated_tiles.len) + unsimulated_tiles = null ////////////// //PROCESSING// @@ -132,7 +129,7 @@ zone #define QUANTIZE(variable) (round(variable,0.0001)) -zone/proc/process() +/zone/proc/process() . = 1 progress = "problem with: SoftDelete()" @@ -151,7 +148,7 @@ zone/proc/process() if(!contents.len) //If we got soft deleted. return - progress = "problem with: air.adjust()" + progress = "problem with: air regeneration" //Sometimes explosions will cause the air to be deleted for some reason. if(!air) @@ -162,36 +159,23 @@ zone/proc/process() air.total_moles() world.log << "Air object lost in zone. Regenerating." - progress = "problem with: ShareSpace()" + progress = "problem with: ShareSpace()" if(unsimulated_tiles) if(locate(/turf/simulated) in unsimulated_tiles) for(var/turf/simulated/T in unsimulated_tiles) - RemoveTurf(T) - if(unsimulated_tiles) + unsimulated_tiles -= T + + if(unsimulated_tiles.len) var/moved_air = ShareSpace(air,unsimulated_tiles) - // Only play a sound effect every once in a while - if(playsound_cooldown <= world.time) - // Play a nice sound effect at one of the bordering turfs - - playsound_cooldown = world.time + rand(30, 70) - - var/turf/random_border = pick(contents) - play_wind_sound(random_border, abs(moved_air)) - if(moved_air > vsc.airflow_lightest_pressure) AirflowSpace(src) - - progress = "problem with: air.react()" - - //React the air here. - //Handled by fire, no need for this. -// air.react(null,0) + else + unsimulated_tiles = null //Check the graphic. - progress = "problem with: modifying turf graphics" air.graphic = 0 @@ -246,12 +230,13 @@ zone/proc/process() //Check if the connection is valid first. if(!C.Cleanup()) continue + //Do merging if conditions are met. Specifically, if there's a non-door connection //to somewhere with space, the zones are merged regardless of equilibrium, to speed //up spacing in areas with double-plated windows. if(C && C.A.zone && C.B.zone) //indirect = 2 is a direct connection. - if(C.indirect == 2 ) + if( C.indirect == 2 ) if(C.A.zone.air.compare(C.B.zone.air) || unsimulated_tiles) ZMerge(C.A.zone,C.B.zone) @@ -259,18 +244,13 @@ zone/proc/process() //Share some for(var/zone/Z in connected_zones) + //If that zone has already processed, skip it. + if(Z.last_update > last_update) + continue + if(air && Z.air) //Ensure we're not doing pointless calculations on equilibrium zones. var/moles_delta = abs(air.total_moles() - Z.air.total_moles()) - if(moles_delta > 0.1) - // Only play a sound effect every once in a while - if(playsound_cooldown <= world.time) - // Play a nice sound effect at one of the bordering turfs - - playsound_cooldown = world.time + rand(30, 70) - - var/turf/random_border = pick(contents) - play_wind_sound(random_border, abs(moles_delta)) if(moles_delta > 0.1 || abs(air.temperature - Z.air.temperature) > 0.1) if(abs(Z.air.return_pressure() - air.return_pressure()) > vsc.airflow_lightest_pressure) Airflow(src,Z) @@ -283,8 +263,11 @@ zone/proc/process() ShareRatio( air , Z.air , connected_zones[Z] + unsimulated_boost) for(var/zone/Z in closed_connection_zones) + //If that zone has already processed, skip it. + if(Z.last_update > last_update) + continue if(air && Z.air) - if( abs(air.temperature - Z.air.temperature) > 10 ) + if( abs(air.temperature - Z.air.temperature) > vsc.connection_temperature_delta ) ShareHeat(air, Z.air, closed_connection_zones[Z]) progress = "all components completed successfully, the problem is not here" @@ -293,7 +276,7 @@ zone/proc/process() //Air Movement// //////////////// -var/list/sharing_lookup_table = list(0.15, 0.20, 0.24, 0.27, 0.30, 0.33) +var/list/sharing_lookup_table = list(0.30, 0.40, 0.48, 0.54, 0.60, 0.66) proc/ShareRatio(datum/gas_mixture/A, datum/gas_mixture/B, connecting_tiles) //Shares a specific ratio of gas between mixtures using simple weighted averages. @@ -423,7 +406,9 @@ proc/ShareSpace(datum/gas_mixture/A, list/unsimulated_tiles, dbg_output) if(sharing_lookup_table.len >= unsimulated_tiles.len) //6 or more interconnecting tiles will max at 42% of air moved per tick. ratio = sharing_lookup_table[unsimulated_tiles.len] - ratio *= 2 + + //We need to adjust it to account for the insulation settings. + ratio *= 1 - vsc.connection_insulation A.oxygen = max(0, (A.oxygen - oxy_avg) * (1 - ratio) + oxy_avg ) A.nitrogen = max(0, (A.nitrogen - nit_avg) * (1 - ratio) + nit_avg ) @@ -543,22 +528,6 @@ zone/proc/Rebuild() if(istype(T) && T.zone && S.CanPass(null, T, 0, 0)) T.zone.AddTurf(S) - -proc/play_wind_sound(var/turf/random_border, var/n) - if(random_border) - var/windsound = 'sound/effects/wind/wind_2_1.ogg' - switch(n) - if(31 to 40) - windsound = pick('sound/effects/wind/wind_2_1.ogg', 'sound/effects/wind/wind_2_2.ogg') - if(41 to 50) - windsound = pick('sound/effects/wind/wind_3_1.ogg') - if(51 to 60) - windsound = pick('sound/effects/wind/wind_4_1.ogg', 'sound/effects/wind/wind_4_2.ogg') - if(61 to 1000000) - windsound = pick('sound/effects/wind/wind_5_1.ogg') - - playsound(random_border, windsound, 50, 1, 1) - //UNUSED /* zone/proc/connected_zones() diff --git a/code/controllers/master_controller.dm b/code/controllers/master_controller.dm index c22bf1e2dd8..22a905a2070 100644 --- a/code/controllers/master_controller.dm +++ b/code/controllers/master_controller.dm @@ -132,12 +132,12 @@ datum/controller/game_controller/proc/process() //src.set_debug_state("Air Master") air_master.current_cycle++ - var/success = air_master.tick() //Changed so that a runtime does not crash the ticker. - if(!success) //Runtimed. + if(!air_master.tick()) //Runtimed. air_master.failed_ticks++ if(air_master.failed_ticks > 5) world << "RUNTIMES IN ATMOS TICKER. Killing air simulation!" - message_admins("ZASALERT: unable run [air_master.tick_progress], tell someone about this!") + world.log << "### ZAS SHUTDOWN" + message_admins("ZASALERT: unable to run [air_master.tick_progress], shutting down!") log_admin("ZASALERT: unable run zone/process() -- [air_master.tick_progress]") air_processing_killed = 1 air_master.failed_ticks = 0 diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index 904761eba83..76cab54fd93 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -58,6 +58,10 @@ G.fields["sex"] = H.gender G.fields["species"] = H.get_species() G.fields["photo"] = get_id_photo(H) + if(H.gen_record && !jobban_isbanned(H, "Records")) + G.fields["notes"] = H.gen_record + else + G.fields["notes"] = "No notes found." general += G //Medical Record diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm index 81abf92546a..cafc1c58cd3 100644 --- a/code/datums/datumvars.dm +++ b/code/datums/datumvars.dm @@ -256,9 +256,12 @@ client body += "" body += "" + body += "" + body += "" if(ishuman(D)) body += "" body += "" + body += "" body += "" body += "" body += "" @@ -743,6 +746,63 @@ client H.dna.mutantrace = new_mutantrace H.update_mutantrace() + else if(href_list["setspecies"]) + if(!check_rights(R_SPAWN)) return + + var/mob/living/carbon/human/H = locate(href_list["setspecies"]) + if(!istype(H)) + usr << "This can only be done to instances of type /mob/living/carbon/human" + return + + var/datum/species/new_species = input("Please choose a new species.","Species",null) as null|anything in (typesof(/datum/species)-/datum/species) + + if(!H) + usr << "Mob doesn't exist anymore" + return + + if(H.set_species(new new_species)) + usr << "Set species of [H] to [H.species]." + else + usr << "Failed! Something went wrong." + + else if(href_list["addlanguage"]) + if(!check_rights(R_SPAWN)) return + + var/mob/H = locate(href_list["addlanguage"]) + if(!istype(H)) + usr << "This can only be done to instances of type /mob" + return + + var/datum/language/new_language = input("Please choose a language to add.","Language",null) as null|anything in (typesof(/datum/language)-/datum/language) + + if(!H) + usr << "Mob doesn't exist anymore" + return + + if(H.add_language(new new_language)) + usr << "Added [new_language] to [H]." + else + usr << "Mob already knows that language." + + else if(href_list["remlanguage"]) + if(!check_rights(R_SPAWN)) return + + var/mob/H = locate(href_list["remlanguage"]) + if(!istype(H)) + usr << "This can only be done to instances of type /mob" + return + + var/datum/language/rem_language = input("Please choose a language to remove.","Language",null) as null|anything in H.languages + + if(!H) + usr << "Mob doesn't exist anymore" + return + + if(H.remove_language(rem_language)) + usr << "Removed [rem_language] from [H]." + else + usr << "Mob doesn't know that language." + else if(href_list["regenerateicons"]) if(!check_rights(0)) return diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm index 57ddf7817e5..b3b03e6ac26 100755 --- a/code/datums/supplypacks.dm +++ b/code/datums/supplypacks.dm @@ -356,10 +356,12 @@ var/list/all_supply_groups = list("Operations","Security","Hospitality","Enginee /obj/item/weapon/storage/firstaid/fire, /obj/item/weapon/storage/firstaid/toxin, /obj/item/weapon/storage/firstaid/o2, + /obj/item/weapon/storage/firstaid/adv, /obj/item/weapon/reagent_containers/glass/bottle/antitoxin, /obj/item/weapon/reagent_containers/glass/bottle/inaprovaline, /obj/item/weapon/reagent_containers/glass/bottle/stoxin, - /obj/item/weapon/storage/box/syringes) + /obj/item/weapon/storage/box/syringes, + /obj/item/weapon/storage/box/autoinjectors) cost = 10 containertype = /obj/structure/closet/crate/medical containername = "Medical crate" diff --git a/code/defines/obj.dm b/code/defines/obj.dm index 661f4c43b38..a4ef521d9d7 100644 --- a/code/defines/obj.dm +++ b/code/defines/obj.dm @@ -51,7 +51,7 @@ //This list tracks characters spawned in the world and cannot be modified in-game. Currently referenced by respawn_character(). var/locked[] = list() - proc/get_manifest(monochrome) + proc/get_manifest(monochrome, OOC) var/list/heads = new() var/list/sec = new() var/list/eng = new() @@ -80,7 +80,15 @@ var/name = t.fields["name"] var/rank = t.fields["rank"] var/real_rank = t.fields["real_rank"] - isactive[name] = t.fields["p_stat"] + if(OOC) + var/active = 0 + for(var/mob/M in player_list) + if(M.real_name == name && M.client && M.client.inactivity <= 10 * 60 * 10) + active = 1 + break + isactive[name] = active ? "Active" : "Inactive" + else + isactive[name] = t.fields["p_stat"] //world << "[name]: [rank]" diff --git a/code/defines/obj/hydro.dm b/code/defines/obj/hydro.dm index 9e26cb48fdb..bfea9a3b22b 100644 --- a/code/defines/obj/hydro.dm +++ b/code/defines/obj/hydro.dm @@ -81,30 +81,6 @@ plant_type = 2 growthstages = 3 -/obj/item/seeds/replicapod - name = "pack of replica pod seeds" - desc = "These seeds grow into replica pods. They say these are used to harvest humans." - icon_state = "seed-replicapod" - mypath = "/obj/item/seeds/replicapod" - species = "replicapod" - plantname = "Replica Pod" - productname = "/mob/living/carbon/human" //verrry special -- Urist - lifespan = 50 //no idea what those do - endurance = 8 - maturation = 10 - production = 10 - yield = 1 //seeds if there isn't a dna inside - oneharvest = 1 - potency = 30 - plant_type = 0 - growthstages = 6 - var/ui = null //for storing the guy - var/se = null - var/ckey = null - var/realName = null - var/datum/mind/mind = null - gender = MALE - /obj/item/seeds/grapeseed name = "pack of grape seeds" desc = "These seeds grow into grape vines." diff --git a/code/game/area/Space Station 13 areas.dm b/code/game/area/Space Station 13 areas.dm index 049d7f0cd70..fd034fbf5ae 100755 --- a/code/game/area/Space Station 13 areas.dm +++ b/code/game/area/Space Station 13 areas.dm @@ -309,6 +309,11 @@ proc/process_ghost_teleport_locs() /area/shuttle/research/outpost icon_state = "shuttle" +/area/shuttle/vox/station + name = "\improper Vox Skipjack" + icon_state = "yellow" + requires_power = 0 + /area/airtunnel1/ // referenced in airtunnel.dm:759 /area/dummy/ // Referenced in engine.dm:261 @@ -489,10 +494,29 @@ proc/process_ghost_teleport_locs() icon_state = "yellow" requires_power = 0 +/area/vox_station/transit + name = "\improper hyperspace" + icon_state = "shuttle" +/area/vox_station/southwest_solars + name = "\improper aft port solars" + icon_state = "southwest" +/area/vox_station/northwest_solars + name = "\improper fore port solars" + icon_state = "northwest" +/area/vox_station/northeast_solars + name = "\improper fore starboard solars" + icon_state = "northeast" +/area/vox_station/southeast_solars + name = "\improper aft starboard solars" + icon_state = "southeast" + +/area/vox_station/mining + name = "\improper nearby mining asteroid" + icon_state = "north" //PRISON /area/prison diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index c0921cd54a1..1c9d5373300 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -47,6 +47,10 @@ var/list/cameras = list() for (var/obj/machinery/camera/C in src) cameras += C + if(state == 1) + C.network.Remove("Power Alarms") + else + C.network.Add("Power Alarms") for (var/mob/living/silicon/aiPlayer in player_list) if(aiPlayer.z == source.z) if (state == 1) @@ -73,11 +77,15 @@ //updateicon() for(var/obj/machinery/camera/C in RA) cameras += C + C.network.Add("Atmosphere Alarms") for(var/mob/living/silicon/aiPlayer in player_list) aiPlayer.triggerAlarm("Atmosphere", src, cameras, src) for(var/obj/machinery/computer/station_alert/a in machines) a.triggerAlarm("Atmosphere", src, cameras, src) else if (atmosalm == 2) + for(var/area/RA in related) + for(var/obj/machinery/camera/C in RA) + C.network.Remove("Atmosphere Alarms") for(var/mob/living/silicon/aiPlayer in player_list) aiPlayer.cancelAlarm("Atmosphere", src, src) for(var/obj/machinery/computer/station_alert/a in machines) @@ -101,8 +109,10 @@ spawn() D.close() var/list/cameras = list() - for (var/obj/machinery/camera/C in src) - cameras += C + for(var/area/RA in related) + for (var/obj/machinery/camera/C in RA) + cameras.Add(C) + C.network.Add("Fire Alarms") for (var/mob/living/silicon/ai/aiPlayer in player_list) aiPlayer.triggerAlarm("Fire", src, cameras, src) for (var/obj/machinery/computer/station_alert/a in machines) @@ -120,6 +130,9 @@ else if(D.density) spawn(0) D.open() + for(var/area/RA in related) + for (var/obj/machinery/camera/C in RA) + C.network.Remove("Fire Alarms") for (var/mob/living/silicon/ai/aiPlayer in player_list) aiPlayer.cancelAlarm("Fire", src, src) for (var/obj/machinery/computer/station_alert/a in machines) diff --git a/code/game/atoms.dm b/code/game/atoms.dm index 784ba44c188..d160e662e84 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -490,7 +490,7 @@ its easier to just keep the beam vertical. var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblClickNew() proc is being tested) -/atom/proc/DblClickNew() +/*/atom/proc/DblClickNew() if(!usr) return // TODO DOOHL: Intergrate params to new proc. Saved for another time because var/valid_place is a fucking brainfuck @@ -792,7 +792,7 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl if (in_range) if ( !animal.restrained() ) - attack_animal(animal) + attack_animal(animal)*/ /atom/DblClick(location, control, params) //TODO: DEFERRED: REWRITE if(!usr) return @@ -943,9 +943,9 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl // ------- ( CAN USE ITEM OR HAS 1 SECOND USE DELAY ) AND NOT CLICKING ON SCREEN ------- - if (usr.next_move < world.time) - usr.prev_move = usr.next_move - usr.next_move = world.time + 10 + if (usr.last_click + usr.click_delay < world.time) + usr.last_click = world.time + usr.click_delay = 0 else // ------- ALREADY USED ONE ITEM WITH USE DELAY IN THE PREVIOUS SECOND ------- return @@ -1109,10 +1109,9 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl // ------- ITEM INACESSIBLE OR CLICKING ON SCREEN ------- if (istype(src, /obj/screen)) // ------- IT'S THE HUD YOU'RE CLICKING ON ------- - usr.prev_move = usr.next_move - usr:lastDblClick = world.time + 2 - if (usr.next_move < world.time) - usr.next_move = world.time + 2 + usr.delay_click(2) + if (usr.last_click + usr.click_delay < world.time) + usr.last_click = world.time else return @@ -1144,7 +1143,7 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl src.hand_al(usr, usr.hand) else // ------- YOU ARE CLICKING ON AN OBJECT THAT'S INACCESSIBLE TO YOU AND IS NOT YOUR HUD ------- - if((LASER in usr:mutations) && usr:a_intent == "hurt" && world.time >= usr.next_move) + if((LASER in usr:mutations) && usr:a_intent == "hurt" && usr.last_click + usr.click_delay < world.time) // ------- YOU HAVE THE LASER MUTATION, YOUR INTENT SET TO HURT AND IT'S BEEN MORE THAN A DECISECOND SINCE YOU LAS TATTACKED ------- var/turf/T = get_turf(usr) @@ -1169,7 +1168,7 @@ var/using_new_click_proc = 0 //TODO ERRORAGE (This is temporary, while the DblCl spawn( 1 ) A.process() - usr.next_move = world.time + 6 + usr.delay_click(6) return /atom/proc/ShiftClick(var/mob/M as mob) diff --git a/code/game/communications.dm b/code/game/communications.dm index 94d53f6bf52..32d8ca69348 100644 --- a/code/game/communications.dm +++ b/code/game/communications.dm @@ -74,7 +74,6 @@ Radio: 1359 - Security 1441 - death squad 1443 - Confession Intercom -1349 - Miners 1347 - Cargo techs Devices: @@ -110,10 +109,21 @@ var/list/radiochannels = list( "Supply" = 1347, ) //depenging helpers -var/list/DEPT_FREQS = list(1351,1355,1357,1359,1213, 1443, 1441,1347) +var/list/DEPT_FREQS = list(1351, 1355, 1357, 1359, 1213, 1443, 1441, 1347) + +// central command channels, i.e deathsquid & response teams +var/list/CENT_FREQS = list(1441, 1443) + var/const/COMM_FREQ = 1353 //command, colored gold in chat window var/const/SYND_FREQ = 1213 +// department channels +var/const/SEC_FREQ = 1359 +var/const/ENG_FREQ = 1357 +var/const/SCI_FREQ = 1351 +var/const/MED_FREQ = 1355 +var/const/SUP_FREQ = 1347 + #define TRANSMISSION_WIRE 0 #define TRANSMISSION_RADIO 1 diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm index 7cca20dfac0..e53053764b2 100644 --- a/code/game/gamemodes/blob/blob.dm +++ b/code/game/gamemodes/blob/blob.dm @@ -6,7 +6,7 @@ var/list/blob_cores = list() var/list/blob_nodes = list() -/datum/game_mode/blob +/*/datum/game_mode/blob name = "blob" config_tag = "blob" required_players = 0 @@ -130,3 +130,4 @@ var/list/blob_nodes = list() stage = 3 return +*/ \ No newline at end of file diff --git a/code/game/gamemodes/cult/runes.dm b/code/game/gamemodes/cult/runes.dm index 9366cd00523..e73cfeb9422 100644 --- a/code/game/gamemodes/cult/runes.dm +++ b/code/game/gamemodes/cult/runes.dm @@ -389,7 +389,7 @@ var/list/sacrificed = list() var/chose_name = 0 for(var/obj/item/weapon/paper/P in this_rune.loc) if(P.info) - D.real_name = copytext(P.info, 1, MAX_NAME_LEN) + D.real_name = copytext(P.info, findtext(P.info,">")+1, findtext(P.info,"<",2) ) chose_name = 1 break if(!chose_name) diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm index 85fdca943e9..bb627fd3bcf 100644 --- a/code/game/gamemodes/game_mode.dm +++ b/code/game/gamemodes/game_mode.dm @@ -278,6 +278,7 @@ Implants; if(BE_REV) roletext="revolutionary" if(BE_CULTIST) roletext="cultist" if(BE_NINJA) roletext="ninja" + if(BE_RAIDER) roletext="raider" // Assemble a list of active players without jobbans. for(var/mob/new_player/player in player_list) diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm new file mode 100644 index 00000000000..fa4299c3c1b --- /dev/null +++ b/code/game/gamemodes/heist/heist.dm @@ -0,0 +1,252 @@ +/* +VOX HEIST ROUNDTYPE +*/ + +#define MAX_VOX_KILLS 10 //Number of kills during the round before the Inviolate is broken. + //Would be nice to use vox-specific kills but is currently not feasible. + +var/global/vox_kills = 0 //Used to check the Inviolate. + +/datum/game_mode/heist + name = "heist" + config_tag = "heist" + required_players = 15 + required_players_secret = 25 + required_enemies = 4 + recommended_enemies = 6 + + var/const/waittime_l = 600 //lower bound on time before intercept arrives (in tenths of seconds) + var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds) + + var/list/raid_objectives = list() //Raid objectives. + var/list/datum/mind/raiders = list() //Antags. + var/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective. + +/datum/game_mode/heist/announce() + world << "The current game mode is - Heist!" + world << "An unidentified bluespace signature has slipped past the Icarus and is approaching [station_name()]!" + world << "Whoever they are, they're likely up to no good. Protect the crew and station resources against this dastardly threat!" + world << "Raiders: Loot [station_name()] for anything and everything you need." + world << "Personnel: Repel the raiders and their low, low prices and/or crossbows." + +/datum/game_mode/heist/can_start() + + if(!..()) + return 0 + + var/list/candidates = get_players_for_role(BE_RAIDER) + var/raider_num = 0 + + //Check that we have enough vox. + if(candidates.len < required_enemies) + return 0 + else if(candidates.len < recommended_enemies) + raider_num = candidates.len + else + raider_num = recommended_enemies + + //Grab candidates randomly until we have enough. + while(raider_num > 0) + var/datum/mind/new_raider = pick(candidates) + raiders += new_raider + candidates -= new_raider + raider_num-- + + for(var/datum/mind/raider in raiders) + raider.assigned_role = "MODE" + raider.special_role = "Vox Raider" + return 1 + +/datum/game_mode/heist/pre_setup() + return 1 + +/datum/game_mode/heist/post_setup() + + //Build a list of spawn points. + var/list/turf/raider_spawn = list() + + for(var/obj/effect/landmark/L in landmarks_list) + if(L.name == "voxstart") + raider_spawn += get_turf(L) + del(L) + continue + + //Generate objectives for the group. + raid_objectives = forge_vox_objectives() + + var/index = 1 + + //Spawn the vox! + for(var/datum/mind/raider in raiders) + + if(index > raider_spawn.len) + index = 1 + + raider.current.loc = raider_spawn[index] + index++ + + var/sounds = rand(2,8) + var/i = 0 + var/newname = "" + + while(i<=sounds) + i++ + newname += pick(list("ti","hi","ki","ya","ta","ha","ka","ya","chi","cha","kah")) + + var/mob/living/carbon/human/vox = raider.current + + vox.languages += new /datum/language/vox + vox.real_name = capitalize(newname) + vox.name = vox.real_name + vox.age = rand(12,20) + vox.set_species(new /datum/species/vox) + vox.dna.mutantrace = "vox" + vox.h_style = "Short Vox Quills" + vox.equip_vox_raider() + vox.regenerate_icons() + + raider.objectives = raid_objectives + greet_vox(raider) + + spawn (rand(waittime_l, waittime_h)) + send_intercept() + +/datum/game_mode/heist/proc/is_raider_crew_safe() + + if(cortical_stacks.len == 0) + return 0 + + for(var/obj/stack in cortical_stacks) + if (get_area(stack) != locate(/area/shuttle/vox/station)) + return 0 + return 1 + +/datum/game_mode/heist/proc/is_raider_crew_alive() + + for(var/datum/mind/raider in raiders) + if(raider.current) + if(istype(raider.current,/mob/living/carbon/human) && raider.current.stat != 2) + return 1 + return 0 + +/datum/game_mode/heist/proc/forge_vox_objectives() + + + //Commented out for testing. + /* var/i = 1 + var/max_objectives = pick(2,2,2,3,3) + var/list/objs = list() + while(i<= max_objectives) + var/list/goals = list("kidnap","loot","salvage") + var/goal = pick(goals) + var/datum/objective/heist/O + + if(goal == "kidnap") + goals -= "kidnap" + O = new /datum/objective/heist/kidnap() + else if(goal == "loot") + O = new /datum/objective/heist/loot() + else + O = new /datum/objective/heist/salvage() + O.choose_target() + objs += O + + i++ + + //-All- vox raids have these two objectives. Failing them loses the game. + objs += new /datum/objective/heist/inviolate_crew + objs += new /datum/objective/heist/inviolate_death */ + + raid_objectives += new /datum/objective/heist/kidnap + raid_objectives += new /datum/objective/heist/loot + raid_objectives += new /datum/objective/heist/salvage + raid_objectives += new /datum/objective/heist/inviolate_crew + raid_objectives += new /datum/objective/heist/inviolate_death + + for(var/datum/objective/heist/O in raid_objectives) + O.choose_target() + + return raid_objectives + +/datum/game_mode/heist/proc/greet_vox(var/datum/mind/raider) + raider.current << "\blue You are a Vox Raider, fresh from the Shoal!" + raider.current << "\blue The Vox are a race of cunning, sharp-eyed nomadic raiders and traders endemic to Tau Ceti and much of the unexplored galaxy. You and the crew have come to the Exodus for plunder, trade or both." + raider.current << "\blue Vox are cowardly and will flee from larger groups, but corner one or find them en masse and they are vicious." + raider.current << "\blue Use :V to voxtalk, :H to talk on your encrypted channel, and don't forget to turn on your nitrogen internals!" + var/obj_count = 1 + for(var/datum/objective/objective in raider.objectives) + raider.current << "Objective #[obj_count]: [objective.explanation_text]" + obj_count++ + + +/datum/game_mode/heist/declare_completion() + + //No objectives, go straight to the feedback. + if(!(raid_objectives.len)) return ..() + + var/win_type = "Major" + var/win_group = "Crew" + var/win_msg = "" + + var/success = raid_objectives.len + + //Decrease success for failed objectives. + for(var/datum/objective/O in raid_objectives) + if(!(O.check_completion())) success-- + + //Set result by objectives. + if(success == raid_objectives.len) + win_type = "Major" + win_group = "Vox" + else if(success > 2) + win_type = "Minor" + win_group = "Vox" + else + win_type = "Minor" + win_group = "Crew" + + //Now we modify that result by the state of the vox crew. + if(!is_raider_crew_alive()) + + win_type = "Major" + win_group = "Crew" + win_msg += "The Vox Raiders have been wiped out!" + + else if(!is_raider_crew_safe()) + + if(win_group == "Crew" && win_type == "Minor") + win_type = "Major" + + win_group = "Crew" + win_msg += "The Vox Raiders have left someone behind!" + + else + + if(win_group == "Vox") + if(win_type == "Minor") + + win_type = "Major" + win_msg += "The Vox Raiders escaped the station!" + else + win_msg += "The Vox Raiders were repelled!" + + world << "\red [win_type] [win_group] victory!" + world << "[win_msg]" + feedback_set_details("round_end_result","heist - [win_type] [win_group]") + + var/count = 1 + for(var/datum/objective/objective in raid_objectives) + if(objective.check_completion()) + world << "
Objective #[count]: [objective.explanation_text] Success!" + feedback_add_details("traitor_objective","[objective.type]|SUCCESS") + else + world << "
Objective #[count]: [objective.explanation_text] Fail." + feedback_add_details("traitor_objective","[objective.type]|FAIL") + count++ + + ..() + +/datum/game_mode/heist/check_finished() + if (!(is_raider_crew_alive()) || (vox_shuttle_location && (vox_shuttle_location == "start"))) + return 1 + return ..() \ No newline at end of file diff --git a/code/game/gamemodes/nuclear/nuclearbomb.dm b/code/game/gamemodes/nuclear/nuclearbomb.dm index 9d6e12c2223..7480555d694 100644 --- a/code/game/gamemodes/nuclear/nuclearbomb.dm +++ b/code/game/gamemodes/nuclear/nuclearbomb.dm @@ -15,6 +15,8 @@ var/bomb_set var/yes_code = 0.0 var/safety = 1.0 var/obj/item/weapon/disk/nuclear/auth = null + var/removal_stage = 0 // 0 is no removal, 1 is covers removed, 2 is covers open, + // 3 is sealant open, 4 is unwrenched, 5 is removed from bolts. flags = FPRINT use_power = 0 @@ -33,14 +35,83 @@ var/bomb_set src.attack_hand(M) return -/obj/machinery/nuclearbomb/attackby(obj/item/weapon/I as obj, mob/user as mob) +/obj/machinery/nuclearbomb/attackby(obj/item/weapon/O as obj, mob/user as mob) if (src.extended) - if (istype(I, /obj/item/weapon/disk/nuclear)) + if (istype(O, /obj/item/weapon/disk/nuclear)) usr.drop_item() - I.loc = src - src.auth = I + O.loc = src + src.auth = O src.add_fingerprint(user) return + + if (src.anchored) + switch(removal_stage) + if(0) + if(istype(O,/obj/item/weapon/weldingtool)) + + var/obj/item/weapon/weldingtool/WT = O + if(!WT.isOn()) return + if (WT.get_fuel() < 5) // uses up 5 fuel. + user << "\red You need more fuel to complete this task." + return + + user.visible_message("[user] starts cutting loose the anchoring bolt covers on [src].", "You start cutting loose the anchoring bolt covers with [O]...") + + if(do_after(user,40)) + if(!src || !user || !WT.remove_fuel(5, user)) return + user.visible_message("[user] cuts through the bolt covers on [src].", "You cut through the bolt cover.") + removal_stage = 1 + return + + if(1) + if(istype(O,/obj/item/weapon/crowbar)) + user.visible_message("[user] starts forcing open the bolt covers on [src].", "You start forcing open the anchoring bolt covers with [O]...") + + if(do_after(user,15)) + if(!src || !user) return + user.visible_message("[user] forces open the bolt covers on [src].", "You force open the bolt covers.") + removal_stage = 2 + return + + if(2) + if(istype(O,/obj/item/weapon/weldingtool)) + + var/obj/item/weapon/weldingtool/WT = O + if(!WT.isOn()) return + if (WT.get_fuel() < 5) // uses up 5 fuel. + user << "\red You need more fuel to complete this task." + return + + user.visible_message("[user] starts cutting apart the anchoring system sealant on [src].", "You start cutting apart the anchoring system's sealant with [O]...") + + if(do_after(user,40)) + if(!src || !user || !WT.remove_fuel(5, user)) return + user.visible_message("[user] cuts apart the anchoring system sealant on [src].", "You cut apart the anchoring system's sealant.") + removal_stage = 3 + return + + if(3) + if(istype(O,/obj/item/weapon/wrench)) + + user.visible_message("[user] begins unwrenching the anchoring bolts on [src].", "You begin unwrenching the anchoring bolts...") + + if(do_after(user,50)) + if(!src || !user) return + user.visible_message("[user] unwrenches the anchoring bolts on [src].", "You unwrench the anchoring bolts.") + removal_stage = 4 + return + + if(4) + if(istype(O,/obj/item/weapon/crowbar)) + + user.visible_message("[user] begins lifting [src] off of the anchors.", "You begin lifting the device off the anchors...") + + if(do_after(user,80)) + if(!src || !user) return + user.visible_message("[user] crowbars [src] off of the anchors. It can now be moved.", "You jam the crowbar under the nuclear device and lift it off its anchors. You can now move it!") + anchored = 0 + removal_stage = 5 + return ..() /obj/machinery/nuclearbomb/attack_paw(mob/user as mob) @@ -69,7 +140,11 @@ var/bomb_set user << browse(dat, "window=nuclearbomb;size=300x400") onclose(user, "nuclearbomb") else if (src.deployable) - src.anchored = 1 + if(removal_stage < 5) + src.anchored = 1 + visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring!") + else + visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") flick("nuclearbombc", src) src.icon_state = "nuclearbomb1" src.extended = 1 @@ -81,8 +156,10 @@ var/bomb_set set src in oview(1) if (src.deployable) + usr << "\red You close several panels to make [src] undeployable." src.deployable = 0 else + usr << "\red You adjust some panels to make [src] deployable." src.deployable = 1 /obj/machinery/nuclearbomb/Topic(href, href_list) @@ -148,7 +225,18 @@ var/bomb_set src.timing = 0 bomb_set = 0 if (href_list["anchor"]) + + if(removal_stage == 5) + src.anchored = 0 + visible_message("\red \The [src] makes a highly unpleasant crunching noise. It looks like the anchoring bolts have been cut.") + return + src.anchored = !( src.anchored ) + if(src.anchored) + visible_message("\red With a steely snap, bolts slide out of [src] and anchor it to the flooring.") + else + visible_message("\red The anchoring bolts slide back into the depths of [src].") + src.add_fingerprint(usr) for(var/mob/M in viewers(1, src)) if ((M.client && M.machine == src)) diff --git a/code/game/gamemodes/objective.dm b/code/game/gamemodes/objective.dm index 1b3552408c5..3d154485133 100644 --- a/code/game/gamemodes/objective.dm +++ b/code/game/gamemodes/objective.dm @@ -742,3 +742,173 @@ datum/objective/absorb /*-------ENDOF CULTIST------*/ */ + +//Vox heist objectives. + +datum/objective/heist + proc/choose_target() + return + +datum/objective/heist/kidnap + choose_target() + var/list/roles = list("Chief Engineer","Research Director","Roboticist","Chemist","Station Engineer") + var/list/possible_targets = list() + var/list/priority_targets = list() + + for(var/datum/mind/possible_target in ticker.minds) + if(possible_target != owner && ishuman(possible_target.current) && (possible_target.current.stat != 2) && (possible_target.assigned_role != "MODE")) + possible_targets += possible_target + for(var/role in roles) + if(possible_target.assigned_role == role) + priority_targets += possible_target + continue + + if(priority_targets.len > 0) + target = pick(priority_targets) + else if(possible_targets.len > 0) + target = pick(possible_targets) + + if(target && target.current) + explanation_text = "The Shoal has a need for [target.current.real_name], the [target.assigned_role]. Take them alive." + else + explanation_text = "Free Objective" + return target + + check_completion() + if(target && target.current) + if (target.current.stat == 2) + return 0 // They're dead. Fail. + //if (!target.current.restrained()) + // return 0 // They're loose. Close but no cigar. + + var/area/shuttle/vox/station/A = locate() + for(var/mob/living/carbon/human/M in A) + if(target.current == M) + return 1 //They're restrained on the shuttle. Success. + else + return 0 + +datum/objective/heist/loot + + choose_target() + var/loot = "an object" + switch(rand(1,8)) + if(1) + target = /obj/structure/particle_accelerator + target_amount = 6 + loot = "a complete particle accelerator" + if(2) + target = /obj/machinery/the_singularitygen + target_amount = 1 + loot = "a gravitational generator" + if(3) + target = /obj/machinery/power/emitter + target_amount = 4 + loot = "four emitters" + if(4) + target = /obj/machinery/nuclearbomb + target_amount = 1 + loot = "a nuclear bomb" + if(5) + target = /obj/item/weapon/gun + target_amount = 6 + loot = "six guns" + if(6) + target = /obj/item/weapon/gun/energy + target_amount = 4 + loot = "four energy guns" + if(7) + target = /obj/item/weapon/gun/energy/laser + target_amount = 2 + loot = "two laser guns" + if(8) + target = /obj/item/weapon/gun/energy/ionrifle + target_amount = 1 + loot = "an ion gun" + + explanation_text = "We are lacking in hardware. Steal [loot]." + + check_completion() + + var/total_amount = 0 + + for(var/obj/O in locate(/area/shuttle/vox/station)) + if(istype(O,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + var/datum/game_mode/heist/H = ticker.mode + for(var/datum/mind/raider in H.raiders) + if(raider.current) + for(var/obj/O in raider.current.get_contents()) + if(istype(O,target)) total_amount++ + if(total_amount >= target_amount) return 1 + + return 0 + +datum/objective/heist/salvage + + choose_target() + switch(rand(1,8)) + if(1) + target = "metal" + target_amount = 300 + if(2) + target = "glass" + target_amount = 200 + if(3) + target = "plasteel" + target_amount = 100 + if(4) + target = "plasma" + target_amount = 100 + if(5) + target = "silver" + target_amount = 50 + if(6) + target = "gold" + target_amount = 20 + if(7) + target = "uranium" + target_amount = 20 + if(8) + target = "diamond" + target_amount = 20 + + explanation_text = "Ransack the station and escape with [target_amount] [target]." + + check_completion() + + var/total_amount = 0 + + for(var/obj/item/O in locate(/area/shuttle/vox/station)) + if(istype(O,/obj/item/stack/sheet)) + if(O.name == target) + var/obj/item/stack/sheet/S = O + total_amount += S.amount + + var/datum/game_mode/heist/H = ticker.mode + for(var/datum/mind/raider in H.raiders) + if(raider.current) + for(var/obj/item/O in raider.current.get_contents()) + if(istype(O,/obj/item/stack/sheet)) + if(O.name == target) + var/obj/item/stack/sheet/S = O + total_amount += S.amount + + if(total_amount >= target_amount) return 1 + return 0 + + +datum/objective/heist/inviolate_crew + explanation_text = "Do not leave any Vox behind, alive or dead." + + check_completion() + var/datum/game_mode/heist/H = ticker.mode + if(H.is_raider_crew_safe()) return 1 + return 0 + +datum/objective/heist/inviolate_death + explanation_text = "Follow the Inviolate. Minimise death and loss of resources." + check_completion() + if(vox_kills>5) return 0 + return 1 \ No newline at end of file diff --git a/code/game/jobs/job/medical.dm b/code/game/jobs/job/medical.dm index cacd825d017..22dd096bcca 100644 --- a/code/game/jobs/job/medical.dm +++ b/code/game/jobs/job/medical.dm @@ -28,7 +28,7 @@ H.equip_to_slot_or_del(new /obj/item/clothing/shoes/brown(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/heads/cmo(H), slot_belt) H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/labcoat/cmo(H), slot_wear_suit) - H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(H), slot_l_hand) + H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/adv(H), slot_l_hand) H.equip_to_slot_or_del(new /obj/item/device/flashlight/pen(H), slot_s_store) if(H.backbag == 1) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) @@ -88,7 +88,7 @@ H.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/labcoat(H), slot_wear_suit) H.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(H), slot_shoes) H.equip_to_slot_or_del(new /obj/item/device/pda/medical(H), slot_belt) - H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/regular(H), slot_l_hand) + H.equip_to_slot_or_del(new /obj/item/weapon/storage/firstaid/adv(H), slot_l_hand) H.equip_to_slot_or_del(new /obj/item/device/flashlight/pen(H), slot_s_store) if(H.backbag == 1) H.equip_to_slot_or_del(new /obj/item/weapon/storage/box/survival(H), slot_r_hand) diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm index 69519c585d1..7078d9df906 100644 --- a/code/game/machinery/OpTable.dm +++ b/code/game/machinery/OpTable.dm @@ -18,6 +18,7 @@ for(dir in list(NORTH,EAST,SOUTH,WEST)) computer = locate(/obj/machinery/computer/operating, get_step(src, dir)) if (computer) + computer.table = src break // spawn(100) //Wont the MC just call this process() before and at the 10 second mark anyway? // process() diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm index 9f9ff56f780..a4158218a1e 100644 --- a/code/game/machinery/Sleeper.dm +++ b/code/game/machinery/Sleeper.dm @@ -70,12 +70,14 @@ dat += text("[]\t-Burn Severity %: []
", (occupant.getFireLoss() < 60 ? "" : ""), occupant.getFireLoss()) dat += text("
Paralysis Summary %: [] ([] seconds left!)
", occupant.paralysis, round(occupant.paralysis / 4)) if(occupant.reagents) - dat += text("Inaprovaline units: [] units
", occupant.reagents.get_reagent_amount("inaprovaline")) - dat += text("Soporific: [] units
", occupant.reagents.get_reagent_amount("stoxin")) - dat += text("Dermaline: [] units
", occupant.reagents.get_reagent_amount("dermaline")) - dat += text("Bicaridine: [] units
", occupant.reagents.get_reagent_amount("bicaridine")) - dat += text("Dexalin: [] units
", occupant.reagents.get_reagent_amount("dexalin")) - dat += text("
Refresh meter readings each second
Inject Inaprovaline
Inject Soporific
Inject Dermaline
Inject Bicaridine
Inject Dexalin", src, src, src, src, src, src) + for(var/chemical in connected.available_chemicals) + dat += "[connected.available_chemicals[chemical]]: [occupant.reagents.get_reagent_amount(chemical)] units
" + dat += "
Refresh meter readings each second
" + for(var/chemical in connected.available_chemicals) + dat += "Inject [connected.available_chemicals[chemical]]: " + for(var/amount in connected.amounts) + dat += "[amount] units " + dat += "
" else dat += "The sleeper is empty." dat += text("

Close", user) @@ -88,27 +90,15 @@ return if ((usr.contents.Find(src) || ((get_dist(src, usr) <= 1) && istype(src.loc, /turf))) || (istype(usr, /mob/living/silicon/ai))) usr.set_machine(src) - if (src.connected) - if (src.connected.occupant) - if(src.connected.occupant.health > 0) - if (href_list["inap"]) - src.connected.inject_inap(usr) - if (href_list["stox"]) - src.connected.inject_stox(usr) - if (href_list["derm"]) - src.connected.inject_dermaline(usr) - if (href_list["bic"]) - src.connected.inject_bicaridine(usr) - if (href_list["dex"]) - src.connected.inject_dexalin(usr) - else - if(src.connected.occupant.health > -100) - if (href_list["inap"]) - src.connected.inject_inap(usr) - if (href_list["stox"] || href_list["derm"] || href_list["bic"] || href_list["dex"]) - usr << "\red \b this person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!" - else + if (href_list["chemical"]) + if (src.connected) + if (src.connected.occupant) + if (src.connected.occupant.stat == DEAD) usr << "\red \b This person has no life for to preserve anymore. Take them to a department capable of reanimating them." + else if(src.connected.occupant.health > 0 || href_list["chemical"] == "inaprovaline") + src.connected.inject_chemical(usr,href_list["chemical"],text2num(href_list["amount"])) + else + usr << "\red \b This person is not in good enough condition for sleepers to be effective! Use another means of treatment, such as cryogenics!" if (href_list["refresh"]) src.updateUsrDialog() src.add_fingerprint(usr) @@ -142,6 +132,8 @@ anchored = 1 var/orient = "LEFT" // "RIGHT" changes the dir suffix to "-r" var/mob/living/occupant = null + var/available_chemicals = list("inaprovaline" = "Inaprovaline", "stoxin" = "Soporific", "dermaline" = "Dermaline", "bicaridine" = "Bicaridine", "dexalin" = "Dexalin") + var/amounts = list(10, 20) New() @@ -275,53 +267,13 @@ return - proc/inject_inap(mob/living/user as mob) + proc/inject_chemical(mob/living/user as mob, chemical, amount) if(src.occupant && src.occupant.reagents) - if(src.occupant.reagents.get_reagent_amount("inaprovaline") + 30 <= 60) - src.occupant.reagents.add_reagent("inaprovaline", 30) - user << text("Occupant now has [] units of Inaprovaline in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("inaprovaline")) - else - user << "There's no occupant in the sleeper or the subject rejects the chemicals!" - return - - - proc/inject_stox(mob/living/user as mob) - if(src.occupant && src.occupant.reagents) - if(src.occupant.reagents.get_reagent_amount("stoxin") + 20 <= 40) - src.occupant.reagents.add_reagent("stoxin", 20) - user << text("Occupant now has [] units of soporifics in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("stoxin")) - else - user << "There's no occupant in the sleeper or the subject rejects the chemicals!" - return - - - proc/inject_dermaline(mob/living/user as mob) - if(src.occupant && src.occupant.reagents) - if(src.occupant.reagents.get_reagent_amount("dermaline") + 20 <= 40) - src.occupant.reagents.add_reagent("dermaline", 20) - user << text("Occupant now has [] units of Dermaline in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("dermaline")) - else - user << "There's no occupant in the sleeper or the subject rejects the chemicals!" - return - - - proc/inject_bicaridine(mob/living/user as mob) - if(src.occupant && src.occupant.reagents) - if(src.occupant.reagents.get_reagent_amount("bicaridine") + 10 <= 20) - src.occupant.reagents.add_reagent("bicaridine", 10) - user << text("Occupant now has [] units of Bicaridine in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("bicaridine")) - else - user << "There's no occupant in the sleeper or the subject rejects the chemicals!" - return - - - proc/inject_dexalin(mob/living/user as mob) - if(src.occupant && src.occupant.reagents) - if(src.occupant.reagents.get_reagent_amount("dexalin") + 20 <= 40) - src.occupant.reagents.add_reagent("dexalin", 20) - user << text("Occupant now has [] units of Dexalin in his/her bloodstream.", src.occupant.reagents.get_reagent_amount("dexalin")) - else - user << "There's no occupant in the sleeper or the subject rejects the chemicals!" + if(src.occupant.reagents.get_reagent_amount(chemical) + amount <= 40) + src.occupant.reagents.add_reagent(chemical, amount) + user << "Occupant now has [src.occupant.reagents.get_reagent_amount(chemical)] units of [available_chemicals[chemical]] in his/her bloodstream." + return + user << "There's no occupant in the sleeper or the subject rejects the chemicals!" return @@ -398,4 +350,4 @@ del(O) src.add_fingerprint(usr) return - return + return \ No newline at end of file diff --git a/code/game/machinery/alarm.dm b/code/game/machinery/alarm.dm index ec48cf76cc4..ea2456cf977 100644 --- a/code/game/machinery/alarm.dm +++ b/code/game/machinery/alarm.dm @@ -1479,8 +1479,7 @@ FIRE ALARM A = A.loc if (!( istype(A, /area) )) return - for(var/area/RA in A.related) - RA.firereset() + A.firereset() update_icon() return @@ -1491,8 +1490,7 @@ FIRE ALARM A = A.loc if (!( istype(A, /area) )) return - for(var/area/RA in A.related) - RA.firealert() + A.firealert() update_icon() //playsound(src.loc, 'sound/ambience/signal.ogg', 75, 0) return diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm index 47b27ac54bd..d0345f60905 100644 --- a/code/game/machinery/bots/cleanbot.dm +++ b/code/game/machinery/bots/cleanbot.dm @@ -233,7 +233,8 @@ text("[src.oddbutton ? "Yes" : "No" if(target && path.len == 0) spawn(0) if(!src || !target) return - src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, 0, 30) + src.path = AStar(src.loc, src.target.loc, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id=botcard) + if (!path) path = list() if(src.path.len == 0) src.oldtarget = src.target src.target = null diff --git a/code/game/machinery/bots/ed209bot.dm b/code/game/machinery/bots/ed209bot.dm index 5e5ae744068..d71a43c083e 100644 --- a/code/game/machinery/bots/ed209bot.dm +++ b/code/game/machinery/bots/ed209bot.dm @@ -615,6 +615,7 @@ Auto Patrol: []"}, // given an optional turf to avoid /obj/machinery/bot/ed209/proc/calc_path(var/turf/avoid = null) src.path = AStar(src.loc, patrol_target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 120, id=botcard, exclude=avoid) + if (!src.path) src.path = list() // look for a criminal in view of the bot diff --git a/code/game/machinery/bots/floorbot.dm b/code/game/machinery/bots/floorbot.dm index bb984a1787b..69fc5afd3f3 100644 --- a/code/game/machinery/bots/floorbot.dm +++ b/code/game/machinery/bots/floorbot.dm @@ -241,9 +241,10 @@ if(src.target && (src.target != null) && src.path.len == 0) spawn(0) if(!istype(src.target, /turf/)) - src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) + src.path = AStar(src.loc, src.target.loc, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard) else - src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30) + src.path = AStar(src.loc, src.target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=botcard) + if (!src.path) src.path = list() if(src.path.len == 0) src.oldtarget = src.target src.target = null diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index c67a5a77b19..d5408d33308 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -87,6 +87,9 @@ usr << "No network found please hang up and try your call again." return + var/temptag = "[get_area(src)] ([rand(1, 999)])" + input = strip_html(input(usr, "How would you like to name the camera?", "Set Camera Name", temptag)) + state = 4 var/obj/machinery/camera/C = new(src.loc) src.loc = C @@ -94,9 +97,12 @@ C.auto_turn() - C.network = tempnetwork + C.network = uniquelist(tempnetwork) + tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS) + if(!tempnetwork.len)//Camera isn't on any open network - remove its chunk from AI visibility. + cameranet.removeCamera(C) - C.c_tag = "[get_area_name(src)] ([rand(1, 999)]" + C.c_tag = input for(var/i = 5; i >= 0; i -= 1) var/direct = input(user, "Direction?", "Assembling Camera", null) in list("LEAVE IT", "NORTH", "EAST", "SOUTH", "WEST" ) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 124239dc82b..fd66d0c2c32 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -116,7 +116,7 @@ //Clonepod //Start growing a human clone in the pod! -/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/mrace) +/obj/machinery/clonepod/proc/growclone(var/ckey, var/clonename, var/ui, var/se, var/mindref, var/datum/species/mrace) if(mess || attempting) return 0 var/datum/mind/clonemind = locate(mindref) @@ -191,13 +191,11 @@ randmutb(H) //Sometimes the clones come out wrong. H.f_style = "Shaved" - if(mrace == "none") //no more xenos losing ears/tentacles + if(mrace.name == "Human") //no more xenos losing ears/tentacles H.h_style = pick("Bedhead", "Bedhead 2", "Bedhead 3") - if(H.dna) - H.dna.mutantrace = mrace - H.update_mutantrace() - H.update_mutantrace_languages() + H.species = mrace + H.update_mutantrace() H.suiciding = 0 src.attempting = 0 return 1 diff --git a/code/game/machinery/computer/Operating.dm b/code/game/machinery/computer/Operating.dm index accd7b7a683..f1a1f02db70 100644 --- a/code/game/machinery/computer/Operating.dm +++ b/code/game/machinery/computer/Operating.dm @@ -13,7 +13,8 @@ ..() for(dir in list(NORTH,EAST,SOUTH,WEST)) table = locate(/obj/machinery/optable, get_step(src, dir)) - if (!isnull(table)) + if (table) + table.computer = src break /obj/machinery/computer/operating/attack_ai(mob/user) diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 2081a640d8e..7dca0ae01fb 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -37,6 +37,10 @@ /obj/item/weapon/circuitboard/security name = "Circuit board (Security)" build_path = "/obj/machinery/computer/security" + var/network = list("SS13") + req_access = list(access_security) + var/locked = 1 + var/emagged = 0 /obj/item/weapon/circuitboard/aicore name = "Circuit board (AI core)" origin_tech = "programming=4;biotech=2" @@ -80,6 +84,9 @@ /obj/item/weapon/circuitboard/secure_data name = "Circuit board (Security Records)" build_path = "/obj/machinery/computer/secure_data" +/obj/item/weapon/circuitboard/skills + name = "Circuit board (Employment Records)" + build_path = "/obj/machinery/computer/skills" /obj/item/weapon/circuitboard/stationalert name = "Circuit board (Station Alerts)" build_path = "/obj/machinery/computer/station_alert" @@ -166,10 +173,6 @@ name = "Circuit board (Operating Computer)" build_path = "/obj/machinery/computer/operating" origin_tech = "programming=2;biotech=2" -/obj/item/weapon/circuitboard/mining - name = "Circuit board (Outpost Status Display)" - build_path = "/obj/machinery/computer/security/mining" - origin_tech = "programming=2" /obj/item/weapon/circuitboard/comm_monitor name = "Circuit board (Telecommunications Monitor)" build_path = "/obj/machinery/computer/telecomms/monitor" @@ -238,6 +241,40 @@ user << "DERP! BUG! Report this (And what you were doing to cause it) to Agouri" return +/obj/item/weapon/circuitboard/security/attackby(obj/item/I as obj, mob/user as mob) + if(istype(I,/obj/item/weapon/card/emag)) + if(emagged) + user << "Circuit lock is already removed." + return + user << "\blue You override the circuit lock and open controls." + emagged = 1 + locked = 0 + else if(istype(I,/obj/item/weapon/card/id)) + if(emagged) + user << "\red Circuit lock does not respond." + return + if(check_access(I)) + locked = !locked + user << "\blue You [locked ? "" : "un"]lock the circuit controls." + else + user << "\red Access denied." + else if(istype(I,/obj/item/device/multitool)) + if(locked) + user << "\red Circuit controls are locked." + return + var/existing_networks = dd_list2text(network,",") + var/input = strip_html(input(usr, "Which networks would you like to connect this camera console circuit to? Seperate networks with a comma. No Spaces!\nFor example: SS13,Security,Secret ", "Multitool-Circuitboard interface", existing_networks)) + if(!input) + usr << "No input found please hang up and try your call again." + return + var/list/tempnetwork = text2list(input, ",") + tempnetwork = difflist(tempnetwork,RESTRICTED_CAMERA_NETWORKS,1) + if(tempnetwork.len < 1) + usr << "No network found please hang up and try your call again." + return + network = tempnetwork + return + /obj/item/weapon/circuitboard/rdconsole/attackby(obj/item/I as obj, mob/user as mob) if(istype(I,/obj/item/weapon/screwdriver)) if(src.build_path == "/obj/machinery/computer/rdconsole/core") @@ -353,4 +390,8 @@ var/obj/machinery/computer/supplycomp/SC = B var/obj/item/weapon/circuitboard/supplycomp/C = circuit SC.can_order_contraband = C.contraband_enabled - del(src) + if(istype(circuit,/obj/item/weapon/circuitboard/security)) + var/obj/machinery/computer/security/C = B + var/obj/item/weapon/circuitboard/security/CB = circuit + C.network = CB.network + del(src) \ No newline at end of file diff --git a/code/game/machinery/computer/camera.dm b/code/game/machinery/computer/camera.dm index 0e4caf97c3f..aeec294fa40 100644 --- a/code/game/machinery/computer/camera.dm +++ b/code/game/machinery/computer/camera.dm @@ -5,7 +5,6 @@ name = "Security Cameras" desc = "Used to access the various cameras on the station." icon_state = "cameras" - circuit = "/obj/item/weapon/circuitboard/security" var/obj/machinery/camera/current = null var/last_pic = 1.0 var/list/network = list("SS13") @@ -78,7 +77,38 @@ attack_hand(user) return - + attackby(I as obj, user as mob) + if(istype(I, /obj/item/weapon/screwdriver)) + playsound(loc, 'sound/items/Screwdriver.ogg', 50, 1) + if(do_after(user, 20)) + if (stat & BROKEN) + user << "\blue The broken glass falls out." + var/obj/structure/computerframe/CF = new /obj/structure/computerframe(loc) + new /obj/item/weapon/shard(loc) + var/obj/item/weapon/circuitboard/security/CB = new /obj/item/weapon/circuitboard/security(CF) + CB.network = network + for (var/obj/C in src) + C.loc = loc + CF.circuit = CB + CF.state = 3 + CF.icon_state = "3" + CF.anchored = 1 + del(src) + else + user << "\blue You disconnect the monitor." + var/obj/structure/computerframe/CF = new /obj/structure/computerframe( loc ) + var/obj/item/weapon/circuitboard/security/CB = new /obj/item/weapon/circuitboard/security(CF) + CB.network = network + for (var/obj/C in src) + C.loc = loc + CF.circuit = CB + CF.state = 4 + CF.icon_state = "4" + CF.anchored = 1 + del(src) + else + attack_hand(user) + return /obj/machinery/computer/security/telescreen name = "Telescreen" @@ -87,7 +117,6 @@ icon_state = "telescreen" network = list("thunder") density = 0 - circuit = null /obj/machinery/computer/security/telescreen/update_icon() icon_state = initial(icon_state) @@ -100,10 +129,6 @@ desc = "Damn, they better have /tg/thechannel on these things." icon = 'icons/obj/status_display.dmi' icon_state = "entertainment" - network = list("thunder") - density = 0 - circuit = null - /obj/machinery/computer/security/wooden_tv name = "Security Cameras" @@ -116,4 +141,9 @@ desc = "Used to access the various cameras on the outpost." icon_state = "miningcameras" network = list("MINE") - circuit = "/obj/item/weapon/circuitboard/mining" + +/obj/machinery/computer/security/engineering + name = "Engineering Cameras" + desc = "Used to monitor fires and breaches." + icon_state = "engineeringcameras" + network = list("Power Alarms","Atmosphere Alarms","Fire Alarms") \ No newline at end of file diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm index edb4882cd2b..e29097a0308 100644 --- a/code/game/machinery/computer/cloning.dm +++ b/code/game/machinery/computer/cloning.dm @@ -443,10 +443,7 @@ subject.dna.check_integrity() var/datum/data/record/R = new /datum/data/record( ) - if(subject.dna) - R.fields["mrace"] = subject.dna.mutantrace - else - R.fields["mrace"] = null + R.fields["mrace"] = subject.species R.fields["ckey"] = subject.ckey R.fields["name"] = subject.real_name R.fields["id"] = copytext(md5(subject.real_name), 2, 6) diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm new file mode 100644 index 00000000000..7613d711ce6 --- /dev/null +++ b/code/game/machinery/computer/skills.dm @@ -0,0 +1,419 @@ +//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 + +/obj/machinery/computer/skills//TODO:SANITY + name = "Employment Records" + desc = "Used to view personnel's employment records" + icon_state = "medlaptop" + req_one_access = list(access_heads) + circuit = "/obj/item/weapon/circuitboard/skills" + var/obj/item/weapon/card/id/scan = null + var/authenticated = null + var/rank = null + var/screen = null + var/datum/data/record/active1 = null + var/a_id = null + var/temp = null + var/printing = null + var/can_change_id = 0 + var/list/Perp + var/tempname = null + //Sorting Variables + var/sortBy = "name" + var/order = 1 // -1 = Descending - 1 = Ascending + + +/obj/machinery/computer/skills/attackby(obj/item/O as obj, user as mob) + if(istype(O, /obj/item/weapon/card/id) && !scan) + usr.drop_item() + O.loc = src + scan = O + user << "You insert [O]." + ..() + +/obj/machinery/computer/skills/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/skills/attack_paw(mob/user as mob) + return attack_hand(user) + +//Someone needs to break down the dat += into chunks instead of long ass lines. +/obj/machinery/computer/skills/attack_hand(mob/user as mob) + if(..()) + return + if (src.z > 6) + user << "\red Unable to establish a connection: \black You're too far away from the station!" + return + var/dat + + if (temp) + dat = text("[]

Clear Screen", temp, src) + else + dat = text("Confirm Identity: []
", src, (scan ? text("[]", scan.name) : "----------")) + if (authenticated) + switch(screen) + if(1.0) + dat += {" +

"} + dat += text("Search Records
", src) + dat += text("New Record
", src) + dat += {" +

+ + + + +
Records:
+ + + + + + +"} + if(!isnull(data_core.general)) + for(var/datum/data/record/R in sortRecord(data_core.general, sortBy, order)) + for(var/datum/data/record/E in data_core.security) + var/background + dat += text("", background, src, R, R.fields["name"]) + dat += text("", R.fields["id"]) + dat += text("", R.fields["rank"]) + dat += text("", R.fields["fingerprint"]) + dat += "
NameIDRankFingerprints
[][][][]

" + dat += text("Record Maintenance

", src) + dat += text("{Log Out}",src) + if(2.0) + dat += "Records Maintenance
" + dat += "
Delete All Records

Back" + if(3.0) + dat += "
Employment Record

" + if ((istype(active1, /datum/data/record) && data_core.general.Find(active1))) + var/icon/front = new(active1.fields["photo"], dir = SOUTH) + var/icon/side = new(active1.fields["photo"], dir = WEST) + user << browse_rsc(front, "front.png") + user << browse_rsc(side, "side.png") + dat += text(" \ +
\ + Name: [active1.fields["name"]]
\ + ID: [active1.fields["id"]]
\n \ + Sex: [active1.fields["sex"]]
\n \ + Age: [active1.fields["age"]]
\n \ + Rank: [active1.fields["rank"]]
\n \ + Fingerprint: [active1.fields["fingerprint"]]
\n \ + Physical Status: [active1.fields["p_stat"]]
\n \ + Mental Status: [active1.fields["m_stat"]]

\n \ + Employment/skills summary:
[active1.fields["notes"]]
Photo:
\ +
") + else + dat += "General Record Lost!
" + dat += text("\nDelete Record (ALL)

\nPrint Record
\nBack
", src, src, src) + if(4.0) + if(!Perp.len) + dat += text("ERROR. String could not be located.

Back", src) + else + dat += {" + + "} + dat += text("", tempname) + dat += {" + +
Search Results for '[]':
+ + + + + + + "} + for(var/i=1, i<=Perp.len, i += 2) + var/crimstat = "" + var/datum/data/record/R = Perp[i] + if(istype(Perp[i+1],/datum/data/record/)) + var/datum/data/record/E = Perp[i+1] + crimstat = E.fields["criminal"] + var/background + background = "'background-color:#00FF7F;'" + dat += text("", background, src, R, R.fields["name"]) + dat += text("", R.fields["id"]) + dat += text("", R.fields["rank"]) + dat += text("", R.fields["fingerprint"]) + dat += text("", crimstat) + dat += "
NameIDRankFingerprints
[][][][][]

" + dat += text("
Return to index.", src) + else + else + dat += text("{Log In}", src) + user << browse(text("Employment Records[]", dat), "window=secure_rec;size=600x400") + onclose(user, "secure_rec") + return + +/*Revised /N +I can't be bothered to look more of the actual code outside of switch but that probably needs revising too. +What a mess.*/ +/obj/machinery/computer/skills/Topic(href, href_list) + if(..()) + return + if (!( data_core.general.Find(active1) )) + active1 = null + if ((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (istype(usr, /mob/living/silicon))) + usr.set_machine(src) + switch(href_list["choice"]) +// SORTING! + if("Sorting") + // Reverse the order if clicked twice + if(sortBy == href_list["sort"]) + if(order == 1) + order = -1 + else + order = 1 + else + // New sorting order! + sortBy = href_list["sort"] + order = initial(order) +//BASIC FUNCTIONS + if("Clear Screen") + temp = null + + if ("Return") + screen = 1 + active1 = null + + if("Confirm Identity") + if (scan) + if(istype(usr,/mob/living/carbon/human) && !usr.get_active_hand()) + usr.put_in_hands(scan) + else + scan.loc = get_turf(src) + scan = null + else + var/obj/item/I = usr.get_active_hand() + if (istype(I, /obj/item/weapon/card/id)) + usr.drop_item() + I.loc = src + scan = I + + if("Log Out") + authenticated = null + screen = null + active1 = null + + if("Log In") + if (istype(usr, /mob/living/silicon/ai)) + src.active1 = null + src.authenticated = usr.name + src.rank = "AI" + src.screen = 1 + else if (istype(usr, /mob/living/silicon/robot)) + src.active1 = null + src.authenticated = usr.name + var/mob/living/silicon/robot/R = usr + src.rank = R.braintype + src.screen = 1 + else if (istype(scan, /obj/item/weapon/card/id)) + active1 = null + if(check_access(scan)) + authenticated = scan.registered_name + rank = scan.assignment + screen = 1 +//RECORD FUNCTIONS + if("Search Records") + var/t1 = input("Search String: (Partial Name or ID or Fingerprints or Rank)", "Secure. records", null, null) as text + if ((!( t1 ) || usr.stat || !( authenticated ) || usr.restrained() || !in_range(src, usr))) + return + Perp = new/list() + t1 = lowertext(t1) + var/list/components = text2list(t1, " ") + if(components.len > 5) + return //Lets not let them search too greedily. + for(var/datum/data/record/R in data_core.general) + var/temptext = R.fields["name"] + " " + R.fields["id"] + " " + R.fields["fingerprint"] + " " + R.fields["rank"] + for(var/i = 1, i<=components.len, i++) + if(findtext(temptext,components[i])) + var/prelist = new/list(2) + prelist[1] = R + Perp += prelist + for(var/i = 1, i<=Perp.len, i+=2) + for(var/datum/data/record/E in data_core.security) + var/datum/data/record/R = Perp[i] + if ((E.fields["name"] == R.fields["name"] && E.fields["id"] == R.fields["id"])) + Perp[i+1] = E + tempname = t1 + screen = 4 + + if("Record Maintenance") + screen = 2 + active1 = null + + if ("Browse Record") + var/datum/data/record/R = locate(href_list["d_rec"]) + if (!( data_core.general.Find(R) )) + temp = "Record Not Found!" + else + for(var/datum/data/record/E in data_core.security) + active1 = R + screen = 3 + +/* if ("Search Fingerprints") + var/t1 = input("Search String: (Fingerprint)", "Secure. records", null, null) as text + if ((!( t1 ) || usr.stat || !( authenticated ) || usr.restrained() || (!in_range(src, usr)) && (!istype(usr, /mob/living/silicon)))) + return + active1 = null + t1 = lowertext(t1) + for(var/datum/data/record/R in data_core.general) + if (lowertext(R.fields["fingerprint"]) == t1) + active1 = R + if (!( active1 )) + temp = text("Could not locate record [].", t1) + else + for(var/datum/data/record/E in data_core.security) + if ((E.fields["name"] == active1.fields["name"] || E.fields["id"] == active1.fields["id"])) + screen = 3 */ + + if ("Print Record") + if (!( printing )) + printing = 1 + sleep(50) + var/obj/item/weapon/paper/P = new /obj/item/weapon/paper( loc ) + P.info = "
Employment Record

" + if ((istype(active1, /datum/data/record) && data_core.general.Find(active1))) + P.info += text("Name: [] ID: []
\nSex: []
\nAge: []
\nFingerprint: []
\nPhysical Status: []
\nMental Status: []
\nEmployment/Skills Summary:[]
", active1.fields["name"], active1.fields["id"], active1.fields["sex"], active1.fields["age"], active1.fields["fingerprint"], active1.fields["p_stat"], active1.fields["m_stat"], active1.fields["notes"]) + else + P.info += "General Record Lost!
" + P.info += "" + P.name = "paper - 'Employment Record'" + printing = null +//RECORD DELETE + if ("Delete All Records") + temp = "" + temp += "Are you sure you wish to delete all Employment records?
" + temp += "Yes
" + temp += "No" + + if ("Purge All Records") + for(var/datum/data/record/R in data_core.security) + del(R) + temp = "All Employment records deleted." + + if ("Delete Record (ALL)") + if (active1) + temp = "
Are you sure you wish to delete the record (ALL)?
" + temp += "Yes
" + temp += "No" +//RECORD CREATE + if ("New Record (General)") + var/datum/data/record/G = new /datum/data/record() + G.fields["name"] = "New Record" + G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6)) + G.fields["rank"] = "Unassigned" + G.fields["real_rank"] = "Unassigned" + G.fields["sex"] = "Male" + G.fields["age"] = "Unknown" + G.fields["fingerprint"] = "Unknown" + G.fields["p_stat"] = "Active" + G.fields["m_stat"] = "Stable" + G.fields["species"] = "Human" + data_core.general += G + active1 = G + +//FIELD FUNCTIONS + if ("Edit Field") + var/a1 = active1 + switch(href_list["field"]) + if("name") + if (istype(active1, /datum/data/record)) + var/t1 = input("Please input name:", "Secure. records", active1.fields["name"], null) as text + if ((!( t1 ) || !length(trim(t1)) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon)))) || active1 != a1) + return + active1.fields["name"] = t1 + if("id") + if (istype(active1, /datum/data/record)) + var/t1 = copytext(sanitize(input("Please input id:", "Secure. records", active1.fields["id"], null) as text),1,MAX_MESSAGE_LEN) + if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) + return + active1.fields["id"] = t1 + if("fingerprint") + if (istype(active1, /datum/data/record)) + var/t1 = copytext(sanitize(input("Please input fingerprint hash:", "Secure. records", active1.fields["fingerprint"], null) as text),1,MAX_MESSAGE_LEN) + if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) + return + active1.fields["fingerprint"] = t1 + if("sex") + if (istype(active1, /datum/data/record)) + if (active1.fields["sex"] == "Male") + active1.fields["sex"] = "Female" + else + active1.fields["sex"] = "Male" + if("age") + if (istype(active1, /datum/data/record)) + var/t1 = input("Please input age:", "Secure. records", active1.fields["age"], null) as num + if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) + return + active1.fields["age"] = t1 + if("rank") + var/list/L = list( "Head of Personnel", "Captain", "AI" ) + //This was so silly before the change. Now it actually works without beating your head against the keyboard. /N + if ((istype(active1, /datum/data/record) && L.Find(rank))) + temp = "
Rank:
" + temp += "" + else + alert(usr, "You do not have the required rank to do this!") + if("species") + if (istype(active1, /datum/data/record)) + var/t1 = copytext(sanitize(input("Please enter race:", "General records", active1.fields["species"], null) as message),1,MAX_MESSAGE_LEN) + if ((!( t1 ) || !( authenticated ) || usr.stat || usr.restrained() || (!in_range(src, usr) && (!istype(usr, /mob/living/silicon))) || active1 != a1)) + return + active1.fields["species"] = t1 + +//TEMPORARY MENU FUNCTIONS + else//To properly clear as per clear screen. + temp=null + switch(href_list["choice"]) + if ("Change Rank") + if (active1) + active1.fields["rank"] = href_list["rank"] + if(href_list["rank"] in get_all_jobs()) + active1.fields["real_rank"] = href_list["real_rank"] + + if ("Delete Record (ALL) Execute") + if (active1) + for(var/datum/data/record/R in data_core.medical) + if ((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"])) + del(R) + else + del(active1) + else + temp = "This function does not appear to be working at the moment. Our apologies." + + add_fingerprint(usr) + updateUsrDialog() + return + +/obj/machinery/computer/skills/emp_act(severity) + if(stat & (BROKEN|NOPOWER)) + ..(severity) + return + + for(var/datum/data/record/R in data_core.security) + if(prob(10/severity)) + switch(rand(1,6)) + if(1) + R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]" + if(2) + R.fields["sex"] = pick("Male", "Female") + if(3) + R.fields["age"] = rand(5, 85) + if(4) + R.fields["criminal"] = pick("None", "*Arrest*", "Incarcerated", "Parolled", "Released") + if(5) + R.fields["p_stat"] = pick("*Unconcious*", "Active", "Physically Unfit") + if(6) + R.fields["m_stat"] = pick("*Insane*", "*Unstable*", "*Watch*", "Stable") + continue + + else if(prob(1)) + del(R) + continue + + ..(severity) \ No newline at end of file diff --git a/code/game/machinery/computer/vox_shuttle.dm b/code/game/machinery/computer/vox_shuttle.dm new file mode 100644 index 00000000000..fa9d05d7b90 --- /dev/null +++ b/code/game/machinery/computer/vox_shuttle.dm @@ -0,0 +1,106 @@ +#define VOX_SHUTTLE_MOVE_TIME 260 +#define VOX_SHUTTLE_COOLDOWN 460 + +//Copied from Syndicate shuttle. +var/global/vox_shuttle_location + +/obj/machinery/computer/vox_station + name = "vox skipjack terminal" + icon = 'icons/obj/computer.dmi' + icon_state = "syndishuttle" + req_access = list(access_syndicate) + var/area/curr_location + var/moving = 0 + var/lastMove = 0 + var/warning //Warning about the end of the round. + +/obj/machinery/computer/vox_station/New() + curr_location= locate(/area/shuttle/vox/station) + + +/obj/machinery/computer/vox_station/proc/vox_move_to(area/destination as area) + if(moving) return + if(lastMove + VOX_SHUTTLE_COOLDOWN > world.time) return + var/area/dest_location = locate(destination) + if(curr_location == dest_location) return + + moving = 1 + lastMove = world.time + + if(curr_location.z != dest_location.z) + var/area/transit_location = locate(/area/vox_station/transit) + curr_location.move_contents_to(transit_location) + curr_location = transit_location + sleep(VOX_SHUTTLE_MOVE_TIME) + + curr_location.move_contents_to(dest_location) + curr_location = dest_location + moving = 0 + + return 1 + + +/obj/machinery/computer/vox_station/attackby(obj/item/I as obj, mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/vox_station/attack_ai(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/vox_station/attack_paw(mob/user as mob) + return attack_hand(user) + +/obj/machinery/computer/vox_station/attack_hand(mob/user as mob) + if(!allowed(user)) + user << "\red Access Denied" + return + + user.set_machine(src) + + var/dat = {"Location: [curr_location]
+ Ready to move[max(lastMove + VOX_SHUTTLE_COOLDOWN - world.time, 0) ? " in [max(round((lastMove + VOX_SHUTTLE_COOLDOWN - world.time) * 0.1), 0)] seconds" : ": now"]
+ Return to dark space
+ Fore port solar | + Aft port solar | + Fore starboard solar
+ Aft starboard solar | + Mining Asteroid
+ Close"} + + user << browse(dat, "window=computer;size=575x450") + onclose(user, "computer") + return + + +/obj/machinery/computer/vox_station/Topic(href, href_list) + if(!isliving(usr)) return + var/mob/living/user = usr + + if(in_range(src, user) || istype(user, /mob/living/silicon)) + user.set_machine(src) + + vox_shuttle_location = "station" + if(href_list["start"]) + if(ticker && (istype(ticker.mode,/datum/game_mode/heist))) + if(!warning) + user << "\red Returning to dark space will end your raid and report your success or failure. If you are sure, press the button again." + warning = 1 + return + vox_move_to(/area/shuttle/vox/station) + vox_shuttle_location = "start" + else if(href_list["solars_fore_starboard"]) + vox_move_to(/area/vox_station/northeast_solars) + else if(href_list["solars_fore_port"]) + vox_move_to(/area/vox_station/northwest_solars) + else if(href_list["solars_aft_starboard"]) + vox_move_to(/area/vox_station/southeast_solars) + else if(href_list["solars_aft_port"]) + vox_move_to(/area/vox_station/southwest_solars) + else if(href_list["mining"]) + vox_move_to(/area/vox_station/mining) + + add_fingerprint(usr) + updateUsrDialog() + return + +/obj/machinery/computer/vox_station/bullet_act(var/obj/item/projectile/Proj) + visible_message("[Proj] ricochets off [src]!") \ No newline at end of file diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 4d634d45895..a5eb560e3c1 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -17,222 +17,287 @@ anchored = 1.0 // can't pick it up density = 0 // can walk through it. var/id = null // id of door it controls. - var/releasetime = 0 // when world.time reaches it - release the prisoneer + var/releasetime = 0 // when world.timeofday reaches it - release the prisoner var/timing = 1 // boolean, true/1 timer is on, false/0 means it's not timing var/picture_state // icon_state of alert picture, if not displaying text/numbers var/list/obj/machinery/targets = list() + var/timetoset = 0 // Used to set releasetime upon starting the timer - New() - ..() +/obj/machinery/door_timer/New() + ..() - pixel_x = ((src.dir & 3)? (0) : (src.dir == 4 ? 32 : -32)) - pixel_y = ((src.dir & 3)? (src.dir ==1 ? 24 : -32) : (0)) + pixel_x = ((src.dir & 3)? (0) : (src.dir == 4 ? 32 : -32)) + pixel_y = ((src.dir & 3)? (src.dir ==1 ? 24 : -32) : (0)) - spawn(20) - for(var/obj/machinery/door/window/brigdoor/M in world) - if (M.id == src.id) - targets += M + spawn(20) + for(var/obj/machinery/door/window/brigdoor/M in world) + if (M.id == src.id) + targets += M - for(var/obj/machinery/flasher/F in world) - if(F.id == src.id) - targets += F + for(var/obj/machinery/flasher/F in world) + if(F.id == src.id) + targets += F - for(var/obj/structure/closet/secure_closet/brig/C in world) - if(C.id == src.id) - targets += C + for(var/obj/structure/closet/secure_closet/brig/C in world) + if(C.id == src.id) + targets += C - if(targets.len==0) - stat |= BROKEN - update_icon() - return + if(targets.len==0) + stat |= BROKEN + update_icon() return + return //Main door timer loop, if it's timing and time is >0 reduce time by 1. // if it's less than 0, open door, reset timer // update the door_timer window and the icon - process() - if(stat & (NOPOWER|BROKEN)) return - if(src.timing) - if(world.time > src.releasetime) - src.timer_end() // open doors, reset timer, clear status screen - src.timing = 0 - src.updateUsrDialog() - src.update_icon() - else - timer_end() - return +/obj/machinery/door_timer/process() + + if(stat & (NOPOWER|BROKEN)) return + if(src.timing) + + // poorly done midnight rollover + // (no seriously there's gotta be a better way to do this) + var/timeleft = timeleft() + if(timeleft > 1e5) + src.releasetime = 0 -// has the door power sitatuation changed, if so update icon. - power_change() - ..() - update_icon() - return + if(world.timeofday > src.releasetime) + src.timer_end() // open doors, reset timer, clear status screen + src.timing = 0 + + src.updateUsrDialog() + src.update_icon() + + else + timer_end() + + return + + +// has the door power situation changed, if so update icon. +/obj/machinery/door_timer/power_change() + ..() + update_icon() + return // open/closedoor checks if door_timer has power, if so it checks if the // linked door is open/closed (by density) then opens it/closes it. - proc/timer_start() - if(stat & (NOPOWER|BROKEN)) return 0 - for(var/obj/machinery/door/window/brigdoor/door in targets) - if(door.density) continue - spawn(0) - door.close() +// Closes and locks doors, power check +/obj/machinery/door_timer/proc/timer_start() + if(stat & (NOPOWER|BROKEN)) return 0 - for(var/obj/structure/closet/secure_closet/brig/C in targets) - if(C.broken) continue - if(C.opened && !C.close()) continue - C.locked = 1 - C.icon_state = C.icon_locked - return 1 + // Set releasetime + releasetime = world.timeofday + timetoset + + for(var/obj/machinery/door/window/brigdoor/door in targets) + if(door.density) continue + spawn(0) + door.close() + + for(var/obj/structure/closet/secure_closet/brig/C in targets) + if(C.broken) continue + if(C.opened && !C.close()) continue + C.locked = 1 + C.icon_state = C.icon_locked + return 1 - proc/timer_end() - if(stat & (NOPOWER|BROKEN)) return 0 +// Opens and unlocks doors, power check +/obj/machinery/door_timer/proc/timer_end() + if(stat & (NOPOWER|BROKEN)) return 0 - for(var/obj/machinery/door/window/brigdoor/door in targets) - if(!door.density) continue - spawn(0) - door.open() + // Reset releasetime + releasetime = 0 - for(var/obj/structure/closet/secure_closet/brig/C in targets) - if(C.broken) continue - if(C.opened) continue - C.locked = 0 - C.icon_state = C.icon_closed + for(var/obj/machinery/door/window/brigdoor/door in targets) + if(!door.density) continue + spawn(0) + door.open() - return 1 + for(var/obj/structure/closet/secure_closet/brig/C in targets) + if(C.broken) continue + if(C.opened) continue + C.locked = 0 + C.icon_state = C.icon_closed + + return 1 - proc/timeleft() - . = (releasetime-world.time)/10 - if(. < 0) - . = 0 +// Check for releasetime timeleft +/obj/machinery/door_timer/proc/timeleft() + . = (releasetime - world.timeofday)/10 + if(. < 0) + . = 0 +// Set timetoset +/obj/machinery/door_timer/proc/timeset(var/seconds) + timetoset = seconds * 10 - proc/timeset(var/seconds) - releasetime=world.time+seconds*10 - return + if(timetoset <= 0) + timetoset = 0 + return //Allows AIs to use door_timer, see human attack_hand function below - attack_ai(var/mob/user as mob) - return src.attack_hand(user) +/obj/machinery/door_timer/attack_ai(var/mob/user as mob) + return src.attack_hand(user) //Allows humans to use door_timer //Opens dialog window when someone clicks on door timer // Allows altering timer and the timing boolean. // Flasher activation limited to 150 seconds - attack_hand(var/mob/user as mob) - if(..()) - return - var/second = round(timeleft() % 60) - var/minute = round((timeleft() - second) / 60) - user.set_machine(src) - var/dat = "" - dat += "
Timer System:" - dat += "Door [src.id] controls
" - if (src.timing) - dat += "Stop Timer and open door
" - else - dat += "Activate Timer and close door
" - - dat += "Time Left: [(minute ? text("[minute]:") : null)][second]
" - dat += "- - + +
" - - for(var/obj/machinery/flasher/F in targets) - if(F.last_flash && (F.last_flash + 150) > world.time) - dat += "
Flash Charging" - else - dat += "
Activate Flash" - - dat += "

Close" - dat += "
" - user << browse(dat, "window=computer;size=400x500") - onclose(user, "computer") +/obj/machinery/door_timer/attack_hand(var/mob/user as mob) + if(..()) return + // Used for the 'time left' display + var/second = round(timeleft() % 60) + var/minute = round((timeleft() - second) / 60) + + // Used for 'set timer' + var/setsecond = round((timetoset / 10) % 60) + var/setminute = round(((timetoset / 10) - setsecond) / 60) + + user.set_machine(src) + + // dat + var/dat = "" + + dat += "
Timer System:" + dat += " Door [src.id] controls
" + + // Start/Stop timer + if (src.timing) + dat += "Stop Timer and open door
" + else + dat += "Activate Timer and close door
" + + // Time Left display (uses releasetime) + dat += "Time Left: [(minute ? text("[minute]:") : null)][second]
" + dat += "
" + + // Set Timer display (uses timetoset) + if(src.timing) + dat += "Set Timer: [(setminute ? text("[setminute]:") : null)][setsecond] Set
" + else + dat += "Set Timer: [(setminute ? text("[setminute]:") : null)][setsecond]
" + + // Controls + dat += "- - + +
" + + // Mounted flash controls + for(var/obj/machinery/flasher/F in targets) + if(F.last_flash && (F.last_flash + 150) > world.time) + dat += "
Flash Charging" + else + dat += "
Activate Flash" + + dat += "

Close" + dat += "
" + + user << browse(dat, "window=computer;size=400x500") + onclose(user, "computer") + return + //Function for using door_timer dialog input, checks if user has permission // href_list to // "timing" turns on timer // "tp" value to modify timer // "fc" activates flasher +// "change" resets the timer to the timetoset amount while the timer is counting down // Also updates dialog window and timer icon - Topic(href, href_list) - if(..()) - return - if(!src.allowed(usr)) - return +/obj/machinery/door_timer/Topic(href, href_list) + if(..()) + return + if(!src.allowed(usr)) + return + + usr.set_machine(src) + + if(href_list["timing"]) + src.timing = text2num(href_list["timing"]) - usr.set_machine(src) - if(href_list["timing"]) - src.timing = text2num(href_list["timing"]) - else - if(href_list["tp"]) //adjust timer, close door if not already closed - var/tp = text2num(href_list["tp"]) - var/timeleft = timeleft() - timeleft += tp - timeleft = min(max(round(timeleft), 0), 3600) - timeset(timeleft) - //src.timing = 1 - //src.closedoor() - if(href_list["fc"]) - for(var/obj/machinery/flasher/F in targets) - F.flash() - src.add_fingerprint(usr) - src.updateUsrDialog() - src.update_icon() if(src.timing) src.timer_start() else src.timer_end() - return + + else + if(href_list["tp"]) //adjust timer, close door if not already closed + var/tp = text2num(href_list["tp"]) + var/addtime = (timetoset / 10) + addtime += tp + addtime = min(max(round(addtime), 0), 3600) + + timeset(addtime) + + if(href_list["fc"]) + for(var/obj/machinery/flasher/F in targets) + F.flash() + + if(href_list["change"]) + src.timer_start() + + src.add_fingerprint(usr) + src.updateUsrDialog() + src.update_icon() + + /* if(src.timing) + src.timer_start() + + else + src.timer_end() */ + + return //icon update function // if NOPOWER, display blank // if BROKEN, display blue screen of death icon AI uses // if timing=true, run update display function - update_icon() - if(stat & (NOPOWER)) - icon_state = "frame" - return - if(stat & (BROKEN)) - set_picture("ai_bsod") - return - if(src.timing) - var/disp1 = uppertext(id) - var/timeleft = timeleft() - var/disp2 = "[add_zero(num2text((timeleft / 60) % 60),2)]~[add_zero(num2text(timeleft % 60), 2)]" - spawn( 5 ) - update_display(disp1, disp2) - else - update_display("SET","TIME") +/obj/machinery/door_timer/update_icon() + if(stat & (NOPOWER)) + icon_state = "frame" return + if(stat & (BROKEN)) + set_picture("ai_bsod") + return + if(src.timing) + var/disp1 = uppertext(id) + var/timeleft = timeleft() + var/disp2 = "[add_zero(num2text((timeleft / 60) % 60),2)]~[add_zero(num2text(timeleft % 60), 2)]" + spawn( 5 ) + update_display(disp1, disp2) + else + update_display("SET","TIME") + return // Adds an icon in case the screen is broken/off, stolen from status_display.dm - proc/set_picture(var/state) - picture_state = state - overlays.Cut() - overlays += image('icons/obj/status_display.dmi', icon_state=picture_state) +/obj/machinery/door_timer/proc/set_picture(var/state) + picture_state = state + overlays.Cut() + overlays += image('icons/obj/status_display.dmi', icon_state=picture_state) //Checks to see if there's 1 line or 2, adds text-icons-numbers/letters over display // Stolen from status_display - proc/update_display(var/line1, var/line2) - if(line2 == null) // single line display - overlays.Cut() - overlays += texticon(line1, 23, -13) - else // dual line display - overlays.Cut() - overlays += texticon(line1, 23, -9) - overlays += texticon(line2, 23, -17) +/obj/machinery/door_timer/proc/update_display(var/line1, var/line2) + if(line2 == null) // single line display + overlays.Cut() + overlays += texticon(line1, 23, -13) + else // dual line display + overlays.Cut() + overlays += texticon(line1, 23, -9) + overlays += texticon(line2, 23, -17) // return an icon of a time text string (tn) // valid characters are 0-9 and : // px, py are pixel offsets @@ -240,19 +305,19 @@ //Actual string input to icon display for loop, with 5 pixel x offsets for each letter. //Stolen from status_display - proc/texticon(var/tn, var/px = 0, var/py = 0) - var/image/I = image('icons/obj/status_display.dmi', "blank") - var/len = lentext(tn) +/obj/machinery/door_timer/proc/texticon(var/tn, var/px = 0, var/py = 0) + var/image/I = image('icons/obj/status_display.dmi', "blank") + var/len = lentext(tn) - for(var/d = 1 to len) - var/char = copytext(tn, len-d+1, len-d+2) - if(char == " ") - continue - var/image/ID = image('icons/obj/status_display.dmi', icon_state=char) - ID.pixel_x = -(d-1)*5 + px - ID.pixel_y = py - I.overlays += ID - return I + for(var/d = 1 to len) + var/char = copytext(tn, len-d+1, len-d+2) + if(char == " ") + continue + var/image/ID = image('icons/obj/status_display.dmi', icon_state=char) + ID.pixel_x = -(d-1)*5 + px + ID.pixel_y = py + I.overlays += ID + return I /obj/machinery/door_timer/cell_1 diff --git a/code/game/machinery/hydroponics.dm b/code/game/machinery/hydroponics.dm index 5d187b337c7..a0f8c371e41 100644 --- a/code/game/machinery/hydroponics.dm +++ b/code/game/machinery/hydroponics.dm @@ -915,115 +915,13 @@ obj/machinery/hydroponics/attackby(var/obj/item/O as obj, var/mob/user as mob) parent.update_tray() -/obj/item/seeds/replicapod/harvest(mob/user = usr) //now that one is fun -- Urist - var/obj/machinery/hydroponics/parent = loc - var/make_podman = 0 - var/mob/ghost - if(ckey && config.revival_pod_plants) - ghost = find_dead_player("[ckey]") - if(ismob(ghost)) - if(istype(ghost,/mob/dead/observer)) - var/mob/dead/observer/O = ghost - if(istype(mind,/datum/mind)) - if(O.can_reenter_corpse) - make_podman = 1 - else - make_podman = 1 - - if(make_podman) //all conditions met! - var/mob/living/carbon/human/podman = new /mob/living/carbon/human(parent.loc) - if(realName) - podman.real_name = realName - else - podman.real_name = "Pod Person [rand(0,999)]" - var/oldactive = mind.active - mind.active = 1 - mind.transfer_to(podman) - mind.active = oldactive - // -- Mode/mind specific stuff goes here. TODO! Broken :( Should be merged into mob/living/Login - switch(ticker.mode.name) - if ("revolution") - if (podman.mind in ticker.mode:revolutionaries) - ticker.mode:add_revolutionary(podman.mind) - ticker.mode:update_all_rev_icons() //So the icon actually appears - if (podman.mind in ticker.mode:head_revolutionaries) - ticker.mode:update_all_rev_icons() - if ("nuclear emergency") - if (podman.mind in ticker.mode:syndicates) - ticker.mode:update_all_synd_icons() - if ("cult") - if (podman.mind in ticker.mode:cult) - ticker.mode:add_cultist(podman.mind) - ticker.mode:update_all_cult_icons() //So the icon actually appears - - // -- End mode specific stuff - - podman.gender = ghost.gender - if(podman.gender in list(NEUTER, PLURAL)) //Sanity check, which should never actually happen. - podman.gender = pick(MALE,FEMALE) - - if(!podman.dna) - podman.dna = new /datum/dna() - podman.dna.real_name = podman.real_name - if(ui) - podman.dna.uni_identity = ui - updateappearance(podman, ui) - if(se) - podman.dna.struc_enzymes = se - if(!prob(potency)) //if it fails, plantman! - if(podman) -// podman.dna.mutantrace = "plant" - podman.mutations.Add(PLANT) - podman.update_mutantrace() - - else //else, one packet of seeds. maybe two - var/seed_count = 1 - if(prob(yield * parent.yieldmod * 20)) - seed_count++ - for(var/i=0,iYour blood has been placed into a replica pod seed. Return to your body if you want to be returned to life as a pod person! (Verbs -> Ghost -> Re-enter corpse)" + break + else + user << "Nothing happens." + return + + if (!istype(source)) + return + + if(source.ckey) + realName = source.real_name + ckey = source.ckey + + W:reagents.clear_reagents() + return + + return ..() + +/obj/item/seeds/replicapod/harvest(mob/user = usr) + + var/obj/machinery/hydroponics/parent = loc + var/mob/ghost + var/list/candidates = list() + + user.visible_message("\blue You carefully begin to open the pod...","[user] carefully begins to open the pod...") + + //If a sample is injected (and revival is allowed) the plant will be controlled by the original donor. + if(source && source.mind && source.ckey && config.revival_pod_plants) + ghost = source + else // If no sample was injected or revival is not allowed, we grab an interested observer. + for(var/mob/dead/observer/O in player_list) + if(O.client) + var/response = alert(O, "Someone is harvesting a replica pod. Would you like to play as a Dionaea?", "Replica pod harvest", "Yes", "No") + if(response == "Yes") + candidates += O + + if(!do_after(user, 100)) + return + + if(!src || !user) + return + + if(candidates.len) + ghost = pick(candidates) + + //If we don't have a ghost or the ghost is now unplayed, we just give the harvester some seeds. + if(!ghost || !(ghost.ckey)) + user << "The pod has formed badly, and all you can do is salvage some of the seeds." + var/seed_count = 1 + + if(prob(yield * parent.yieldmod * 20)) + seed_count++ + + for(var/i=0,iYou awaken slowly, feeling your sap stir into sluggish motion as the warm air caresses your bark." + if(source && ckey && podman.ckey == ckey) + podman << "Memories of a life as [source] drift oddly through a mind unsuited for them, like a skin of oil over a fathomless lake." + podman << "You are now one of the Dionaea, a race of drifting interstellar plantlike creatures that sometimes share their seeds with human traders." + podman << "Too much darkness will send you into shock and starve you, but light will help you heal." + + if(!realName) + var/newname = input(podman,"Enter a name, or leave blank for the default name.", "Name change","") as text + if (newname != "") + podman.real_name = newname + parent.update_tray() \ No newline at end of file diff --git a/code/game/machinery/telecomms/broadcaster.dm b/code/game/machinery/telecomms/broadcaster.dm index 4ab483076b7..7302ed81b6c 100644 --- a/code/game/machinery/telecomms/broadcaster.dm +++ b/code/game/machinery/telecomms/broadcaster.dm @@ -341,12 +341,10 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept freq_text = "Engineering" if(1359) freq_text = "Security" -// if(1349) -// freq_text = "Mining" if(1347) freq_text = "Supply" if(1441) - freq_text = "Death Squad" + freq_text = "Special Ops" if(1443) freq_text = "Response Team" //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO @@ -365,10 +363,35 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept var/part_b = " \icon[radio]\[[freq_text]\][part_b_extra] " // Tweaked for security headsets -- TLE var/part_c = "" - if (display_freq==SYND_FREQ) + // syndies! + if (display_freq == SYND_FREQ) part_a = "" - else if (display_freq==COMM_FREQ) + + // centcomm channels (deathsquid and ert) + else if (display_freq in CENT_FREQS) + part_a = "" + + // command channel + else if (display_freq == COMM_FREQ) part_a = "" + + // department radio formatting (poorly optimized, ugh) + else if (display_freq == SEC_FREQ) + part_a = "" + + else if (display_freq == ENG_FREQ) + part_a = "" + + else if (display_freq == SCI_FREQ) + part_a = "" + + else if (display_freq == MED_FREQ) + part_a = "" + + else if (display_freq == SUP_FREQ) // cargo + part_a = "" + + // If all else fails and it's a dept_freq, color me purple! else if (display_freq in DEPT_FREQS) part_a = "" @@ -406,8 +429,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept blackbox.msg_deathsquad += blackbox_msg if(1213) blackbox.msg_syndicate += blackbox_msg -// if(1349) -// blackbox.msg_mining += blackbox_msg if(1347) blackbox.msg_cargo += blackbox_msg else @@ -629,8 +650,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept freq_text = "Engineering" if(1359) freq_text = "Security" -// if(1349) -// freq_text = "Mining" if(1347) freq_text = "Supply" //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO @@ -685,8 +704,6 @@ var/message_delay = 0 // To make sure restarting the recentmessages list is kept blackbox.msg_deathsquad += blackbox_msg if(1213) blackbox.msg_syndicate += blackbox_msg -// if(1349) -// blackbox.msg_mining += blackbox_msg if(1347) blackbox.msg_cargo += blackbox_msg else diff --git a/code/game/machinery/telecomms/presets.dm b/code/game/machinery/telecomms/presets.dm index 2b708ded291..914bd8c9016 100644 --- a/code/game/machinery/telecomms/presets.dm +++ b/code/game/machinery/telecomms/presets.dm @@ -142,12 +142,7 @@ id = "Supply Server" freq_listening = list(1347) autolinkers = list("supply") -/* -/obj/machinery/telecomms/server/presets/mining - id = "Mining Server" - freq_listening = list(1349) - autolinkers = list("mining") -*/ + /obj/machinery/telecomms/server/presets/common id = "Common Server" freq_listening = list() diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm index d98d57de30b..5e33df7f56f 100644 --- a/code/game/machinery/vending.dm +++ b/code/game/machinery/vending.dm @@ -707,7 +707,8 @@ products = list(/obj/item/weapon/reagent_containers/glass/bottle/antitoxin = 4,/obj/item/weapon/reagent_containers/glass/bottle/inaprovaline = 4, /obj/item/weapon/reagent_containers/glass/bottle/stoxin = 4,/obj/item/weapon/reagent_containers/glass/bottle/toxin = 4, /obj/item/weapon/reagent_containers/syringe/antiviral = 4,/obj/item/weapon/reagent_containers/syringe = 12, - /obj/item/device/healthanalyzer = 5,/obj/item/weapon/reagent_containers/glass/beaker = 4, /obj/item/weapon/reagent_containers/dropper = 2) + /obj/item/device/healthanalyzer = 5,/obj/item/weapon/reagent_containers/glass/beaker = 4, /obj/item/weapon/reagent_containers/dropper = 2, + /obj/item/stack/medical/advanced/bruise_pack = 3, /obj/item/stack/medical/advanced/ointment = 3, /obj/item/stack/medical/splint = 2) contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3,/obj/item/weapon/reagent_containers/pill/stox = 4,/obj/item/weapon/reagent_containers/pill/antitox = 6) @@ -727,7 +728,7 @@ icon_deny = "wallmed-deny" req_access_txt = "5" density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude - products = list(/obj/item/stack/medical/bruise_pack = 2,/obj/item/stack/medical/ointment = 2,/obj/item/weapon/reagent_containers/syringe/inaprovaline = 4,/obj/item/device/healthanalyzer = 1) + products = list(/obj/item/stack/medical/bruise_pack = 2,/obj/item/stack/medical/ointment = 2,/obj/item/weapon/reagent_containers/hypospray/autoinjector = 4,/obj/item/device/healthanalyzer = 1) contraband = list(/obj/item/weapon/reagent_containers/syringe/antitoxin = 4,/obj/item/weapon/reagent_containers/syringe/antiviral = 4,/obj/item/weapon/reagent_containers/pill/tox = 1) /obj/machinery/vending/wallmed2 @@ -737,7 +738,7 @@ icon_deny = "wallmed-deny" req_access_txt = "5" density = 0 //It is wall-mounted, and thus, not dense. --Superxpdude - products = list(/obj/item/weapon/reagent_containers/syringe/inaprovaline = 5,/obj/item/weapon/reagent_containers/syringe/antitoxin = 3,/obj/item/stack/medical/bruise_pack = 3, + products = list(/obj/item/weapon/reagent_containers/hypospray/autoinjector = 5,/obj/item/weapon/reagent_containers/syringe/antitoxin = 3,/obj/item/stack/medical/bruise_pack = 3, /obj/item/stack/medical/ointment =3,/obj/item/device/healthanalyzer = 3) contraband = list(/obj/item/weapon/reagent_containers/pill/tox = 3) diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm index 9ff9c68a5c3..c877084339b 100644 --- a/code/game/mecha/equipment/tools/tools.dm +++ b/code/game/mecha/equipment/tools/tools.dm @@ -484,6 +484,7 @@ return "[..()] [mode==1?"([locked||"Nothing"])":null] \[S|P\]" Topic(href, href_list) + ..() if(href_list["mode"]) mode = text2num(href_list["mode"]) send_byjax(chassis.occupant,"exosuit.browser","\ref[src]",src.get_equip_info()) diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm index 5bf46648228..7b72a5597bf 100644 --- a/code/game/mecha/mech_fabricator.dm +++ b/code/game/mecha/mech_fabricator.dm @@ -49,7 +49,8 @@ /obj/item/robot_parts/robot_component/radio, /obj/item/robot_parts/robot_component/actuator, /obj/item/robot_parts/robot_component/diagnosis_unit, - /obj/item/robot_parts/robot_component/camera + /obj/item/robot_parts/robot_component/camera, + /obj/item/robot_parts/robot_component/armour ), "Ripley"=list( /obj/item/mecha_parts/chassis/ripley, diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index c55684eb197..281c23f0fd0 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -131,8 +131,7 @@ else if(isliving(src.loc)) return - user.lastDblClick = world.time + 2 - user.next_move = world.time + 2 + user.delay_click(2) src.pickup(user) add_fingerprint(user) user.put_in_active_hand(src) @@ -166,8 +165,7 @@ if(istype(src.loc, /mob/living)) return src.pickup(user) - user.lastDblClick = world.time + 2 - user.next_move = world.time + 2 + user.delay_click(2) user.put_in_active_hand(src) return @@ -229,6 +227,8 @@ log_attack("[user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)]) (DAMTYE: [uppertext(src.damtype)])" ) msg_admin_attack("ATTACK: [user.name] ([user.ckey]) attacked [M.name] ([M.ckey]) with [src.name] (INTENT: [uppertext(user.a_intent)])") //BS12 EDIT ALG + user.delay_click(10) + //spawn(1800) // this wont work right // M.lastattacker = null ///////////////////////// diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm new file mode 100644 index 00000000000..da297fbb55b --- /dev/null +++ b/code/game/objects/items/devices/pipe_painter.dm @@ -0,0 +1,22 @@ +/obj/item/device/pipe_painter + name = "pipe painter" + icon = 'icons/obj/bureaucracy.dmi' + icon_state = "labeler1" + item_state = "flight" + var/list/modes = list("grey","red","blue","cyan","green","yellow","purple") + var/mode = "grey" + +/obj/item/device/pipe_painter/afterattack(atom/A, mob/user as mob) + if(!istype(A,/obj/machinery/atmospherics/pipe) || istype(A,/obj/machinery/atmospherics/pipe/tank) || istype(A,/obj/machinery/atmospherics/pipe/vent) || istype(A,/obj/machinery/atmospherics/pipe/simple/heat_exchanging) || istype(A,/obj/machinery/atmospherics/pipe/simple/insulated)) + return + var/obj/machinery/atmospherics/pipe/P = A + P.color = mode + user.visible_message("[user] paints \the [P] [mode].","You paint \the [P] [mode].") + P.update_icon() + +/obj/item/device/pipe_painter/attack_self(mob/user as mob) + mode = input("Which colour do you want to use?","Pipe painter") in modes + +/obj/item/device/pipe_painter/examine() + ..() + usr << "It is in [mode] mode." \ No newline at end of file diff --git a/code/game/objects/items/devices/radio/encryptionkey.dm b/code/game/objects/items/devices/radio/encryptionkey.dm index 165f6748ec5..d2d5417d6c3 100644 --- a/code/game/objects/items/devices/radio/encryptionkey.dm +++ b/code/game/objects/items/devices/radio/encryptionkey.dm @@ -121,7 +121,8 @@ desc = "An encyption key for a radio headset. Contains cypherkeys." icon_state = "cargo_cypherkey" channels = list("Supply" = 1) + /obj/item/device/encryptionkey/ert name = "NanoTrasen ERT Radio Encryption Key" desc = "An encyption key for a radio headset. Contains cypherkeys." - channels = list("Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Mining" = 1, "Cargo" = 1,) + channels = list("Response Team" = 1, "Science" = 1, "Command" = 1, "Medical" = 1, "Engineering" = 1, "Security" = 1, "Supply" = 1) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 0081954da84..422a27897c0 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -499,8 +499,6 @@ var/GLOBAL_RADIO_TYPE = 1 // radio type to use freq_text = "Engineering" if(1359) freq_text = "Security" -// if(1349) -// freq_text = "Mining" if(1347) freq_text = "Supply" //There's probably a way to use the list var of channels in code\game\communications.dm to make the dept channels non-hardcoded, but I wasn't in an experimentive mood. --NEO diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 6020cc834a2..7a76812b34e 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -32,6 +32,7 @@ R.icon_state = "robot" del(R.module) R.module = null + R.camera.network.Remove(list("Medical","MINE")) R.updatename("Default") R.status_flags |= CANPUSH R.updateicon() diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm index ca538c254e2..4721bcc8fe6 100644 --- a/code/game/objects/items/stacks/medical.dm +++ b/code/game/objects/items/stacks/medical.dm @@ -11,15 +11,6 @@ var/heal_burn = 0 /obj/item/stack/medical/attack(mob/living/carbon/M as mob, mob/user as mob) - if (M.stat == 2) - var/t_him = "it" - if (M.gender == MALE) - t_him = "him" - else if (M.gender == FEMALE) - t_him = "her" - user << "\red \The [M] is dead, you cannot help [t_him]!" - return 1 - if (!istype(M)) user << "\red \The [src] cannot be applied to [M]!" return 1 @@ -47,42 +38,16 @@ user << "\red This isn't useful at all on a robotic limb.." return 1 - if(src.heal_brute) - if(!affecting.bandage()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been bandaged." - return 1 - else - for (var/datum/wound/W in affecting.wounds) - if (W.internal) - continue - if (W.current_stage <= W.max_bleeding_stage) - user.visible_message( "\blue [user] bandages [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You bandage [W.desc] on [M]'s [affecting.display_name]." ) - //H.add_side_effect("Itch") - else if (istype(W,/datum/wound/bruise)) - user.visible_message( "\blue [user] places bruise patch over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You place bruise patch over [W.desc] on [M]'s [affecting.display_name]." ) - else - user.visible_message( "\blue [user] places bandaid over [W.desc] on [M]'s [affecting.display_name].", \ - "\blue You place bandaid over [W.desc] on [M]'s [affecting.display_name]." ) - - else if(src.heal_burn) - if(!affecting.salve()) - user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." - return 1 - else - user.visible_message( "\blue [user] salves wounds on [M]'s [affecting.display_name].", \ - "\blue You salve wounds on [M]'s [affecting.display_name]." ) - H.UpdateDamageIcon() + else + M.heal_organ_damage((src.heal_brute/2), (src.heal_burn/2)) user.visible_message( \ "\blue [M] has been applied with [src] by [user].", \ "\blue You apply \the [src] to [M]." \ ) - - use(1) + use(1) M.updatehealth() /obj/item/stack/medical/bruise_pack @@ -90,18 +55,60 @@ singular_name = "gauze length" desc = "Some sterile gauze to wrap around bloody stumps." icon_state = "brutepack" - heal_brute = 60 origin_tech = "biotech=1" +/obj/item/stack/medical/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + + if(!affecting.bandage()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been bandaged." + return 1 + else + for (var/datum/wound/W in affecting.wounds) + if (W.internal) + continue + if (W.current_stage <= W.max_bleeding_stage) + user.visible_message( "\blue [user] bandages [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You bandage [W.desc] on [M]'s [affecting.display_name]." ) + //H.add_side_effect("Itch") + else if (istype(W,/datum/wound/bruise)) + user.visible_message( "\blue [user] places bruise patch over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place bruise patch over [W.desc] on [M]'s [affecting.display_name]." ) + else + user.visible_message( "\blue [user] places bandaid over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place bandaid over [W.desc] on [M]'s [affecting.display_name]." ) + use(1) + /obj/item/stack/medical/ointment name = "ointment" desc = "Used to treat those nasty burns." gender = PLURAL singular_name = "ointment" icon_state = "ointment" - heal_burn = 40 + heal_burn = 1 origin_tech = "biotech=1" +/obj/item/stack/medical/ointment/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + + if(!affecting.salve()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." + return 1 + else + user.visible_message( "\blue [user] salves wounds on [M]'s [affecting.display_name].", \ + "\blue You salve wounds on [M]'s [affecting.display_name]." ) + use(1) + /obj/item/stack/medical/bruise_pack/tajaran name = "\improper S'rendarr's Hand leaf" singular_name = "S'rendarr's Hand leaf" @@ -126,6 +133,34 @@ heal_brute = 12 origin_tech = "biotech=1" +/obj/item/stack/medical/advanced/bruise_pack/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + + if(!affecting.bandage()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been treated." + return 1 + else + for (var/datum/wound/W in affecting.wounds) + if (W.internal) + continue + if (W.current_stage <= W.max_bleeding_stage) + user.visible_message( "\blue [user] cleans [W.desc] on [M]'s [affecting.display_name] and seals edges with bioglue.", \ + "\blue You clean and seal [W.desc] on [M]'s [affecting.display_name]." ) + //H.add_side_effect("Itch") + else if (istype(W,/datum/wound/bruise)) + user.visible_message( "\blue [user] places medicine patch over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You place medicine patch over [W.desc] on [M]'s [affecting.display_name]." ) + else + user.visible_message( "\blue [user] smears some bioglue over [W.desc] on [M]'s [affecting.display_name].", \ + "\blue You smear some bioglue over [W.desc] on [M]'s [affecting.display_name]." ) + affecting.heal_damage(heal_brute,0) + use(1) + /obj/item/stack/medical/advanced/ointment name = "advanced burn kit" singular_name = "advanced burn kit" @@ -134,8 +169,26 @@ heal_burn = 12 origin_tech = "biotech=1" + +/obj/item/stack/medical/advanced/ointment/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + + if(!affecting.salve()) + user << "\red The wounds on [M]'s [affecting.display_name] have already been salved." + return 1 + else + user.visible_message( "\blue [user] covers wounds on [M]'s [affecting.display_name] with regenerative membrane.", \ + "\blue You cover wounds on [M]'s [affecting.display_name] with regenerative membrane." ) + affecting.heal_damage(0,heal_burn) + use(1) + /obj/item/stack/medical/splint - name = "medical splint" + name = "medical splints" singular_name = "medical splint" icon_state = "splint" amount = 5 @@ -143,3 +196,38 @@ /obj/item/stack/medical/splint/single amount = 1 + + +/obj/item/stack/medical/splint/attack(mob/living/carbon/M as mob, mob/user as mob) + if(..()) + return 1 + + if (istype(M, /mob/living/carbon/human)) + var/mob/living/carbon/human/H = M + var/datum/organ/external/affecting = H.get_organ(user.zone_sel.selecting) + var/limb = affecting.display_name + if(!((affecting.name == "l_arm") || (affecting.name == "r_arm") || (affecting.name == "l_leg") || (affecting.name == "r_leg"))) + user << "\red You can't apply a splint there!" + return + if(affecting.status & ORGAN_SPLINTED) + user << "\red [M]'s [limb] is already splinted!" + return + if (M != user) + user.visible_message("\red [user] starts to apply \the [src] to [M]'s [limb].", "\red You start to apply \the [src] to [M]'s [limb].", "\red You hear something being wrapped.") + else + if((!user.hand && affecting.name == "r_arm") || (user.hand && affecting.name == "l_arm")) + user << "\red You can't apply a splint to the arm you're using!" + return + user.visible_message("\red [user] starts to apply \the [src] to their [limb].", "\red You start to apply \the [src] to your [limb].", "\red You hear something being wrapped.") + if(do_after(user, 50)) + if (M != user) + user.visible_message("\red [user] finishes applying \the [src] to [M]'s [limb].", "\red You finish applying \the [src] to [M]'s [limb].", "\red You hear something being wrapped.") + else + if(prob(25)) + user.visible_message("\red [user] successfully applies \the [src] to their [limb].", "\red You successfully apply \the [src] to your [limb].", "\red You hear something being wrapped.") + else + user.visible_message("\red [user] fumbles \the [src].", "\red You fumble \the [src].", "\red You hear something being wrapped.") + return + affecting.status |= ORGAN_SPLINTED + use(1) + return \ No newline at end of file diff --git a/code/game/objects/items/weapons/extinguisher.dm b/code/game/objects/items/weapons/extinguisher.dm index 77cf343de21..6a26f70e1f5 100644 --- a/code/game/objects/items/weapons/extinguisher.dm +++ b/code/game/objects/items/weapons/extinguisher.dm @@ -14,7 +14,6 @@ m_amt = 90 attack_verb = list("slammed", "whacked", "bashed", "thunked", "battered", "bludgeoned", "thrashed") var/max_water = 50 - var/last_use = 1.0 var/safety = 1 var/sprite_name = "fire_extinguisher" @@ -67,11 +66,6 @@ usr << "\red \The [src] is empty." return - if (world.time < src.last_use + 20) - return - - src.last_use = world.time - playsound(src.loc, 'sound/effects/extinguish.ogg', 75, 1, -3) var/direction = get_dir(src,target) diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm index 903bb1b1bf9..a0c3be517b1 100644 --- a/code/game/objects/items/weapons/implants/implant.dm +++ b/code/game/objects/items/weapons/implants/implant.dm @@ -461,3 +461,7 @@ the implant may become unstable and either pre-maturely inject the subject or si islegal() return 0 + +/obj/item/weapon/implant/cortical + name = "cortical stack" + desc = "A fist-sized mass of biocircuits and chips." \ No newline at end of file diff --git a/code/game/objects/items/weapons/manuals.dm b/code/game/objects/items/weapons/manuals.dm index f4b2a147620..cc2c284adce 100644 --- a/code/game/objects/items/weapons/manuals.dm +++ b/code/game/objects/items/weapons/manuals.dm @@ -12,7 +12,7 @@ icon_state ="bookEngineering" author = "Engineering Encyclopedia" // Who wrote the thing, can be changed by pen or PC. It is not automatically assigned title = "Station Repairs and Construction" - dat = {" + /*dat = {" @@ -23,7 +23,7 @@ - "} + "}*/ /obj/item/weapon/book/manual/engineering_particle_accelerator name = "Particle Accelerator User's Guide" @@ -32,7 +32,7 @@ title = "Particle Accelerator User's Guide" //big pile of shit below. - dat = {" + /*dat = {"