Skip to content

Commit

Permalink
add: Shadow Demon (#3616)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gottfrei authored Nov 7, 2023
1 parent 98cc137 commit 50c8780
Show file tree
Hide file tree
Showing 17 changed files with 666 additions and 475 deletions.
2 changes: 1 addition & 1 deletion code/__DEFINES/gamemode.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
#define SPECIAL_ROLE_REVENANT "Revenant"
#define SPECIAL_ROLE_SHADOWLING "Shadowling"
#define SPECIAL_ROLE_SHADOWLING_THRALL "Shadowling Thrall"
#define SPECIAL_ROLE_SLAUGHTER_DEMON "Slaughter Demon"
#define SPECIAL_ROLE_DEMON "Demon"
#define SPECIAL_ROLE_SUPER "Super"
#define SPECIAL_ROLE_SYNDICATE_DEATHSQUAD "Syndicate Commando"
#define SPECIAL_ROLE_TRAITOR "Traitor"
Expand Down
2 changes: 1 addition & 1 deletion code/__DEFINES/role_preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#define ROLE_TERROR_SPIDER "Terror Spider"
// Role tags for EVERYONE!
#define ROLE_BORER "cortical borer"
#define ROLE_DEMON "slaughter demon"
#define ROLE_DEMON "demon"
#define ROLE_SENTIENT "sentient animal"
#define ROLE_POSIBRAIN "positronic brain"
#define ROLE_GUARDIAN "guardian"
Expand Down
178 changes: 89 additions & 89 deletions code/datums/spells/bloodcrawl.dm
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@

/obj/effect/proc_holder/spell/bloodcrawl/proc/block_hands(mob/living/carbon/user)
if(user.l_hand || user.r_hand)
to_chat(user, "<span class='warning'>You may not hold items while blood crawling!</span>")
to_chat(user, span_warning("You may not hold items while blood crawling!"))
return FALSE

var/obj/item/bloodcrawl/left_hand = new(user)
Expand All @@ -113,61 +113,61 @@
flick(animation_state, src) // Setting the icon_state to the animation has timing issues and can cause frame skips


/obj/effect/proc_holder/spell/bloodcrawl/proc/sink_animation(atom/target, mob/living/user)
/obj/effect/proc_holder/spell/bloodcrawl/proc/sink_animation(atom/enter_point, mob/living/user)
var/turf/mob_loc = get_turf(user)
visible_message("<span class='danger'>[user] sinks into [target].</span>")
visible_message(span_danger("[user] sinks into [enter_point]."))
playsound(mob_loc, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
new /obj/effect/temp_visual/dir_setting/bloodcrawl(mob_loc, user.dir, "jaunt")


/obj/effect/proc_holder/spell/bloodcrawl/proc/handle_consumption(mob/living/L, mob/living/victim, atom/A, obj/effect/dummy/slaughter/holder)
if(!HAS_TRAIT(L, TRAIT_BLOODCRAWL_EAT))
/obj/effect/proc_holder/spell/bloodcrawl/proc/handle_consumption(mob/living/user, mob/living/victim, atom/enter_point, obj/effect/dummy/slaughter/holder)
if(!HAS_TRAIT(user, TRAIT_BLOODCRAWL_EAT))
return

if(!istype(victim))
return

if(victim.stat == CONSCIOUS)
A.visible_message("<span class='warning'>[victim] kicks free of [A] just before entering it!</span>")
L.stop_pulling()
enter_point.visible_message(span_warning("[victim] kicks free of [enter_point] just before entering it!"))
user.stop_pulling()
return

victim.forceMove(holder)
victim.emote("scream")
A.visible_message("<span class='warning'><b>[L] drags [victim] into [A]!</b></span>")
L.stop_pulling()
to_chat(L, "<b>You begin to feast on [victim]. You can not move while you are doing this.</b>")
A.visible_message("<span class='warning'><B>Loud eating sounds come from the blood...</b></span>")
enter_point.visible_message(span_warning("<b>[user] drags [victim] into [enter_point]!</b>"))
user.stop_pulling()
to_chat(user, "<b>You begin to feast on [victim]. You can not move while you are doing this.</b>")
enter_point.visible_message(span_warning("<B>Loud eating sounds come from the blood...</b>"))
var/sound
if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/SD = L
sound = SD.feast_sound
if(isslaughterdemon(user))
var/mob/living/simple_animal/demon/slaughter/demon = user
sound = demon.feast_sound
else
sound = 'sound/misc/demon_consume.ogg'

for(var/i in 1 to 3)
playsound(get_turf(L), sound, 100, 1)
playsound(get_turf(user), sound, 100, TRUE)
sleep(3 SECONDS)

if(!victim)
to_chat(L, "<span class='danger'>You happily devour... nothing? Your meal vanished at some point!</span>")
to_chat(user, span_danger("You happily devour... nothing? Your meal vanished at some point!"))
return

if(ishuman(victim) || isrobot(victim))
to_chat(L, "<span class='warning'>You devour [victim]. Your health is fully restored.</span>")
L.adjustBruteLoss(-1000)
L.adjustFireLoss(-1000)
L.adjustOxyLoss(-1000)
L.adjustToxLoss(-1000)
to_chat(user, span_warning("You devour [victim]. Your health is fully restored."))
user.adjustBruteLoss(-1000)
user.adjustFireLoss(-1000)
user.adjustOxyLoss(-1000)
user.adjustToxLoss(-1000)
else
to_chat(L, "<span class='warning'>You devour [victim], but this measly meal barely sates your appetite!</span>")
L.adjustBruteLoss(-25)
L.adjustFireLoss(-25)
to_chat(user, span_warning("You devour [victim], but this measly meal barely sates your appetite!"))
user.adjustBruteLoss(-25)
user.adjustFireLoss(-25)

if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/demon = L
if(isslaughterdemon(user))
var/mob/living/simple_animal/demon/slaughter/demon = user
demon.devoured++
to_chat(victim, "<span class='userdanger'>You feel teeth sink into your flesh, and the--</span>")
to_chat(victim, span_userdanger("You feel teeth sink into your flesh, and the--"))
var/obj/item/organ/internal/regenerative_core/legion/core = victim.get_int_organ(/obj/item/organ/internal/regenerative_core/legion)
if(core)
core.remove(victim)
Expand All @@ -177,126 +177,126 @@
demon.consumed_mobs.Add(victim)
//ADD_TRAIT(victim, TRAIT_UNREVIVABLE, "demon")
if(ishuman(victim))
var/mob/living/carbon/human/H = victim
if(H.w_uniform && istype(H.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/U = H.w_uniform
U.sensor_mode = SENSOR_OFF
var/mob/living/carbon/human/h_victim = victim
if(h_victim.w_uniform && istype(h_victim.w_uniform, /obj/item/clothing/under))
var/obj/item/clothing/under/uniform = h_victim.w_uniform
uniform.sensor_mode = SENSOR_OFF
else
victim.ghostize()
qdel(victim)


/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_in(mob/living/L, obj/effect/dummy/slaughter/holder)
L.notransform = FALSE
/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_in(mob/living/user, obj/effect/dummy/slaughter/holder)
user.notransform = FALSE


/obj/effect/proc_holder/spell/bloodcrawl/proc/phaseout(obj/effect/decal/cleanable/B, mob/living/L)
/obj/effect/proc_holder/spell/bloodcrawl/proc/phaseout(obj/effect/decal/cleanable/enter_point, mob/living/carbon/user)

if(iscarbon(L) && !block_hands(L))
if(istype(user) && !block_hands(user))
return FALSE

L.notransform = TRUE
INVOKE_ASYNC(src, PROC_REF(async_phase), B, L)
user.notransform = TRUE
INVOKE_ASYNC(src, PROC_REF(async_phase), enter_point, user)
return TRUE


/obj/effect/proc_holder/spell/bloodcrawl/proc/async_phase(obj/effect/decal/cleanable/B, mob/living/L)
var/turf/mobloc = get_turf(L)
sink_animation(B, L)
/obj/effect/proc_holder/spell/bloodcrawl/proc/async_phase(obj/effect/decal/cleanable/enter_point, mob/living/user)
var/turf/mobloc = get_turf(user)
sink_animation(enter_point, user)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(mobloc)
L.forceMove(holder)
L.ExtinguishMob()
handle_consumption(L, L.pulling, B, holder)
post_phase_in(L, holder)
user.forceMove(holder)
user.ExtinguishMob()
handle_consumption(user, user.pulling, enter_point, holder)
post_phase_in(user, holder)


/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_animation(turf/tele_loc, mob/living/L, atom/A)
new /obj/effect/temp_visual/dir_setting/bloodcrawl(tele_loc, L.dir, "jauntup")
if(prob(25) && isdemon(L))
/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_animation(turf/tele_loc, mob/living/user, atom/exit_point)
new /obj/effect/temp_visual/dir_setting/bloodcrawl(tele_loc, user.dir, "jauntup")
if(prob(25) && isdemon(user))
var/list/voice = list('sound/hallucinations/behind_you1.ogg', 'sound/hallucinations/im_here1.ogg', 'sound/hallucinations/turn_around1.ogg', 'sound/hallucinations/i_see_you1.ogg')
playsound(tele_loc, pick(voice),50, 1, -1)
A.visible_message("<span class='warning'><b>[L] rises out of [A]!</b>")
playsound(get_turf(tele_loc), 'sound/misc/exit_blood.ogg', 100, 1, -1)
playsound(tele_loc, pick(voice), 50, TRUE, -1)
exit_point.visible_message(span_warning("<b>[user] rises out of [exit_point]!</b>"))
playsound(get_turf(tele_loc), 'sound/misc/exit_blood.ogg', 100, TRUE, -1)


/obj/effect/proc_holder/spell/bloodcrawl/proc/unblock_hands(mob/living/carbon/C)
if(!istype(C))
/obj/effect/proc_holder/spell/bloodcrawl/proc/unblock_hands(mob/living/carbon/user)
if(!istype(user))
return
for(var/obj/item/bloodcrawl/BC in C)
qdel(BC)
for(var/obj/item/bloodcrawl/item in user)
qdel(item)


/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_message(atom/A)
A.visible_message("<span class='warning'>[A] starts to bubble...</span>")
/obj/effect/proc_holder/spell/bloodcrawl/proc/rise_message(atom/exit_point)
exit_point.visible_message(span_warning("[exit_point] starts to bubble..."))


/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_out(atom/A, mob/living/L)
if(isslaughterdemon(L))
var/mob/living/simple_animal/demon/slaughter/S = L
S.speed = 0
S.boost = world.time + 6 SECONDS
L.color = A.color
addtimer(VARSET_CALLBACK(L, color, null), 6 SECONDS)
/obj/effect/proc_holder/spell/bloodcrawl/proc/post_phase_out(atom/exit_point, mob/living/user)
if(isslaughterdemon(user))
var/mob/living/simple_animal/demon/slaughter/demon = user
demon.speed = 0
demon.boost = world.time + 6 SECONDS
user.color = exit_point.color
addtimer(VARSET_CALLBACK(user, color, null), 6 SECONDS)


/obj/effect/proc_holder/spell/bloodcrawl/proc/phasein(atom/A, mob/living/L)
/obj/effect/proc_holder/spell/bloodcrawl/proc/phasein(atom/enter_point, mob/living/user)

if(L.notransform)
to_chat(L, "<span class='warning'>Finish eating first!</span>")
if(user.notransform)
to_chat(user, span_warning("Finish eating first!"))
return FALSE
rise_message(A)
if(!do_after(L, 2 SECONDS, target = A))
rise_message(enter_point)
if(!do_after(user, 2 SECONDS, target = enter_point))
return FALSE
if(!A)
if(!enter_point)
return FALSE
var/turf/tele_loc = isturf(A) ? A : A.loc
var/holder = L.loc
L.forceMove(tele_loc)
L.client.eye = L
var/turf/tele_loc = isturf(enter_point) ? enter_point : enter_point.loc
var/holder = user.loc
user.forceMove(tele_loc)
user.client.eye = user

rise_animation(tele_loc, L, A)
rise_animation(tele_loc, user, enter_point)

unblock_hands(L)
unblock_hands(user)

QDEL_NULL(holder)

post_phase_out(A, L)
post_phase_out(enter_point, user)
return TRUE


/*/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl
name = "Shadow Crawl"
desc = "Use darkness to phase out of existence."
allowed_type = /turf
action_background_icon_state = "shadow_demon_bg"
action_icon_state = "shadow_crawl"
allowed_type = /turf


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/valid_target(turf/target, user)
return target.get_lumcount() < 0.2


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_message(atom/A)
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_message(atom/exit_point)
return


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_animation(turf/tele_loc, mob/living/L, atom/A)
new /obj/effect/temp_visual/dir_setting/bloodcrawl(get_turf(L), L.dir, "shadowwalk_appear")
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/rise_animation(turf/tele_loc, mob/living/user, atom/exit_point)
new /obj/effect/temp_visual/dir_setting/bloodcrawl(get_turf(user), user.dir, "shadowwalk_appear")


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/handle_consumption(mob/living/L, mob/living/victim, atom/A, obj/effect/dummy/slaughter/holder)
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/handle_consumption(mob/living/L, mob/living/victim, atom/enter_point, obj/effect/dummy/slaughter/holder)
return


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/sink_animation(atom/A, mob/living/L)
A.visible_message("<span class='danger'>[L] sinks into the shadows...</span>")
new /obj/effect/temp_visual/dir_setting/bloodcrawl(get_turf(L), L.dir, "shadowwalk_disappear")
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/sink_animation(atom/enter_point, mob/living/user)
enter_point.visible_message(span_danger("[user] sinks into the shadows..."))
new /obj/effect/temp_visual/dir_setting/bloodcrawl(get_turf(user), user.dir, "shadowwalk_disappear")


/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/post_phase_in(mob/living/L, obj/effect/dummy/slaughter/holder)
/obj/effect/proc_holder/spell/bloodcrawl/shadow_crawl/post_phase_in(mob/living/user, obj/effect/dummy/slaughter/holder)
..()
if(!istype(L, /mob/living/simple_animal/demon/shadow))
if(!istype(user, /mob/living/simple_animal/demon/shadow))
return
var/mob/living/simple_animal/demon/shadow/S = L
S.RegisterSignal(holder, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/simple_animal/demon/shadow, check_darkness))*/
var/mob/living/simple_animal/demon/shadow/demon = user
demon.RegisterSignal(holder, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/simple_animal/demon/shadow, check_darkness))

Loading

0 comments on commit 50c8780

Please sign in to comment.