diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 8947a87be90..a650d6fd978 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -43,9 +43,9 @@
#define isslime(A) (istype((A), /mob/living/simple_animal/slime))
-#define ispulsedemon(A) (istype(A, /mob/living/simple_animal/demon/pulse_demon))
+#define ispulsedemon(A) (istype(A, /mob/living/basic/demon/pulse_demon))
-#define isshadowdemon(A) (istype(A, /mob/living/simple_animal/demon/shadow))
+#define isshadowdemon(A) (istype(A, /mob/living/basic/demon/shadow))
// Basic mobs
diff --git a/code/__DEFINES/mob_defines.dm b/code/__DEFINES/mob_defines.dm
index 39e0016bb4c..dfb55686bcc 100644
--- a/code/__DEFINES/mob_defines.dm
+++ b/code/__DEFINES/mob_defines.dm
@@ -256,8 +256,8 @@
#define ishostile(A) (istype((A), /mob/living/simple_animal/hostile))
#define isretaliate(A) (istype((A), /mob/living/simple_animal/hostile/retaliate))
#define isterrorspider(A) (istype((A), /mob/living/simple_animal/hostile/poison/terror_spider) || istype((A), /mob/living/basic/spiderling/terror_spiderling))
-#define isslaughterdemon(A) (istype((A), /mob/living/simple_animal/demon/slaughter))
-#define isdemon(A) (istype((A), /mob/living/simple_animal/demon))
+#define isslaughterdemon(A) (istype((A), /mob/living/basic/demon/slaughter))
+#define isdemon(A) (istype((A), /mob/living/basic/demon))
#define iscat(A) (istype((A), /mob/living/simple_animal/pet/cat))
#define isgorilla(A) (istype((A), /mob/living/basic/gorilla))
#define ismorph(A) (istype((A), /mob/living/simple_animal/hostile/morph))
diff --git a/code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm b/code/datums/components/cross_shock_component.dm
similarity index 100%
rename from code/game/gamemodes/miniantags/pulsedemon/cross_shock_component.dm
rename to code/datums/components/cross_shock_component.dm
diff --git a/code/datums/spells/bloodcrawl.dm b/code/datums/spells/bloodcrawl.dm
index 425a1721f8b..1314f938e32 100644
--- a/code/datums/spells/bloodcrawl.dm
+++ b/code/datums/spells/bloodcrawl.dm
@@ -81,7 +81,7 @@
GM.set_nitrogen(MOLES_N2STANDARD)
GM.set_temperature(T20C)
return GM
-
+
/datum/spell/bloodcrawl/proc/block_hands(mob/living/carbon/C)
if(C.l_hand || C.r_hand)
to_chat(C, "You may not hold items while blood crawling!")
@@ -141,7 +141,7 @@
)
var/sound
if(isslaughterdemon(L))
- var/mob/living/simple_animal/demon/slaughter/SD = L
+ var/mob/living/basic/demon/slaughter/SD = L
sound = SD.feast_sound
else
sound = 'sound/misc/demon_consume.ogg'
@@ -171,7 +171,7 @@
L.adjustFireLoss(-25)
if(isslaughterdemon(L))
- var/mob/living/simple_animal/demon/slaughter/demon = L
+ var/mob/living/basic/demon/slaughter/demon = L
demon.devoured++
to_chat(victim, "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)
@@ -236,7 +236,7 @@
/datum/spell/bloodcrawl/proc/post_phase_out(atom/A, mob/living/L)
if(isslaughterdemon(L))
- var/mob/living/simple_animal/demon/slaughter/S = L
+ var/mob/living/basic/demon/slaughter/S = L
S.speed = 0
S.boost = world.time + 6 SECONDS
var/old_color = L.color
@@ -275,7 +275,7 @@
action_icon_state = "shadow_crawl"
/datum/spell/bloodcrawl/shadow_crawl/can_cast(mob/user, charge_check, show_message)
- var/mob/living/simple_animal/demon/shadow/current_demon = user
+ var/mob/living/basic/demon/shadow/current_demon = user
if(!istype(current_demon))
return ..()
@@ -303,10 +303,10 @@
/datum/spell/bloodcrawl/shadow_crawl/post_phase_in(mob/living/L, obj/effect/dummy/slaughter/holder)
..()
- if(!istype(L, /mob/living/simple_animal/demon/shadow))
+ if(!istype(L, /mob/living/basic/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/basic/demon/shadow/S = L
+ S.RegisterSignal(holder, COMSIG_MOVABLE_MOVED, TYPE_PROC_REF(/mob/living/basic/demon/shadow, check_darkness))
#undef BLOODCRAWL
#undef BLOODCRAWL_EAT
diff --git a/code/game/gamemodes/cult/cult_actions.dm b/code/game/gamemodes/cult/cult_actions.dm
index a43b78fba66..4329d6eb08f 100644
--- a/code/game/gamemodes/cult/cult_actions.dm
+++ b/code/game/gamemodes/cult/cult_actions.dm
@@ -47,7 +47,7 @@
var/title
var/large = FALSE
var/living_message
- if(istype(user, /mob/living/simple_animal/demon/slaughter/cult)) //Harbringers of the Slaughter
+ if(istype(user, /mob/living/basic/demon/slaughter/cult)) //Harbringers of the Slaughter
title = "Harbringer of the Slaughter"
large = TRUE
else
diff --git a/code/game/gamemodes/cult/cult_items.dm b/code/game/gamemodes/cult/cult_items.dm
index bcb138e8cfe..eeafdbba7f2 100644
--- a/code/game/gamemodes/cult/cult_items.dm
+++ b/code/game/gamemodes/cult/cult_items.dm
@@ -281,7 +281,7 @@
if(curselimit > 1)
to_chat(user, "We have exhausted our ability to curse the shuttle.")
return
- if(locate(/obj/singularity/narsie) in GLOB.poi_list || locate(/mob/living/simple_animal/demon/slaughter/cult) in GLOB.mob_list)
+ if(locate(/obj/singularity/narsie) in GLOB.poi_list || locate(/mob/living/basic/demon/slaughter/cult) in GLOB.mob_list)
to_chat(user, "Nar'Sie or her avatars are already on this plane, there is no delaying the end of all things.")
return
diff --git a/code/game/gamemodes/miniantags/demons/slaughter_demon/slaughter.dm b/code/game/gamemodes/miniantags/demons/slaughter_demon/slaughter.dm
deleted file mode 100644
index 621b56c4676..00000000000
--- a/code/game/gamemodes/miniantags/demons/slaughter_demon/slaughter.dm
+++ /dev/null
@@ -1,357 +0,0 @@
-//////////////////The Monster
-
-/mob/living/simple_animal/demon/slaughter
- name = "slaughter demon"
- real_name = "slaughter demon"
- desc = "A large, menacing creature covered in armored black scales. You should run."
- maxHealth = 240
- health = 240
- speak = list("ire", "ego", "nahlizet", "certum", "veri", "jatkaa", "balaq", "mgar", "karazet", "geeri", "orkan", "allaq")
- icon = 'icons/mob/mob.dmi'
- icon_state = "daemon"
- icon_living = "daemon"
- var/boost = 0
- var/feast_sound = 'sound/misc/demon_consume.ogg'
- var/devoured = 0
- var/list/consumed_mobs = list()
-
- var/list/nearby_mortals = list()
- var/cooldown = 0
- var/gorecooldown = 0
- var/vialspawned = FALSE
- loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon/slaughter)
- var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: to kill. \
- You may use the blood crawl icon when on blood pools to travel through them, appearing and dissapearing 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. "
- deathmessage = "screams in anger as it collapses into a puddle of viscera!"
-
-
-/mob/living/simple_animal/demon/slaughter/New()
- ..()
- remove_from_all_data_huds()
- ADD_TRAIT(src, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
- var/datum/spell/bloodcrawl/bloodspell = new
- AddSpell(bloodspell)
- if(istype(loc, /obj/effect/dummy/slaughter))
- bloodspell.phased = TRUE
- addtimer(CALLBACK(src, PROC_REF(attempt_objectives)), 5 SECONDS)
-
-
-/mob/living/simple_animal/demon/slaughter/Life(seconds, times_fired)
- ..()
- if(boost < world.time)
- speed = 1
- else
- speed = 0
-
-/mob/living/simple_animal/demon/slaughter/proc/attempt_objectives()
- if(mind)
- var/list/messages = list()
- messages.Add(playstyle_string)
- messages.Add("You are not currently in the same plane of existence as the station. Use the blood crawl action at a blood pool to manifest.")
- SEND_SOUND(src, sound('sound/misc/demon_dies.ogg'))
- if(!vialspawned)
- SSticker.mode.traitors |= mind
- mind.add_mind_objective(/datum/objective/slaughter)
- mind.add_mind_objective(/datum/objective/demon_fluff)
- messages.Add(mind.prepare_announce_objectives(FALSE))
-
- messages.Add("For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Slaughter_Demon)")
- to_chat(src, chat_box_red(messages.Join("
")))
-
-
-/obj/effect/decal/cleanable/blood/innards
- icon = 'icons/obj/surgery.dmi'
- icon_state = "innards"
- base_icon = 'icons/obj/surgery.dmi'
- icon_state = "innards"
- random_icon_states = list("innards")
- name = "pile of viscera"
- desc = "A repulsive pile of guts and gore."
- weightless_icon = 'icons/obj/surgery.dmi'
-
-/mob/living/simple_animal/demon/slaughter/Destroy()
- // Only execute the below if we successfully died
- for(var/mob/living/M in consumed_mobs)
- REMOVE_TRAIT(M, TRAIT_UNREVIVABLE, "demon")
- release_consumed(M)
- . = ..()
-
-/mob/living/simple_animal/demon/slaughter/proc/release_consumed(mob/living/M)
- M.forceMove(get_turf(src))
-
-
-// Midround slaughter demon, less tanky
-
-/mob/living/simple_animal/demon/slaughter/lesser
- maxHealth = 170
- health = 170
-
-// Cult slaughter demon
-/// Summoned as part of the cult objective "Bring the Slaughter"
-/mob/living/simple_animal/demon/slaughter/cult
- name = "harbinger of the slaughter"
- real_name = "harbinger of the Slaughter"
- desc = "An awful creature from beyond the realms of madness."
- maxHealth = 540
- health = 540
- melee_damage_upper = 60
- melee_damage_lower = 60
- environment_smash = ENVIRONMENT_SMASH_RWALLS //Smashes through EVERYTHING - r-walls included
- faction = list("cult")
- playstyle_string = "You are a Harbinger of the Slaughter. Brought forth by the servants of Nar'Sie, you have a single purpose: slaughter the heretics \
- who do not worship your master. You may use the ability 'Blood Crawl' near a pool of blood to enter it and become incorporeal. Using the ability again near a blood pool will allow you \
- to emerge from it. You are fast, powerful, and almost invincible. By dragging a dead or unconscious body into a blood pool with you, you will consume it after a time and fully regain \
- your health. You may use the ability 'Sense Victims' in your Cultist tab to locate a random, living heretic."
-
-/datum/spell/sense_victims
- name = "Sense Victims"
- desc = "Sense the location of heretics."
- base_cooldown = 0
- clothes_req = FALSE
- overlay = null
- action_icon_state = "bloodcrawl"
- action_background_icon_state = "bg_cult"
-
-/datum/spell/sense_victims/create_new_targeting()
- return new /datum/spell_targeting/alive_mob_list
-
-/datum/spell/sense_victims/valid_target(mob/living/target, user)
- return target.stat == CONSCIOUS && target.key && !IS_CULTIST(target) // Only conscious, non cultist players
-
-/datum/spell/sense_victims/cast(list/targets, mob/user)
- var/mob/living/victim = targets[1]
- to_chat(victim, "You feel an awful sense of being watched...")
- victim.Stun(6 SECONDS) //HUE
- var/area/A = get_area(victim)
- if(!A)
- to_chat(user, "You could not locate any sapient heretics for the Slaughter.")
- return 0
- to_chat(user, "You sense a terrified soul at [A]. Show [A.p_them()] the error of [A.p_their()] ways.")
-
-/mob/living/simple_animal/demon/slaughter/cult/New()
- ..()
- spawn(5)
- var/list/demon_candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, 10 SECONDS, source = /mob/living/simple_animal/demon/slaughter/cult)
- if(!length(demon_candidates))
- visible_message("[src] disappears in a flash of red light!")
- qdel(src)
- return
- if(QDELETED(src)) // Just in case
- return
- var/mob/M = pick(demon_candidates)
- var/mob/living/simple_animal/demon/slaughter/cult/S = src
- if(!M || !M.client)
- visible_message("[src] disappears in a flash of red light!")
- qdel(src)
- return
- var/client/C = M.client
-
- S.key = C.key
- dust_if_respawnable(M)
- S.mind.assigned_role = "Harbinger of the Slaughter"
- S.mind.special_role = "Harbinger of the Slaughter"
- to_chat(S, playstyle_string)
- S.mind.add_antag_datum(/datum/antagonist/cultist)
- var/datum/spell/sense_victims/SV = new
- AddSpell(SV)
-
- S.mind.add_mind_objective(/datum/objective/cult_slaughter)
- var/list/messages = S.mind.prepare_announce_objectives(FALSE)
- to_chat(S, chat_box_red(messages.Join("
")))
-
-////////////////////The Powers
-
-//Paradise Port: I added this because..SPOOPY DEMON IN YOUR BRAIN
-
-
-/datum/action/innate/demon_whisper
- name = "Demonic Whisper"
- button_icon_state = "demon_comms"
- background_icon_state = "bg_demon"
-
-/datum/action/innate/demon_whisper/proc/choose_targets(mob/user = usr)//yes i am copying from telepathy..hush...
- var/list/validtargets = list()
- for(var/mob/living/M in view(user.client.maxview(), get_turf(user)))
- if(M && M.mind && M.stat != DEAD)
- if(M == user)
- continue
-
- validtargets += M
-
- if(!length(validtargets))
- to_chat(usr, "There are no valid targets!")
- return
-
- var/mob/living/target = tgui_input_list(user, "Choose the target to talk to", "Targeting", validtargets)
- return target
-
-/datum/action/innate/demon_whisper/Activate()
- var/mob/living/choice = choose_targets()
- if(!choice)
- return
-
- var/msg = tgui_input_text(usr, "What do you wish to tell [choice]?", null, "")
- if(!msg)
- return
- log_say("(SLAUGHTER to [key_name(choice)]) [msg]", usr)
- to_chat(usr, "You whisper to [choice]: [msg]")
- to_chat(choice, "Suddenly a strange, demonic voice resonates in your head... [msg]")
- for(var/mob/dead/observer/G in GLOB.player_list)
- G.show_message("Demonic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [choice] ([ghost_follow_link(choice, ghost=G)]): [msg]")
-
-
-//////////The Loot
-
-// Demon heart base type
-/obj/item/organ/internal/heart/demon
- name = "demon heart"
- desc = "Still it beats furiously, emanating an aura of utter hate."
- icon_state = "demon_heart"
- origin_tech = "combat=5;biotech=7"
- organ_datums = list(/datum/organ/heart/always_beating, /datum/organ/battery)
-
-/obj/item/organ/internal/heart/demon/update_icon_state()
- return //always beating visually
-
-/obj/item/organ/internal/heart/demon/prepare_eat()
- return // Just so people don't accidentally waste it
-
-/obj/item/organ/internal/heart/demon/attack_self__legacy__attackchain(mob/living/user)
- user.visible_message("[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_their()] teeth!", \
- "An unnatural hunger consumes you. You raise [src] to your mouth and devour it!")
- playsound(user, 'sound/misc/demon_consume.ogg', 50, 1)
-
-//////////The Loot
-
-//The loot from killing a slaughter demon - can be consumed to allow the user to blood crawl
-/// SLAUGHTER DEMON HEART
-
-/obj/item/organ/internal/heart/demon/slaughter/attack_self__legacy__attackchain(mob/living/user)
- ..()
-
- // Eating the heart for the first time. Gives basic bloodcrawling. This is the only time we need to insert the heart.
- if(!HAS_TRAIT(user, TRAIT_BLOODCRAWL))
- 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!")
- ADD_TRAIT(user, TRAIT_BLOODCRAWL, "bloodcrawl")
- user.drop_item()
- insert(user) //Consuming the heart literally replaces your heart with a demon heart. H A R D C O R E.
- return TRUE
-
- // Eating a 2nd heart. Gives the ability to drag people into blood and eat them.
- if(HAS_TRAIT(user, TRAIT_BLOODCRAWL))
- to_chat(user, "You feel differ- CONSUME THEM!")
- ADD_TRAIT(user, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
- qdel(src) // Replacing their demon heart with another demon heart is pointless, just delete this one and return.
- return TRUE
-
- // Eating any more than 2 demon hearts does nothing.
- to_chat(user, "...and you don't feel any different.")
- qdel(src)
-
-/obj/item/organ/internal/heart/demon/slaughter/insert(mob/living/carbon/M, special = 0)
- . = ..()
- if(M.mind)
- M.mind.AddSpell(new /datum/spell/bloodcrawl(null))
-
-/obj/item/organ/internal/heart/demon/slaughter/remove(mob/living/carbon/M, special = 0)
- . = ..()
- if(M.mind)
- REMOVE_TRAIT(M, TRAIT_BLOODCRAWL, "bloodcrawl")
- REMOVE_TRAIT(M, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
- M.mind.RemoveSpell(/datum/spell/bloodcrawl)
-
-/mob/living/simple_animal/demon/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"
- maxHealth = 215
- health = 215
- melee_damage_lower = 25
- melee_damage_upper = 25
- playstyle_string = "You are the Laughter Demon, an adorable creature from another existence. You have a single desire: to hug and tickle. \
- You may use the blood crawl icon when on blood pools to travel through them, appearing and dissapearing 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 hug them. \
- You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
- (You should be attacking people on harm intent, and not nuzzling them.)"
-
- 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/demon/slaughter/laughter/release_consumed(mob/living/M)
- if(M.revive())
- M.grab_ghost(force = TRUE)
- playsound(get_turf(src), feast_sound, 50, TRUE, -1)
- to_chat(M, "You leave [src]'s warm embrace, and feel ready to take on the world.")
- ..(M)
-
-
-//Objectives and helpers.
-
-//Objective info, Based on Reverent mini Atang
-/datum/objective/slaughter
- needs_target = FALSE
- var/targetKill = 10
-
-/datum/objective/slaughter/New()
- targetKill = rand(10,20)
- explanation_text = "Devour [targetKill] mortals."
- ..()
-
-/datum/objective/slaughter/check_completion()
- var/kill_count = 0
- for(var/datum/mind/M in get_owners())
- if(!isslaughterdemon(M.current) || QDELETED(M.current))
- continue
- var/mob/living/simple_animal/demon/slaughter/R = M.current
- kill_count += R.devoured
- if(kill_count >= targetKill)
- return TRUE
- return FALSE
-
-/datum/objective/demon_fluff
- name = "Spread blood"
- needs_target = FALSE
-
-/datum/objective/demon_fluff/New()
- find_target()
- var/targetname = "someone"
- if(target && target.current)
- targetname = target.current.real_name
- var/list/explanation_texts = list(
- "Spread blood all over the bridge.",
- "Spread blood all over the brig.",
- "Spread blood all over the chapel.",
- "Kill or Destroy all Janitors or Sanitation bots.",
- "Spare a few after striking them... make them bleed before the harvest.",
- "Hunt those that try to hunt you first.",
- "Hunt those that run away from you in fear",
- "Show [targetname] the power of blood.",
- "Drive [targetname] insane with demonic whispering."
- )
- // As this is a fluff objective, we don't need a target, so we want to null it out.
- // We don't want the demon getting a "Time for Plan B" message if the target cryos.
- target = null
- explanation_text = pick(explanation_texts)
- ..()
-
-/datum/objective/demon_fluff/check_completion()
- return TRUE
-
-/datum/objective/cult_slaughter
- explanation_text = "Bring forth the Slaughter to the nonbelievers."
- needs_target = FALSE
diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_objectives.dm b/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_objectives.dm
deleted file mode 100644
index 64d9b8af4e0..00000000000
--- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_objectives.dm
+++ /dev/null
@@ -1,57 +0,0 @@
-/datum/objective/pulse_demon/infest
- name = "Hijack APCs"
- /// Amount of APCs we need to hijack, can be 15, 20, or 25
- var/amount = 0
-
-/datum/objective/pulse_demon/infest/New()
- . = ..()
- amount = rand(3, 5) * 5
- explanation_text = "Hijack [amount] APCs."
-
-/datum/objective/pulse_demon/infest/check_completion()
- if(..())
- return TRUE
- var/hijacked = 0
- for(var/datum/mind/M in get_owners())
- if(!ispulsedemon(M.current) || QDELETED(M.current))
- continue
- var/mob/living/simple_animal/demon/pulse_demon/demon = M.current
- hijacked += length(demon.hijacked_apcs)
- return hijacked >= amount
-
-/datum/objective/pulse_demon/drain
- name = "Drain Power"
- /// Amount of power we need to drain, ranges from 500 KW to 5 MW
- var/amount = 0
-
-/datum/objective/pulse_demon/drain/New()
- . = ..()
- amount = rand(1, 10) * 500000
- explanation_text = "Drain [format_si_suffix(amount)]W of power."
-
-/datum/objective/pulse_demon/drain/check_completion()
- if(..())
- return TRUE
- var/drained = 0
- for(var/datum/mind/M in get_owners())
- if(!ispulsedemon(M.current) || QDELETED(M.current))
- continue
- var/mob/living/simple_animal/demon/pulse_demon/demon = M.current
- drained += demon.charge_drained
- return drained >= amount
-
-// Requires 1 APC to be hacked and not destroyed to complete
-/datum/objective/pulse_demon/tamper
- name = "Tamper Machinery"
- explanation_text = "Cause mischief amongst the machines in rooms with APCs you've hijacked, and defend yourself from anyone trying to stop you."
-
-/datum/objective/pulse_demon/tamper/check_completion()
- if(..())
- return TRUE
- for(var/datum/mind/M in get_owners())
- if(!ispulsedemon(M.current) || QDELETED(M.current))
- continue
- var/mob/living/simple_animal/demon/pulse_demon/demon = M.current
- if(!length(demon.hijacked_apcs) || !M.active || demon.stat == DEAD)
- return FALSE
- return TRUE
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index 5bfc0d76f83..74b2b554987 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -184,7 +184,7 @@
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/demon/slaughter
+ var/mob/living/demon_type = /mob/living/basic/demon/slaughter
/obj/item/antag_spawner/slaughter_demon/attack_self__legacy__attackchain(mob/user)
if(level_blocks_magic(user.z)) //this is to make sure the wizard does NOT summon a demon from the Den..
@@ -213,9 +213,9 @@
/obj/item/antag_spawner/slaughter_demon/spawn_antag(client/C, turf/T, type = "", mob/user)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(T)
- var/mob/living/simple_animal/demon/D = new demon_type(holder)
- if(istype(D, /mob/living/simple_animal/demon/slaughter))
- var/mob/living/simple_animal/demon/slaughter/S = D
+ var/mob/living/basic/demon/D = new demon_type(holder)
+ if(istype(D, /mob/living/basic/demon/slaughter))
+ var/mob/living/basic/demon/slaughter/S = D
S.vialspawned = TRUE
D.key = C.key
@@ -246,7 +246,7 @@
veil_msg = "You sense an adorable presence \
lurking just beyond the veil..."
objective_verb = "Hug and tickle"
- demon_type = /mob/living/simple_animal/demon/slaughter/laughter
+ demon_type = /mob/living/basic/demon/slaughter/laughter
/obj/item/antag_spawner/slaughter_demon/shadow
name = "vial of shadow"
@@ -256,7 +256,7 @@
icon_state = "vialshadows"
veil_msg = "You sense a dark presence \
lurking in the shadows..."
- demon_type = /mob/living/simple_animal/demon/shadow
+ demon_type = /mob/living/basic/demon/shadow
///////////MORPH
@@ -397,7 +397,7 @@
var/shatter_msg = "You shatter the bulb, no turning back now!"
var/veil_msg = "The creature sparks energetically and zips away..."
var/objective_verb = "Electrocute"
- var/mob/living/demon_type = /mob/living/simple_animal/demon/pulse_demon/wizard
+ var/mob/living/demon_type = /mob/living/basic/demon/pulse_demon/wizard
/obj/item/antag_spawner/pulse_demon/attack_self__legacy__attackchain(mob/user)
if(level_blocks_magic(user.z))
@@ -436,7 +436,7 @@
var/datum/mind/player_mind = new /datum/mind(C.key)
player_mind.active = TRUE
- var/mob/living/simple_animal/demon/pulse_demon/wizard/demon = new(T)
+ var/mob/living/basic/demon/pulse_demon/wizard/demon = new(T)
player_mind.transfer_to(demon)
player_mind.assigned_role = SPECIAL_ROLE_DEMON
player_mind.special_role = SPECIAL_ROLE_DEMON
diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_event.dm b/code/modules/events/pulsedemon_event.dm
similarity index 94%
rename from code/game/gamemodes/miniantags/pulsedemon/pulsedemon_event.dm
rename to code/modules/events/pulsedemon_event.dm
index 2fb91852d07..594e946f98e 100644
--- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_event.dm
+++ b/code/modules/events/pulsedemon_event.dm
@@ -5,7 +5,7 @@
var/key_of_pulsedemon
/datum/event/spawn_pulsedemon/proc/get_pulsedemon()
- var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a pulse demon?", ROLE_DEMON, FALSE, source = /mob/living/simple_animal/demon/pulse_demon)
+ var/list/candidates = SSghost_spawns.poll_candidates("Do you want to play as a pulse demon?", ROLE_DEMON, FALSE, source = /mob/living/basic/demon/pulse_demon)
if(!length(candidates))
message_admins("no candidates were found for the pulse demon event.")
kill()
@@ -23,7 +23,7 @@
player_mind.active = TRUE
var/turf/spawn_loc = get_spawn_loc(player_mind.current)
- var/mob/living/simple_animal/demon/pulse_demon/demon = new(spawn_loc)
+ var/mob/living/basic/demon/pulse_demon/demon = new(spawn_loc)
player_mind.transfer_to(demon)
message_admins("[key_name_admin(demon)] has been made into a [initial(demon.name)] by an event.")
log_game("[key_name_admin(demon)] was spawned as a [initial(demon.name)] by an event.")
diff --git a/code/modules/events/slaughterevent.dm b/code/modules/events/slaughterevent.dm
index f26fa697139..c1508c4cd8d 100644
--- a/code/modules/events/slaughterevent.dm
+++ b/code/modules/events/slaughterevent.dm
@@ -2,7 +2,7 @@
name = "Slaughter Demon"
noAutoEnd = TRUE
var/key_of_slaughter
- var/mob/living/simple_animal/demon/demon = /mob/living/simple_animal/demon/slaughter/lesser
+ var/mob/living/basic/demon/demon = /mob/living/basic/demon/slaughter/lesser
nominal_severity = EVENT_LEVEL_MAJOR
role_weights = list(ASSIGNMENT_SECURITY = 5, ASSIGNMENT_JANITOR = 5, ASSIGNMENT_MEDICAL = 3, ASSIGNMENT_CREW = 0.7)
role_requirements = list(ASSIGNMENT_SECURITY = 4, ASSIGNMENT_JANITOR = 1, ASSIGNMENT_MEDICAL = 2, ASSIGNMENT_CREW = 25)
@@ -29,7 +29,7 @@
dust_if_respawnable(C)
var/turf/spawn_loc = get_spawn_loc(player_mind.current)
var/obj/effect/dummy/slaughter/holder = new /obj/effect/dummy/slaughter(spawn_loc)
- var/mob/living/simple_animal/demon/S = new demon(holder)
+ var/mob/living/basic/demon/S = new demon(holder)
player_mind.transfer_to(S)
player_mind.assigned_role = "Demon"
player_mind.special_role = SPECIAL_ROLE_DEMON
@@ -54,11 +54,11 @@
/datum/event/spawn_slaughter/greater
name = "Greater Slaughter Demon"
- demon = /mob/living/simple_animal/demon/slaughter
+ demon = /mob/living/basic/demon/slaughter
/datum/event/spawn_slaughter/shadow
name = "Shadow Demon"
- demon = /mob/living/simple_animal/demon/shadow
+ demon = /mob/living/basic/demon/shadow
// Same as slaughter but without Jani
role_weights = list(ASSIGNMENT_SECURITY = 5, ASSIGNMENT_MEDICAL = 3, ASSIGNMENT_CREW = 0.7)
role_requirements = list(ASSIGNMENT_SECURITY = 4, ASSIGNMENT_MEDICAL = 2, ASSIGNMENT_CREW = 25)
diff --git a/code/game/gamemodes/miniantags/demons/demon.dm b/code/modules/mob/living/basic/hostile/demons/demon.dm
similarity index 53%
rename from code/game/gamemodes/miniantags/demons/demon.dm
rename to code/modules/mob/living/basic/hostile/demons/demon.dm
index 5c12637d637..a6e8c90fe86 100644
--- a/code/game/gamemodes/miniantags/demons/demon.dm
+++ b/code/modules/mob/living/basic/hostile/demons/demon.dm
@@ -1,22 +1,24 @@
-/mob/living/simple_animal/demon
+/mob/living/basic/demon
name = "a generic demon"
desc = "you shouldnt be reading this, file a github report."
- speak_emote = list("gurgles")
- emote_hear = list("wails","screeches")
- response_help = "thinks better of touching"
- response_disarm = "flails at"
- response_harm = "punches"
+ speak_emote = list("gurgles", "wails", "screeches")
+ response_help_continuous = "thinks better of touching"
+ response_help_simple = "thinks better of touching"
+ response_disarm_continuous = "flails at"
+ response_disarm_simple = "flail at"
+ response_harm_continuous = "punches"
+ response_harm_simple = "punches"
a_intent = INTENT_HARM
mob_biotypes = MOB_ORGANIC | MOB_HUMANOID
- stop_automated_movement = TRUE
attack_sound = 'sound/misc/demon_attack1.ogg'
death_sound = 'sound/misc/demon_dies.ogg'
atmos_requirements = list("min_oxy" = 16, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
unsuitable_atmos_damage = 10
- minbodytemp = 0
- maxbodytemp = INFINITY
+ minimum_survivable_temperature = 0
+ maximum_survivable_temperature = INFINITY
faction = list("demon")
- attacktext = "wildly tears into"
+ attack_verb_continuous = "wildly tears into"
+ attack_verb_simple = "wildly tears into"
maxHealth = 200
health = 200
environment_smash = ENVIRONMENT_SMASH_STRUCTURES
@@ -25,14 +27,16 @@
melee_damage_upper = 30
see_in_dark = 8
lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
- del_on_death = TRUE
+ basic_mob_flags = DEL_ON_DEATH
var/datum/action/innate/demon_whisper/whisper_action
-/mob/living/simple_animal/demon/Initialize(mapload)
+/mob/living/basic/demon/Initialize(mapload)
. = ..()
whisper_action = new()
whisper_action.Grant(src)
+ add_language("Galactic Common")
+ set_default_language(GLOB.all_languages["Galactic Common"])
-/mob/living/simple_animal/demon/Destroy()
+/mob/living/basic/demon/Destroy()
QDEL_NULL(whisper_action)
return ..()
diff --git a/code/modules/mob/living/basic/hostile/demons/demon_loot.dm b/code/modules/mob/living/basic/hostile/demons/demon_loot.dm
new file mode 100644
index 00000000000..dc94d550397
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/demons/demon_loot.dm
@@ -0,0 +1,114 @@
+// Demon heart base type
+/obj/item/organ/internal/heart/demon
+ name = "demon heart"
+ desc = "Still it beats furiously, emanating an aura of utter hate."
+ icon_state = "demon_heart"
+ origin_tech = "combat=5;biotech=7"
+ organ_datums = list(/datum/organ/heart/always_beating, /datum/organ/battery)
+
+/obj/item/organ/internal/heart/demon/update_icon_state()
+ return //always beating visually
+
+/obj/item/organ/internal/heart/demon/prepare_eat()
+ return // Just so people don't accidentally waste it
+
+/obj/item/organ/internal/heart/demon/attack_self__legacy__attackchain(mob/living/user)
+ user.visible_message("[user] raises [src] to [user.p_their()] mouth and tears into it with [user.p_their()] teeth!", \
+ "An unnatural hunger consumes you. You raise [src] to your mouth and devour it!")
+ playsound(user, 'sound/misc/demon_consume.ogg', 50, 1)
+
+/// SLAUGHTER DEMON HEART
+
+/obj/item/organ/internal/heart/demon/slaughter/attack_self__legacy__attackchain(mob/living/user)
+ ..()
+
+ // Eating the heart for the first time. Gives basic bloodcrawling. This is the only time we need to insert the heart.
+ if(!HAS_TRAIT(user, TRAIT_BLOODCRAWL))
+ 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!")
+ ADD_TRAIT(user, TRAIT_BLOODCRAWL, "bloodcrawl")
+ user.drop_item()
+ insert(user) //Consuming the heart literally replaces your heart with a demon heart. H A R D C O R E.
+ return TRUE
+
+ // Eating a 2nd heart. Gives the ability to drag people into blood and eat them.
+ if(HAS_TRAIT(user, TRAIT_BLOODCRAWL))
+ to_chat(user, "You feel differ- CONSUME THEM!")
+ ADD_TRAIT(user, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
+ qdel(src) // Replacing their demon heart with another demon heart is pointless, just delete this one and return.
+ return TRUE
+
+ // Eating any more than 2 demon hearts does nothing.
+ to_chat(user, "...and you don't feel any different.")
+ qdel(src)
+
+/obj/item/organ/internal/heart/demon/slaughter/insert(mob/living/carbon/M, special = 0)
+ . = ..()
+ if(M.mind)
+ M.mind.AddSpell(new /datum/spell/bloodcrawl(null))
+
+/obj/item/organ/internal/heart/demon/slaughter/remove(mob/living/carbon/M, special = 0)
+ . = ..()
+ if(M.mind)
+ REMOVE_TRAIT(M, TRAIT_BLOODCRAWL, "bloodcrawl")
+ REMOVE_TRAIT(M, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
+ M.mind.RemoveSpell(/datum/spell/bloodcrawl)
+
+/// SHADOW DEMON HEART
+/obj/item/organ/internal/heart/demon/shadow
+ name = "heart of darkness"
+ desc = "It still beats furiously, emitting an aura of fear."
+ color = COLOR_BLACK
+
+/obj/item/organ/internal/heart/demon/shadow/attack_self__legacy__attackchain(mob/living/user)
+ . = ..()
+ user.drop_item()
+ insert(user)
+
+/obj/item/organ/internal/heart/demon/shadow/insert(mob/living/carbon/M, special = 0)
+ . = ..()
+ if(M.mind)
+ M.mind.AddSpell(new /datum/spell/fireball/shadow_grapple)
+
+/obj/item/organ/internal/heart/demon/shadow/remove(mob/living/carbon/M, special = 0)
+ . = ..()
+ if(M.mind)
+ M.mind.RemoveSpell(/datum/spell/fireball/shadow_grapple)
+
+/// PULSE DEMON HEART
+/obj/item/organ/internal/heart/demon/pulse
+ name = "perpetual pacemaker"
+ desc = "It still beats furiously, thousands of bright lights shine within it."
+ color = COLOR_YELLOW
+
+/obj/item/organ/internal/heart/demon/pulse/Initialize(mapload)
+ . = ..()
+ set_light(13, 2, "#bbbb00")
+
+/obj/item/organ/internal/heart/demon/pulse/attack_self__legacy__attackchain(mob/living/user)
+ . = ..()
+ user.drop_item()
+ insert(user)
+
+/obj/item/organ/internal/heart/demon/pulse/insert(mob/living/carbon/M, special, dont_remove_slot)
+ . = ..()
+ M.AddComponent(/datum/component/cross_shock, 30, 500, 2 SECONDS)
+ ADD_TRAIT(M, TRAIT_SHOCKIMMUNE, UNIQUE_TRAIT_SOURCE(src))
+ M.set_light(3, 2, "#bbbb00")
+
+/obj/item/organ/internal/heart/demon/pulse/remove(mob/living/carbon/M, special)
+ . = ..()
+ REMOVE_TRAIT(M, TRAIT_SHOCKIMMUNE, UNIQUE_TRAIT_SOURCE(src))
+ M.remove_light()
+
+/obj/item/organ/internal/heart/demon/pulse/on_life()
+ if(!owner)
+ return
+ for(var/obj/item/stock_parts/cell/cell_to_charge in owner.GetAllContents())
+ var/newcharge = min(0.05 * cell_to_charge.maxcharge + cell_to_charge.charge, cell_to_charge.maxcharge)
+ if(cell_to_charge.charge < newcharge)
+ cell_to_charge.charge = newcharge
+ if(isobj(cell_to_charge.loc))
+ var/obj/cell_location = cell_to_charge.loc
+ cell_location.update_icon() //update power meters and such
+ cell_to_charge.update_icon()
diff --git a/code/modules/mob/living/basic/hostile/demons/demon_objectives.dm b/code/modules/mob/living/basic/hostile/demons/demon_objectives.dm
new file mode 100644
index 00000000000..7354cf3bd70
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/demons/demon_objectives.dm
@@ -0,0 +1,111 @@
+// Objective info, Based on Reverent mini Atang
+/datum/objective/slaughter
+ needs_target = FALSE
+ var/targetKill = 10
+
+/datum/objective/slaughter/New()
+ targetKill = rand(10,20)
+ explanation_text = "Devour [targetKill] mortals."
+ ..()
+
+/datum/objective/slaughter/check_completion()
+ var/kill_count = 0
+ for(var/datum/mind/M in get_owners())
+ if(!isslaughterdemon(M.current) || QDELETED(M.current))
+ continue
+ var/mob/living/basic/demon/slaughter/R = M.current
+ kill_count += R.devoured
+ if(kill_count >= targetKill)
+ return TRUE
+ return FALSE
+
+/datum/objective/demon_fluff
+ name = "Spread blood"
+ needs_target = FALSE
+
+/datum/objective/demon_fluff/New()
+ find_target()
+ var/targetname = "someone"
+ if(target && target.current)
+ targetname = target.current.real_name
+ var/list/explanation_texts = list(
+ "Spread blood all over the bridge.",
+ "Spread blood all over the brig.",
+ "Spread blood all over the chapel.",
+ "Kill or Destroy all Janitors or Sanitation bots.",
+ "Spare a few after striking them... make them bleed before the harvest.",
+ "Hunt those that try to hunt you first.",
+ "Hunt those that run away from you in fear",
+ "Show [targetname] the power of blood.",
+ "Drive [targetname] insane with demonic whispering."
+ )
+ // As this is a fluff objective, we don't need a target, so we want to null it out.
+ // We don't want the demon getting a "Time for Plan B" message if the target cryos.
+ target = null
+ explanation_text = pick(explanation_texts)
+ ..()
+
+/datum/objective/demon_fluff/check_completion()
+ return TRUE
+
+/datum/objective/cult_slaughter
+ explanation_text = "Bring forth the Slaughter to the nonbelievers."
+ needs_target = FALSE
+
+/datum/objective/pulse_demon/infest
+ name = "Hijack APCs"
+ /// Amount of APCs we need to hijack, can be 15, 20, or 25
+ var/amount = 0
+
+/datum/objective/pulse_demon/infest/New()
+ . = ..()
+ amount = rand(3, 5) * 5
+ explanation_text = "Hijack [amount] APCs."
+
+/datum/objective/pulse_demon/infest/check_completion()
+ if(..())
+ return TRUE
+ var/hijacked = 0
+ for(var/datum/mind/M in get_owners())
+ if(!ispulsedemon(M.current) || QDELETED(M.current))
+ continue
+ var/mob/living/basic/demon/pulse_demon/demon = M.current
+ hijacked += length(demon.hijacked_apcs)
+ return hijacked >= amount
+
+/datum/objective/pulse_demon/drain
+ name = "Drain Power"
+ /// Amount of power we need to drain, ranges from 500 KW to 5 MW
+ var/amount = 0
+
+/datum/objective/pulse_demon/drain/New()
+ . = ..()
+ amount = rand(1, 10) * 500000
+ explanation_text = "Drain [format_si_suffix(amount)]W of power."
+
+/datum/objective/pulse_demon/drain/check_completion()
+ if(..())
+ return TRUE
+ var/drained = 0
+ for(var/datum/mind/M in get_owners())
+ if(!ispulsedemon(M.current) || QDELETED(M.current))
+ continue
+ var/mob/living/basic/demon/pulse_demon/demon = M.current
+ drained += demon.charge_drained
+ return drained >= amount
+
+// Requires 1 APC to be hacked and not destroyed to complete
+/datum/objective/pulse_demon/tamper
+ name = "Tamper Machinery"
+ explanation_text = "Cause mischief amongst the machines in rooms with APCs you've hijacked, and defend yourself from anyone trying to stop you."
+
+/datum/objective/pulse_demon/tamper/check_completion()
+ if(..())
+ return TRUE
+ for(var/datum/mind/M in get_owners())
+ if(!ispulsedemon(M.current) || QDELETED(M.current))
+ continue
+ var/mob/living/basic/demon/pulse_demon/demon = M.current
+ if(!length(demon.hijacked_apcs) || !M.active || demon.stat == DEAD)
+ return FALSE
+ return TRUE
diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm b/code/modules/mob/living/basic/hostile/demons/demon_powers.dm
similarity index 73%
rename from code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm
rename to code/modules/mob/living/basic/hostile/demons/demon_powers.dm
index 6b637f7e70b..cb4da56daa9 100644
--- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_abilities.dm
+++ b/code/modules/mob/living/basic/hostile/demons/demon_powers.dm
@@ -1,3 +1,149 @@
+//////////////////////////////
+// MARK: DEMONIC WHISPER
+//////////////////////////////
+/datum/action/innate/demon_whisper
+ name = "Demonic Whisper"
+ button_icon_state = "demon_comms"
+ background_icon_state = "bg_demon"
+
+/datum/action/innate/demon_whisper/proc/choose_targets(mob/user = usr)
+ var/list/validtargets = list()
+ for(var/mob/living/M in view(user.client.maxview(), get_turf(user)))
+ if(M && M.mind && M.stat != DEAD)
+ if(M == user)
+ continue
+
+ validtargets += M
+
+ if(!length(validtargets))
+ to_chat(usr, "There are no valid targets!")
+ return
+
+ var/mob/living/target = tgui_input_list(user, "Choose the target to talk to", "Targeting", validtargets)
+ return target
+
+/datum/action/innate/demon_whisper/Activate()
+ var/mob/living/choice = choose_targets()
+ if(!choice)
+ return
+
+ var/msg = tgui_input_text(usr, "What do you wish to tell [choice]?", null, "")
+ if(!msg)
+ return
+ log_say("(SLAUGHTER to [key_name(choice)]) [msg]", usr)
+ to_chat(usr, "You whisper to [choice]: [msg]")
+ to_chat(choice, "Suddenly a strange, demonic voice resonates in your head... [msg]")
+ for(var/mob/dead/observer/G in GLOB.player_list)
+ G.show_message("Demonic message from [usr] ([ghost_follow_link(usr, ghost=G)]) to [choice] ([ghost_follow_link(choice, ghost=G)]): [msg]")
+
+//////////////////////////////
+// MARK: CULT DEMON
+//////////////////////////////
+/datum/spell/sense_victims
+ name = "Sense Victims"
+ desc = "Sense the location of heretics."
+ base_cooldown = 0
+ clothes_req = FALSE
+ overlay = null
+ action_icon_state = "bloodcrawl"
+ action_background_icon_state = "bg_cult"
+
+/datum/spell/sense_victims/create_new_targeting()
+ return new /datum/spell_targeting/alive_mob_list
+
+/datum/spell/sense_victims/valid_target(mob/living/target, user)
+ return target.stat == CONSCIOUS && target.key && !IS_CULTIST(target) // Only conscious, non cultist players
+
+/datum/spell/sense_victims/cast(list/targets, mob/user)
+ var/mob/living/victim = targets[1]
+ to_chat(victim, "You feel an awful sense of being watched...")
+ victim.Stun(6 SECONDS) //HUE
+ var/area/A = get_area(victim)
+ if(!A)
+ to_chat(user, "You could not locate any sapient heretics for the Slaughter.")
+ return 0
+ to_chat(user, "You sense a terrified soul at [A]. Show [A.p_them()] the error of [A.p_their()] ways.")
+
+//////////////////////////////
+// MARK: SHADOW DEMON
+//////////////////////////////
+/datum/spell/fireball/shadow_grapple
+ name = "Shadow Grapple"
+ desc = "Fire one of your hands, if it hits a person it pulls them in. If you hit a structure you get pulled to the structure. Any light source hit with this will be disabled in a two tile radius."
+ base_cooldown = 10 SECONDS
+ fireball_type = /obj/projectile/magic/shadow_hand
+
+ selection_activated_message = "You raise your hand, full of demonic energy! Left-click to cast at a target!"
+ selection_deactivated_message = "You re-absorb the energy...for now."
+
+ action_background_icon_state = "shadow_demon_bg"
+ action_icon_state = "shadow_grapple"
+ sound = null
+ invocation_type = "none"
+ invocation = null
+
+/datum/spell/fireball/shadow_grapple/update_spell_icon()
+ return
+
+/obj/projectile/magic/shadow_hand
+ name = "shadow hand"
+ icon_state = "shadow_hand"
+ plane = FLOOR_PLANE
+ hitsound = 'sound/shadowdemon/shadowattack1.ogg' // Plays when hitting something living or a light
+ var/hit = FALSE
+
+/obj/projectile/magic/shadow_hand/pixel_move(trajectory_multiplier, hitscanning)
+ . = ..()
+ var/obj/machinery/light/floor/floor_light = locate(/obj/machinery/light/floor) in get_turf(src)
+ if(floor_light)
+ Bump(floor_light)
+
+/obj/projectile/magic/shadow_hand/fire(setAngle)
+ if(firer)
+ var/mob/living/basic/demon/shadow/current_demon = firer
+ if(istype(current_demon))
+ current_demon.block_shadow_crawl()
+ firer.Beam(src, icon_state = "grabber_beam", time = INFINITY, maxdistance = INFINITY, beam_type = /obj/effect/ebeam/floor)
+ return ..()
+
+/obj/projectile/magic/shadow_hand/on_hit(atom/target, blocked, hit_zone)
+ if(hit)
+ return
+ hit = TRUE // to prevent double hits from the pull
+ . = ..()
+ for(var/atom/extinguish_target in range(2, src))
+ extinguish_target.extinguish_light(TRUE)
+ if(!isliving(target))
+ if(isshadowdemon(firer))
+ firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10, callback = CALLBACK(firer, TYPE_PROC_REF(/mob/living/basic/demon/shadow, unblock_shadow_crawl)))
+ else
+ firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10)
+ else
+ unblock_shadowdemon_crawl()
+ if(!.)
+ return
+ else
+ var/mob/living/L = target
+ L.Immobilize(2 SECONDS)
+ L.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
+ L.throw_at(get_step(firer, get_dir(firer, target)), 50, 10)
+
+/obj/projectile/magic/shadow_hand/Destroy()
+ if(!hit)
+ unblock_shadowdemon_crawl()
+ return ..()
+
+/obj/projectile/magic/shadow_hand/proc/unblock_shadowdemon_crawl()
+ var/mob/living/basic/demon/shadow/current_demon = firer
+ if(istype(current_demon))
+ current_demon.unblock_shadow_crawl()
+
+/obj/effect/ebeam/floor
+ plane = FLOOR_PLANE
+
+//////////////////////////////
+// MARK: PULSE DEMON
+//////////////////////////////
#define PULSEDEMON_REMOTE_DRAIN_MULTIPLIER 5
#define PD_UPGRADE_HIJACK_SPEED "Speed"
@@ -36,7 +182,7 @@
action.desc = desc
action.build_all_button_icons()
-/datum/spell/pulse_demon/can_cast(mob/living/simple_animal/demon/pulse_demon/user, charge_check, show_message)
+/datum/spell/pulse_demon/can_cast(mob/living/basic/demon/pulse_demon/user, charge_check, show_message)
if(!..())
return FALSE
if(!istype(user))
@@ -57,7 +203,7 @@
return FALSE
return TRUE
-/datum/spell/pulse_demon/cast(list/targets, mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/cast(list/targets, mob/living/basic/demon/pulse_demon/user)
if(!istype(user) || locked || user.charge < cast_cost || !length(targets))
return FALSE
if(requires_area && !user.controlling_area)
@@ -77,7 +223,7 @@
/datum/spell/pulse_demon/create_new_targeting()
return new /datum/spell_targeting/clicked_atom
-/datum/spell/pulse_demon/proc/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/proc/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
return FALSE
/datum/spell/pulse_demon/proc/reveal_demon(mob/user, reveal_time)
@@ -87,7 +233,7 @@
user.layer = ABOVE_PLATING_LAYER
// handles purchasing and upgrading abilities
-/datum/spell/pulse_demon/AltClick(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/AltClick(mob/living/basic/demon/pulse_demon/user)
if(!istype(user))
return
@@ -122,7 +268,7 @@
else
to_chat(user, "You cannot afford to upgrade this ability! It costs [format_si_suffix(upgrade_cost)] APC\s to upgrade.")
-/datum/spell/pulse_demon/proc/do_upgrade(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/proc/do_upgrade(mob/living/basic/demon/pulse_demon/user)
cooldown_handler.recharge_duration = round(base_cooldown / (1.5 ** spell_level))
to_chat(user, "You have upgraded [initial(name)] to level [spell_level + 1], it now takes [cooldown_handler.recharge_duration / 10] seconds to recharge.")
@@ -136,7 +282,7 @@
revealing = TRUE
reveal_time = 5 SECONDS
-/datum/spell/pulse_demon/cablehop/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/cablehop/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
var/turf/O = get_turf(user)
var/turf/T = get_turf(target)
var/obj/structure/cable/C = locate(/obj/structure/cable) in T
@@ -167,7 +313,7 @@
requires_area = TRUE
revealing = TRUE
-/datum/spell/pulse_demon/emagtamper/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/emagtamper/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
to_chat(user, "You attempt to tamper with [target]!")
target.emag_act(user)
return TRUE
@@ -182,7 +328,7 @@
requires_area = TRUE
revealing = TRUE
-/datum/spell/pulse_demon/emp/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/emp/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
to_chat(user, "You attempt to EMP [target]!")
empulse(get_turf(target), 1, 1)
return TRUE
@@ -199,7 +345,7 @@
base_cooldown = 60 SECONDS
reveal_time = 20 SECONDS
-/datum/spell/pulse_demon/overload/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/overload/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
var/obj/machinery/M = target
if(!istype(M))
to_chat(user, "That is not a machine.")
@@ -211,7 +357,7 @@
addtimer(CALLBACK(src, PROC_REF(detonate), user, M), 5 SECONDS)
return TRUE
-/datum/spell/pulse_demon/overload/proc/detonate(mob/living/simple_animal/demon/pulse_demon/user, obj/machinery/target)
+/datum/spell/pulse_demon/overload/proc/detonate(mob/living/basic/demon/pulse_demon/user, obj/machinery/target)
if(!QDELETED(target))
if(spell_level == level_max)
explosion(get_turf(target), 0, 1, 2, 2, smoke = TRUE, cause = "Pulse Demon: [name]")
@@ -229,7 +375,7 @@
level_max = 0
base_cooldown = 3 SECONDS // you have to wait for the regular hijack time anyway
-/datum/spell/pulse_demon/remotehijack/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/remotehijack/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
var/obj/machinery/power/apc/A = target
if(!istype(A))
to_chat(user, "That is not an APC.")
@@ -246,7 +392,7 @@
cast_cost = 50 KJ
upgrade_cost = 2
-/datum/spell/pulse_demon/remotedrain/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/remotedrain/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
if(isapc(target))
var/drained = user.drain_APC(target, PULSEDEMON_REMOTE_DRAIN_MULTIPLIER)
if(drained == PULSEDEMON_SOURCE_DRAIN_INVALID)
@@ -290,11 +436,11 @@
locked = FALSE
level_max = 0
-/datum/spell/pulse_demon/toggle/do_drain/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/toggle/do_drain/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
user.do_drain = do_toggle(!user.do_drain, user)
return TRUE
-/datum/spell/pulse_demon/toggle/do_drain/AltClick(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/toggle/do_drain/AltClick(mob/living/basic/demon/pulse_demon/user)
if(!istype(user))
return
@@ -317,14 +463,14 @@
level_max = 3
locked = FALSE
-/datum/spell/pulse_demon/toggle/can_exit_cable/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/toggle/can_exit_cable/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
if(user.can_exit_cable && !(user.current_cable || user.current_power))
to_chat(user, "Enter a cable or power source first!")
return FALSE
user.can_exit_cable = do_toggle(!user.can_exit_cable, user)
return TRUE
-/datum/spell/pulse_demon/toggle/can_exit_cable/do_upgrade(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/toggle/can_exit_cable/do_upgrade(mob/living/basic/demon/pulse_demon/user)
user.outside_cable_speed = max(initial(user.outside_cable_speed) - spell_level, 1)
to_chat(user, "You have upgraded [initial(name)] to level [spell_level + 1], you will now move faster outside of cables.")
@@ -343,7 +489,7 @@
/datum/spell/pulse_demon/cycle_camera/create_new_targeting()
return new /datum/spell_targeting/self
-/datum/spell/pulse_demon/cycle_camera/AltClick(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/cycle_camera/AltClick(mob/living/basic/demon/pulse_demon/user)
if(!istype(user))
return
current_camera = 0
@@ -354,7 +500,7 @@
return
user.forceMove(user.current_power)
-/datum/spell/pulse_demon/cycle_camera/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/cycle_camera/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
if(!length(user.controlling_area.cameras))
return FALSE
@@ -383,7 +529,7 @@
/datum/spell/pulse_demon/toggle/penetrating_shock/create_new_targeting()
return new /datum/spell_targeting/self
-/datum/spell/pulse_demon/toggle/penetrating_shock/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/toggle/penetrating_shock/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
user.strong_shocks = do_toggle(!user.strong_shocks, user)
/datum/spell/pulse_demon/open_upgrades
@@ -417,7 +563,7 @@
/datum/spell/pulse_demon/open_upgrades/create_new_targeting()
return new /datum/spell_targeting/self
-/datum/spell/pulse_demon/open_upgrades/proc/calc_cost(mob/living/simple_animal/demon/pulse_demon/user, upgrade)
+/datum/spell/pulse_demon/open_upgrades/proc/calc_cost(mob/living/basic/demon/pulse_demon/user, upgrade)
var/cost
switch(upgrade)
if(PD_UPGRADE_HIJACK_SPEED)
@@ -459,7 +605,7 @@
return -1
return cost
-/datum/spell/pulse_demon/open_upgrades/proc/get_upgrades(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/open_upgrades/proc/get_upgrades(mob/living/basic/demon/pulse_demon/user)
var/upgrades = list()
for(var/upgrade in upgrade_icons)
var/cost = calc_cost(user, upgrade)
@@ -468,7 +614,7 @@
upgrades["[upgrade] ([format_si_suffix(cost)] APC\s)"] = upgrade_icons[upgrade]
return upgrades
-/datum/spell/pulse_demon/open_upgrades/AltClick(mob/living/simple_animal/demon/pulse_demon/user)
+/datum/spell/pulse_demon/open_upgrades/AltClick(mob/living/basic/demon/pulse_demon/user)
if(!istype(user))
return
@@ -477,7 +623,7 @@
var/cost = calc_cost(user, upgrade)
to_chat(user, "[upgrade] ([cost == -1 ? "Fully Upgraded" : "[format_si_suffix(cost)]J"]) - [upgrade_descs[upgrade]]")
-/datum/spell/pulse_demon/open_upgrades/try_cast_action(mob/living/simple_animal/demon/pulse_demon/user, atom/target)
+/datum/spell/pulse_demon/open_upgrades/try_cast_action(mob/living/basic/demon/pulse_demon/user, atom/target)
var/upgrades = get_upgrades(user)
if(!length(upgrades))
to_chat(user, "You have already fully upgraded everything available!")
diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm b/code/modules/mob/living/basic/hostile/demons/pulse_demon.dm
similarity index 79%
rename from code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm
rename to code/modules/mob/living/basic/hostile/demons/pulse_demon.dm
index 19b69942a0d..4ae2c524d92 100644
--- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon.dm
+++ b/code/modules/mob/living/basic/hostile/demons/pulse_demon.dm
@@ -9,25 +9,25 @@
#define ALERT_CATEGORY_NOREGEN "pulse_noregen"
/// Conversion ratio from Watt ticks to joules.
-/mob/living/simple_animal/demon/pulse_demon
+/mob/living/basic/demon/pulse_demon
name = "pulse demon"
real_name = "pulse demon"
desc = "A strange electrical apparition that lives in wires."
- gender = NEUTER
- speak_chance = 20
damage_coeff = list(BRUTE = 0.25, BURN = 0.5, TOX = 0, CLONE = 0, STAMINA = 0, OXY = 0) // Pulse demons take reduced damage from most sources. Use ions
- emote_hear = list("vibrates", "sizzles")
- speak_emote = list("modulates")
+ speak_emote = list("modulates", "vibrates", "sizzles")
icon_state = "pulsedem"
icon_living = "pulsedem"
icon_dead = "pulsedem"
- response_help = "reaches their hand into"
- response_disarm = "pushes their hand through"
- response_harm = "punches their fist through"
- deathmessage = "fizzles out into faint sparks, leaving only a slight trail of smoke..."
+ response_help_continuous = "reaches their hand into"
+ response_help_simple = "reach their hand into"
+ response_disarm_continuous = "pushes their hand through"
+ response_disarm_simple = "push their hand through"
+ response_harm_continuous = "punches their fist through"
+ response_harm_simple = "punches their fist through"
+ death_message = "fizzles out into faint sparks, leaving only a slight trail of smoke..."
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) // "I don't need air, just MORE POWER!"
unsuitable_atmos_damage = 0
level = 1
@@ -40,7 +40,8 @@
mob_size = MOB_SIZE_TINY
density = FALSE
- attacktext = "electrocutes"
+ attack_verb_continuous = "electrocutes"
+ attack_verb_simple = "electrocute"
attack_sound = "sparks"
harm_intent_damage = 0
melee_damage_lower = 0
@@ -125,18 +126,18 @@
/// Reference to the APC currently being hijacked.
var/obj/machinery/power/apc/apc_being_hijacked
-/mob/living/simple_animal/demon/pulse_demon/wizard
+/mob/living/basic/demon/pulse_demon/wizard
name = "Empowered Pulse Demon"
real_name = "Empowered Pulse Demon"
desc = "A strange electrical apparition that lives in wires. This one appears more charged than usual."
-/mob/living/simple_animal/demon/pulse_demon/wizard/Initialize(mapload)
+/mob/living/basic/demon/pulse_demon/wizard/Initialize(mapload)
. = ..()
src.apcs_remaining = 20
src.maxcharge = 500 KJ
src.charge = 100 KJ
-/mob/living/simple_animal/demon/pulse_demon/Initialize(mapload)
+/mob/living/basic/demon/pulse_demon/Initialize(mapload)
. = ..()
if(!mapload)
name += " ([rand(100, 999)])"
@@ -174,18 +175,17 @@
whisper_action.button_icon_state = "pulse_whisper"
whisper_action.background_icon_state = "bg_pulsedemon"
-/mob/living/simple_animal/demon/pulse_demon/proc/deleted_handler(our_demon, force)
+/mob/living/basic/demon/pulse_demon/proc/deleted_handler(our_demon, force)
SIGNAL_HANDLER
// assume normal deletion if we're on a turf, otherwise deletion could be inherited from loc
if(force || isnull(loc) || isturf(loc))
return FALSE
- // if we did actually die, simple_animal/death will set del_on_death to FALSE before calling qdel
- if(!del_on_death)
+ if(!(basic_mob_flags & DEL_ON_DEATH))
return FALSE
exit_to_turf()
return TRUE
-/mob/living/simple_animal/demon/pulse_demon/proc/cable_updated_handler(SSdcs, turf/T)
+/mob/living/basic/demon/pulse_demon/proc/cable_updated_handler(SSdcs, turf/T)
SIGNAL_HANDLER
if(cable_images[T])
var/list/turf_images = cable_images[T]
@@ -201,11 +201,11 @@
cable_images[T] += cable_image
client?.images += cable_image
-/mob/living/simple_animal/demon/pulse_demon/proc/apc_deleted_handler(obj/machinery/power/apc/A, force)
+/mob/living/basic/demon/pulse_demon/proc/apc_deleted_handler(obj/machinery/power/apc/A, force)
SIGNAL_HANDLER
hijacked_apcs -= A
-/mob/living/simple_animal/demon/pulse_demon/Destroy()
+/mob/living/basic/demon/pulse_demon/Destroy()
cable_images.Cut()
apc_images.Cut()
@@ -221,17 +221,17 @@
return ..()
-/mob/living/simple_animal/demon/pulse_demon/Login()
+/mob/living/basic/demon/pulse_demon/Login()
. = ..()
update_cableview()
-/mob/living/simple_animal/demon/pulse_demon/proc/make_pulse_antagonist(demon)
+/mob/living/basic/demon/pulse_demon/proc/make_pulse_antagonist(demon)
SIGNAL_HANDLER
mind.assigned_role = SPECIAL_ROLE_DEMON
mind.special_role = SPECIAL_ROLE_DEMON
give_objectives()
-/mob/living/simple_animal/demon/pulse_demon/vv_edit_var(var_name, var_value)
+/mob/living/basic/demon/pulse_demon/vv_edit_var(var_name, var_value)
switch(var_name)
if("glow_color")
update_glow()
@@ -241,7 +241,7 @@
return TRUE
return ..()
-/mob/living/simple_animal/demon/pulse_demon/forceMove(atom/destination)
+/mob/living/basic/demon/pulse_demon/forceMove(atom/destination)
var/old_location = loc
. = ..()
current_weapon = null
@@ -252,12 +252,12 @@
if(istype(old_location, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = old_location
// only set rigged if there are no remaining demons in the cell
- C.rigged = !(locate(/mob/living/simple_animal/demon/pulse_demon) in old_location)
+ C.rigged = !(locate(/mob/living/basic/demon/pulse_demon) in old_location)
if(istype(loc, /obj/item/stock_parts/cell))
var/obj/item/stock_parts/cell/C = loc
C.rigged = FALSE
-/mob/living/simple_animal/demon/pulse_demon/proc/give_objectives()
+/mob/living/basic/demon/pulse_demon/proc/give_objectives()
if(!mind)
return
mind.wipe_memory()
@@ -274,7 +274,7 @@
to_chat(src, chat_box_red(greeting.Join("
")))
SSticker.mode.traitors |= mind
-/mob/living/simple_animal/demon/pulse_demon/proc/give_spells()
+/mob/living/basic/demon/pulse_demon/proc/give_spells()
AddSpell(new /datum/spell/pulse_demon/open_upgrades)
AddSpell(new /datum/spell/pulse_demon/cycle_camera)
AddSpell(new /datum/spell/pulse_demon/toggle/penetrating_shock(strong_shocks))
@@ -287,7 +287,7 @@
AddSpell(new /datum/spell/pulse_demon/remotehijack)
AddSpell(new /datum/spell/pulse_demon/remotedrain)
-/mob/living/simple_animal/demon/pulse_demon/get_status_tab_items()
+/mob/living/basic/demon/pulse_demon/get_status_tab_items()
var/list/status_tab_data = ..()
. = status_tab_data
status_tab_data[++status_tab_data.len] = list("Energy:", "[format_si_suffix(charge)]J")
@@ -298,13 +298,13 @@
status_tab_data[++status_tab_data.len] = list("Drain Rate:", "[format_si_suffix(power_drain_rate)]W")
status_tab_data[++status_tab_data.len] = list("Hijack Time:", "[hijack_time / 10] seconds")
-/mob/living/simple_animal/demon/pulse_demon/dust()
+/mob/living/basic/demon/pulse_demon/dust()
return death()
-/mob/living/simple_animal/demon/pulse_demon/gib()
+/mob/living/basic/demon/pulse_demon/gib()
return death()
-/mob/living/simple_animal/demon/pulse_demon/death()
+/mob/living/basic/demon/pulse_demon/death()
var/turf/T = get_turf(src)
do_sparks(rand(2, 4), FALSE, src)
. = ..()
@@ -315,7 +315,7 @@
playsound(T, pick(hurt_sounds), 30, TRUE)
SEND_SIGNAL(src, COMSIG_MOB_DEATH)
-/mob/living/simple_animal/demon/pulse_demon/proc/exit_to_turf()
+/mob/living/basic/demon/pulse_demon/proc/exit_to_turf()
var/turf/T = get_turf(src)
current_power = null
update_controlling_area()
@@ -329,7 +329,7 @@
S.do_toggle(can_exit_cable)
to_chat(src, "Your self-sustaining ability has automatically enabled itself to prevent death from having no connection!")
-/mob/living/simple_animal/demon/pulse_demon/proc/update_controlling_area(reset = FALSE)
+/mob/living/basic/demon/pulse_demon/proc/update_controlling_area(reset = FALSE)
var/area/prev = controlling_area
if(reset || current_power == null)
controlling_area = null
@@ -349,10 +349,10 @@
S.action.build_all_button_icons()
// can enter an apc at all?
-/mob/living/simple_animal/demon/pulse_demon/proc/is_valid_apc(obj/machinery/power/apc/A)
+/mob/living/basic/demon/pulse_demon/proc/is_valid_apc(obj/machinery/power/apc/A)
return istype(A) && !(A.stat & BROKEN) && !A.shorted
-/mob/living/simple_animal/demon/pulse_demon/Move(newloc)
+/mob/living/basic/demon/pulse_demon/Move(newloc)
var/obj/machinery/power/new_power = locate(/obj/machinery/power) in newloc
var/obj/structure/cable/new_cable = locate(/obj/structure/cable) in newloc
@@ -429,7 +429,7 @@
if(!ispulsedemon(user))
return ..()
- var/mob/living/simple_animal/demon/pulse_demon/demon = user
+ var/mob/living/basic/demon/pulse_demon/demon = user
var/turf/T = get_turf(src)
var/turf/T2 = get_step(T, dir)
if(demon.can_exit_cable || locate(/obj/structure/cable) in T2)
@@ -439,7 +439,7 @@
if(isapc(src))
demon.update_controlling_area(TRUE)
-/mob/living/simple_animal/demon/pulse_demon/proc/adjust_charge(amount, adjust_max = FALSE)
+/mob/living/basic/demon/pulse_demon/proc/adjust_charge(amount, adjust_max = FALSE)
if(!amount)
return FALSE
if(adjust_max)
@@ -468,27 +468,27 @@
// 2.5 at 50000
// 3 at 600000 etc
-/mob/living/simple_animal/demon/pulse_demon/proc/update_glow()
+/mob/living/basic/demon/pulse_demon/proc/update_glow()
var/range = charge / 200000
range = clamp(range, 1.5, 5)
set_light(range, 2, glow_color)
-/mob/living/simple_animal/demon/pulse_demon/proc/drain_APC(obj/machinery/power/apc/A, multiplier = 1)
+/mob/living/basic/demon/pulse_demon/proc/drain_APC(obj/machinery/power/apc/A, multiplier = 1)
if(A.being_hijacked)
return PULSEDEMON_SOURCE_DRAIN_INVALID
- //CELLRATE is the conversion ratio between a watt tick and powercell energy storage units
+ // CELLRATE is the conversion ratio between a watt tick and powercell energy storage units
var/amount_to_drain = clamp(A.cell.charge / GLOB.CELLRATE, 0, power_drain_rate * WATT_TICK_TO_JOULE * multiplier)
A.cell.use(min(amount_to_drain * GLOB.CELLRATE, maxcharge - charge)) // calculated seperately because the apc charge multiplier shouldn't affect the actual consumption
return adjust_charge(amount_to_drain * PULSEDEMON_APC_CHARGE_MULTIPLIER)
-/mob/living/simple_animal/demon/pulse_demon/proc/drain_SMES(obj/machinery/power/smes/S, multiplier = 1)
- //CELLRATE is the conversion ratio between a watt tick and powercell energy storage units.
+/mob/living/basic/demon/pulse_demon/proc/drain_SMES(obj/machinery/power/smes/S, multiplier = 1)
+ // CELLRATE is the conversion ratio between a watt tick and powercell energy storage units.
var/amount_to_drain = clamp(S.charge / GLOB.CELLRATE, 0, power_drain_rate * WATT_TICK_TO_JOULE * multiplier * PULSEDEMON_SMES_DRAIN_MULTIPLIER)
var/drained = adjust_charge(amount_to_drain)
S.charge -= drained * GLOB.CELLRATE
return drained
-/mob/living/simple_animal/demon/pulse_demon/Life(seconds, times_fired)
+/mob/living/basic/demon/pulse_demon/Life(seconds, times_fired)
. = ..()
var/got_power = FALSE
@@ -532,12 +532,12 @@
if(--regen_lock == 0)
clear_alert(ALERT_CATEGORY_NOREGEN)
-/mob/living/simple_animal/demon/pulse_demon/proc/gen_speech_name()
+/mob/living/basic/demon/pulse_demon/proc/gen_speech_name()
. = ""
for(var/i = 1 to 10)
. += pick("!", "@", "#", "$", "%", "^", "&", "*")
-/mob/living/simple_animal/demon/pulse_demon/say(message, verb, sanitize = TRUE, ignore_speech_problems = FALSE, ignore_atmospherics = FALSE, ignore_languages = FALSE)
+/mob/living/basic/demon/pulse_demon/say(message, verb, sanitize = TRUE, ignore_speech_problems = FALSE, ignore_atmospherics = FALSE, ignore_languages = FALSE)
if(client && check_mute(client.ckey, MUTE_IC))
to_chat(src, "You cannot speak in IC (Muted).")
return FALSE
@@ -602,16 +602,15 @@
name = real_name
return TRUE
- emote("me", message = "[pick(emote_hear)]")
return TRUE
-/mob/living/simple_animal/demon/pulse_demon/update_runechat_msg_location()
+/mob/living/basic/demon/pulse_demon/update_runechat_msg_location()
if(istype(loc, /obj/machinery/hologram/holopad))
runechat_msg_location = loc.UID()
else
return ..()
-/mob/living/simple_animal/demon/pulse_demon/visible_message(message, self_message, blind_message, chat_message_type)
+/mob/living/basic/demon/pulse_demon/visible_message(message, self_message, blind_message, chat_message_type)
// overriden because pulse demon is quite often in non-turf locs, and /mob/visible_message acts differently there
for(var/mob/M as anything in get_mobs_in_view(7, src, ai_eyes = AI_EYE_INCLUDE))
if(M.see_invisible < invisibility)
@@ -621,10 +620,10 @@
msg = self_message
M.show_message(msg, EMOTE_VISIBLE, blind_message, EMOTE_AUDIBLE, chat_message_type = MESSAGE_TYPE_LOCALCHAT)
-/mob/living/simple_animal/demon/pulse_demon/has_internal_radio_channel_access(mob/user, list/req_one_accesses)
+/mob/living/basic/demon/pulse_demon/has_internal_radio_channel_access(mob/user, list/req_one_accesses)
return has_access(list(), req_one_accesses, get_all_accesses())
-/mob/living/simple_animal/demon/pulse_demon/proc/try_hijack_apc(obj/machinery/power/apc/A, remote = FALSE)
+/mob/living/basic/demon/pulse_demon/proc/try_hijack_apc(obj/machinery/power/apc/A, remote = FALSE)
// one APC per pulse demon, one pulse demon per APC, no duplicate APCs
if(!is_valid_apc(A) || (A in hijacked_apcs) || apc_being_hijacked || A.being_hijacked)
return FALSE
@@ -644,12 +643,12 @@
// Basically this proc gives you more max charge per apc you have hijacked
// Looks weird but it gets the job done
-/mob/living/simple_animal/demon/pulse_demon/proc/calc_maxcharge(hijacked_apcs)
+/mob/living/basic/demon/pulse_demon/proc/calc_maxcharge(hijacked_apcs)
if(!hijacked_apcs) // No APCs hijacked? No extra charge
return 100000
return 100000 + (hijacked_apcs * 25000)
-/mob/living/simple_animal/demon/pulse_demon/proc/finish_hijack_apc(obj/machinery/power/apc/A, remote = FALSE)
+/mob/living/basic/demon/pulse_demon/proc/finish_hijack_apc(obj/machinery/power/apc/A, remote = FALSE)
var/image/apc_image = image('icons/obj/power.dmi', A, "apcemag", ABOVE_LIGHTING_LAYER, A.dir)
apc_image.plane = ABOVE_LIGHTING_PLANE
LAZYADD(apc_images[get_turf(A)], apc_image)
@@ -666,7 +665,7 @@
var/distance = 0
strengthen_cables(T, distance)
-/mob/living/simple_animal/demon/pulse_demon/proc/strengthen_cables(turf/T, distance)
+/mob/living/basic/demon/pulse_demon/proc/strengthen_cables(turf/T, distance)
distance += 1
for(var/obj/structure/cable/cable in T.contents)
if(cable.strengthened == TRUE)
@@ -683,24 +682,24 @@
var/turf/next_turf = get_turf(cable)
strengthen_cables(next_turf, distance)
-/mob/living/simple_animal/demon/pulse_demon/proc/on_atom_entered(datum/source, atom/movable/entered)
+/mob/living/basic/demon/pulse_demon/proc/on_atom_entered(datum/source, atom/movable/entered)
SIGNAL_HANDLER // COMSIG_ATOM_ENTERED
try_cross_shock(entered)
-/mob/living/simple_animal/demon/pulse_demon/proc/on_movable_moved(datum/source, old_location, direction, forced)
+/mob/living/basic/demon/pulse_demon/proc/on_movable_moved(datum/source, old_location, direction, forced)
SIGNAL_HANDLER // COMSIG_MOVABLE_MOVED
if(is_under_tile())
return
for(var/mob/living/mob in loc)
try_shock_mob(mob)
-/mob/living/simple_animal/demon/pulse_demon/proc/try_cross_shock(atom/movable/A)
+/mob/living/basic/demon/pulse_demon/proc/try_cross_shock(atom/movable/A)
if(!isliving(A) || is_under_tile())
return
var/mob/living/L = A
try_shock_mob(L)
-/mob/living/simple_animal/demon/pulse_demon/proc/try_shock_mob(mob/living/L, siemens_coeff = 1)
+/mob/living/basic/demon/pulse_demon/proc/try_shock_mob(mob/living/L, siemens_coeff = 1)
var/dealt = 0
if(current_cable && current_cable.powernet && current_cable.powernet.available_power)
// returns used energy, not damage dealt, but ez conversion with /20
@@ -719,12 +718,12 @@
add_attack_logs(src, L, "shocked ([dealt] damage)")
-/mob/living/simple_animal/demon/pulse_demon/proc/is_under_tile()
+/mob/living/basic/demon/pulse_demon/proc/is_under_tile()
var/turf/T = get_turf(src)
return T.intact || HAS_TRAIT(T, TRAIT_TURF_COVERED)
// cable (and hijacked APC) view helper
-/mob/living/simple_animal/demon/pulse_demon/proc/update_cableview()
+/mob/living/basic/demon/pulse_demon/proc/update_cableview()
if(!client)
return
@@ -760,7 +759,7 @@
LAZYADD(apc_images[apc_turf], apc_image)
client.images += apc_image
-/mob/living/simple_animal/demon/pulse_demon/proc/handle_emp(datum/source, severity)
+/mob/living/basic/demon/pulse_demon/proc/handle_emp(datum/source, severity)
SIGNAL_HANDLER
if(emp_debounce)
return
@@ -777,12 +776,12 @@
emp_debounce = TRUE
addtimer(VARSET_CALLBACK(src, emp_debounce, FALSE), 0.1 SECONDS, TIMER_UNIQUE | TIMER_OVERRIDE)
-/mob/living/simple_animal/demon/pulse_demon/proc/try_attack_mob(mob/living/L)
+/mob/living/basic/demon/pulse_demon/proc/try_attack_mob(mob/living/L)
if(!is_under_tile() && L != src)
do_attack_animation(L)
try_shock_mob(L)
-/mob/living/simple_animal/demon/pulse_demon/UnarmedAttack(atom/A)
+/mob/living/basic/demon/pulse_demon/UnarmedAttack(atom/A)
if(isliving(A))
try_attack_mob(A)
else if(isitem(A) && !is_under_tile())
@@ -793,20 +792,20 @@
adjust_charge(min(C.charge, power_drain_rate))
visible_message("[src] touches [O] and drains its power!", "You touch [O] and drain it's power!")
-/mob/living/simple_animal/demon/pulse_demon/attack_hand(mob/living/carbon/human/M)
+/mob/living/basic/demon/pulse_demon/attack_hand(mob/living/carbon/human/M)
if(is_under_tile())
to_chat(M, "You can't interact with something that's under the floor!")
return
switch(M.intent)
if(INTENT_HELP)
- visible_message("[M] [response_help] [src].")
+ visible_message("[M] [response_help_continuous] [src].")
if(INTENT_DISARM, INTENT_GRAB)
- visible_message("[M] [response_disarm] [src].")
+ visible_message("[M] [response_disarm_continuous] [src].")
if(INTENT_HELP)
- visible_message("[M] [response_harm] [src].")
+ visible_message("[M] [response_harm_continuous] [src].")
try_attack_mob(M)
-/mob/living/simple_animal/demon/pulse_demon/attack_by(obj/item/O, mob/living/user, params)
+/mob/living/basic/demon/pulse_demon/attack_by(obj/item/O, mob/living/user, params)
if(..())
return FINISH_ATTACK
@@ -824,63 +823,63 @@
try_shock_mob(user, O.siemens_coefficient)
return FINISH_ATTACK
-/mob/living/simple_animal/demon/pulse_demon/ex_act()
+/mob/living/basic/demon/pulse_demon/ex_act()
return
-/mob/living/simple_animal/demon/pulse_demon/CanPass(atom/movable/mover, border_dir)
+/mob/living/basic/demon/pulse_demon/CanPass(atom/movable/mover, border_dir)
. = ..()
if(istype(mover, /obj/projectile/ion))
return FALSE
-/mob/living/simple_animal/demon/pulse_demon/bullet_act(obj/projectile/proj)
+/mob/living/basic/demon/pulse_demon/bullet_act(obj/projectile/proj)
if(proj.damage_type == BURN)
regen_lock = max(regen_lock, 1)
return ..()
else
visible_message("[proj] goes right through [src]!")
-/mob/living/simple_animal/demon/pulse_demon/electrocute_act(shock_damage, source, siemens_coeff, flags)
+/mob/living/basic/demon/pulse_demon/electrocute_act(shock_damage, source, siemens_coeff, flags)
return
-/mob/living/simple_animal/demon/pulse_demon/blob_act(obj/structure/blob/B)
+/mob/living/basic/demon/pulse_demon/blob_act(obj/structure/blob/B)
return // will likely end up dying if the blob cuts its wires anyway
-/mob/living/simple_animal/demon/pulse_demon/narsie_act()
+/mob/living/basic/demon/pulse_demon/narsie_act()
return // you can't turn electricity into a harvester
-/mob/living/simple_animal/demon/pulse_demon/get_access()
+/mob/living/basic/demon/pulse_demon/get_access()
return get_all_accesses()
-/mob/living/simple_animal/demon/pulse_demon/IsAdvancedToolUser()
+/mob/living/basic/demon/pulse_demon/IsAdvancedToolUser()
return TRUE // interacting with machines
-/mob/living/simple_animal/demon/pulse_demon/can_be_pulled()
+/mob/living/basic/demon/pulse_demon/can_be_pulled()
return FALSE
-/mob/living/simple_animal/demon/pulse_demon/can_buckle()
+/mob/living/basic/demon/pulse_demon/can_buckle()
return FALSE
-/mob/living/simple_animal/demon/pulse_demon/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
+/mob/living/basic/demon/pulse_demon/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
return
-/mob/living/simple_animal/demon/pulse_demon/experience_pressure_difference(flow_x, flow_y)
+/mob/living/basic/demon/pulse_demon/experience_pressure_difference(flow_x, flow_y)
return // Immune to gas flow.
-/mob/living/simple_animal/demon/pulse_demon/singularity_pull()
+/mob/living/basic/demon/pulse_demon/singularity_pull()
return
-/mob/living/simple_animal/demon/pulse_demon/mob_negates_gravity()
+/mob/living/basic/demon/pulse_demon/mob_negates_gravity()
return TRUE
-/mob/living/simple_animal/demon/pulse_demon/mob_has_gravity()
+/mob/living/basic/demon/pulse_demon/mob_has_gravity()
return TRUE
-/mob/living/simple_animal/demon/pulse_demon/can_remote_apc_interface(obj/machinery/power/apc/ourapc)
+/mob/living/basic/demon/pulse_demon/can_remote_apc_interface(obj/machinery/power/apc/ourapc)
if(ourapc.hacked_by_ruin_AI || ourapc.malfai || ourapc.malfhack)
return FALSE
return TRUE
-/mob/living/simple_animal/demon/pulse_demon/adjustHealth(amount, updating_health)
+/mob/living/basic/demon/pulse_demon/adjustHealth(amount, updating_health)
if(amount > 0) // This damages the pulse demon
return ..()
@@ -892,43 +891,6 @@
amount = round(amount, 1)
return ..()
-/obj/item/organ/internal/heart/demon/pulse
- name = "perpetual pacemaker"
- desc = "It still beats furiously, thousands of bright lights shine within it."
- color = COLOR_YELLOW
-
-/obj/item/organ/internal/heart/demon/pulse/Initialize(mapload)
- . = ..()
- set_light(13, 2, "#bbbb00")
-
-/obj/item/organ/internal/heart/demon/pulse/attack_self__legacy__attackchain(mob/living/user)
- . = ..()
- user.drop_item()
- insert(user)
-
-/obj/item/organ/internal/heart/demon/pulse/insert(mob/living/carbon/M, special, dont_remove_slot)
- . = ..()
- M.AddComponent(/datum/component/cross_shock, 30, 500, 2 SECONDS)
- ADD_TRAIT(M, TRAIT_SHOCKIMMUNE, UNIQUE_TRAIT_SOURCE(src))
- M.set_light(3, 2, "#bbbb00")
-
-/obj/item/organ/internal/heart/demon/pulse/remove(mob/living/carbon/M, special)
- . = ..()
- REMOVE_TRAIT(M, TRAIT_SHOCKIMMUNE, UNIQUE_TRAIT_SOURCE(src))
- M.remove_light()
-
-/obj/item/organ/internal/heart/demon/pulse/on_life()
- if(!owner)
- return
- for(var/obj/item/stock_parts/cell/cell_to_charge in owner.GetAllContents())
- var/newcharge = min(0.05 * cell_to_charge.maxcharge + cell_to_charge.charge, cell_to_charge.maxcharge)
- if(cell_to_charge.charge < newcharge)
- cell_to_charge.charge = newcharge
- if(isobj(cell_to_charge.loc))
- var/obj/cell_location = cell_to_charge.loc
- cell_location.update_icon() //update power meters and such
- cell_to_charge.update_icon()
-
/atom/movable/screen/alert/pulse_nopower
name = "No Power"
desc = "You are not connected to a cable or machine and are losing health!"
diff --git a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_interactions.dm b/code/modules/mob/living/basic/hostile/demons/pulse_demon_interactions.dm
similarity index 80%
rename from code/game/gamemodes/miniantags/pulsedemon/pulsedemon_interactions.dm
rename to code/modules/mob/living/basic/hostile/demons/pulse_demon_interactions.dm
index e1b106efac9..a43c39c4fbd 100644
--- a/code/game/gamemodes/miniantags/pulsedemon/pulsedemon_interactions.dm
+++ b/code/modules/mob/living/basic/hostile/demons/pulse_demon_interactions.dm
@@ -1,4 +1,4 @@
-/mob/living/simple_animal/demon/pulse_demon/ClickOn(atom/A, params)
+/mob/living/basic/demon/pulse_demon/ClickOn(atom/A, params)
if(client?.click_intercept)
client.click_intercept.InterceptClickOn(src, params, A)
return
@@ -42,7 +42,7 @@
changeNext_click(0.1 SECONDS)
// returns TRUE if any [modifier]ClickOn was called
-/mob/living/simple_animal/demon/pulse_demon/proc/try_modified_click(atom/A, params)
+/mob/living/basic/demon/pulse_demon/proc/try_modified_click(atom/A, params)
var/list/modifiers = params2list(params)
if(modifiers["middle"])
if(modifiers["shift"])
@@ -62,43 +62,43 @@
return FALSE
// check area for all of these, then do AI actions
-/mob/living/simple_animal/demon/pulse_demon/MiddleShiftClickOn(atom/A)
+/mob/living/basic/demon/pulse_demon/MiddleShiftClickOn(atom/A)
if(get_area(A) == controlling_area)
A.AIShiftMiddleClick(src)
-/mob/living/simple_animal/demon/pulse_demon/ShiftClickOn(atom/A)
+/mob/living/basic/demon/pulse_demon/ShiftClickOn(atom/A)
if(get_area(A) == controlling_area)
A.AIShiftClick(src)
else
examinate(A)
-/mob/living/simple_animal/demon/pulse_demon/AltClickOn(atom/A)
+/mob/living/basic/demon/pulse_demon/AltClickOn(atom/A)
if(get_area(A) == controlling_area)
A.AIAltClick(src)
else
AltClickNoInteract(src, A)
-/mob/living/simple_animal/demon/pulse_demon/CtrlClickOn(atom/A)
+/mob/living/basic/demon/pulse_demon/CtrlClickOn(atom/A)
if(get_area(A) == controlling_area)
A.AICtrlClick(src)
// for alt-click status tab
-/mob/living/simple_animal/demon/pulse_demon/TurfAdjacent(turf/T)
+/mob/living/basic/demon/pulse_demon/TurfAdjacent(turf/T)
return get_area(T) == controlling_area || ..()
// for overrides in general
-/atom/proc/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/atom/proc/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
return
-/obj/machinery/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
return attack_ai(user)
// ai not allowed to use cams consoles
-/obj/machinery/computer/security/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/computer/security/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
return attack_hand(user)
// jump back into our apc
-/obj/machinery/power/apc/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/power/apc/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
if(user.loc != src)
user.forceMove(src)
user.current_power = src
@@ -106,7 +106,7 @@
else
attack_ai(user)
-/mob/living/simple_animal/bot/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/mob/living/simple_animal/bot/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
if(user.loc == src)
return
to_chat(user, "You are now inside [src]. If it is destroyed, you will be dropped onto the ground, and may die if there is no cable under you.")
@@ -121,12 +121,12 @@
to_chat(user, "[src] isn't turned on!")
return
if(ispulsedemon(user))
- var/mob/living/simple_animal/demon/pulse_demon/demon = user
+ var/mob/living/basic/demon/pulse_demon/demon = user
if(demon.bot_movedelay <= world.time && dir)
Move(get_step(get_turf(src), dir))
demon.bot_movedelay = world.time + (BOT_STEP_DELAY * (base_speed - 1)) * ((dir in GLOB.diagonals) ? SQRT_2 : 1)
-/obj/machinery/recharger/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/recharger/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
user.forceMove(src)
if(!charging)
to_chat(user, "There is no weapon charging. Click again to retry.")
@@ -141,7 +141,7 @@
user.forceMove(charging)
user.current_weapon = charging
-/obj/machinery/cell_charger/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/cell_charger/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
user.forceMove(src)
if(!charging)
to_chat(user, "There is no cell charging. Click again to retry.")
@@ -159,7 +159,7 @@
to_chat(user, "You are now inside [charging]. Click on a hijacked APC to return.")
user.forceMove(charging)
-/obj/machinery/recharge_station/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/recharge_station/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
user.forceMove(src)
if(!isrobot(occupant))
to_chat(user, "There is no silicon-based occupant inside. Click again to retry.")
@@ -177,7 +177,7 @@
return
to_chat(src, "Failed to hijack [src].")
-/mob/living/simple_animal/demon/pulse_demon/proc/do_hijack_robot(mob/living/silicon/robot/R)
+/mob/living/basic/demon/pulse_demon/proc/do_hijack_robot(mob/living/silicon/robot/R)
to_chat(src, "You are now inside [R]. Click on a hijacked APC to return.")
forceMove(R)
current_robot = R
@@ -185,25 +185,25 @@
hijacked_robots += R
to_chat(R, "TARGETING SYSTEMS HIJACKED, REPORT ALL UNWANTED ACTIVITY")
-/obj/machinery/camera/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/camera/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
if(user.loc != src)
user.forceMove(src)
to_chat(user, "You jump towards [src]. Click on a hijacked APC to return.")
// see pulse_demon/say
-/obj/machinery/hologram/holopad/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/machinery/hologram/holopad/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
if(user.loc != src)
user.forceMove(src)
to_chat(user, "You jump towards [src]. You can now communicate via the holopad's speaker. Click on a hijacked APC to return.")
-/obj/item/radio/attack_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user)
+/obj/item/radio/attack_pulsedemon(mob/living/basic/demon/pulse_demon/user)
if(user.loc != src)
user.forceMove(src)
to_chat(user, "You jump towards [src]. You can now communicate via radio. Click on a hijacked APC to return.")
else
attack_ai(user)
-/mob/living/simple_animal/bot/proc/attack_integrated_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user, atom/A)
+/mob/living/simple_animal/bot/proc/attack_integrated_pulsedemon(mob/living/basic/demon/pulse_demon/user, atom/A)
if(!on)
return
if(Adjacent(A))
@@ -211,7 +211,7 @@
else
RangedAttack(A)
-/mob/living/simple_animal/bot/secbot/attack_integrated_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user, atom/A)
+/mob/living/simple_animal/bot/secbot/attack_integrated_pulsedemon(mob/living/basic/demon/pulse_demon/user, atom/A)
if(!on)
return
if(Adjacent(A))
@@ -221,7 +221,7 @@
playsound(loc, pick('sound/voice/bcriminal.ogg', 'sound/voice/bjustice.ogg', 'sound/voice/bfreeze.ogg'), 50)
visible_message("[src] points at [A.name]!")
-/mob/living/simple_animal/bot/floorbot/attack_integrated_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user, atom/A)
+/mob/living/simple_animal/bot/floorbot/attack_integrated_pulsedemon(mob/living/basic/demon/pulse_demon/user, atom/A)
if(!on)
return
if(isfloorturf(A) && Adjacent(A))
@@ -230,7 +230,7 @@
F.break_tile_to_plating()
audible_message("[src] makes an excited booping sound.")
-/mob/living/simple_animal/bot/cleanbot/attack_integrated_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user, atom/A)
+/mob/living/simple_animal/bot/cleanbot/attack_integrated_pulsedemon(mob/living/basic/demon/pulse_demon/user, atom/A)
if(!on)
return
if(isfloorturf(A) && Adjacent(A))
@@ -243,7 +243,7 @@
new /obj/effect/decal/cleanable/blood/gibs(F)
playsound(F, 'sound/effects/blobattack.ogg', 40, TRUE)
-/mob/living/simple_animal/bot/mulebot/attack_integrated_pulsedemon(mob/living/simple_animal/demon/pulse_demon/user, atom/A)
+/mob/living/simple_animal/bot/mulebot/attack_integrated_pulsedemon(mob/living/basic/demon/pulse_demon/user, atom/A)
if(!on)
return
if(istype(A) && Adjacent(A) && ismovable(A))
diff --git a/code/game/gamemodes/miniantags/demons/shadow_demon/shadow_demon.dm b/code/modules/mob/living/basic/hostile/demons/shadow_demon.dm
similarity index 65%
rename from code/game/gamemodes/miniantags/demons/shadow_demon/shadow_demon.dm
rename to code/modules/mob/living/basic/hostile/demons/shadow_demon.dm
index 5a75c97211a..494d138ea79 100644
--- a/code/game/gamemodes/miniantags/demons/shadow_demon/shadow_demon.dm
+++ b/code/modules/mob/living/basic/hostile/demons/shadow_demon.dm
@@ -1,4 +1,4 @@
-/mob/living/simple_animal/demon/shadow
+/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'
@@ -17,7 +17,7 @@
/// Used for fault tolerance. If you set it manually, it may fuck up shooting_grapple var.
var/last_block_shadow_crawl = 0
-/mob/living/simple_animal/demon/shadow/Login()
+/mob/living/basic/demon/shadow/Login()
..()
var/list/L = list(
"You are a shadow demon!",
@@ -30,7 +30,7 @@
)
to_chat(src, chat_box_red(L.Join("
")))
-/mob/living/simple_animal/demon/shadow/Life(seconds, times_fired)
+/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
@@ -41,7 +41,7 @@
else
adjustBruteLoss(-20)
-/mob/living/simple_animal/demon/shadow/UnarmedAttack(atom/A)
+/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))
@@ -52,7 +52,7 @@
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
+ 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)
@@ -71,16 +71,16 @@
target.forceMove(C)
wrapping = FALSE
-/mob/living/simple_animal/demon/shadow/proc/block_shadow_crawl()
+/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/simple_animal/demon/shadow/proc/unblock_shadow_crawl()
+/mob/living/basic/demon/shadow/proc/unblock_shadow_crawl()
last_block_shadow_crawl = 0
block_shadow_crawl = FALSE
-/mob/living/simple_animal/demon/shadow/proc/check_block_shadow_crawl(block_time)
+/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, "You feel good enough to use Shadow Crawl again.")
@@ -109,7 +109,7 @@
/obj/structure/shadowcocoon/examine(mob/user)
. = ..()
- if(istype(user, /mob/living/simple_animal/demon/shadow))
+ if(istype(user, /mob/living/basic/demon/shadow))
. += silent ? "The tendrils are idle and will not produce noise." : "The tendrils are agitated and will occasionally produce noise to lure in more prey."
. += "Alt+Click to toggle whether [src] should produce noise to lure in victims."
@@ -161,12 +161,12 @@
A.forceMove(loc)
return..()
-/mob/living/simple_animal/demon/shadow/hitby(atom/movable/AM, skipcatch, hitpush, blocked, datum/thrownthing/throwingdatum)
+/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/simple_animal/demon/shadow/Initialize(mapload)
+/mob/living/basic/demon/shadow/Initialize(mapload)
. = ..()
AddSpell(new /datum/spell/fireball/shadow_grapple)
var/datum/spell/bloodcrawl/shadow_crawl/S = new
@@ -175,11 +175,11 @@
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/simple_animal/demon/shadow, check_darkness))
+ 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/simple_animal/demon/shadow/proc/check_darkness()
+/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)
@@ -195,98 +195,3 @@
alpha = 125
speed = 0.5
return lum_count
-
-
-/datum/spell/fireball/shadow_grapple
- name = "Shadow Grapple"
- desc = "Fire one of your hands, if it hits a person it pulls them in. If you hit a structure you get pulled to the structure. Any light source hit with this will be disabled in a two tile radius."
- base_cooldown = 10 SECONDS
- fireball_type = /obj/projectile/magic/shadow_hand
-
- selection_activated_message = "You raise your hand, full of demonic energy! Left-click to cast at a target!"
- selection_deactivated_message = "You re-absorb the energy...for now."
-
- action_background_icon_state = "shadow_demon_bg"
- action_icon_state = "shadow_grapple"
- sound = null
- invocation_type = "none"
- invocation = null
-
-/datum/spell/fireball/shadow_grapple/update_spell_icon()
- return
-
-/obj/projectile/magic/shadow_hand
- name = "shadow hand"
- icon_state = "shadow_hand"
- plane = FLOOR_PLANE
- hitsound = 'sound/shadowdemon/shadowattack1.ogg' // Plays when hitting something living or a light
- var/hit = FALSE
-
-/obj/projectile/magic/shadow_hand/pixel_move(trajectory_multiplier, hitscanning)
- . = ..()
- var/obj/machinery/light/floor/floor_light = locate(/obj/machinery/light/floor) in get_turf(src)
- if(floor_light)
- Bump(floor_light)
-
-/obj/projectile/magic/shadow_hand/fire(setAngle)
- if(firer)
- var/mob/living/simple_animal/demon/shadow/current_demon = firer
- if(istype(current_demon))
- current_demon.block_shadow_crawl()
- firer.Beam(src, icon_state = "grabber_beam", time = INFINITY, maxdistance = INFINITY, beam_type = /obj/effect/ebeam/floor)
- return ..()
-
-/obj/projectile/magic/shadow_hand/on_hit(atom/target, blocked, hit_zone)
- if(hit)
- return
- hit = TRUE // to prevent double hits from the pull
- . = ..()
- for(var/atom/extinguish_target in range(2, src))
- extinguish_target.extinguish_light(TRUE)
- if(!isliving(target))
- if(isshadowdemon(firer))
- firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10, callback = CALLBACK(firer, TYPE_PROC_REF(/mob/living/simple_animal/demon/shadow, unblock_shadow_crawl)))
- else
- firer.throw_at(get_step(target, get_dir(target, firer)), 50, 10)
- else
- unblock_shadowdemon_crawl()
- if(!.)
- return
- else
- var/mob/living/L = target
- L.Immobilize(2 SECONDS)
- L.apply_damage(40, BRUTE, BODY_ZONE_CHEST)
- L.throw_at(get_step(firer, get_dir(firer, target)), 50, 10)
-
-/obj/projectile/magic/shadow_hand/Destroy()
- if(!hit)
- unblock_shadowdemon_crawl()
- return ..()
-
-/obj/projectile/magic/shadow_hand/proc/unblock_shadowdemon_crawl()
- var/mob/living/simple_animal/demon/shadow/current_demon = firer
- if(istype(current_demon))
- current_demon.unblock_shadow_crawl()
-
-/obj/effect/ebeam/floor
- plane = FLOOR_PLANE
-
-/obj/item/organ/internal/heart/demon/shadow
- name = "heart of darkness"
- desc = "It still beats furiously, emitting an aura of fear."
- color = COLOR_BLACK
-
-/obj/item/organ/internal/heart/demon/shadow/attack_self__legacy__attackchain(mob/living/user)
- . = ..()
- user.drop_item()
- insert(user)
-
-/obj/item/organ/internal/heart/demon/shadow/insert(mob/living/carbon/M, special = 0)
- . = ..()
- if(M.mind)
- M.mind.AddSpell(new /datum/spell/fireball/shadow_grapple)
-
-/obj/item/organ/internal/heart/demon/shadow/remove(mob/living/carbon/M, special = 0)
- . = ..()
- if(M.mind)
- M.mind.RemoveSpell(/datum/spell/fireball/shadow_grapple)
diff --git a/code/modules/mob/living/basic/hostile/demons/slaughter_demon.dm b/code/modules/mob/living/basic/hostile/demons/slaughter_demon.dm
new file mode 100644
index 00000000000..71bb4706047
--- /dev/null
+++ b/code/modules/mob/living/basic/hostile/demons/slaughter_demon.dm
@@ -0,0 +1,168 @@
+/// The Monster
+
+/mob/living/basic/demon/slaughter
+ name = "slaughter demon"
+ real_name = "slaughter demon"
+ desc = "A large, menacing creature covered in armored black scales. You should run."
+ maxHealth = 240
+ health = 240
+ icon = 'icons/mob/mob.dmi'
+ icon_state = "daemon"
+ icon_living = "daemon"
+ var/boost = 0
+ var/feast_sound = 'sound/misc/demon_consume.ogg'
+ var/devoured = 0
+ var/list/consumed_mobs = list()
+
+ var/list/nearby_mortals = list()
+ var/cooldown = 0
+ var/gorecooldown = 0
+ var/vialspawned = FALSE
+ loot = list(/obj/effect/decal/cleanable/blood/innards, /obj/effect/decal/cleanable/blood, /obj/effect/gibspawner/generic, /obj/effect/gibspawner/generic, /obj/item/organ/internal/heart/demon/slaughter)
+ var/playstyle_string = "You are the Slaughter Demon, a terrible creature from another existence. You have a single desire: to kill. \
+ You may use the blood crawl icon when on blood pools to travel through them, appearing and dissapearing 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. "
+ death_message = "screams in anger as it collapses into a puddle of viscera!"
+
+/mob/living/basic/demon/slaughter/New()
+ ..()
+ remove_from_all_data_huds()
+ ADD_TRAIT(src, TRAIT_BLOODCRAWL_EAT, "bloodcrawl_eat")
+ var/datum/spell/bloodcrawl/bloodspell = new
+ AddSpell(bloodspell)
+ if(istype(loc, /obj/effect/dummy/slaughter))
+ bloodspell.phased = TRUE
+ addtimer(CALLBACK(src, PROC_REF(attempt_objectives)), 5 SECONDS)
+
+/mob/living/basic/demon/slaughter/Life(seconds, times_fired)
+ ..()
+ if(boost < world.time)
+ speed = 1
+ else
+ speed = 0
+
+/mob/living/basic/demon/slaughter/proc/attempt_objectives()
+ if(mind)
+ var/list/messages = list()
+ messages.Add(playstyle_string)
+ messages.Add("You are not currently in the same plane of existence as the station. Use the blood crawl action at a blood pool to manifest.")
+ SEND_SOUND(src, sound('sound/misc/demon_dies.ogg'))
+ if(!vialspawned)
+ SSticker.mode.traitors |= mind
+ mind.add_mind_objective(/datum/objective/slaughter)
+ mind.add_mind_objective(/datum/objective/demon_fluff)
+ messages.Add(mind.prepare_announce_objectives(FALSE))
+
+ messages.Add("For more information, check the wiki page: ([GLOB.configuration.url.wiki_url]/index.php/Slaughter_Demon)")
+ to_chat(src, chat_box_red(messages.Join("
")))
+
+/obj/effect/decal/cleanable/blood/innards
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "innards"
+ base_icon = 'icons/obj/surgery.dmi'
+ icon_state = "innards"
+ random_icon_states = list("innards")
+ name = "pile of viscera"
+ desc = "A repulsive pile of guts and gore."
+ weightless_icon = 'icons/obj/surgery.dmi'
+
+/mob/living/basic/demon/slaughter/Destroy()
+ // Only execute the below if we successfully died
+ for(var/mob/living/M in consumed_mobs)
+ REMOVE_TRAIT(M, TRAIT_UNREVIVABLE, "demon")
+ release_consumed(M)
+ . = ..()
+
+/mob/living/basic/demon/slaughter/proc/release_consumed(mob/living/M)
+ M.forceMove(get_turf(src))
+
+// Midround slaughter demon, less tanky
+/mob/living/basic/demon/slaughter/lesser
+ maxHealth = 170
+ health = 170
+
+// Cult slaughter demon
+/// Summoned as part of the cult objective "Bring the Slaughter"
+/mob/living/basic/demon/slaughter/cult
+ name = "harbinger of the slaughter"
+ real_name = "harbinger of the Slaughter"
+ desc = "An awful creature from beyond the realms of madness."
+ maxHealth = 540
+ health = 540
+ melee_damage_upper = 60
+ melee_damage_lower = 60
+ environment_smash = ENVIRONMENT_SMASH_RWALLS // Smashes through EVERYTHING - r-walls included
+ faction = list("cult")
+ playstyle_string = "You are a Harbinger of the Slaughter. Brought forth by the servants of Nar'Sie, you have a single purpose: slaughter the heretics \
+ who do not worship your master. You may use the ability 'Blood Crawl' near a pool of blood to enter it and become incorporeal. Using the ability again near a blood pool will allow you \
+ to emerge from it. You are fast, powerful, and almost invincible. By dragging a dead or unconscious body into a blood pool with you, you will consume it after a time and fully regain \
+ your health. You may use the ability 'Sense Victims' in your Cultist tab to locate a random, living heretic."
+
+/mob/living/basic/demon/slaughter/cult/New()
+ ..()
+ spawn(5)
+ var/list/demon_candidates = SSghost_spawns.poll_candidates("Do you want to play as a slaughter demon?", ROLE_DEMON, TRUE, 10 SECONDS, source = /mob/living/basic/demon/slaughter/cult)
+ if(!length(demon_candidates))
+ visible_message("[src] disappears in a flash of red light!")
+ qdel(src)
+ return
+ if(QDELETED(src)) // Just in case
+ return
+ var/mob/M = pick(demon_candidates)
+ var/mob/living/basic/demon/slaughter/cult/S = src
+ if(!M || !M.client)
+ visible_message("[src] disappears in a flash of red light!")
+ qdel(src)
+ return
+ var/client/C = M.client
+
+ S.key = C.key
+ dust_if_respawnable(M)
+ S.mind.assigned_role = "Harbinger of the Slaughter"
+ S.mind.special_role = "Harbinger of the Slaughter"
+ to_chat(S, playstyle_string)
+ S.mind.add_antag_datum(/datum/antagonist/cultist)
+ var/datum/spell/sense_victims/SV = new
+ AddSpell(SV)
+
+ S.mind.add_mind_objective(/datum/objective/cult_slaughter)
+ var/list/messages = S.mind.prepare_announce_objectives(FALSE)
+ to_chat(S, chat_box_red(messages.Join("
")))
+
+/mob/living/basic/demon/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", "gaffaws", "laughs")
+ response_help_continuous = "hugs"
+ response_help_simple = "hug"
+ attack_verb_continuous = "wildly tickles"
+ attack_verb_simple = "wildly tickles"
+ maxHealth = 215
+ health = 215
+ melee_damage_lower = 25
+ melee_damage_upper = 25
+ playstyle_string = "You are the Laughter Demon, an adorable creature from another existence. You have a single desire: to hug and tickle. \
+ You may use the blood crawl icon when on blood pools to travel through them, appearing and dissapearing 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 hug them. \
+ You move quickly upon leaving a pool of blood, but the material world will soon sap your strength and leave you sluggish. \
+ (You should be attacking people on harm intent, and not nuzzling them.)"
+
+ 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"
+ death_message = "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/basic/demon/slaughter/laughter/release_consumed(mob/living/M)
+ if(M.revive())
+ M.grab_ghost(force = TRUE)
+ playsound(get_turf(src), feast_sound, 50, TRUE, -1)
+ to_chat(M, "You leave [src]'s warm embrace, and feel ready to take on the world.")
+ ..(M)
diff --git a/code/modules/mob/living/silicon/robot/robot_mob.dm b/code/modules/mob/living/silicon/robot/robot_mob.dm
index 82ff3460ea1..407d0cf2b6a 100644
--- a/code/modules/mob/living/silicon/robot/robot_mob.dm
+++ b/code/modules/mob/living/silicon/robot/robot_mob.dm
@@ -1007,7 +1007,7 @@ GLOBAL_LIST_INIT(robot_verbs_default, list(
C.install(W)
var/been_hijacked = FALSE
- for(var/mob/living/simple_animal/demon/pulse_demon/demon in cell)
+ for(var/mob/living/basic/demon/pulse_demon/demon in cell)
if(!been_hijacked)
demon.do_hijack_robot(src)
been_hijacked = TRUE
diff --git a/code/modules/power/apc/apc.dm b/code/modules/power/apc/apc.dm
index ef8460035db..f46a15a871c 100644
--- a/code/modules/power/apc/apc.dm
+++ b/code/modules/power/apc/apc.dm
@@ -253,7 +253,7 @@
"[user] inserts [used] into [src].",
"You insert [used] into [src]."
)
- for(var/mob/living/simple_animal/demon/pulse_demon/demon in cell)
+ for(var/mob/living/basic/demon/pulse_demon/demon in cell)
demon.forceMove(src)
demon.current_power = src
if(!being_hijacked) // First come, first serve!
diff --git a/code/modules/tgui/states/default.dm b/code/modules/tgui/states/default.dm
index 27cc3fdfda5..b1e4b312359 100644
--- a/code/modules/tgui/states/default.dm
+++ b/code/modules/tgui/states/default.dm
@@ -52,7 +52,7 @@ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
/mob/living/basic/revenant/default_can_use_topic(src_object)
return UI_UPDATE
-/mob/living/simple_animal/demon/pulse_demon/default_can_use_topic(src_object)
+/mob/living/basic/demon/pulse_demon/default_can_use_topic(src_object)
. = shared_ui_interaction(src_object)
if(. < UI_INTERACTIVE)
return
diff --git a/code/modules/tgui/states/physical.dm b/code/modules/tgui/states/physical.dm
index ea16eaf3d84..8fbf00542ab 100644
--- a/code/modules/tgui/states/physical.dm
+++ b/code/modules/tgui/states/physical.dm
@@ -19,7 +19,7 @@ GLOBAL_DATUM_INIT(physical_state, /datum/ui_state/physical, new)
/mob/proc/physical_can_use_topic(src_object)
return UI_CLOSE
-/mob/living/simple_animal/demon/pulse_demon/physical_can_use_topic(src_object)
+/mob/living/basic/demon/pulse_demon/physical_can_use_topic(src_object)
return UI_UPDATE
/mob/living/physical_can_use_topic(src_object)
diff --git a/paradise.dme b/paradise.dme
index 4530a2b0d5d..0bbf9e40a70 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -542,6 +542,7 @@
#include "code\datums\components\connect_mob_behalf.dm"
#include "code\datums\components\connect_range.dm"
#include "code\datums\components\corpse_description.dm"
+#include "code\datums\components\cross_shock_component.dm"
#include "code\datums\components\cult_held_body.dm"
#include "code\datums\components\deadchat_control.dm"
#include "code\datums\components\debris.dm"
@@ -923,9 +924,6 @@
#include "code\game\gamemodes\miniantags\abduction\machinery\dispenser.dm"
#include "code\game\gamemodes\miniantags\abduction\machinery\experiment.dm"
#include "code\game\gamemodes\miniantags\abduction\machinery\pad.dm"
-#include "code\game\gamemodes\miniantags\demons\demon.dm"
-#include "code\game\gamemodes\miniantags\demons\shadow_demon\shadow_demon.dm"
-#include "code\game\gamemodes\miniantags\demons\slaughter_demon\slaughter.dm"
#include "code\game\gamemodes\miniantags\guardian\guardian.dm"
#include "code\game\gamemodes\miniantags\guardian\host_actions.dm"
#include "code\game\gamemodes\miniantags\guardian\types\assassin.dm"
@@ -944,12 +942,6 @@
#include "code\game\gamemodes\miniantags\morph\spells\open_vent.dm"
#include "code\game\gamemodes\miniantags\morph\spells\pass_airlock.dm"
#include "code\game\gamemodes\miniantags\morph\spells\reproduce.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\cross_shock_component.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\pulsedemon.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\pulsedemon_abilities.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\pulsedemon_event.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\pulsedemon_interactions.dm"
-#include "code\game\gamemodes\miniantags\pulsedemon\pulsedemon_objectives.dm"
#include "code\game\gamemodes\miniantags\tourist\tourist_arrivals.dm"
#include "code\game\gamemodes\miniantags\tourist\tourist_objectives.dm"
#include "code\game\gamemodes\nuclear\nuclear.dm"
@@ -2135,6 +2127,7 @@
#include "code\modules\events\meteors_event.dm"
#include "code\modules\events\money_spam.dm"
#include "code\modules\events\prison_break.dm"
+#include "code\modules\events\pulsedemon_event.dm"
#include "code\modules\events\radiation_storm_event.dm"
#include "code\modules\events\revenant_spawn_event.dm"
#include "code\modules\events\rogue_drones.dm"
@@ -2523,6 +2516,14 @@
#include "code\modules\mob\living\basic\hostile\alien\alien_mob_maid.dm"
#include "code\modules\mob\living\basic\hostile\alien\alien_mob_queen.dm"
#include "code\modules\mob\living\basic\hostile\alien\alien_mob_sentinel.dm"
+#include "code\modules\mob\living\basic\hostile\demons\demon.dm"
+#include "code\modules\mob\living\basic\hostile\demons\demon_loot.dm"
+#include "code\modules\mob\living\basic\hostile\demons\demon_objectives.dm"
+#include "code\modules\mob\living\basic\hostile\demons\demon_powers.dm"
+#include "code\modules\mob\living\basic\hostile\demons\pulse_demon.dm"
+#include "code\modules\mob\living\basic\hostile\demons\pulse_demon_interactions.dm"
+#include "code\modules\mob\living\basic\hostile\demons\shadow_demon.dm"
+#include "code\modules\mob\living\basic\hostile\demons\slaughter_demon.dm"
#include "code\modules\mob\living\basic\hostile\bees\bee_ai_behaviors.dm"
#include "code\modules\mob\living\basic\hostile\bees\bee_ai_subtree.dm"
#include "code\modules\mob\living\basic\hostile\bees\bees.dm"
diff --git a/tools/ci/check_simplemob_additions.py b/tools/ci/check_simplemob_additions.py
index 41c193f93ea..2b3aa743c8e 100644
--- a/tools/ci/check_simplemob_additions.py
+++ b/tools/ci/check_simplemob_additions.py
@@ -45,14 +45,6 @@ BURNDOWN_LIST = {
"/mob/living/simple_animal/bot/secbot/griefsky/toy",
"/mob/living/simple_animal/bot/secbot/ofitser",
"/mob/living/simple_animal/bot/secbot/pingsky",
- "/mob/living/simple_animal/demon",
- "/mob/living/simple_animal/demon/pulse_demon",
- "/mob/living/simple_animal/demon/pulse_demon/wizard",
- "/mob/living/simple_animal/demon/shadow",
- "/mob/living/simple_animal/demon/slaughter",
- "/mob/living/simple_animal/demon/slaughter/cult",
- "/mob/living/simple_animal/demon/slaughter/laughter",
- "/mob/living/simple_animal/demon/slaughter/lesser",
"/mob/living/simple_animal/drone",
"/mob/living/simple_animal/hostile",
"/mob/living/simple_animal/hostile/ancient_robot_leg",