mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-23 13:05:44 +01:00
Implement powersink surge (#2452)
Implements suggestion https://forums.aurorastation.org/viewtopic.php?f=21&p=78011 in the following fashion: Powersinks explode ~18 minutes after being placed on normal SMES setup. Obviously more input from engineering will make this process go faster. Upon reaching their capacity, they will now cause a larger area power surge. The surge will smash all lights belonging to APCs within close to moderate proximity, and call EMP act on all connected powernet items that are within range (severity depending on distance). All of those items have a small chance to cause a minor explosion as well, primarily because EMP act is fucking whimpy.
This commit is contained in:
@@ -25,4 +25,21 @@
|
||||
#define INFINITY 1.#INF
|
||||
|
||||
#define TICKS_IN_DAY 24*60*60*10
|
||||
#define TICKS_IN_SECOND 10
|
||||
#define TICKS_IN_SECOND 10
|
||||
|
||||
// A neat little helper to convert the value X, that's between imin and imax, into a value
|
||||
// that's proportionally scaled and in range of omin and omax.
|
||||
#define MAP(x, imin, imax, omin, omax) ((x - imin) * (omax - omin) / (imax - imin) + omin)
|
||||
|
||||
#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW)
|
||||
|
||||
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
|
||||
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
|
||||
//collapsed to percent_of_tick_used * tick_lag
|
||||
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
|
||||
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(world.tick_usage-starting_tickusage))
|
||||
|
||||
//time of day but automatically adjusts to the server going into the next day within the same round.
|
||||
//for when you need a reliable time number that doesn't depend on byond time.
|
||||
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
|
||||
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
|
||||
|
||||
+6
-19
@@ -1,6 +1,3 @@
|
||||
// Macro functions.
|
||||
#define RAND_F(LOW, HIGH) (rand()*(HIGH-LOW) + LOW)
|
||||
|
||||
// min is inclusive, max is exclusive
|
||||
/proc/Wrap(val, min, max)
|
||||
var/d = max - min
|
||||
@@ -124,24 +121,14 @@
|
||||
return sqrt(squaredNorm(x, y))
|
||||
|
||||
/proc/IsPowerOfTwo(var/val)
|
||||
return (val & (val-1)) == 0
|
||||
return (val & (val-1)) == 0
|
||||
|
||||
/proc/RoundUpToPowerOfTwo(var/val)
|
||||
return 2 ** -round(-log(2,val))
|
||||
|
||||
//"fancy" math for calculating time in ms from tick_usage percentage and the length of ticks
|
||||
//percent_of_tick_used * (ticklag * 100(to convert to ms)) / 100(percent ratio)
|
||||
//collapsed to percent_of_tick_used * tick_lag
|
||||
#define TICK_DELTA_TO_MS(percent_of_tick_used) ((percent_of_tick_used) * world.tick_lag)
|
||||
#define TICK_USAGE_TO_MS(starting_tickusage) (TICK_DELTA_TO_MS(world.tick_usage-starting_tickusage))
|
||||
|
||||
//time of day but automatically adjusts to the server going into the next day within the same round.
|
||||
//for when you need a reliable time number that doesn't depend on byond time.
|
||||
#define REALTIMEOFDAY (world.timeofday + (MIDNIGHT_ROLLOVER * MIDNIGHT_ROLLOVER_CHECK))
|
||||
#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
|
||||
return 2 ** -round(-log(2,val))
|
||||
|
||||
//Returns the cube root of the input number
|
||||
/proc/cubert(var/num, var/iterations = 10)
|
||||
. = num
|
||||
for (var/i = 0, i < iterations, i++)
|
||||
. = (1/3) * (num/(.**2)+2*.)
|
||||
. = num
|
||||
for (var/i = 0, i < iterations, i++)
|
||||
. = (1/3) * (num/(.**2)+2*.)
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
var/apc_drain_rate = 5000 // Max. amount drained from single APC. In Watts.
|
||||
var/dissipation_rate = 20000 // Passive dissipation of drained power. In Watts.
|
||||
var/power_drained = 0 // Amount of power drained.
|
||||
var/max_power = 5e9 // Detonation point.
|
||||
var/max_power = 8e8 // Detonation point. Roughly 18 minutes with default setup.
|
||||
var/mode = 0 // 0 = off, 1=clamped (off), 2=operating
|
||||
var/drained_this_tick = 0 // This is unfortunately necessary to ensure we process powersinks BEFORE other machinery such as APCs.
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
|
||||
/obj/item/device/powersink/Destroy()
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
processing_power_items.Remove(src)
|
||||
processing_power_items -= src
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/item/device/powersink/attackby(var/obj/item/I, var/mob/user)
|
||||
@@ -37,15 +38,15 @@
|
||||
if(isturf(T) && !!T.is_plating())
|
||||
attached = locate() in T
|
||||
if(!attached)
|
||||
user << "No exposed cable here to attach to."
|
||||
to_chat(user, "<span class='warning'>No exposed cable here to attach to.</span>")
|
||||
return
|
||||
else
|
||||
anchored = 1
|
||||
mode = 1
|
||||
src.visible_message("<span class='notice'>[user] attaches [src] to the cable!</span>")
|
||||
visible_message("<span class='notice'>\The [user] attaches \the [src] to the cable!</span>")
|
||||
return
|
||||
else
|
||||
user << "Device must be placed over an exposed cable to attach to it."
|
||||
to_chat(user, "<span class='warning'>\The [src] must be placed over an exposed cable to attach to it.</span>")
|
||||
return
|
||||
else
|
||||
if (mode == 2)
|
||||
@@ -53,7 +54,7 @@
|
||||
processing_power_items.Remove(src)
|
||||
anchored = 0
|
||||
mode = 0
|
||||
src.visible_message("<span class='notice'>[user] detaches [src] from the cable!</span>")
|
||||
visible_message("<span class='notice'>\The [user] detaches \the [src] from the cable!</span>")
|
||||
set_light(0)
|
||||
icon_state = "powersink0"
|
||||
|
||||
@@ -69,18 +70,18 @@
|
||||
if(0)
|
||||
..()
|
||||
if(1)
|
||||
src.visible_message("<span class='notice'>[user] activates [src]!</span>")
|
||||
visible_message("<span class='notice'>\The [user] activates \the [src]!</span>")
|
||||
mode = 2
|
||||
icon_state = "powersink1"
|
||||
START_PROCESSING(SSprocessing, src)
|
||||
processing_power_items.Add(src)
|
||||
processing_power_items += src
|
||||
if(2) //This switch option wasn't originally included. It exists now. --NeoFite
|
||||
src.visible_message("<span class='notice'>[user] deactivates [src]!</span>")
|
||||
visible_message("<span class='notice'>\The [user] deactivates \the [src]!</span>")
|
||||
mode = 1
|
||||
set_light(0)
|
||||
icon_state = "powersink0"
|
||||
STOP_PROCESSING(SSprocessing, src)
|
||||
processing_power_items.Remove(src)
|
||||
processing_power_items -= src
|
||||
|
||||
/obj/item/device/powersink/pwr_drain()
|
||||
if(!attached)
|
||||
@@ -120,13 +121,62 @@
|
||||
/obj/item/device/powersink/process()
|
||||
drained_this_tick = 0
|
||||
power_drained -= min(dissipation_rate, power_drained)
|
||||
if(power_drained > max_power * 0.95)
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1, 1)
|
||||
if(power_drained >= max_power)
|
||||
explosion(src.loc, 3,6,9,12)
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
if(attached && attached.powernet)
|
||||
PN = attached.powernet
|
||||
else
|
||||
PN = null
|
||||
|
||||
if(power_drained > max_power * 0.98) // Lower the screeching period. It was pretty long during testing.
|
||||
playsound(src, 'sound/effects/screech.ogg', 100, 1, 1)
|
||||
|
||||
if(power_drained >= max_power)
|
||||
handle_overload()
|
||||
qdel(src)
|
||||
return
|
||||
|
||||
/obj/item/device/powersink/proc/handle_overload()
|
||||
if (QDELETED(src))
|
||||
return
|
||||
|
||||
// No attached node, or no powernet.
|
||||
if (!PN)
|
||||
explosion(src.loc, 0, 1, 3, 6)
|
||||
return
|
||||
|
||||
// Propagate the power surge through the powernet nodes.
|
||||
for (var/A in PN.nodes)
|
||||
if (!A || A == src)
|
||||
continue
|
||||
|
||||
var/dist = get_dist(src, A)
|
||||
|
||||
if (dist < 1)
|
||||
dist = 1 // For later calculations.
|
||||
else if (dist > 24)
|
||||
continue // Out of range.
|
||||
|
||||
// Map it to a range of [3, 1] for severity.
|
||||
dist = round(MAP(dist, 1, 28, 3, 1))
|
||||
|
||||
// Check for terminals and affect their master nodes. Also add a special
|
||||
// case for APCs whereby their lights are popped or flicked.
|
||||
if (istype(A, /obj/machinery/power/terminal))
|
||||
var/obj/machinery/power/terminal/T = A
|
||||
if (istype(T.master, /obj/machinery/power/apc))
|
||||
var/obj/machinery/power/apc/AP = T.master
|
||||
if (dist > 1)
|
||||
AP.overload_lighting(100, TRUE)
|
||||
else
|
||||
AP.flicker_all()
|
||||
else if (T.master)
|
||||
T.master.emp_act(dist)
|
||||
|
||||
var/atom/aa = A
|
||||
aa.emp_act(dist)
|
||||
|
||||
if (prob(15 * dist))
|
||||
explosion(aa.loc, 0, 0, 3, 4)
|
||||
|
||||
// Also destroy the source.
|
||||
explosion(src.loc, 0, 0, 1, 2)
|
||||
|
||||
@@ -1313,17 +1313,19 @@ obj/machinery/power/apc/proc/autoset(var/val, var/on)
|
||||
|
||||
// overload the lights in this APC area
|
||||
|
||||
/obj/machinery/power/apc/proc/overload_lighting(var/chance = 100)
|
||||
if(/* !get_connection() || */ !operating || shorted)
|
||||
/obj/machinery/power/apc/proc/overload_lighting(var/chance = 100, var/force = FALSE)
|
||||
if((!operating || shorted) && !force)
|
||||
return
|
||||
if( cell && cell.charge>=20)
|
||||
cell.use(20);
|
||||
|
||||
if(force || (cell && cell.charge >= 20))
|
||||
cell.use(20) // Draining an empty cell is fine.
|
||||
|
||||
spawn(0)
|
||||
for(var/obj/machinery/light/L in area)
|
||||
if(prob(chance))
|
||||
for (var/obj/machinery/light/L in area)
|
||||
if (prob(chance))
|
||||
L.on = 1
|
||||
L.broken()
|
||||
sleep(1)
|
||||
sleep(1)
|
||||
|
||||
/obj/machinery/power/apc/proc/flicker_all()
|
||||
var/offset = 0
|
||||
|
||||
Reference in New Issue
Block a user