diff --git a/code/__DEFINES/machines.dm b/code/__DEFINES/machines.dm index 8bdfe4a79bf..569fe5a0629 100644 --- a/code/__DEFINES/machines.dm +++ b/code/__DEFINES/machines.dm @@ -7,15 +7,20 @@ #define AREA_USAGE_STATIC_LIGHT 5 #define AREA_USAGE_STATIC_ENVIRON 6 #define AREA_USAGE_LEN AREA_USAGE_STATIC_ENVIRON // largest idx + /// Index of the first dynamic usage channel #define AREA_USAGE_DYNAMIC_START AREA_USAGE_EQUIP /// Index of the last dynamic usage channel #define AREA_USAGE_DYNAMIC_END AREA_USAGE_ENVIRON + /// Index of the first static usage channel #define AREA_USAGE_STATIC_START AREA_USAGE_STATIC_EQUIP /// Index of the last static usage channel #define AREA_USAGE_STATIC_END AREA_USAGE_STATIC_ENVIRON +#define DYNAMIC_TO_STATIC_CHANNEL(dyn_channel) (dyn_channel + (AREA_USAGE_STATIC_START - AREA_USAGE_DYNAMIC_START)) +#define STATIC_TO_DYNAMIC_CHANNEL(static_channel) (static_channel - (AREA_USAGE_STATIC_START - AREA_USAGE_DYNAMIC_START)) + //Power use #define NO_POWER_USE 0 @@ -196,3 +201,12 @@ #define AIRALARM_BUILD_NO_WIRES 1 /// Air alarm has all components but isn't completed #define AIRALARM_BUILD_COMPLETE 2 + +///TLV datums wont check limits set to this +#define TLV_DONT_CHECK -1 +///the gas mixture is within the bounds of both warning and hazard limits +#define TLV_NO_DANGER 0 +///the gas value is outside the warning limit but within the hazard limit, the air alarm will go into warning mode +#define TLV_OUTSIDE_WARNING_LIMIT 1 +///the gas is outside the hazard limit, the air alarm will go into hazard mode +#define TLV_OUTSIDE_HAZARD_LIMIT 2 diff --git a/code/controllers/subsystem/machines.dm b/code/controllers/subsystem/machines.dm index dd17b86f633..8bf09c82e6a 100644 --- a/code/controllers/subsystem/machines.dm +++ b/code/controllers/subsystem/machines.dm @@ -13,25 +13,24 @@ SUBSYSTEM_DEF(machines) return ..() /datum/controller/subsystem/machines/proc/makepowernets() - for(var/datum/powernet/PN in powernets) - qdel(PN) + for(var/datum/powernet/power_network as anything in powernets) + qdel(power_network) powernets.Cut() - for(var/obj/structure/cable/PC in GLOB.cable_list) - if(!PC.powernet) - var/datum/powernet/NewPN = new() - NewPN.add_cable(PC) - propagate_network(PC,PC.powernet) + for(var/obj/structure/cable/power_cable as anything in GLOB.cable_list) + if(!power_cable.powernet) + var/datum/powernet/new_powernet = new() + new_powernet.add_cable(power_cable) + propagate_network(power_cable, power_cable.powernet) /datum/controller/subsystem/machines/stat_entry(msg) msg = "M:[length(processing)]|PN:[length(powernets)]" return ..() - /datum/controller/subsystem/machines/fire(resumed = FALSE) if (!resumed) - for(var/datum/powernet/Powernet in powernets) - Powernet.reset() //reset the power state. + for(var/datum/powernet/powernet as anything in powernets) + powernet.reset() //reset the power state. src.currentrun = processing.Copy() //cache for sanic speed (lists are references anyways) @@ -40,13 +39,9 @@ SUBSYSTEM_DEF(machines) while(currentrun.len) var/obj/machinery/thing = currentrun[currentrun.len] currentrun.len-- - if(!QDELETED(thing) && thing.process(wait * 0.1) != PROCESS_KILL) - if(thing.use_power) - thing.auto_use_power() //add back the power state - else + if(QDELETED(thing) || thing.process(wait * 0.1) == PROCESS_KILL) processing -= thing - if (!QDELETED(thing)) - thing.datum_flags &= ~DF_ISPROCESSING + thing.datum_flags &= ~DF_ISPROCESSING if (MC_TICK_CHECK) return diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm index f9e10d33bfc..f2e71841c5c 100644 --- a/code/game/area/areas.dm +++ b/code/game/area/areas.dm @@ -92,6 +92,9 @@ ///Used to decide what the maximum time between ambience is var/max_ambience_cooldown = 90 SECONDS + var/list/air_vent_info = list() + var/list/air_scrub_info = list() + /** * A list of teleport locations * @@ -432,8 +435,6 @@ GLOBAL_LIST_EMPTY(teleportlocs) * Updates the area icon, calls power change on all machinees in the area, and sends the `COMSIG_AREA_POWER_CHANGE` signal. */ /area/proc/power_change() - for(var/obj/machinery/M in src) // for each machine in the area - M.power_change() // reverify power status (to update icons etc.) SEND_SIGNAL(src, COMSIG_AREA_POWER_CHANGE) update_appearance() @@ -452,13 +453,28 @@ GLOBAL_LIST_EMPTY(teleportlocs) power_usage[powerchannel] += value /** - * Clear all power usage in area + * Remove a static amount of power load to an area * - * Clears all power used for equipment, light and environment channels + * Possible channels + * *AREA_USAGE_STATIC_EQUIP + * *AREA_USAGE_STATIC_LIGHT + * *AREA_USAGE_STATIC_ENVIRON + */ +/area/proc/removeStaticPower(value, powerchannel) + switch(powerchannel) + if(AREA_USAGE_STATIC_START to AREA_USAGE_STATIC_END) + power_usage[powerchannel] -= value + +/** + * Clear all non-static power usage in area + * + * Clears all power used for the dynamic equipment, light and environment channels */ /area/proc/clear_usage() - for(var/i in AREA_USAGE_DYNAMIC_START to AREA_USAGE_DYNAMIC_END) - power_usage[i] = 0 + power_usage[AREA_USAGE_EQUIP] = 0 + power_usage[AREA_USAGE_LIGHT] = 0 + power_usage[AREA_USAGE_ENVIRON] = 0 + /** * Add a power value amount to the stored used_x variables diff --git a/code/game/machinery/Beacon.dm b/code/game/machinery/Beacon.dm index 91415544261..ac48758be17 100644 --- a/code/game/machinery/Beacon.dm +++ b/code/game/machinery/Beacon.dm @@ -5,7 +5,7 @@ name = "bluespace gigabeacon" desc = "A device that draws power from bluespace and creates a permanent tracking beacon." layer = LOW_OBJ_LAYER - use_power = IDLE_POWER_USE + use_power = NO_POWER_USE idle_power_usage = 0 var/obj/item/beacon/Beacon diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 08b46ea40b5..a76a2c20f50 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -39,18 +39,22 @@ * EMPED -- temporary broken by EMP pulse * *Class Procs: - * Initialize() 'game/machinery/machine.dm' + * Initialize() * - * Destroy() 'game/machinery/machine.dm' + * Destroy() * - * auto_use_power() 'game/machinery/machine.dm' - * This proc determines how power mode power is deducted by the machine. - * 'auto_use_power()' is called by the 'master_controller' game_controller every - * tick. + * update_mode_power_usage() + * updates the static_power_usage var of this machine and makes its static power usage from its area accurate. + * called after the idle or active power usage has been changed. + * + * update_power_channel() + * updates the static_power_usage var of this machine and makes its static power usage from its area accurate. + * called after the power_channel var has been changed or called to change the var itself. + * + * unset_static_power() + * completely removes the current static power usage of this machine from its area. + * used in the other power updating procs to then readd the correct power usage. * - * Return Value: - * return:1 -- if object is powered - * return:0 -- if object is not powered. * * Default definition uses 'use_power', 'power_channel', 'active_power_usage', * 'idle_power_usage', 'powered()', and 'use_power()' implement behavior. @@ -99,11 +103,15 @@ var/machine_stat = NONE var/use_power = IDLE_POWER_USE - //0 = dont run the auto - //1 = run auto, use idle - //2 = run auto, use active + //0 = dont use power + //1 = use idle_power_usage + //2 = use active_power_usage + ///the amount of static power load this machine adds to its area's power_usage list when use_power = IDLE_POWER_USE var/idle_power_usage = 0 + ///the amount of static power load this machine adds to its area's power_usage list when use_power = ACTIVE_POWER_USE var/active_power_usage = 0 + ///the current amount of static power usage this machine is taking from its area + var/static_power_usage = 0 var/power_channel = AREA_USAGE_EQUIP //AREA_USAGE_EQUIP,AREA_USAGE_ENVIRON or AREA_USAGE_LIGHT ///A combination of factors such as having power, not being broken and so on. Boolean. @@ -154,6 +162,63 @@ return INITIALIZE_HINT_LATELOAD +/obj/machinery/LateInitialize() + . = ..() + power_change() + if(use_power == NO_POWER_USE) + return + + update_current_power_usage() + setup_area_power_relationship() + +/obj/machinery/Destroy() + GLOB.machines.Remove(src) + end_processing() + dump_inventory_contents() + QDEL_LIST(component_parts) + QDEL_NULL(circuit) + unset_static_power() + return ..() + +/** + * proc to call when the machine starts to require power after a duration of not requiring power + * sets up power related connections to its area if it exists and becomes area sensitive + * does not affect power usage itself + */ +/obj/machinery/proc/setup_area_power_relationship() + become_area_sensitive(INNATE_TRAIT) + + var/area/our_area = get_area(src) + if(our_area) + RegisterSignal(our_area, COMSIG_AREA_POWER_CHANGE, .proc/power_change) + RegisterSignal(src, COMSIG_ENTER_AREA, .proc/on_enter_area) + RegisterSignal(src, COMSIG_EXIT_AREA, .proc/on_exit_area) + +/** + * proc to call when the machine stops requiring power after a duration of requiring power + * saves memory by removing the power relationship with its area if it exists and loses area sensitivity + * does not affect power usage itself + */ +/obj/machinery/proc/remove_area_power_relationship() + var/area/our_area = get_area(src) + if(our_area) + UnregisterSignal(our_area, COMSIG_AREA_POWER_CHANGE) + + REMOVE_TRAIT(src, TRAIT_AREA_SENSITIVE, INNATE_TRAIT) + UnregisterSignal(src, COMSIG_ENTER_AREA) + UnregisterSignal(src, COMSIG_EXIT_AREA) + +/obj/machinery/proc/on_enter_area(datum/source, area/area_to_register) + SIGNAL_HANDLER + update_current_power_usage() + power_change() + RegisterSignal(area_to_register, COMSIG_AREA_POWER_CHANGE, .proc/power_change) + +/obj/machinery/proc/on_exit_area(datum/source, area/area_to_unregister) + SIGNAL_HANDLER + unset_static_power() + UnregisterSignal(area_to_unregister, COMSIG_AREA_POWER_CHANGE) + /obj/machinery/proc/set_occupant(atom/movable/new_occupant) SHOULD_CALL_PARENT(TRUE) @@ -170,20 +235,6 @@ var/datum/controller/subsystem/processing/subsystem = locate(subsystem_type) in Master.subsystems STOP_PROCESSING(subsystem, src) -/obj/machinery/LateInitialize() - . = ..() - power_change() - become_area_sensitive(ROUNDSTART_TRAIT) - RegisterSignal(src, COMSIG_ENTER_AREA, .proc/power_change) - -/obj/machinery/Destroy() - GLOB.machines.Remove(src) - end_processing() - dump_inventory_contents() - QDEL_LIST(component_parts) - QDEL_NULL(circuit) - return ..() - /obj/machinery/proc/locate_machinery() return @@ -315,15 +366,119 @@ updateUsrDialog() update_appearance() -/obj/machinery/proc/auto_use_power() - if(!powered(power_channel)) +///updates the use_power var for this machine and updates its static power usage from its area to reflect the new value +/obj/machinery/proc/update_use_power(new_use_power) + SHOULD_CALL_PARENT(TRUE) + if(new_use_power == use_power) return FALSE - if(use_power == IDLE_POWER_USE) - use_power(idle_power_usage,power_channel) - else if(use_power >= ACTIVE_POWER_USE) - use_power(active_power_usage,power_channel) + + unset_static_power() + + var/new_usage = 0 + switch(new_use_power) + if(IDLE_POWER_USE) + new_usage = idle_power_usage + if(ACTIVE_POWER_USE) + new_usage = active_power_usage + + if(use_power == NO_POWER_USE) + setup_area_power_relationship() + else if(new_use_power == NO_POWER_USE) + remove_area_power_relationship() + + static_power_usage = new_usage + + if(new_usage) + var/area/our_area = get_area(src) + our_area?.addStaticPower(new_usage, DYNAMIC_TO_STATIC_CHANNEL(power_channel)) + + use_power = new_use_power + return TRUE +///updates the power channel this machine uses. removes the static power usage from the old channel and readds it to the new channel +/obj/machinery/proc/update_power_channel(new_power_channel) + SHOULD_CALL_PARENT(TRUE) + if(new_power_channel == power_channel) + return FALSE + + var/usage = unset_static_power() + + var/area/our_area = get_area(src) + + if(our_area && usage) + our_area.addStaticPower(usage, DYNAMIC_TO_STATIC_CHANNEL(new_power_channel)) + + power_channel = new_power_channel + + return TRUE + +///internal proc that removes all static power usage from the current area +/obj/machinery/proc/unset_static_power() + SHOULD_NOT_OVERRIDE(TRUE) + var/old_usage = static_power_usage + + var/area/our_area = get_area(src) + + if(our_area && old_usage) + our_area.removeStaticPower(old_usage, DYNAMIC_TO_STATIC_CHANNEL(power_channel)) + static_power_usage = 0 + + return old_usage + +/** + * sets the power_usage linked to the specified use_power_mode to new_usage + * e.g. update_mode_power_usage(ACTIVE_POWER_USE, 10) sets active_power_use = 10 and updates its power draw from the machines area if use_power == ACTIVE_POWER_USE + * + * Arguments: + * * use_power_mode - the use_power power mode to change. if IDLE_POWER_USE changes idle_power_usage, ACTIVE_POWER_USE changes active_power_usage + * * new_usage - the new value to set the specified power mode var to + */ +/obj/machinery/proc/update_mode_power_usage(use_power_mode, new_usage) + SHOULD_CALL_PARENT(TRUE) + if(use_power_mode == NO_POWER_USE) + stack_trace("trying to set the power usage associated with NO_POWER_USE in update_mode_power_usage()!") + return FALSE + + unset_static_power() //completely remove our static_power_usage from our area, then readd new_usage + + switch(use_power_mode) + if(IDLE_POWER_USE) + idle_power_usage = new_usage + if(ACTIVE_POWER_USE) + active_power_usage = new_usage + + if(use_power_mode == use_power) + static_power_usage = new_usage + + var/area/our_area = get_area(src) + + if(our_area) + our_area.addStaticPower(static_power_usage, DYNAMIC_TO_STATIC_CHANNEL(power_channel)) + + return TRUE + +///makes this machine draw power from its area according to which use_power mode it is set to +/obj/machinery/proc/update_current_power_usage() + if(static_power_usage) + unset_static_power() + + var/area/our_area = get_area(src) + if(!our_area) + return FALSE + + switch(use_power) + if(IDLE_POWER_USE) + static_power_usage = idle_power_usage + if(ACTIVE_POWER_USE) + static_power_usage = active_power_usage + if(NO_POWER_USE) + return + + if(static_power_usage) + our_area.addStaticPower(static_power_usage, DYNAMIC_TO_STATIC_CHANNEL(power_channel)) + + return TRUE ///Called when we want to change the value of the `is_operational` variable. Boolean. /obj/machinery/proc/set_is_operational(new_value) diff --git a/code/game/machinery/dish_drive.dm b/code/game/machinery/dish_drive.dm index 4d1f200529e..97fdb00a17d 100644 --- a/code/game/machinery/dish_drive.dm +++ b/code/game/machinery/dish_drive.dm @@ -65,23 +65,20 @@ ..() /obj/machinery/dish_drive/RefreshParts() - idle_power_usage = initial(idle_power_usage) - active_power_usage = initial(active_power_usage) - use_power = initial(use_power) var/total_rating = 0 for(var/obj/item/stock_parts/S in component_parts) total_rating += S.rating if(total_rating >= 9) - active_power_usage = 0 - use_power = NO_POWER_USE + update_mode_power_usage(ACTIVE_POWER_USE, 0) else - idle_power_usage = max(0, idle_power_usage - total_rating) - active_power_usage = max(0, active_power_usage - total_rating) + update_mode_power_usage(IDLE_POWER_USE, max(0, initial(idle_power_usage) - total_rating)) + update_mode_power_usage(ACTIVE_POWER_USE, max(0, initial(active_power_usage) - total_rating)) var/obj/item/circuitboard/machine/dish_drive/board = locate() in component_parts if(board) suction_enabled = board.suction transmit_enabled = board.transmit + /obj/machinery/dish_drive/process() if(time_since_dishes <= world.time && transmit_enabled) do_the_dishes() diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 46356c33074..c03f7e5a046 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -402,12 +402,7 @@ Possible to do for anyone motivated enough: /obj/machinery/holopad/process() if(LAZYLEN(masters)) - for(var/I in masters) - var/mob/living/master = I - var/mob/living/silicon/ai/AI = master - if(!istype(AI)) - AI = null - + for(var/mob/living/master as anything in masters) if(!is_operational || !validate_user(master)) clear_holo(master) @@ -416,22 +411,23 @@ Possible to do for anyone motivated enough: ringing = FALSE - for(var/I in holo_calls) - var/datum/holocall/HC = I - if(HC.connected_holopad != src) - if(force_answer_call && world.time > (HC.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2))) - HC.Answer(src) - break - if(HC.head_call && !secure) - HC.Answer(src) - break - if(outgoing_call) - HC.Disconnect(src)//can't answer calls while calling - else - playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring! - ringing = TRUE + for(var/datum/holocall/holocall as anything in holo_calls) + if(holocall.connected_holopad == src) + continue - update_appearance() + if(force_answer_call && world.time > (holocall.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2))) + holocall.Answer(src) + break + if(holocall.head_call && !secure) + holocall.Answer(src) + break + if(outgoing_call) + holocall.Disconnect(src)//can't answer calls while calling + else + playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring! + ringing = TRUE + + update_appearance(UPDATE_ICON_STATE) /obj/machinery/holopad/proc/activate_holo(mob/living/user) var/mob/living/silicon/ai/AI = user @@ -495,8 +491,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ /obj/machinery/holopad/proc/SetLightsAndPower() var/total_users = LAZYLEN(masters) + LAZYLEN(holo_calls) - use_power = total_users > 0 ? ACTIVE_POWER_USE : IDLE_POWER_USE - active_power_usage = HOLOPAD_PASSIVE_POWER_USAGE + (HOLOGRAM_POWER_USAGE * total_users) + update_use_power(total_users > 0 ? ACTIVE_POWER_USE : IDLE_POWER_USE) + update_mode_power_usage(ACTIVE_POWER_USE, HOLOPAD_PASSIVE_POWER_USAGE + (HOLOGRAM_POWER_USAGE * total_users)) if(total_users || replay_mode) set_light(2) else diff --git a/code/game/machinery/launch_pad.dm b/code/game/machinery/launch_pad.dm index c799dfdf158..f393a8a1246 100644 --- a/code/game/machinery/launch_pad.dm +++ b/code/game/machinery/launch_pad.dm @@ -3,7 +3,7 @@ desc = "A bluespace pad able to thrust matter through bluespace, teleporting it to or from nearby locations." icon = 'icons/obj/telescience.dmi' icon_state = "lpad-idle" - use_power = TRUE + use_power = IDLE_POWER_USE idle_power_usage = 200 active_power_usage = 2500 hud_possible = list(DIAG_LAUNCHPAD_HUD) @@ -212,7 +212,7 @@ icon_state = "blpad-idle" icon_teleport = "blpad-beam" anchored = FALSE - use_power = FALSE + use_power = IDLE_POWER_USE idle_power_usage = 0 active_power_usage = 0 teleport_speed = 20 diff --git a/code/game/machinery/recharger.dm b/code/game/machinery/recharger.dm index cdcb73b40b3..800af0d2c39 100755 --- a/code/game/machinery/recharger.dm +++ b/code/game/machinery/recharger.dm @@ -47,12 +47,12 @@ charging = new_charging if (new_charging) START_PROCESSING(SSmachines, src) + update_use_power(ACTIVE_POWER_USE) finished_recharging = FALSE - use_power = ACTIVE_POWER_USE using_power = TRUE update_appearance() else - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) using_power = FALSE update_appearance() diff --git a/code/game/machinery/rechargestation.dm b/code/game/machinery/rechargestation.dm index 85f66a1d347..b9256914df3 100644 --- a/code/game/machinery/rechargestation.dm +++ b/code/game/machinery/rechargestation.dm @@ -90,12 +90,12 @@ /obj/machinery/recharge_station/open_machine() . = ..() - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) /obj/machinery/recharge_station/close_machine() . = ..() if(occupant) - use_power = ACTIVE_POWER_USE //It always tries to charge, even if it can't. + update_use_power(ACTIVE_POWER_USE) //It always tries to charge, even if it can't. add_fingerprint(occupant) /obj/machinery/recharge_station/update_icon_state() diff --git a/code/game/machinery/stasis.dm b/code/game/machinery/stasis.dm index 242859999df..218de35c9d1 100644 --- a/code/game/machinery/stasis.dm +++ b/code/game/machinery/stasis.dm @@ -108,13 +108,13 @@ target.apply_status_effect(STATUS_EFFECT_STASIS, STASIS_MACHINE_EFFECT) ADD_TRAIT(target, TRAIT_TUMOR_SUPPRESSED, TRAIT_GENERIC) target.extinguish_mob() - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) /obj/machinery/stasis/proc/thaw_them(mob/living/target) target.remove_status_effect(STATUS_EFFECT_STASIS, STASIS_MACHINE_EFFECT) REMOVE_TRAIT(target, TRAIT_TUMOR_SUPPRESSED, TRAIT_GENERIC) if(target == occupant) - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) /obj/machinery/stasis/post_buckle_mob(mob/living/L) if(!can_be_occupant(L)) @@ -131,8 +131,8 @@ update_appearance() /obj/machinery/stasis/process() - if( !( occupant && isliving(occupant) && check_nap_violations() ) ) - use_power = IDLE_POWER_USE + if(!(occupant && isliving(occupant) && check_nap_violations())) + update_use_power(IDLE_POWER_USE) return var/mob/living/L_occupant = occupant if(stasis_running()) diff --git a/code/modules/NTNet/relays.dm b/code/modules/NTNet/relays.dm index a586cef8e98..d2e0df46df5 100644 --- a/code/modules/NTNet/relays.dm +++ b/code/modules/NTNet/relays.dm @@ -63,10 +63,7 @@ return ..() /obj/machinery/ntnet_relay/process(delta_time) - if(is_operational) - use_power = ACTIVE_POWER_USE - else - use_power = IDLE_POWER_USE + update_use_power(is_operational ? ACTIVE_POWER_USE : IDLE_POWER_USE) update_appearance() diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm index 007e6eacdcc..2e5221e45a9 100644 --- a/code/modules/atmospherics/machinery/airalarm.dm +++ b/code/modules/atmospherics/machinery/airalarm.dm @@ -1,37 +1,43 @@ +// A datum for dealing with threshold limit values /datum/tlv - var/min2 - var/min1 - var/max1 - var/max2 + var/warning_min + var/warning_max + var/hazard_min + var/hazard_max /datum/tlv/New(min2 as num, min1 as num, max1 as num, max2 as num) - if(min2) src.min2 = min2 - if(min1) src.min1 = min1 - if(max1) src.max1 = max1 - if(max2) src.max2 = max2 + if(min2) + hazard_min = min2 + if(min1) + warning_min = min1 + if(max1) + warning_max = max1 + if(max2) + hazard_max = max2 -/datum/tlv/proc/get_danger_level(val as num) - if(max2 != -1 && val >= max2) - return 2 - if(min2 != -1 && val <= min2) - return 2 - if(max1 != -1 && val >= max1) - return 1 - if(min1 != -1 && val <= min1) - return 1 - return 0 +/datum/tlv/proc/get_danger_level(val) + if(hazard_max != TLV_DONT_CHECK && val >= hazard_max) + return TLV_OUTSIDE_HAZARD_LIMIT + if(hazard_min != TLV_DONT_CHECK && val <= hazard_min) + return TLV_OUTSIDE_HAZARD_LIMIT + if(warning_max != TLV_DONT_CHECK && val >= warning_max) + return TLV_OUTSIDE_WARNING_LIMIT + if(warning_min != TLV_DONT_CHECK && val <= warning_min) + return TLV_OUTSIDE_WARNING_LIMIT + + return TLV_NO_DANGER /datum/tlv/no_checks - min2 = -1 - min1 = -1 - max1 = -1 - max2 = -1 + hazard_min = TLV_DONT_CHECK + warning_min = TLV_DONT_CHECK + warning_max = TLV_DONT_CHECK + hazard_max = TLV_DONT_CHECK /datum/tlv/dangerous - min2 = -1 - min1 = -1 - max1 = 0.2 - max2 = 0.5 + hazard_min = TLV_DONT_CHECK + warning_min = TLV_DONT_CHECK + warning_max = 0.2 + hazard_max = 0.5 /obj/item/electronics/airalarm name = "air alarm electronics" @@ -85,8 +91,10 @@ ///Represents a signel source of atmos alarms, complains to all the listeners if one of our thresholds is violated var/datum/alarm_handler/alarm_manager + var/static/list/atmos_connections = list(COMSIG_TURF_EXPOSE = .proc/check_air_dangerlevel) + var/list/TLV = list( // Breathable air. - "pressure" = new/datum/tlv(HAZARD_LOW_PRESSURE, WARNING_LOW_PRESSURE, WARNING_HIGH_PRESSURE, HAZARD_HIGH_PRESSURE), // kPa. Values are min2, min1, max1, max2 + "pressure" = new/datum/tlv(HAZARD_LOW_PRESSURE, WARNING_LOW_PRESSURE, WARNING_HIGH_PRESSURE, HAZARD_HIGH_PRESSURE), // kPa. Values are hazard_min, warning_min, warning_max, hazard_max "temperature" = new/datum/tlv(BODYTEMP_COLD_WARNING_1, BODYTEMP_COLD_WARNING_1+10, BODYTEMP_HEAT_WARNING_1-27, BODYTEMP_HEAT_WARNING_1), /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), @@ -111,109 +119,6 @@ /datum/gas/halon = new/datum/tlv/dangerous ) -/obj/machinery/airalarm/server // No checks here. - TLV = list( - "pressure" = new/datum/tlv/no_checks, - "temperature" = new/datum/tlv/no_checks, - /datum/gas/oxygen = new/datum/tlv/no_checks, - /datum/gas/nitrogen = new/datum/tlv/no_checks, - /datum/gas/carbon_dioxide = new/datum/tlv/no_checks, - /datum/gas/miasma = new/datum/tlv/no_checks, - /datum/gas/plasma = new/datum/tlv/no_checks, - /datum/gas/nitrous_oxide = new/datum/tlv/no_checks, - /datum/gas/bz = new/datum/tlv/no_checks, - /datum/gas/hypernoblium = new/datum/tlv/no_checks, - /datum/gas/water_vapor = new/datum/tlv/no_checks, - /datum/gas/tritium = new/datum/tlv/no_checks, - /datum/gas/stimulum = new/datum/tlv/no_checks, - /datum/gas/nitryl = new/datum/tlv/no_checks, - /datum/gas/pluoxium = new/datum/tlv/no_checks, - /datum/gas/freon = new/datum/tlv/no_checks, - /datum/gas/hydrogen = new/datum/tlv/no_checks, - /datum/gas/healium = new/datum/tlv/dangerous, - /datum/gas/proto_nitrate = new/datum/tlv/dangerous, - /datum/gas/zauker = new/datum/tlv/dangerous, - /datum/gas/helium = new/datum/tlv/dangerous, - /datum/gas/antinoblium = new/datum/tlv/dangerous, - /datum/gas/halon = new/datum/tlv/dangerous - ) - -/obj/machinery/airalarm/kitchen_cold_room // Kitchen cold rooms start off at -14°C or 259.15K. - TLV = list( - "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE * 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa - "temperature" = new/datum/tlv(COLD_ROOM_TEMP-40, COLD_ROOM_TEMP-20, COLD_ROOM_TEMP+20, COLD_ROOM_TEMP+40), - /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa - /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), - /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), - /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), - /datum/gas/plasma = new/datum/tlv/dangerous, - /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, - /datum/gas/bz = new/datum/tlv/dangerous, - /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic - /datum/gas/water_vapor = new/datum/tlv/dangerous, - /datum/gas/tritium = new/datum/tlv/dangerous, - /datum/gas/stimulum = new/datum/tlv/dangerous, - /datum/gas/nitryl = new/datum/tlv/dangerous, - /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000), // Unlike oxygen, pluoxium does not fuel plasma/tritium fires - /datum/gas/freon = new/datum/tlv/dangerous, - /datum/gas/hydrogen = new/datum/tlv/dangerous, - /datum/gas/healium = new/datum/tlv/dangerous, - /datum/gas/proto_nitrate = new/datum/tlv/dangerous, - /datum/gas/zauker = new/datum/tlv/dangerous, - /datum/gas/helium = new/datum/tlv/dangerous, - /datum/gas/antinoblium = new/datum/tlv/dangerous, - /datum/gas/halon = new/datum/tlv/dangerous - ) - -/obj/machinery/airalarm/unlocked - locked = FALSE - -/obj/machinery/airalarm/engine - name = "engine air alarm" - locked = FALSE - req_access = null - req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE) - -/obj/machinery/airalarm/mixingchamber - name = "chamber air alarm" - locked = FALSE - req_access = null - req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ORDNANCE) - -/obj/machinery/airalarm/all_access - name = "all-access air alarm" - desc = "This particular atmos control unit appears to have no access restrictions." - locked = FALSE - req_access = null - req_one_access = null - -/obj/machinery/airalarm/syndicate //general syndicate access - req_access = list(ACCESS_SYNDICATE) - -/obj/machinery/airalarm/away //general away mission access - req_access = list(ACCESS_AWAY_GENERAL) - -/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New() - dir = SOUTH - pixel_y = 24 - -/obj/machinery/airalarm/directional/south - dir = NORTH - pixel_y = -24 - -/obj/machinery/airalarm/directional/east - dir = WEST - pixel_x = 24 - -/obj/machinery/airalarm/directional/west - dir = EAST - pixel_x = -24 - -//all air alarms in area are connected via magic -/area - var/list/air_vent_info = list() - var/list/air_scrub_info = list() - /obj/machinery/airalarm/New(loc, ndir, nbuild) ..() wires = new /datum/wires/airalarm(src) @@ -241,6 +146,7 @@ /obj/machinery/airalarm/Initialize(mapload) . = ..() set_frequency(frequency) + AddElement(/datum/element/connect_loc, atmos_connections) AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/air_alarm, )) @@ -367,27 +273,27 @@ selected = TLV["pressure"] thresholds += list(list("name" = "Pressure", "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "max2", "selected" = selected.max2)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "hazard_min", "selected" = selected.hazard_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "warning_min", "selected" = selected.warning_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "warning_max", "selected" = selected.warning_max)) + thresholds[thresholds.len]["settings"] += list(list("env" = "pressure", "val" = "hazard_max", "selected" = selected.hazard_max)) selected = TLV["temperature"] thresholds += list(list("name" = "Temperature", "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "max2", "selected" = selected.max2)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "hazard_min", "selected" = selected.hazard_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "warning_min", "selected" = selected.warning_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "warning_max", "selected" = selected.warning_max)) + thresholds[thresholds.len]["settings"] += list(list("env" = "temperature", "val" = "hazard_max", "selected" = selected.hazard_max)) for(var/gas_id in GLOB.meta_gas_info) if(!(gas_id in TLV)) // We're not interested in this gas, it seems. continue selected = TLV[gas_id] thresholds += list(list("name" = GLOB.meta_gas_info[gas_id][META_GAS_NAME], "settings" = list())) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min2", "selected" = selected.min2)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "min1", "selected" = selected.min1)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max1", "selected" = selected.max1)) - thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "max2", "selected" = selected.max2)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "hazard_min", "selected" = selected.hazard_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "warning_min", "selected" = selected.warning_min)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "warning_max", "selected" = selected.warning_max)) + thresholds[thresholds.len]["settings"] += list(list("env" = gas_id, "val" = "hazard_max", "selected" = selected.hazard_max)) data["thresholds"] = thresholds return data @@ -441,6 +347,9 @@ else tlv.vars[name] = round(value, 0.01) investigate_log(" treshold value for [env]:[name] was set to [value] by [key_name(usr)]",INVESTIGATE_ATMOS) + var/turf/our_turf = get_turf(src) + var/datum/gas_mixture/environment = our_turf.return_air() + check_air_dangerlevel(our_turf, environment, environment.temperature) . = TRUE if("mode") mode = text2num(params["mode"]) @@ -668,33 +577,36 @@ icon_state = "alarm1" return ..() -/obj/machinery/airalarm/process() +/** + * main proc for throwing a shitfit if the air isnt right. + * goes into warning mode if gas parameters are beyond the tlv warning bounds, goes into hazard mode if gas parameters are beyond tlv hazard bounds + * + */ +/obj/machinery/airalarm/proc/check_air_dangerlevel(turf/location, datum/gas_mixture/environment, exposed_temperature) + SIGNAL_HANDLER if((machine_stat & (NOPOWER|BROKEN)) || shorted) return - var/turf/location = get_turf(src) - if(!location) - return + var/datum/tlv/current_tlv + //cache for sanic speed (lists are references anyways) + var/list/cached_tlv = TLV - var/datum/tlv/cur_tlv - - var/datum/gas_mixture/environment = location.return_air() var/list/env_gases = environment.gases - var/partial_pressure = R_IDEAL_GAS_EQUATION * environment.temperature / environment.volume + var/partial_pressure = R_IDEAL_GAS_EQUATION * exposed_temperature / environment.volume - cur_tlv = TLV["pressure"] + current_tlv = cached_tlv["pressure"] var/environment_pressure = environment.return_pressure() - var/pressure_dangerlevel = cur_tlv.get_danger_level(environment_pressure) + var/pressure_dangerlevel = current_tlv.get_danger_level(environment_pressure) - cur_tlv = TLV["temperature"] - var/temperature_dangerlevel = cur_tlv.get_danger_level(environment.temperature) + current_tlv = cached_tlv["temperature"] + var/temperature_dangerlevel = current_tlv.get_danger_level(exposed_temperature) var/gas_dangerlevel = 0 for(var/gas_id in env_gases) - if(!(gas_id in TLV)) // We're not interested in this gas, it seems. + if(!(gas_id in cached_tlv)) // We're not interested in this gas, it seems. continue - cur_tlv = TLV[gas_id] - gas_dangerlevel = max(gas_dangerlevel, cur_tlv.get_danger_level(env_gases[gas_id][MOLES] * partial_pressure)) + current_tlv = cached_tlv[gas_id] + gas_dangerlevel = max(gas_dangerlevel, current_tlv.get_danger_level(env_gases[gas_id][MOLES] * partial_pressure)) environment.garbage_collect() @@ -702,10 +614,10 @@ danger_level = max(pressure_dangerlevel, temperature_dangerlevel, gas_dangerlevel) if(old_danger_level != danger_level) - apply_danger_level() + INVOKE_ASYNC(src, .proc/apply_danger_level) if(mode == AALARM_MODE_REPLACEMENT && environment_pressure < ONE_ATMOSPHERE * 0.05) mode = AALARM_MODE_SCRUBBING - apply_mode(src) + INVOKE_ASYNC(src, .proc/apply_mode, src) /obj/machinery/airalarm/proc/post_alert(alert_level) @@ -894,6 +806,104 @@ new /obj/item/stack/cable_coil(loc, 3) qdel(src) +/obj/machinery/airalarm/server // No checks here. + TLV = list( + "pressure" = new/datum/tlv/no_checks, + "temperature" = new/datum/tlv/no_checks, + /datum/gas/oxygen = new/datum/tlv/no_checks, + /datum/gas/nitrogen = new/datum/tlv/no_checks, + /datum/gas/carbon_dioxide = new/datum/tlv/no_checks, + /datum/gas/miasma = new/datum/tlv/no_checks, + /datum/gas/plasma = new/datum/tlv/no_checks, + /datum/gas/nitrous_oxide = new/datum/tlv/no_checks, + /datum/gas/bz = new/datum/tlv/no_checks, + /datum/gas/hypernoblium = new/datum/tlv/no_checks, + /datum/gas/water_vapor = new/datum/tlv/no_checks, + /datum/gas/tritium = new/datum/tlv/no_checks, + /datum/gas/stimulum = new/datum/tlv/no_checks, + /datum/gas/nitryl = new/datum/tlv/no_checks, + /datum/gas/pluoxium = new/datum/tlv/no_checks, + /datum/gas/freon = new/datum/tlv/no_checks, + /datum/gas/hydrogen = new/datum/tlv/no_checks, + /datum/gas/healium = new/datum/tlv/dangerous, + /datum/gas/proto_nitrate = new/datum/tlv/dangerous, + /datum/gas/zauker = new/datum/tlv/dangerous, + /datum/gas/helium = new/datum/tlv/dangerous, + /datum/gas/antinoblium = new/datum/tlv/dangerous, + /datum/gas/halon = new/datum/tlv/dangerous, + ) + +/obj/machinery/airalarm/kitchen_cold_room // Kitchen cold rooms start off at -14°C or 259.15K. + TLV = list( + "pressure" = new/datum/tlv(ONE_ATMOSPHERE * 0.8, ONE_ATMOSPHERE * 0.9, ONE_ATMOSPHERE * 1.1, ONE_ATMOSPHERE * 1.2), // kPa + "temperature" = new/datum/tlv(COLD_ROOM_TEMP-40, COLD_ROOM_TEMP-20, COLD_ROOM_TEMP+20, COLD_ROOM_TEMP+40), + /datum/gas/oxygen = new/datum/tlv(16, 19, 135, 140), // Partial pressure, kpa + /datum/gas/nitrogen = new/datum/tlv(-1, -1, 1000, 1000), + /datum/gas/carbon_dioxide = new/datum/tlv(-1, -1, 5, 10), + /datum/gas/miasma = new/datum/tlv/(-1, -1, 2, 5), + /datum/gas/plasma = new/datum/tlv/dangerous, + /datum/gas/nitrous_oxide = new/datum/tlv/dangerous, + /datum/gas/bz = new/datum/tlv/dangerous, + /datum/gas/hypernoblium = new/datum/tlv(-1, -1, 1000, 1000), // Hyper-Noblium is inert and nontoxic + /datum/gas/water_vapor = new/datum/tlv/dangerous, + /datum/gas/tritium = new/datum/tlv/dangerous, + /datum/gas/stimulum = new/datum/tlv/dangerous, + /datum/gas/nitryl = new/datum/tlv/dangerous, + /datum/gas/pluoxium = new/datum/tlv(-1, -1, 1000, 1000), // Unlike oxygen, pluoxium does not fuel plasma/tritium fires + /datum/gas/freon = new/datum/tlv/dangerous, + /datum/gas/hydrogen = new/datum/tlv/dangerous, + /datum/gas/healium = new/datum/tlv/dangerous, + /datum/gas/proto_nitrate = new/datum/tlv/dangerous, + /datum/gas/zauker = new/datum/tlv/dangerous, + /datum/gas/helium = new/datum/tlv/dangerous, + /datum/gas/antinoblium = new/datum/tlv/dangerous, + /datum/gas/halon = new/datum/tlv/dangerous, + ) + +/obj/machinery/airalarm/unlocked + locked = FALSE + +/obj/machinery/airalarm/engine + name = "engine air alarm" + locked = FALSE + req_access = null + req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ENGINE) + +/obj/machinery/airalarm/mixingchamber + name = "chamber air alarm" + locked = FALSE + req_access = null + req_one_access = list(ACCESS_ATMOSPHERICS, ACCESS_ORDNANCE) + +/obj/machinery/airalarm/all_access + name = "all-access air alarm" + desc = "This particular atmos control unit appears to have no access restrictions." + locked = FALSE + req_access = null + req_one_access = null + +/obj/machinery/airalarm/syndicate //general syndicate access + req_access = list(ACCESS_SYNDICATE) + +/obj/machinery/airalarm/away //general away mission access + req_access = list(ACCESS_AWAY_GENERAL) + +/obj/machinery/airalarm/directional/north //Pixel offsets get overwritten on New() + dir = SOUTH + pixel_y = 24 + +/obj/machinery/airalarm/directional/south + dir = NORTH + pixel_y = -24 + +/obj/machinery/airalarm/directional/east + dir = WEST + pixel_x = 24 + +/obj/machinery/airalarm/directional/west + dir = EAST + pixel_x = -24 + /obj/item/circuit_component/air_alarm display_name = "Air Alarm" desc = "Controls levels of gases and their temperature as well as all vents and scrubbers in the room." @@ -968,10 +978,10 @@ return var/datum/tlv/settings = connected_alarm.TLV[options_map[current_option]] - settings.min2 = min_2 - settings.min1 = min_1 - settings.max1 = max_1 - settings.max2 = max_2 + settings.hazard_min = min_2 + settings.warning_min = min_1 + settings.warning_max = max_1 + settings.hazard_max = max_2 #undef AALARM_MODE_SCRUBBING #undef AALARM_MODE_VENTING diff --git a/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm b/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm index b236621ca55..07570fb5305 100644 --- a/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm +++ b/code/modules/atmospherics/machinery/components/binary_devices/thermomachine.dm @@ -439,7 +439,7 @@ switch(action) if("power") on = !on - use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE + update_use_power(on ? ACTIVE_POWER_USE : IDLE_POWER_USE) investigate_log("was turned [on ? "on" : "off"] by [key_name(usr)]", INVESTIGATE_ATMOS) . = TRUE if("cooling") diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm index ec5730b291d..621f84fa2c1 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_parts.dm @@ -310,7 +310,7 @@ switch(action) if("start_power") connected_core.start_power = !connected_core.start_power - connected_core.use_power = connected_core.start_power ? ACTIVE_POWER_USE : IDLE_POWER_USE + connected_core.update_use_power(connected_core.start_power ? ACTIVE_POWER_USE : IDLE_POWER_USE) . = TRUE if("start_cooling") connected_core.start_cooling = !connected_core.start_cooling diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm index ebd65b6e8b3..d02e76d305d 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm @@ -188,7 +188,8 @@ if(machine_stat & (NOPOWER|BROKEN)) return FALSE if(use_power == ACTIVE_POWER_USE) - active_power_usage = ((power_level + 1) * MIN_POWER_USAGE) //Max around 350 KW + update_mode_power_usage(ACTIVE_POWER_USE, (power_level + 1) * MIN_POWER_USAGE) //Max around 350 KW + return TRUE ///Checks if the gases in the input are the ones needed by the recipe diff --git a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm index d0ed65bef96..017f85794db 100644 --- a/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm +++ b/code/modules/atmospherics/machinery/components/unary_devices/vent_scrubber.dm @@ -19,7 +19,7 @@ var/filter_types = list(/datum/gas/carbon_dioxide) var/volume_rate = 200 - var/widenet = 0 //is this scrubber acting on the 3x3 area around it. + var/widenet = FALSE //is this scrubber acting on the 3x3 area around it. var/list/turf/adjacent_turfs = list() var/frequency = FREQ_ATMOS_CONTROL @@ -50,22 +50,6 @@ adjacent_turfs.Cut() return ..() -/obj/machinery/atmospherics/components/unary/vent_scrubber/auto_use_power() - if(!on || welded || !is_operational || !powered(power_channel)) - return FALSE - - var/amount = idle_power_usage - - if(scrubbing & SCRUBBING) - amount += idle_power_usage * length(filter_types) - else //scrubbing == SIPHONING - amount = active_power_usage - - if(widenet) - amount += amount * (adjacent_turfs.len * (adjacent_turfs.len / 2)) - use_power(amount, power_channel) - return TRUE - /obj/machinery/atmospherics/components/unary/vent_scrubber/update_icon_nopipes() cut_overlays() if(showpipe) @@ -162,7 +146,7 @@ if(air_contents.return_pressure() >= 50 * ONE_ATMOSPHERE) return FALSE - if(scrubbing & SCRUBBING) + if(scrubbing == SCRUBBING) if(length(env_gases & filter_types)) var/transfer_moles = min(1, volume_rate / environment.volume) * environment.total_moles() @@ -209,19 +193,21 @@ if(widenet) check_turfs() -//we populate a list of turfs with nonatmos-blocked cardinal turfs AND -// diagonal turfs that can share atmos with *both* of the cardinal turfs - +///we populate a list of turfs with nonatmos-blocked cardinal turfs AND +/// diagonal turfs that can share atmos with *both* of the cardinal turfs /obj/machinery/atmospherics/components/unary/vent_scrubber/proc/check_turfs() adjacent_turfs.Cut() var/turf/T = get_turf(src) - if(istype(T)) - adjacent_turfs = T.GetAtmosAdjacentTurfs(alldir = 1) + adjacent_turfs = T.GetAtmosAdjacentTurfs(alldir = TRUE) /obj/machinery/atmospherics/components/unary/vent_scrubber/receive_signal(datum/signal/signal) if(!is_operational || !signal.data["tag"] || (signal.data["tag"] != id_tag) || (signal.data["sigtype"]!="command")) return + var/old_widenet = widenet + var/old_scrubbing = scrubbing + var/old_filter_length = length(filter_types) + var/atom/signal_sender = signal.data["user"] if("power" in signal.data) @@ -234,7 +220,6 @@ if("toggle_widenet" in signal.data) widenet = !widenet - var/old_scrubbing = scrubbing if("scrubbing" in signal.data) scrubbing = text2num(signal.data["scrubbing"]) if("toggle_scrubbing" in signal.data) @@ -260,7 +245,25 @@ broadcast_status() update_appearance() - return + + if(length(filter_types) == old_filter_length && old_scrubbing == scrubbing && old_widenet == widenet) + return + + idle_power_usage = initial(idle_power_usage) + active_power_usage = initial(idle_power_usage) + + var/new_power_usage = 0 + if(scrubbing == SCRUBBING) + new_power_usage = idle_power_usage + idle_power_usage * length(filter_types) + update_use_power(IDLE_POWER_USE) + else + new_power_usage = active_power_usage + update_use_power(ACTIVE_POWER_USE) + + if(widenet) + new_power_usage += new_power_usage * (length(adjacent_turfs) * (length(adjacent_turfs) / 2)) + + update_mode_power_usage(scrubbing == SCRUBBING ? IDLE_POWER_USE : ACTIVE_POWER_USE, new_power_usage) /obj/machinery/atmospherics/components/unary/vent_scrubber/power_change() . = ..() diff --git a/code/modules/atmospherics/machinery/other/miner.dm b/code/modules/atmospherics/machinery/other/miner.dm index 9606fb646e1..a9668d97c73 100644 --- a/code/modules/atmospherics/machinery/other/miner.dm +++ b/code/modules/atmospherics/machinery/other/miner.dm @@ -87,15 +87,15 @@ var/P = G.return_pressure() switch(power_draw) if(GASMINER_POWER_NONE) - active_power_usage = 0 + update_use_power(ACTIVE_POWER_USE, 0) if(GASMINER_POWER_STATIC) - active_power_usage = power_draw_static + update_use_power(ACTIVE_POWER_USE, power_draw_static) if(GASMINER_POWER_MOLES) - active_power_usage = spawn_mol * power_draw_dynamic_mol_coeff + update_use_power(ACTIVE_POWER_USE, spawn_mol * power_draw_dynamic_mol_coeff) if(GASMINER_POWER_KPA) - active_power_usage = P * power_draw_dynamic_kpa_coeff + update_use_power(ACTIVE_POWER_USE, P * power_draw_dynamic_kpa_coeff) if(GASMINER_POWER_FULLSCALE) - active_power_usage = (spawn_mol * power_draw_dynamic_mol_coeff) + (P * power_draw_dynamic_kpa_coeff) + update_use_power(ACTIVE_POWER_USE, (spawn_mol * power_draw_dynamic_mol_coeff) + (P * power_draw_dynamic_kpa_coeff)) /obj/machinery/atmospherics/miner/proc/do_use_power(amount) var/turf/T = get_turf(src) diff --git a/code/modules/atmospherics/machinery/portable/scrubber.dm b/code/modules/atmospherics/machinery/portable/scrubber.dm index dbf5e60b749..c028e392635 100644 --- a/code/modules/atmospherics/machinery/portable/scrubber.dm +++ b/code/modules/atmospherics/machinery/portable/scrubber.dm @@ -197,7 +197,7 @@ if((!anchored && !movable) || !is_operational) on = FALSE update_appearance() - use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE + update_use_power(on ? ACTIVE_POWER_USE : IDLE_POWER_USE) if(!on) return ..() diff --git a/code/modules/awaymissions/gateway.dm b/code/modules/awaymissions/gateway.dm index eaced868090..8f27765fad7 100644 --- a/code/modules/awaymissions/gateway.dm +++ b/code/modules/awaymissions/gateway.dm @@ -198,7 +198,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) target = null dest.deactivate(src) QDEL_NULL(portal) - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) update_appearance() portal_visuals.reset_visuals() @@ -222,7 +222,7 @@ GLOBAL_LIST_EMPTY(gateway_destinations) target.activate(destination) portal_visuals.setup_visuals(target) generate_bumper() - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) update_appearance() /obj/machinery/gateway/proc/Transfer(atom/movable/AM) diff --git a/code/modules/explorer_drone/scanner_array.dm b/code/modules/explorer_drone/scanner_array.dm index 03cb4b91d70..54dc498c5ae 100644 --- a/code/modules/explorer_drone/scanner_array.dm +++ b/code/modules/explorer_drone/scanner_array.dm @@ -206,9 +206,9 @@ GLOBAL_LIST_INIT(scan_conditions,init_scan_conditions()) /obj/machinery/exoscanner/proc/scan_change() SIGNAL_HANDLER if(GLOB.exoscanner_controller.current_scan) - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) else - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) update_icon_state() /obj/machinery/exoscanner/Destroy() diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index d1d98e1c744..135ea279e28 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -339,10 +339,10 @@ /obj/machinery/smartfridge/drying_rack/proc/toggle_drying(forceoff) if(drying || forceoff) drying = FALSE - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) else drying = TRUE - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) update_appearance() /obj/machinery/smartfridge/drying_rack/proc/rack_dry(obj/item/target) diff --git a/code/modules/holodeck/computer.dm b/code/modules/holodeck/computer.dm index 32e1ecfc112..06066f7092b 100644 --- a/code/modules/holodeck/computer.dm +++ b/code/modules/holodeck/computer.dm @@ -203,7 +203,7 @@ and clear when youre done! if you dont i will use :newspaper2: on you spawning_simulation = TRUE active = (map_id != offline_program) - use_power = active + IDLE_POWER_USE + update_use_power(active + IDLE_POWER_USE) program = map_id //clear the items from the previous program @@ -326,7 +326,7 @@ and clear when youre done! if you dont i will use :newspaper2: on you derez(item) for(var/obj/effect/holodeck_effect/holo_effect as anything in effects) holo_effect.tick() - active_power_usage = 50 + spawned.len * 3 + effects.len * 5 + update_mode_power_usage(ACTIVE_POWER_USE, 50 + spawned.len * 3 + effects.len * 5) /obj/machinery/computer/holodeck/proc/toggle_power(toggleOn = FALSE) if(active == toggleOn) diff --git a/code/modules/hydroponics/hydroponics.dm b/code/modules/hydroponics/hydroponics.dm index c50d96b8481..8fa860cf2ac 100644 --- a/code/modules/hydroponics/hydroponics.dm +++ b/code/modules/hydroponics/hydroponics.dm @@ -7,7 +7,8 @@ pixel_z = 8 obj_flags = CAN_BE_HIT | UNIQUE_RENAME circuit = /obj/item/circuitboard/machine/hydroponics - idle_power_usage = 0 + idle_power_usage = 5000 + use_power = NO_POWER_USE ///The amount of water in the tray (max 100) var/waterlevel = 100 ///The maximum amount of water in the tray @@ -125,6 +126,11 @@ else return ..() +/obj/machinery/hydroponics/power_change() + . = ..() + if(machine_stat & NOPOWER && self_sustaining) + self_sustaining = FALSE + /obj/machinery/hydroponics/process(delta_time) var/needs_update = 0 // Checks if the icon needs updating so we don't redraw empty trays every time @@ -132,8 +138,8 @@ myseed.forceMove(src) if(!powered() && self_sustaining) - visible_message(span_warning("[name]'s auto-grow functionality shuts off!")) - idle_power_usage = 0 + visible_message("[name]'s auto-grow functionality shuts off!") + update_use_power(NO_POWER_USE) self_sustaining = FALSE update_appearance() @@ -767,12 +773,14 @@ return if(!powered()) to_chat(user, span_warning("[name] has no power.")) + update_use_power(NO_POWER_USE) return if(!anchored) return self_sustaining = !self_sustaining - idle_power_usage = self_sustaining ? 5000 : 0 + update_use_power(self_sustaining ? IDLE_POWER_USE : NO_POWER_USE) to_chat(user, "You [self_sustaining ? "activate" : "deactivated"] [src]'s autogrow function[self_sustaining ? ", maintaining the tray's health while using high amounts of power" : ""].") + update_appearance() /obj/machinery/hydroponics/AltClick(mob/user) @@ -809,7 +817,7 @@ desc = initial(desc) TRAY_NAME_UPDATE if(self_sustaining) //No reason to pay for an empty tray. - idle_power_usage = 0 + update_use_power(NO_POWER_USE) self_sustaining = FALSE update_appearance() diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 84c3fd87680..ab46dbba246 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -32,6 +32,8 @@ /// The APCs power channel is automatically on. #define APC_CHANNEL_AUTO_ON 3 +#define APC_CHANNEL_IS_ON(channel) (channel >= APC_CHANNEL_ON) + // APC autoset enums: /// The APC turns automated and manual power channels off. #define AUTOSET_FORCE_OFF 0 @@ -129,7 +131,7 @@ var/environ = APC_CHANNEL_AUTO_ON var/operating = TRUE var/charging = APC_NOT_CHARGING - var/chargemode = 1 + var/chargemode = TRUE var/chargecount = 0 var/locked = TRUE var/coverlocked = TRUE @@ -149,6 +151,7 @@ var/beenhit = 0 // used for counting how many times it has been hit, used for Aliens at the moment var/mob/living/silicon/ai/occupier = null var/transfer_in_progress = FALSE //Is there an AI being transferred out of us? + ///buffer state that makes apcs not shut off channels immediately as long as theres some power left, effect visible in apcs only slowly losing power var/longtermpower = 10 var/auto_name = FALSE var/failure_timer = 0 @@ -1255,9 +1258,10 @@ force_update = TRUE return - lastused_light = area.power_usage[AREA_USAGE_LIGHT] + area.power_usage[AREA_USAGE_STATIC_LIGHT] - lastused_equip = area.power_usage[AREA_USAGE_EQUIP] + area.power_usage[AREA_USAGE_STATIC_EQUIP] - lastused_environ = area.power_usage[AREA_USAGE_ENVIRON] + area.power_usage[AREA_USAGE_STATIC_ENVIRON] + //dont use any power from that channel if we shut that power channel off + lastused_light = APC_CHANNEL_IS_ON(lighting) ? area.power_usage[AREA_USAGE_LIGHT] + area.power_usage[AREA_USAGE_STATIC_LIGHT] : 0 + lastused_equip = APC_CHANNEL_IS_ON(equipment) ? area.power_usage[AREA_USAGE_EQUIP] + area.power_usage[AREA_USAGE_STATIC_EQUIP] : 0 + lastused_environ = APC_CHANNEL_IS_ON(environ) ? area.power_usage[AREA_USAGE_ENVIRON] + area.power_usage[AREA_USAGE_STATIC_ENVIRON] : 0 area.clear_usage() lastused_total = lastused_light + lastused_equip + lastused_environ @@ -1404,17 +1408,18 @@ * - [AUTOSET_OFF]: The APC turns automatic channels off. */ /obj/machinery/power/apc/proc/autoset(val, on) - if(on == AUTOSET_FORCE_OFF) - if(val == APC_CHANNEL_ON) // if on, return off - return APC_CHANNEL_OFF - else if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off - return APC_CHANNEL_AUTO_OFF - else if(on == AUTOSET_ON) - if(val == APC_CHANNEL_AUTO_OFF) // if auto-off, return auto-on - return APC_CHANNEL_AUTO_ON - else if(on == AUTOSET_OFF) - if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off - return APC_CHANNEL_AUTO_OFF + switch(on) + if(AUTOSET_FORCE_OFF) + if(val == APC_CHANNEL_ON) // if on, return off + return APC_CHANNEL_OFF + else if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off + return APC_CHANNEL_AUTO_OFF + if(AUTOSET_ON) + if(val == APC_CHANNEL_AUTO_OFF) // if auto-off, return auto-on + return APC_CHANNEL_AUTO_ON + if(AUTOSET_OFF) + if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off + return APC_CHANNEL_AUTO_OFF return val /** diff --git a/code/modules/power/gravitygenerator.dm b/code/modules/power/gravitygenerator.dm index cefb3a72f22..4c381898428 100644 --- a/code/modules/power/gravitygenerator.dm +++ b/code/modules/power/gravitygenerator.dm @@ -294,7 +294,7 @@ GLOBAL_LIST_EMPTY(gravity_generators) // We will keep track of this by adding ne /obj/machinery/gravity_generator/main/proc/set_state(new_state) charging_state = POWER_IDLE on = new_state - use_power = on ? ACTIVE_POWER_USE : IDLE_POWER_USE + update_use_power(on ? ACTIVE_POWER_USE : IDLE_POWER_USE) // Sound the alert if gravity was just enabled or disabled. var/alert = FALSE if(SSticker.IsRoundInProgress()) diff --git a/code/modules/power/monitor.dm b/code/modules/power/monitor.dm index 37d9278bd1a..738ea6a0a83 100644 --- a/code/modules/power/monitor.dm +++ b/code/modules/power/monitor.dm @@ -39,10 +39,10 @@ /obj/machinery/computer/monitor/process() if(!get_powernet()) - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) search() else - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) record() /obj/machinery/computer/monitor/proc/search() //keep in sync with /datum/computer_file/program/power_monitor's version diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index ac9c1db17a2..1d9d3988a81 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -79,7 +79,7 @@ // returns true if the area has power on given channel (or doesn't require power). // defaults to power_channel -/obj/machinery/proc/powered(chan = -1) // defaults to power_channel +/obj/machinery/proc/powered(chan = power_channel) if(!loc) return FALSE if(!use_power) @@ -88,18 +88,13 @@ var/area/A = get_area(src) // make sure it's in an area if(!A) return FALSE // if not, then not powered - if(chan == -1) - chan = power_channel + return A.powered(chan) // return power status of the area // increment the power usage stats for an area -/obj/machinery/proc/use_power(amount, chan = -1) // defaults to power_channel +/obj/machinery/proc/use_power(amount, chan = power_channel) var/area/A = get_area(src) // make sure it's in an area - if(!A) - return - if(chan == -1) - chan = power_channel - A.use_power(amount, chan) + A?.use_power(amount, chan) /** * An alternative to 'use_power', this proc directly costs the APC in direct charge, as opposed to being calculated periodically. @@ -154,9 +149,7 @@ /obj/machinery/proc/addStaticPower(value, powerchannel) var/area/A = get_area(src) - if(!A) - return - A.addStaticPower(value, powerchannel) + A?.addStaticPower(value, powerchannel) /obj/machinery/proc/removeStaticPower(value, powerchannel) addStaticPower(-value, powerchannel) diff --git a/code/modules/power/powernet.dm b/code/modules/power/powernet.dm index 910e03a8f5b..ac24b109913 100644 --- a/code/modules/power/powernet.dm +++ b/code/modules/power/powernet.dm @@ -80,7 +80,7 @@ //see if there's a surplus of power remaining in the powernet and stores unused power in the SMES netexcess = avail - load - if(netexcess > 100 && nodes?.len) // if there was excess power last cycle + if(netexcess > 100 && length(nodes)) // if there was excess power last cycle for(var/obj/machinery/power/smes/S in nodes) // find the SMESes in the network S.restore() // and restore some of the power that was used diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 556cbdc0f38..22e629364e7 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -69,7 +69,7 @@ toggle_power() user.visible_message(span_notice("[user.name] turns the [src.name] [active? "on":"off"]."), \ span_notice("You turn the [src.name] [active? "on":"off"].")) - var/datum/gas_mixture/tank_mix = loaded_tank.return_air() + var/datum/gas_mixture/tank_mix = loaded_tank?.return_air() var/fuel if(loaded_tank) fuel = tank_mix.gases[/datum/gas/plasma] diff --git a/code/modules/power/singularity/emitter.dm b/code/modules/power/singularity/emitter.dm index 3e1f120ca8e..48c30688a51 100644 --- a/code/modules/power/singularity/emitter.dm +++ b/code/modules/power/singularity/emitter.dm @@ -67,12 +67,12 @@ /obj/machinery/power/emitter/ctf name = "Energy Cannon" active = TRUE - active_power_usage = FALSE - idle_power_usage = FALSE + active_power_usage = 0 + idle_power_usage = 0 locked = TRUE req_access_txt = "100" welded = TRUE - use_power = FALSE + use_power = NO_POWER_USE /obj/machinery/power/emitter/Initialize() . = ..() @@ -110,7 +110,7 @@ fire_delay = fire_shoot_delay for(var/obj/item/stock_parts/manipulator/manipulator in component_parts) power_usage -= 50 * manipulator.rating - active_power_usage = power_usage + update_mode_power_usage(ACTIVE_POWER_USE, power_usage) /obj/machinery/power/emitter/examine(mob/user) . = ..() diff --git a/code/modules/reagents/chemistry/machinery/pandemic.dm b/code/modules/reagents/chemistry/machinery/pandemic.dm index 2839404720f..041ea949b00 100644 --- a/code/modules/reagents/chemistry/machinery/pandemic.dm +++ b/code/modules/reagents/chemistry/machinery/pandemic.dm @@ -9,7 +9,7 @@ icon_state = "mixer0" icon_keyboard = null base_icon_state = "mixer" - use_power = TRUE + use_power = IDLE_POWER_USE idle_power_usage = 20 resistance_flags = ACID_PROOF circuit = /obj/item/circuitboard/computer/pandemic diff --git a/code/modules/research/bepis.dm b/code/modules/research/bepis.dm index f3869ec6b01..2dadc186522 100644 --- a/code/modules/research/bepis.dm +++ b/code/modules/research/bepis.dm @@ -187,7 +187,7 @@ return calcsuccess() use_power(MACHINE_OPERATION * power_saver) //This thing should eat your APC battery if you're not careful. - use_power = IDLE_POWER_USE //Machine shuts off after use to prevent spam and look better visually. + update_use_power(IDLE_POWER_USE) //Machine shuts off after use to prevent spam and look better visually. update_appearance() if("amount") var/input = text2num(params["amount"]) @@ -195,9 +195,9 @@ banking_amount = input if("toggle_power") if(use_power == ACTIVE_POWER_USE) - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) else - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) update_appearance() if("account_reset") if(use_power == IDLE_POWER_USE) diff --git a/code/modules/shuttle/special.dm b/code/modules/shuttle/special.dm index ff89b901fa0..7bbdaf14686 100644 --- a/code/modules/shuttle/special.dm +++ b/code/modules/shuttle/special.dm @@ -229,7 +229,7 @@ name = "luxury shuttle ticket field" density = FALSE //allows shuttle airlocks to close, nothing but an approved passenger gets past CanPass locked = TRUE - use_power = FALSE + use_power = NO_POWER_USE resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF var/threshold = 500 var/static/list/approved_passengers = list() diff --git a/code/modules/station_goals/shield.dm b/code/modules/station_goals/shield.dm index 9e4e69eb7fa..3c5f6a5b379 100644 --- a/code/modules/station_goals/shield.dm +++ b/code/modules/station_goals/shield.dm @@ -92,7 +92,7 @@ base_icon_state = "sat" anchored = FALSE density = TRUE - use_power = FALSE + use_power = NO_POWER_USE var/mode = "NTPROBEV0.8" var/active = FALSE var/static/gid = 0 diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index 9438e1c3a43..13c9c84c894 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -185,7 +185,7 @@ */ /obj/machinery/mecha_part_fabricator/proc/on_start_printing() add_overlay("fab-active") - use_power = ACTIVE_POWER_USE + update_use_power(ACTIVE_POWER_USE) /** * Intended to be called when the exofab has stopped working and is no longer printing items. @@ -194,7 +194,7 @@ */ /obj/machinery/mecha_part_fabricator/proc/on_finish_printing() cut_overlay("fab-active") - use_power = IDLE_POWER_USE + update_use_power(IDLE_POWER_USE) desc = initial(desc) process_queue = FALSE diff --git a/tgui/packages/tgui/interfaces/AirAlarm.js b/tgui/packages/tgui/interfaces/AirAlarm.js index ed493236531..402ced320eb 100644 --- a/tgui/packages/tgui/interfaces/AirAlarm.js +++ b/tgui/packages/tgui/interfaces/AirAlarm.js @@ -255,10 +255,10 @@ const AirAlarmControlThresholds = (props, context) => { - min2 - min1 - max1 - max2 + hazard_min + warning_min + warning_max + hazard_max