diff --git a/code/datums/spells/bloodcrawl.dm b/code/datums/spells/bloodcrawl.dm
index 0e5db631223..320661b61c7 100644
--- a/code/datums/spells/bloodcrawl.dm
+++ b/code/datums/spells/bloodcrawl.dm
@@ -1,13 +1,14 @@
/obj/effect/proc_holder/spell/bloodcrawl
- name = "Blood crawl"
- desc = "Use blood to travel."
- charge_max = 10
+ name = "Blood Crawl"
+ desc = "Use pools of blood to phase out of existence."
+ charge_max = 0
clothes_req = 0
selection_type = "range"
range = 1
cooldown_min = 0
overlay = null
action_icon_state = "bloodcrawl"
+ action_background_icon_state = "bg_slaughter"
var/phased = 0
/obj/effect/proc_holder/spell/bloodcrawl/choose_targets(mob/user = usr)
@@ -16,7 +17,7 @@
perform(target)
return
revert_cast()
- user << "You need blood to blood crawl."
+ user << "There must be a nearby source of blood!"
/obj/effect/proc_holder/spell/bloodcrawl/perform(obj/effect/decal/cleanable/target, recharge = 1, mob/living/user = usr)
if(istype(user))
@@ -29,4 +30,4 @@
start_recharge()
return
revert_cast()
- user << "You cannot blood crawl."
\ No newline at end of file
+ user << "You are unable to blood crawl!"
\ No newline at end of file
diff --git a/code/modules/mob/living/bloodcrawl.dm b/code/modules/mob/living/bloodcrawl.dm
index 3f7bfba90cf..c185a60a582 100644
--- a/code/modules/mob/living/bloodcrawl.dm
+++ b/code/modules/mob/living/bloodcrawl.dm
@@ -35,7 +35,7 @@ obj/effect/dummy/slaughter/relaymove(mob/user, direction)
var/turf/mobloc = get_turf(src.loc)
src.notransform = TRUE
spawn(0)
- src.visible_message("[src] sinks into the pool of blood.")
+ src.visible_message("[src] sinks into the pool of blood!")
playsound(get_turf(src), 'sound/magic/enter_blood.ogg', 100, 1, -1)
var/obj/effect/dummy/slaughter/holder = PoolOrNew(/obj/effect/dummy/slaughter,mobloc)
src.ExtinguishMob()
@@ -45,41 +45,50 @@ obj/effect/dummy/slaughter/relaymove(mob/user, direction)
if(istype(src.pulling, /mob/living))
var/mob/living/victim = src.pulling
if(victim.stat == CONSCIOUS)
- src.visible_message("[victim] kicks free of the [src] at the last second!")
+ src.visible_message("[victim] kicks free of the blood pool just before entering it!")
else
victim.loc = holder
- src.visible_message("The [src] drags [victim] into the pool of blood!")
+ victim.emote("scream")
+ src.visible_message("[src] drags [victim] into the pool of blood!")
kidnapped = victim
src.loc = holder
src.holder = holder
if(kidnapped)
- src << "You begin to feast on [kidnapped]. You can not move while you are doing this."
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
- playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
- sleep(30)
+ src << "You begin to feast on [kidnapped]. You can not move while you are doing this."
+ for(var/i = 3; i > 0; i--)
+ playsound(get_turf(src),'sound/magic/Demon_consume.ogg', 100, 1)
+ sleep(30)
if(kidnapped)
- src << "You devour [kidnapped]. Your health is fully restored."
+ src << "You devour [kidnapped]. Your health is fully restored."
src.adjustBruteLoss(-1000)
src.adjustFireLoss(-1000)
src.adjustOxyLoss(-1000)
src.adjustToxLoss(-1000)
- kidnapped.ghostize()
- qdel(kidnapped)
+ if(istype(src, /mob/living/simple_animal/slaughter))
+ var/mob/living/simple_animal/slaughter/S = src
+ kidnapped << "You feel teeth sink into your flesh, and the--"
+ kidnapped.adjustBruteLoss(1000)
+ kidnapped.loc = src
+ S.consumed_mobs.Add(kidnapped)
+ else
+ kidnapped.ghostize()
+ qdel(kidnapped)
else
- src << "You happily devour...nothing? Your meal vanished at some point!"
+ src << "You happily devour... nothing? Your meal vanished at some point!"
src.notransform = 0
/mob/living/proc/phasein(obj/effect/decal/cleanable/B)
if(src.notransform)
- src << "Finish eating first!"
+ src << "Finish eating first!"
return 0
-
+ B.visible_message("[B] starts to bubble...")
+ if(!do_after(src, 20, target = B))
+ return
+ if(!B)
+ return
src.loc = B.loc
src.client.eye = src
- src.visible_message("The [src] rises out of the pool of blood!")
+ src.visible_message("[src] rises out of the pool of blood!")
playsound(get_turf(src), 'sound/magic/exit_blood.ogg', 100, 1, -1)
qdel(src.holder)
src.holder = null
diff --git a/code/modules/mob/living/simple_animal/morph/morph.dm b/code/modules/mob/living/simple_animal/morph/morph.dm
index b8d9d8e3230..c815f567578 100644
--- a/code/modules/mob/living/simple_animal/morph/morph.dm
+++ b/code/modules/mob/living/simple_animal/morph/morph.dm
@@ -1,9 +1,9 @@
#define MORPH_COOLDOWN 50
/mob/living/simple_animal/hostile/morph
- name = "Morph"
- real_name = "Morph"
- desc = "some amorphous blob"
+ name = "morph"
+ real_name = "morph"
+ desc = "A revolting, pulsating pile of flesh."
speak_emote = list("gurgles")
emote_hear = list("gurgles")
icon = 'icons/mob/animal.dmi'
@@ -28,16 +28,25 @@
see_invisible = SEE_INVISIBLE_MINIMUM
idle_vision_range = 1 // Only attack when target is close
wander = 0
+ attacktext = "glomps"
+ attack_sound = 'sound/effects/blobattack.ogg'
var/morphed = 0
var/atom/movable/form = null
var/morph_time = 0
+ var/playstyle_string = "You are a morph, an abomination of science created primarily with changeling cells. \
+ You may take the form of anything nearby by middle-clicking it. This process will alert any nearby \
+ observers, and can only be performed once every five seconds. While morphed, you move faster, but do \
+ less damage. In addition, anyone within three tiles will note an uncanny wrongness if examining you. \
+ You can attack any item or dead creature to consume it - creatures will fully restore your health. \
+ Finally, you can restore yourself to your original form while morphed by middle-clicking yourself."
+
/mob/living/simple_animal/hostile/morph/examine(mob/user)
if(morphed)
form.examine(user) // Refactor examine to return desc so it's static? Not sure if worth it
if(get_dist(user,src)<=3)
- user << "Looks odd!"
+ user << "It doesn't look quite right..."
else
..()
return
@@ -57,6 +66,7 @@
if(istype(A) && allowed(A))
assume(A)
else
+ src << "Your chameleon skin is still repairing itself!"
..()
/mob/living/simple_animal/hostile/morph/proc/assume(atom/movable/target)
@@ -72,11 +82,15 @@
else
overlays = target.overlays.Copy()
+ visible_message("[src] suddenly twists and changes shape, becoming a copy of [target]!", \
+ "You twist your body and assume the form of [target].")
+
name = target.name
icon = target.icon
icon_state = target.icon_state
overlays = target.overlays
+
//Morphed is weaker
melee_damage_lower = 5
melee_damage_upper = 5
@@ -93,6 +107,8 @@
//anim(loc,src,'icons/mob/mob.dmi',,"morph",,src.dir)
+ visible_message("[src] suddenly collapses in on itself, dissolving into a pile of green flesh!", \
+ "You reform to your normal body.")
name = initial(name)
icon = initial(icon)
icon_state = initial(icon_state)
@@ -108,7 +124,8 @@
/mob/living/simple_animal/hostile/morph/death()
if(morphed)
- visible_message("The [src] dissolves!")
+ visible_message("[src] twists and dissolves into a pile of green flesh!", \
+ "Your skin ruptures! Your flesh breaks apart! No disguise can ward off de--")
restore()
//Dump eaten stuff
@@ -148,7 +165,7 @@
var/mob/living/L = target
if(L.stat == DEAD)
if(do_after(src, 30, target = L))
- visible_message("[src] swallows the [target] whole!")
+ visible_message("[src] swallows [target] whole!")
L.loc = src
adjustBruteLoss(-50)
return
@@ -156,7 +173,7 @@
var/obj/item/I = target
if(!I.anchored)
if(do_after(src,20, target = I))
- visible_message("[src] swallows the [target] whole!")
+ visible_message("[src] swallows [target] whole!")
I.loc = src
return
target.attack_animal(src)
@@ -198,15 +215,10 @@
player_mind.assigned_role = "Morph"
player_mind.special_role = "Morph"
ticker.mode.traitors |= player_mind
- var/info = {"You are a Morph, a shapeshifting alien creature.
- You can assume the shape of anything in sight by Shift-Clicking it.
- You can only transform every 5 seconds.
- To return to your basic form Shift-Click on yourself.
- Base form is slow but strong, you're much weaker and faster when disguised.
- You can eat items and corpses by clicking on them,eating corpses will heal you."}
- S << info
- message_admins("[key_of_morph] has been made into Morph by an event.")
- log_game("[key_of_morph] was spawned as a Morph by an event.")
+ S << S.playstyle_string
+ S << 'sound/magic/Mutate.ogg'
+ message_admins("[key_of_morph] has been made into morph by an event.")
+ log_game("[key_of_morph] was spawned as a morph by an event.")
return 1
/datum/round_event/morph/start()
@@ -214,11 +226,11 @@
/datum/round_event/morph/proc/find_morph()
- message_admins("Attempted to spawn a Morph but there was no players available. Will try again momentarily.")
+ message_admins("Attempted to spawn a morph but there was no players available. Will try again momentarily.")
spawn(50)
if(get_morph(1))
- message_admins("Situation has been resolved, [key_of_morph] has been spawned as a Morph.")
- log_game("[key_of_morph] was spawned as a Morph by an event.")
+ message_admins("Situation has been resolved, [key_of_morph] has been spawned as a morph.")
+ log_game("[key_of_morph] was spawned as a morph by an event.")
return 0
- message_admins("Unfortunately, no candidates were available for becoming a Morph. Shutting down.")
+ message_admins("Unfortunately, no candidates were available for becoming a morph. Shutting down.")
return kill()
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
index 5f39ad01d46..07896ec81fa 100644
--- a/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
+++ b/code/modules/mob/living/simple_animal/slaughter/slaughter.dm
@@ -1,9 +1,9 @@
//////////////////The Monster
/mob/living/simple_animal/slaughter
- name = "Slaughter Demon"
- real_name = "Slaughter Demon"
- desc = "You should run."
+ name = "slaughter demon"
+ real_name = "slaughter demon"
+ desc = "A large, menacing creature covered in armored black scales."
speak_emote = list("gurgles")
emote_hear = list("wails","screeches")
response_help = "thinks better of touching"
@@ -31,10 +31,11 @@
var/boost = 0
bloodcrawl = BLOODCRAWL_EAT
see_invisible = SEE_INVISIBLE_MINIMUM
- var/playstyle_string = "You are the Slaughter Demon, a terible creature from another existence. You have a single desire: To kill. \
- You may Ctrl+Click on blood pools to travel through them, appearing and dissaapearing from the station at will. \
- Pulling a dead or critical mob while you enter a pool will pull them in with you, allowing you to feast. \
- You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. "
+ var/list/consumed_mobs = list()
+ var/playstyle_string = "You are a slaughter demon, a terrible creature from another realm. You have a single desire: To kill. \
+ You may use the \"Blood Crawl\" ability near blood pools to travel through them, appearing and dissaapearing from the station at will. \
+ Pulling a dead or unconscious mob while you enter a pool will pull them in with you, allowing you to feast and regain your health. \
+ You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. "
/mob/living/simple_animal/slaughter/New()
..()
@@ -52,10 +53,17 @@
/mob/living/simple_animal/slaughter/death()
..(1)
- new /obj/effect/decal/cleanable/blood (src.loc)
- new /obj/item/weapon/demonheart (src.loc)
+ new /obj/effect/decal/cleanable/blood (get_turf(src))
+ var/obj/effect/decal/cleanable/blood/innards = new (get_turf(src))
+ innards.icon = 'icons/obj/surgery.dmi'
+ innards.icon_state = "innards"
+ innards.name = "pile of viscera"
+ innards.desc = "A repulsive pile of guts and gore."
+ new /obj/item/organ/internal/heart/demon (src.loc)
playsound(get_turf(src),'sound/magic/demon_dies.ogg', 200, 1)
- visible_message("The [src] screams in anger as its form collapes into a pool of viscera.")
+ visible_message("[src] screams in anger as it collapses into a puddle of viscera, its most recent meals spilling out of it.")
+ for(var/mob/living/M in consumed_mobs)
+ M.loc = get_turf(src)
ghostize()
qdel(src)
return
@@ -67,23 +75,28 @@
boost = world.time + 30
-//////////The Loot
-
-/obj/item/weapon/demonheart
- name = "demon's heart"
- desc = "It's still faintly beating with rage"
+//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
+/obj/item/organ/internal/heart/demon
+ name = "demon heart"
+ desc = "Still it beats furiously, emanating an aura of utter hate."
icon = 'icons/obj/surgery.dmi'
- icon_state = "heart-on"
+ icon_state = "demon_heart"
origin_tech = "combat=5;biotech=8"
+ beating = 1 //What did you expect?
-/obj/item/weapon/demonheart/attack_self(mob/living/user)
- visible_message("[user] feasts upon the [src].")
+/obj/item/organ/internal/heart/demon/attack(mob/M, mob/living/user, obj/target)
+ if(M != user)
+ return ..()
+ user.visible_message("[user] raises [src] to their mouth and tears into it with their teeth!", \
+ "An unnatural hunger consumes you. You raise [src] your mouth and devour it!")
+ playsound(user, 'sound/magic/Demon_consume.ogg', 50, 1)
for(var/obj/effect/proc_holder/spell/knownspell in user.mind.spell_list)
if(knownspell.type == /obj/effect/proc_holder/spell/bloodcrawl)
- user <<"You already know how to blood crawl."
+ user <<"...and you don't feel any different."
qdel(src)
return
- user << "You absorb some of the demon's power!"
+ user.visible_message("[user]'s eyes flare a deep crimson!", \
+ "You feel a strange power seep into your body... you have absorbed the demon's blood-travelling powers!")
user.mind.AddSpell(new /obj/effect/proc_holder/spell/bloodcrawl)
+ user.drop_item()
qdel(src)
-
diff --git a/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm b/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
index de3e477ab6d..cbc845bc69d 100644
--- a/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
+++ b/code/modules/mob/living/simple_animal/slaughter/slaughterevent.dm
@@ -44,9 +44,10 @@
player_mind.special_role = "Slaughter Demon"
ticker.mode.traitors |= player_mind
S << S.playstyle_string
- S << "You are currently not currently in the same plane of existence as the station. Ctrl+Click a blood pool to manifest."
- message_admins("[key_of_slaughter] has been made into a Slaughter Demon by an event.")
- log_game("[key_of_slaughter] was spawned as a Slaughter Demon by an event.")
+ S << "You are currently not currently in the same plane of existence as the station. Blood Crawl near a blood pool to manifest."
+ S << 'sound/magic/demon_dies.ogg'
+ message_admins("[key_of_slaughter] has been made into a slaughter demon by an event.")
+ log_game("[key_of_slaughter] was spawned as a slaughter demon by an event.")
return 1
@@ -57,11 +58,11 @@
/datum/round_event/slaughter/proc/find_slaughter()
- message_admins("Attempted to spawn a Slaughter Demon but there was no players available. Will try again momentarily.")
+ message_admins("Attempted to spawn a slaughter demon but there was no players available. Will try again momentarily.")
spawn(50)
if(get_slaughter(1))
- message_admins("Situation has been resolved, [key_of_slaughter] has been spawned as a Slaughter Demon.")
- log_game("[key_of_slaughter] was spawned as a Slaughter Demon by an event.")
+ message_admins("Situation has been resolved, [key_of_slaughter] has been spawned as a slaughter demon.")
+ log_game("[key_of_slaughter] was spawned as a slaughter demon by an event.")
return 0
- message_admins("Unfortunately, no candidates were available for becoming a Slaugter Demon. Shutting down.")
+ message_admins("Unfortunately, no candidates were available for becoming a slaughter demon. Shutting down.")
return kill()
diff --git a/html/changelogs/Xhuis-DemonsAndMorphs.yml b/html/changelogs/Xhuis-DemonsAndMorphs.yml
new file mode 100644
index 00000000000..1862bea6f80
--- /dev/null
+++ b/html/changelogs/Xhuis-DemonsAndMorphs.yml
@@ -0,0 +1,13 @@
+author: Xhuis
+delete-after: True
+
+changes:
+ - tweak: "When a morph changes form, a message is shown to nearby people. This also happens upon undisguising."
+ - tweak: "Morphs now have an attack sound and message."
+ - tweak: "The Spawn Morph event now plays a sound to the chosen candidate."
+ - tweak: "Slaughter Demons (and other creatures with blood crawl) now take two seconds to emerge from blood pools. Entering is still instantaneous."
+ - tweak: "The demon heart's sprite has been updated."
+ - tweak: "Blood Crawl no longer has a 1-second cooldown, instead having none."
+ - tweak: "Creatures that can Blood Crawl now take two seconds to emerge from blood pools."
+ - tweak: "Slaughter demons now store devoured creatures, and will drop them upon death."
+ - tweak: "The Spawn Slaughter Demon event now plays a sound to the chosen candidate."
\ No newline at end of file
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index 23f5e04c7db..343654c5810 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index eefdb1ad455..bfb8378f049 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/obj/surgery.dmi b/icons/obj/surgery.dmi
index e1f7fe92119..53e3b56f76c 100644
Binary files a/icons/obj/surgery.dmi and b/icons/obj/surgery.dmi differ