Files
Aurora.3/code/game/objects/items/devices/powersink.dm
Fluffy a3a4d46fa7 Hitby refactor (#19624)
Refactored hitby to be in line with TG's version.
Refactored item weight defines to a more clear naming scheme, also in
line with TG's version.
Refactored how the movement bumps are handled, ported signals to handle
them, in preparation for the movement update.
Fixed disposal hit bouncing the hitting atom on the wall.
Items do not push other items anymore if they are tiny.
2024-07-28 20:52:08 +00:00

194 lines
5.2 KiB
Plaintext

// Powersink - used to drain station power
/obj/item/device/powersink
name = "power sink"
desc = "A nulling power sink which drains energy from electrical systems."
icon_state = "powersink0"
item_state = "powersink0"
w_class = WEIGHT_CLASS_BULKY
obj_flags = OBJ_FLAG_CONDUCTABLE
throwforce = 5
throw_speed = 1
throw_range = 2
matter = list(DEFAULT_WALL_MATERIAL = 750)
origin_tech = list(TECH_POWER = 3, TECH_ILLEGAL = 5)
///Amount of power to drain per second, in watts
var/drain_rate = 1.5 MEGA WATTS
///Maximum amount of power to drain from a single APW, in watts
var/apc_drain_rate = 50 KILO WATTS
///Passive dissipation of drained power in Watts
var/dissipation_rate = 20000
///Amount of power drained, in watts
var/power_drained = 04
///Power at which the sink will explode (after having absorbed that), in watts
var/max_power = 800 MEGA WATTS
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.
var/datum/powernet/PN // Our powernet
var/obj/structure/cable/attached // the attached cable
/obj/item/device/powersink/Destroy()
PN = null
attached = null
return ..()
/obj/item/device/powersink/attackby(obj/item/attacking_item, mob/user)
if(attacking_item.isscrewdriver())
if(mode == 0)
var/turf/T = loc
if(isturf(T) && !!T.is_plating())
attached = locate() in T
if(!attached)
to_chat(user, SPAN_WARNING("No exposed cable here to attach to."))
else
anchored = 1
mode = 1
visible_message(SPAN_NOTICE("\The [user] attaches \the [src] to the cable!"))
else
to_chat(user, SPAN_WARNING("\The [src] must be placed over an exposed cable to attach to it."))
return TRUE
else
if (mode == 2)
STOP_PROCESSING(SSprocessing, src)
anchored = 0
mode = 0
visible_message(SPAN_NOTICE("\The [user] detaches \the [src] from the cable!"))
set_light(0)
icon_state = "powersink0"
item_state = "powersink0"
return TRUE
else
return ..()
/obj/item/device/powersink/attack_ai()
return
/obj/item/device/powersink/attack_hand(var/mob/user)
switch(mode)
if(0)
..()
if(1)
visible_message(SPAN_NOTICE("\The [user] activates \the [src]!"))
mode = 2
icon_state = "powersink1"
item_state = "powersink1"
START_PROCESSING(SSprocessing, src)
if(2) //This switch option wasn't originally included. It exists now. --NeoFite
visible_message(SPAN_NOTICE("\The [user] deactivates \the [src]!"))
mode = 1
set_light(0)
icon_state = "powersink0"
item_state = "powersink0"
STOP_PROCESSING(SSprocessing, src)
/obj/item/device/powersink/proc/siphon_power(seconds_per_tick)
if(!attached)
return 0
if(drained_this_tick)
return 1
drained_this_tick = 1
var/drained = 0
if(!PN)
return 1
set_light(12)
PN.trigger_warning()
// found a powernet, so drain up to max power from it
drained = PN.draw_power(drain_rate * seconds_per_tick)
// if tried to drain more than available on powernet
// now look for APCs and drain their cells
if(drained < drain_rate * seconds_per_tick)
for(var/obj/machinery/power/terminal/T in PN.nodes)
// Enough power drained this tick, no need to torture more APCs
if(drained >= drain_rate * seconds_per_tick)
break
if(istype(T.master, /obj/machinery/power/apc))
var/obj/machinery/power/apc/A = T.master
if(A.operating && A.cell)
var/cur_charge = A.cell.charge / CELLRATE
var/drain_val = min(apc_drain_rate * seconds_per_tick, cur_charge)
A.cell.use(drain_val * CELLRATE)
drained += drain_val
power_drained += drained
return 1
/obj/item/device/powersink/process(seconds_per_tick)
drained_this_tick = 0
power_drained -= min(dissipation_rate, power_drained)
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
siphon_power(seconds_per_tick)
/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(EMP_LIGHT)
var/atom/aa = A
aa.emp_act(EMP_LIGHT)
if (prob(15 * dist))
explosion(aa.loc, 0, 0, 3, 4)
// Also destroy the source.
explosion(src.loc, 0, 0, 1, 2)