Files
BlackMajorandGitHub c9711d4cf8 Replaces the RnG of electric shocks with a more sane calculation (#6213)
TL;DR
Shock damage being an RnG value hard capped at 1MW with "jumps" in
damage at certain breakpoints was weird so I smoothed out the math.
Overall, damage is uncapped but does a little less damage.

Extended answer:
The old method returns burn damage to the victim in a series of five
"tiers" based on the available power at the time.
These tiers roll a random with disadvantage, the thresholds in question
were as follows:
Note that these values are rolled with disadvantage.
1kW to 50kw = 10-20
50kW to 100kW = 15-40
100kW to 200kW = 20-60
200kW to 1MW = 25-80
1MW+ = 50-160

I've replaced the math with a logarithmic that looks like this
burn damage = log(1.1, power) - log(1.1, (log(1.1, power)*1.5))
which results in a smoothed out damage curve with a plateau around 1MW,
as follows:
1kW = 5
10kW = 24
100kW = 45
250kW = 53
1MW = 66
10MW = 88
100MW = 110
1GW = 132
2023-12-22 18:42:56 -08:00

173 lines
5.2 KiB
Plaintext

/datum/powernet
var/list/cables = list() // all cables & junctions
var/list/nodes = list() // all connected machines
/**
* Power tracking
* Units: Kilowatts
*/
var/load = 0 // the current load on the powernet, increased by each machine at processing
var/newavail = 0 // what available power was gathered last tick, then becomes...
var/avail = 0 //...the current available power in the powernet
var/viewavail = 0 // the availability as it appears on the power console (gradually updated)
var/viewload = 0 // the load as it appears on the power console (gradually updated)
var/number = 0 // Unused //TODEL
var/perapc = 0 // per-apc avilability
var/perapc_excess = 0
var/netexcess = 0 // excess power on the powernet (typically avail-load)
var/problem = 0 // If this is not 0 there is some sort of issue in the powernet. Monitors will display warnings.
/datum/powernet/New()
START_PROCESSING_POWERNET(src)
..()
/datum/powernet/Destroy()
for(var/obj/structure/cable/C in cables)
cables -= C
C.powernet = null
for(var/obj/machinery/power/M in nodes)
nodes -= M
M.powernet = null
STOP_PROCESSING_POWERNET(src)
return ..()
//Returns the amount of excess power (before refunding to SMESs) from last tick.
//This is for machines that might adjust their power consumption using this data.
/datum/powernet/proc/last_surplus()
return max(avail - load, 0)
/datum/powernet/proc/draw_power(var/amount)
var/draw = clamp( amount, 0, avail - load)
load += draw
return draw
/datum/powernet/proc/is_empty()
return !cables.len && !nodes.len
//remove a cable from the current powernet
//if the powernet is then empty, delete it
//Warning : this proc DON'T check if the cable exists
/datum/powernet/proc/remove_cable(var/obj/structure/cable/C)
cables -= C
C.powernet = null
if(is_empty())//the powernet is now empty...
qdel(src)///... delete it
//add a cable to the current powernet
//Warning : this proc DON'T check if the cable exists
/datum/powernet/proc/add_cable(var/obj/structure/cable/C)
if(C.powernet)// if C already has a powernet...
if(C.powernet == src)
return
else
C.powernet.remove_cable(C) //..remove it
C.powernet = src
cables +=C
//remove a power machine from the current powernet
//if the powernet is then empty, delete it
//Warning : this proc DON'T check if the machine exists
/datum/powernet/proc/remove_machine(var/obj/machinery/power/M)
nodes -=M
M.powernet = null
if(is_empty())//the powernet is now empty...
qdel(src)///... delete it - qdel
//add a power machine to the current powernet
//Warning : this proc DON'T check if the machine exists
/datum/powernet/proc/add_machine(var/obj/machinery/power/M)
if(M.powernet)// if M already has a powernet...
if(M.powernet == src)
return
else
M.disconnect_from_network()//..remove it
M.powernet = src
nodes[M] = M
// Triggers warning for certain amount of ticks
/datum/powernet/proc/trigger_warning(var/duration_ticks = 20)
problem = max(duration_ticks, problem)
//handles the power changes in the powernet
//called every ticks by the powernet controller
/datum/powernet/proc/reset()
var/numapc = 0
if(problem > 0)
problem = max(problem - 1, 0)
if(nodes && nodes.len) // 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++
netexcess = avail - load
if(numapc)
//very simple load balancing. If there was a net excess this tick then it must have been that some APCs used less than perapc, since perapc*numapc = avail
//Therefore we can raise the amount of power rationed out to APCs on the assumption that those APCs that used less than perapc will continue to do so.
//If that assumption fails, then some APCs will miss out on power next tick, however it will be rebalanced for the tick after.
if (netexcess >= 0)
perapc_excess += min(netexcess/numapc, (avail - perapc) - perapc_excess)
else
perapc_excess = 0
perapc = avail/numapc + perapc_excess
if(netexcess > 100 && nodes && nodes.len) // 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
//updates the viewed load (as seen on power computers)
viewavail = round(0.8 * viewavail + 0.2 * avail)
viewload = round(0.8 * viewload + 0.2 * load)
//reset the powernet
load = 0
avail = newavail
newavail = 0
/datum/powernet/proc/get_electrocute_damage()
//1kW = 5
//10kW = 24
//100kW = 45
//250kW = 53
//1MW = 66
//10MW = 88
//100MW = 110
//1GW = 132
if(avail >= 1000)
var/damage = log(1.1,avail)
damage = damage - (log(1.1,damage)*1.5)
return round(damage)
else
return 0
/datum/powernet/proc/drain_energy_handler(datum/actor, amount, flags)
// amount is in kj so no conversion needed
. = draw_power(amount)
if(flags & ENERGY_DRAIN_SURGE)
trigger_warning()
////////////////////////////////////////////////
// Misc.
///////////////////////////////////////////////
// return a knot cable (O-X) if one is present in the turf
// null if there's none
/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()
return apc