merge into main

This commit is contained in:
Brett Davis
2022-02-04 17:34:29 -06:00
parent 465c97020a
commit b6aa002a82
8 changed files with 1983 additions and 1983 deletions

View File

@@ -1,18 +1,18 @@
/obj/screen/horror_chemicals
name = "chemicals"
icon_state = "horror_counter"
screen_loc = ui_lingchemdisplay
/datum/hud/chemical_counter
ui_style = 'icons/mob/screen_midnight.dmi'
var/obj/screen/horror_chemicals/chemical_counter
/datum/hud/chemical_counter/New(mob/owner)
. = ..()
chemical_counter = new /obj/screen/horror_chemicals
infodisplay += chemical_counter
/datum/hud/chemical_counter/Destroy()
. = ..()
QDEL_NULL(chemical_counter)
/obj/screen/horror_chemicals
name = "chemicals"
icon_state = "horror_counter"
screen_loc = ui_lingchemdisplay
/datum/hud/chemical_counter
ui_style = 'icons/mob/screen_midnight.dmi'
var/obj/screen/horror_chemicals/chemical_counter
/datum/hud/chemical_counter/New(mob/owner)
. = ..()
chemical_counter = new /obj/screen/horror_chemicals
infodisplay += chemical_counter
/datum/hud/chemical_counter/Destroy()
. = ..()
QDEL_NULL(chemical_counter)

File diff suppressed because it is too large Load Diff

View File

@@ -1,461 +1,461 @@
//ABILITIES
/datum/action/innate/horror
background_icon_state = "bg_ecult"
icon_icon = 'icons/mob/actions/actions_horror.dmi'
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/IsAvailable()
if(!B)
return
if(!B.has_chemicals(chemical_cost))
return
. = ..()
/datum/action/innate/horror/mutate
name = "Mutate"
desc = "Use consumed souls to mutate your abilities."
button_icon_state = "mutate"
blacklisted = TRUE
category = list("horror")
/datum/action/innate/horror/mutate/Activate()
to_chat(usr, span_velvet(span_bold("You focus on mutating your body...")))
B.ui_interact(usr)
return TRUE
/datum/action/innate/horror/seek_soul
name = "Seek target 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"
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/talk_to_host
name = "Converse with 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/toggle_hide
name = "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"
desc = "Communicate mentally with your horror."
button_icon_state = "talk_to_horror"
blacklisted = TRUE
var/mob/living/O
/datum/action/innate/horror/talk_to_horror/IsAvailable()
if(owner.stat == DEAD)
return
return TRUE
/datum/action/innate/horror/talk_to_horror/Activate()
var/mob/living/O = owner
O.horror_comm()
/datum/action/innate/horror/talk_to_brain
name = "Converse with Trapped Mind"
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"
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"
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"
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"
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"
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"
desc = "Makes your host grow a tentacle in their arm. Costs 50 chemicals to activate."
button_icon_state = "tentacle"
chemical_cost = 50
category = list("infest", "control")
soul_price = 2
/datum/action/innate/horror/tentacle/IsAvailable()
if(!active && !B.has_chemicals(chemical_cost))
return
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(span_warning("[B.victim]'s arm contorts into tentacles!"), span_notice("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, span_warning("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(span_warning("[B.victim]'s tentacle transforms back!"), span_notice("Your tentacle disappears!"))
playsound(B.victim, 'sound/effects/blobattack.ogg', 30, 1)
to_chat(B, span_warning("You transform [B.victim]'s arm back."))
for(var/obj/item/horrortentacle/T in B.victim)
qdel(T)
return TRUE
/datum/action/innate/horror/transfer_host
name = "Transfer to another Host"
desc = "Move into another host directly. Grabbing makes the process faster."
button_icon_state = "transfer_host"
category = list("infest", "control")
soul_price = 1
var/transferring = FALSE
/datum/action/innate/horror/transfer_host/proc/is_transferring(var/mob/living/carbon/C)
return transferring && C.Adjacent(B.victim)
/datum/action/innate/horror/transfer_host/Activate()
if(transferring)
transferring = FALSE
to_chat(src, span_warning("You decide against leaving your host."))
return
var/list/choices = list()
for(var/mob/living/carbon/C in range(1,B.victim))
if(C!=B.victim && C.Adjacent(B.victim))
choices += C
if(!choices.len)
return
var/mob/living/carbon/C = choices.len > 1 ? input(owner,"Who do you wish to infest?") in null|choices : choices[1]
if(!C || !B)
return
if(!C.Adjacent(B.victim))
return
var/obj/item/bodypart/head/head = C.get_bodypart(BODY_ZONE_HEAD)
if(!head)
to_chat(owner, span_warning("[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(owner, span_warning("[C] doesn't have a brain!"))
return
if((!C.key || !C.mind) && C != B.target.current)
to_chat(owner, span_warning("[C]'s mind seems unresponsive. Try someone else!"))
return
if(C.has_horror_inside())
to_chat(owner, span_warning("[C] is already infested!"))
return
to_chat(owner, span_warning("You move your tentacles away from [B.victim] and begin to transfer to [C]..."))
var/delay = 20 SECONDS
var/silent
if(B.victim.pulling != C)
silent = TRUE
else
switch(B.victim.grab_state)
if(GRAB_PASSIVE)
delay = 10 SECONDS
if(GRAB_AGGRESSIVE)
delay = 5 SECONDS
if(GRAB_NECK)
delay = 3 SECONDS
else
delay = 1 SECONDS
transferring = TRUE
if(!do_after(B.victim, delay, target = C, extra_checks = CALLBACK(src, .proc/is_transferring, C), stayStill = FALSE))
to_chat(owner, span_warning("As [C] moves away, your transfer gets interrupted!"))
transferring = FALSE
return
transferring = FALSE
if(!C || !B || !C.Adjacent(B.victim))
return
B.leave_victim()
B.Infect(C)
if(!silent)
to_chat(C, span_warning("Something slimy wiggles into your ear!"))
playsound(B, 'sound/effects/blobattack.ogg', 30, 1)
/datum/action/innate/horror/jumpstart_host
name = "Revive 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"
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"
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()
/datum/action/innate/horror/lube_spill
name = "Lube spill"
desc = "Makes you spin around and flail slippery lube around you. Costs 30 chemicals to activate."
button_icon_state = "lube_spill"
chemical_cost = 30
category = list("horror")
soul_price = 1
var/cooldown = 0
/datum/action/innate/horror/lube_spill/IsAvailable()
if(cooldown > world.time || !B.has_chemicals(chemical_cost) || !B.can_use_ability())
return
return ..()
/datum/action/innate/horror/lube_spill/Activate()
B.use_chemicals(30)
cooldown = world.time + 10 SECONDS
UpdateButtonIcon()
addtimer(CALLBACK(src, .proc/UpdateButtonIcon), 10 SECONDS)
B.visible_message(span_warning("[B] starts spinning and throwing some sort of substance!"), span_notice("Your start to spin and flail oily substance everywhere!"))
var/spins_remaining = 10
B.icon_state = "horror_spin"
while(spins_remaining > 0)
playsound(B, 'sound/effects/blobattack.ogg', rand(20, 30), rand(0.5, 2))
for(var/turf/open/t in range(1, B))
if(prob(60) && B.Adjacent(t))
t.MakeSlippery(TURF_WET_LUBE, 100)
sleep(5)
spins_remaining--
if(!B.can_use_ability())
return TRUE
B.icon_state = "horror"
return TRUE
//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(/datum/action/innate/horror/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 = 2
/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
//Doubles 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 a host."
soul_price = 2
/datum/horror_upgrade/hp_up/apply_effects()
B.health = round(min(B.maxHealth,B.health * 2))
B.maxHealth = round(B.maxHealth * 2)
//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 = "crushes"
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."
//ABILITIES
/datum/action/innate/horror
background_icon_state = "bg_ecult"
icon_icon = 'icons/mob/actions/actions_horror.dmi'
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/IsAvailable()
if(!B)
return
if(!B.has_chemicals(chemical_cost))
return
. = ..()
/datum/action/innate/horror/mutate
name = "Mutate"
desc = "Use consumed souls to mutate your abilities."
button_icon_state = "mutate"
blacklisted = TRUE
category = list("horror")
/datum/action/innate/horror/mutate/Activate()
to_chat(usr, span_velvet(span_bold("You focus on mutating your body...")))
B.ui_interact(usr)
return TRUE
/datum/action/innate/horror/seek_soul
name = "Seek target 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"
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/talk_to_host
name = "Converse with 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/toggle_hide
name = "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"
desc = "Communicate mentally with your horror."
button_icon_state = "talk_to_horror"
blacklisted = TRUE
var/mob/living/O
/datum/action/innate/horror/talk_to_horror/IsAvailable()
if(owner.stat == DEAD)
return
return TRUE
/datum/action/innate/horror/talk_to_horror/Activate()
var/mob/living/O = owner
O.horror_comm()
/datum/action/innate/horror/talk_to_brain
name = "Converse with Trapped Mind"
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"
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"
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"
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"
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"
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"
desc = "Makes your host grow a tentacle in their arm. Costs 50 chemicals to activate."
button_icon_state = "tentacle"
chemical_cost = 50
category = list("infest", "control")
soul_price = 2
/datum/action/innate/horror/tentacle/IsAvailable()
if(!active && !B.has_chemicals(chemical_cost))
return
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(span_warning("[B.victim]'s arm contorts into tentacles!"), span_notice("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, span_warning("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(span_warning("[B.victim]'s tentacle transforms back!"), span_notice("Your tentacle disappears!"))
playsound(B.victim, 'sound/effects/blobattack.ogg', 30, 1)
to_chat(B, span_warning("You transform [B.victim]'s arm back."))
for(var/obj/item/horrortentacle/T in B.victim)
qdel(T)
return TRUE
/datum/action/innate/horror/transfer_host
name = "Transfer to another Host"
desc = "Move into another host directly. Grabbing makes the process faster."
button_icon_state = "transfer_host"
category = list("infest", "control")
soul_price = 1
var/transferring = FALSE
/datum/action/innate/horror/transfer_host/proc/is_transferring(var/mob/living/carbon/C)
return transferring && C.Adjacent(B.victim)
/datum/action/innate/horror/transfer_host/Activate()
if(transferring)
transferring = FALSE
to_chat(src, span_warning("You decide against leaving your host."))
return
var/list/choices = list()
for(var/mob/living/carbon/C in range(1,B.victim))
if(C!=B.victim && C.Adjacent(B.victim))
choices += C
if(!choices.len)
return
var/mob/living/carbon/C = choices.len > 1 ? input(owner,"Who do you wish to infest?") in null|choices : choices[1]
if(!C || !B)
return
if(!C.Adjacent(B.victim))
return
var/obj/item/bodypart/head/head = C.get_bodypart(BODY_ZONE_HEAD)
if(!head)
to_chat(owner, span_warning("[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(owner, span_warning("[C] doesn't have a brain!"))
return
if((!C.key || !C.mind) && C != B.target.current)
to_chat(owner, span_warning("[C]'s mind seems unresponsive. Try someone else!"))
return
if(C.has_horror_inside())
to_chat(owner, span_warning("[C] is already infested!"))
return
to_chat(owner, span_warning("You move your tentacles away from [B.victim] and begin to transfer to [C]..."))
var/delay = 20 SECONDS
var/silent
if(B.victim.pulling != C)
silent = TRUE
else
switch(B.victim.grab_state)
if(GRAB_PASSIVE)
delay = 10 SECONDS
if(GRAB_AGGRESSIVE)
delay = 5 SECONDS
if(GRAB_NECK)
delay = 3 SECONDS
else
delay = 1 SECONDS
transferring = TRUE
if(!do_after(B.victim, delay, target = C, extra_checks = CALLBACK(src, .proc/is_transferring, C), stayStill = FALSE))
to_chat(owner, span_warning("As [C] moves away, your transfer gets interrupted!"))
transferring = FALSE
return
transferring = FALSE
if(!C || !B || !C.Adjacent(B.victim))
return
B.leave_victim()
B.Infect(C)
if(!silent)
to_chat(C, span_warning("Something slimy wiggles into your ear!"))
playsound(B, 'sound/effects/blobattack.ogg', 30, 1)
/datum/action/innate/horror/jumpstart_host
name = "Revive 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"
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"
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()
/datum/action/innate/horror/lube_spill
name = "Lube spill"
desc = "Makes you spin around and flail slippery lube around you. Costs 30 chemicals to activate."
button_icon_state = "lube_spill"
chemical_cost = 30
category = list("horror")
soul_price = 1
var/cooldown = 0
/datum/action/innate/horror/lube_spill/IsAvailable()
if(cooldown > world.time || !B.has_chemicals(chemical_cost) || !B.can_use_ability())
return
return ..()
/datum/action/innate/horror/lube_spill/Activate()
B.use_chemicals(30)
cooldown = world.time + 10 SECONDS
UpdateButtonIcon()
addtimer(CALLBACK(src, .proc/UpdateButtonIcon), 10 SECONDS)
B.visible_message(span_warning("[B] starts spinning and throwing some sort of substance!"), span_notice("Your start to spin and flail oily substance everywhere!"))
var/spins_remaining = 10
B.icon_state = "horror_spin"
while(spins_remaining > 0)
playsound(B, 'sound/effects/blobattack.ogg', rand(20, 30), rand(0.5, 2))
for(var/turf/open/t in range(1, B))
if(prob(60) && B.Adjacent(t))
t.MakeSlippery(TURF_WET_LUBE, 100)
sleep(5)
spins_remaining--
if(!B.can_use_ability())
return TRUE
B.icon_state = "horror"
return TRUE
//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(/datum/action/innate/horror/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 = 2
/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
//Doubles 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 a host."
soul_price = 2
/datum/horror_upgrade/hp_up/apply_effects()
B.health = round(min(B.maxHealth,B.health * 2))
B.maxHealth = round(B.maxHealth * 2)
//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 = "crushes"
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

View File

@@ -1,96 +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, span_boldnotice("You need [C.chemuse] chemicals stored to use this chemical!"))
return
to_chat(src, span_danger("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
/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, span_boldnotice("You need [C.chemuse] chemicals stored to use this chemical!"))
return
to_chat(src, span_danger("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."

View File

@@ -1,333 +1,333 @@
//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.current) && owner.current.mind)
var/mob/living/simple_animal/horror/H = owner.current
H.update_horror_hud()
/datum/antagonist/horror/proc/give_objectives()
if(summoner)
var/datum/objective/newobjective = new
newobjective.explanation_text = "Serve your summoner, [summoner.name]."
newobjective.owner = owner
newobjective.completed = TRUE
objectives += newobjective
else
//succ some souls
var/datum/objective/horrorascend/ascend = new
ascend.owner = owner
ascend.hor = owner.current
ascend.target_amount = rand(5, 8)
objectives += ascend
ascend.update_explanation_text()
//looking for antagonist we can assist
var/list/possible_targets = list()
for(var/datum/mind/M in SSticker.minds)
if(M.current && M.current.stat != DEAD)
if(ishuman(M.current))
if(M.special_role)
possible_targets += M
if(possible_targets.len)
var/datum/mind/M = pick(possible_targets)
var/datum/objective/protect/O = new
O.owner = owner
O.target = M
O.explanation_text = "Protect and assist \the [M.current.real_name], the [M.assigned_role]."
objectives += O
//don't die while you're at is
var/datum/objective/survive/survive = new
survive.owner = owner
objectives += survive
/datum/objective/horrorascend
name = "consume souls"
var/mob/living/simple_animal/horror/hor
/datum/objective/horrorascend/update_explanation_text()
. = ..()
explanation_text = "Consume [target_amount] souls."
/datum/objective/horrorascend/check_completion()
if(hor && hor.consumed_souls >= target_amount)
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
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.key = C.key
H.mind.enslave_mind_to_creator(user)
H.mind.add_antag_datum(C)
H.mind.memory += "You are " + span_purple(span_bold("[H.real_name]")) + ", an eldritch horror. Consume souls to evolve.<br>"
var/datum/antagonist/horror/S = new
S.summoner = user.mind
S.antag_memory += "<b>[user.mind]</b> woke you from your eternal slumber. Aid them in their objectives as a token of gratitude.<br>"
H.mind.add_antag_datum(S)
log_game("[key_name(user)] has summoned [key_name(H)], an eldritch horror.")
to_chat(user, span_bold("[H.real_name]</b> 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, span_notice("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, span_purple("Blowing into this horn will recall the horror back to you. Be wary, the horn is loud, and may attract <B>unwanted</B> attention."))
/obj/item/horrorsummonhorn/attack_self(mob/living/user)
if(cooldown > world.time)
to_chat(user, span_notice("Take a breath before you blow [src] again."))
return
to_chat(user, span_notice("You take a deep breath and prepare to blow into [src]..."))
if(do_mob(user, src, 10 SECONDS))
if(cooldown > world.time)
return
cooldown = world.time + 10 SECONDS
to_chat(src, span_notice("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(span_danger("[R] emerges!"))
else
if(!horror || horror.stat == DEAD)
summonplace.visible_message(span_danger("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(span_notice("[horror] appears out of nowhere!"))
if(user.mind != summoner)
sleep(2 SECONDS)
playsound(summonplace, "sound/effects/glassbr2.ogg", 30, 1)
to_chat(user, span_danger("[src] breaks!"))
qdel(src)
/obj/item/horrorsummonhorn/suicide_act(mob/living/user) //"I am the prettiest unicorn that ever was!" ~Spy 2013
user.visible_message(span_suicide("[user] stabs [user.p_their()] forehead with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS
//Tentacle arm
/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
weapon_stats = list(SWING_SPEED = 1, ENCUMBRANCE = 0, ENCUMBRANCE_TIME = 0, REACH = 2, DAMAGE_LOW = 0, DAMAGE_HIGH = 0)
range_cooldown_mod = 0 //tentacle is designed to hit from range
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, span_velvet(span_bold("Functions:")))
to_chat(user, span_velvet("<b>All attacks work up to 2 tiles away.</b>"))
to_chat(user, span_velvet("<b>Help intent:</b> Usual help function of an arm."))
to_chat(user, span_velvet("<b>Disarm intent:</b> Whips the tentacle, disarming your opponent."))
to_chat(user, span_velvet("<b>Grab intent:</b> Instant aggressive grab on an opponent. Can also throw them!"))
to_chat(user, span_velvet("<b>Harm intent:</b> Whips the tentacle, damaging your opponent."))
to_chat(user, span_velvet("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(span_danger("[I] is whipped out of [C]'s hand by [user]!"),span_userdanger("A tentacle whips [I] out of your hand!"))
return
else
to_chat(user, span_danger("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(span_warning("[user] throws [H] with [user.p_their()] [src]!"), span_warning("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, span_warning("The airlock's bolts prevent it from being forced!"))
return
if(A.hasPower())
user.visible_message(span_warning("[user] jams [src] into the airlock and starts prying it open!"), span_warning("You start forcing the airlock open."),
span_italics("You hear a metal screeching sound."))
playsound(A, 'sound/machines/airlock_alien_prying.ogg', 150, 1)
if(!do_after(user, 10 SECONDS, target = A))
return
user.visible_message(span_warning("[user] forces the airlock to open with [user.p_their()] [src]!"), span_warning("You force the airlock to open."),
span_italics("You hear a metal screeching sound."))
A.open(2)
return
. = ..()
/obj/item/horrortentacle/suicide_act(mob/user) //this will never be called, since horror stops suicide, but might as well if they get tentacle through other means
user.visible_message(span_suicide("[src] coils itself around [user] tightly gripping [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!"))
return (OXYLOSS)
//Pinpointer
/obj/screen/alert/status_effect/agent_pinpointer/horror
name = "Soul locator"
desc = "Find your target soul."
/datum/status_effect/agent_pinpointer/horror
id = "horror_pinpointer"
minimum_range = 0
range_fuzz_factor = 0
tick_interval = 20
alert_type = /obj/screen/alert/status_effect/agent_pinpointer/horror
/datum/status_effect/agent_pinpointer/horror/scan_for_target()
return
//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"
var/datum/action/innate/resist_control/R
var/mob/living/simple_animal/horror/H
/mob/living/captive_brain/Initialize(mapload, gen=1)
..()
R = new
R.Grant(src)
/mob/living/captive_brain/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, span_danger("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
if(stat == 2)
return say_dead(message)
to_chat(src, span_alien(span_italics("You whisper silently, \"[message]\"")))
to_chat(H.victim, span_alien(span_italics("[src] whispers, \"[message]\"")))
for(var/M in GLOB.dead_mob_list)
if(isobserver(M))
var/rendered = span_changeling("<i>[src] transfers: \"[message]\"</i>")
var/link = FOLLOW_LINK(M, H.victim)
to_chat(M, "[link] [rendered]")
/mob/living/captive_brain/emote(act, m_type = null, message = null, intentional = FALSE)
return
/datum/action/innate/resist_control
name = "Resist control"
desc = "Try to take back control over your brain. A strong nerve impulse should do it."
background_icon_state = "bg_ecult"
icon_icon = 'icons/mob/actions/actions_horror.dmi'
button_icon_state = "resist_control"
/datum/action/innate/resist_control/Activate()
var/mob/living/captive_brain/B = owner
if(B)
B.try_resist()
/mob/living/captive_brain/resist()
try_resist()
/mob/living/captive_brain/proc/try_resist()
var/delay = rand(20 SECONDS,30 SECONDS)
if(H.horrorupgrades["deep_control"])
delay += rand(20 SECONDS,30 SECONDS)
to_chat(src, span_danger("You begin doggedly resisting the parasite's control."))
to_chat(H.victim, span_danger("You feel the captive mind of [src] begin to resist your control."))
addtimer(CALLBACK(src, .proc/return_control), delay)
/mob/living/captive_brain/proc/return_control()
if(!H || !H.controlling)
return
to_chat(src, span_userdanger("With an immense exertion of will, you regain control of your body!"))
to_chat(H.victim, span_danger("You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you."))
H.detatch()
//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.current) && owner.current.mind)
var/mob/living/simple_animal/horror/H = owner.current
H.update_horror_hud()
/datum/antagonist/horror/proc/give_objectives()
if(summoner)
var/datum/objective/newobjective = new
newobjective.explanation_text = "Serve your summoner, [summoner.name]."
newobjective.owner = owner
newobjective.completed = TRUE
objectives += newobjective
else
//succ some souls
var/datum/objective/horrorascend/ascend = new
ascend.owner = owner
ascend.hor = owner.current
ascend.target_amount = rand(5, 8)
objectives += ascend
ascend.update_explanation_text()
//looking for antagonist we can assist
var/list/possible_targets = list()
for(var/datum/mind/M in SSticker.minds)
if(M.current && M.current.stat != DEAD)
if(ishuman(M.current))
if(M.special_role)
possible_targets += M
if(possible_targets.len)
var/datum/mind/M = pick(possible_targets)
var/datum/objective/protect/O = new
O.owner = owner
O.target = M
O.explanation_text = "Protect and assist \the [M.current.real_name], the [M.assigned_role]."
objectives += O
//don't die while you're at is
var/datum/objective/survive/survive = new
survive.owner = owner
objectives += survive
/datum/objective/horrorascend
name = "consume souls"
var/mob/living/simple_animal/horror/hor
/datum/objective/horrorascend/update_explanation_text()
. = ..()
explanation_text = "Consume [target_amount] souls."
/datum/objective/horrorascend/check_completion()
if(hor && hor.consumed_souls >= target_amount)
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
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.key = C.key
H.mind.enslave_mind_to_creator(user)
H.mind.add_antag_datum(C)
H.mind.memory += "You are " + span_purple(span_bold("[H.real_name]")) + ", an eldritch horror. Consume souls to evolve.<br>"
var/datum/antagonist/horror/S = new
S.summoner = user.mind
S.antag_memory += "<b>[user.mind]</b> woke you from your eternal slumber. Aid them in their objectives as a token of gratitude.<br>"
H.mind.add_antag_datum(S)
log_game("[key_name(user)] has summoned [key_name(H)], an eldritch horror.")
to_chat(user, span_bold("[H.real_name]</b> 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, span_notice("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, span_purple("Blowing into this horn will recall the horror back to you. Be wary, the horn is loud, and may attract <B>unwanted</B> attention."))
/obj/item/horrorsummonhorn/attack_self(mob/living/user)
if(cooldown > world.time)
to_chat(user, span_notice("Take a breath before you blow [src] again."))
return
to_chat(user, span_notice("You take a deep breath and prepare to blow into [src]..."))
if(do_mob(user, src, 10 SECONDS))
if(cooldown > world.time)
return
cooldown = world.time + 10 SECONDS
to_chat(src, span_notice("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(span_danger("[R] emerges!"))
else
if(!horror || horror.stat == DEAD)
summonplace.visible_message(span_danger("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(span_notice("[horror] appears out of nowhere!"))
if(user.mind != summoner)
sleep(2 SECONDS)
playsound(summonplace, "sound/effects/glassbr2.ogg", 30, 1)
to_chat(user, span_danger("[src] breaks!"))
qdel(src)
/obj/item/horrorsummonhorn/suicide_act(mob/living/user) //"I am the prettiest unicorn that ever was!" ~Spy 2013
user.visible_message(span_suicide("[user] stabs [user.p_their()] forehead with [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
return BRUTELOSS
//Tentacle arm
/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
weapon_stats = list(SWING_SPEED = 1, ENCUMBRANCE = 0, ENCUMBRANCE_TIME = 0, REACH = 2, DAMAGE_LOW = 0, DAMAGE_HIGH = 0)
range_cooldown_mod = 0 //tentacle is designed to hit from range
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, span_velvet(span_bold("Functions:")))
to_chat(user, span_velvet("<b>All attacks work up to 2 tiles away.</b>"))
to_chat(user, span_velvet("<b>Help intent:</b> Usual help function of an arm."))
to_chat(user, span_velvet("<b>Disarm intent:</b> Whips the tentacle, disarming your opponent."))
to_chat(user, span_velvet("<b>Grab intent:</b> Instant aggressive grab on an opponent. Can also throw them!"))
to_chat(user, span_velvet("<b>Harm intent:</b> Whips the tentacle, damaging your opponent."))
to_chat(user, span_velvet("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(span_danger("[I] is whipped out of [C]'s hand by [user]!"),span_userdanger("A tentacle whips [I] out of your hand!"))
return
else
to_chat(user, span_danger("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(span_warning("[user] throws [H] with [user.p_their()] [src]!"), span_warning("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, span_warning("The airlock's bolts prevent it from being forced!"))
return
if(A.hasPower())
user.visible_message(span_warning("[user] jams [src] into the airlock and starts prying it open!"), span_warning("You start forcing the airlock open."),
span_italics("You hear a metal screeching sound."))
playsound(A, 'sound/machines/airlock_alien_prying.ogg', 150, 1)
if(!do_after(user, 10 SECONDS, target = A))
return
user.visible_message(span_warning("[user] forces the airlock to open with [user.p_their()] [src]!"), span_warning("You force the airlock to open."),
span_italics("You hear a metal screeching sound."))
A.open(2)
return
. = ..()
/obj/item/horrortentacle/suicide_act(mob/user) //this will never be called, since horror stops suicide, but might as well if they get tentacle through other means
user.visible_message(span_suicide("[src] coils itself around [user] tightly gripping [user.p_their()] neck! It looks like [user.p_theyre()] trying to commit suicide!"))
return (OXYLOSS)
//Pinpointer
/obj/screen/alert/status_effect/agent_pinpointer/horror
name = "Soul locator"
desc = "Find your target soul."
/datum/status_effect/agent_pinpointer/horror
id = "horror_pinpointer"
minimum_range = 0
range_fuzz_factor = 0
tick_interval = 20
alert_type = /obj/screen/alert/status_effect/agent_pinpointer/horror
/datum/status_effect/agent_pinpointer/horror/scan_for_target()
return
//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"
var/datum/action/innate/resist_control/R
var/mob/living/simple_animal/horror/H
/mob/living/captive_brain/Initialize(mapload, gen=1)
..()
R = new
R.Grant(src)
/mob/living/captive_brain/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, span_danger("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
if(stat == 2)
return say_dead(message)
to_chat(src, span_alien(span_italics("You whisper silently, \"[message]\"")))
to_chat(H.victim, span_alien(span_italics("[src] whispers, \"[message]\"")))
for(var/M in GLOB.dead_mob_list)
if(isobserver(M))
var/rendered = span_changeling("<i>[src] transfers: \"[message]\"</i>")
var/link = FOLLOW_LINK(M, H.victim)
to_chat(M, "[link] [rendered]")
/mob/living/captive_brain/emote(act, m_type = null, message = null, intentional = FALSE)
return
/datum/action/innate/resist_control
name = "Resist control"
desc = "Try to take back control over your brain. A strong nerve impulse should do it."
background_icon_state = "bg_ecult"
icon_icon = 'icons/mob/actions/actions_horror.dmi'
button_icon_state = "resist_control"
/datum/action/innate/resist_control/Activate()
var/mob/living/captive_brain/B = owner
if(B)
B.try_resist()
/mob/living/captive_brain/resist()
try_resist()
/mob/living/captive_brain/proc/try_resist()
var/delay = rand(20 SECONDS,30 SECONDS)
if(H.horrorupgrades["deep_control"])
delay += rand(20 SECONDS,30 SECONDS)
to_chat(src, span_danger("You begin doggedly resisting the parasite's control."))
to_chat(H.victim, span_danger("You feel the captive mind of [src] begin to resist your control."))
addtimer(CALLBACK(src, .proc/return_control), delay)
/mob/living/captive_brain/proc/return_control()
if(!H || !H.controlling)
return
to_chat(src, span_userdanger("With an immense exertion of will, you regain control of your body!"))
to_chat(H.victim, span_danger("You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you."))
H.detatch()

View File

@@ -1,102 +1,102 @@
/mob/living/simple_animal/horror/proc/get_html_template(content)
var/html = {"<!DOCTYPE html">
<html>
<head>
<title>Horror Chemicals</title>
<link rel='stylesheet' type='text/css' href='icons.css'>
<link rel='stylesheet' type='text/css' href='shared.css'>
<style type='text/css'>
body {
padding: 10;
margin: 0;
font-size: 12px;
color: #ffffff;
line-height: 170%;
font-family: Verdana, Geneva, sans-serif;
background: #272727 url(uiBackground.png) 50% 0 repeat-x;
overflow-x: hidden;
}
a, a:link, a:visited, a:active, .link, .linkOn, .linkOff, .selected, .disabled {
color: #ffffff;
text-decoration: none;
background: #40628a;
border: 1px solid #161616;
padding: 2px 2px 2px 2px;
margin: 2px 2px 2px 2px;
cursor: pointer;
display: inline-block;
}
a:hover, .linkActive:hover {
background: #507aac;
cursor: pointer;
}
img {
border: 0px;
}
p {
padding: 4px;
margin: 0px;
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
padding: 16px 0 8px 0;
color: #517087;
clear: both;
}
h1 {
font-size: 15px;
}
h2 {
font-size: 14px;
}
h3 {
font-size: 13px;
}
h4 {
font-size: 12px;
}
#header {
margin: 3px;
padding: 0px;
}
table {
width: 570px;
margin: 10px;
}
td {
border: solid 1px #000;
width: 560px;
}
.chem-select {
width: 560px;
margin: 5px;
text-align: center;
}
.enabled {
background-color: #0a0;
}
.disabled {
background-color: #a00;
}
.shown {
display: block;
}
.hidden {
display: none;
}
</style>
<script src="jquery.min.js"></script>
<script type='text/javascript'>
function update_chemicals(chemicals) {
$('#chemicals').text(chemicals);
}
$(function() {
});
</script>
</head>
<body scroll='yes'><div id='content'>
<h1 id='header'>Horror Chemicals</h1>
<br />
[content]
</div></body></html>"}
/mob/living/simple_animal/horror/proc/get_html_template(content)
var/html = {"<!DOCTYPE html">
<html>
<head>
<title>Horror Chemicals</title>
<link rel='stylesheet' type='text/css' href='icons.css'>
<link rel='stylesheet' type='text/css' href='shared.css'>
<style type='text/css'>
body {
padding: 10;
margin: 0;
font-size: 12px;
color: #ffffff;
line-height: 170%;
font-family: Verdana, Geneva, sans-serif;
background: #272727 url(uiBackground.png) 50% 0 repeat-x;
overflow-x: hidden;
}
a, a:link, a:visited, a:active, .link, .linkOn, .linkOff, .selected, .disabled {
color: #ffffff;
text-decoration: none;
background: #40628a;
border: 1px solid #161616;
padding: 2px 2px 2px 2px;
margin: 2px 2px 2px 2px;
cursor: pointer;
display: inline-block;
}
a:hover, .linkActive:hover {
background: #507aac;
cursor: pointer;
}
img {
border: 0px;
}
p {
padding: 4px;
margin: 0px;
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
padding: 16px 0 8px 0;
color: #517087;
clear: both;
}
h1 {
font-size: 15px;
}
h2 {
font-size: 14px;
}
h3 {
font-size: 13px;
}
h4 {
font-size: 12px;
}
#header {
margin: 3px;
padding: 0px;
}
table {
width: 570px;
margin: 10px;
}
td {
border: solid 1px #000;
width: 560px;
}
.chem-select {
width: 560px;
margin: 5px;
text-align: center;
}
.enabled {
background-color: #0a0;
}
.disabled {
background-color: #a00;
}
.shown {
display: block;
}
.hidden {
display: none;
}
</style>
<script src="jquery.min.js"></script>
<script type='text/javascript'>
function update_chemicals(chemicals) {
$('#chemicals').text(chemicals);
}
$(function() {
});
</script>
</head>
<body scroll='yes'><div id='content'>
<h1 id='header'>Horror Chemicals</h1>
<br />
[content]
</div></body></html>"}
return html

View File

@@ -1,97 +1,97 @@
// Horror mutation menu
// Totally not a copypaste of darkspawn menu, not a copypaste of cellular emporium, i swear. Edit: now looks like guardianbuilder too
/mob/living/simple_animal/horror/proc/has_ability(typepath)
for(var/datum/action/innate/horror/ability in horrorabilities)
if(istype(ability, typepath))
return ability
return
/mob/living/simple_animal/horror/proc/add_ability(typepath)
if(has_ability(typepath))
return
var/datum/action/innate/horror/action = new typepath
action.B = src
horrorabilities += action
RefreshAbilities()
to_chat(src, span_velvet("You have mutated the <b>[action.name]</b>."))
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, "<span class='velvet bold'>You have adapted the \"[U.name]\" upgrade.</span>")
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["typepath"] = path
AL["desc"] = initial(ability.desc)
AL["soul_cost"] = initial(ability.soul_price)
AL["owned"] = has_ability(path)
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["typepath"])
if("upgrade")
// Horror mutation menu
// Totally not a copypaste of darkspawn menu, not a copypaste of cellular emporium, i swear. Edit: now looks like guardianbuilder too
/mob/living/simple_animal/horror/proc/has_ability(typepath)
for(var/datum/action/innate/horror/ability in horrorabilities)
if(istype(ability, typepath))
return ability
return
/mob/living/simple_animal/horror/proc/add_ability(typepath)
if(has_ability(typepath))
return
var/datum/action/innate/horror/action = new typepath
action.B = src
horrorabilities += action
RefreshAbilities()
to_chat(src, span_velvet("You have mutated the <b>[action.name]</b>."))
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, "<span class='velvet bold'>You have adapted the \"[U.name]\" upgrade.</span>")
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["typepath"] = path
AL["desc"] = initial(ability.desc)
AL["soul_cost"] = initial(ability.soul_price)
AL["owned"] = has_ability(path)
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["typepath"])
if("upgrade")
add_upgrade(params["id"])

View File

@@ -1,34 +1,34 @@
/datum/round_event_control/horror
name = "Spawn Eldritch Horror"
typepath = /datum/round_event/ghost_role/horror
max_occurrences = 2
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)))
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
/datum/round_event_control/horror
name = "Spawn Eldritch Horror"
typepath = /datum/round_event/ghost_role/horror
max_occurrences = 2
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)))
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