diff --git a/code/datums/mind.dm b/code/datums/mind.dm index a3d9dbd8442..2e88f141f4a 100644 --- a/code/datums/mind.dm +++ b/code/datums/mind.dm @@ -1516,6 +1516,19 @@ spell.action.Grant(new_character) return +/datum/mind/proc/get_ghost(even_if_they_cant_reenter) + for(var/mob/dead/observer/G in dead_mob_list) + if(G.mind == src) + if(G.can_reenter_corpse || even_if_they_cant_reenter) + return G + break + +/datum/mind/proc/grab_ghost(force) + var/mob/dead/observer/G = get_ghost(even_if_they_cant_reenter = force) + . = G + if(G) + G.reenter_corpse() + //Initialisation procs /mob/proc/mind_initialize() if(mind) diff --git a/code/game/gamemodes/antag_spawner.dm b/code/game/gamemodes/antag_spawner.dm index 42d82639129..2e462a49ea5 100644 --- a/code/game/gamemodes/antag_spawner.dm +++ b/code/game/gamemodes/antag_spawner.dm @@ -72,6 +72,12 @@ desc = "A magically infused bottle of blood, distilled from countless murder victims. Used in unholy rituals to attract horrifying creatures." icon = 'icons/obj/wizard.dmi' icon_state = "vial" + var/shatter_msg = "You shatter the bottle, no \ + turning back now!" + var/veil_msg = "You sense a dark presence lurking \ + just beyond the veil..." + var/objective_verb = "Kill" + var/mob/living/demon_type = /mob/living/simple_animal/slaughter /obj/item/weapon/antag_spawner/slaughter_demon/attack_self(mob/user as mob) if(user.z == ZLEVEL_CENTCOMM)//this is to make sure the wizard does NOT summon a demon from the Den.. @@ -88,9 +94,9 @@ if(candidates.len > 0) var/mob/C = pick(candidates) - spawn_antag(C, get_turf(src.loc), "Slaughter Demon", user) - to_chat(user, "You shatter the bottle, no turning back now!") - to_chat(user, "You sense a dark presence lurking just beyond the veil...") + spawn_antag(C, get_turf(src.loc), initial(demon_type.name), user) + to_chat(user, "[shatter_msg]") + to_chat(user, "[veil_msg]") playsound(user.loc, 'sound/effects/Glassbr1.ogg', 100, 1) qdel(src) else @@ -99,22 +105,34 @@ /obj/item/weapon/antag_spawner/slaughter_demon/spawn_antag(var/client/C, var/turf/T, var/type = "", mob/user as mob) var /obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T) - var/mob/living/simple_animal/slaughter/S = new /mob/living/simple_animal/slaughter/(holder) + var/mob/living/simple_animal/slaughter/S = new demon_type(holder) S.vialspawned = TRUE S.holder = holder S.key = C.key - S.mind.assigned_role = "Slaughter Demon" - S.mind.special_role = "Slaughter Demon" + S.mind.assigned_role = S.name + S.mind.special_role = S.name ticker.mode.traitors += S.mind var/datum/objective/assassinate/KillDaWiz = new /datum/objective/assassinate KillDaWiz.owner = S.mind KillDaWiz.target = user.mind - KillDaWiz.explanation_text = "Kill [user.real_name], the one who was foolish enough to summon you." + KillDaWiz.explanation_text = "[objective_verb] [user.real_name], the one who was foolish enough to summon you." S.mind.objectives += KillDaWiz var/datum/objective/KillDaCrew = new /datum/objective KillDaCrew.owner = S.mind - KillDaCrew.explanation_text = "Kill everyone else while you're at it." + KillDaCrew.explanation_text = "[objective_verb] everyone else while you're at it." S.mind.objectives += KillDaCrew S.mind.objectives += KillDaCrew to_chat(S, "Objective #[1]: [KillDaWiz.explanation_text]") to_chat(S, "Objective #[2]: [KillDaCrew.explanation_text]") + + +/obj/item/weapon/antag_spawner/slaughter_demon/laughter + name = "vial of tickles" + desc = "A magically infused bottle of clown love, distilled from \ + countless hugging attacks. Used in funny rituals to attract \ + adorable creatures." + color = "#FF69B4" // HOT PINK + veil_msg = "You sense an adorable presence \ + lurking just beyond the veil..." + objective_verb = "Hug and Tickle" + demon_type = /mob/living/simple_animal/slaughter/laughter \ No newline at end of file diff --git a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm index bab7c597a69..a0a1f9f30d1 100644 --- a/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm +++ b/code/game/gamemodes/miniantags/slaughter/bloodcrawl.dm @@ -59,8 +59,15 @@ sleep(6) if(animation) qdel(animation) - for(var/i = 3; i > 0; i--) - playsound(get_turf(src),'sound/misc/Demon_consume.ogg', 100, 1) + var/sound + if(istype(src, /mob/living/simple_animal/slaughter)) + var/mob/living/simple_animal/slaughter/SD = src + sound = SD.feast_sound + else + sound = 'sound/misc/Demon_consume.ogg' + + for(var/i in 1 to 3) + playsound(get_turf(src), sound, 100, 1) sleep(30) if(kidnapped) to_chat(src, "You devour [kidnapped]. Your health is fully restored.") diff --git a/code/game/gamemodes/miniantags/slaughter/slaughter.dm b/code/game/gamemodes/miniantags/slaughter/slaughter.dm index e255394e7af..ac32105229a 100644 --- a/code/game/gamemodes/miniantags/slaughter/slaughter.dm +++ b/code/game/gamemodes/miniantags/slaughter/slaughter.dm @@ -18,6 +18,8 @@ stop_automated_movement = 1 status_flags = CANPUSH attack_sound = 'sound/misc/demon_attack1.ogg' + var/feast_sound = 'sound/misc/Demon_consume.ogg' + var/death_sound = 'sound/misc/demon_dies.ogg' atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) minbodytemp = 0 maxbodytemp = INFINITY @@ -47,6 +49,7 @@ 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/deathmessage = "screams in anger as it collapses into a puddle of viscera!" /mob/living/simple_animal/slaughter/New() @@ -88,8 +91,8 @@ /mob/living/simple_animal/slaughter/death() ..() - playsound(get_turf(src),'sound/misc/demon_dies.ogg', 200, 1) - visible_message("[src] screams in anger as it collapses into a puddle of viscera, its most recent meals spilling out of it.") + playsound(get_turf(src), death_sound, 200, 1) + visible_message("[src] [deathmessage].") for(var/mob/living/M in consumed_mobs) M.forceMove(get_turf(src)) ghostize() @@ -181,6 +184,36 @@ /obj/item/organ/internal/heart/demon/Stop() return 0 // Always beating. + +/mob/living/simple_animal/slaughter/laughter + // The laughter demon! It's everyone's best friend! It just wants to hug + // them so much, it wants to hug everyone at once! + name = "laughter demon" + real_name = "laughter demon" + desc = "A large, adorable creature covered in armor with pink bows." + speak_emote = list("giggles", "titters", "chuckles") + emote_hear = list("gaffaws", "laughs") + response_help = "hugs" + attacktext = "wildly tickles" + + attack_sound = 'sound/items/bikehorn.ogg' + feast_sound = 'sound/spookoween/scary_horn2.ogg' + death_sound = 'sound/misc/sadtrombone.ogg' + + icon_state = "bowmon" + icon_living = "bowmon" + deathmessage = "fades out, as all of its friends are released from its prison of hugs." + loot = list(/mob/living/simple_animal/pet/cat/kitten{name = "Laughter"}) + +/mob/living/simple_animal/slaughter/laughter/death() + for(var/mob/living/M in consumed_mobs) + if(M.revive()) + M.grab_ghost(force = TRUE) + playsound(get_turf(src), feast_sound, 50, 1, -1) + to_chat(M, "You leave the [src]'s warm embrace, and feel ready to take on the world.") + ..() + + //Objectives and helpers. //Objective info, Based on Reverent mini Atang diff --git a/code/game/gamemodes/wizard/spellbook.dm b/code/game/gamemodes/wizard/spellbook.dm index 8d3d7cc4278..ac487a8e703 100644 --- a/code/game/gamemodes/wizard/spellbook.dm +++ b/code/game/gamemodes/wizard/spellbook.dm @@ -363,6 +363,21 @@ limit = 3 category = "Assistance" +/datum/spellbook_entry/item/hugbottle + name = "Bottle of Tickles" + desc = "A bottle of magically infused fun, the smell of which will \ + attract adorable extradimensional beings when broken. These beings \ + are similar to slaughter demons, but they do not permamently kill \ + their victims, instead putting them in an extradimensional hugspace, \ + to be released on the demon's death. Chaotic, but not ultimately \ + damaging. The crew's reaction to the other hand could be very \ + destructive." + item_path = /obj/item/weapon/antag_spawner/slaughter_demon/laughter + cost = 1 //non-destructive; it's just a jape, sibling! + log_name = "HB" + limit = 3 + category = "Assistance" + /datum/spellbook_entry/item/tarotdeck name = "Tarot Deck" desc = "A deck of tarot cards that can be used to summon a spirit companion for the wizard." diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index f41cef386aa..7bce0e0e0cf 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1328,11 +1328,11 @@ mob/proc/yank_out_object() /mob/proc/get_ghost(even_if_they_cant_reenter = 0) if(mind) - for(var/mob/dead/observer/G in dead_mob_list) - if(G.mind == mind) - if(G.can_reenter_corpse || even_if_they_cant_reenter) - return G - break + return mind.get_ghost(even_if_they_cant_reenter) + +/mob/proc/grab_ghost(force) + if(mind) + return mind.grab_ghost(force = force) /mob/proc/notify_ghost_cloning(var/message = "Someone is trying to revive you. Re-enter your corpse if you want to be revived!", var/sound = 'sound/effects/genetics.ogg', var/atom/source = null) var/mob/dead/observer/ghost = get_ghost() diff --git a/icons/mob/mob.dmi b/icons/mob/mob.dmi index 685e6b2977b..491349985d4 100644 Binary files a/icons/mob/mob.dmi and b/icons/mob/mob.dmi differ diff --git a/sound/spookoween/scary_horn2.ogg b/sound/spookoween/scary_horn2.ogg new file mode 100644 index 00000000000..fb2805bd2cd Binary files /dev/null and b/sound/spookoween/scary_horn2.ogg differ