/
moderate.dm
478 lines (418 loc) · 16.1 KB
/
moderate.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
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
/**
* # Hallucination - Bolts (Moderate)
*
* A variation that affects more airlocks.
*/
/obj/effect/hallucination/bolts/moderate
bolt_amount = 7
/**
* # Hallucination - Fake Alert
*
* Displays a random alert on the target's HUD.
*/
/obj/effect/hallucination/fake_alert
duration = list(10 SECONDS, 25 SECONDS)
/// The possible alerts to be displayed. Key is alert type, value is alert category.
var/list/alerts = list(
/obj/screen/alert/not_enough_oxy = "not_enough_oxy",
/obj/screen/alert/not_enough_tox = "not_enough_tox",
/obj/screen/alert/not_enough_co2 = "not_enough_co2",
/obj/screen/alert/not_enough_nitro = "not_enough_nitro",
/obj/screen/alert/too_much_oxy = "too_much_oxy",
/obj/screen/alert/too_much_co2 = "too_much_co2",
/obj/screen/alert/too_much_tox = "too_much_tox",
/obj/screen/alert/fat = "nutrition",
/obj/screen/alert/starving = "nutrition",
/obj/screen/alert/hot = "temp",
/obj/screen/alert/cold = "temp",
/obj/screen/alert/highpressure = "pressure",
/obj/screen/alert/lowpressure = "pressure",
)
/// Alert severities. Only needed for some alerts such as temperature or pressure. Key is alert category, value is severity.
var/list/severities = list(
"temp" = 3,
"pressure" = 2,
)
/// The alert category that was affected(arc) as part of this hallucination.
var/alert_category
/obj/effect/hallucination/fake_alert/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/alert_type = pick(alerts)
alert_category = alerts[alert_type]
target.throw_alert(alert_category, alert_type, override = TRUE, severity = severities[alert_category])
/obj/effect/hallucination/fake_alert/Destroy()
target?.clear_alert(alert_category, clear_override = TRUE)
return ..()
/**
* # Hallucination - Fake Item
*
* Displays a random fake item around the target. If it's on the floor and they try to pick it up, they will trip and fall.
*/
/obj/effect/hallucination/fake_item
hallucination_override = TRUE
hallucination_layer = OBJ_LAYER
/// Static list of items this hallucination can be.
var/static/list/items = list(
"\improper .357 revolver" = list('icons/obj/guns/projectile.dmi', "revolver"),
"\improper ARG" = list('icons/obj/guns/projectile.dmi', "arg-30"),
"\improper C4" = list('icons/obj/grenade.dmi', "plastic-explosive0"),
"\improper L6 SAW" = list('icons/obj/guns/projectile.dmi', "l6closed100"),
"chainsaw" = list('icons/obj/items.dmi', "chainsaw0"),
"combat shotgun" = list('icons/obj/guns/projectile.dmi', "cshotgun"),
"double-bladed energy sword" = list('icons/obj/items.dmi', "dualsaberred1"),
"energy sword" = list('icons/obj/items.dmi', "swordred"),
"fireaxe" = list('icons/obj/items.dmi', "fireaxe1"),
"ritual dagger" = list('icons/obj/cult.dmi', "blood_dagger"),
"ritual dagger" = list('icons/obj/cult.dmi', "death_dagger"),
"ritual dagger" = list('icons/obj/cult.dmi', "hell_dagger"),
"sniper rifle" = list('icons/obj/guns/projectile.dmi', "sniper"),
)
/obj/effect/hallucination/fake_item/Initialize(mapload, mob/living/carbon/target)
name = pick(items)
var/list/icon_data = items[name]
hallucination_icon = icon_data[1]
hallucination_icon_state = icon_data[2]
. = ..()
var/list/locs = list()
for(var/turf/T in oview(world.view, target))
if(!is_blocked_turf(T))
locs += T
if(!length(locs))
qdel(src)
return
loc = pick(locs)
/obj/effect/hallucination/fake_item/attack_hand(mob/living/user)
if(user != target)
return
if(hasorgans(user))
var/mob/living/carbon/human/H = user
var/obj/item/organ/external/temp = H.bodyparts_by_name["r_hand"]
if(user.hand)
temp = H.bodyparts_by_name["l_hand"]
if(!temp)
to_chat(user, "<span class='warning'>You try to use your hand, but it's missing!</span>")
return
if(!temp.is_usable())
to_chat(user, "<span class='warning'>You try to move your [temp.name], but cannot!</span>")
return
user.Weaken(4 SECONDS_TO_LIFE_CYCLES)
user.visible_message("<span class='warning'>[user] does a grabbing motion towards [get_turf(src)] but [user.p_they()] stumble[user.p_s()] - nothing is there!</span>",
"<span class='userdanger'>[src] vanishes as you try grabbing it, causing you to stumble!</span>")
qdel(src)
/**
* # Hallucination - Fake Weapon
*
* Displays a random fake weapon wielded by a human around the target.
*/
/obj/effect/hallucination/fake_weapon
/// Static list of weapons this hallucination can be. Key is icon state, value is LEFT-HAND icon file.
var/static/list/weapons = list(
"advtaserstun4" = 'icons/mob/inhands/guns_lefthand.dmi',
"arm_blade" = null,
"blood_blade" = null,
"crossbow" = 'icons/mob/inhands/guns_lefthand.dmi',
"death_blade" = null,
"disintegrate" = null,
"fireaxe0" = null,
"hell_blade" = null,
"ling_shield" = null,
"nucgun" = 'icons/mob/inhands/guns_lefthand.dmi',
"prod" = null,
"staffofslipping" = null,
"staffofstorms" = null,
"swordred" = null,
"ttv" = null,
)
/// The default LEFT-HAND icon file for weapons. Static.
var/static/default_icon = 'icons/mob/inhands/items_lefthand.dmi'
/// Static list of RIGHT-HAND counterpart for any LEFT-HAND icon files used above.
var/static/right_hand_icons = list(
'icons/mob/inhands/items_lefthand.dmi' = 'icons/mob/inhands/items_righthand.dmi',
'icons/mob/inhands/guns_lefthand.dmi' = 'icons/mob/inhands/guns_righthand.dmi',
)
/// The mob wielding the fake weapon.
var/mob/living/carbon/human/wielder = null
/obj/effect/hallucination/fake_weapon/Initialize(mapload, mob/living/carbon/target)
. = ..()
// Find able-bodied mobs first
var/list/mobs = list()
for(var/mob/living/carbon/human/H in oview(world.view, target))
if(H.stat || !((H.has_left_hand() && !H.l_hand) || (H.has_right_hand() && !H.r_hand)))
continue
mobs += H
if(!length(mobs))
qdel(src)
return
// Pick a hand if it exists of course
wielder = pick(mobs)
var/right = FALSE
if(!(wielder.bodyparts_by_name["l_hand"] && !wielder.l_hand) || ((wielder.bodyparts_by_name["r_hand"] && !wielder.r_hand) && prob(50)))
right = TRUE
// Create the icon
hallucination_icon_state = pick(weapons)
var/icon = weapons[hallucination_icon_state] || default_icon
if(right)
icon = right_hand_icons[icon]
var/image/I = image(icon, wielder, hallucination_icon_state)
I = center_image(I, 32, 32)
add_icon(I)
if(hallucination_icon_state == "swordred")
target.playsound_local(get_turf(wielder), 'sound/weapons/saberon.ogg', 35, TRUE)
/obj/effect/hallucination/fake_weapon/Destroy()
if(!QDELETED(wielder) && hallucination_icon_state == "swordred")
target.playsound_local(get_turf(wielder), 'sound/weapons/saberoff.ogg', 35, TRUE)
return ..()
/**
* # Hallucination - Chasms
*
* Displays fake chasms around the target that if crossed, cause them to trip.
*/
/obj/effect/hallucination/chasms
/// Minimum number of chasms to create.
var/min_amount = 3
/// Maximum number of chasms to create.
var/max_amount = 7
/obj/effect/hallucination/chasms/Initialize(mapload, mob/living/carbon/target)
. = ..()
// Let's check if we can spawn somewhere first
var/list/locs = list()
for(var/turf/T in oview(world.view, target))
if(isfloorturf(T) && !is_blocked_turf(T))
locs += T
if(!length(locs))
qdel(src)
return
var/amount = rand(min_amount, max_amount)
while(amount-- && length(locs))
new /obj/effect/hallucination/tripper/chasm(pick_n_take(locs), target)
/**
* # Hallucination - Chasm
*
* A fake chasm that if crossed by the target, causes them to trip.
*/
/obj/effect/hallucination/tripper/chasm
name = "chasm"
hallucination_icon = 'icons/turf/floors/Chasms.dmi'
hallucination_icon_state = "smooth"
hallucination_override = TRUE
hallucination_layer = HIGH_TURF_LAYER
stun = 8 SECONDS_TO_LIFE_CYCLES
weaken = 8 SECONDS_TO_LIFE_CYCLES
/obj/effect/hallucination/tripper/chasm/on_crossed()
target.visible_message("<span class='warning'>[target] trips over nothing and flails on [get_turf(target)] as if they were falling!</span>",
"<span class='userdanger'>You stumble and stare into an abyss before you. It stares back, and you fall into the enveloping dark!</span>")
/**
* # Hallucination - Delamination Alarm
*
* A fake radio message and audio that alerts of an increasing SM unstability.
*/
/obj/effect/hallucination/delamination_alarm
duration = 0
/obj/effect/hallucination/delamination_alarm/Initialize(mapload, mob/living/carbon/target)
. = ..()
target.playsound_local(target, 'sound/machines/engine_alert2.ogg', 25, FALSE, 30, 30)
target.hear_radio(message_to_multilingual("Danger! Crystal hyperstructure integrity faltering! Integrity: [rand(30, 50)]%"), vname = "supermatter crystal", part_a = "<span class='[SSradio.frequency_span_class(PUB_FREQ)]'><b>\[[get_frequency_name(PUB_FREQ)]\]</b> <span class='name'>", part_b = "</span> <span class='message'>")
/**
* # Hallucination - Plasma Flood
*
* A fake plasma flood emanating from a nearby vent.
*/
/obj/effect/hallucination/plasma_flood
duration = 25 SECONDS
/// List of turfs that need expanding from.
var/list/turf/expand_queue = list()
/// Associative list of turfs that have already been processed.
var/list/turf/processed = list()
/// The delay at which the plasma flood expands in deciseconds. Shouldn't be too low to prevent lag.
var/expand_delay = 2.5 SECONDS // Expand 10 times
/// Expand timer handle.
var/expand_timer = null
/obj/effect/hallucination/plasma_flood/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/list/vents = list()
for(var/obj/machinery/atmospherics/unary/vent_pump/vent in oview(world.view, target))
if(!is_blocked_turf(vent) && !vent.welded)
vents += vent
if(!length(vents))
qdel(src)
return
var/turf/T = get_turf(pick(vents))
create_plasma(T)
expand_queue += T
processed[T] = TRUE
expand_timer = addtimer(CALLBACK(src, .proc/expand), expand_delay, TIMER_LOOP | TIMER_STOPPABLE)
/obj/effect/hallucination/plasma_flood/Destroy()
deltimer(expand_timer)
QDEL_NULL(expand_queue)
QDEL_NULL(processed)
return ..()
/**
* Called regularly in a timer to process the plasma flooding.
*/
/obj/effect/hallucination/plasma_flood/proc/expand()
// Brace for potentially expensive proc
for(var/t in expand_queue)
var/turf/source_turf = t
expand_queue -= source_turf
// Expand to each dir
for(var/dir in GLOB.cardinal)
var/turf/target_turf = get_step(source_turf, dir)
if(processed[target_turf] || !source_turf.CanAtmosPass(target_turf))
continue
create_plasma(target_turf)
expand_queue += target_turf
processed[target_turf] = TRUE
/**
* Creates a fake plasma overlay on the given turf.
*
* Arguments:
* * T - The turf to create a fake plasma overlay on.
*/
/obj/effect/hallucination/plasma_flood/proc/create_plasma(turf/T)
var/image/I = image('icons/effects/tile_effects.dmi', T, "plasma", layer = FLY_LAYER)
I.plane = GAME_PLANE
add_icon(I)
/**
* # Hallucination - Husks
*
* A random number of fake husks around the target.
*/
/obj/effect/hallucination/husks
duration = 25 SECONDS
/// The base number of husks to create.
var/num_base = 3
/// The husk number variation, both negative and positive.
var/variation = 1
/obj/effect/hallucination/husks/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/list/locs = list()
for(var/turf/T in oview(world.view, target))
if(isfloorturf(T) && !is_blocked_turf(T))
locs += T
if(!length(locs))
qdel(src)
return
var/to_spawn = num_base + rand(-variation, variation)
while(to_spawn-- && length(locs))
var/image/I = image('icons/mob/human.dmi', pick_n_take(locs), "husk_s", layer = MOB_LAYER, dir = pick(GLOB.cardinal))
I.plane = GAME_PLANE
I.transform = turn(I.transform, pick(-90, 90))
add_icon(I)
/**
* # Hallucination - Stunprodding
*
* A series of localized audio playback simulating a kidnapping with a stunprod.
*/
/obj/effect/hallucination/stunprodding
duration = 3 SECONDS
/obj/effect/hallucination/stunprodding/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/list/turfs = list()
for(var/turf/T in range(world.view, target))
turfs += T
var/turf/T = pick(turfs)
target.playsound_local(T, 'sound/weapons/Egloves.ogg', 25, TRUE)
target.playsound_local(T, get_sfx("bodyfall"), 25, TRUE)
target.playsound_local(T, "sparks", 50, TRUE)
if(prob(50))
var/snd = pick('sound/goonstation/voice/female_scream.ogg', 'sound/goonstation/voice/male_scream.ogg')
play_sound_in(rand(13, 20), T, snd, 50, TRUE, rand(9, 11) / 10)
play_sound_in(rand(17, 20), T, 'sound/weapons/cablecuff.ogg', 15, TRUE)
/**
* # Hallucination - Energy Sword
*
* A series of localized audio playback simulating an energy sword murder.
*/
/obj/effect/hallucination/energy_sword
duration = 10 SECONDS
/obj/effect/hallucination/energy_sword/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/list/turfs = list()
for(var/turf/T in range(world.view, target))
turfs += T
var/turf/T = pick(turfs)
loc = T
target.playsound_local(T, 'sound/weapons/saberon.ogg', 20, TRUE)
var/scream_sound = pick('sound/goonstation/voice/female_scream.ogg', 'sound/goonstation/voice/male_scream.ogg')
var/scream_pitch = rand(9, 11) / 10
var/num_hits = rand(5, 6)
var/scream_cd = 0
for(var/i in 1 to num_hits)
var/time = i * CLICK_CD_MELEE + rand(3, 7)
play_sound_in(time, T, 'sound/weapons/blade1.ogg', 15, TRUE)
if(i == num_hits)
play_sound_in(time, T, pick('sound/goonstation/voice/deathgasp_1.ogg', 'sound/goonstation/voice/deathgasp_2.ogg'), 50, TRUE, scream_pitch)
else if(scream_sound && scream_cd-- <= 0 && prob(20))
scream_cd = 2
play_sound_in(time, T, scream_sound, 50, TRUE, scream_pitch)
/obj/effect/hallucination/energy_sword/Destroy()
target.playsound_local(loc, 'sound/weapons/saberoff.ogg', 20, TRUE)
return ..()
/**
* # Hallucination - Gunfire
*
* A series of localized audio playback simulating a gunshot murder.
*/
/obj/effect/hallucination/gunfire
duration = 10 SECONDS
/obj/effect/hallucination/gunfire/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/list/turfs = list()
for(var/turf/T in range(world.view, target))
turfs += T
var/turf/T = pick(turfs)
loc = T
var/gun_sound = pick('sound/weapons/gunshots/gunshot_pistol.ogg', 'sound/weapons/gunshots/gunshot_strong.ogg')
var/scream_sound = pick('sound/goonstation/voice/female_scream.ogg', 'sound/goonstation/voice/male_scream.ogg')
var/scream_pitch = rand(9, 11) / 10
var/num_hits = rand(7, 8)
var/scream_cd = 0
for(var/i in 1 to num_hits)
var/time = i * CLICK_CD_RANGE + rand(2, 4)
play_sound_in(time, T, gun_sound, 25, TRUE)
if(i == num_hits)
play_sound_in(time, T, pick('sound/goonstation/voice/deathgasp_1.ogg', 'sound/goonstation/voice/deathgasp_2.ogg'), 50, TRUE, scream_pitch)
else if(scream_sound && scream_cd-- <= 0 && prob(20))
scream_cd = 2
play_sound_in(time, T, scream_sound, 50, TRUE, scream_pitch)
/**
* # Hallucination - Self Delusion
*
* Changes the target's appearance to something else temporarily.
*/
/obj/effect/hallucination/self_delusion
duration = 15 SECONDS
/obj/effect/hallucination/self_delusion/Initialize(mapload, mob/living/carbon/target)
. = ..()
var/image/I = get_image()
I.override = TRUE
add_icon(I)
to_chat(target, "<span class='italics'>...wabbajack...wabbajack...</span>")
target.playsound_local(get_turf(target), 'sound/magic/staff_change.ogg', 50, TRUE, -1)
/**
* Returns the image to use as override to the target's appearance.
*/
/obj/effect/hallucination/self_delusion/proc/get_image()
return image('icons/mob/animal.dmi', target, pick("bear", "brownbear", "corgi", "cow", "deer", "goat", "goose", "pig", "blank-body"))
/**
* # Hallucination - Delusion
*
* Changes the appearance of all humans around the target.
*/
/obj/effect/hallucination/delusion
duration = 15 SECONDS
/obj/effect/hallucination/delusion/Initialize(mapload, mob/living/carbon/target, override_icon, override_icon_state)
. = ..()
for(var/mob/living/carbon/human/H in orange(world.view, target))
var/image/I
if(override_icon && override_icon_state)
I = image(override_icon, H, override_icon_state)
else
I = get_image(H)
I.override = TRUE
add_icon(I)
/**
* Returns the image to use as override to the target's appearance.
*/
/obj/effect/hallucination/delusion/proc/get_image(mob/living/carbon/human/H)
return image('icons/mob/animal.dmi', H, pick("bear", "brownbear", "corgi", "cow", "deer", "goat", "goose", "pig", "blank-body"))