mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-29 08:08:49 +01:00
Reworks phobias to use the new fear system instead of handling all the code via traumas (#94455)
## About The Pull Request Phobias have been refactored to use the new fear system instead of handling their effects via simple triggers on themselves. The overall idea is still the same, triggering upon seeing/hearing/saying a scary word or thing, but instead of instantly sending you into a panic it adds some fear and has a chance of triggering a new startle fear effect, which mirrors some of the previous phobia effects that weren't already included in other handlers. To complete the phobic trio, I've added monophobia as a quirk - its quite interesting compared to nycto- and claustrophobia, as it forces you to stick to other people, thus indirectly incentivizing social interactions, and could make for actually interesting moments. Additionally, I've cleaned up some of the related code and added message CDs to all other handlers that were missing them as to avoid chat spam which could sometimes occur when the effect triggered far too frequently. ## Why It's Good For The Game Using the new system makes phobias much more immersive and interesting to play around, as they no longer absolutely cripple you to the point of making the game unplayable in case of some of them due to random stuns or knockouts. It also makes them natively interact with other phobias and quirks, which is a neat thing for character building. Currently getting a phobia basically forces you to go to medbay as to not risk randomly falling unconscious every once in a while if you roll a common one (like cyborgs, blood, doctors or authority), and picking one as a quirk is basically not an option. ## Changelog 🆑 add: Monophobia is now availible as a negative (-3) quirk. balance: Phobias now have accumulating, and less debilitating effects due to conversion to the new fear system. qol: Fear effects now have a cooldown between messages as to avoid chat spam. code: Cleaned up some of fear code. refactor: Refactored phobias to use the fear system /🆑
This commit is contained in:
+15
-1
@@ -51,7 +51,7 @@
|
||||
#define TERROR_HANDLER_EFFECT "effect"
|
||||
|
||||
// Default cooldown for terror messages, to not get spammy
|
||||
#define TERROR_MESSAGE_CD 30 SECONDS
|
||||
#define TERROR_MESSAGE_CD 15 SECONDS
|
||||
|
||||
// Values for terror buildup effects
|
||||
/// Initial value for effects that apply the component from spooking you
|
||||
@@ -76,6 +76,20 @@
|
||||
/// How much terror being hugged reduces, or increases if its done by a nightmare or someone you're afraid of
|
||||
#define HUG_TERROR_AMOUNT 90
|
||||
|
||||
/// Cooldown for phobia checks, to avoid constantly refreshing views
|
||||
#define PHOBIA_CHECK_DELAY 5 SECONDS
|
||||
/// Delay between phobia freakouts, also the time it takes for the buildup effect to fade away
|
||||
#define PHOBIA_FREAKOUT_DELAY 12 SECONDS
|
||||
/// Amount of terror granted whenever we hear a word we're afraid of
|
||||
#define PHOBIA_WORD_TERROR_BUILDUP 40
|
||||
/// Amount of terror granted by each phobia trigger
|
||||
#define PHOBIA_FREAKOUT_TERROR_BUILDUP 120
|
||||
|
||||
/// Cooldown for fear screams
|
||||
#define TERROR_STARTLE_COOLDOWN 12 SECONDS
|
||||
/// Minimum difference in fear per tick for screams to actually trigger, so we don't proc from minor fears
|
||||
#define TERROR_STARTLE_MINIMUM_DIFFERENCE 40
|
||||
|
||||
/// Relates to fear or resisting fear
|
||||
#define MOOD_EVENT_FEAR (1<<0)
|
||||
/// Relates to art
|
||||
|
||||
@@ -4,21 +4,12 @@
|
||||
scan_desc = "phobia"
|
||||
gain_text = span_warning("You start finding default values very unnerving...")
|
||||
lose_text = span_notice("You no longer feel afraid of default values.")
|
||||
/// What do we fear exactly?
|
||||
var/phobia_type
|
||||
/// Cooldown for proximity checks so we don't spam a range 7 view every two seconds.
|
||||
COOLDOWN_DECLARE(check_cooldown)
|
||||
/// Cooldown for freakouts to prevent permastunning.
|
||||
COOLDOWN_DECLARE(scare_cooldown)
|
||||
|
||||
///What mood event to apply when we see the thing & freak out.
|
||||
var/datum/mood_event/mood_event_type = /datum/mood_event/phobia
|
||||
|
||||
var/regex/trigger_regex
|
||||
//instead of cycling every atom, only cycle the relevant types
|
||||
var/list/trigger_mobs
|
||||
var/list/trigger_objs //also checked in mob equipment
|
||||
var/list/trigger_turfs
|
||||
var/list/trigger_species
|
||||
/// Specific terror handler to apply, in case we want
|
||||
var/terror_handler = /datum/terror_handler/phobia_source
|
||||
/// What mood event to apply when we see the thing & freak out.
|
||||
var/mood_event_type = /datum/mood_event/phobia
|
||||
|
||||
/datum/brain_trauma/mild/phobia/New(new_phobia_type)
|
||||
if(new_phobia_type)
|
||||
@@ -30,132 +21,22 @@
|
||||
gain_text = span_warning("You start finding [phobia_type] very unnerving...")
|
||||
lose_text = span_notice("You no longer feel afraid of [phobia_type].")
|
||||
scan_desc += " of [phobia_type]"
|
||||
trigger_regex = GLOB.phobia_regexes[phobia_type]
|
||||
trigger_mobs = GLOB.phobia_mobs[phobia_type]
|
||||
trigger_objs = GLOB.phobia_objs[phobia_type]
|
||||
trigger_turfs = GLOB.phobia_turfs[phobia_type]
|
||||
trigger_species = GLOB.phobia_species[phobia_type]
|
||||
..()
|
||||
|
||||
/datum/brain_trauma/mild/phobia/on_lose(silent)
|
||||
owner.clear_mood_event("phobia_[phobia_type]")
|
||||
return ..()
|
||||
|
||||
/datum/brain_trauma/mild/phobia/on_life(seconds_per_tick, times_fired)
|
||||
..()
|
||||
if(HAS_TRAIT(owner, TRAIT_FEARLESS))
|
||||
return
|
||||
if(owner.is_blind())
|
||||
return
|
||||
/datum/brain_trauma/mild/phobia/on_gain()
|
||||
. = ..()
|
||||
var/datum/component/fearful/fear = owner.AddComponentFrom(REF(src), /datum/component/fearful, list(/datum/terror_handler/startle))
|
||||
var/datum/terror_handler/phobia_source/phobia = fear.add_handler(terror_handler, REF(src))
|
||||
phobia.trigger_regex = GLOB.phobia_regexes[phobia_type]
|
||||
phobia.trigger_mobs = GLOB.phobia_mobs[phobia_type]
|
||||
phobia.trigger_objs = GLOB.phobia_objs[phobia_type]
|
||||
phobia.trigger_turfs = GLOB.phobia_turfs[phobia_type]
|
||||
phobia.trigger_species = GLOB.phobia_species[phobia_type]
|
||||
phobia.mood_event_type = mood_event_type
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, check_cooldown) || !COOLDOWN_FINISHED(src, scare_cooldown))
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, check_cooldown, 5 SECONDS)
|
||||
var/list/seen_atoms = view(7, owner)
|
||||
if(LAZYLEN(trigger_objs))
|
||||
for(var/obj/seen_item in seen_atoms)
|
||||
if(is_scary_item(seen_item))
|
||||
freak_out(seen_item)
|
||||
return
|
||||
|
||||
if(LAZYLEN(trigger_turfs))
|
||||
for(var/turf/checked in seen_atoms)
|
||||
if(is_type_in_typecache(checked, trigger_turfs))
|
||||
freak_out(checked)
|
||||
return
|
||||
|
||||
seen_atoms -= owner //make sure they aren't afraid of themselves.
|
||||
if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_species) || LAZYLEN(trigger_objs))
|
||||
for(var/mob/living/checked in seen_atoms)
|
||||
if (is_scary_mob(checked))
|
||||
freak_out(checked)
|
||||
return
|
||||
|
||||
/// Returns true if this item should be scary to us
|
||||
/datum/brain_trauma/mild/phobia/proc/is_scary_item(obj/checked)
|
||||
if (QDELETED(checked) || !is_type_in_typecache(checked, trigger_objs) || checked.invisibility > owner.see_invisible)
|
||||
return FALSE
|
||||
if (!isitem(checked))
|
||||
return TRUE
|
||||
var/obj/item/checked_item = checked
|
||||
return !HAS_TRAIT(checked_item, TRAIT_EXAMINE_SKIP)
|
||||
|
||||
/datum/brain_trauma/mild/phobia/proc/is_scary_mob(mob/living/checked)
|
||||
if(is_type_in_typecache(checked, trigger_mobs))
|
||||
return TRUE
|
||||
|
||||
if (!ishuman(checked))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/as_human = checked
|
||||
if (LAZYLEN(trigger_species))
|
||||
if (is_type_in_typecache(as_human.dna?.species, trigger_species))
|
||||
return TRUE
|
||||
|
||||
if (!LAZYLEN(trigger_objs))
|
||||
return FALSE
|
||||
|
||||
for(var/obj/item/equipped as anything in as_human.get_visible_items())
|
||||
if(is_scary_item(equipped))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/brain_trauma/mild/phobia/handle_hearing(datum/source, list/hearing_args)
|
||||
if(!owner.can_hear() || owner == hearing_args[HEARING_SPEAKER] || !owner.has_language(hearing_args[HEARING_LANGUAGE])) //words can't trigger you if you can't hear them *taps head*
|
||||
return
|
||||
|
||||
if(HAS_TRAIT(owner, TRAIT_FEARLESS) || !COOLDOWN_FINISHED(src, scare_cooldown))
|
||||
return
|
||||
|
||||
if(trigger_regex.Find(hearing_args[HEARING_RAW_MESSAGE]) != 0)
|
||||
addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 1 SECONDS) //to react AFTER the chat message
|
||||
hearing_args[HEARING_RAW_MESSAGE] = trigger_regex.Replace(hearing_args[HEARING_RAW_MESSAGE], "[span_phobia("$2")]$3")
|
||||
|
||||
/datum/brain_trauma/mild/phobia/handle_speech(datum/source, list/speech_args)
|
||||
if (HAS_TRAIT(owner, TRAIT_FEARLESS))
|
||||
return
|
||||
if (trigger_regex.Find(speech_args[SPEECH_MESSAGE]) == 0)
|
||||
return
|
||||
|
||||
var/stutter = prob(50)
|
||||
var/whisper = prob(30)
|
||||
|
||||
if (!stutter && !whisper)
|
||||
return
|
||||
|
||||
if (whisper)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_SMALL_VOICE
|
||||
if (stutter)
|
||||
owner.set_stutter_if_lower(4 SECONDS)
|
||||
to_chat(owner, span_warning("You struggle to say the word \"[span_phobia("[trigger_regex.group[2]]")]\"!"))
|
||||
|
||||
/datum/brain_trauma/mild/phobia/proc/freak_out(atom/reason, trigger_word)
|
||||
if(owner.stat == DEAD)
|
||||
return
|
||||
|
||||
var/message = pick("spooks you to the bone", "shakes you up", "terrifies you", "sends you into a panic", "sends chills down your spine")
|
||||
if(trigger_word)
|
||||
if (owner.has_status_effect(/datum/status_effect/minor_phobia_reaction))
|
||||
return
|
||||
to_chat(owner, span_userdanger("Hearing [span_phobia(trigger_word)] [message]!"))
|
||||
owner.apply_status_effect(/datum/status_effect/minor_phobia_reaction)
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, scare_cooldown, 12 SECONDS)
|
||||
if(mood_event_type)
|
||||
owner.add_mood_event("phobia_[phobia_type]", mood_event_type)
|
||||
|
||||
if(reason)
|
||||
to_chat(owner, span_userdanger("Seeing [span_phobia(reason.name)] [message]!"))
|
||||
else
|
||||
to_chat(owner, span_userdanger("Something [message]!"))
|
||||
|
||||
if(reason)
|
||||
owner.face_atom(reason)
|
||||
owner._pointed(reason)
|
||||
owner.apply_status_effect(/datum/status_effect/stacking/phobia_reaction, 1, mood_event_type)
|
||||
/datum/brain_trauma/mild/phobia/on_lose(silent)
|
||||
. = ..()
|
||||
owner.RemoveComponentSource(REF(src), /datum/component/fearful)
|
||||
|
||||
// Defined phobia types for badminry, not included in the RNG trauma pool to avoid diluting.
|
||||
|
||||
@@ -178,11 +59,7 @@
|
||||
/datum/brain_trauma/mild/phobia/blood
|
||||
phobia_type = "blood"
|
||||
random_gain = FALSE
|
||||
|
||||
/datum/brain_trauma/mild/phobia/blood/is_scary_item(obj/checked)
|
||||
if (GET_ATOM_BLOOD_DNA_LENGTH(checked))
|
||||
return TRUE
|
||||
return ..()
|
||||
terror_handler = /datum/terror_handler/phobia_source/blood
|
||||
|
||||
/datum/brain_trauma/mild/phobia/clowns
|
||||
phobia_type = "clowns"
|
||||
|
||||
@@ -204,7 +204,6 @@
|
||||
scan_desc = "monophobia"
|
||||
gain_text = span_warning("You feel really lonely...")
|
||||
lose_text = span_notice("You feel like you could be safe on your own.")
|
||||
var/stress = 0
|
||||
|
||||
/datum/brain_trauma/severe/monophobia/on_gain()
|
||||
. = ..()
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
/datum/terror_handler/heart_problems
|
||||
handler_type = TERROR_HANDLER_EFFECT
|
||||
default = TRUE
|
||||
COOLDOWN_DECLARE(effect_cd)
|
||||
COOLDOWN_DECLARE(message_cd)
|
||||
|
||||
/datum/terror_handler/heart_problems/tick(seconds_per_tick, terror_buildup)
|
||||
. = ..()
|
||||
@@ -67,6 +67,9 @@
|
||||
|
||||
if (terror_buildup < TERROR_BUILDUP_HEART_ATTACK || !prob(15))
|
||||
owner.adjust_oxy_loss(8)
|
||||
if (!COOLDOWN_FINISHED(src, message_cd))
|
||||
return
|
||||
COOLDOWN_START(src, message_cd, TERROR_MESSAGE_CD)
|
||||
if (terror_buildup < TERROR_BUILDUP_FEAR)
|
||||
to_chat(owner, span_warning("Your heart skips a beat."))
|
||||
else
|
||||
@@ -167,4 +170,48 @@
|
||||
deltimer(panic_end_timer)
|
||||
panic_end_timer = null
|
||||
|
||||
/datum/terror_handler/startle
|
||||
handler_type = TERROR_HANDLER_EFFECT
|
||||
COOLDOWN_DECLARE(startle_cd)
|
||||
|
||||
/datum/terror_handler/startle/tick(seconds_per_tick, terror_buildup)
|
||||
. = ..()
|
||||
if (owner.stat >= UNCONSCIOUS || !COOLDOWN_FINISHED(src, startle_cd))
|
||||
return
|
||||
|
||||
if (terror_buildup < TERROR_BUILDUP_FEAR || terror_buildup - component.last_tick_buildup < TERROR_STARTLE_MINIMUM_DIFFERENCE)
|
||||
return
|
||||
|
||||
// The more scared we are, and the more fear we acquired at once last tick, the higher the probability of us being startled is
|
||||
// Not SPT_PROB or FEAR_SCALING because this is only triggered during ticks when we actually acquire fear
|
||||
if (!prob(15 * (terror_buildup - component.last_tick_buildup) / TERROR_STARTLE_MINIMUM_DIFFERENCE * terror_buildup / TERROR_BUILDUP_FEAR))
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, startle_cd, TERROR_STARTLE_COOLDOWN)
|
||||
switch (rand(1, 3))
|
||||
if (1)
|
||||
to_chat(owner, span_warning("You are startled!"))
|
||||
owner.emote("jump")
|
||||
owner.Immobilize(0.1 SECONDS * (terror_buildup / TERROR_BUILDUP_FEAR))
|
||||
|
||||
if (2)
|
||||
owner.emote("scream")
|
||||
owner.say("AAAAH!!", forced = "phobia")
|
||||
if (!prob(15 * (terror_buildup / TERROR_BUILDUP_FEAR)))
|
||||
return
|
||||
var/held_item = owner.get_active_held_item()
|
||||
if (owner.dropItemToGround(held_item))
|
||||
owner.visible_message(
|
||||
span_danger("[owner.name] drops \the [held_item]!"),
|
||||
span_warning("You drop \the [held_item]!"), null, COMBAT_MESSAGE_RANGE)
|
||||
|
||||
if (3)
|
||||
to_chat(owner, span_warning("You lose your balance!"))
|
||||
owner.adjust_staggered_up_to(2 SECONDS * (terror_buildup / TERROR_BUILDUP_FEAR), 20 SECONDS)
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/spooked)
|
||||
addtimer(CALLBACK(src, PROC_REF(speed_up)), 3 SECONDS, TIMER_STOPPABLE | TIMER_DELETE_ME)
|
||||
|
||||
/datum/terror_handler/startle/proc/speed_up()
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/spooked)
|
||||
|
||||
#undef FEAR_SCALING
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
|
||||
/datum/component/fearful/proc/add_handler(handler_type, source)
|
||||
for (var/datum/terror_handler/existing as anything in terror_handlers)
|
||||
if (existing.type == handler_type)
|
||||
if (existing.type == handler_type && !existing.bespoke)
|
||||
terror_handlers[existing] += source
|
||||
return
|
||||
|
||||
@@ -83,6 +83,7 @@
|
||||
if (!overriden_handlers[override_type])
|
||||
overriden_handlers[override_type] = list()
|
||||
overriden_handlers[override_type][handler_type] = TRUE
|
||||
return handler
|
||||
|
||||
/datum/component/fearful/proc/get_fear_multiplier()
|
||||
var/multiplier = 1
|
||||
@@ -168,11 +169,12 @@
|
||||
)
|
||||
return COMPONENT_BLOCK_MISC_HELP
|
||||
|
||||
for (var/datum/brain_trauma/mild/phobia/phobia in source.get_traumas())
|
||||
if (!phobia.is_scary_mob(hugger))
|
||||
continue
|
||||
var/hug_buildup = 0
|
||||
for (var/datum/terror_handler/handler as anything in terror_handlers)
|
||||
hug_buildup += handler.on_hug(hugger)
|
||||
|
||||
terror_buildup += HUG_TERROR_AMOUNT
|
||||
if (hug_buildup > 0)
|
||||
terror_buildup += hug_buildup
|
||||
source.visible_message(
|
||||
span_warning("[source] recoils in fear as [hugger] attempts to hug [source.p_them()]!"),
|
||||
span_boldwarning("You recoil in terror as [hugger] attempts to hug you!"),
|
||||
|
||||
+12
-3
@@ -71,7 +71,7 @@
|
||||
. = ..()
|
||||
owner.clear_mood_event("nyctophobia")
|
||||
|
||||
// Nightmare spell version with quicker buildup that shadows the quirk one, also handles removing the status upon reaching 0 terror
|
||||
/// Nightmare spell version with quicker buildup that shadows the quirk one, also handles removing the status upon reaching 0 terror
|
||||
/datum/terror_handler/simple_source/nyctophobia/terrified
|
||||
// Takes about 30 seconds to reach maximum if you include 100 from casting the spell
|
||||
buildup_per_second = 15
|
||||
@@ -87,6 +87,7 @@
|
||||
/// Makes the owner afraid of being stuck in closets, crates, mechs, etc
|
||||
/datum/terror_handler/simple_source/claustrophobia
|
||||
buildup_per_second = 15
|
||||
COOLDOWN_DECLARE(message_cd)
|
||||
|
||||
/datum/terror_handler/simple_source/claustrophobia/Destroy(force)
|
||||
owner.clear_mood_event("claustrophobia")
|
||||
@@ -100,8 +101,9 @@
|
||||
if (isturf(owner.loc))
|
||||
return FALSE
|
||||
|
||||
if (SPT_PROB(15, seconds_per_tick))
|
||||
if (COOLDOWN_FINISHED(src, message_cd) && SPT_PROB(15, seconds_per_tick))
|
||||
to_chat(owner, span_warning("You feel trapped! Must escape... can't breathe..."))
|
||||
COOLDOWN_START(src, message_cd, TERROR_MESSAGE_CD)
|
||||
|
||||
return TRUE
|
||||
|
||||
@@ -116,6 +118,7 @@
|
||||
/// Makes the owner afraid of certain jolly figures
|
||||
/datum/terror_handler/simple_source/clausophobia
|
||||
buildup_per_second = 20
|
||||
COOLDOWN_DECLARE(message_cd)
|
||||
|
||||
/datum/terror_handler/simple_source/clausophobia/check_condition(seconds_per_tick, terror_buildup)
|
||||
. = ..()
|
||||
@@ -142,14 +145,16 @@
|
||||
if (!certified_jolly)
|
||||
return FALSE
|
||||
|
||||
if (SPT_PROB(15, seconds_per_tick))
|
||||
if (COOLDOWN_FINISHED(src, message_cd) && SPT_PROB(15, seconds_per_tick))
|
||||
to_chat(owner, span_warning("Santa Claus is here! I gotta get out of here!"))
|
||||
COOLDOWN_START(src, message_cd, TERROR_MESSAGE_CD)
|
||||
|
||||
return TRUE
|
||||
|
||||
/// Makes the owner afraid of being alone
|
||||
/datum/terror_handler/simple_source/monophobia
|
||||
buildup_per_second = 2.5 // Pretty low, ~4 minutes to reach passive cap
|
||||
COOLDOWN_DECLARE(message_cd)
|
||||
|
||||
/datum/terror_handler/simple_source/monophobia/check_condition(seconds_per_tick, terror_buildup)
|
||||
. = ..()
|
||||
@@ -167,4 +172,8 @@
|
||||
if (istype(friend, /mob/living/basic/pet) || friend.ckey)
|
||||
return FALSE
|
||||
|
||||
if (COOLDOWN_FINISHED(src, message_cd) && SPT_PROB(10, seconds_per_tick))
|
||||
to_chat(owner, span_warning("You feel terribly lonely..."))
|
||||
COOLDOWN_START(src, message_cd, TERROR_MESSAGE_CD)
|
||||
|
||||
return TRUE
|
||||
@@ -0,0 +1,170 @@
|
||||
/// Complex terror source that increases buildup whenever the owner hears, sees, or tries to say something they're afraid of
|
||||
/datum/terror_handler/phobia_source
|
||||
handler_type = TERROR_HANDLER_SOURCE
|
||||
bespoke = TRUE
|
||||
/// Last time we got scared shitless for passive increase in fear
|
||||
/// Regex for words that set the phobia off
|
||||
var/regex/trigger_regex
|
||||
// Instead of cycling every atom, only cycle the relevant types
|
||||
var/list/trigger_mobs
|
||||
/// Includes mob equipment
|
||||
var/list/trigger_objs
|
||||
var/list/trigger_turfs
|
||||
var/list/trigger_species
|
||||
/// What mood event to apply when we see the thing & freak out.
|
||||
var/mood_event_type = /datum/mood_event/phobia
|
||||
/// Cooldown for proximity checks so we don't spam a range 7 view every two seconds.
|
||||
COOLDOWN_DECLARE(check_cooldown)
|
||||
/// Cooldown for the actual scare effect so chat spam won't instantly send us spiraling
|
||||
COOLDOWN_DECLARE(scare_cooldown)
|
||||
|
||||
/datum/terror_handler/phobia_source/New(mob/living/new_owner, datum/component/fearful/new_component)
|
||||
. = ..()
|
||||
RegisterSignal(new_owner, COMSIG_MOB_SAY, PROC_REF(handle_speech))
|
||||
RegisterSignal(new_owner, COMSIG_MOVABLE_HEAR, PROC_REF(handle_hearing))
|
||||
|
||||
/datum/terror_handler/phobia_source/Destroy(force)
|
||||
UnregisterSignal(owner, list(COMSIG_MOB_SAY, COMSIG_MOVABLE_HEAR))
|
||||
return ..()
|
||||
|
||||
/datum/terror_handler/phobia_source/proc/can_trigger()
|
||||
return !HAS_TRAIT(owner, TRAIT_FEARLESS) && !HAS_TRAIT(owner, TRAIT_MIND_TEMPORARILY_GONE) && owner.stat < UNCONSCIOUS
|
||||
|
||||
/datum/terror_handler/phobia_source/tick(seconds_per_tick, terror_buildup)
|
||||
. = ..()
|
||||
if (!can_trigger())
|
||||
return
|
||||
|
||||
// If we're still scared from the last trigger, keep adding just a tiiiiny buildup to prevent it from fading away
|
||||
if (!COOLDOWN_FINISHED(src, scare_cooldown))
|
||||
return 0.01
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, check_cooldown) || owner.is_blind())
|
||||
return
|
||||
|
||||
COOLDOWN_START(src, check_cooldown, PHOBIA_CHECK_DELAY)
|
||||
if(LAZYLEN(trigger_objs))
|
||||
for (var/obj/seen_thing in view(owner.client?.view || world.view, owner))
|
||||
if(is_scary_item(seen_thing))
|
||||
return freak_out(seen_thing)
|
||||
|
||||
if(LAZYLEN(trigger_turfs))
|
||||
for(var/turf/checked in view(owner.client?.view || world.view, owner))
|
||||
if(is_type_in_typecache(checked, trigger_turfs))
|
||||
return freak_out(checked)
|
||||
|
||||
if(LAZYLEN(trigger_mobs) || LAZYLEN(trigger_species) || LAZYLEN(trigger_objs))
|
||||
for(var/mob/living/checked in view(owner.client?.view || world.view, owner))
|
||||
if (checked != owner && is_scary_mob(checked))
|
||||
return freak_out(checked)
|
||||
|
||||
/// Returns true if this item should be scary to us
|
||||
/datum/terror_handler/phobia_source/proc/is_scary_item(obj/checked)
|
||||
if (QDELETED(checked) || !is_type_in_typecache(checked, trigger_objs) || checked.invisibility > owner.see_invisible)
|
||||
return FALSE
|
||||
|
||||
if (!isitem(checked) || !ismob(checked.loc) || HAS_TRAIT(checked.loc, TRAIT_UNKNOWN_APPEARANCE))
|
||||
return TRUE
|
||||
|
||||
var/obj/item/checked_item = checked
|
||||
return !HAS_TRAIT(checked_item, TRAIT_EXAMINE_SKIP)
|
||||
|
||||
/datum/terror_handler/phobia_source/proc/is_scary_mob(mob/living/checked)
|
||||
if (checked.invisibility > owner.see_invisible || checked.alpha == 0)
|
||||
return FALSE
|
||||
|
||||
if (is_type_in_typecache(checked, trigger_mobs))
|
||||
return TRUE
|
||||
|
||||
if (!ishuman(checked))
|
||||
return FALSE
|
||||
|
||||
var/mob/living/carbon/human/as_human = checked
|
||||
if (LAZYLEN(trigger_species))
|
||||
// Can't be racist(?) if you can't see their face
|
||||
if (is_type_in_typecache(as_human.dna?.species, trigger_species) && !as_human.is_face_obscured())
|
||||
return TRUE
|
||||
|
||||
if (!LAZYLEN(trigger_objs))
|
||||
return FALSE
|
||||
|
||||
for (var/obj/item/equipped as anything in as_human.get_visible_items())
|
||||
if (is_scary_item(equipped))
|
||||
return TRUE
|
||||
|
||||
return FALSE
|
||||
|
||||
/datum/terror_handler/phobia_source/proc/handle_hearing(datum/source, list/hearing_args)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!can_trigger() || !COOLDOWN_FINISHED(src, scare_cooldown))
|
||||
return
|
||||
|
||||
// Words can't trigger you if you can't hear them *taps head*
|
||||
if(!owner.can_hear() || owner == hearing_args[HEARING_SPEAKER] || !owner.has_language(hearing_args[HEARING_LANGUAGE]))
|
||||
return
|
||||
|
||||
if(trigger_regex.Find(hearing_args[HEARING_RAW_MESSAGE]))
|
||||
// To react AFTER the chat message
|
||||
addtimer(CALLBACK(src, PROC_REF(freak_out), null, trigger_regex.group[2]), 1 SECONDS)
|
||||
hearing_args[HEARING_RAW_MESSAGE] = trigger_regex.Replace(hearing_args[HEARING_RAW_MESSAGE], "[span_phobia("$2")]$3")
|
||||
|
||||
/datum/terror_handler/phobia_source/proc/handle_speech(datum/source, list/speech_args)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if (!can_trigger())
|
||||
return
|
||||
|
||||
if (trigger_regex.Find(speech_args[SPEECH_MESSAGE]) == 0)
|
||||
return
|
||||
|
||||
var/stutter = prob(50)
|
||||
var/whisper = prob(30)
|
||||
|
||||
if (!stutter && !whisper)
|
||||
return
|
||||
|
||||
if (whisper)
|
||||
speech_args[SPEECH_SPANS] |= SPAN_SMALL_VOICE
|
||||
if (stutter)
|
||||
owner.set_stutter_if_lower(4 SECONDS)
|
||||
to_chat(owner, span_warning("You struggle to say the word \"[span_phobia("[trigger_regex.group[2]]")]\"!"))
|
||||
|
||||
/datum/terror_handler/phobia_source/proc/freak_out(reason)
|
||||
COOLDOWN_START(src, scare_cooldown, 12 SECONDS)
|
||||
var/message = pick("spooks you to the bone", "shakes you up", "terrifies you", "sends you into a panic", "sends chills down your spine")
|
||||
if(istext(reason))
|
||||
to_chat(owner, span_bolddanger("Hearing [span_phobia(reason)] [message]!"))
|
||||
owner.add_mood_event("phobia_minor", /datum/mood_event/startled)
|
||||
// Because this is called from a signal and not the main process, we need to add the buildup by hand
|
||||
if (component.terror_buildup < TERROR_BUILDUP_PASSIVE_MAXIMUM)
|
||||
component.terror_buildup = min(component.terror_buildup + PHOBIA_WORD_TERROR_BUILDUP, TERROR_BUILDUP_PASSIVE_MAXIMUM)
|
||||
return
|
||||
|
||||
if(mood_event_type)
|
||||
owner.add_mood_event("phobia", mood_event_type)
|
||||
|
||||
if(isatom(reason))
|
||||
var/atom/as_atom = reason
|
||||
to_chat(owner, span_bolddanger("Seeing [span_phobia("[as_atom.name]")] [message]!"))
|
||||
else
|
||||
to_chat(owner, span_bolddanger("Something [message]!"))
|
||||
return PHOBIA_FREAKOUT_TERROR_BUILDUP
|
||||
|
||||
/datum/terror_handler/phobia_source/on_hug(mob/living/hugger)
|
||||
if (is_scary_mob(hugger))
|
||||
return HUG_TERROR_AMOUNT
|
||||
return 0
|
||||
|
||||
/// Snowflake handler for hemophobia which triggers on bloodied items and mobs
|
||||
/datum/terror_handler/phobia_source/blood
|
||||
|
||||
/datum/terror_handler/phobia_source/blood/is_scary_item(obj/checked)
|
||||
if (GET_ATOM_BLOOD_DNA_LENGTH(checked))
|
||||
return TRUE
|
||||
return ..()
|
||||
|
||||
/datum/terror_handler/phobia_source/blood/is_scary_mob(mob/living/checked)
|
||||
if (GET_ATOM_BLOOD_DNA_LENGTH(checked))
|
||||
return TRUE
|
||||
return ..()
|
||||
@@ -11,6 +11,8 @@
|
||||
var/default = FALSE
|
||||
/// Other effects which should be disabled while this one is running
|
||||
var/list/overrides
|
||||
/// Is this handler bespoke, and always requires a new instance upon adding even when one is already present?
|
||||
var/bespoke = FALSE
|
||||
|
||||
/datum/terror_handler/New(mob/living/new_owner, datum/component/fearful/new_component)
|
||||
. = ..()
|
||||
@@ -25,3 +27,7 @@
|
||||
/// Single tick of terror handler, returns adjustment to terror buildup
|
||||
/datum/terror_handler/proc/tick(seconds_per_tick, terror_buildup)
|
||||
return 0
|
||||
|
||||
/// Additional effects when we're hugged by a mob, returns fear adjustment per hug. Should only be positive.
|
||||
/datum/terror_handler/proc/on_hug(mob/living/hugger)
|
||||
return 0
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/datum/quirk/monophobia
|
||||
name = "Monophobia"
|
||||
desc = "You have an extreme fear of loneliness, and have always tried to stick to large groups."
|
||||
icon = FA_ICON_PEOPLE_GROUP
|
||||
value = -3
|
||||
medical_record_text = "Patient has a severe fear of being left alone."
|
||||
hardcore_value = 5
|
||||
mail_goodies = list(/obj/effect/spawner/random/entertainment/plushie)
|
||||
|
||||
/datum/quirk/monophobia/add(client/client_source)
|
||||
var/mob/living/carbon/human/human_holder = quirk_holder
|
||||
human_holder.gain_trauma(new /datum/brain_trauma/severe/monophobia(), TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
|
||||
/datum/quirk/monophobia/remove()
|
||||
var/mob/living/carbon/human/human_holder = quirk_holder
|
||||
human_holder.cure_trauma_type(/datum/brain_trauma/severe/monophobia, TRAUMA_RESILIENCE_ABSOLUTE)
|
||||
@@ -1,77 +0,0 @@
|
||||
/// Basically a cooldown which makes you emote when it starts, but allows it to be easily shared between multiple phobias
|
||||
/datum/status_effect/minor_phobia_reaction
|
||||
id = "phobia_minor"
|
||||
duration = 12 SECONDS
|
||||
alert_type = null
|
||||
|
||||
/datum/status_effect/minor_phobia_reaction/on_apply()
|
||||
. = ..()
|
||||
owner.emote("scream")
|
||||
owner.set_jitter_if_lower(6 SECONDS)
|
||||
owner.add_mood_event("phobia_minor", /datum/mood_event/startled)
|
||||
|
||||
/// Stacking severity of phobic reaction
|
||||
/// The more stacks you are the more scared you are
|
||||
/datum/status_effect/stacking/phobia_reaction
|
||||
id = "phobia"
|
||||
status_type = STATUS_EFFECT_REFRESH
|
||||
stacks = 1
|
||||
max_stacks = 6
|
||||
tick_interval = 40 SECONDS
|
||||
consumed_on_threshold = FALSE
|
||||
|
||||
/datum/status_effect/stacking/phobia_reaction/on_creation(mob/living/new_owner, stacks_to_apply = 1, mood_event_type)
|
||||
. = ..()
|
||||
if (!.)
|
||||
return FALSE
|
||||
|
||||
if (mood_event_type)
|
||||
owner.add_mood_event("phobia", mood_event_type)
|
||||
return TRUE
|
||||
|
||||
/datum/status_effect/stacking/phobia_reaction/refresh(effect, stacks_to_add)
|
||||
. = ..()
|
||||
add_stacks(stacks_to_add)
|
||||
|
||||
/datum/status_effect/stacking/phobia_reaction/add_stacks(stacks_added)
|
||||
. = ..()
|
||||
if (stacks_added <= 0 || stacks <= 0)
|
||||
return
|
||||
|
||||
var/reaction = rand(1,4)
|
||||
switch(reaction)
|
||||
if(1)
|
||||
to_chat(owner, span_warning("You are startled!"))
|
||||
owner.emote("jump")
|
||||
owner.Immobilize(0.1 SECONDS * stacks)
|
||||
|
||||
if(2)
|
||||
owner.emote("scream")
|
||||
owner.say("AAAAH!!", forced = "phobia")
|
||||
|
||||
if(stacks >= 5)
|
||||
var/held_item = owner.get_active_held_item()
|
||||
if (owner.dropItemToGround(held_item))
|
||||
owner.visible_message(
|
||||
span_danger("[owner.name] drops \the [held_item]!"),
|
||||
span_warning("You drop \the [held_item]!"), null, COMBAT_MESSAGE_RANGE)
|
||||
|
||||
if(3)
|
||||
to_chat(owner, span_warning("You lose your balance!"))
|
||||
owner.adjust_staggered_up_to(2 SECONDS * stacks, 20 SECONDS)
|
||||
owner.add_movespeed_modifier(/datum/movespeed_modifier/status_effect/spooked)
|
||||
// We're relying on the fact that there's a 12 second application cooldown to not have to bother cancelling and replacing this timer
|
||||
// So if you adjust the duration keep that in mind
|
||||
addtimer(CALLBACK(src, PROC_REF(speed_up)), 1 SECONDS * stacks, TIMER_STOPPABLE | TIMER_DELETE_ME)
|
||||
|
||||
if(4)
|
||||
to_chat(owner, span_warning("You feel faint with fright!"))
|
||||
owner.adjust_dizzy_up_to(2 SECONDS * stacks, 20 SECONDS)
|
||||
owner.adjust_eye_blur_up_to(1.5 SECONDS * stacks, 6 SECONDS)
|
||||
|
||||
/datum/status_effect/stacking/phobia_reaction/fadeout_effect()
|
||||
to_chat(owner, span_notice("You calm down."))
|
||||
|
||||
/// Remove our active movespeed modifier
|
||||
/datum/status_effect/stacking/phobia_reaction/proc/speed_up()
|
||||
owner.remove_movespeed_modifier(/datum/movespeed_modifier/status_effect/spooked)
|
||||
+3
-2
@@ -1385,8 +1385,9 @@
|
||||
#include "code\datums\components\fantasy\suffixes.dm"
|
||||
#include "code\datums\components\fearful\effects.dm"
|
||||
#include "code\datums\components\fearful\fearful.dm"
|
||||
#include "code\datums\components\fearful\sources.dm"
|
||||
#include "code\datums\components\fearful\terror_handler.dm"
|
||||
#include "code\datums\components\fearful\sources\_sources.dm"
|
||||
#include "code\datums\components\fearful\sources\phobia.dm"
|
||||
#include "code\datums\components\food\decomposition.dm"
|
||||
#include "code\datums\components\food\edible.dm"
|
||||
#include "code\datums\components\food\germ_sensitive.dm"
|
||||
@@ -1887,6 +1888,7 @@
|
||||
#include "code\datums\quirks\negative_quirks\indebted.dm"
|
||||
#include "code\datums\quirks\negative_quirks\insanity.dm"
|
||||
#include "code\datums\quirks\negative_quirks\light_drinker.dm"
|
||||
#include "code\datums\quirks\negative_quirks\monophobia.dm"
|
||||
#include "code\datums\quirks\negative_quirks\mute.dm"
|
||||
#include "code\datums\quirks\negative_quirks\narcolepsy.dm"
|
||||
#include "code\datums\quirks\negative_quirks\nearsighted.dm"
|
||||
@@ -2031,7 +2033,6 @@
|
||||
#include "code\datums\status_effects\debuffs\hooked.dm"
|
||||
#include "code\datums\status_effects\debuffs\jitteriness.dm"
|
||||
#include "code\datums\status_effects\debuffs\pacifism.dm"
|
||||
#include "code\datums\status_effects\debuffs\phobia.dm"
|
||||
#include "code\datums\status_effects\debuffs\rust_corruption.dm"
|
||||
#include "code\datums\status_effects\debuffs\screen_blur.dm"
|
||||
#include "code\datums\status_effects\debuffs\screwy_hud.dm"
|
||||
|
||||
Reference in New Issue
Block a user