mirror of
https://github.com/PolarisSS13/Polaris.git
synced 2025-12-19 14:42:25 +00:00
auto_use_power only shows up in the master_controller following code: *************** for(var/obj/machinery/machine in machines) if(machine) machine.process() if(machine && machine.use_power) machine.auto_use_power() *************** on the second line it checks if machine exists. If it doesn't exit it would go to the next machine. So it is not null at this point. then it calls machine.process()... on the fourth line it cehcks again if the machine exists. Then it calls machine.auto_use_power() So at this point the machine has been checked twice for existence. Now moving into aut_use_power() proc ********************* /obj/machinery/proc/auto_use_power() if(!powered(power_channel)) return 0 if(src.use_power == 1) use_power(idle_power_usage,power_channel) else if(src.use_power >= 2) use_power(active_power_usage,power_channel) return 1 ********************* This calls powered() on the second line. now stepping into powered() proc ************************** /obj/machinery/proc/powered(var/chan = EQUIP) var/area/A = src.loc.loc // make sure it's in an area if(!A || !isarea(A)) return 0 // if not, then not powered return A.master.powered(chan) // return power status of the area ************************** the second line "var/area/A = src.loc.loc" line 26 in power.dm is what caused the problem. It is asking for the location. src.loc appears to be null. The reason why this call keeps happening and doesn't stop is because the object itself exists but its location does not. So my final analysis is that src.loc == null and calling loc on src.loc gives us a runtime error since src.loc.loc == null.loc and null cannot call loc. runtime error: Cannot read null.loc proc name: powered (/obj/machinery/proc/powered) source file: power.dm,26 usr: null src: Emitter (/obj/machinery/emitter) call stack: Emitter (/obj/machinery/emitter): powered(1) Emitter (/obj/machinery/emitter): auto use power() /datum/controller/game_control... (/datum/controller/game_controller): process() /datum/controller/game_control... (/datum/controller/game_controller): process() git-svn-id: http://tgstation13.googlecode.com/svn/trunk@1932 316c924e-a436-60f5-8080-3fe189b3f50e
487 lines
12 KiB
Plaintext
487 lines
12 KiB
Plaintext
// 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)
|
|
powernet.newload += amount
|
|
|
|
/obj/machinery/power/proc/surplus()
|
|
if(powernet)
|
|
return powernet.avail-powernet.load
|
|
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 equipment channel
|
|
|
|
/obj/machinery/proc/powered(var/chan = EQUIP)
|
|
|
|
if(!src.loc)
|
|
return 0
|
|
|
|
var/area/A = src.loc.loc // make sure it's in an area
|
|
if(!A || !isarea(A))
|
|
return 0 // if not, then not powered
|
|
|
|
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=EQUIP) // defaults to Equipment channel
|
|
var/area/A = src.loc.loc // make sure it's in an area
|
|
if(!A || !isarea(A))
|
|
return
|
|
|
|
A.master.use_power(amount, chan)
|
|
|
|
/obj/machinery/proc/power_change() // called whenever the power settings of the containing area change
|
|
// by default, check equipment channel & set flag
|
|
// can override if needed
|
|
if(powered())
|
|
stat &= ~NOPOWER
|
|
else
|
|
|
|
stat |= NOPOWER
|
|
return
|
|
|
|
|
|
// the powernet datum
|
|
// each contiguous network of cables & nodes
|
|
|
|
|
|
// rebuild all power networks from scratch
|
|
|
|
/proc/makepowernets()
|
|
|
|
var/netcount = 0
|
|
powernets = list()
|
|
|
|
for(var/obj/cable/PC in world)
|
|
PC.netnum = 0
|
|
for(var/obj/machinery/power/M in machines)
|
|
if(M.netnum >=0)
|
|
M.netnum = 0
|
|
|
|
|
|
for(var/obj/cable/PC in world)
|
|
if(!PC.netnum)
|
|
PC.netnum = ++netcount
|
|
|
|
if(Debug) world.log << "Starting mpn at [PC.x],[PC.y] ([PC.d1]/[PC.d2]) #[netcount]"
|
|
powernet_nextlink(PC, PC.netnum)
|
|
|
|
if(Debug) world.log << "[netcount] powernets found"
|
|
|
|
for(var/L = 1 to netcount)
|
|
var/datum/powernet/PN = new()
|
|
//PN.tag = "powernet #[L]"
|
|
powernets += PN
|
|
PN.number = L
|
|
|
|
|
|
for(var/obj/cable/C in world)
|
|
var/datum/powernet/PN = powernets[C.netnum]
|
|
PN.cables += C
|
|
|
|
for(var/obj/machinery/power/M in machines)
|
|
if(M.netnum<=0) // APCs have netnum=-1 so they don't count as network nodes directly
|
|
continue
|
|
|
|
M.powernet = powernets[M.netnum]
|
|
M.powernet.nodes += M
|
|
|
|
|
|
// 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 netnum==0
|
|
|
|
/proc/power_list(var/turf/T, var/source, var/d, var/unmarked=0)
|
|
var/list/result = list()
|
|
var/fdir = (!d)? 0 : turn(d, 180) // the opposite direction to d (or 0 if d==0)
|
|
|
|
for(var/obj/machinery/power/P in T)
|
|
if(P.netnum < 0) // exclude APCs
|
|
continue
|
|
|
|
if(P.directwired) // true if this machine covers the whole turf (so can be joined to a cable on neighbour turf)
|
|
if(!unmarked || !P.netnum)
|
|
result += P
|
|
else if(d == 0) // otherwise, need a 0-X cable on same turf to connect
|
|
if(!unmarked || !P.netnum)
|
|
result += P
|
|
|
|
|
|
for(var/obj/cable/C in T)
|
|
if(C.d1 == fdir || C.d2 == fdir)
|
|
if(!unmarked || !C.netnum)
|
|
result += C
|
|
|
|
result -= source
|
|
|
|
return result
|
|
|
|
|
|
/obj/cable/proc/get_connections()
|
|
|
|
var/list/res = list() // this will be a list of all connected power objects
|
|
|
|
var/turf/T
|
|
if(!d1)
|
|
T = src.loc // if d1=0, same turf as src
|
|
else
|
|
T = get_step(src, d1)
|
|
|
|
res += power_list(T, src , d1, 1)
|
|
|
|
T = get_step(src, d2)
|
|
|
|
res += power_list(T, src, d2, 1)
|
|
|
|
return res
|
|
|
|
|
|
/obj/machinery/power/proc/get_connections()
|
|
|
|
if(!directwired)
|
|
return get_indirect_connections()
|
|
|
|
var/list/res = list()
|
|
var/cdir
|
|
|
|
for(var/turf/T in orange(1, src))
|
|
|
|
cdir = get_dir(T, src)
|
|
|
|
for(var/obj/cable/C in T)
|
|
|
|
if(C.netnum)
|
|
continue
|
|
|
|
if(C.d1 == cdir || C.d2 == cdir)
|
|
res += C
|
|
|
|
return res
|
|
|
|
/obj/machinery/power/proc/get_indirect_connections()
|
|
|
|
var/list/res = list()
|
|
|
|
for(var/obj/cable/C in src.loc)
|
|
|
|
if(C.netnum)
|
|
continue
|
|
|
|
if(C.d1 == 0)
|
|
res += C
|
|
|
|
return res
|
|
|
|
|
|
/proc/powernet_nextlink(var/obj/O, var/num)
|
|
|
|
var/list/P
|
|
|
|
//world.log << "start: [O] at [O.x].[O.y]"
|
|
|
|
|
|
while(1)
|
|
|
|
if( istype(O, /obj/cable) )
|
|
var/obj/cable/C = O
|
|
|
|
C.netnum = num
|
|
P = C.get_connections()
|
|
|
|
else if( istype(O, /obj/machinery/power) )
|
|
|
|
var/obj/machinery/power/M = O
|
|
|
|
M.netnum = num
|
|
P = M.get_connections()
|
|
|
|
if(P.len == 0)
|
|
//world.log << "end1"
|
|
return
|
|
|
|
O = P[1]
|
|
|
|
|
|
for(var/L = 2 to P.len)
|
|
|
|
powernet_nextlink(P[L], num)
|
|
|
|
//world.log << "next: [O] at [O.x].[O.y]"
|
|
|
|
|
|
// cut a powernet at this cable object
|
|
|
|
/datum/powernet/proc/cut_cable(var/obj/cable/C)
|
|
|
|
var/turf/T1 = C.loc
|
|
if(C.d1)
|
|
T1 = get_step(C, C.d1)
|
|
|
|
var/turf/T2 = get_step(C, C.d2)
|
|
|
|
var/list/P1 = power_list(T1, C, C.d1) // what joins on to cut cable in dir1
|
|
|
|
var/list/P2 = power_list(T2, C, C.d2) // what joins on to cut cable in dir2
|
|
|
|
if(Debug)
|
|
for(var/obj/O in P1)
|
|
world.log << "P1: [O] at [O.x] [O.y] : [istype(O, /obj/cable) ? "[O:d1]/[O:d2]" : null] "
|
|
for(var/obj/O in P2)
|
|
world.log << "P2: [O] at [O.x] [O.y] : [istype(O, /obj/cable) ? "[O:d1]/[O:d2]" : null] "
|
|
|
|
|
|
|
|
if(P1.len == 0 || P2.len ==0) // if nothing in either list, then the cable was an endpoint
|
|
// no need to rebuild the powernet, just remove cut cable from the list
|
|
cables -= C
|
|
if(Debug) world.log << "Was end of cable"
|
|
return
|
|
|
|
// zero the netnum of all cables & nodes in this powernet
|
|
|
|
for(var/obj/cable/OC in cables)
|
|
OC.netnum = 0
|
|
for(var/obj/machinery/power/OM in nodes)
|
|
OM.netnum = 0
|
|
|
|
|
|
// remove the cut cable from the network
|
|
C.netnum = -1
|
|
C.loc = null
|
|
cables -= C
|
|
|
|
|
|
|
|
powernet_nextlink(P1[1], number) // propagate network from 1st side of cable, using current netnum
|
|
|
|
// now test to see if propagation reached to the other side
|
|
// if so, then there's a loop in the network
|
|
|
|
var/notlooped = 0
|
|
for(var/obj/O in P2)
|
|
if( istype(O, /obj/machinery/power) )
|
|
var/obj/machinery/power/OM = O
|
|
if(OM.netnum != number)
|
|
notlooped = 1
|
|
break
|
|
else if( istype(O, /obj/cable) )
|
|
var/obj/cable/OC = O
|
|
if(OC.netnum != number)
|
|
notlooped = 1
|
|
break
|
|
|
|
if(notlooped)
|
|
|
|
// not looped, so make a new powernet
|
|
|
|
var/datum/powernet/PN = new()
|
|
//PN.tag = "powernet #[L]"
|
|
powernets += PN
|
|
PN.number = powernets.len
|
|
|
|
if(Debug) world.log << "Was not looped: spliting PN#[number] ([cables.len];[nodes.len])"
|
|
|
|
for(var/obj/cable/OC in cables)
|
|
|
|
if(!OC.netnum) // non-connected cables will have netnum==0, since they weren't reached by propagation
|
|
|
|
OC.netnum = PN.number
|
|
cables -= OC
|
|
PN.cables += OC // remove from old network & add to new one
|
|
|
|
for(var/obj/machinery/power/OM in nodes)
|
|
if(!OM.netnum)
|
|
OM.netnum = PN.number
|
|
OM.powernet = PN
|
|
nodes -= OM
|
|
PN.nodes += OM // same for power machines
|
|
|
|
if(Debug)
|
|
world.log << "Old PN#[number] : ([cables.len];[nodes.len])"
|
|
world.log << "New PN#[PN.number] : ([PN.cables.len];[PN.nodes.len])"
|
|
|
|
else
|
|
if(Debug)
|
|
world.log << "Was looped."
|
|
//there is a loop, so nothing to be done
|
|
return
|
|
|
|
return
|
|
|
|
|
|
|
|
/datum/powernet/proc/reset()
|
|
load = newload
|
|
newload = 0
|
|
avail = newavail
|
|
newavail = 0
|
|
|
|
|
|
viewload = 0.8*viewload + 0.2*load
|
|
|
|
viewload = round(viewload)
|
|
|
|
var/numapc = 0
|
|
|
|
if(nodes) // Added to fix a bad list bug -- TLE
|
|
for(var/obj/machinery/power/terminal/term in nodes)
|
|
if( istype( term.master, /obj/machinery/power/apc ) )
|
|
numapc++
|
|
|
|
if(numapc)
|
|
perapc = avail/numapc
|
|
|
|
netexcess = avail - load
|
|
|
|
if( netexcess > 100) // 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
|
|
|
|
/datum/powernet/proc/get_electrocute_damage()
|
|
switch(avail)
|
|
if (1300000 to INFINITY)
|
|
return min(rand(70,150),rand(70,150))
|
|
if (750000 to 1300000)
|
|
return min(rand(50,115),rand(50,115))
|
|
if (100000 to 750000-1)
|
|
return min(rand(35,101),rand(35,101))
|
|
if (75000 to 100000-1)
|
|
return min(rand(30,95),rand(30,95))
|
|
if (50000 to 75000-1)
|
|
return min(rand(25,80),rand(25,80))
|
|
if (25000 to 50000-1)
|
|
return min(rand(20,70),rand(20,70))
|
|
if (10000 to 25000-1)
|
|
return min(rand(20,65),rand(20,65))
|
|
if (1000 to 10000-1)
|
|
return min(rand(10,20),rand(10,20))
|
|
else
|
|
return 0
|
|
|
|
/datum/powernet/proc/merge_powernets(var/datum/powernet/P)
|
|
// The powernet that calls this proc will consume the other powernet - Rockdtben
|
|
|
|
if(src == P)
|
|
return
|
|
|
|
if(nodes.len >= P.nodes.len)
|
|
nodes += P.nodes
|
|
else
|
|
P.nodes += nodes
|
|
nodes = P.nodes
|
|
for(var/obj/machinery/power/M in nodes)
|
|
M.netnum = number
|
|
M.powernet = powernets[M.netnum] // Thanks to Derp__
|
|
|
|
|
|
if(cables.len >= P.cables.len)
|
|
cables += P.cables
|
|
else
|
|
P.cables += cables
|
|
cables = P.cables
|
|
for(var/obj/cable/C in cables)
|
|
C.netnum = number
|
|
del P
|
|
|
|
/obj/machinery/power/proc/connect_to_network()
|
|
var/turf/T = src.loc
|
|
var/obj/cable/C = T.get_cable_node()
|
|
if (!C || !C.netnum)
|
|
return
|
|
makepowernets() //TODO: find fast way
|
|
|
|
/obj/machinery/power/proc/disconnect_from_network()
|
|
//TODO: dunno how to do that
|
|
return
|
|
|
|
/turf/proc/get_cable_node()
|
|
if(!istype(src, /turf/simulated/floor))
|
|
return null
|
|
for(var/obj/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,/mob/living/carbon/human))
|
|
var/mob/living/carbon/human/H = M
|
|
if(H.gloves)
|
|
var/obj/item/clothing/gloves/G = H.gloves
|
|
var/siem_coef = G.siemens_coefficient
|
|
if(siem_coef == 0) //to avoid spamming with insulated glvoes on
|
|
return 0
|
|
var/area/source_area
|
|
if (istype(power_source,/area))
|
|
source_area = power_source
|
|
power_source = source_area.get_apc()
|
|
if (istype(power_source,/obj/cable))
|
|
var/obj/cable/tmp = power_source
|
|
power_source = powernets[tmp.netnum]
|
|
|
|
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/CELLRATE)
|
|
else if (istype(power_source,/datum/powernet))
|
|
var/drained_power = drained_energy/CELLRATE //convert from "joules" to "watts"
|
|
PN.newload+=drained_power
|
|
else if (istype(power_source, /obj/item/weapon/cell))
|
|
cell.use(drained_energy)
|
|
return drained_energy |