[MIRROR] large refactor of machine/power code to cut down on processing time and wasted lists (#7920)

* large refactor of machine/power code to cut down on processing time and wasted lists (#60317)

original pr here: #59789 (Closed because he didn't think it was good enough)
came back to this because i realized that

    all machines were area sensitive, meaning they had a list with at least a reference to themselves (assuming they arent in the contents of another movable which most arent) for the purposes of handling power differences when their area changes
    pipes are machines
    there are ~14k machines and ~6k pipes
    i made this problem worse with a recent pr by making it a nested list

so i needed to track what machines needed power, and this pr had work already done that could be used for that purpose. now machines that have use_power == NO_POWER_USE do not have this extra memory overhead for no reason

currently every machine that uses power draws that amount from its area from a dynamic channel via auto_use_power() which is called every SSmachines fire(), then in apc/process() the area's dynamic power draw is reset and the power is used. with static power its not calculated then reset every loop, its just taken from the grid. so now machines handle updating their static power usage from their current area (this doesnt touch power machines that require a wire connection). in order to allow this, use_power, idle_power_usage, and active_power_usage have setters to track state correctly and update the static power usage on the machines current area and handle area sensitivity.

also goes through a lot of heavy abusers of SSmachine processing time and tries to make it faster. makes airalarm/process() into a signal handler for COMSIG_TURF_EXPOSE since air alarms only need to process for changes.
Why It's Good For The Game

SSmachines isnt the heaviest hitter in terms of total cpu and certainly not in terms of overtime, but its not a lightweight. it frequently takes > 50ms to complete a run and seems to be in the top 5 or so of subsystem costs looking at some round profilers

also gets rid of a few thousand lists since every pipe no longer has two useless lists each (and any other machines that dont use power)

Love ya kyler

Co-authored-by: Rohesie <rohesie@ gmail.com>

* large refactor of machine/power code to cut down on processing time and wasted lists

Co-authored-by: Kylerace <kylerlumpkin1@gmail.com>
Co-authored-by: Rohesie <rohesie@ gmail.com>
This commit is contained in:
SkyratBot
2021-09-02 04:11:59 +02:00
committed by GitHub
parent d8e8493e85
commit a2aaacdead
37 changed files with 547 additions and 357 deletions

View File

@@ -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

View File

@@ -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,12 +39,8 @@ 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
if (MC_TICK_CHECK)
return

View File

@@ -92,6 +92,9 @@
///Used to decide what the maximum time between ambience is
var/max_ambience_cooldown = 60 SECONDS //SKYRAT EDIT CHANGE - ORIGINAL: 90
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

View File

@@ -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

View File

@@ -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)

View File

@@ -67,23 +67,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()

View File

@@ -434,12 +434,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)
@@ -448,22 +443,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)
for(var/datum/holocall/holocall as anything in holo_calls)
if(holocall.connected_holopad == src)
continue
if(force_answer_call && world.time > (holocall.call_start_time + (HOLOPAD_MAX_DIAL_TIME / 2)))
holocall.Answer(src)
break
if(HC.head_call && !secure)
HC.Answer(src)
if(holocall.head_call && !secure)
holocall.Answer(src)
break
if(outgoing_call)
HC.Disconnect(src)//can't answer calls while calling
holocall.Disconnect(src)//can't answer calls while calling
else
playsound(src, 'sound/machines/twobeep.ogg', 100) //bring, bring!
ringing = TRUE
update_appearance()
update_appearance(UPDATE_ICON_STATE)
/obj/machinery/holopad/proc/activate_holo(mob/living/user)
var/mob/living/silicon/ai/AI = user
@@ -527,8 +523,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

View File

@@ -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

View File

@@ -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()

View File

@@ -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()

View File

@@ -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))
@@ -132,7 +132,7 @@
/obj/machinery/stasis/process()
if(!(occupant && isliving(occupant) && check_nap_violations()))
use_power = IDLE_POWER_USE
update_use_power(IDLE_POWER_USE)
return
var/mob/living/L_occupant = occupant
if(stasis_running())

View File

@@ -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()

View File

@@ -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

View File

@@ -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")

View File

@@ -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

View File

@@ -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

View File

@@ -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,8 +245,26 @@
broadcast_status()
update_appearance()
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()
. = ..()
update_icon_nopipes()

View File

@@ -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)

View File

@@ -202,7 +202,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 ..()

View File

@@ -216,7 +216,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()
@@ -244,7 +244,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)

View File

@@ -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()

View File

@@ -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)

View File

@@ -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)

View File

@@ -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("<span class='warning'>[name]'s auto-grow functionality shuts off!</span>")
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, "<span class='notice'>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()

View File

@@ -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
@@ -138,7 +140,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
@@ -158,6 +160,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
@@ -1281,9 +1284,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
@@ -1447,15 +1451,16 @@
* - [AUTOSET_OFF]: The APC turns automatic channels off.
*/
/obj/machinery/power/apc/proc/autoset(val, on)
if(on == AUTOSET_FORCE_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
else if(on == AUTOSET_ON)
if(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(AUTOSET_OFF)
if(val == APC_CHANNEL_AUTO_ON) // if auto-on, return auto-off
return APC_CHANNEL_AUTO_OFF
return val

View File

@@ -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())

View File

@@ -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

View File

@@ -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)

View File

@@ -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

View File

@@ -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]

View File

@@ -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)
. = ..()

View File

@@ -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

View File

@@ -188,7 +188,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"])
@@ -196,9 +196,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)

View File

@@ -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()

View File

@@ -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

View File

@@ -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

View File

@@ -255,10 +255,10 @@ const AirAlarmControlThresholds = (props, context) => {
<thead>
<tr>
<td />
<td className="color-bad">min2</td>
<td className="color-average">min1</td>
<td className="color-average">max1</td>
<td className="color-bad">max2</td>
<td className="color-bad">hazard_min</td>
<td className="color-average">warning_min</td>
<td className="color-average">warning_max</td>
<td className="color-bad">hazard_max</td>
</tr>
</thead>
<tbody>