mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 10:43:20 +00:00
Co-authored-by: Will <7099514+Willburd@users.noreply.github.com> Co-authored-by: Cameron Lennox <killer65311@gmail.com>
293 lines
10 KiB
Plaintext
293 lines
10 KiB
Plaintext
#define MIN_DISCOMFORT_MESSAGE 50
|
|
|
|
/**
|
|
* Component that serves as a base type for detecting groups of mobs or players around us.
|
|
* It functions as a framework for lonely and agoraphobia to share large sections of code.
|
|
* Can be extended for other situations in the future.
|
|
* */
|
|
/datum/component/crowd_detection
|
|
VAR_PROTECTED/mob/living/carbon/human/human_parent
|
|
VAR_PROTECTED/discomfort = 0
|
|
VAR_PROTECTED/hallucination_cap = 25
|
|
VAR_PROTECTED/warning_cap = 400
|
|
VAR_PROTECTED/escalation_speed = 0.8
|
|
VAR_PROTECTED/only_people = FALSE
|
|
VAR_PROTECTED/invis_matters = TRUE
|
|
VAR_PROTECTED/belly_is_calming = TRUE
|
|
|
|
VAR_PRIVATE/is_calm = TRUE
|
|
VAR_PRIVATE/next_message_time = 0
|
|
|
|
/datum/component/crowd_detection/Initialize()
|
|
if(!ishuman(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
human_parent = parent
|
|
RegisterSignal(human_parent, COMSIG_LIVING_LIFE, PROC_REF(handle_life))
|
|
|
|
/datum/component/crowd_detection/Destroy(force = FALSE)
|
|
UnregisterSignal(human_parent, COMSIG_LIVING_LIFE)
|
|
human_parent = null
|
|
. = ..()
|
|
|
|
/datum/component/crowd_detection/proc/handle_life()
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
SIGNAL_HANDLER
|
|
// If they're dead or unconcious they're a bit beyond this kind of thing.
|
|
if(human_parent.stat)
|
|
discomfort = 0
|
|
return TRUE
|
|
// No point processing if we're already stressing the hell out.
|
|
if(human_parent.hallucination >= hallucination_cap && discomfort >= warning_cap)
|
|
discomfort = warning_cap
|
|
return TRUE
|
|
// I don't need to be told every 2 seconds I'm freaking out when I'm in a belly trying to WRITE!!! We can't be reasonably crowded in a belly, and won't be alone in one, so lets just handle it here.
|
|
if(isbelly(human_parent.loc))
|
|
if(belly_is_calming)
|
|
calm_discomfort()
|
|
return TRUE
|
|
// Changelings are immune to these, so we may as well stop handling it... It's unlikely you will turn back from a changeling as well.
|
|
if(human_parent.GetComponent(/datum/component/antag/changeling)) // We are never alone~
|
|
qdel(src)
|
|
return TRUE
|
|
return FALSE
|
|
|
|
/datum/component/crowd_detection/proc/increase_discomfort()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
// No company? Suffer :(
|
|
if(discomfort < warning_cap)
|
|
discomfort = min(warning_cap,discomfort+escalation_speed)
|
|
// Handle message delay
|
|
if(world.time >= next_message_time)
|
|
var/ms = get_discomfort_message(discomfort)
|
|
if(ms)
|
|
to_chat(human_parent, ms)
|
|
next_message_time = world.time + 50 SECONDS
|
|
human_parent.fear = min((human_parent.fear + 3), 102)
|
|
is_calm = FALSE // We'll only get one message early
|
|
// Hallucinations
|
|
if(discomfort >= warning_cap && human_parent.hallucination < hallucination_cap)
|
|
human_parent.hallucination = min(hallucination_cap,human_parent.hallucination+2.5*escalation_speed)
|
|
|
|
/datum/component/crowd_detection/proc/check_contents(atom/item, max_layer = 3, current_layer = 1)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
RETURN_TYPE(/list)
|
|
var/list/in_range = list()
|
|
if(!item || !istype(item) || current_layer > max_layer)
|
|
return in_range
|
|
for(var/datum/content in item.contents)
|
|
if(istype(content,/obj/item/holder))
|
|
var/obj/item/holder/contentholder = content
|
|
in_range |= check_mob_company(contentholder.held_mob)
|
|
else
|
|
in_range |= check_contents(content,max_layer,current_layer+1)
|
|
return in_range
|
|
|
|
/datum/component/crowd_detection/proc/check_mob_company(mob/living/M)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
RETURN_TYPE(/list)
|
|
var/list/in_range = list()
|
|
if(!istype(M))
|
|
return in_range
|
|
var/social_check = only_people && !istype(M, /mob/living/carbon) && !istype(M, /mob/living/silicon/robot)
|
|
var/self_invisible_check = M == human_parent || M.invisibility > human_parent.see_invisible
|
|
var/ckey_check = only_people && !M.ckey
|
|
var/overall_checks = M == human_parent || M.stat == DEAD || social_check || ckey_check
|
|
if(invis_matters && self_invisible_check)
|
|
return in_range
|
|
if((M.faction == FACTION_NEUTRAL || M.faction == human_parent.faction) && !overall_checks)
|
|
in_range |= M
|
|
else
|
|
in_range |= check_contents(M)
|
|
if(M.vore_organs)
|
|
for(var/obj/belly/B in M.vore_organs)
|
|
for(var/mob/living/content in B.contents)
|
|
if(istype(content))
|
|
in_range |= check_mob_company(content)
|
|
return in_range
|
|
|
|
/datum/component/crowd_detection/proc/get_discomfort_message(current_discomfort)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
return null
|
|
|
|
/datum/component/crowd_detection/proc/calm_discomfort(amount = 4, message = null)
|
|
SHOULD_CALL_PARENT(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
discomfort = max(discomfort - amount, 0)
|
|
if(world.time >= next_message_time && (discomfort > 0 || !is_calm))
|
|
if(message)
|
|
to_chat(human_parent, message)
|
|
if(discomfort < MIN_DISCOMFORT_MESSAGE)
|
|
is_calm = TRUE
|
|
next_message_time = world.time + 50 SECONDS
|
|
|
|
/datum/component/crowd_detection/proc/find_held_by(atom/item)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PROTECTED_PROC(TRUE)
|
|
RETURN_TYPE(/atom)
|
|
if(!item || !istype(item))
|
|
return null
|
|
else if(istype(item,/mob/living))
|
|
return item
|
|
else
|
|
return find_held_by(item.loc)
|
|
|
|
/datum/component/crowd_detection/proc/get_calm()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
return is_calm
|
|
|
|
/datum/component/crowd_detection/proc/get_discomfort()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
return discomfort
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Lonelyness
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/datum/component/crowd_detection/lonely
|
|
|
|
/datum/component/crowd_detection/lonely/major
|
|
only_people = TRUE
|
|
warning_cap = 300
|
|
hallucination_cap = 50
|
|
escalation_speed = 1.3
|
|
|
|
/datum/component/crowd_detection/lonely/handle_life()
|
|
if(..())
|
|
return
|
|
|
|
// Brain friends!
|
|
if(human_parent.has_brain_worms())
|
|
calm_discomfort()
|
|
return
|
|
|
|
// Grabbed by a mob
|
|
if(istype(human_parent.loc, /obj/item/holder))
|
|
calm_discomfort()
|
|
return
|
|
|
|
// Check for company.
|
|
if(length(check_contents(human_parent))) //Check our item slots and storage for any micros.
|
|
calm_discomfort()
|
|
return
|
|
for(var/mob/living/M in viewers(get_turf(human_parent)))
|
|
if(length(check_mob_company(M)))
|
|
calm_discomfort()
|
|
return
|
|
|
|
//Check to see if there's anyone in our belly
|
|
if(human_parent.vore_organs)
|
|
for(var/obj/belly/B in human_parent.vore_organs)
|
|
for(var/mob/living/content in B.contents)
|
|
if(istype(content))
|
|
if(length(check_mob_company(content)))
|
|
calm_discomfort()
|
|
return
|
|
|
|
//Things that are not mobs, but will calm lonelyness
|
|
for(var/obj/effect/overlay/aiholo/A in range(5, human_parent))
|
|
calm_discomfort()
|
|
return
|
|
for(var/obj/item/toy/plushie/teshari/P in range(5, human_parent))
|
|
calm_discomfort()
|
|
return
|
|
|
|
increase_discomfort()
|
|
|
|
/datum/component/crowd_detection/lonely/get_discomfort_message(var/current_discomfort)
|
|
if(current_discomfort >= warning_cap)
|
|
human_parent.stuttering += 25
|
|
return span_danger(span_bold(pick("Where are the others?", "Please, there has to be someone nearby!", "I don't want to be alone!","Please, anyone! I don't want to be alone!")))
|
|
if(current_discomfort >= 250)
|
|
if(human_parent.stuttering < hallucination_cap)
|
|
human_parent.stuttering += 5
|
|
return pick("You don't think you can last much longer without some visible company!", "You should go find someone to be with!","You need to find company!","Find someone to be with!")
|
|
if(current_discomfort >= MIN_DISCOMFORT_MESSAGE)
|
|
return pick("You begin to feel alone...","You feel isolated...","You need company...","Where is everyone?...","You need to find someone...")
|
|
if(get_calm())
|
|
return pick("Well.. No one is around you anymore...","Well.. You're alone now...","You suddenly feel alone...")
|
|
. = ..()
|
|
|
|
/datum/component/crowd_detection/lonely/calm_discomfort(var/amount = 4, var/message)
|
|
if(!message && !get_calm())
|
|
message = span_infoplain("The nearby company calms you down...")
|
|
. = ..(amount, message)
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
// Agoraphobia
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
/datum/component/crowd_detection/agoraphobia
|
|
belly_is_calming = FALSE // Stops message spam, but doesn't decrease discomfort
|
|
|
|
/datum/component/crowd_detection/agoraphobia/handle_life()
|
|
if(..())
|
|
return
|
|
|
|
var/list/in_range = list()
|
|
in_range |= check_mob_company(human_parent) //Checks our item slots and bellies for any people.
|
|
in_range |= belly_check(human_parent.loc) //Recursive check if we're in anyones bellies, are they in anyone's belly, etc.
|
|
in_range |= holder_check(human_parent.loc) //Recursive check if someone's holding us, is anyone holding them, etc.
|
|
|
|
// Check for company.
|
|
for(var/mob/living/M in viewers(get_turf(human_parent)))
|
|
in_range |= check_mob_company(M)
|
|
for(var/obj/effect/overlay/aiholo/A in range(5, human_parent))
|
|
in_range |= A
|
|
if(length(in_range) <= 2)
|
|
calm_discomfort()
|
|
return
|
|
|
|
increase_discomfort()
|
|
|
|
/datum/component/crowd_detection/agoraphobia/get_discomfort_message( current_discomfort)
|
|
if(current_discomfort >= warning_cap)
|
|
human_parent.stuttering += 25
|
|
return span_bolddanger(pick("Why am I still here? I have to leave and get some space!",
|
|
"Please, just let me be alone!",
|
|
"I need to be alone!"))
|
|
if(current_discomfort >= 250)
|
|
if(human_parent.stuttering < hallucination_cap)
|
|
human_parent.stuttering += 5
|
|
return pick("You don't think you can last much longer with this much company!", "You should go find some space!")
|
|
if(current_discomfort >= MIN_DISCOMFORT_MESSAGE)
|
|
return "You start to feel anxious from the number of people around you."
|
|
if(get_calm())
|
|
return "You notice there's more people than you feel comfortable with around you..."
|
|
. = ..()
|
|
|
|
/datum/component/crowd_detection/agoraphobia/calm_discomfort(amount = 4, message)
|
|
if(!message && !get_calm())
|
|
message = span_infoplain("You feel calmer with noone around...")
|
|
. = ..(amount, message)
|
|
|
|
/datum/component/crowd_detection/agoraphobia/proc/holder_check(obj/item/holder/H_holder)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PRIVATE_PROC(TRUE)
|
|
RETURN_TYPE(/list)
|
|
var/list/in_range = list()
|
|
if(istype(H_holder))
|
|
var/mob/living/held_by = find_held_by(H_holder)
|
|
if(held_by)
|
|
in_range |= check_mob_company(held_by)
|
|
in_range |= holder_check(human_parent,held_by)
|
|
return in_range
|
|
|
|
/datum/component/crowd_detection/agoraphobia/proc/belly_check(obj/belly/B)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
PRIVATE_PROC(TRUE)
|
|
RETURN_TYPE(/list)
|
|
var/list/in_range = list()
|
|
if(istype(B))
|
|
in_range |= check_mob_company(B.owner)
|
|
if(isbelly(B.owner.loc))
|
|
in_range |= belly_check(human_parent,B.owner.loc)
|
|
return in_range
|
|
|
|
#undef MIN_DISCOMFORT_MESSAGE
|