/
powersink.dm
209 lines (180 loc) · 6.68 KB
/
powersink.dm
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#define DISCONNECTED 0
#define CLAMPED_OFF 1
#define OPERATING 2
#define FRACTION_TO_RELEASE 50
#define ALERT 90
#define MINIMUM_HEAT 10000
// Powersink - used to drain station power
/obj/item/powersink
name = "power sink"
desc = "A power sink which drains energy from electrical systems and converts it to heat. Ensure short workloads and ample time to cool down if used in high energy systems."
icon = 'icons/obj/devices/syndie_gadget.dmi'
icon_state = "powersink0"
inhand_icon_state = "electronic"
lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi'
righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi'
w_class = WEIGHT_CLASS_BULKY
obj_flags = CONDUCTS_ELECTRICITY
item_flags = NO_PIXEL_RANDOM_DROP
throwforce = 5
throw_speed = 1
throw_range = 2
custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT* 7.5)
var/max_heat = 5e7 // Maximum contained heat before exploding. Not actual temperature.
var/internal_heat = 0 // Contained heat, goes down every tick.
var/mode = DISCONNECTED // DISCONNECTED, CLAMPED_OFF, OPERATING
var/warning_given = FALSE //! Stop warning spam, only warn the admins/deadchat once that we are about to boom.
var/obj/structure/cable/attached
/obj/item/powersink/update_icon_state()
icon_state = "powersink[mode == OPERATING]"
return ..()
/obj/item/powersink/examine(mob/user)
. = ..()
if(mode)
. += "\The [src] is bolted to the floor."
if((in_range(user, src) || isobserver(user)) && internal_heat > max_heat * 0.5)
. += span_danger("[src] is warping the air above it. It must be very hot.")
/obj/item/powersink/set_anchored(anchorvalue)
. = ..()
set_density(anchorvalue)
/obj/item/powersink/proc/set_mode(value)
if(value == mode)
return
switch(value)
if(DISCONNECTED)
attached = null
if(mode == OPERATING && internal_heat < MINIMUM_HEAT)
STOP_PROCESSING(SSobj, src)
internal_heat = 0
set_anchored(FALSE)
if(CLAMPED_OFF)
if(!attached)
return
if(mode == OPERATING && internal_heat < MINIMUM_HEAT)
STOP_PROCESSING(SSobj, src)
internal_heat = 0
set_anchored(TRUE)
if(OPERATING)
if(!attached)
return
START_PROCESSING(SSobj, src)
set_anchored(TRUE)
mode = value
update_appearance()
set_light(0)
/obj/item/powersink/wrench_act(mob/living/user, obj/item/tool)
. = TRUE
if(mode == DISCONNECTED)
var/turf/T = loc
if(isturf(T) && T.underfloor_accessibility >= UNDERFLOOR_INTERACTABLE)
attached = locate() in T
if(!attached)
to_chat(user, span_warning("\The [src] must be placed over an exposed, powered cable node!"))
else
set_mode(CLAMPED_OFF)
user.visible_message( \
"[user] attaches \the [src] to the cable.", \
span_notice("You bolt \the [src] into the floor and connect it to the cable."),
span_hear("You hear some wires being connected to something."))
else
to_chat(user, span_warning("\The [src] must be placed over an exposed, powered cable node!"))
else
set_mode(DISCONNECTED)
user.visible_message( \
"[user] detaches \the [src] from the cable.", \
span_notice("You unbolt \the [src] from the floor and detach it from the cable."),
span_hear("You hear some wires being disconnected from something."))
/obj/item/powersink/screwdriver_act(mob/living/user, obj/item/tool)
user.visible_message( \
"[user] messes with \the [src] for a bit.", \
span_notice("You can't fit the screwdriver into \the [src]'s bolts! Try using a wrench."))
return TRUE
/obj/item/powersink/attack_paw(mob/user, list/modifiers)
return
/obj/item/powersink/attack_ai()
return
/obj/item/powersink/attack_hand(mob/user, list/modifiers)
. = ..()
if(.)
return
switch(mode)
if(DISCONNECTED)
..()
if(CLAMPED_OFF)
user.visible_message( \
"[user] activates \the [src]!", \
span_notice("You activate \the [src]."),
span_hear("You hear a click."))
message_admins("Power sink activated by [ADMIN_LOOKUPFLW(user)] at [ADMIN_VERBOSEJMP(src)]")
user.log_message("activated a powersink", LOG_GAME)
notify_ghosts(
"[user] has activated a power sink!",
source = src,
header = "Shocking News!",
)
set_mode(OPERATING)
if(OPERATING)
user.visible_message( \
"[user] deactivates \the [src]!", \
span_notice("You deactivate \the [src]."),
span_hear("You hear a click."))
user.log_message("deactivated the powersink", LOG_GAME)
set_mode(CLAMPED_OFF)
/// Removes internal heat and shares it with the atmosphere.
/obj/item/powersink/proc/release_heat()
var/turf/our_turf = get_turf(src)
var/temp_to_give = internal_heat / FRACTION_TO_RELEASE
internal_heat -= temp_to_give
var/datum/gas_mixture/environment = our_turf.return_air()
var/delta_temperature = temp_to_give / environment.heat_capacity()
if(delta_temperature)
environment.temperature += delta_temperature
air_update_turf(FALSE, FALSE)
if(warning_given && internal_heat < max_heat * 0.75)
warning_given = FALSE
message_admins("Power sink at ([x],[y],[z] - <A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has cooled down and will not explode.")
if(mode != OPERATING && internal_heat < MINIMUM_HEAT)
internal_heat = 0
STOP_PROCESSING(SSobj, src)
/// Drains power from the connected powernet, if any.
/obj/item/powersink/proc/drain_power()
var/datum/powernet/powernet = attached.powernet
var/drained = 0
set_light(5)
// Drain as much as we can from the powernet.
drained = attached.newavail()
attached.add_delayedload(drained)
// If tried to drain more than available on powernet, now look for APCs and drain their cells
for(var/obj/machinery/power/terminal/terminal in powernet.nodes)
if(istype(terminal.master, /obj/machinery/power/apc))
var/obj/machinery/power/apc/apc = terminal.master
if(apc.operating && apc.cell)
drained += 0.001 * apc.cell.use(0.05 * STANDARD_CELL_CHARGE, force = TRUE)
internal_heat += drained
/obj/item/powersink/process()
if(!attached)
set_mode(DISCONNECTED)
release_heat()
if(mode != OPERATING)
return
drain_power()
if(internal_heat > max_heat * ALERT / 100)
if (!warning_given)
warning_given = TRUE
message_admins("Power sink at ([x],[y],[z] - <A HREF='?_src_=holder;[HrefToken()];adminplayerobservecoodjump=1;X=[x];Y=[y];Z=[z]'>JMP</a>) has reached [ALERT]% of max heat. Explosion imminent.")
notify_ghosts(
"[src] is about to reach critical heat capacity!",
source = src,
header = "Power Sunk",
)
playsound(src, 'sound/effects/screech.ogg', 100, TRUE, TRUE)
if(internal_heat >= max_heat)
STOP_PROCESSING(SSobj, src)
explosion(src, devastation_range = 4, heavy_impact_range = 8, light_impact_range = 16, flash_range = 32)
qdel(src)
#undef DISCONNECTED
#undef CLAMPED_OFF
#undef OPERATING
#undef FRACTION_TO_RELEASE
#undef ALERT
#undef MINIMUM_HEAT