mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-12 23:53:47 +01:00
b0463d3c83
* spanish? * aaaagain * keep maptext * Update robot_items.dm * Update span_defines.dm * compiles * Update silicon_mob.dm * compile
198 lines
8.3 KiB
Plaintext
198 lines
8.3 KiB
Plaintext
/mob/living/basic/demon/shadow
|
|
name = "shadow demon"
|
|
desc = "A creature that's barely tangible, you can feel its gaze piercing you."
|
|
icon = 'icons/mob/mob.dmi'
|
|
icon_state = "shadow_demon"
|
|
icon_living = "shadow_demon"
|
|
move_resist = MOVE_FORCE_STRONG
|
|
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_VISIBLE // so they can tell where the darkness is
|
|
see_in_dark = 10 // Below 10 `see_in_dark`, you'll not have full vision with fullscreen
|
|
loot = list(/obj/item/organ/internal/heart/demon/shadow)
|
|
death_sound = 'sound/shadowdemon/shadowdeath.ogg'
|
|
unsuitable_atmos_damage = 18 // You will heal very slowly in a vacuum (2 damage). Go back to the air to heal faster.
|
|
var/thrown_alert = FALSE
|
|
var/wrapping = FALSE
|
|
/// Should only be TRUE if we're shooting the Shadow Grapple right now. If its TRUE, the demon wont be able to shadow crawl.
|
|
var/block_shadow_crawl = FALSE
|
|
/// Used for fault tolerance. If you set it manually, it may fuck up shooting_grapple var.
|
|
var/last_block_shadow_crawl = 0
|
|
|
|
/mob/living/basic/demon/shadow/Login()
|
|
..()
|
|
var/list/L = list(
|
|
SPAN_DEADSAY("<font size=3><b>You are a shadow demon!</b></font>"),
|
|
"<b>You are a lethal ambush predator who thrives in the darkness, calling upon the shadows to heal your injured form and increase your speed.</b>",
|
|
"<b>Light is however your worst enemy and being exposed for too long will be fatal.</b>",
|
|
"<b>Striking your victims with your shadow grapple extinguishes any light sources around them. Striking items silences any light within them.</b>",
|
|
"<b>You can wrap your dead victims into a shadow cocoon which provides a shroud of darkness which tears away any light near it.</b>",
|
|
"<b><i>You do not remember anything of your past lives, nor will you remember anything about this one after your death.</i></b>",
|
|
"<br>[SPAN_MOTD("For more information, check the wiki page: [wiki_link("Shadow_Demon")]")]"
|
|
)
|
|
to_chat(src, chat_box_red(L.Join("<br>")))
|
|
|
|
/mob/living/basic/demon/shadow/Life(seconds, times_fired)
|
|
. = ..()
|
|
var/lum_count = check_darkness()
|
|
var/damage_mod = istype(loc, /obj/effect/dummy/slaughter) ? 0.5 : 1
|
|
if(lum_count > 0.2)
|
|
adjustBruteLoss(40 * damage_mod) // 10 seconds in light
|
|
SEND_SOUND(src, sound('sound/weapons/sear.ogg'))
|
|
to_chat(src, SPAN_BIGGERDANGER("The light scalds you!"))
|
|
else
|
|
adjustBruteLoss(-20)
|
|
|
|
/mob/living/basic/demon/shadow/UnarmedAttack(atom/A)
|
|
// Pick a random attack sound for each attack
|
|
attack_sound = pick('sound/shadowdemon/shadowattack2.ogg', 'sound/shadowdemon/shadowattack3.ogg', 'sound/shadowdemon/shadowattack4.ogg')
|
|
if(!ishuman(A))
|
|
if(isitem(A))
|
|
A.extinguish_light()
|
|
return ..()
|
|
var/mob/living/carbon/human/target = A
|
|
if(target.stat != DEAD)
|
|
return ..()
|
|
|
|
if(isLivingSSD(target) && client.send_ssd_warning(target)) // Similar to revenants, only wrap SSD targets if you've accepted the SSD warning
|
|
return
|
|
|
|
if(wrapping)
|
|
to_chat(src, SPAN_NOTICE("We are already wrapping something."))
|
|
return
|
|
|
|
visible_message(SPAN_DANGER("[src] begins wrapping [target] in shadowy threads."))
|
|
wrapping = TRUE
|
|
if(!do_after(src, 4 SECONDS, FALSE, target = target))
|
|
wrapping = FALSE
|
|
return
|
|
|
|
target.visible_message(SPAN_WARNING("<b>[src] envelops [target] into an ethereal cocoon, and darkness begins to creep from it.</b>"))
|
|
var/obj/structure/shadowcocoon/C = new(get_turf(target))
|
|
target.extinguish_light() // may as well be safe
|
|
target.forceMove(C)
|
|
wrapping = FALSE
|
|
|
|
/mob/living/basic/demon/shadow/proc/block_shadow_crawl()
|
|
last_block_shadow_crawl = world.time
|
|
block_shadow_crawl = TRUE
|
|
addtimer(CALLBACK(src, PROC_REF(check_block_shadow_crawl), last_block_shadow_crawl), 10 SECONDS)
|
|
|
|
/mob/living/basic/demon/shadow/proc/unblock_shadow_crawl()
|
|
last_block_shadow_crawl = 0
|
|
block_shadow_crawl = FALSE
|
|
|
|
/mob/living/basic/demon/shadow/proc/check_block_shadow_crawl(block_time)
|
|
if(block_time == last_block_shadow_crawl)
|
|
/// it means 10 seconds passed from last shadow grapple shot and it didnt unset block_shadow_crawl
|
|
to_chat(src, SPAN_WARNING("You feel good enough to use Shadow Crawl again."))
|
|
unblock_shadow_crawl()
|
|
|
|
/obj/structure/shadowcocoon
|
|
name = "shadowy cocoon"
|
|
desc = "Something wrapped in what seems to be manifested darkness. Its surface distorts unnaturally, and it emanates deep shadows."
|
|
icon = 'icons/effects/effects.dmi'
|
|
icon_state = "shadowcocoon"
|
|
light_power = -4
|
|
light_range = 6
|
|
max_integrity = 100
|
|
light_color = "#ddd6cf"
|
|
anchored = TRUE
|
|
/// Amount of SSobj ticks (Roughly 2 seconds) since the last hallucination proc'd
|
|
var/time_since_last_hallucination = 0
|
|
/// Will we play hallucination sounds or not
|
|
var/silent = TRUE
|
|
|
|
/obj/structure/shadowcocoon/Initialize(mapload)
|
|
. = ..()
|
|
playsound(loc, 'sound/shadowdemon/shadownode.ogg', 5, TRUE, -1)
|
|
START_PROCESSING(SSobj, src)
|
|
|
|
|
|
/obj/structure/shadowcocoon/examine(mob/user)
|
|
. = ..()
|
|
if(istype(user, /mob/living/basic/demon/shadow))
|
|
. += silent ? SPAN_NOTICE("The tendrils are idle and will not produce noise.") : SPAN_NOTICE("The tendrils are agitated <b>and will occasionally produce noise to lure in more prey.</b>")
|
|
. += SPAN_NOTICE("Alt+Click to toggle whether [src] should produce noise to lure in victims.")
|
|
|
|
/obj/structure/shadowcocoon/process()
|
|
time_since_last_hallucination++
|
|
for(var/atom/to_darken in range(4, src))
|
|
if(prob(60) || !length(to_darken.light_sources))
|
|
continue
|
|
if(iswelder(to_darken) && length(to_darken.light_sources))
|
|
var/obj/item/weldingtool/welder_to_darken = to_darken
|
|
welder_to_darken.remove_fuel(welder_to_darken.reagents.get_reagent_amount("fuel"))
|
|
welder_to_darken.visible_message(SPAN_NOTICE("The shadows swarm around and overwhelm the flame of [welder_to_darken]."))
|
|
return
|
|
if(istype(to_darken, /obj/item/flashlight/flare))
|
|
var/obj/item/flashlight/flare/flare_to_darken = to_darken
|
|
if(!flare_to_darken.on)
|
|
continue
|
|
flare_to_darken.turn_off()
|
|
flare_to_darken.fuel = 0
|
|
flare_to_darken.visible_message(SPAN_NOTICE("[flare_to_darken] suddenly dims."))
|
|
to_darken.extinguish_light()
|
|
if(!silent && time_since_last_hallucination >= rand(8, 12))
|
|
playsound(src, pick('sound/shadowdemon/shadowhalluc1.ogg', 'sound/shadowdemon/shadowhalluc2.ogg', 'sound/machines/airlock_open.ogg', 'sound/machines/airlock_close.ogg', 'sound/machines/boltsup.ogg', 'sound/shadowdemon/shadowhalluc3.ogg', get_sfx("bodyfall"), 'sound/weapons/egloves.ogg'), 50)
|
|
time_since_last_hallucination = 0
|
|
|
|
|
|
// Allows you to turn on cocoons making hallucination sounds or not
|
|
/obj/structure/shadowcocoon/AltClick(mob/user)
|
|
if(!isdemon(user))
|
|
return ..()
|
|
if(silent)
|
|
to_chat(user, SPAN_NOTICE("You twist and change your trapped victim in [src] to lure in more prey."))
|
|
silent = FALSE
|
|
return
|
|
to_chat(user, SPAN_NOTICE("The tendrils from [src] snap back to their orignal form."))
|
|
silent = TRUE
|
|
|
|
/obj/structure/shadowcocoon/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0)
|
|
if(damage_type != BURN) //I unashamedly stole this from spider cocoon code
|
|
return
|
|
playsound(loc, 'sound/items/welder.ogg', 100, TRUE)
|
|
|
|
/obj/structure/shadowcocoon/obj_destruction()
|
|
visible_message(SPAN_DANGER("[src] splits open, and the shadows dancing around it fade."))
|
|
return ..()
|
|
|
|
/obj/structure/shadowcocoon/Destroy()
|
|
for(var/atom/movable/A in contents)
|
|
A.forceMove(loc)
|
|
return..()
|
|
|
|
/mob/living/basic/demon/shadow/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
|
|
if(isliving(AM)) // when a living creature is thrown at it, dont knock it back
|
|
return
|
|
..()
|
|
|
|
/mob/living/basic/demon/shadow/Initialize(mapload)
|
|
. = ..()
|
|
AddSpell(new /datum/spell/fireball/shadow_grapple)
|
|
var/datum/spell/bloodcrawl/shadow_crawl/S = new
|
|
AddSpell(S)
|
|
whisper_action.button_icon_state = "shadow_whisper"
|
|
whisper_action.background_icon_state = "shadow_demon_bg"
|
|
if(istype(loc, /obj/effect/dummy/slaughter))
|
|
S.phased = TRUE
|
|
RegisterSignal(loc, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/basic/demon/shadow, check_darkness))
|
|
RegisterSignal(src, COMSIG_MOVABLE_MOVED, PROC_REF(check_darkness))
|
|
add_overlay(emissive_appearance(icon, "shadow_demon_eye_glow_overlay"))
|
|
|
|
/mob/living/basic/demon/shadow/proc/check_darkness()
|
|
var/turf/T = get_turf(src)
|
|
var/lum_count = T.get_lumcount()
|
|
if(lum_count > 0.2)
|
|
if(!thrown_alert)
|
|
thrown_alert = TRUE
|
|
throw_alert("light", /atom/movable/screen/alert/lightexposure)
|
|
alpha = 255
|
|
speed = initial(speed)
|
|
else
|
|
if(thrown_alert)
|
|
thrown_alert = FALSE
|
|
clear_alert("light")
|
|
alpha = 125
|
|
speed = 0.5
|
|
return lum_count
|