forked from BeeStation/BeeStation-Hornet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
revenant_abilities.dm
419 lines (390 loc) · 17.3 KB
/
revenant_abilities.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
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
/mob/living/simple_animal/revenant/ClickOn(atom/A, params) //revenants can't interact with the world directly.
if(check_click_intercept(params,A))
return
var/list/modifiers = params2list(params)
if(modifiers["shift"])
ShiftClickOn(A)
return
if(modifiers["alt"])
AltClickNoInteract(src, A)
return
if(modifiers["ctrl"])
CtrlClickOn(A)
return
if(ishuman(A))
if(A in drained_mobs)
to_chat(src, "<span class='revenwarning'>[A]'s soul is dead and empty.</span>" )
else if(in_range(src, A))
Harvest(A)
if(isturf(A))
var/turf/T = A
if(T == get_turf(src))
T.show_zmove_radial(src)
//Harvest; activated by clicking the target, will try to drain their essence.
/mob/living/simple_animal/revenant/proc/Harvest(mob/living/carbon/human/target)
if(!castcheck(0))
return
if(draining)
to_chat(src, "<span class='revenwarning'>You are already siphoning the essence of a soul!</span>")
return
if(orbiting)
to_chat(src, "<span class='revenwarning'>You can't siphon essence during orbiting!</span>")
return
if(!target.stat && !target.stam_paralyzed)
to_chat(src, "<span class='revennotice'>[target.p_their(TRUE)] soul is too strong to harvest.</span>")
if(prob(10))
to_chat(target, "You feel as if you are being watched.")
return
draining = TRUE
essence_drained += rand(15, 20)
to_chat(src, "<span class='revennotice'>You search for the soul of [target].</span>")
if(do_after(src, rand(10, 20), target, timed_action_flags = IGNORE_HELD_ITEM)) //did they get deleted in that second?
if(target.ckey)
to_chat(src, "<span class='revennotice'>[target.p_their(TRUE)] soul burns with intelligence.</span>")
essence_drained += rand(20, 30)
if(target.stat != DEAD)
to_chat(src, "<span class='revennotice'>[target.p_their(TRUE)] soul blazes with life!</span>")
essence_drained += rand(40, 50)
else
to_chat(src, "<span class='revennotice'>[target.p_their(TRUE)] soul is weak and faltering.</span>")
if(do_after(src, rand(15, 20), target, timed_action_flags = IGNORE_HELD_ITEM)) //did they get deleted NOW?
switch(essence_drained)
if(1 to 30)
to_chat(src, "<span class='revennotice'>[target] will not yield much essence. Still, every bit counts.</span>")
if(30 to 70)
to_chat(src, "<span class='revennotice'>[target] will yield an average amount of essence.</span>")
if(70 to 90)
to_chat(src, "<span class='revenboldnotice'>Such a feast! [target] will yield much essence to you.</span>")
if(90 to INFINITY)
to_chat(src, "<span class='revenbignotice'>Ah, the perfect soul. [target] will yield massive amounts of essence to you.</span>")
if(do_after(src, rand(15, 25), target, timed_action_flags = IGNORE_HELD_ITEM)) //how about now
if(!target.stat && !target.stam_paralyzed)
to_chat(src, "<span class='revenwarning'>[target.p_theyre(TRUE)] now powerful enough to fight off your draining.</span>")
to_chat(target, "<span class='boldannounce'>You feel something tugging across your body before subsiding.</span>")
draining = 0
essence_drained = 0
return //hey, wait a minute...
to_chat(src, "<span class='revenminor'>You begin siphoning essence from [target]'s soul.</span>")
if(target.stat != DEAD)
to_chat(target, "<span class='warning'>You feel a horribly unpleasant draining sensation as your grip on life weakens...</span>")
if(target.stat == SOFT_CRIT)
target.Stun(46)
reveal(46)
stun(46)
target.visible_message("<span class='warning'>[target] suddenly rises slightly into the air, [target.p_their()] skin turning an ashy gray.</span>")
if(target.anti_magic_check(FALSE, TRUE))
to_chat(src, "<span class='revenminor'>Something's wrong! [target] seems to be resisting the siphoning, leaving you vulnerable!</span>")
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
"<span class='revenwarning'>Violet lights, dancing in your vision, receding--</span>")
draining = FALSE
return
var/datum/beam/B = Beam(target,icon_state="drain_life",time=INFINITY)
if(do_after(src, 46, target, timed_action_flags = IGNORE_HELD_ITEM)) //As one cannot prove the existance of ghosts, ghosts cannot prove the existance of the target they were draining.
change_essence_amount(essence_drained, FALSE, target)
if(essence_drained <= 90 && target.stat != DEAD)
essence_regen_cap += 5
to_chat(src, "<span class='revenboldnotice'>The absorption of [target]'s living soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>")
if(essence_drained > 90)
essence_regen_cap += 15
perfectsouls++
to_chat(src, "<span class='revenboldnotice'>The perfection of [target]'s soul has increased your maximum essence level. Your new maximum essence is [essence_regen_cap].</span>")
to_chat(src, "<span class='revennotice'>[target]'s soul has been considerably weakened and will yield no more essence for the time being.</span>")
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
"<span class='revenwarning'>Violets lights, dancing in your vision, getting clo--</span>")
drained_mobs.Add(target)
target.death(0)
else
to_chat(src, "<span class='revenwarning'>[target ? "[target] has":"[target.p_theyve(TRUE)]"] been drawn out of your grasp. The link has been broken.</span>")
if(target) //Wait, target is WHERE NOW?
target.visible_message("<span class='warning'>[target] slumps onto the ground.</span>", \
"<span class='revenwarning'>Violets lights, dancing in your vision, receding--</span>")
qdel(B)
else
to_chat(src, "<span class='revenwarning'>You are not close enough to siphon [target ? "[target]'s":"[target.p_their()]"] soul. The link has been broken.</span>")
draining = FALSE
essence_drained = 0
//Toggle night vision: lets the revenant toggle its night vision
/obj/effect/proc_holder/spell/targeted/night_vision/revenant
charge_max = 0
panel = "Revenant Abilities"
message = "<span class='revennotice'>You toggle your night vision.</span>"
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_icon_state = "r_nightvision"
action_background_icon_state = "bg_revenant"
//Transmit: the revemant's only direct way to communicate. Sends a single message silently to a single mob
/obj/effect/proc_holder/spell/targeted/telepathy/revenant
name = "Revenant Transmit"
panel = "Revenant Abilities"
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_icon_state = "r_transmit"
action_background_icon_state = "bg_revenant"
notice = "revennotice"
boldnotice = "revenboldnotice"
holy_check = TRUE
/obj/effect/proc_holder/spell/self/revenant_phase_shift
name = "Phase Shift"
desc = "Shift in and out of your corporeal form"
panel = "Revenant Abilities"
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_icon_state = "r_phase"
action_background_icon_state = "bg_revenant"
clothes_req = FALSE
charge_max = 0
/obj/effect/proc_holder/spell/self/revenant_phase_shift/cast(mob/user = usr)
if(!isrevenant(user))
return FALSE
var/mob/living/simple_animal/revenant/revenant = user
// if they're trapped in consecrated tiles, they can get out with this. but they can't hide back on these tiles.
if(revenant.incorporeal_move != INCORPOREAL_MOVE_JAUNT)
var/turf/open/floor/stepTurf = get_turf(user)
if(stepTurf)
var/obj/effect/decal/cleanable/food/salt/salt = locate() in stepTurf
if(salt)
to_chat(user, "<span class='warning'>[salt] blocks your way to spirit realm!</span>")
// the purpose is just letting not them hide onto salt tiles incorporeally. no need to stun.
return
if(stepTurf.flags_1 & NOJAUNT_1)
to_chat(user, "<span class='warning'>Some strange aura blocks your way to spirit realm.</span>")
return
if(stepTurf.is_holy())
to_chat(user, "<span class='warning'>Holy energies block your way to spirit realm!</span>")
return
revenant.phase_shift()
revenant.orbiting?.end_orbit(revenant)
/obj/effect/proc_holder/spell/aoe_turf/revenant
clothes_req = 0
action_icon = 'icons/mob/actions/actions_revenant.dmi'
action_background_icon_state = "bg_revenant"
panel = "Revenant Abilities (Locked)"
name = "Report this to a coder"
var/reveal = 80 //How long it reveals the revenant in deciseconds
var/stun = 20 //How long it stuns the revenant in deciseconds
var/locked = TRUE //If it's locked and needs to be unlocked before use
var/unlock_amount = 100 //How much essence it costs to unlock
var/cast_amount = 50 //How much essence it costs to use
/obj/effect/proc_holder/spell/aoe_turf/revenant/Initialize(mapload)
. = ..()
if(locked)
name = "[initial(name)] ([unlock_amount]SE)"
else
name = "[initial(name)] ([cast_amount]E)"
/obj/effect/proc_holder/spell/aoe_turf/revenant/can_cast(mob/living/simple_animal/revenant/user = usr)
if(charge_counter < charge_max)
return FALSE
if(!istype(user)) //Badmins, no. Badmins, don't do it.
return TRUE
if(user.inhibited)
return FALSE
if(locked)
if(user.essence_excess <= unlock_amount)
return FALSE
if(user.essence <= cast_amount)
return FALSE
return TRUE
/obj/effect/proc_holder/spell/aoe_turf/revenant/proc/attempt_cast(mob/living/simple_animal/revenant/user = usr)
if(!istype(user)) //If you're not a revenant, it works. Please, please, please don't give this to a non-revenant.
name = "[initial(name)]"
if(locked)
panel = "Revenant Abilities"
locked = FALSE
return TRUE
if(locked)
if (!user.unlock(unlock_amount))
charge_counter = charge_max
return FALSE
name = "[initial(name)] ([cast_amount]E)"
to_chat(user, "<span class='revennotice'>You have unlocked [initial(name)]!</span>")
panel = "Revenant Abilities"
locked = FALSE
charge_counter = charge_max
return FALSE
if(!user.castcheck(-cast_amount))
charge_counter = charge_max
return FALSE
name = "[initial(name)] ([cast_amount]E)"
user.reveal(reveal)
user.stun(stun)
if(action)
action.UpdateButtonIcon()
return TRUE
//Overload Light: Breaks a light that's online and sends out lightning bolts to all nearby people.
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload
name = "Overload Lights"
desc = "Directs a large amount of essence into nearby electrical lights, causing lights to shock those nearby."
charge_max = 200
range = 5
stun = 30
unlock_amount = 25
cast_amount = 40
var/shock_range = 2
var/shock_damage = 15
action_icon_state = "overload_lights"
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
INVOKE_ASYNC(src, PROC_REF(overload), T, user)
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/overload(turf/T, mob/user)
for(var/obj/machinery/light/L in T)
if(!L.on)
return
L.visible_message("<span class='warning'><b>\The [L] suddenly flares brightly and begins to spark!</span>")
var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(4, 0, L)
s.start()
new /obj/effect/temp_visual/revenant(get_turf(L))
addtimer(CALLBACK(src, PROC_REF(overload_shock), L, user), 20)
/obj/effect/proc_holder/spell/aoe_turf/revenant/overload/proc/overload_shock(obj/machinery/light/L, mob/user)
if(!L.on) //wait, wait, don't shock me
return
flick("[L.base_state]2", L)
for(var/mob/living/carbon/human/M in hearers(shock_range, L))
if(M == user)
continue
L.Beam(M,icon_state="purple_lightning",time=5)
if(!M.anti_magic_check(FALSE, TRUE))
M.electrocute_act(shock_damage, L, safety=TRUE)
do_sparks(4, FALSE, M)
playsound(M, 'sound/machines/defib_zap.ogg', 50, 1, -1)
//Defile: Corrupts nearby stuff, unblesses floor tiles.
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile
name = "Defile"
desc = "Twists and corrupts the nearby area as well as dispelling holy auras on floors."
charge_max = 150
range = 4
stun = 20
reveal = 40
unlock_amount = 10
cast_amount = 30
action_icon_state = "defile"
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
INVOKE_ASYNC(src, PROC_REF(defile), T)
/obj/effect/proc_holder/spell/aoe_turf/revenant/defile/proc/defile(turf/T)
for(var/obj/effect/blessing/B in T)
qdel(B)
new /obj/effect/temp_visual/revenant(T)
if(!isplatingturf(T) && !istype(T, /turf/open/floor/engine/cult) && isfloorturf(T) && prob(15))
var/turf/open/floor/floor = T
if(floor.intact && floor.floor_tile)
new floor.floor_tile(floor)
floor.broken = 0
floor.burnt = 0
floor.make_plating(1)
if(T.type == /turf/closed/wall && prob(15))
new /obj/effect/temp_visual/revenant(T)
T.AddElement(/datum/element/rust)
if(T.type == /turf/closed/wall/r_wall && prob(10))
new /obj/effect/temp_visual/revenant(T)
T.AddElement(/datum/element/rust)
for(var/obj/effect/decal/cleanable/food/salt/salt in T)
new /obj/effect/temp_visual/revenant(T)
qdel(salt)
for(var/obj/structure/closet/closet in T.contents)
closet.open()
for(var/obj/structure/bodycontainer/corpseholder in T)
if(corpseholder.connected.loc == corpseholder)
corpseholder.open()
for(var/obj/machinery/dna_scannernew/dna in T)
dna.open_machine()
for(var/obj/structure/window/window in T)
window.take_damage(rand(30,80))
if(window && window.fulltile)
new /obj/effect/temp_visual/revenant/cracks(window.loc)
for(var/obj/machinery/light/light in T)
light.flicker(20) //spooky
//Malfunction: Makes bad stuff happen to robots and machines.
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction
name = "Malfunction"
desc = "Corrupts and damages nearby machines and mechanical objects."
charge_max = 200
range = 4
cast_amount = 60
unlock_amount = 125
action_icon_state = "malfunction"
//A note to future coders: do not replace this with an EMP because it will wreck malf AIs and everyone will hate you.
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
INVOKE_ASYNC(src, PROC_REF(malfunction), T, user)
/obj/effect/proc_holder/spell/aoe_turf/revenant/malfunction/proc/malfunction(turf/T, mob/user)
for(var/mob/living/simple_animal/bot/bot in T)
if(!bot.emagged)
new /obj/effect/temp_visual/revenant(bot.loc)
bot.locked = FALSE
bot.open = TRUE
bot.use_emag()
for(var/mob/living/carbon/human/human in T)
if(human == user)
continue
if(human.anti_magic_check(FALSE, TRUE))
continue
to_chat(human, "<span class='revenwarning'>You feel [pick("your sense of direction flicker out", "a stabbing pain in your head", "your mind fill with static")].</span>")
new /obj/effect/temp_visual/revenant(human.loc)
human.emp_act(EMP_HEAVY)
for(var/obj/thing in T)
if(istype(thing, /obj/machinery/power/apc) || istype(thing, /obj/machinery/power/smes)) //Doesn't work on SMES and APCs, to prevent kekkery
continue
if(prob(20))
if(prob(50))
new /obj/effect/temp_visual/revenant(thing.loc)
thing.use_emag(null)
else
if(!istype(thing, /obj/machinery/clonepod)) //I hate everything but mostly the fact there's no better way to do this without just not affecting it at all
thing.emp_act(EMP_HEAVY)
for(var/mob/living/silicon/robot/S in T) //Only works on cyborgs, not AI
playsound(S, 'sound/machines/warning-buzzer.ogg', 50, 1)
new /obj/effect/temp_visual/revenant(S.loc)
S.spark_system.start()
S.emp_act(EMP_HEAVY)
//Blight: Infects nearby humans and in general messes living stuff up.
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight
name = "Blight"
desc = "Causes nearby living things to waste away."
charge_max = 200
range = 3
cast_amount = 50
unlock_amount = 75
action_icon_state = "blight"
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight/cast(list/targets, mob/living/simple_animal/revenant/user = usr)
if(attempt_cast(user))
for(var/turf/T in targets)
INVOKE_ASYNC(src, PROC_REF(blight), T, user)
/obj/effect/proc_holder/spell/aoe_turf/revenant/blight/proc/blight(turf/T, mob/user)
for(var/mob/living/mob in T)
if(mob == user)
continue
if(mob.anti_magic_check(FALSE, TRUE))
continue
new /obj/effect/temp_visual/revenant(mob.loc)
if(iscarbon(mob))
if(ishuman(mob))
var/mob/living/carbon/human/H = mob
if(H.dna?.species)
H.dna.species.handle_hair(H,"#1d2953") //will be reset when blight is cured
var/blightfound = FALSE
for(var/datum/disease/revblight/blight in H.diseases)
blightfound = TRUE
if(blight.stage < 5)
blight.stage++
if(!blightfound)
H.ForceContractDisease(new /datum/disease/revblight(), FALSE, TRUE)
to_chat(H, "<span class='revenminor'>You feel [pick("suddenly sick", "a surge of nausea", "like your skin is <i>wrong</i>")].</span>")
else
if(mob.reagents)
mob.reagents.add_reagent(/datum/reagent/toxin/plasma, 5)
else
mob.adjustToxLoss(5)
for(var/obj/structure/spacevine/vine in T) //Fucking with botanists, the ability.
vine.add_atom_colour("#823abb", TEMPORARY_COLOUR_PRIORITY)
new /obj/effect/temp_visual/revenant(vine.loc)
QDEL_IN(vine, 10)
for(var/obj/structure/glowshroom/shroom in T)
shroom.add_atom_colour("#823abb", TEMPORARY_COLOUR_PRIORITY)
new /obj/effect/temp_visual/revenant(shroom.loc)
QDEL_IN(shroom, 10)
for(var/obj/machinery/hydroponics/tray in T)
new /obj/effect/temp_visual/revenant(tray.loc)
tray.pestlevel = rand(8, 10)
tray.weedlevel = rand(8, 10)
tray.toxic = rand(45, 55)