mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
- Fixes issues caused when makepowernets() was somehow called. - Substations (or read, breakerboxes) work properly now. Tested. - Powernets no longer decide to randomly stop working when stuff is being modified. - Mostly temporary fix until next devmerge which will (hopefully) add /tg/ powernet code.
342 lines
9.8 KiB
Plaintext
342 lines
9.8 KiB
Plaintext
/obj/machinery/power
|
|
name = null
|
|
icon = 'icons/obj/power.dmi'
|
|
anchored = 1.0
|
|
var/datum/powernet/powernet = null
|
|
var/directwired = 1 // by default, power machines are connected by a cable in a neighbouring turf
|
|
// if set to 0, requires a 0-X cable on this turf
|
|
use_power = 0
|
|
idle_power_usage = 0
|
|
active_power_usage = 0
|
|
|
|
/obj/machinery/power/Del()
|
|
disconnect_from_network()
|
|
..()
|
|
|
|
// common helper procs for all power machines
|
|
/obj/machinery/power/proc/add_avail(var/amount)
|
|
if(powernet)
|
|
powernet.newavail += amount
|
|
|
|
/obj/machinery/power/proc/add_load(var/amount)
|
|
if(powernet)
|
|
return powernet.draw_power(amount)
|
|
return 0
|
|
|
|
/obj/machinery/power/proc/surplus()
|
|
if(powernet)
|
|
return powernet.surplus()
|
|
else
|
|
return 0
|
|
|
|
/obj/machinery/power/proc/avail()
|
|
if(powernet)
|
|
return powernet.avail
|
|
else
|
|
return 0
|
|
|
|
// returns true if the area has power on given channel (or doesn't require power).
|
|
// defaults to power_channel
|
|
|
|
/obj/machinery/proc/powered(var/chan = -1)
|
|
|
|
if(!src.loc)
|
|
return 0
|
|
|
|
//This is bad. This makes machines which are switched off not update their stat flag correctly when power_change() is called.
|
|
//If use_power is 0, then you probably shouldn't be checking power to begin with.
|
|
//if(!use_power)
|
|
// return 1
|
|
|
|
var/area/A = src.loc.loc // make sure it's in an area
|
|
if(!A || !isarea(A) || !A.master)
|
|
return 0 // if not, then not powered
|
|
if(chan == -1)
|
|
chan = power_channel
|
|
return A.master.powered(chan) // return power status of the area
|
|
|
|
// increment the power usage stats for an area
|
|
|
|
/obj/machinery/proc/use_power(var/amount, var/chan = -1, var/autocalled = 0) // defaults to power_channel
|
|
var/area/A = src.loc.loc // make sure it's in an area
|
|
if(!A || !isarea(A) || !A.master)
|
|
return
|
|
if(chan == -1)
|
|
chan = power_channel
|
|
A.master.use_power(amount, chan)
|
|
if(!autocalled)
|
|
log_power_update_request(A.master, src)
|
|
A.master.powerupdate = 2 // Decremented by 2 each GC tick, since it's not auto power change we're going to update power twice.
|
|
return 1
|
|
|
|
//The master_area optional argument can be used to save on a lot of processing if the master area is already known. This is mainly intended for when this proc is called by the master controller.
|
|
/obj/machinery/proc/power_change(var/area/master_area = null) // called whenever the power settings of the containing area change
|
|
// by default, check equipment channel & set flag
|
|
// can override if needed
|
|
var/has_power
|
|
if (master_area)
|
|
has_power = master_area.powered(power_channel)
|
|
else
|
|
has_power = powered(power_channel)
|
|
|
|
if(has_power)
|
|
stat &= ~NOPOWER
|
|
else
|
|
stat |= NOPOWER
|
|
|
|
// the powernet datum
|
|
// each contiguous network of cables & nodes
|
|
|
|
|
|
// rebuild all power networks from scratch
|
|
|
|
/hook/startup/proc/buildPowernets()
|
|
return makepowernets()
|
|
|
|
/proc/makepowernets()
|
|
for(var/datum/powernet/PN in powernets)
|
|
del(PN)
|
|
powernets.Cut()
|
|
|
|
for(var/obj/structure/cable/PC in cable_list)
|
|
if(!PC.powernet)
|
|
PC.powernet = new()
|
|
powernets += PC.powernet
|
|
// if(Debug) world.log << "Starting mpn at [PC.x],[PC.y] ([PC.d1]/[PC.d2])"
|
|
powernet_nextlink(PC,PC.powernet)
|
|
|
|
// if(Debug) world.log << "[powernets.len] powernets found"
|
|
|
|
for(var/obj/structure/cable/C in cable_list)
|
|
if(!C.powernet) continue
|
|
C.powernet.cables += C
|
|
|
|
for(var/obj/machinery/power/M in machines)
|
|
M.connect_to_network()
|
|
|
|
return 1
|
|
|
|
|
|
// returns a list of all power-related objects (nodes, cable, junctions) in turf,
|
|
// excluding source, that match the direction d
|
|
// if unmarked==1, only return those with no powernet
|
|
/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0)
|
|
. = list()
|
|
var/fdir = (!d)? 0 : turn(d, 180)
|
|
// the opposite direction to d (or 0 if d==0)
|
|
///// Z-Level Stuff
|
|
var/Zdir
|
|
if(d==11)
|
|
Zdir = 11
|
|
else if (d==12)
|
|
Zdir = 12
|
|
else
|
|
Zdir = 999
|
|
///// Z-Level Stuff
|
|
// world.log << "d=[d] fdir=[fdir]"
|
|
for(var/AM in T)
|
|
if(AM == source) continue //we don't want to return source
|
|
|
|
if(istype(AM,/obj/machinery/power))
|
|
var/obj/machinery/power/P = AM
|
|
if(P.powernet == 0) continue // exclude APCs which have powernet=0
|
|
|
|
if(!unmarked || !P.powernet) //if unmarked=1 we only return things with no powernet
|
|
if(P.directwired || (d == 0))
|
|
. += P
|
|
|
|
else if(istype(AM,/obj/structure/cable))
|
|
var/obj/structure/cable/C = AM
|
|
|
|
if(!unmarked || !C.powernet)
|
|
///// Z-Level Stuff
|
|
if(C.d1 == fdir || C.d2 == fdir || C.d1 == Zdir || C.d2 == Zdir)
|
|
///// Z-Level Stuff
|
|
. += C
|
|
else if(C.d1 == turn(C.d2, 180))
|
|
. += C
|
|
return .
|
|
|
|
|
|
/obj/structure/cable/proc/get_connections()
|
|
. = list() // this will be a list of all connected power objects
|
|
var/turf/T = loc
|
|
|
|
///// Z-Level Stuff
|
|
if(d1)
|
|
if(d1 <= 10)
|
|
T = get_step(src, d1)
|
|
if(T)
|
|
. += power_list(T, src, d1, 1)
|
|
else if (d1 == 11 || d1 == 12)
|
|
var/turf/controllerlocation = locate(1, 1, z)
|
|
for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
|
|
if(controller.up && d1 == 12)
|
|
T = locate(src.x, src.y, controller.up_target)
|
|
if(T)
|
|
. += power_list(T, src, 11, 1)
|
|
if(controller.down && d1 == 11)
|
|
T = locate(src.x, src.y, controller.down_target)
|
|
if(T)
|
|
. += power_list(T, src, 12, 1)
|
|
else if(!d1)
|
|
if(T)
|
|
. += power_list(T, src, d1, 1)
|
|
|
|
if(d2 == 11 || d2 == 12)
|
|
var/turf/controllerlocation = locate(1, 1, z)
|
|
for(var/obj/effect/landmark/zcontroller/controller in controllerlocation)
|
|
if(controller.up && d2 == 12)
|
|
T = locate(src.x, src.y, controller.up_target)
|
|
if(T)
|
|
. += power_list(T, src, 11, 1)
|
|
if(controller.down && d2 == 11)
|
|
T = locate(src.x, src.y, controller.down_target)
|
|
if(T)
|
|
. += power_list(T, src, 12, 1)
|
|
else
|
|
T = get_step(src, d2)
|
|
if(T)
|
|
. += power_list(T, src, d2, 1)
|
|
///// Z-Level Stuff
|
|
|
|
return .
|
|
|
|
|
|
/obj/machinery/power/proc/get_connections()
|
|
|
|
. = list()
|
|
|
|
if(!directwired)
|
|
return get_indirect_connections()
|
|
|
|
var/cdir
|
|
|
|
for(var/card in cardinal)
|
|
var/turf/T = get_step(loc,card)
|
|
cdir = get_dir(T,loc)
|
|
|
|
for(var/obj/structure/cable/C in T)
|
|
if(C.powernet) continue
|
|
if(C.d1 == cdir || C.d2 == cdir)
|
|
. += C
|
|
return .
|
|
|
|
/obj/machinery/power/proc/get_indirect_connections()
|
|
. = list()
|
|
for(var/obj/structure/cable/C in loc)
|
|
if(C.powernet) continue
|
|
if(C.d1 == 0)
|
|
. += C
|
|
return .
|
|
|
|
/obj/machinery/power/proc/connect_to_network()
|
|
// First disconnect us from the old powernet
|
|
if(powernet)
|
|
powernet.nodes -= src
|
|
powernet = null
|
|
// Then find any cables on our location
|
|
var/turf/T = src.loc
|
|
var/obj/structure/cable/C = T.get_cable_node()
|
|
if(!C || !C.powernet) return 0
|
|
// And connect us to their powernet
|
|
powernet = C.powernet
|
|
powernet.nodes += src
|
|
return 1
|
|
|
|
/obj/machinery/power/proc/disconnect_from_network()
|
|
if(!powernet)
|
|
//world << " no powernet"
|
|
return 0
|
|
powernet.nodes -= src
|
|
powernet = null
|
|
//world << "powernet null"
|
|
return 1
|
|
|
|
/turf/proc/get_cable_node()
|
|
if(!istype(src, /turf/simulated/floor))
|
|
return null
|
|
for(var/obj/structure/cable/C in src)
|
|
if(C.d1 == 0)
|
|
return C
|
|
return null
|
|
|
|
/area/proc/get_apc()
|
|
for(var/area/RA in src.related)
|
|
var/obj/machinery/power/apc/FINDME = locate() in RA
|
|
if (FINDME)
|
|
return FINDME
|
|
|
|
|
|
//Determines how strong could be shock, deals damage to mob, uses power.
|
|
//M is a mob who touched wire/whatever
|
|
//power_source is a source of electricity, can be powercell, area, apc, cable, powernet or null
|
|
//source is an object caused electrocuting (airlock, grille, etc)
|
|
//No animations will be performed by this proc.
|
|
/proc/electrocute_mob(mob/living/carbon/M as mob, var/power_source, var/obj/source, var/siemens_coeff = 1.0)
|
|
if(istype(M.loc,/obj/mecha)) return 0 //feckin mechs are dumb
|
|
|
|
//This is for performance optimization only.
|
|
//DO NOT modify siemens_coeff here. That is checked in human/electrocute_act()
|
|
if(istype(M,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = M
|
|
if(H.species.insulated)
|
|
return 0
|
|
else if(H.gloves)
|
|
var/obj/item/clothing/gloves/G = H.gloves
|
|
if(G.siemens_coefficient == 0)
|
|
return 0 //to avoid spamming with insulated glvoes on
|
|
|
|
var/area/source_area
|
|
if(istype(power_source,/area))
|
|
source_area = power_source
|
|
power_source = source_area.get_apc()
|
|
if(istype(power_source,/obj/structure/cable))
|
|
var/obj/structure/cable/Cable = power_source
|
|
power_source = Cable.powernet
|
|
|
|
var/datum/powernet/PN
|
|
var/obj/item/weapon/cell/cell
|
|
|
|
if(istype(power_source,/datum/powernet))
|
|
PN = power_source
|
|
else if(istype(power_source,/obj/item/weapon/cell))
|
|
cell = power_source
|
|
else if(istype(power_source,/obj/machinery/power/apc))
|
|
var/obj/machinery/power/apc/apc = power_source
|
|
cell = apc.cell
|
|
if (apc.terminal)
|
|
PN = apc.terminal.powernet
|
|
else if (!power_source)
|
|
return 0
|
|
else
|
|
log_admin("ERROR: /proc/electrocute_mob([M], [power_source], [source]): wrong power_source")
|
|
return 0
|
|
if (!cell && !PN)
|
|
return 0
|
|
var/PN_damage = 0
|
|
var/cell_damage = 0
|
|
if (PN)
|
|
PN_damage = PN.get_electrocute_damage()
|
|
if (cell)
|
|
cell_damage = cell.get_electrocute_damage()
|
|
var/shock_damage = 0
|
|
if (PN_damage>=cell_damage)
|
|
power_source = PN
|
|
shock_damage = PN_damage
|
|
else
|
|
power_source = cell
|
|
shock_damage = cell_damage
|
|
var/drained_hp = M.electrocute_act(shock_damage, source, siemens_coeff) //zzzzzzap!
|
|
var/drained_energy = drained_hp*20
|
|
|
|
if (source_area)
|
|
source_area.use_power(drained_energy)
|
|
else if (istype(power_source,/datum/powernet))
|
|
//var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts" <<< NO. THIS IS WRONG. CELLRATE DOES NOT CONVERT TO OR FROM JOULES.
|
|
PN.draw_power(drained_energy)
|
|
else if (istype(power_source, /obj/item/weapon/cell))
|
|
cell.use(drained_energy*CELLRATE) //convert to units of charge.
|
|
return drained_energy
|
|
|