mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-01-06 23:51:43 +00:00
This converts the machine and mob processes to the SMC. Additionally, it adds the Atom subsystem, which handles all Initialize() calls in place of the old gameticker. Due to incompatibility with our atmospherics (FUCK OUR ATMOSPHERICS FOR FUCKING EVER JESUS CHRIST WHO THE FUCK MADE THIS PIECE OF GODDAMN SHIT) atmospherics machines do not use Initialize() as they should, instead opting for a custom atmos_init proc that the air controller handles.
362 lines
10 KiB
Plaintext
362 lines
10 KiB
Plaintext
//////////////////////////////
|
|
// POWER MACHINERY BASE CLASS
|
|
//////////////////////////////
|
|
|
|
/////////////////////////////
|
|
// Definitions
|
|
/////////////////////////////
|
|
|
|
/obj/machinery/power
|
|
name = null
|
|
icon = 'icons/obj/power.dmi'
|
|
anchored = 1.0
|
|
on_blueprints = TRUE
|
|
var/datum/powernet/powernet = null
|
|
use_power = 0
|
|
idle_power_usage = 0
|
|
active_power_usage = 0
|
|
|
|
/obj/machinery/power/Destroy()
|
|
disconnect_from_network()
|
|
return ..()
|
|
|
|
///////////////////////////////
|
|
// General procedures
|
|
//////////////////////////////
|
|
|
|
// common helper procs for all power machines
|
|
/obj/machinery/power/proc/add_avail(var/amount)
|
|
if(powernet)
|
|
powernet.newavail += amount
|
|
|
|
/obj/machinery/power/proc/draw_power(var/amount)
|
|
if(powernet)
|
|
return powernet.draw_power(amount)
|
|
return 0
|
|
|
|
/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
|
|
|
|
/obj/machinery/power/proc/load()
|
|
if(powernet)
|
|
return powernet.load
|
|
else
|
|
return 0
|
|
|
|
/obj/machinery/power/proc/disconnect_terminal() // machines without a terminal will just return, no harm no fowl.
|
|
return
|
|
|
|
// 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) // defaults to power_channel
|
|
|
|
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
|
|
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(var/amount, var/chan = -1) // defaults to power_channel
|
|
var/area/A = get_area(src) // make sure it's in an area
|
|
if(!A || !isarea(A))
|
|
return
|
|
if(chan == -1)
|
|
chan = power_channel
|
|
A.use_power(amount, chan)
|
|
|
|
/obj/machinery/proc/addStaticPower(value, powerchannel)
|
|
var/area/A = get_area(src)
|
|
if(!A)
|
|
return
|
|
A.addStaticPower(value, powerchannel)
|
|
|
|
/obj/machinery/proc/removeStaticPower(value, powerchannel)
|
|
addStaticPower(-value, powerchannel)
|
|
|
|
/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(power_channel))
|
|
stat &= ~NOPOWER
|
|
else
|
|
|
|
stat |= NOPOWER
|
|
return
|
|
|
|
// connect the machine to a powernet if a node cable is present on the turf
|
|
/obj/machinery/power/proc/connect_to_network()
|
|
var/turf/T = src.loc
|
|
if(!T || !istype(T))
|
|
return 0
|
|
|
|
var/obj/structure/cable/C = T.get_cable_node() //check if we have a node cable on the machine turf, the first found is picked
|
|
if(!C || !C.powernet)
|
|
return 0
|
|
|
|
C.powernet.add_machine(src)
|
|
return 1
|
|
|
|
// remove and disconnect the machine from its current powernet
|
|
/obj/machinery/power/proc/disconnect_from_network()
|
|
if(!powernet)
|
|
return 0
|
|
powernet.remove_machine(src)
|
|
return 1
|
|
|
|
// attach a wire to a power machine - leads from the turf you are standing on
|
|
//almost never called, overwritten by all power machines but terminal and generator
|
|
/obj/machinery/power/attackby(obj/item/W, mob/user)
|
|
|
|
if(istype(W, /obj/item/stack/cable_coil))
|
|
|
|
var/obj/item/stack/cable_coil/coil = W
|
|
|
|
var/turf/T = user.loc
|
|
|
|
if(T.intact || !istype(T, /turf/simulated/floor))
|
|
return
|
|
|
|
if(get_dist(src, user) > 1)
|
|
return
|
|
|
|
coil.place_turf(T, user)
|
|
return
|
|
else
|
|
..()
|
|
return
|
|
|
|
///////////////////////////////////////////
|
|
// Powernet handling helpers
|
|
//////////////////////////////////////////
|
|
|
|
//returns all the cables WITHOUT a powernet in neighbors turfs,
|
|
//pointing towards the turf the machine is located at
|
|
/obj/machinery/power/proc/get_connections()
|
|
|
|
. = list()
|
|
|
|
var/cdir
|
|
var/turf/T
|
|
|
|
for(var/card in cardinal)
|
|
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 .
|
|
|
|
//returns all the cables in neighbors turfs,
|
|
//pointing towards the turf the machine is located at
|
|
/obj/machinery/power/proc/get_marked_connections()
|
|
|
|
. = list()
|
|
|
|
var/cdir
|
|
var/turf/T
|
|
|
|
for(var/card in cardinal)
|
|
T = get_step(loc,card)
|
|
cdir = get_dir(T,loc)
|
|
|
|
for(var/obj/structure/cable/C in T)
|
|
if(C.d1 == cdir || C.d2 == cdir)
|
|
. += C
|
|
return .
|
|
|
|
//returns all the NODES (O-X) cables WITHOUT a powernet in the turf the machine is located at
|
|
/obj/machinery/power/proc/get_indirect_connections()
|
|
. = list()
|
|
for(var/obj/structure/cable/C in loc)
|
|
if(C.powernet) continue
|
|
if(C.d1 == 0) // the cable is a node cable
|
|
. += C
|
|
return .
|
|
|
|
///////////////////////////////////////////
|
|
// GLOBAL PROCS for powernets handling
|
|
//////////////////////////////////////////
|
|
|
|
|
|
// 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, var/cable_only = 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
|
|
for(var/AM in T)
|
|
if(AM == source) continue //we don't want to return source
|
|
|
|
if(!cable_only && 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(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 == d || C.d2 == d)
|
|
. += C
|
|
return .
|
|
|
|
//remove the old powernet and replace it with a new one throughout the network.
|
|
/proc/propagate_network(var/obj/O, var/datum/powernet/PN)
|
|
//log_world("propagating new network")
|
|
var/list/worklist = list()
|
|
var/list/found_machines = list()
|
|
var/index = 1
|
|
var/obj/P = null
|
|
|
|
worklist+=O //start propagating from the passed object
|
|
|
|
while(index<=worklist.len) //until we've exhausted all power objects
|
|
P = worklist[index] //get the next power object found
|
|
index++
|
|
|
|
if( istype(P,/obj/structure/cable))
|
|
var/obj/structure/cable/C = P
|
|
if(C.powernet != PN) //add it to the powernet, if it isn't already there
|
|
PN.add_cable(C)
|
|
worklist |= C.get_connections() //get adjacents power objects, with or without a powernet
|
|
|
|
else if(P.anchored && istype(P,/obj/machinery/power))
|
|
var/obj/machinery/power/M = P
|
|
found_machines |= M //we wait until the powernet is fully propagates to connect the machines
|
|
|
|
else
|
|
continue
|
|
|
|
//now that the powernet is set, connect found machines to it
|
|
for(var/obj/machinery/power/PM in found_machines)
|
|
if(!PM.connect_to_network()) //couldn't find a node on its turf...
|
|
PM.disconnect_from_network() //... so disconnect if already on a powernet
|
|
|
|
|
|
//Merge two powernets, the bigger (in cable length term) absorbing the other
|
|
/proc/merge_powernets(var/datum/powernet/net1, var/datum/powernet/net2)
|
|
if(!net1 || !net2) //if one of the powernet doesn't exist, return
|
|
return
|
|
|
|
if(net1 == net2) //don't merge same powernets
|
|
return
|
|
|
|
//We assume net1 is larger. If net2 is in fact larger we are just going to make them switch places to reduce on code.
|
|
if(net1.cables.len < net2.cables.len) //net2 is larger than net1. Let's switch them around
|
|
var/temp = net1
|
|
net1 = net2
|
|
net2 = temp
|
|
|
|
//merge net2 into net1
|
|
for(var/obj/structure/cable/Cable in net2.cables) //merge cables
|
|
net1.add_cable(Cable)
|
|
|
|
if(!net2) return net1
|
|
|
|
for(var/obj/machinery/power/Node in net2.nodes) //merge power machines
|
|
if(!Node.connect_to_network())
|
|
Node.disconnect_from_network() //if somehow we can't connect the machine to the new powernet, disconnect it from the old nonetheless
|
|
|
|
return net1
|
|
|
|
//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))
|
|
return 0
|
|
if(istype(M.loc,/obj/mecha))
|
|
return 0 //feckin mechs are dumb
|
|
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
|
|
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/stock_parts/cell/cell
|
|
|
|
if(istype(power_source,/datum/powernet))
|
|
PN = power_source
|
|
else if(istype(power_source,/obj/item/stock_parts/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"
|
|
drained_power = PN.draw_power(drained_power)
|
|
else if(istype(power_source, /obj/item/stock_parts/cell))
|
|
cell.use(drained_energy)
|
|
return drained_energy
|