Merge branch 'master' of https://github.com/yogstation13/Yogstation into katmos
@@ -5132,12 +5132,6 @@
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/security/main)
|
||||
"akN" = (
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 1
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/crew_quarters/fitness/recreation)
|
||||
"akQ" = (
|
||||
/obj/machinery/atmospherics/pipe/simple/supply/hidden/layer2{
|
||||
dir = 10
|
||||
@@ -72521,6 +72515,15 @@
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/hallway/secondary/exit/departure_lounge)
|
||||
"lTY" = (
|
||||
/obj/effect/turf_decal/tile/neutral{
|
||||
dir = 1
|
||||
},
|
||||
/obj/structure/cable/yellow{
|
||||
icon_state = "4-8"
|
||||
},
|
||||
/turf/open/floor/plasteel,
|
||||
/area/crew_quarters/fitness/recreation)
|
||||
"lUl" = (
|
||||
/obj/effect/turf_decal/tile/blue{
|
||||
dir = 1
|
||||
@@ -119386,7 +119389,7 @@ jPM
|
||||
oSR
|
||||
qca
|
||||
vLb
|
||||
akN
|
||||
lTY
|
||||
ahg
|
||||
ahg
|
||||
ahg
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -7,9 +7,8 @@
|
||||
var/blocks_self = TRUE
|
||||
var/datum/callback/reaction
|
||||
var/datum/callback/expire
|
||||
var/special_role = 0
|
||||
|
||||
/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire, _special_role = 0)
|
||||
/datum/component/anti_magic/Initialize(_magic = FALSE, _holy = FALSE, _psychic = FALSE, _allowed_slots, _charges, _blocks_self = TRUE, datum/callback/_reaction, datum/callback/_expire)
|
||||
if(isitem(parent))
|
||||
RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, .proc/on_equip)
|
||||
RegisterSignal(parent, COMSIG_ITEM_DROPPED, .proc/on_drop)
|
||||
@@ -28,14 +27,12 @@
|
||||
blocks_self = _blocks_self
|
||||
reaction = _reaction
|
||||
expire = _expire
|
||||
special_role = _special_role
|
||||
|
||||
/datum/component/anti_magic/proc/on_equip(datum/source, mob/equipper, slot)
|
||||
if(!CHECK_BITFIELD(allowed_slots, slotdefine2slotbit(slot))) //Check that the slot is valid for antimagic
|
||||
UnregisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC)
|
||||
return
|
||||
if(equipper.mind?.holy_role >= special_role) //CONVERT OR DIE
|
||||
RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE)
|
||||
RegisterSignal(equipper, COMSIG_MOB_RECEIVE_MAGIC, .proc/protect, TRUE)
|
||||
|
||||
/datum/component/anti_magic/proc/on_drop(datum/source, mob/user)
|
||||
UnregisterSignal(user, COMSIG_MOB_RECEIVE_MAGIC)
|
||||
|
||||
@@ -88,13 +88,13 @@
|
||||
var/mob/living/carbon/human/H = LM
|
||||
var/feetCover = (H.wear_suit && (H.wear_suit.body_parts_covered & FEET)) || (H.w_uniform && (H.w_uniform.body_parts_covered & FEET))
|
||||
|
||||
if(H.shoes || feetCover) //are we wearing shoes
|
||||
if((H.shoes && !istype(H.shoes, /obj/item/clothing/shoes/xeno_wraps)) || feetCover)
|
||||
playsound(T, pick(GLOB.footstep[T.footstep][1]),
|
||||
GLOB.footstep[T.footstep][2] * v,
|
||||
TRUE,
|
||||
GLOB.footstep[T.footstep][3] + e)
|
||||
|
||||
if((!H.shoes && !feetCover)) //are we NOT wearing shoes
|
||||
else
|
||||
if(H.dna.species.special_step_sounds)
|
||||
playsound(T, pick(H.dna.species.special_step_sounds), 50, TRUE)
|
||||
else
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
|
||||
// Shank - Makeshift weapon that can embed on throw
|
||||
/obj/item/kitchen/knife/shank
|
||||
name = "Shank"
|
||||
name = "shank"
|
||||
desc = "A crude knife fashioned by securing a glass shard and a rod together with cables, and welding them together."
|
||||
icon = 'icons/obj/items_and_weapons.dmi'
|
||||
icon_state = "shank"
|
||||
@@ -240,6 +240,7 @@
|
||||
weapon_stats = list(SWING_SPEED = 0.8, ENCUMBRANCE = 0, ENCUMBRANCE_TIME = 0, REACH = 1, DAMAGE_LOW = 5, DAMAGE_HIGH = 7)
|
||||
embedding = list("embedded_pain_multiplier" = 3, "embed_chance" = 20, "embedded_fall_chance" = 10) // Incentive to disengage/stop chasing when stuck
|
||||
attack_verb = list("stuck", "shanked", "stabbed", "shivved")
|
||||
materials = list(/datum/material/iron=1150, /datum/material/glass=2075)
|
||||
|
||||
/obj/item/kitchen/rollingpin
|
||||
name = "rolling pin"
|
||||
|
||||
@@ -43,7 +43,7 @@ GLOBAL_LIST_INIT(bibleitemstates, list("bible", "koran", "scrapbook", "burning",
|
||||
|
||||
/obj/item/storage/book/bible/Initialize()
|
||||
. = ..()
|
||||
AddComponent(/datum/component/anti_magic, FALSE, TRUE, FALSE, null, null, TRUE, null, null, HOLY_ROLE_PRIEST)
|
||||
AddComponent(/datum/component/anti_magic, FALSE, TRUE)
|
||||
|
||||
/obj/item/storage/book/bible/suicide_act(mob/user)
|
||||
user.visible_message(span_suicide("[user] is offering [user.p_them()]self to [deity_name]! It looks like [user.p_theyre()] trying to commit suicide!"))
|
||||
|
||||
@@ -47,11 +47,13 @@
|
||||
qdel(I)
|
||||
if(!isplasmaman(H)) //no killing plasmies
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/kilt/highlander(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), SLOT_HEAD)
|
||||
else
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/under/plasmaman(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/tank/internals/plasmaman(H), SLOT_W_UNIFORM)
|
||||
H.equip_to_slot_or_del(new /obj/item/tank/internals/plasmaman/belt/full(H), SLOT_BELT)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/plasmaman(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/mask/breath(H), SLOT_WEAR_MASK)
|
||||
H.equip_to_slot_or_del(new /obj/item/radio/headset/heads/captain(H), SLOT_EARS)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/highlander(H), SLOT_HEAD)
|
||||
H.equip_to_slot_or_del(new /obj/item/clothing/shoes/combat(H), SLOT_SHOES)
|
||||
H.equip_to_slot_or_del(new /obj/item/pinpointer/nuke(H), SLOT_L_STORE)
|
||||
//Yogs Start: Pacifists want to play too
|
||||
|
||||
@@ -1,461 +1,440 @@
|
||||
//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
|
||||
//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 = 30 SECONDS
|
||||
var/silent
|
||||
if(B.victim.pulling != C)
|
||||
silent = TRUE
|
||||
else
|
||||
switch(B.victim.grab_state)
|
||||
if(GRAB_PASSIVE)
|
||||
delay = 20 SECONDS
|
||||
if(GRAB_AGGRESSIVE)
|
||||
delay = 10 SECONDS
|
||||
if(GRAB_NECK)
|
||||
delay = 5 SECONDS
|
||||
else
|
||||
delay = 3 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
|
||||
|
||||
//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)
|
||||
|
||||
//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
|
||||
|
||||
@@ -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."
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
@@ -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"])
|
||||
@@ -159,6 +159,7 @@
|
||||
name = "reactive tesla armor"
|
||||
desc = "An experimental suit of armor with sensitive detectors hooked up to a huge capacitor grid, with emitters strutting out of it. Zap."
|
||||
siemens_coefficient = -1
|
||||
reactivearmor_cooldown_duration = 3 SECONDS
|
||||
var/tesla_power = 25000
|
||||
var/tesla_range = 20
|
||||
var/tesla_flags = TESLA_MOB_DAMAGE | TESLA_OBJ_DAMAGE
|
||||
@@ -195,6 +196,7 @@
|
||||
/obj/item/clothing/suit/armor/reactive/repulse
|
||||
name = "reactive repulse armor"
|
||||
desc = "An experimental suit of armor that violently throws back attackers."
|
||||
reactivearmor_cooldown_duration = 5 SECONDS
|
||||
var/repulse_force = MOVE_FORCE_EXTREMELY_STRONG
|
||||
|
||||
/obj/item/clothing/suit/armor/reactive/repulse/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK)
|
||||
|
||||
@@ -164,6 +164,9 @@
|
||||
to_chat(user, span_notice("You detach [A] from [src]."))
|
||||
else
|
||||
to_chat(user, span_notice("You detach [A] from [src] and it falls on the floor."))
|
||||
var/turf/T = get_turf(src)
|
||||
if(!T)
|
||||
T = get_turf(user)
|
||||
A.forceMove(get_turf(src))
|
||||
|
||||
if(ishuman(loc))
|
||||
|
||||
@@ -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
|
||||
@@ -71,7 +71,6 @@
|
||||
transform = matrix()*0.75
|
||||
animate(src, transform = matrix()*1.5, time = duration)
|
||||
deltimer(timerid)
|
||||
addtimer(CALLBACK(src, .proc/replicate, get_turf(src), creator, duration), duration, TIMER_STOPPABLE)//yogs: adds field replication
|
||||
timerid = addtimer(CALLBACK(src, .proc/burst), duration, TIMER_STOPPABLE)
|
||||
|
||||
/obj/effect/temp_visual/resonance/Destroy()
|
||||
@@ -97,6 +96,7 @@
|
||||
new /obj/effect/temp_visual/resonance_crush(T)
|
||||
if(ismineralturf(T))
|
||||
var/turf/closed/mineral/M = T
|
||||
replicate(M)
|
||||
M.gets_drilled(creator)
|
||||
check_pressure(T)
|
||||
playsound(T,'sound/weapons/resonator_blast.ogg',50,1)
|
||||
@@ -117,10 +117,9 @@
|
||||
transform = matrix()*1.5
|
||||
animate(src, transform = matrix()*0.1, alpha = 50, time = 4)
|
||||
|
||||
/obj/effect/temp_visual/resonance/proc/replicate(turf/closed/mineral/M, creator, timetoburst) //yogs start: adds replication to resonator fields
|
||||
if(!istype(M))
|
||||
/obj/effect/temp_visual/resonance/proc/replicate(turf/closed/mineral/M) //yogs start: adds replication to resonator fields
|
||||
if(!istype(M) || !M.mineralType) // so we don't end up in the ultimate chain reaction
|
||||
return
|
||||
for(var/turf/closed/mineral/T in orange(1, M))
|
||||
if(istype(T))
|
||||
if(M.mineralType == T.mineralType && M.mineralType != null) // so we don't end up in the ultimate chain reaction
|
||||
new /obj/effect/temp_visual/resonance(T, creator, null, timetoburst) //yogs end
|
||||
if(istype(T) && M.mineralType == T.mineralType)
|
||||
new /obj/effect/temp_visual/resonance(T, creator, null, duration) //yogs end
|
||||
|
||||
@@ -221,6 +221,9 @@
|
||||
. += get_modular_computer_parts_examine(user)
|
||||
|
||||
/obj/item/modular_computer/update_icon()
|
||||
if(!physical)
|
||||
return
|
||||
|
||||
SSvis_overlays.remove_vis_overlay(physical, physical.managed_vis_overlays)
|
||||
var/program_overlay = ""
|
||||
var/is_broken = obj_integrity <= integrity_failure
|
||||
@@ -560,4 +563,3 @@
|
||||
active_program = program
|
||||
program.alert_pending = FALSE
|
||||
enabled = TRUE
|
||||
update_icon()
|
||||
|
||||
@@ -2,25 +2,21 @@
|
||||
. = ..()
|
||||
ui_interact(user)
|
||||
|
||||
/obj/item/modular_computer/proc/can_show_ui(mob/user, datum/tgui/ui)
|
||||
/obj/item/modular_computer/proc/can_show_ui(mob/user)
|
||||
if(!enabled)
|
||||
if(ui)
|
||||
ui.close()
|
||||
return FALSE
|
||||
if(!use_power())
|
||||
if(ui)
|
||||
ui.close()
|
||||
return FALSE
|
||||
// Robots don't really need to see the screen, their wireless connection works as long as computer is on.
|
||||
if(!screen_on && !issilicon(user))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
// Operates TGUI
|
||||
/obj/item/modular_computer/ui_interact(mob/user, datum/tgui/ui)
|
||||
if (!can_show_ui(user, ui))
|
||||
if (!can_show_ui(user))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return
|
||||
// If we have an active program switch to it now.
|
||||
if(active_program)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
// No running around with open laptops in hands.
|
||||
item_flags = SLOWS_WHILE_IN_HAND
|
||||
|
||||
screen_on = 0 // Starts closed
|
||||
screen_on = FALSE // Starts closed
|
||||
var/start_open = TRUE // unless this var is set to 1
|
||||
var/icon_state_closed = "laptop-closed"
|
||||
var/w_class_open = WEIGHT_CLASS_BULKY
|
||||
@@ -95,10 +95,15 @@
|
||||
to_chat(user, span_notice("You close \the [src]."))
|
||||
slowdown = initial(slowdown)
|
||||
w_class = initial(w_class)
|
||||
icon_state = icon_state_closed
|
||||
else
|
||||
to_chat(user, span_notice("You open \the [src]."))
|
||||
slowdown = slowdown_open
|
||||
w_class = w_class_open
|
||||
if(enabled)
|
||||
icon_state = icon_state_powered
|
||||
else
|
||||
icon_state = icon_state_unpowered
|
||||
|
||||
screen_on = !screen_on
|
||||
update_icon()
|
||||
|
||||
@@ -197,7 +197,9 @@
|
||||
|
||||
/datum/computer_file/program/ui_interact(mob/user, datum/tgui/ui)
|
||||
ui = SStgui.try_update_ui(user, src, ui)
|
||||
if (!computer.can_show_ui(user, ui))
|
||||
if (!computer.can_show_ui(user))
|
||||
if(ui)
|
||||
ui.close()
|
||||
return
|
||||
if(!ui && tgui_id)
|
||||
ui = new(user, src, tgui_id, filedesc)
|
||||
@@ -214,10 +216,12 @@
|
||||
if(computer)
|
||||
switch(action)
|
||||
if("PC_exit")
|
||||
computer.play_interact_sound()
|
||||
computer.kill_program()
|
||||
ui.close()
|
||||
return TRUE
|
||||
if("PC_shutdown")
|
||||
computer.play_interact_sound()
|
||||
computer.shutdown_computer()
|
||||
ui.close()
|
||||
return TRUE
|
||||
@@ -225,7 +229,7 @@
|
||||
var/mob/user = usr
|
||||
if(!computer.active_program || !computer.all_components[MC_CPU])
|
||||
return
|
||||
|
||||
computer.play_interact_sound()
|
||||
computer.idle_threads.Add(computer.active_program)
|
||||
program_state = PROGRAM_STATE_BACKGROUND // Should close any existing UIs
|
||||
|
||||
@@ -246,4 +250,6 @@
|
||||
/datum/computer_file/program/ui_status(mob/user)
|
||||
if(program_state != PROGRAM_STATE_ACTIVE) // Our program was closed. Close the ui if it exists.
|
||||
return UI_CLOSE
|
||||
if(!computer.can_show_ui(user))
|
||||
return UI_CLOSE
|
||||
return ..()
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
var/turf/T = get_turf(computer)
|
||||
z = T.z
|
||||
var/list/death_list = GLOB.crewmonitor.death_list?["[z]"]
|
||||
if(death_list.len > 0)
|
||||
if(death_list && death_list.len > 0)
|
||||
alarm = TRUE
|
||||
else
|
||||
alarm = FALSE
|
||||
|
||||
@@ -133,6 +133,8 @@ Place a pool filter somewhere in the pool if you want people to be able to modif
|
||||
var/obj/item/clothing/CS = F.wear_suit
|
||||
if (CS.clothing_flags & THICKMATERIAL)
|
||||
zap --
|
||||
if(zap > 0)
|
||||
zap = 3 - zap // 1 is higher severity emp than 2
|
||||
if(zap > 0)
|
||||
user.emp_act(zap)
|
||||
user.emote("scream") //Chad coders use M.say("*scream")
|
||||
@@ -201,6 +203,7 @@ GLOBAL_LIST_EMPTY(pool_filters)
|
||||
var/desired_temperature = 300 //Room temperature
|
||||
var/current_temperature = 300 //current temp
|
||||
var/preset_reagent_type = null //Set this if you want your pump to start filled with a given reagent. SKEWIUM POOL SKEWIUM POOL!
|
||||
var/temp_rate = 0.5
|
||||
|
||||
/obj/machinery/pool_filter/examine(mob/user)
|
||||
. = ..()
|
||||
@@ -241,9 +244,13 @@ GLOBAL_LIST_EMPTY(pool_filters)
|
||||
if(!LAZYLEN(pool) || !is_operational())
|
||||
return //No use having one of these processing for no reason is there?
|
||||
use_power(idle_power_usage)
|
||||
var/delta = (current_temperature > desired_temperature) ? -0.5 : 0.5
|
||||
current_temperature += delta
|
||||
current_temperature = clamp(current_temperature, T0C, desired_temperature)
|
||||
if (current_temperature > desired_temperature)
|
||||
current_temperature -= temp_rate
|
||||
current_temperature = max(desired_temperature, current_temperature)
|
||||
else if (current_temperature < desired_temperature)
|
||||
current_temperature += temp_rate
|
||||
current_temperature = min(desired_temperature, current_temperature)
|
||||
|
||||
var/trans_amount = reagents.total_volume / pool.len //Split up the reagents equally.
|
||||
for(var/turf/open/indestructible/sound/pool/water as() in pool)
|
||||
if(reagents.reagent_list.len)
|
||||
@@ -267,12 +274,13 @@ GLOBAL_LIST_EMPTY(pool_filters)
|
||||
var/mob/living/carbon/C = M
|
||||
if(current_temperature <= 283.5) //Colder than 10 degrees is going to make you very cold
|
||||
if(iscarbon(M))
|
||||
C.adjust_bodytemperature(-80, 80)
|
||||
C.adjust_bodytemperature(-80, current_temperature)
|
||||
to_chat(M, "<span class='warning'>The water is freezing cold!</span>")
|
||||
else if(current_temperature >= 308.5) //Hotter than 35 celsius is going to make you burn up
|
||||
if(iscarbon(M))
|
||||
C.adjust_bodytemperature(35, 0, 500)
|
||||
M.adjustFireLoss(5)
|
||||
C.adjust_bodytemperature(35, 0, current_temperature)
|
||||
if(!HAS_TRAIT(C, TRAIT_RESISTHEAT))
|
||||
C.adjustFireLoss(5)
|
||||
to_chat(M, "<span class='danger'>The water is searing hot!</span>")
|
||||
|
||||
/obj/structure/pool_ladder/attack_hand(mob/user)
|
||||
|
||||
@@ -498,7 +498,7 @@
|
||||
set_light(gun_light.brightness_on)
|
||||
else
|
||||
set_light(0)
|
||||
cut_overlays(flashlight_overlay, TRUE)
|
||||
cut_overlay(flashlight_overlay, TRUE)
|
||||
var/state = "flight[gun_light.on? "_on":""]" //Generic state.
|
||||
if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state?
|
||||
state = gun_light.icon_state
|
||||
@@ -508,7 +508,7 @@
|
||||
add_overlay(flashlight_overlay, TRUE)
|
||||
else
|
||||
set_light(0)
|
||||
cut_overlays(flashlight_overlay, TRUE)
|
||||
cut_overlay(flashlight_overlay, TRUE)
|
||||
flashlight_overlay = null
|
||||
update_icon(TRUE)
|
||||
for(var/X in actions)
|
||||
|
||||
@@ -96,13 +96,17 @@
|
||||
starting_organ = /obj/item/organ/cyberimp/chest/reviver
|
||||
|
||||
/obj/item/autosurgeon/medibeam
|
||||
uses = 1
|
||||
starting_organ = /obj/item/organ/cyberimp/arm/medibeam
|
||||
|
||||
/obj/item/autosurgeon/organ/syndicate/syndie_mantis
|
||||
uses = 1
|
||||
starting_organ = /obj/item/organ/cyberimp/arm/syndie_mantis
|
||||
|
||||
/obj/item/autosurgeon/organ/syndicate/syndie_mantis/l
|
||||
uses = 1
|
||||
starting_organ = /obj/item/organ/cyberimp/arm/syndie_mantis/l
|
||||
|
||||
/obj/item/autosurgeon/plasmavessel //Yogs Start: Just an autosurgeon with a plasma vessel in it, used in /obj/item/storage/box/syndie_kit/xeno_organ_kit
|
||||
uses = 3
|
||||
starting_organ = /obj/item/organ/alien/plasmavessel //Yogs End
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
/obj/item/organ/heart/cursed
|
||||
name = "cursed heart"
|
||||
desc = "A heart that, when inserted, will force you to pump it manually."
|
||||
icon_state = "cursedheart-off"
|
||||
icon_state = "cursedheart"
|
||||
icon_base = "cursedheart"
|
||||
decay_factor = 0
|
||||
actions_types = list(/datum/action/item_action/organ_action/cursed_heart)
|
||||
|
||||
@@ -498,7 +498,7 @@
|
||||
/obj/item/organ/lungs/ghetto
|
||||
name = "oxygen tanks welded to a modular reciever"
|
||||
desc = "A pair of oxygen tanks which have been attached to a modular (oxygen) receiver. They are incapable of supplying air, but can work as a replacement for lungs."
|
||||
icon_state = "lungs_g"
|
||||
icon_state = "lungs-g"
|
||||
organ_efficiency = 0.5
|
||||
organ_flags = ORGAN_SYNTHETIC //the moment i understood the weakness of flesh, it disgusted me, and i yearned for the certainty, of steel
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
AshCorr = Host
|
||||
Xantam = Host
|
||||
|
||||
Ynot01 = Council Member
|
||||
tehladyk = Council Member
|
||||
MenacingManatee = Council Member
|
||||
Num1bamf = Council Member
|
||||
adamsogm = Council Member
|
||||
|
||||
@@ -58,6 +58,86 @@
|
||||
-->
|
||||
<div class="commit sansserif">
|
||||
|
||||
<h2 class="date">10 March 2022</h2>
|
||||
<h3 class="author">ToasterBiome updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">flashlights on guns properly clear their overlay instead of all overlays</li>
|
||||
</ul>
|
||||
<h3 class="author">adamsong updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">Veil now works on light prisms</li>
|
||||
<li class="bugfix">fixed runtime in crew_monitor.dm</li>
|
||||
<li class="bugfix">fixed runtime in remove_accessory</li>
|
||||
</ul>
|
||||
<h3 class="author">cuackles updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">tweaked a few things</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">09 March 2022</h2>
|
||||
<h3 class="author">SomeguyManperson updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">resonator field replication now works if you manually detonate the resonatoe field rather than only working if the field detonates naturally</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">07 March 2022</h2>
|
||||
<h3 class="author">ChesterTheCheesy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">gives the rest of reactive armors respectible cooldowns</li>
|
||||
</ul>
|
||||
<h3 class="author">Mqiib updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscdel">Removed invisible escape and funny aoe knockout ability upgrades</li>
|
||||
<li class="tweak">Massively increased escape time and soul eating time</li>
|
||||
<li class="tweak">Moderate increases to direct host transfer time</li>
|
||||
<li class="tweak">Increases time to crawl into someone's ear</li>
|
||||
</ul>
|
||||
<h3 class="author">SomeguyManperson updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">the bible's holy antimagic effect now works on normal people again</li>
|
||||
</ul>
|
||||
<h3 class="author">ToasterBiome updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">cursed heart has correct sprite now</li>
|
||||
</ul>
|
||||
<h3 class="author">adamsong updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">fixed pool emp effect being the wrong severity</li>
|
||||
<li class="bugfix">fixed pools temperature instantly lowering</li>
|
||||
<li class="bugfix">fixed pools damaging people with heat resistance</li>
|
||||
<li class="bugfix">fixed pools violating the laws of thermodynamics</li>
|
||||
</ul>
|
||||
<h3 class="author">nmajask updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">modular laptops now use the correct icons when opened</li>
|
||||
<li class="bugfix">you can no longer use programs on a modular laptop with its lid is shut</li>
|
||||
<li class="bugfix">fixed some buttons not having interaction sounds</li>
|
||||
<li class="bugfix">fixed a missing wire on meta</li>
|
||||
</ul>
|
||||
<h3 class="author">tattax updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">plasmaman now spawn with proper clothing on highlander event</li>
|
||||
</ul>
|
||||
<h3 class="author">ynot01 updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">All traitor-available autosurgeons are now corrected to be one-time-use</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">06 March 2022</h2>
|
||||
<h3 class="author">Mqiib updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">Fixes the icon state for ghetto lungs</li>
|
||||
</ul>
|
||||
<h3 class="author">cuackles updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="imageadd">added t45b new sprite</li>
|
||||
<li class="imagedel">deleted t45b old sprite</li>
|
||||
</ul>
|
||||
<h3 class="author">tattax updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Adds all four states to the shank sprite in-hands.</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">03 March 2022</h2>
|
||||
<h3 class="author">ToasterBiome updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
@@ -1181,114 +1261,6 @@
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">fixed a locker name in the yogurtstation brig</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">10 December 2021</h2>
|
||||
<h3 class="author"> Lucy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">Holoparasites are now bound to a user's mind rather than body.</li>
|
||||
<li class="tweak">Holoparasite injectors are now refundable if you don't manage to get a holoparasite.</li>
|
||||
<li class="tweak">Holoparasite injectors now cost 12 TC for traitors, as quite honestly, more often than not they're a wildcard/liability.</li>
|
||||
<li class="tweak">Assassin now costs 3 points.</li>
|
||||
<li class="tweak">The Hand now costs 4 points.</li>
|
||||
<li class="tweak">Limited Healing now costs 2 points.</li>
|
||||
<li class="tweak">Time Erasure now costs 4 points.</li>
|
||||
<li class="bugfix">Scout holoparasites are now properly invincible when scouting.</li>
|
||||
<li class="tweak">Frenzy's ranged punch now has much higher knockback.</li>
|
||||
<li class="tweak">The Guardian Builder UI is now multi-tabbed, as originally intended.</li>
|
||||
<li class="tweak">There is no more limit to how much you can reset your holoparasites.</li>
|
||||
<li class="tweak">When ghosts are prompted to become a holoparasite, they will be shown the stats and abilities of the holoparasite.</li>
|
||||
<li class="tweak">Holoparasites will be anchored to their owner after manifesting until it chooses to move itself.</li>
|
||||
</ul>
|
||||
<h3 class="author">Absolucy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">All infiltrator chameleon items are now syndicate chameleon items, meaning only they will get the action buttons for them.</li>
|
||||
<li class="tweak">All chameleon hardsuits now default to being called "engineering hardsuit", and their chameleon functionality is also syndicate-only</li>
|
||||
<li class="tweak">Infiltrators now have an engineer box and not a syndicate box in their backpack, because why do they need a very un-stealthy syndicate mask?</li>
|
||||
<li class="bugfix">Chameleon IDs and PDAs will no longer go back to a "generic" name when their appearance is changed</li>
|
||||
<li class="bugfix">The "steal 28 moles of plasma" objective will now be complete for infiltrators if it's in the base</li>
|
||||
</ul>
|
||||
<h3 class="author">SomeguyManperson updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">no more spare ID spamming</li>
|
||||
</ul>
|
||||
<h3 class="author">adamsong updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscdel">Removed the viro database on the med records console</li>
|
||||
<li class="bugfix">fixed massive security exploit with the viro database on the med records console</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">09 December 2021</h2>
|
||||
<h3 class="author">nmajask updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">on delta, the medbay security checkpoint and bottom left maints door now have the correct areas</li>
|
||||
</ul>
|
||||
<h3 class="author">wejengin2 updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">disables deltastation</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">08 December 2021</h2>
|
||||
<h3 class="author">nmajask updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">reworked Delta medbay</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">07 December 2021</h2>
|
||||
<h3 class="author">SomeguyManperson updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscdel">every map except box is now out of rotation, aka nothing has changed</li>
|
||||
</ul>
|
||||
<h3 class="author">UselessTheremin updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">cat butcher ruin now has a tiny fan</li>
|
||||
</ul>
|
||||
<h3 class="author">nmajask updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">added a shuttle docking port to the space bar</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">06 December 2021</h2>
|
||||
<h3 class="author">ChesterTheCheesy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Added a new space ruin: UFO crashed into asteroid</li>
|
||||
</ul>
|
||||
<h3 class="author">SomeguyManperson updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">mega arachnid snares now work</li>
|
||||
<li class="bugfix">the supermatter cutting scalpel no longer gets deleted for cutting the supermatter when trying to cut the supermatter</li>
|
||||
</ul>
|
||||
<h3 class="author">ToasterBiome updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">grilling items dont spam steam overlays</li>
|
||||
<li class="bugfix">placing things on the griddle doesn't have the item move animation</li>
|
||||
</ul>
|
||||
<h3 class="author">redmoogle updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">Drones and clockwork shells now remove their listing if used up</li>
|
||||
<li class="rscadd">Positronic brains now show up in ghost menu</li>
|
||||
<li class="tweak">Spawner menu now looks marginally better if there are no spawners</li>
|
||||
</ul>
|
||||
|
||||
<h2 class="date">05 December 2021</h2>
|
||||
<h3 class="author"> Absolucy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="rscadd">Added the Infiltration game mode!</li>
|
||||
<li class="rscadd">In Infiltration, there's a team of Syndicate infiltrators who will attempt to infiltrate Space Station 13.</li>
|
||||
<li class="rscadd">The infiltrators can have various objectives, ranging from simple traitor objectives, to kidnapping someone important, hijacking the AI unit, or stealing power!</li>
|
||||
</ul>
|
||||
<h3 class="author"> Lucy updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">Scout holoparasites can now properly scout.</li>
|
||||
</ul>
|
||||
<h3 class="author">TheGamerdk updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="tweak">Updates the changelog. Yes, the changelog that YOU ARE CURRENTLY READING! If you can spot the difference you may be entitled to a prize!</li>
|
||||
</ul>
|
||||
<h3 class="author">nmajask updated:</h3>
|
||||
<ul class="changes bgimages16">
|
||||
<li class="bugfix">fixed some jobs getting antags they shouldn't and vice versa on dynamic</li>
|
||||
<li class="tweak">the bounty board, energy harvester controller, and portrait painter programs now have program icons</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<b>GoonStation 13 Development Team</b>
|
||||
|
||||
@@ -30235,3 +30235,50 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py.
|
||||
- rscadd: Adds the ability for external tooling to send server messages
|
||||
maxion12345:
|
||||
- rscadd: AI's can now research RGB lightings for their datacores.
|
||||
2022-03-06:
|
||||
Mqiib:
|
||||
- bugfix: Fixes the icon state for ghetto lungs
|
||||
cuackles:
|
||||
- imageadd: added t45b new sprite
|
||||
- imagedel: deleted t45b old sprite
|
||||
tattax:
|
||||
- rscadd: Adds all four states to the shank sprite in-hands.
|
||||
2022-03-07:
|
||||
ChesterTheCheesy:
|
||||
- tweak: gives the rest of reactive armors respectible cooldowns
|
||||
Mqiib:
|
||||
- rscdel: Removed invisible escape and funny aoe knockout ability upgrades
|
||||
- tweak: Massively increased escape time and soul eating time
|
||||
- tweak: Moderate increases to direct host transfer time
|
||||
- tweak: Increases time to crawl into someone's ear
|
||||
SomeguyManperson:
|
||||
- tweak: the bible's holy antimagic effect now works on normal people again
|
||||
ToasterBiome:
|
||||
- bugfix: cursed heart has correct sprite now
|
||||
adamsong:
|
||||
- bugfix: fixed pool emp effect being the wrong severity
|
||||
- bugfix: fixed pools temperature instantly lowering
|
||||
- bugfix: fixed pools damaging people with heat resistance
|
||||
- bugfix: fixed pools violating the laws of thermodynamics
|
||||
nmajask:
|
||||
- bugfix: modular laptops now use the correct icons when opened
|
||||
- bugfix: you can no longer use programs on a modular laptop with its lid is shut
|
||||
- bugfix: fixed some buttons not having interaction sounds
|
||||
- bugfix: fixed a missing wire on meta
|
||||
tattax:
|
||||
- bugfix: plasmaman now spawn with proper clothing on highlander event
|
||||
ynot01:
|
||||
- tweak: All traitor-available autosurgeons are now corrected to be one-time-use
|
||||
2022-03-09:
|
||||
SomeguyManperson:
|
||||
- tweak: resonator field replication now works if you manually detonate the resonatoe
|
||||
field rather than only working if the field detonates naturally
|
||||
2022-03-10:
|
||||
ToasterBiome:
|
||||
- bugfix: flashlights on guns properly clear their overlay instead of all overlays
|
||||
adamsong:
|
||||
- tweak: Veil now works on light prisms
|
||||
- bugfix: fixed runtime in crew_monitor.dm
|
||||
- bugfix: fixed runtime in remove_accessory
|
||||
cuackles:
|
||||
- tweak: tweaked a few things
|
||||
|
||||
|
Before Width: | Height: | Size: 228 KiB After Width: | Height: | Size: 229 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 372 KiB After Width: | Height: | Size: 372 KiB |
|
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 128 KiB After Width: | Height: | Size: 128 KiB |
@@ -175,6 +175,8 @@
|
||||
if(istype(LO, /obj/machinery/power/floodlight))
|
||||
var/obj/machinery/power/floodlight/FL = LO
|
||||
FL.change_setting(2) // Set floodlight to lowest setting
|
||||
if(istype(LO, /obj/structure/light_prism))
|
||||
qdel(LO)
|
||||
|
||||
for(var/obj/structure/glowshroom/G in orange(7, user)) //High radius because glowshroom spam wrecks shadowlings
|
||||
if(!istype(G, /obj/structure/glowshroom/shadowshroom))
|
||||
|
||||