diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 77ed7f308e6..8c6befa38f8 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -398,4 +398,65 @@ datum/projectile_data var/r = mixOneColor(weights, reds) var/g = mixOneColor(weights, greens) var/b = mixOneColor(weights, blues) - return rgb(r,g,b) \ No newline at end of file + return rgb(r,g,b) + +/** +* Gets the highest and lowest pressures from the tiles in cardinal directions +* around us, then checks the difference. +*/ +/proc/getOPressureDifferential(var/turf/loc) + var/minp=16777216; + var/maxp=0; + for(var/dir in cardinal) + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/cp=0 + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + cp = environment.return_pressure() + else + if(istype(T,/turf/simulated)) + continue + if(cpmaxp)maxp=cp + return abs(minp-maxp) + +/proc/convert_k2c(var/temp) + return ((temp - T0C)) + +/proc/convert_c2k(var/temp) + return ((temp + T0C)) + +/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature")) + var/list/temps = new/list(4) + for(var/dir in cardinal) + var/direction + switch(dir) + if(NORTH) + direction = 1 + if(SOUTH) + direction = 2 + if(EAST) + direction = 3 + if(WEST) + direction = 4 + var/turf/simulated/T=get_turf(get_step(loc,dir)) + var/list/rstats = new /list(stats.len) + if(T && istype(T) && T.zone) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + else if(istype(T, /turf/simulated)) + rstats = null // Exclude zone (wall, door, etc). + else if(istype(T, /turf)) + // Should still work. (/turf/return_air()) + var/datum/gas_mixture/environment = T.return_air() + for(var/i=1;i<=stats.len;i++) + if(stats[i] == "pressure") + rstats[i] = environment.return_pressure() + else + rstats[i] = environment.vars[stats[i]] + temps[direction] = rstats + return temps diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm index 12f224ac527..c49da985df7 100644 --- a/code/game/machinery/doors/door.dm +++ b/code/game/machinery/doors/door.dm @@ -1,4 +1,6 @@ //This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31 +#define DOOR_OPEN_LAYER 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 +#define DOOR_CLOSED_LAYER 3.1 //Above most items if closed /obj/machinery/door name = "Door" @@ -8,7 +10,9 @@ anchored = 1 opacity = 1 density = 1 - layer = 2.7 + layer = DOOR_OPEN_LAYER + var/open_layer = DOOR_OPEN_LAYER + var/closed_layer = DOOR_CLOSED_LAYER var/secondsElectrified = 0 var/visible = 1 @@ -27,11 +31,11 @@ /obj/machinery/door/New() . = ..() if(density) - layer = 3.1 //Above most items if closed + layer = closed_layer explosion_resistance = initial(explosion_resistance) update_heat_protection(get_turf(src)) else - layer = 2.7 //Under all objects if opened. 2.7 due to tables being at 2.6 + layer = open_layer explosion_resistance = 0 @@ -226,7 +230,7 @@ icon_state = "door0" src.SetOpacity(0) sleep(10) - src.layer = 2.7 + src.layer = open_layer src.density = 0 explosion_resistance = 0 update_icon() @@ -250,10 +254,10 @@ if(operating > 0) return operating = 1 - do_animate("closing") src.density = 1 explosion_resistance = initial(explosion_resistance) - src.layer = 3.1 + src.layer = closed_layer + do_animate("closing") sleep(10) update_icon() if(visible && !glass) diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 40bc8d7e51d..299238e42e4 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -1,5 +1,15 @@ /var/const/OPEN = 1 /var/const/CLOSED = 2 + +#define FIREDOOR_MAX_PRESSURE_DIFF 25 // kPa +#define FIREDOOR_MAX_TEMP 50 // °C +#define FIREDOOR_MIN_TEMP 0 + +// Bitflags +#define FIREDOOR_ALERT_HOT 1 +#define FIREDOOR_ALERT_COLD 2 +// Not used #define FIREDOOR_ALERT_LOWPRESS 4 + /obj/machinery/door/firedoor name = "\improper Emergency Shutter" desc = "Emergency air-tight shutter, capable of sealing off breached areas." @@ -8,17 +18,33 @@ req_one_access = list(access_atmospherics, access_engine_equip) opacity = 0 density = 0 + layer = DOOR_OPEN_LAYER - 0.1 + open_layer = DOOR_OPEN_LAYER - 0.1 // Just below doors when open + closed_layer = DOOR_CLOSED_LAYER + 0.1 // Just above doors when closed var/blocked = 0 + var/lockdown = 0 // When the door has detected a problem, it locks. + var/pdiff_alert = 0 + var/pdiff = 0 var/nextstate = null var/net_id var/list/areas_added - var/list/users_to_open - + var/list/users_to_open = new + var/next_process_time = 0 + power_channel = ENVIRON use_power = 1 idle_power_usage = 5 + var/list/tile_info[4] + var/list/dir_alerts[4] // 4 dirs, bitflags + + // MUST be in same order as FIREDOOR_ALERT_* + var/list/ALERT_STATES=list( + "hot", + "cold" + ) + /obj/machinery/door/firedoor/New() . = ..() for(var/obj/machinery/door/firedoor/F in loc) @@ -38,7 +64,6 @@ A.all_doors.Add(src) areas_added += A - /obj/machinery/door/firedoor/Del() for(var/area/A in areas_added) A.all_doors.Remove(src) @@ -48,14 +73,47 @@ /obj/machinery/door/firedoor/examine() set src in view() . = ..() - if( islist(users_to_open) && users_to_open.len) + + if(get_dist(src, usr) > 1 && !isAI(usr)) + return + + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + usr << "WARNING: Current pressure differential is [pdiff]kPa! Opening door may result in injury!" + + usr << "Sensor readings:" + for(var/index = 1; index <= tile_info.len; index++) + var/o = "  " + switch(index) + if(1) + o += "NORTH: " + if(2) + o += "SOUTH: " + if(3) + o += "EAST: " + if(4) + o += "WEST: " + if(tile_info[index] == null) + o += "DATA UNAVAILABLE" + usr << o + continue + var/celsius = convert_k2c(tile_info[index][1]) + var/pressure = tile_info[index][2] + if(dir_alerts[index] & (FIREDOOR_ALERT_HOT|FIREDOOR_ALERT_COLD)) + o += "" + else + o += "" + o += "[celsius]°C " + o += "" + o += "[pressure]kPa" + usr << o + + if(islist(users_to_open) && users_to_open.len) var/users_to_open_string = users_to_open[1] if(users_to_open.len >= 2) for(var/i = 2 to users_to_open.len) users_to_open_string += ", [users_to_open[i]]" usr << "These people have opened \the [src] during an alert: [users_to_open_string]." - /obj/machinery/door/firedoor/Bumped(atom/AM) if(p_open || operating) return @@ -63,7 +121,7 @@ return ..() if(istype(AM, /obj/mecha)) var/obj/mecha/mecha = AM - if (mecha.occupant) + if(mecha.occupant) var/mob/M = mecha.occupant if(world.time - M.last_bumped <= 10) return //Can bump-open one airlock per second. This is to prevent popup message spam. M.last_bumped = world.time @@ -79,12 +137,7 @@ user << "\The [src] is welded solid!" return - if(!allowed(user)) - user << "Access denied." - return - - var/alarmed = 0 - + var/alarmed = lockdown for(var/area/A in areas_added) //Checks if there are fire alarms in any areas associated with that firedoor if(A.fire || A.air_doors_activated) alarmed = 1 @@ -100,9 +153,21 @@ user << "\The [src] is not functioning, you'll have to force it open manually." return + if(alarmed && density && lockdown && !allowed(user)) + user << "Access denied. Please wait for authorities to arrive, or for the alert to clear." + return + else + user.visible_message("\The [src] [density ? "open" : "close"]s for \the [user].",\ + "\The [src] [density ? "open" : "close"]s.",\ + "You hear a beep, and a door opening.") + var/needs_to_close = 0 if(density) if(alarmed) + // Accountability! + users_to_open |= user.name + log_admin("[user]([user.ckey]) has opened an alarming emergency shutter.") + message_admins("[user]([user.ckey]) has opened an alarming emergency shutter.") needs_to_close = 1 spawn() open() @@ -128,38 +193,37 @@ var/obj/item/weapon/weldingtool/W = C if(W.remove_fuel(0, user)) blocked = !blocked - user.visible_message("\red \The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ + user.visible_message("\The [user] [blocked ? "welds" : "unwelds"] \the [src] with \a [W].",\ "You [blocked ? "weld" : "unweld"] \the [src] with \the [W].",\ "You hear something being welded.") update_icon() return if(blocked) - user << "\red \The [src] is welded solid!" + user << "\The [src] is welded solid!" return - - if( istype(C, /obj/item/weapon/crowbar) || ( istype(C,/obj/item/weapon/twohanded/fireaxe) && C:wielded == 1 ) ) + if(istype(C, /obj/item/weapon/crowbar) || ( istype(C,/obj/item/weapon/twohanded/fireaxe) && C:wielded == 1)) if(operating) return - if( blocked && istype(C, /obj/item/weapon/crowbar) ) - user.visible_message("\red \The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ + if(blocked && istype(C, /obj/item/weapon/crowbar)) + user.visible_message("\The [user] pries at \the [src] with \a [C], but \the [src] is welded in place!",\ "You try to pry \the [src] [density ? "open" : "closed"], but it is welded in place!",\ "You hear someone struggle and metal straining.") return - user.visible_message("\red \The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ + user.visible_message("\The [user] starts to force \the [src] [density ? "open" : "closed"] with \a [C]!",\ "You start forcing \the [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain.") if(do_after(user,30)) - if( istype(C, /obj/item/weapon/crowbar) ) - if( stat & (BROKEN|NOPOWER) || !density) - user.visible_message("\red \The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ + if(istype(C, /obj/item/weapon/crowbar)) + if(stat & (BROKEN|NOPOWER) || !density) + user.visible_message("\The [user] forces \the [src] [density ? "open" : "closed"] with \a [C]!",\ "You force \the [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain, and a door [density ? "open" : "close"].") else - user.visible_message("\red \The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ + user.visible_message("\The [user] forces \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \a [C]!",\ "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [C]!",\ "You hear metal strain and groan, and a door [density ? "opening" : "closing"].") if(density) @@ -170,7 +234,50 @@ close() return +// CHECK PRESSURE +/obj/machinery/door/firedoor/process() + ..() + if(density && next_process_time <= world.time) + next_process_time = world.time + 100 // 10 second delays between process updates + var/changed = 0 + lockdown=0 + // Pressure alerts + pdiff = getOPressureDifferential(src.loc) + if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) + lockdown = 1 + if(!pdiff_alert) + pdiff_alert = 1 + changed = 1 // update_icon() + else + if(pdiff_alert) + pdiff_alert = 0 + changed = 1 // update_icon() + + tile_info = getCardinalAirInfo(src.loc,list("temperature","pressure")) + var/old_alerts = dir_alerts + for(var/index = 1; index <= 4; index++) + var/list/tileinfo=tile_info[index] + if(tileinfo==null) + continue // Bad data. + var/celsius = convert_k2c(tileinfo[1]) + + var/alerts=0 + + // Temperatures + if(celsius >= FIREDOOR_MAX_TEMP) + alerts |= FIREDOOR_ALERT_HOT + lockdown = 1 + else if(celsius <= FIREDOOR_MIN_TEMP) + alerts |= FIREDOOR_ALERT_COLD + lockdown = 1 + + dir_alerts[index]=alerts + + if(dir_alerts != old_alerts) + changed = 1 + if(changed) + update_icon() /obj/machinery/door/firedoor/proc/latetoggle() if(operating || !nextstate) @@ -178,6 +285,7 @@ switch(nextstate) if(OPEN) nextstate = null + open() if(CLOSED) nextstate = null @@ -189,15 +297,17 @@ return ..() /obj/machinery/door/firedoor/open(var/forced = 0) - if (!forced) - if (stat & (BROKEN|NOPOWER)) + if(!forced) + if(stat & (BROKEN|NOPOWER)) return //needs power to open unless it was forced else use_power(360) + else + log_admin("[usr]([usr.ckey]) has forced open an emergency shutter.") + message_admins("[usr]([usr.ckey]) has forced open an emergency shutter.") latetoggle() return ..() - /obj/machinery/door/firedoor/do_animate(animation) switch(animation) if("opening") @@ -213,6 +323,14 @@ icon_state = "door_closed" if(blocked) overlays += "welded" + if(pdiff_alert) + overlays += "palert" + if(dir_alerts) + for(var/d=1;d<=4;d++) + var/cdir = cardinal[d] + for(var/i=1;i<=ALERT_STATES.len;i++) + if(dir_alerts[d] & (1<<(i-1))) + overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir) else icon_state = "door_open" if(blocked) @@ -220,7 +338,6 @@ return - /obj/machinery/door/firedoor/border_only //These are playing merry hell on ZAS. Sorry fellas :( /* diff --git a/icons/obj/doors/DoorHazard.dmi b/icons/obj/doors/DoorHazard.dmi index 757c94f3270..594c65b44f9 100644 Binary files a/icons/obj/doors/DoorHazard.dmi and b/icons/obj/doors/DoorHazard.dmi differ