From 06c9c492df8bd13dfdd78d3006c4dbbc28a2a3aa Mon Sep 17 00:00:00 2001 From: Rob Nelson Date: Thu, 24 Jul 2014 01:26:24 -0700 Subject: [PATCH] Firelock rebalance, see changelog. Conflicts: code/game/machinery/doors/firedoor.dm html/changelog.html --- code/__HELPERS/mobs.dm | 12 + code/game/machinery/doors/firedoor.dm | 374 ++++++++++++-------------- icons/obj/doors/DoorHazard.dmi | Bin 5227 -> 5050 bytes 3 files changed, 188 insertions(+), 198 deletions(-) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index 5a120865893..e46f8ab7897 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -17,6 +17,18 @@ proc/random_hair_style(gender, species = "Human") return h_style +/proc/GetOppositeDir(var/dir) + switch(dir) + if(NORTH) return SOUTH + if(SOUTH) return NORTH + if(EAST) return WEST + if(WEST) return EAST + if(SOUTHWEST) return NORTHEAST + if(NORTHWEST) return SOUTHEAST + if(NORTHEAST) return SOUTHWEST + if(SOUTHEAST) return NORTHWEST + return 0 + proc/random_facial_hair_style(gender, species = "Human") var/f_style = "Shaved" diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm index 2aed445e38f..e358690afe0 100644 --- a/code/game/machinery/doors/firedoor.dm +++ b/code/game/machinery/doors/firedoor.dm @@ -1,41 +1,13 @@ /var/const/OPEN = 1 /var/const/CLOSED = 2 -#define NORTHCOLD 1 -#define NORTHHOT 2 -#define SOUTHCOLD 4 -#define SOUTHHOT 8 -#define WESTCOLD 32 -#define WESTHOT 64 -#define EASTCOLD 128 -#define EASTHOT 256 -/* HAHA TOPY PASTAN -/proc/getTemperatureDifferential(var/turf/loc) - var/mint=16777216; - var/maxt= 0; - for(var/dir in cardinal) - var/turf/simulated/T=get_turf(get_step(loc,dir)) - var/ct=0 - if(T && istype(T) && T.zone) - var/datum/gas_mixture/environment = T.return_air() - ct = environment.temperature - else - if(istype(T,/turf/simulated)) - continue - if(ctmaxt)maxt=ct - if(mint <= T20C - 20) - return convert_temperature(mint)-convert_temperature(maxt) - else - return convert_temperature(maxt)-convert_temperature(mint) -*/ /proc/convert_k2c(var/temp) return ((temp - T0C)) // * 1.8) + 32 /proc/convert_c2k(var/temp) return ((temp + T0C)) // * 1.8) + 32 -/proc/getCardinalTemperatures(var/turf/loc) +/proc/getCardinalAirInfo(var/turf/loc, var/list/stats=list("temperature")) var/list/temps = new/list(4) for(var/dir in cardinal) var/direction @@ -49,17 +21,29 @@ 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() - temps[direction] = environment.temperature - else - if(istype(T, /turf/simulated)) - temps[direction] = T20C - else - temps[direction] = 0 + for(var/i=1;i<=stats.len;i++) + 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++) + rstats[i] = environment.vars[stats[i]] + temps[direction] = rstats return temps #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" @@ -71,13 +55,21 @@ density = 0 var/blocked = 0 + var/lockdown = 0 // When the door has detected a problem, it locks. var/pdiff_alert = 0 var/pdiff = 0 - var/tdiff_alert = 0 var/nextstate = null var/net_id var/list/areas_added var/list/users_to_open + 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() . = ..() @@ -109,39 +101,35 @@ set src in view() . = ..() if(pdiff >= FIREDOOR_MAX_PRESSURE_DIFF) - usr << "WARNING: Current pressure differential is [pdiff]kPa!" - if(tdiff_alert) - var/alerts - var/list/temperatures = getCardinalTemperatures(src.loc) - for(var/index = 1; index <= temperatures.len; index++) - var/celsius = convert_k2c(temperatures[index]) - switch(index) - if(1) - alerts += "NORTH: " - if(celsius >= 50 || celsius <= 0) - alerts += "[celsius]" - else - alerts += "NORMAL" - if(2) - alerts += " SOUTH: " - if(celsius >= 50 || celsius <= 0) - alerts += "[celsius]" - else - alerts += "NORMAL" - if(3) - alerts += " EAST: " - if(celsius >= 50 || celsius <= 0) - alerts += "[celsius]" - else - alerts += "NORMAL" - if(4) - alerts += " WEST: " - if(celsius >= 50 || celsius <= 0) - alerts += "[celsius]" - else - alerts += "NORMAL" + 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 - usr << "WARNING: Current temperatures are, [alerts] " if( islist(users_to_open) && users_to_open.len) var/users_to_open_string = users_to_open[1] if(users_to_open.len >= 2) @@ -149,7 +137,6 @@ 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 @@ -174,47 +161,7 @@ /obj/machinery/door/firedoor/attack_hand(mob/user as mob) - add_fingerprint(user) - if(operating) - return//Already doing something. - - if(blocked) - user << "\The [src] is welded solid!" - return - - if(!allowed(user)) - user << "Access denied." - return - - var/area/A = get_area(src) - ASSERT(istype(A)) - if(A.master) - A = A.master - var/alarmed = A.air_doors_activated || A.fire - - var/answer = alert(user, "Would you like to [density ? "open" : "close"] this [src.name]?[ alarmed && density ? "\nNote that by doing so, you acknowledge any damages from opening this\n[src.name] as being your own fault, and you will be held accountable under the law." : ""]",\ - "\The [src]", "Yes, [density ? "open" : "close"]", "No") - if(answer == "No") - return - if(user.stat || !user.canmove || user.stunned || user.weakened || user.paralysis || get_dist(src, user) > 1) - user << "Sorry, you must remain able bodied and close to \the [src] in order to use it." - return - - var/needs_to_close = 0 - if(density) - if(alarmed) - needs_to_close = 1 - spawn() - open() - else - spawn() - close() - - if(needs_to_close) - spawn(50) - if(alarmed) - nextstate = CLOSED - + return attackby(null, user) /obj/machinery/door/firedoor/attackby(obj/item/weapon/C as obj, mob/user as mob) add_fingerprint(user) @@ -235,48 +182,102 @@ return var/area/A = get_area_master(src) - ASSERT(istype(A)) - if(A.master) - A = A.master - var/alarmed = A.air_doors_activated || A.fire + ASSERT(istype(A)) // This worries me. + var/alarmed = A.doors_down || A.fire 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) ) + if( blocked ) user.visible_message("\red \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]!",\ - "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]!",\ - "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]!",\ - "You force \the [ blocked ? "welded" : "" ] [src] [density ? "open" : "closed"] with \the [C]!",\ - "You hear metal strain and groan, and a door [density ? "open" : "close"].") - var/needs_to_close = 0 - if(density) - if(alarmed) - needs_to_close = 1 - spawn(0) - open() - else - spawn(0) - close() - if(needs_to_close) - spawn(50) - if(alarmed) - nextstate = CLOSED + if( stat & (BROKEN|NOPOWER) || !density || !alarmed ) + user.visible_message("\red \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 if( allowed(user) ) + user.visible_message("\blue \The [user] lifts \the [src] with \a [C].",\ + "\The [src] scans your ID, and obediently opens as you apply your [C].",\ + "You hear metal move, and a door [density ? "open" : "close"].") + else if(lockdown) + user.visible_message("\blue \The [user] pries at \the [src] with \a [C], but \the [src] resists being opened.",\ + "\red You pry at \the [src], but it actively resists your efforts. Maybe use your ID, perhaps?",\ + "You hear someone struggling and metal straining") return + if(density) + spawn(0) + open() + else + spawn(0) + close() + return + var/access_granted = 0 + var/users_name + if(!istype(C, /obj)) //If someone hit it with their hand. We need to see if they are allowed. + if(allowed(user)) + access_granted = 1 + if(ishuman(user)) + users_name = FindNameFromID(user) + else + users_name = "Unknown" + + if( ishuman(user) && !stat && ( istype(C, /obj/item/weapon/card/id) || istype(C, /obj/item/device/pda) ) ) + var/obj/item/weapon/card/id/ID = C + + if( istype(C, /obj/item/device/pda) ) + var/obj/item/device/pda/pda = C + ID = pda.id + if(!istype(ID)) + ID = null + + if(ID) + users_name = ID.registered_name + + if(check_access(ID)) + access_granted = 1 + + var/answer = "Yes" + if(answer == "No") + return + if(user.stat || user.stunned || user.weakened || user.paralysis || get_dist(src, user) > 1) + user << "Sorry, you must remain able bodied and close to \the [src] in order to use it." + return + + if(alarmed && density && lockdown && !access_granted/* && !( users_name in users_to_open ) */) + // Too many shitters on /vg/ for the honor system to work. + user << "Access denied. Please wait for authorities to arrive, or for the alert to clear." + return + // End anti-shitter system + /* + user.visible_message("\red \The [src] opens for \the [user]",\ + "\The [src] opens after you acknowledge the consequences.",\ + "You hear a beep, and a door opening.") + */ + else + user.visible_message("\blue \The [src] [density ? "open" : "close"]s for \the [user].",\ + "\The [src] [density ? "open" : "close"]s.",\ + "You hear a beep, and a door opening.") + // Accountability! + if(!users_to_open) + users_to_open = list() + users_to_open += users_name + + var/needs_to_close = 0 + if(density) + if(alarmed) + needs_to_close = 1 + spawn() + open() + else + spawn() + close() + + if(needs_to_close) + spawn(50) + if(alarmed) + nextstate = CLOSED @@ -285,11 +286,12 @@ ..() if(density) - pdiff = getOPressureDifferential(get_turf(src)) - - 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() @@ -297,33 +299,28 @@ if(pdiff_alert) pdiff_alert = 0 changed = 1 // update_icon() - var/list/temperatures = getCardinalTemperatures(src.loc) - var/oldtdiff = tdiff_alert - for(var/index = 1; index <= temperatures.len; index++) - var/celsius = convert_k2c(temperatures[index]) - switch(index) - if(1) - if(celsius >= 50) - tdiff_alert |= NORTHHOT - else if(celsius <= 0) - tdiff_alert |= NORTHCOLD - if(2) - if(celsius >= 50) - tdiff_alert |= SOUTHHOT - else if(celsius <= 0) - tdiff_alert |= SOUTHCOLD - if(3) - if(celsius >= 50) - tdiff_alert |= EASTHOT - else if(celsius <= 0) - tdiff_alert |= EASTCOLD - if(4) - if(celsius >= 50) - tdiff_alert |= WESTHOT - else if(celsius <= 0) - tdiff_alert |= WESTCOLD - if(oldtdiff != tdiff_alert) + 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() @@ -369,23 +366,13 @@ overlays += "welded" if(pdiff_alert) overlays += "palert" - if(tdiff_alert) - if(tdiff_alert & NORTHCOLD) - overlays += "calert_north" - if(tdiff_alert & NORTHHOT) - overlays += "halert_north" - if(tdiff_alert & SOUTHCOLD) - overlays += "calert_south" - if(tdiff_alert & SOUTHHOT) - overlays += "halert_south" - if(tdiff_alert & WESTCOLD) - overlays += "calert_west" - if(tdiff_alert & WESTHOT) - overlays += "halert_west" - if(tdiff_alert & EASTCOLD) - overlays += "calert_east" - if(tdiff_alert & EASTHOT) - overlays += "halert_east" + if(dir_alerts) + for(var/d=1;d<=4;d++) + var/cdir = cardinal[d] + // Loop while i = [1, 3], incrementing each loop + for(var/i=1;i<=ALERT_STATES.len;i++) // + if(dir_alerts[d] & (1<<(i-1))) // Check to see if dir_alerts[d] has the i-1th bit set. + overlays += new /icon(icon,"alert_[ALERT_STATES[i]]",dir=cdir) else icon_state = "door_open" if(blocked) @@ -445,12 +432,3 @@ //used in the AStar algorithm to determinate if the turf the door is on is passable /obj/machinery/door/firedoor/CanAStarPass() return !density - -#undef NORTHCOLD -#undef NORTHHOT -#undef SOUTHCOLD -#undef SOUTHHOT -#undef WESTCOLD -#undef WESTHOT -#undef EASTCOLD -#undef EASTHOT diff --git a/icons/obj/doors/DoorHazard.dmi b/icons/obj/doors/DoorHazard.dmi index 085efacb4a0d2ee2b564abdf0e3c327f4dbb8470..59ce0b2adcaa8dd0c9de0e777b795b35d31a1653 100644 GIT binary patch literal 5050 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 C09w!h