Files
Paradise/code/modules/power/powernets/local_powernet.dm
Ryan 7c3cd86f14 APC & Machinery Refactor + Local Powernets (#19991)
* local powernet and machine power refactor

* some fixes

* more tweaks + powerchange() refactor

* fixes var edited apcs on meatpackers.dmm

* fixes issue with power channels

* Reviews

* delta fix

* Update code/game/machinery/portable_turret.dm

Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>

* Apply suggestions from code review

Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>

* removed area power change proc

* damn morgues

* requested changes

* request changes

* deconfliction

* mapping fixes

* some fixes from TM

---------

Co-authored-by: Henri215 <77684085+Henri215@users.noreply.github.com>
2023-01-30 22:28:10 +00:00

189 lines
7.6 KiB
Plaintext

/**
* # local_powernet
*
* Manages all power related mechanics for a single /area
* Machines in areas will directly register to this datum in order to recieve power
*
* Machine/Turf/Item -> Local Powernet -> APC -> Terminal -> Wirenet
*
* Non-machines cannot register to the local powernet and should instead listen for power change signals
*/
/datum/local_powernet
/// The area this local powernet is attached to
var/area/powernet_area = null
/// The APC associated with this powernet
var/obj/machinery/power/apc/powernet_apc = null
/// Bit Flags indicating special behaviour on this powernet, always powered, never powered, etc
var/power_flags
/// Is the equipment power channel on?
var/equipment_powered = TRUE
/// Is the lighting power channel on?
var/lighting_powered = TRUE
/// Is the environment power channel on?
var/environment_powered = TRUE
/* Passive consumption vars, only change when machines are added/removed from the powernet (not if the power channel turns on/off) */
/// The amount of power consumed by equipment in every power cycle
var/passive_equipment_consumption = 0
/// The amount of power consumed by lighting in every power cycle
var/passive_lighting_consumption = 0
/// The amount of power consumed by environment in every power cycle
var/passive_environment_consumption = 0
/* Active consumption vars, changed when machines need spurts of power, unlike passive consumption these reset to 0 every process() cycle */
/// The amount of power consumed by equipment in this power cycle
var/equipment_consumption = 0
/// The amount of power consumed by lighting in this power cycle
var/lighting_consumption = 0
/// The amount of power consumed by environment in this power cycle
var/environment_consumption = 0
/* Total consumption vars, tracking vars that only count aggregate consumption from active power channels */
/// The amount of the total power consumed passively in power cycles (i.e, each cycle), does not include power channels that are off
var/passive_consumption = 0
/// The amount of total power consumed consumed in only this cycle
var/active_consumption = 0
/// All machines registered to this local powernet, strictly typed to machines, everything else needs to register power change signals
var/list/registered_machines = list()
/// tethers a machine to this local powernet
/datum/local_powernet/proc/register_machine(obj/machinery/machine)
if(machine in registered_machines)
machine.power_change() // this is probably what they wanted anyway by calling this proc
log_debug("[machine] try to register to [powernet_apc]'s local powernet but was already registered!")
return
// machines ref'd in this list should clear themselves from it in destroy(), no need for signals here
machine.machine_powernet = src
registered_machines += machine
machine.power_change()
/// untethers a machine to this local powernet
/datum/local_powernet/proc/unregister_machine(obj/machinery/machine)
if(!(machine in registered_machines))
return
machine.machine_powernet = null
registered_machines -= machine
machine.power_change()
/**
* # power_change
*
* Called when the area power status changes
* calls power change on all machines in the area, and sends the `COMSIG_POWERNET_POWER_CHANGE` signal.
*/
/datum/local_powernet/proc/power_change()
for(var/obj/machinery/M as anything in registered_machines) // for each machine in the area
M.power_change() // reverify power status (to update icons etc.)
SEND_SIGNAL(src, COMSIG_POWERNET_POWER_CHANGE)
/// sets a power channel on or off and adjusts total power usage accordingly
/datum/local_powernet/proc/set_power_channel(channel, new_state)
switch(channel)
if(PW_CHANNEL_EQUIPMENT)
if(equipment_powered == new_state)
return
passive_consumption += (passive_equipment_consumption * (new_state ? 1 : -1))
equipment_powered = new_state
if(PW_CHANNEL_LIGHTING)
if(lighting_powered == new_state)
return
passive_consumption += (passive_lighting_consumption * (new_state ? 1 : -1))
lighting_powered = new_state
if(PW_CHANNEL_ENVIRONMENT)
if(environment_powered == new_state)
return
passive_consumption += (passive_environment_consumption * (new_state ? 1 : -1))
environment_powered = new_state
power_change()
/// checks to see if the given channel in this local powernet has power
/datum/local_powernet/proc/has_power(channel)
if(power_flags & PW_ALWAYS_UNPOWERED) //if this local powernet can never be powered, always return FALSE
return FALSE
if(power_flags & PW_ALWAYS_POWERED) //if this powernet is always powered, we always return TRUE
return TRUE
if(powernet_apc?.stat & (BROKEN|MAINT)) //no working apc, no power
return FALSE
switch(channel)
if(PW_CHANNEL_EQUIPMENT)
return equipment_powered
if(PW_CHANNEL_LIGHTING)
return lighting_powered
if(PW_CHANNEL_ENVIRONMENT)
return environment_powered
return FALSE
/// Add active power usage to the given channel, returns FALSE is channel cannot be found or the channel does not have power to give
/datum/local_powernet/proc/use_active_power(channel, amount)
if(!has_power(channel))
return FALSE
if(power_flags & PW_ALWAYS_POWERED)
return TRUE //we check here as well because we want to skip calculations if we will always have power
switch(channel)
if(PW_CHANNEL_EQUIPMENT)
equipment_consumption += amount
if(PW_CHANNEL_LIGHTING)
lighting_consumption += amount
if(PW_CHANNEL_ENVIRONMENT)
environment_consumption += amount
else
return FALSE
active_consumption += amount
return TRUE
/// Adjust static power for a specified channel, does not check to see if channel has power flowing into it
/datum/local_powernet/proc/adjust_static_power(channel, amount)
if(power_flags & PW_ALWAYS_POWERED)
return TRUE //we check here as well because we want to skip calculations if we will always have power
switch(channel)
if(PW_CHANNEL_EQUIPMENT)
passive_equipment_consumption += amount
if(PW_CHANNEL_LIGHTING)
passive_lighting_consumption += amount
if(PW_CHANNEL_ENVIRONMENT)
passive_environment_consumption += amount
else
return FALSE
if(has_power(channel)) // our total consumption vars don't track unpowered channels, so don't change the var if there's no power
passive_consumption += amount
return TRUE
/datum/local_powernet/proc/get_total_usage()
return passive_consumption + active_consumption
/// returns active + passive power of a channel, if the channel is not powered it returns 0 watts
/datum/local_powernet/proc/get_channel_usage(channel)
switch(channel)
if(PW_CHANNEL_EQUIPMENT)
return equipment_powered ? passive_equipment_consumption + equipment_consumption : 0
if(PW_CHANNEL_LIGHTING)
return lighting_powered ? passive_lighting_consumption + lighting_consumption : 0
if(PW_CHANNEL_ENVIRONMENT)
return environment_powered ? passive_environment_consumption + environment_consumption : 0
/datum/local_powernet/proc/clear_usage()
equipment_consumption = 0
lighting_consumption = 0
environment_consumption = 0
active_consumption = 0
/// Handles flicker operations for apc processing, will flicker machines and lights in the powernet's area by random chance
/datum/local_powernet/proc/handle_flicker()
if(prob(MACHINE_FLICKER_CHANCE))
powernet_apc?.flicker()
// lights don't have their own processing loop, so local powernets will be the father they never had. 3x as likely to cause a light flicker in a particular area, pick a light to flicker at random
if(prob(MACHINE_FLICKER_CHANCE * 3))
var/list/lights = list()
for(var/obj/machinery/light/L in powernet_area)
lights += L
if(length(lights))
var/obj/machinery/light/picked_light = pick(lights)
ASSERT(istype(picked_light))
picked_light.flicker()