From 371afef40c82acb7885b0b40f09aee5a815b9f45 Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:47:06 +0200
Subject: [PATCH 01/76] Update is_helpers.dm
---
code/__DEFINES/is_helpers.dm | 2 ++
1 file changed, 2 insertions(+)
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 03778ec77400..dae1c56072c0 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -111,6 +111,8 @@ GLOBAL_LIST_INIT(turfs_without_ground, typecacheof(list(
#define isrevenant(A) (istype(A, /mob/living/simple_animal/revenant))
+#define ishorror(A) (istype(A, /mob/living/simple_animal/horror))
+
#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
#define isshade(A) (istype(A, /mob/living/simple_animal/shade))
From 26028e71d40f8b0bd79c248a33918d1c9a58b0a5 Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:48:09 +0200
Subject: [PATCH 02/76] Add files via upload
---
code/modules/events/horror.dm | 37 +++++++++++++++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 code/modules/events/horror.dm
diff --git a/code/modules/events/horror.dm b/code/modules/events/horror.dm
new file mode 100644
index 000000000000..72da216986a5
--- /dev/null
+++ b/code/modules/events/horror.dm
@@ -0,0 +1,37 @@
+/datum/round_event_control/horror
+ name = "Spawn Eldritch Horror"
+ typepath = /datum/round_event/ghost_role/horror
+ max_occurrences = 3
+ min_players = 15
+ earliest_start = 20 MINUTES
+
+/datum/round_event/ghost_role/horror
+ minimum_required = 1
+ role_name = "horror"
+ fakeable = FALSE
+
+/datum/round_event/ghost_role/horror/spawn_role()
+ var/list/candidates = get_candidates(ROLE_HORROR, null, ROLE_HORROR)
+ if(!candidates.len)
+ return NOT_ENOUGH_PLAYERS
+
+ var/mob/dead/selected = pick_n_take(candidates)
+
+ var/datum/mind/player_mind = new /datum/mind(selected.key)
+ player_mind.active = 1
+ if(!GLOB.generic_event_spawns)
+ return MAP_ERROR
+ var/mob/living/simple_animal/horror/S = new /mob/living/simple_animal/horror(get_turf(pick(GLOB.generic_event_spawns)))
+ var/datum/reagent/W = pick(/datum/reagent/water/holywater, /datum/reagent/consumable/garlic, /datum/reagent/consumable/ketchup, /datum/reagent/consumable/eggyolk, /datum/reagent/consumable/sodiumchloride, /datum/reagent/consumable/hot_ramen)
+ W = new W
+ S.weakness = W
+ player_mind.transfer_to(S)
+ player_mind.assigned_role = "Eldritch Horror"
+ player_mind.special_role = "Eldritch Horror"
+ player_mind.add_antag_datum(/datum/antagonist/horror)
+ to_chat(S, S.playstyle_string)
+ SEND_SOUND(S, sound('sound/hallucinations/growl2.ogg'))
+ message_admins("[ADMIN_LOOKUPFLW(S)] has been made into an eldritch horror by an event.")
+ log_game("[key_name(S)] was spawned as an eldritch horror by an event.")
+ spawned_mobs += S
+ return SUCCESSFUL_SPAWN
\ No newline at end of file
From 3a4ff49236e373a709607d4118c8cdbf8fa28d6f Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:48:40 +0200
Subject: [PATCH 03/76] Update horror.dm
---
code/modules/events/horror.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/modules/events/horror.dm b/code/modules/events/horror.dm
index 72da216986a5..cff8f4db0f75 100644
--- a/code/modules/events/horror.dm
+++ b/code/modules/events/horror.dm
@@ -1,7 +1,7 @@
/datum/round_event_control/horror
name = "Spawn Eldritch Horror"
typepath = /datum/round_event/ghost_role/horror
- max_occurrences = 3
+ max_occurrences = 0 //needs testing first
min_players = 15
earliest_start = 20 MINUTES
@@ -34,4 +34,4 @@
message_admins("[ADMIN_LOOKUPFLW(S)] has been made into an eldritch horror by an event.")
log_game("[key_name(S)] was spawned as an eldritch horror by an event.")
spawned_mobs += S
- return SUCCESSFUL_SPAWN
\ No newline at end of file
+ return SUCCESSFUL_SPAWN
From 85df09b6718b588a3c94b5f4d1e7c6d3c3ccc8d4 Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:50:29 +0200
Subject: [PATCH 04/76] Update role_preferences.dm
---
code/__DEFINES/role_preferences.dm | 2 ++
1 file changed, 2 insertions(+)
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index 3c4a3043527e..27e99baa6dde 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -45,6 +45,7 @@
#define ROLE_GANG "gangster" // Yogs
#define ROLE_DARKSPAWN "darkspawn" //Yogs
#define ROLE_HOLOPARASITE "Holoparasite" // Yogs
+#define ROLE_HORROR "Eldritch Horror" // Yogs
#define ROLE_ZOMBIE "Zombie"
@@ -63,6 +64,7 @@ GLOBAL_LIST_INIT(special_roles, list(
ROLE_MALF,
ROLE_REV = /datum/game_mode/revolution,
ROLE_ALIEN,
+ ROLE_HORROR,
ROLE_PAI,
ROLE_CULTIST = /datum/game_mode/cult,
ROLE_BLOB,
From e664833f1c1914859056603531375d778d08e0ce Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:51:27 +0200
Subject: [PATCH 05/76] Update sql_ban_system.dm
---
code/modules/admin/sql_ban_system.dm | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/code/modules/admin/sql_ban_system.dm b/code/modules/admin/sql_ban_system.dm
index 3480853aee8b..2d9c7b033784 100644
--- a/code/modules/admin/sql_ban_system.dm
+++ b/code/modules/admin/sql_ban_system.dm
@@ -266,10 +266,10 @@
break_counter++
output += ""
var/list/long_job_lists = list("Civilian" = GLOB.civilian_positions,
- "Ghost and Other Roles" = list(ROLE_BRAINWASHED, ROLE_DEATHSQUAD, ROLE_DRONE, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_LAVALAND, ROLE_MIND_TRANSFER, ROLE_POSIBRAIN, ROLE_SENTIENCE),
+ "Ghost and Other Roles" = list(ROLE_BRAINWASHED, ROLE_DEATHSQUAD, ROLE_DRONE, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_HORROR, ROLE_LAVALAND, ROLE_MIND_TRANSFER, ROLE_POSIBRAIN, ROLE_SENTIENCE),
"Antagonist Positions" = list(ROLE_ABDUCTOR, ROLE_ALIEN, ROLE_BLOB,
ROLE_BROTHER, ROLE_CHANGELING, ROLE_CULTIST,
- ROLE_DEVIL, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_INTERNAL_AFFAIRS, ROLE_MALF,
+ ROLE_DEVIL, ROLE_FUGITIVE, ROLE_HOLOPARASITE, ROLE_HORROR, ROLE_INTERNAL_AFFAIRS, ROLE_MALF,
ROLE_MONKEY, ROLE_NINJA, ROLE_OPERATIVE,
ROLE_OVERTHROW, ROLE_REV, ROLE_REVENANT,
ROLE_REV_HEAD, ROLE_SERVANT_OF_RATVAR, ROLE_SYNDICATE,
From e67e67aa03f160081ab2935ad1c3ae3dc129500d Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:52:33 +0200
Subject: [PATCH 06/76] Update death.dm
---
code/modules/mob/living/carbon/death.dm | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/code/modules/mob/living/carbon/death.dm b/code/modules/mob/living/carbon/death.dm
index 3a998a7d4a2b..61cb09bc23da 100644
--- a/code/modules/mob/living/carbon/death.dm
+++ b/code/modules/mob/living/carbon/death.dm
@@ -25,7 +25,10 @@
stomach_contents.Remove(M)
//yogs end
M.forceMove(Tsec)
- visible_message("[M] bursts out of [src]!")
+ if(ishorror(M)) //eldritch horror(aka. borer) check, they die along with their host to prevent mind controlled suicides
+ M.gib()
+ else
+ visible_message("[M] bursts out of [src]!")
..()
/mob/living/carbon/spill_organs(no_brain, no_organs, no_bodyparts)
From 67ea8c213fc45f4fee314d41c2390005b3c17165 Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:53:10 +0200
Subject: [PATCH 07/76] Add files via upload
---
code/modules/antagonists/horror/horror.dm | 880 ++++++++++++++++++
.../antagonists/horror/horror_chemicals.dm | 96 ++
.../antagonists/horror/horror_datums.dm | 678 ++++++++++++++
.../modules/antagonists/horror/horror_html.dm | 102 ++
.../antagonists/horror/horror_mutate.dm | 99 ++
5 files changed, 1855 insertions(+)
create mode 100644 code/modules/antagonists/horror/horror.dm
create mode 100644 code/modules/antagonists/horror/horror_chemicals.dm
create mode 100644 code/modules/antagonists/horror/horror_datums.dm
create mode 100644 code/modules/antagonists/horror/horror_html.dm
create mode 100644 code/modules/antagonists/horror/horror_mutate.dm
diff --git a/code/modules/antagonists/horror/horror.dm b/code/modules/antagonists/horror/horror.dm
new file mode 100644
index 000000000000..b34fcadf0092
--- /dev/null
+++ b/code/modules/antagonists/horror/horror.dm
@@ -0,0 +1,880 @@
+/mob/living/simple_animal/horror
+ name = "eldritch horror"
+ real_name = "eldritch horror"
+ desc = "Your eyes can barely comprehend what they're looking at."
+ icon_state = "horror"
+ icon_living = "horror"
+ icon_dead = "horror_dead"
+ health = 50
+ maxHealth = 50
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ see_in_dark = 7
+ stop_automated_movement = TRUE
+ attacktext = "bites"
+ speak_emote = list("gurgles")
+ attack_sound = 'sound/weapons/bite.ogg'
+ pass_flags = PASSTABLE | PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ faction = list("neutral","silicon","hostile","creature","heretics")
+ ventcrawler = VENTCRAWLER_ALWAYS
+ initial_language_holder = /datum/language_holder/universal
+ hud_type = /datum/hud/chemical_counter
+
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = 1500
+
+ var/playstyle_string = "You are an eldritch horror, an evermutating parasitic abomination. Seek human souls to consume. \
+ Crawl into people's heads and steal their essence. Use it to mutate yourself, giving you access to more power and abilities. \
+ You operate on chemicals that get built up while you spend time in someone's head. You are weak when outside, play carefully.\
+ Check your notes to see which chemical reagent is your bane, and avoid from getting in contact with it. "
+
+ var/datum/reagent/weakness = /datum/reagent/consumable/sugar //default is sugar, but a random one is attributed
+ var/mob/living/carbon/victim
+ var/datum/mind/target
+ var/mob/living/captive_brain/host_brain
+ var/truename = null
+ var/available_points = 4
+ var/consumed_souls = 0
+ var/list/horrorabilities = list() //An associative list ("id" = ability datum) containing the abilities the horror has
+ var/list/horrorupgrades = list() //same, but for permanent upgrades
+ var/docile = FALSE
+ var/bonding = FALSE
+ var/controlling = FALSE
+ var/chemicals = 10
+ var/chem_regen_rate = 2
+ var/used_freeze
+ var/used_target
+ var/horror_chems = list()
+
+ var/leaving = FALSE
+ var/hiding = FALSE
+ var/invisible = FALSE
+ var/waketimerid = null
+ var/datum/action/innate/horror/talk_to_horror/talk_to_horror_action = new
+
+/mob/living/simple_animal/horror/Initialize(mapload, gen=1)
+ ..()
+ real_name = "Eldritch horror"
+ truename = "[pick(GLOB.horror_names)]"
+
+ //default abilities
+ add_ability("mutate")
+ add_ability("seek_soul")
+ add_ability("consume_soul")
+ add_ability("locate_soul")
+ add_ability("talk_to_host")
+ add_ability("freeze_victim")
+ add_ability("infest")
+ add_ability("toggle_hide")
+ add_ability("talk_to_brain")
+ add_ability("take_control")
+ add_ability("leave_body")
+ add_ability("make_chems")
+ add_ability("talk_to_brain")
+ add_ability("release_control")
+
+ //starting chems, more are to be unlocked
+ horror_chems += list(/datum/horror_chem/epinephrine,/datum/horror_chem/mannitol,/datum/horror_chem/bicaridine,/datum/horror_chem/kelotane,/datum/horror_chem/charcoal)
+ var/datum/atom_hud/hud = GLOB.huds[DATA_HUD_MEDICAL_ADVANCED]
+ hud.add_hud_to(src)
+ update_horror_hud()
+
+
+/mob/living/simple_animal/horror/Destroy()
+ host_brain = null
+ victim = null
+ return ..()
+
+
+/mob/living/simple_animal/horror/proc/has_chemicals(amt)
+ return chemicals >= amt
+
+/mob/living/simple_animal/horror/proc/use_chemicals(amt)
+ if(!has_chemicals(amt))
+ return
+ chemicals -= amt
+ update_horror_hud()
+ return TRUE
+
+/mob/living/simple_animal/horror/proc/regenerate_chemicals(amt)
+ chemicals += amt
+ chemicals = min(250, chemicals)
+ update_horror_hud()
+
+/mob/living/simple_animal/horror/proc/update_horror_hud()
+ if(!src || !hud_used)
+ return
+ var/datum/hud/chemical_counter/H = hud_used
+ var/obj/screen/counter = H.chemical_counter
+ counter.maptext = "
[chemicals]
"
+
+/mob/living/simple_animal/horror/proc/can_use_ability()
+ if(stat != CONSCIOUS)
+ to_chat(src, "You cannot do that in your current state.")
+ return FALSE
+ if(docile)
+ to_chat(src, "You are feeling far too docile to do that.")
+ return FALSE
+ return TRUE
+
+/mob/living/simple_animal/horror/proc/SearchTarget()
+ if(world.time - used_target < 240)
+ to_chat(src, "You cannot use that ability again so soon.")
+ return
+ if(target)
+ if(alert("You already have a target ([target.name]). Would you like to change that target?","Swap targets?","Yes","No") != "Yes")
+ return
+ var/list/possible_targets = list()
+ //get crewmen minds
+ var/datum/mind/crew = list()
+ for(var/V in GLOB.data_core.locked)
+ var/datum/data/record/R = V
+ var/datum/mind/M = R.fields["mindref"]
+ if(M)
+ crew += M
+
+ for(var/datum/mind/possible_target in crew)
+ if(ishuman(possible_target.current) && (possible_target.current.stat != DEAD) && possible_target.hasSoul && possible_target != mind.enslaved_to.mind && possible_target != target) //checking if our target possesses a soul
+ possible_targets += possible_target
+
+ if(possible_targets.len > 0)
+ used_target = world.time
+ target = pick(possible_targets)
+ to_chat(src,"Your new target has been selected, go and consume [target.name]'s soul!")
+ else
+ to_chat(src,"A new target could not be found.")
+
+/mob/living/simple_animal/horror/proc/ConsumeSoul()
+ if(!can_use_ability())
+ return
+
+ if(!src.victim.mind.hasSoul)
+ to_chat(src, "This host doesn't have a soul!")
+ return
+
+ if(src.victim == src.mind.enslaved_to)
+ to_chat(src, "No, not yet...We still need them...")
+ return
+
+ if(src.victim.mind != src.target)
+ to_chat(src, "This soul isn't your target, you can't consume it!")
+ return
+
+ to_chat(src, "You begin consuming [src.victim.name]'s soul!")
+ addtimer(CALLBACK(src, .proc/consume), 200)
+
+/mob/living/simple_animal/horror/proc/consume()
+ if(!src.victim.mind.hasSoul)
+ return
+ src.consumed_souls++
+ src.available_points++
+ to_chat(src, "You succeed in consuming [victim.name]'s soul!")
+ to_chat(src.victim, "You suddenly feel hollow inside...")
+ src.victim.mind.hasSoul = FALSE
+ target = null
+ playsound(src, 'sound/effects/curseattack.ogg', 150)
+ playsound(src, 'sound/effects/ghost.ogg', 50)
+
+
+/mob/living/simple_animal/horror/proc/Locate()
+ if(stat != CONSCIOUS)
+ return
+ if(!target)
+ to_chat(src,"")
+ return
+
+ var/mob/living/carbon/T = target.current
+ var/dist = get_dist(src.loc,T.loc)
+ var/dir = get_dir(src.loc,T.loc)
+
+ if(src.z != T.z)
+ to_chat(src,"[T.name] is near you. They are to the [dir2text(dir)] of you!")
+ if(16 to 31)
+ to_chat(src,"[T.name] is somewhere in your vicinty. They are to the [dir2text(dir)] of you!")
+ if(32 to 127)
+ to_chat(src,"[T.name] is far away from you. They are to the [dir2text(dir)] of you!")
+ else
+ to_chat(src,"[T.name] is beyond our reach.")
+
+
+
+
+/mob/living/simple_animal/horror/proc/Communicate()
+ if(!can_use_ability())
+ return
+ if(!src.victim)
+ to_chat(src, "You do not have a host to communicate with!")
+ return
+
+ var/input = stripped_input(src, "Please enter a message to tell your host.", "Horror", null)
+ if(!input)
+ return
+
+ if(src && !QDELETED(src) && !QDELETED(src.victim))
+ var/say_string = (src.docile) ? "slurs" :"states"
+ if(src.victim)
+ to_chat(victim, "[truename] [say_string]: [input]")
+ log_say("Horror Communication: [key_name(src)] -> [key_name(victim)] : [input]")
+ for(var/M in GLOB.dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Horror Communication from [truename] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [rendered]")
+ to_chat(src, "[truename] [say_string]: [input]")
+ victim.verbs += /mob/living/proc/horror_comm
+ talk_to_horror_action.Grant(victim)
+
+/mob/living/proc/horror_comm()
+ set name = "Converse with Horror"
+ set category = "Horror"
+ set desc = "Communicate mentally with the thing in your head."
+
+
+ var/mob/living/simple_animal/horror/B = has_brain_worms()
+ if(!B)
+ return
+
+ var/input = stripped_input(src, "Please enter a message to tell the horror.", "Message", null)
+ if(!input)
+ return
+
+ to_chat(B, "[src] says: [input]")
+ log_say("Horror Communication: [key_name(src)] -> [key_name(B)] : [input]")
+
+ for(var/M in GLOB.dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Horror Communication from [src] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [rendered]")
+ to_chat(src, "[src] says: [input]")
+
+/mob/living/proc/trapped_mind_comm()
+ var/mob/living/simple_animal/horror/B = has_brain_worms()
+ if(!B || !B.host_brain)
+ return
+ var/mob/living/captive_brain/CB = B.host_brain
+ var/input = stripped_input(src, "Please enter a message to tell the trapped mind.", "Message", null)
+ if(!input)
+ return
+
+ to_chat(CB, "[B.truename] says: [input]")
+ log_say("Horror Communication: [key_name(B)] -> [key_name(CB)] : [input]")
+
+ for(var/M in GLOB.dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Horror Communication from [B] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ to_chat(M, "[link] [rendered]")
+ to_chat(src, "[B.truename] says: [input]")
+
+/mob/living/simple_animal/horror/Life()
+ ..()
+ if(horrorupgrades["regen"])
+ heal_overall_damage(5)
+
+ if(invisible) //don't regenerate chemicals when invisible
+ if(has_chemicals(5))
+ use_chemicals(5)
+ alpha = max(alpha - 100, 1)
+ else
+ to_chat(src, "You ran out of chemicals to support your invisibility.")
+ invisible = FALSE
+ Update_Invisibility_Button()
+ else
+ if(horrorupgrades["nohost_regen"])
+ regenerate_chemicals(chem_regen_rate)
+ else if(victim)
+ if(victim.stat == DEAD)
+ regenerate_chemicals(1)
+ else
+ regenerate_chemicals(chem_regen_rate)
+ alpha = min(255, alpha + 50)
+
+ if(victim)
+ if(stat != DEAD && victim.stat != DEAD)
+ heal_overall_damage(1)
+ if(victim.reagents.has_reagent(weakness.type))
+ if(!docile || waketimerid)
+ if(controlling)
+ to_chat(victim, "You feel the soporific flow of [weakness.name] in your host's blood, lulling you into docility.")
+ else
+ to_chat(src, "You feel the soporific flow of [weakness.name] in your host's blood, lulling you into docility.")
+ if(waketimerid)
+ deltimer(waketimerid)
+ waketimerid = null
+ docile = TRUE
+ else
+ if(docile && !waketimerid)
+ if(controlling)
+ to_chat(victim, "You start shaking off your lethargy as the [weakness.name] leaves your host's blood. This will take about 10 seconds...")
+ else
+ to_chat(src, "You start shaking off your lethargy as the [weakness.name] leaves your host's blood. This will take about 10 seconds...")
+
+ waketimerid = addtimer(CALLBACK(src, "wakeup"), 10, TIMER_STOPPABLE)
+ if(controlling)
+ if(docile)
+ to_chat(victim, "You are feeling far too docile to continue controlling your host...")
+ victim.release_control()
+ return
+
+
+/mob/living/simple_animal/horror/proc/wakeup()
+ if(controlling)
+ to_chat(victim, "You finish shaking off your lethargy.")
+ else
+ to_chat(src, "You finish shaking off your lethargy.")
+ docile = FALSE
+ if(waketimerid)
+ waketimerid = null
+
+/mob/living/simple_animal/horror/say(message)
+ if(victim)
+ to_chat(src, "You cannot speak out loud while inside a host!")
+ return
+ else
+ ..()
+
+/mob/living/simple_animal/horror/emote(var/message)
+ if(victim)
+ to_chat(src, "You cannot emote while inside a host!")
+ return
+ else
+ ..()
+
+/mob/living/simple_animal/horror/UnarmedAttack(atom/A)
+ if(isliving(A))
+ if(victim || A == src.mind.enslaved_to)
+ healthscan(usr, A)
+ chemscan(usr, A)
+ else
+ alpha = 255
+ invisible = FALSE
+ Update_Invisibility_Button()
+ ..()
+
+/mob/living/simple_animal/horror/ex_act()
+ if(victim)
+ return
+
+ ..()
+
+/mob/living/simple_animal/horror/proc/infect_victim()
+ if(!can_use_ability())
+ return
+ if(victim)
+ to_chat(src, "You are already within a host.")
+
+ if(stat == DEAD)
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/carbon/H in view(1,src))
+ if(H!=src && Adjacent(H))
+ choices += H
+
+ if(!choices.len)
+ return
+ var/mob/living/carbon/H = choices.len > 1 ? input(src,"Who do you wish to infest?") in null|choices : choices[1]
+ if(!H || !src)
+ return
+
+ if(!Adjacent(H))
+ return FALSE
+
+ if(H.has_brain_worms())
+ to_chat(src, "[victim] is already infested!")
+ return
+
+ to_chat(src, "You slither your tentacles up [H] and begin probing at their ear canal...")
+ if(!do_mob(src, H, 30))
+ to_chat(src, "As [H] moves away, you are dislodged and fall to the ground.")
+ return
+
+ if(!H || !src)
+ return
+
+ Infect(H)
+
+/mob/living/simple_animal/horror/proc/Infect(mob/living/carbon/C)
+
+ if(!C)
+ return
+ var/obj/item/bodypart/head/head = C.get_bodypart(BODY_ZONE_HEAD)
+ if(!head)
+ to_chat(src, "[C] doesn't have a head!")
+ return
+ var/hasbrain = FALSE
+ for(var/obj/item/organ/brain/X in C.internal_organs)
+ hasbrain = TRUE
+ break
+ if(!hasbrain)
+ to_chat(src, "[C] doesn't have a brain! ")
+ return
+
+ if(C.has_brain_worms())
+ to_chat(src, "[C] is already infested!")
+ return
+
+ if(!C.key || !C.mind)
+ to_chat(src, "[C]'s mind seems unresponsive. Try someone else!")
+ return
+
+ invisible = FALSE
+ Update_Invisibility_Button()
+ victim = C
+ forceMove(victim)
+
+ RefreshAbilities()
+
+ log_game("[src]/([src.ckey]) has infested [victim]/([victim.ckey]")
+
+/mob/living/simple_animal/horror/proc/secrete_chemicals()
+ if(!victim)
+ to_chat(src, "You are not inside a host body.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ var content = ""
+ content += "Chemicals: [chemicals]
"
+
+ content += ""
+
+ for(var/datum in horror_chems)
+ var/datum/horror_chem/C = new datum()
+ if(C.chemname)
+ content += "| [C.chemname] ([C.chemuse]) [C.chem_desc] |
"
+
+ content += "
"
+
+ var/html = get_html_template(content)
+
+ usr << browse(null, "window=ViewHorror\ref[src]Chems;size=600x800")
+ usr << browse(html, "window=ViewHorror\ref[src]Chems;size=600x800")
+
+ return
+
+/mob/living/simple_animal/horror/proc/hide()
+ if(victim)
+ to_chat(src, "You cannot do this while you're inside a host.")
+ return
+
+ if(stat != CONSCIOUS)
+ return
+
+ if(!hiding)
+ layer = LATTICE_LAYER
+ visible_message("[src] scurries to the ground!", \
+ "You are now hiding.")
+ hiding = TRUE
+ else
+ layer = MOB_LAYER
+ visible_message("[src] slowly peaks up from the ground...", \
+ "You stop hiding.")
+ hiding = FALSE
+
+/mob/living/simple_animal/horror/proc/go_invisible()
+ if(victim)
+ to_chat(src, "You cannot do this while you're inside a host.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ if(!has_chemicals(10))
+ to_chat(src, "You don't have enough chemicals to do that.")
+ return
+
+ if(!invisible)
+ to_chat(src, "You focus your chameleon skin to blend into the environment.")
+ invisible = TRUE
+ else
+ to_chat(src, "You stop your camouflage.")
+ invisible = FALSE
+
+/mob/living/simple_animal/horror/proc/freeze_victim()
+ if(world.time - used_freeze < 150)
+ to_chat(src, "You cannot use that ability again so soon.")
+ return
+
+ if(victim)
+ to_chat(src, "You cannot do that from within a host body.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/carbon/C in view(1,src))
+ if(C.stat == CONSCIOUS)
+ choices += C
+
+ if(!choices.len)
+ return
+ var/mob/living/carbon/M = choices.len > 1 ? input(src,"Who do you wish to stun?") in null|choices : choices[1]
+
+
+ if(!M || !src || stat != CONSCIOUS || victim || (world.time - used_freeze < 150))
+ return
+ if(!Adjacent(M))
+ return
+
+ layer = MOB_LAYER
+ if(horrorupgrades["paralysis"])
+ to_chat(src, "You whip your electrocharged tentacle at [M]'s leg and knock them down!")
+ playsound(loc, "sound/effects/sparks4.ogg", 30, 1, -1)
+ M.Stun(60)
+ M.Knockdown(80)
+ M.electrocute_act(15, src, 1, FALSE, FALSE, FALSE, 1, FALSE)
+ else
+ to_chat(src, "You whip your tentacle at [M]'s leg and knock them down!")
+ to_chat(M, "You feel something wrapping around your leg, pulling you down!")
+ playsound(loc, "sound/weapons/whipgrab.ogg", 30, 1, -1)
+ M.Stun(50)
+ M.Knockdown(70)
+ used_freeze = world.time
+
+/mob/living/simple_animal/horror/proc/release_victim()
+ if(!victim)
+ to_chat(src, "You are not inside a host body.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ if(leaving)
+ leaving = FALSE
+ to_chat(src, "You decide against leaving your host.")
+ return
+
+ to_chat(src, "You begin disconnecting from [victim]'s synapses and prodding at their internal ear canal.")
+
+ if(victim.stat != DEAD && !horrorupgrades["invisible_exit"])
+ to_chat(victim, "An odd, uncomfortable pressure begins to build inside your skull, behind your ear...")
+
+ leaving = TRUE
+
+ addtimer(CALLBACK(src, .proc/release_host), 100)
+
+/mob/living/simple_animal/horror/proc/release_host()
+ if(!victim || !src || QDELETED(victim) || QDELETED(src))
+ return
+ if(!leaving)
+ return
+ if(controlling)
+ return
+
+ if(stat != CONSCIOUS)
+ to_chat(src, "You cannot release your host in your current state.")
+ return
+
+ if(horrorupgrades["invisible_exit"])
+ alpha = 60
+ if(has_ability("chameleon"))
+ invisible = TRUE
+ Update_Invisibility_Button()
+ to_chat(src, "You silently wiggle out of [victim]'s ear and plop to the ground before vanishing via reflective solution that covers you.")
+ else
+ to_chat(src, "You wiggle out of [victim]'s ear and plop to the ground.")
+ if(victim.mind)
+ if(!horrorupgrades["invisible_exit"])
+ to_chat(victim, "Something slimy wiggles out of your ear and plops to the ground!")
+
+ leaving = FALSE
+
+ leave_victim()
+
+/mob/living/simple_animal/horror/proc/leave_victim()
+ if(!victim)
+ return
+
+ if(controlling)
+ detatch()
+
+ forceMove(get_turf(victim))
+
+ reset_perspective(null)
+ machine = null
+
+ victim.reset_perspective(null)
+ victim.machine = null
+
+ var/mob/living/V = victim
+ V.verbs -= /mob/living/proc/horror_comm
+ talk_to_horror_action.Remove(victim)
+
+ for(var/obj/item/horrortentacle/T in victim)
+ victim.visible_message("[victim]'s tentacle transforms back!", "Your tentacle disappears!")
+ playsound(victim, 'sound/effects/blobattack.ogg', 30, 1)
+ qdel(T)
+ victim = null
+
+ RefreshAbilities()
+ return
+
+/mob/living/simple_animal/horror/proc/jumpstart()
+ if(!victim)
+ to_chat(src, "You need a host to be able to use this.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ if(victim.stat != DEAD)
+ to_chat(src, "Your host is already alive!")
+ return
+
+ if(!has_chemicals(250))
+ to_chat(src, "You need 250 chemicals to use this!")
+ return
+
+ if(victim.stat == DEAD)
+ victim.tod = null
+ victim.setToxLoss(0)
+ victim.setOxyLoss(0)
+ victim.setCloneLoss(0)
+ victim.SetUnconscious(0)
+ victim.SetStun(0)
+ victim.SetKnockdown(0)
+ victim.radiation = 0
+ victim.heal_overall_damage(victim.getBruteLoss(), victim.getFireLoss())
+ victim.reagents.clear_reagents()
+ if(ishuman(victim))
+ var/mob/living/carbon/human/H = victim
+ H.restore_blood()
+ H.remove_all_embedded_objects()
+ victim.revive()
+ log_game("[src]/([src.ckey]) has revived [victim]/([victim.ckey]")
+ chemicals -= 250
+ to_chat(src, "You send a jolt of energy to your host, reviving them!")
+ victim.grab_ghost(force = TRUE) //brings the host back, no eggscape
+ to_chat(victim, "You bolt upright, gasping for breath!")
+
+/mob/living/simple_animal/horror/proc/view_memory()
+ if(!victim)
+ to_chat(src, "You need a host to be able to use this.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ if(victim.stat == DEAD)
+ to_chat(src, "Your host brain is unresponsive. They are dead!")
+ return
+
+ if(prob(20))
+ to_chat(victim, "You suddenly feel your memory being tangled with...")//chance to alert the victim
+
+ if(victim.mind)
+ var/datum/mind/suckedbrain = victim.mind
+ to_chat(src, "You skim through [victim]'s memories...[suckedbrain.memory]")
+ for(var/A in suckedbrain.antag_datums)
+ var/datum/antagonist/antag_types = A
+ var/list/all_objectives = antag_types.objectives.Copy()
+ if(antag_types.antag_memory)
+ to_chat(src, "[antag_types.antag_memory]")
+ if(LAZYLEN(all_objectives))
+ to_chat(src, "Objectives:")
+ var/obj_count = 1
+ for(var/O in all_objectives)
+ var/datum/objective/objective = O
+ to_chat(src, "Objective #[obj_count++]: [objective.explanation_text]")
+ var/list/datum/mind/other_owners = objective.get_owners() - suckedbrain
+ if(other_owners.len)
+ for(var/mind in other_owners)
+ var/datum/mind/M = mind
+ to_chat(src, "Conspirator: [M.name]")
+
+ var/list/recent_speech = list()
+ var/list/say_log = list()
+ var/log_source = victim.logging
+ for(var/log_type in log_source)
+ var/nlog_type = text2num(log_type)
+ if(nlog_type & LOG_SAY)
+ var/list/reversed = log_source[log_type]
+ if(islist(reversed))
+ say_log = reverseRange(reversed.Copy())
+ break
+ if(LAZYLEN(say_log))
+ for(var/spoken_memory in say_log)
+ if(recent_speech.len >= 5)//up to 5 random lines of speech, favoring more recent speech
+ break
+ if(prob(50))
+ recent_speech[spoken_memory] = say_log[spoken_memory]
+ if(recent_speech.len)
+ to_chat(src, "You catch some drifting memories of their past conversations...")
+ for(var/spoken_memory in recent_speech)
+ to_chat(src, "[recent_speech[spoken_memory]]")
+ var/mob/living/carbon/human/H = victim
+ var/datum/dna/the_dna = H.has_dna()
+ if(the_dna)
+ to_chat(src, "You uncover that [H.p_their()] true identity is [the_dna.real_name].")
+
+/mob/living/simple_animal/horror/proc/bond_brain()
+ if(!victim)
+ to_chat(src, "You are not inside a host body.")
+ return
+
+ if(!can_use_ability())
+ return
+
+ if(victim.stat == DEAD)
+ to_chat(src, "This host lacks enough brain function to control.")
+ return
+
+ if(bonding)
+ bonding = FALSE
+ to_chat(src, "You stop attempting to take control of your host.")
+ return
+
+ to_chat(src, "You begin delicately adjusting your connection to the host brain...")
+
+ if(QDELETED(src) || QDELETED(victim))
+ return
+
+ bonding = TRUE
+
+ var/delay = 200
+ if(horrorupgrades["fast_control"])
+ delay -= 120
+ addtimer(CALLBACK(src, .proc/assume_control), delay)
+
+/mob/living/simple_animal/horror/proc/assume_control()
+ if(!victim || !src || controlling || victim.stat == DEAD)
+ return
+ if(!bonding)
+ return
+ if(docile)
+ to_chat(src, "You are feeling far too docile to do that.")
+ bonding = FALSE
+ return
+ if(is_servant_of_ratvar(victim) || iscultist(victim))
+ to_chat(src, "[victim]'s mind seems to be blocked by some unknown force!")
+ bonding = FALSE
+ return
+ if(HAS_TRAIT(victim, TRAIT_MINDSHIELD))
+ to_chat(src, "[victim]'s mind seems to be shielded from your influence!")
+ bonding = FALSE
+ return
+ else
+ RegisterSignal(victim, COMSIG_MOB_APPLY_DAMAGE, .proc/hit_detatch)
+ log_game("[src]/([src.ckey]) assumed control of [victim]/([victim.ckey] with eldritch powers.")
+ to_chat(src, "You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.")
+ to_chat(victim, "You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.")
+
+ qdel(host_brain)
+ host_brain = new(src)
+ victim.mind.transfer_to(host_brain)
+
+ to_chat(host_brain, "You are trapped in your own mind. You feel that there must be a way to resist!")
+
+ mind.transfer_to(victim)
+
+ bonding = FALSE
+ controlling = TRUE
+
+ victim.verbs += /mob/living/carbon/proc/release_control
+ victim.verbs -= /mob/living/proc/horror_comm
+ victim.verbs += /mob/living/proc/trapped_mind_comm
+ talk_to_horror_action.Remove(victim)
+ GrantControlActions()
+
+ victim.med_hud_set_status()
+
+/mob/living/carbon/proc/release_control()
+ var/mob/living/simple_animal/horror/B = has_brain_worms()
+ if(B && B.host_brain)
+ to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]")
+ B.detatch()
+
+//Check for brain worms in head.
+/mob/proc/has_brain_worms()
+ for(var/I in contents)
+ if(ishorror(I))
+ return I
+ return FALSE
+
+/mob/living/simple_animal/horror/proc/hit_detatch()
+ if(victim.health <= 75)
+ detatch()
+ to_chat(src, "Upon taking damage, [victim]s brain detected danger, and hastily took over.")
+ to_chat(victim, "Your body is under attack, your brain immediately took over!")
+
+/mob/living/simple_animal/horror/proc/detatch()
+ if(!victim || !controlling)
+ return
+
+ controlling = FALSE
+ UnregisterSignal(victim, COMSIG_MOB_APPLY_DAMAGE)
+ victim.verbs -= /mob/living/carbon/proc/release_control
+ victim.verbs += /mob/living/proc/horror_comm
+ victim.verbs -= /mob/living/proc/trapped_mind_comm
+ RemoveControlActions()
+ RefreshAbilities()
+ talk_to_horror_action.Grant(victim)
+
+ victim.med_hud_set_status()
+
+ victim.mind.transfer_to(src)
+ if(host_brain)
+ host_brain.mind.transfer_to(victim)
+
+ log_game("[src]/([src.ckey]) released control of [victim]/([victim.ckey]")
+ qdel(host_brain)
+
+/mob/living/simple_animal/horror/proc/Update_Invisibility_Button()
+ var/datum/action/innate/horror/action = has_ability("chameleon")
+ if(action)
+ action.button_icon_state = "horror_sneak_[invisible ? "true" : "false"]"
+ action.UpdateButtonIcon()
+
+/mob/living/simple_animal/horror/proc/GrantHorrorActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("horror" in ability.category)
+ ability.Grant(src)
+
+/mob/living/simple_animal/horror/proc/RemoveHorrorActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("horror" in ability.category)
+ ability.Remove(src)
+
+/mob/living/simple_animal/horror/proc/GrantInfestActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("infest" in ability.category)
+ ability.Grant(src)
+
+/mob/living/simple_animal/horror/proc/RemoveInfestActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("infest" in ability.category)
+ ability.Remove(src)
+
+/mob/living/simple_animal/horror/proc/GrantControlActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("control" in ability.category)
+ ability.Grant(victim)
+
+/mob/living/simple_animal/horror/proc/RemoveControlActions()
+ for(var/A in horrorabilities)
+ var/datum/action/innate/horror/ability = horrorabilities[A]
+ if("control" in ability.category)
+ ability.Remove(victim)
+
+/mob/living/simple_animal/horror/proc/RefreshAbilities() //control abilities technically don't belong to horror
+ if(victim)
+ RemoveHorrorActions()
+ GrantInfestActions()
+ else
+ RemoveInfestActions()
+ GrantHorrorActions()
\ No newline at end of file
diff --git a/code/modules/antagonists/horror/horror_chemicals.dm b/code/modules/antagonists/horror/horror_chemicals.dm
new file mode 100644
index 000000000000..71b42fca9676
--- /dev/null
+++ b/code/modules/antagonists/horror/horror_chemicals.dm
@@ -0,0 +1,96 @@
+/mob/living/simple_animal/horror/Topic(href, href_list, hsrc)
+ if(href_list["horror_use_chem"])
+ locate(href_list["src"])
+ if(!istype(src, /mob/living/simple_animal/horror))
+ return
+
+ var/topic_chem = href_list["horror_use_chem"]
+ var/datum/horror_chem/C
+
+ for(var/datum in typesof(/datum/horror_chem))
+ var/datum/horror_chem/test = new datum()
+ if(test.chemname == topic_chem)
+ C = test
+ break
+
+ if(!istype(C, /datum/horror_chem))
+ return
+
+ if(!C || !victim || controlling || !src || stat)
+ return
+
+ if(!istype(C, /datum/horror_chem))
+ return
+
+ if(chemicals < C.chemuse)
+ to_chat(src, "You need [C.chemuse] chemicals stored to use this chemical!")
+ return
+
+ to_chat(src, "You squirt a measure of [C.chemname] from your reservoirs into [victim]'s bloodstream.")
+ victim.reagents.add_reagent(C.R, C.quantity)
+ chemicals -= C.chemuse
+ log_game("[src]/([src.ckey]) has injected [C.chemname] into their host [victim]/([victim.ckey])")
+
+ src << output(chemicals, "ViewHorror\ref[src]Chems.browser:update_chemicals")
+
+ ..()
+
+/datum/horror_chem
+ var/chemname
+ var/chem_desc = "This is a chemical"
+ var/datum/reagent/R
+ var/chemuse = 30
+ var/quantity = 10
+
+/datum/horror_chem/epinephrine
+ chemname = "epinephrine"
+ R = /datum/reagent/medicine/epinephrine
+ chem_desc = "Stabilizes critical condition and slowly restores oxygen damage."
+
+/datum/horror_chem/mannitol
+ chemname = "mannitol"
+ R = /datum/reagent/medicine/mannitol
+ chem_desc = "Heals brain damage."
+
+/datum/horror_chem/bicaridine
+ chemname = "bicaridine"
+ R = /datum/reagent/medicine/bicaridine
+ chem_desc = "Heals brute damage."
+
+/datum/horror_chem/kelotane
+ chemname = "kelotane"
+ R = /datum/reagent/medicine/kelotane
+ chem_desc = "Heals burn damage."
+
+/datum/horror_chem/charcoal
+ chemname = "charcoal"
+ R = /datum/reagent/medicine/charcoal
+ chem_desc = "Slowly heals toxin damage, while also slowly removing any other chemicals."
+
+/datum/horror_chem/adrenaline
+ chemname = "adrenaline"
+ R = /datum/reagent/medicine/changelingadrenaline
+ chemuse = 100
+ chem_desc = "Stimulates the brain, shrugging off effect of stuns while regenerating stamina."
+
+/datum/horror_chem/rezadone
+ chemname = "rezadone"
+ R = /datum/reagent/medicine/rezadone
+ chemuse = 50
+ chem_desc = "Heals cellular damage."
+
+/datum/horror_chem/pen_acid
+ chemname = "pentetic acid"
+ R = /datum/reagent/medicine/pen_acid
+ chemuse = 50
+ chem_desc = "Reduces massive amounts of radiation and toxin damage while purging other chemicals from the body."
+
+/datum/horror_chem/sal_acid
+ chemname = "salicyclic acid"
+ R = /datum/reagent/medicine/sal_acid
+ chem_desc = "Stimulates the healing of severe bruises. Rapidly heals severe bruising and slowly heals minor ones."
+
+/datum/horror_chem/oxandrolone
+ chemname = "oxandrolone"
+ R = /datum/reagent/medicine/oxandrolone
+ chem_desc = "Stimulates the healing of severe burns. Rapidly heals severe burns and slowly heals minor ones."
\ No newline at end of file
diff --git a/code/modules/antagonists/horror/horror_datums.dm b/code/modules/antagonists/horror/horror_datums.dm
new file mode 100644
index 000000000000..ad7efc06e116
--- /dev/null
+++ b/code/modules/antagonists/horror/horror_datums.dm
@@ -0,0 +1,678 @@
+//ANTAG DATUMS
+/datum/antagonist/horror
+ name = "Horror"
+ show_in_antagpanel = TRUE
+ prevent_roundtype_conversion = FALSE
+ show_name_in_check_antagonists = TRUE
+ show_to_ghosts = TRUE
+ var/datum/mind/summoner
+
+/datum/antagonist/horror/on_gain()
+ . = ..()
+ give_objectives()
+ if(ishorror(owner) && owner.current.mind)
+ var/mob/living/simple_animal/horror/H = owner.current
+ H.update_horror_hud()
+ H.mind.store_memory("You become docile after contact with [H.weakness.name]. Avoid it.")
+
+/datum/antagonist/horror/proc/give_objectives()
+ var/datum/objective/survive/survive = new
+ survive.owner = owner
+ objectives += survive
+ if(summoner)
+ var/datum/objective/newobjective = new
+ newobjective.explanation_text = "Serve your summoner, [summoner.name]."
+ newobjective.owner = owner
+ objectives += newobjective
+ else
+ var/datum/objective/horrorascend/ascend = new
+ ascend.owner = owner
+ objectives += ascend
+
+/datum/objective/horrorascend
+ explanation_text = "Consume 10 souls."
+
+/datum/objective/horrorascend/check_completion()
+ var/mob/living/simple_animal/horror/H = owner.current
+ if(istype(H) && H.consumed_souls > 10)
+ return TRUE
+ return FALSE
+
+//SPAWNER
+/obj/item/horrorspawner
+ name = "suspicious pet carrier"
+ desc = "It contains some sort of creature inside. You can see tentacles sticking out of it."
+ icon = 'icons/obj/pet_carrier.dmi'
+ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ item_state = "pet_carrier"
+ icon_state = "pet_carrier_occupied"
+ var/used = FALSE
+ var/weakness
+ color = rgb(130, 105, 160)
+
+/obj/item/horrorspawner/attack_self(mob/living/user)
+ if(used)
+ to_chat(user, "The pet carrier appears unresponsive.")
+ return
+ used = TRUE
+ to_chat(user, "You're attempting to wake up the creature inside the box...")
+ sleep(5 SECONDS)
+ var/list/mob/dead/observer/candidates = pollGhostCandidates("Do you want to play as the eldritch horror in service of [user.real_name]?", ROLE_HORROR, null, FALSE, 100)
+ if(LAZYLEN(candidates))
+ var/mob/dead/observer/C = pick(candidates)
+ var/mob/living/simple_animal/horror/H = new /mob/living/simple_animal/horror(get_turf(src))
+ H.weakness = weakness
+ H.key = C.key
+ H.mind.enslave_mind_to_creator(user)
+ H.mind.add_antag_datum(C)
+ H.mind.memory += "You are [H.truename], an eldritch horror. Consume souls to evolve.
"
+ var/datum/antagonist/horror/S = new
+ S.summoner = user.mind
+ S.antag_memory += "[user.mind] woke you from your eternal slumber. Aid them in their objectives as a token of gratitude.
"
+ H.mind.add_antag_datum(S)
+ log_game("[key_name(user)] has summoned [key_name(H)], an eldritch horror.")
+ to_chat(user, "[H.truename] has awoken into your service!")
+ used = TRUE
+ icon_state = "pet_carrier_open"
+ sleep(5)
+ var/obj/item/horrorsummonhorn/horn = new /obj/item/horrorsummonhorn(get_turf(src))
+ horn.summoner = user.mind
+ horn.horror = H
+ to_chat(user, "A strange looking [horn] falls out of [src]!")
+ else
+ to_chat(user, "The creatures looks at you with one of it's eyes before going back to slumber.")
+ used = FALSE
+ return
+
+//Summoning horn
+/obj/item/horrorsummonhorn
+ name = "old horn"
+ desc = "A very old horn. You feel an incredible urge to blow into it."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ lefthand_file = 'icons/mob/inhands/items_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/items_righthand.dmi'
+ item_state = "horn"
+ icon_state = "horn"
+ var/datum/mind/summoner
+ var/mob/living/simple_animal/horror/horror
+ var/cooldown
+
+/obj/item/horrorsummonhorn/examine(mob/user)
+ . = ..()
+ if(user.mind == summoner)
+ to_chat(user, "Blowing into this horn will recall the horror back to you. Be wary, the horn is loud, and may attract unwanted attention.")
+
+/obj/item/horrorsummonhorn/attack_self(mob/living/user)
+ if(cooldown > world.time)
+ to_chat(user, "Take a breath before you blow [src] again.")
+ return
+ to_chat(user, "You take a deep breath and prepare to blow into [src]...")
+ if(do_mob(user, src, 100))
+ if(cooldown > world.time)
+ return
+ cooldown = world.time + 5 SECONDS
+ to_chat(src, "You blow the horn...")
+ playsound(loc, "sound/items/airhorn.ogg", 100, 1, 30)
+ var/turf/summonplace = get_turf(src)
+ sleep(5 SECONDS)
+ if(prob(20)) //yeah you're summoning an eldritch horror allright
+ new /obj/effect/temp_visual/summon(summonplace)
+ sleep(10)
+ var/type = pick(typesof(/mob/living/simple_animal/hostile/abomination))
+ var/mob/R = new type(summonplace)
+ playsound(summonplace, "sound/effects/phasein.ogg", 30)
+ summonplace.visible_message("[R] emerges!")
+ else
+ if(!horror || horror.stat == DEAD)
+ summonplace.visible_message("But nothing responds to the call!")
+ else
+ new /obj/effect/temp_visual/summon(summonplace)
+ sleep(10)
+ horror.leave_victim()
+ horror.forceMove(summonplace)
+ playsound(summonplace, "sound/effects/phasein.ogg", 30)
+ summonplace.visible_message("[horror] appears out of nowhere!")
+ if(user.mind != summoner)
+ sleep(2 SECONDS)
+ playsound(summonplace, "sound/effects/glassbr2.ogg", 30, 1)
+ to_chat(user, "[src] breaks!")
+ qdel(src)
+
+/obj/item/pickaxe/suicide_act(mob/living/user) //"I am the prettiest unicorn that ever was!" ~Spy 2013
+ user.visible_message("[user] stabs [user.p_their()] forehead with [src]! It looks like [user.p_theyre()] trying to commit suicide!")
+ return BRUTELOSS
+
+/obj/item/paper/crumpled/horrorweakness
+ name = "scruffed note"
+ infolang = /datum/language/aphasia //his previous owner got brought to madness, luckily curator can translate
+
+/obj/item/horrortentacle
+ name = "tentacle"
+ desc = "A long, slimy, arm-like appendage."
+ icon = 'icons/obj/items_and_weapons.dmi'
+ icon_state = "horrortentacle"
+ item_state = "tentacle"
+ lefthand_file = 'icons/mob/inhands/antag/horror_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/antag/horror_righthand.dmi'
+ resistance_flags = ACID_PROOF
+ force = 17
+ item_flags = ABSTRACT | DROPDEL
+ reach = 2
+ hitsound = 'sound/weapons/whip.ogg'
+
+/obj/item/horrortentacle/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, ABSTRACT_ITEM_TRAIT)
+
+/obj/item/horrortentacle/examine(mob/user)
+ . = ..()
+ to_chat(user, "Functions:")
+ to_chat(user, "All attacks work up to 2 tiles away.")
+ to_chat(user, "Help intent: Usual help function of an arm.")
+ to_chat(user, "Disarm intent: Whips the tentacle, disarming your opponent.")
+ to_chat(user, "Grab intent: Instant aggressive grab on an opponent. Can also throw them!")
+ to_chat(user, "Harm intent: Whips the tentacle, damaging your opponent.")
+ to_chat(user, "Also functions to pry open unbolted airlocks.")
+
+/obj/item/horrortentacle/attack(atom/target, mob/living/user)
+ if(isliving(target))
+ user.Beam(target,"purpletentacle",time=5)
+ var/mob/living/L = target
+ switch(user.a_intent)
+ if(INTENT_HELP)
+ L.attack_hand(user)
+ return
+ if(INTENT_GRAB)
+ if(L != user)
+ L.grabbedby(user)
+ L.grippedby(user, instant = TRUE)
+ L.Knockdown(30)
+ return
+ if(INTENT_DISARM)
+ if(iscarbon(L))
+ var/mob/living/carbon/C = L
+ var/obj/item/I = C.get_active_held_item()
+ if(I)
+ if(C.dropItemToGround(I))
+ playsound(loc, "sound/weapons/whipgrab.ogg", 30)
+ target.visible_message("[I] is whipped out of [C]'s hand by [user]!","A tentacle whips [I] out of your hand!")
+ return
+ else
+ to_chat(user, "You can't seem to pry [I] off [C]'s hands!")
+ return
+ else
+ C.attack_hand(user)
+ return
+ . = ..()
+
+/obj/item/horrortentacle/afterattack(atom/target, mob/user, proximity)
+ if(isliving(user.pulling) && user.pulling != target)
+ var/mob/living/H = user.pulling
+ user.visible_message("[user] throws [H] with [user.p_their()] [src]!", "You throw [H] with [src].")
+ H.throw_at(target, 8, 2)
+ H.Knockdown(30)
+ return
+ if(!proximity)
+ return
+ if(istype(target, /obj/machinery/door/airlock))
+ var/obj/machinery/door/airlock/A = target
+
+ if((!A.requiresID() || A.allowed(user)) && A.hasPower())
+ return
+ if(A.locked)
+ to_chat(user, "The airlock's bolts prevent it from being forced!")
+ return
+
+ if(A.hasPower())
+ user.visible_message("[user] jams [src] into the airlock and starts prying it open!", "You start forcing the airlock open.",
+ "You hear a metal screeching sound.")
+ playsound(A, 'sound/machines/airlock_alien_prying.ogg', 150, 1)
+ if(!do_after(user, 150, target = A)) //tentacle 50% worse than an armblade
+ return
+ user.visible_message("[user] forces the airlock to open with [user.p_their()] [src]!", "You force the airlock to open.",
+ "You hear a metal screeching sound.")
+ A.open(2)
+ return
+ . = ..()
+
+/obj/item/horrortentacle/suicide_act(mob/user) //funnily enough, this will never be called, since horror stops suicide
+ user.visible_message("[src] coils itself around [user] tightly gripping [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!")
+ return (OXYLOSS)
+
+//ABILITIES
+
+/datum/action/innate/horror
+ background_icon_state = "bg_ecult"
+ icon_icon = 'icons/mob/actions/actions_horror.dmi'
+ var/id //The ability's ID, for giving, taking and such
+ var/blacklisted = FALSE //If the ability can't be mutated
+ var/soul_price = 0 //How much souls the ability costs to buy; if this is 0, it isn't listed on the catalog
+ var/chemical_cost = 0 //How much chemicals the ability costs to use
+ var/mob/living/simple_animal/horror/B //Horror holding the ability
+ var/category //category for when the ability is active, "horror" is for creature, "infest" is during infestation, "controlling" is when a horror is controlling a body
+
+/datum/action/innate/horror/New(Target, horror)
+ B = horror
+ ..()
+
+/datum/action/innate/horror/mutate
+ name = "Mutate"
+ id = "mutate"
+ desc = "Use consumed souls to mutate your abilities."
+ button_icon_state = "mutate"
+ blacklisted = TRUE
+ category = list("horror","infest")
+
+/datum/action/innate/horror/mutate/Activate()
+ to_chat(usr, "You focus on mutating your body...")
+ B.ui_interact(usr)
+ return TRUE
+
+/datum/action/innate/horror/seek_soul
+ name = "Seek target soul"
+ id = "seek_soul"
+ desc = "Search for a soul weak enough for you to consume."
+ button_icon_state = "seek_soul"
+ blacklisted = TRUE
+ category = list("horror","infest")
+
+/datum/action/innate/horror/seek_soul/Activate()
+ B.SearchTarget()
+
+/datum/action/innate/horror/consume_soul
+ name = "Consume soul"
+ id = "consume_soul"
+ desc = "Consume your target's soul."
+ button_icon_state = "consume_soul"
+ blacklisted = TRUE
+ category = list("infest")
+
+/datum/action/innate/horror/consume_soul/Activate()
+ B.ConsumeSoul()
+
+/datum/action/innate/horror/locate_soul
+ name = "Locate Soul"
+ id = "locate_soul"
+ desc = "Locate the whereabouts of your target."
+ button_icon_state = "locate_soul"
+ blacklisted = TRUE
+ category = list("horror","infest")
+
+/datum/action/innate/horror/locate_soul/Activate()
+ B.Locate()
+
+/datum/action/innate/horror/talk_to_host
+ name = "Converse with Host"
+ id = "talk_to_host"
+ desc = "Send a silent message to your host."
+ button_icon_state = "talk_to_host"
+ blacklisted = TRUE
+ category = list("infest")
+
+/datum/action/innate/horror/talk_to_host/Activate()
+ B.Communicate()
+
+/datum/action/innate/horror/infest_host
+ name = "Infest"
+ id = "infest"
+ desc = "Infest a suitable humanoid host."
+ button_icon_state = "infest"
+ blacklisted = TRUE
+ category = list("horror")
+
+/datum/action/innate/horror/infest_host/Activate()
+ B.infect_victim()
+
+/datum/action/innate/horror/toggle_hide
+ name = "Toggle Hide"
+ id = "toggle_hide"
+ desc = "Become invisible to the common eye. Toggled on or off."
+ button_icon_state = "horror_hiding_false"
+ blacklisted = TRUE
+ category = list("horror")
+
+/datum/action/innate/horror/toggle_hide/Activate()
+ B.hide()
+ button_icon_state = "horror_hiding_[B.hiding ? "true" : "false"]"
+ UpdateButtonIcon()
+
+/datum/action/innate/horror/talk_to_horror
+ name = "Converse with Horror"
+ id = "talk_to_horror"
+ desc = "Communicate mentally with your horror."
+ button_icon_state = "talk_to_horror"
+ blacklisted = TRUE
+
+/datum/action/innate/horror/talk_to_horror/Activate()
+ B.victim.horror_comm()
+
+/datum/action/innate/horror/talk_to_brain
+ name = "Converse with Trapped Mind"
+ id = "talk_to_brain"
+ desc = "Communicate mentally with the trapped mind of your host."
+ button_icon_state = "talk_to_trapped_mind"
+ blacklisted = TRUE
+ category = list("control")
+
+/datum/action/innate/horror/talk_to_brain/Activate()
+ B.victim.trapped_mind_comm()
+
+/datum/action/innate/horror/take_control
+ name = "Assume Control"
+ id = "take_control"
+ desc = "Fully connect to the brain of your host."
+ button_icon_state = "horror_brain"
+ blacklisted = TRUE
+ category = list("infest")
+
+/datum/action/innate/horror/take_control/Activate()
+ B.bond_brain()
+
+/datum/action/innate/horror/give_back_control
+ name = "Release Control"
+ id = "release_control"
+ desc = "Release control of your host's body."
+ button_icon_state = "horror_leave"
+ blacklisted = TRUE
+ category = list("control")
+
+/datum/action/innate/horror/give_back_control/Activate()
+ B.victim.release_control()
+
+/datum/action/innate/horror/leave_body
+ name = "Release Host"
+ id = "leave_body"
+ desc = "Slither out of your host."
+ button_icon_state = "horror_leave"
+ blacklisted = TRUE
+ category = list("infest")
+
+/datum/action/innate/horror/leave_body/Activate()
+ B.release_victim()
+
+/datum/action/innate/horror/make_chems
+ name = "Secrete chemicals"
+ id = "make_chems"
+ desc = "Push some chemicals into your host's bloodstream."
+ icon_icon = 'icons/obj/chemical.dmi'
+ button_icon_state = "minidispenser"
+ blacklisted = TRUE
+ category = list("infest")
+
+/datum/action/innate/horror/make_chems/Activate()
+ B.secrete_chemicals()
+
+/datum/action/innate/horror/freeze_victim
+ name = "Knockdown victim"
+ id = "freeze_victim"
+ desc = "Use your tentacle to trip a victim, stunning for a short duration."
+ button_icon_state = "trip"
+ blacklisted = TRUE
+ category = list("horror")
+
+/datum/action/innate/horror/freeze_victim/Activate()
+ B.freeze_victim()
+ UpdateButtonIcon()
+ addtimer(CALLBACK(src, .proc/UpdateButtonIcon), 150)
+
+/datum/action/innate/horror/freeze_victim/IsAvailable()
+ if(world.time - B.used_freeze < 150)
+ return FALSE
+ else
+ return ..()
+
+//non-default abilities, can be mutated
+
+/datum/action/innate/horror/tentacle
+ name = "Grow Tentacle"
+ id = "tentacle"
+ desc = "Makes your host grow a tentacle in their arm. Costs 50 chemicals to activate."
+ button_icon_state = "tentacle"
+ category = list("infest", "control")
+ soul_price = 2
+
+/datum/action/innate/horror/tentacle/IsAvailable()
+ if(!active && !B.has_chemicals(50))
+ return FALSE
+ return ..()
+
+/datum/action/innate/horror/tentacle/New()
+ ..()
+ START_PROCESSING(SSfastprocess, src)
+
+/datum/action/innate/horror/tentacle/Destroy()
+ STOP_PROCESSING(SSfastprocess, src)
+ return ..()
+
+/datum/action/innate/horror/tentacle/process()
+ ..()
+ active = locate(/obj/item/horrortentacle) in B.victim
+ UpdateButtonIcon()
+
+
+/datum/action/innate/horror/tentacle/Activate()
+ B.use_chemicals(50)
+ B.victim.visible_message("[B.victim]'s arm contorts into tentacles!", "Your arm transforms into a giant tentacle. Examine it to see possible uses.")
+ playsound(B.victim, 'sound/effects/blobattack.ogg', 30, 1)
+ to_chat(B, "You transform [B.victim]'s arm into a tentacle!")
+ var/obj/item/horrortentacle/T = new
+ B.victim.put_in_hands(T)
+ return TRUE
+
+/datum/action/innate/horror/tentacle/Deactivate()
+ B.victim.visible_message("[B.victim]'s tentacle transforms back!", "Your tentacle disappears!")
+ playsound(B.victim, 'sound/effects/blobattack.ogg', 30, 1)
+ to_chat(B, "You transform [B.victim]'s arm back.")
+ for(var/obj/item/horrortentacle/T in B.victim)
+ qdel(T)
+ return TRUE
+
+/datum/action/innate/horror/jumpstart_host
+ name = "Revive Host"
+ id = "jumpstart_host"
+ desc = "Bring your host back to life."
+ button_icon_state = "revive"
+ category = list("infest")
+ soul_price = 2
+
+/datum/action/innate/horror/jumpstart_host/Activate()
+ B.jumpstart()
+
+/datum/action/innate/horror/view_memory
+ name = "View Memory"
+ id = "view_memory"
+ desc = "Read recent memory of the host you're inside of."
+ button_icon_state = "view_memory"
+ category = list("infest")
+ soul_price = 1
+
+/datum/action/innate/horror/view_memory/Activate()
+ B.view_memory()
+
+/datum/action/innate/horror/chameleon
+ name = "Chameleon Skin"
+ id = "chameleon"
+ desc = "Adjust your skin color to blend into environment. Costs 5 chemicals per tick, also stopping chemical regeneration while active. Attacking stops the invisibility completely."
+ button_icon_state = "horror_sneak_false"
+ category = list("horror")
+ soul_price = 1
+
+/datum/action/innate/horror/chameleon/Activate()
+ B.go_invisible()
+ button_icon_state = "horror_sneak_[B.invisible ? "true" : "false"]"
+ UpdateButtonIcon()
+
+//UPGRADES
+/datum/horror_upgrade
+ var/name = "horror upgrade"
+ var/desc = "This is an upgrade."
+ var/id
+ var/soul_price = 0 //How much souls an upgrade costs to buy
+ var/mob/living/simple_animal/horror/B //Horror holding the upgrades
+
+/datum/horror_upgrade/proc/unlock()
+ if(!B)
+ return
+ apply_effects()
+ qdel(src)
+ return TRUE
+
+/datum/horror_upgrade/New(owner)
+ ..()
+ B = owner
+
+/datum/horror_upgrade/proc/apply_effects()
+ return
+
+//Upgrades the stun ability
+/datum/horror_upgrade/paralysis
+ name = "Electrocharged tentacle"
+ id = "paralysis"
+ desc = "Empowers your tentacle knockdown ability by giving it extra charge, knocking your victim down unconcious."
+ soul_price = 3
+
+/datum/horror_upgrade/paralysis/apply_effects()
+ var/datum/action/innate/horror/A = B.has_ability("freeze_victim")
+ if(A)
+ A.name = "Paralyze Victim"
+ A.desc = "Shock a victim with an electrically charged tentacle."
+ A.button_icon_state = "paralyze"
+ B.update_action_buttons()
+
+//Increases chemical regeneration rate by 2
+/datum/horror_upgrade/chemical_regen
+ name = "Efficient chemical glands"
+ id = "chem_regen"
+ desc = "Your chemical glands work more efficiently. Unlocking this increases your chemical regeneration."
+ soul_price = 3
+
+/datum/horror_upgrade/chemical_regen/apply_effects()
+ B.chem_regen_rate += 2
+
+//Lets horror regenerate chemicals outside of a host
+/datum/horror_upgrade/nohost_regen
+ name = "Independent chemical glands"
+ id = "nohost_regen"
+ desc = "Your chemical glands become less parasitic and let you regenerate chemicals on their own without need for a host."
+ soul_price = 2
+
+//Lets horror regenerate health
+/datum/horror_upgrade/regen
+ name = "Regenerative skin"
+ id = "regen"
+ desc = "Your skin adapts to sustained damage and slowly regenerates itself, healing your wounds over time."
+ soul_price = 1
+
+//Triples horror's health pool
+/datum/horror_upgrade/hp_up
+ name = "Rhino skin" //Horror can....roll?
+ id = "hp_up"
+ desc = "Your skin becomes hard as rock, greatly increasing your maximum health - and odds of survival outside of host."
+ soul_price = 2
+
+/datum/horror_upgrade/hp_up/apply_effects()
+ B.health = round(min(B.maxHealth,B.health * 3))
+ B.maxHealth = round(B.maxHealth * 3)
+
+//Makes horror almost invisible for a short time after leaving a host
+/datum/horror_upgrade/invisibility
+ name = "Reflective fluids"
+ id = "invisible_exit"
+ desc = "You build up reflective solution inside host's brain. Upon exiting a host, you're briefly covered in it, rendering you near invisible for a few seconds. This mutation also makes the host unable to notice you exiting it directly."
+ soul_price = 2
+
+//Increases melee damage to 20
+/datum/horror_upgrade/dmg_up
+ name = "Sharpened teeth"
+ id = "dmg_up"
+ desc = "Your teeth become sharp blades, this mutation increases your melee damage."
+ soul_price = 2
+
+/datum/horror_upgrade/dmg_up/apply_effects()
+ B.attacktext = "crunches"
+ B.attack_sound = 'sound/weapons/pierce_slow.ogg' //chunky
+ B.melee_damage_lower += 10
+ B.melee_damage_upper += 10
+
+//Expands the reagent selection horror can make
+/datum/horror_upgrade/upgraded_chems
+ name = "Advanced reagent synthesis"
+ id = "upgraded_chems"
+ desc = "Lets you synthetize adrenaline, salicyclic acid, oxandrolone, pentetic acid and rezadone into your host."
+ soul_price = 2
+
+/datum/horror_upgrade/upgraded_chems/apply_effects()
+ B.horror_chems += list(/datum/horror_chem/adrenaline,/datum/horror_chem/sal_acid,/datum/horror_chem/oxandrolone,/datum/horror_chem/pen_acid,/datum/horror_chem/rezadone)
+
+//faster mind control
+/datum/horror_upgrade/fast_control
+ name = "Precise probosci"
+ id = "fast_control"
+ desc = "Your probosci become more precise, allowing you to take control over your host's brain noticably faster."
+ soul_price = 2
+
+//makes it longer for host to snap out of mind control
+/datum/horror_upgrade/deep_control
+ name = "Insulated probosci"
+ id = "deep_control"
+ desc = "Your probosci become insulated, protecting them from neural shocks. This makes it harder for the host to regain control over their body."
+ soul_price = 2
+
+
+//TRAPPED MIND - when horror takes control over your body, you become a mute trapped mind
+/mob/living/captive_brain
+ name = "host brain"
+ real_name = "host brain"
+
+/mob/living/captive_brain/say(var/message)
+
+ if(client)
+ if(client.prefs.muted & MUTE_IC)
+ to_chat(src, "You cannot speak in IC (muted).")
+ return
+ if(client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ if(ishorror(loc))
+ message = sanitize(message)
+ if(!message)
+ return
+ log_say("[key_name(src)] : [message]")
+ if(stat == 2)
+ return say_dead(message)
+
+ var/mob/living/simple_animal/horror/B = loc
+ to_chat(src, "You whisper silently, \"[message]\"")
+ to_chat(B.victim, "The captive mind of [src] whispers, \"[message]\"")
+
+ for (var/mob/M in GLOB.player_list)
+ if(isnewplayer(M))
+ continue
+ else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
+ to_chat(M, "Thought-speech, [src] -> [B.truename]: [message]")
+
+/mob/living/captive_brain/emote(var/message)
+ return
+
+/mob/living/captive_brain/resist()
+
+ var/mob/living/simple_animal/horror/B = loc
+ var/delay = rand(50,150)
+ if(B.victim == B.mind.enslaved_to)
+ delay = 10
+ if(B.horrorupgrades["deep_control"]) //yes, longer control also affects our master
+ delay += rand(50,150)
+ to_chat(src, "You begin doggedly resisting the parasite's control.")
+ to_chat(B.victim, "You feel the captive mind of [src] begin to resist your control.")
+
+
+ addtimer(CALLBACK(src, .proc/return_control, src.loc), delay)
+
+/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/horror/B)
+ if(!B || !B.controlling)
+ return
+
+ to_chat(src, "With an immense exertion of will, you regain control of your body!")
+ to_chat(B.victim, "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.")
+ B.detatch()
\ No newline at end of file
diff --git a/code/modules/antagonists/horror/horror_html.dm b/code/modules/antagonists/horror/horror_html.dm
new file mode 100644
index 000000000000..4f70c856805d
--- /dev/null
+++ b/code/modules/antagonists/horror/horror_html.dm
@@ -0,0 +1,102 @@
+/mob/living/simple_animal/horror/proc/get_html_template(content)
+ var/html = {"
+
+
+ Horror Chemicals
+
+
+
+
+
+
+
+
+
+ [content]
+
"}
+ return html
\ No newline at end of file
diff --git a/code/modules/antagonists/horror/horror_mutate.dm b/code/modules/antagonists/horror/horror_mutate.dm
new file mode 100644
index 000000000000..8c48fd808d99
--- /dev/null
+++ b/code/modules/antagonists/horror/horror_mutate.dm
@@ -0,0 +1,99 @@
+// Horror mutation menu
+// Totally not a copypaste of darkspawn menu, not a copypaste of cellular emporium, i swear.
+
+/mob/living/simple_animal/horror/proc/has_ability(id)
+ if(isnull(horrorabilities[id]))
+ return
+ return horrorabilities[id]
+
+/mob/living/simple_animal/horror/proc/add_ability(id)
+ if(has_ability(id))
+ return
+ for(var/V in subtypesof(/datum/action/innate/horror))
+ var/datum/action/innate/horror/H = V
+ if(initial(H.id) == id)
+ var/datum/action/innate/horror/action = new H(null, src)
+ horrorabilities[id] = action
+ action.B = src
+ RefreshAbilities()
+ to_chat(src, "You have mutated the [action.name].")
+ available_points = max(0, available_points - action.soul_price)
+ return TRUE
+
+/mob/living/simple_animal/horror/proc/has_upgrade(id)
+ return horrorupgrades[id]
+
+/mob/living/simple_animal/horror/proc/add_upgrade(id)
+ if(has_upgrade(id))
+ return
+ for(var/V in subtypesof(/datum/horror_upgrade))
+ var/datum/horror_upgrade/_U = V
+ if(initial(_U.id) == id)
+ var/datum/horror_upgrade/U = new _U(src)
+ horrorupgrades[id] = TRUE
+ to_chat(src, "You have adapted the \"[U.name]\" upgrade.")
+ available_points = max(0, available_points - U.soul_price)
+ U.unlock()
+
+//mutation menu, 100% ripoff of psiweb, pls don't sue
+
+/mob/living/simple_animal/horror/ui_state(mob/user)
+ return GLOB.always_state
+
+/mob/living/simple_animal/horror/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "HorrorMutate", "Horror Mutation")
+ ui.open()
+
+/mob/living/simple_animal/horror/ui_data(mob/user)
+ var/list/data = list()
+
+ data["available_points"] = "[available_points] | [consumed_souls] consumed souls total"
+
+ var/list/abilities = list()
+ var/list/upgrades = list()
+
+ for(var/path in subtypesof(/datum/action/innate/horror))
+ var/datum/action/innate/horror/ability = path
+
+ if(initial(ability.blacklisted))
+ continue
+
+ var/list/AL = list()
+ AL["name"] = initial(ability.name)
+ AL["id"] = initial(ability.id)
+ AL["desc"] = initial(ability.desc)
+ AL["soul_cost"] = initial(ability.soul_price)
+ AL["owned"] = has_ability(initial(ability.id))
+ AL["can_purchase"] = !AL["owned"] && available_points >= initial(ability.soul_price)
+
+ abilities += list(AL)
+
+ data["abilities"] = abilities
+
+ for(var/path in subtypesof(/datum/horror_upgrade))
+ var/datum/horror_upgrade/upgrade = path
+
+ var/list/DE = list()
+ DE["name"] = initial(upgrade.name)
+ DE["id"] = initial(upgrade.id)
+ DE["desc"] = initial(upgrade.desc)
+ DE["soul_cost"] = initial(upgrade.soul_price)
+ DE["owned"] = has_upgrade(initial(upgrade.id))
+ DE["can_purchase"] = !DE["owned"] && available_points >= initial(upgrade.soul_price)
+
+ upgrades += list(DE)
+
+ data["upgrades"] = upgrades
+
+ return data
+
+/mob/living/simple_animal/horror/ui_act(action, params)
+ if(..())
+ return
+ switch(action)
+ if("unlock")
+ add_ability(params["id"])
+ if("upgrade")
+ add_upgrade(params["id"])
\ No newline at end of file
From 6dd946761ced1e73688939fd707e086cd4f23931 Mon Sep 17 00:00:00 2001
From: ChesterTheCheesy <71487903+ChesterTheCheesy@users.noreply.github.com>
Date: Wed, 14 Apr 2021 21:54:08 +0200
Subject: [PATCH 08/76] Add files via upload
---
icons/mob/actions/actions_horror.dmi | Bin 0 -> 15434 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 icons/mob/actions/actions_horror.dmi
diff --git a/icons/mob/actions/actions_horror.dmi b/icons/mob/actions/actions_horror.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..606a5f05258e39ee0f6c6cadede2f4d5908dbec6
GIT binary patch
literal 15434
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
Date: Wed, 14 Apr 2021 21:57:00 +0200
Subject: [PATCH 09/76] Add files via upload
---
icons/mob/animal.dmi | Bin 233706 -> 246247 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 6da9b16d5a0b6af40dfee30f7760427b2b0edad3..2c27d854e0732be7fc733a2e8f676e48e9e86beb 100644
GIT binary patch
delta 117423
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 |