Files
Bubberstation/code/datums/brain_damage/split_personality.dm
MrMelbert ca6bd55664 Revert #92696: "Refactor split personality to use temporary body component and client switching" (#93258)
## About The Pull Request

IDK if temporary body is broken or split personality is broken but it
seems like this code simply doesn't work, as split personalities are
consistently being ghosted and forced DNR

## Changelog

🆑 Melbert
fix: Blackout drunk / Split personality no longer ghosts you
/🆑
2025-11-01 13:38:40 +01:00

344 lines
13 KiB
Plaintext

#define OWNER 0
#define STRANGER 1
/datum/brain_trauma/severe/split_personality
name = "Split Personality"
desc = "Patient's brain is split into two personalities, which randomly switch control of the body."
scan_desc = "complete lobe separation"
gain_text = span_warning("You feel like your mind was split in two.")
lose_text = span_notice("You feel alone again.")
var/current_controller = OWNER
var/initialized = FALSE //to prevent personalities deleting themselves while we wait for ghosts
var/mob/living/split_personality/stranger_backseat //there's two so they can swap without overwriting
var/mob/living/split_personality/owner_backseat
///The role to display when polling ghost
var/poll_role = "split personality"
///How long do we give ghosts to respond?
var/poll_time = 20 SECONDS
/datum/brain_trauma/severe/split_personality/on_gain()
var/mob/living/brain_owner = owner
if(brain_owner.stat == DEAD || !GET_CLIENT(brain_owner) || istype(get_area(brain_owner), /area/deathmatch)) //No use assigning people to a corpse or braindead
return FALSE
. = ..()
make_backseats()
#ifdef UNIT_TESTS
return // There's no ghosts in the unit test
#endif
get_ghost()
/datum/brain_trauma/severe/split_personality/proc/make_backseats()
stranger_backseat = new(owner, src)
var/datum/action/personality_commune/stranger_spell = new(src)
stranger_spell.Grant(stranger_backseat)
owner_backseat = new(owner, src)
var/datum/action/personality_commune/owner_spell = new(src)
owner_spell.Grant(owner_backseat)
/// Attempts to get a ghost to play the personality
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
question = "Do you want to play as [span_danger("[owner.real_name]'s")] [span_notice(poll_role)]?",
check_jobban = ROLE_PAI,
poll_time = poll_time,
checked_target = owner,
ignore_category = POLL_IGNORE_SPLITPERSONALITY,
alert_pic = owner,
role_name_text = poll_role,
)
schism(chosen_one)
/// Ghost poll has concluded
/datum/brain_trauma/severe/split_personality/proc/schism(mob/dead/observer/ghost)
if(isnull(ghost))
qdel(src)
return
stranger_backseat.PossessByPlayer(ghost.ckey)
stranger_backseat.log_message("became [key_name(owner)]'s split personality.", LOG_GAME)
message_admins("[ADMIN_LOOKUPFLW(stranger_backseat)] became [ADMIN_LOOKUPFLW(owner)]'s split personality.")
/datum/brain_trauma/severe/split_personality/on_life(seconds_per_tick, times_fired)
if(owner.stat == DEAD)
if(current_controller != OWNER)
switch_personalities(TRUE)
qdel(src)
else if(SPT_PROB(1.5, seconds_per_tick))
switch_personalities()
..()
/datum/brain_trauma/severe/split_personality/on_lose()
if(current_controller != OWNER) //it would be funny to cure a guy only to be left with the other personality, but it seems too cruel
switch_personalities(TRUE)
QDEL_NULL(stranger_backseat)
QDEL_NULL(owner_backseat)
..()
/datum/brain_trauma/severe/split_personality/proc/switch_personalities(reset_to_owner = FALSE)
if(QDELETED(owner) || QDELETED(stranger_backseat) || QDELETED(owner_backseat))
return
var/mob/living/split_personality/current_backseat
var/mob/living/split_personality/new_backseat
if(current_controller == STRANGER || reset_to_owner)
current_backseat = owner_backseat
new_backseat = stranger_backseat
else
current_backseat = stranger_backseat
new_backseat = owner_backseat
if(!current_backseat.client) //Make sure we never switch to a logged off mob.
return
current_backseat.log_message("assumed control of [key_name(owner)] due to [src]. (Original owner: [current_controller == OWNER ? owner.key : current_backseat.key])", LOG_GAME)
to_chat(owner, span_userdanger("You feel your control being taken away... your other personality is in charge now!"))
to_chat(current_backseat, span_userdanger("You manage to take control of your body!"))
//Body to backseat
var/h2b_id = owner.computer_id
var/h2b_ip= owner.lastKnownIP
owner.computer_id = null
owner.lastKnownIP = null
new_backseat.ckey = owner.ckey
new_backseat.name = owner.name
if(owner.mind)
new_backseat.mind = owner.mind
if(!new_backseat.computer_id)
new_backseat.computer_id = h2b_id
if(!new_backseat.lastKnownIP)
new_backseat.lastKnownIP = h2b_ip
if(reset_to_owner && new_backseat.mind)
new_backseat.ghostize(FALSE)
//Backseat to body
var/s2h_id = current_backseat.computer_id
var/s2h_ip= current_backseat.lastKnownIP
current_backseat.computer_id = null
current_backseat.lastKnownIP = null
owner.ckey = current_backseat.ckey
owner.mind = current_backseat.mind
if(!owner.computer_id)
owner.computer_id = s2h_id
if(!owner.lastKnownIP)
owner.lastKnownIP = s2h_ip
current_controller = !current_controller
/mob/living/split_personality
name = "split personality"
real_name = "unknown conscience"
var/mob/living/carbon/body
var/datum/brain_trauma/severe/split_personality/trauma
/mob/living/split_personality/Initialize(mapload, _trauma)
if(iscarbon(loc))
body = loc
name = body.real_name
real_name = body.real_name
trauma = _trauma
return ..()
/mob/living/split_personality/Life(seconds_per_tick = SSMOBS_DT, times_fired)
if(QDELETED(body))
qdel(src) //in case trauma deletion doesn't already do it
if((body.stat == DEAD && trauma.owner_backseat == src))
trauma.switch_personalities()
qdel(trauma)
//if one of the two ghosts, the other one stays permanently
if(!body.client && trauma.initialized)
trauma.switch_personalities()
qdel(trauma)
..()
/mob/living/split_personality/Login()
. = ..()
if(!. || !client)
return FALSE
to_chat(src, span_notice("As a split personality, you cannot do anything but observe. However, you will eventually gain control of your body, switching places with the current personality."))
to_chat(src, span_warning("<b>Do not commit suicide or put the body in a deadly position. Behave like you care about it as much as the owner.</b>"))
/mob/living/split_personality/try_speak(message, ignore_spam, forced, filterproof)
SHOULD_CALL_PARENT(FALSE)
to_chat(src, span_warning("You cannot speak, your other self is controlling your body!"))
return FALSE
/mob/living/split_personality/emote(act, m_type = null, message = null, intentional = FALSE, force_silence = FALSE, forced = FALSE)
return FALSE
///////////////BRAINWASHING////////////////////
/datum/brain_trauma/severe/split_personality/brainwashing
name = "Split Personality"
desc = "Patient's brain is split into two personalities, which randomly switch control of the body."
scan_desc = "complete lobe separation"
gain_text = ""
lose_text = span_notice("You are free of your brainwashing.")
can_gain = FALSE
var/codeword
var/objective
/datum/brain_trauma/severe/split_personality/brainwashing/New(obj/item/organ/brain/B, _permanent, _codeword, _objective)
..()
if(_codeword)
codeword = _codeword
else
codeword = pick(strings("ion_laws.json", "ionabstract")\
| strings("ion_laws.json", "ionobjects")\
| strings("ion_laws.json", "ionadjectives")\
| strings("ion_laws.json", "ionthreats")\
| strings("ion_laws.json", "ionfood")\
| strings("ion_laws.json", "iondrinks"))
/datum/brain_trauma/severe/split_personality/brainwashing/on_gain()
. = ..()
var/mob/living/split_personality/traitor/traitor_backseat = stranger_backseat
traitor_backseat.codeword = codeword
traitor_backseat.objective = objective
/datum/brain_trauma/severe/split_personality/brainwashing/make_backseats()
stranger_backseat = new /mob/living/split_personality/traitor(owner, src, codeword, objective)
owner_backseat = new(owner, src)
/datum/brain_trauma/severe/split_personality/brainwashing/get_ghost()
set waitfor = FALSE
var/mob/chosen_one = SSpolling.poll_ghosts_for_target("Do you want to play as [span_danger("[owner.real_name]'s")] brainwashed mind?", poll_time = 7.5 SECONDS, checked_target = stranger_backseat, alert_pic = owner, role_name_text = "brainwashed mind")
if(chosen_one)
stranger_backseat.PossessByPlayer(chosen_one.ckey)
else
qdel(src)
/datum/brain_trauma/severe/split_personality/brainwashing/on_life(seconds_per_tick, times_fired)
return //no random switching
/datum/brain_trauma/severe/split_personality/brainwashing/handle_hearing(datum/source, list/hearing_args)
if(!owner.can_hear() || owner == hearing_args[HEARING_SPEAKER] || !owner.has_language(hearing_args[HEARING_LANGUAGE]))
return
var/message = hearing_args[HEARING_RAW_MESSAGE]
if(findtext(message, codeword))
hearing_args[HEARING_RAW_MESSAGE] = replacetext(message, codeword, span_warning("[codeword]"))
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/brain_trauma/severe/split_personality, switch_personalities)), 1 SECONDS)
/datum/brain_trauma/severe/split_personality/brainwashing/handle_speech(datum/source, list/speech_args)
if(findtext(speech_args[SPEECH_MESSAGE], codeword))
speech_args[SPEECH_MESSAGE] = "" //oh hey did you want to tell people about the secret word to bring you back?
/mob/living/split_personality/traitor
name = "split personality"
real_name = "unknown conscience"
var/objective
var/codeword
/mob/living/split_personality/traitor/Login()
. = ..()
if(!. || !client)
return FALSE
to_chat(src, span_notice("As a brainwashed personality, you cannot do anything yet but observe. However, you may gain control of your body if you hear the special codeword, switching places with the current personality."))
to_chat(src, span_notice("Your activation codeword is: <b>[codeword]</b>"))
if(objective)
to_chat(src, span_notice("Your master left you an objective: <b>[objective]</b>. Follow it at all costs when in control."))
/datum/brain_trauma/severe/split_personality/blackout
name = "Alcohol-Induced CNS Impairment"
desc = "Patient's CNS has been temporarily impaired by imbibed alcohol, blocking memory formation, and causing reduced cognition and stupefaction."
scan_desc = "alcohol-induced CNS impairment"
gain_text = span_warning("Crap, that was one drink too many. You black out...")
lose_text = "You wake up very, very confused and hungover. All you can remember is drinking a lot of alcohol... what happened?"
poll_role = "blacked out drunkard"
random_gain = FALSE
poll_time = 10 SECONDS
/// Duration of effect, tracked in seconds, not deciseconds. qdels when reaching 0.
var/duration_in_seconds = 180
/datum/brain_trauma/severe/split_personality/blackout/on_gain()
. = ..()
if(QDELETED(src))
return
RegisterSignal(owner, COMSIG_ATOM_SPLASHED, PROC_REF(on_splashed))
notify_ghosts(
"[owner.real_name] is blacking out!",
source = owner,
header = "Bro I'm not even drunk right now",
notify_flags = NOTIFY_CATEGORY_NOFLASH,
)
var/datum/status_effect/inebriated/inebriation = owner.has_status_effect(/datum/status_effect/inebriated)
inebriation?.iron_liver = TRUE
/datum/brain_trauma/severe/split_personality/blackout/on_lose()
. = ..()
owner.add_mood_event("hang_over", /datum/mood_event/hang_over)
UnregisterSignal(owner, COMSIG_ATOM_SPLASHED)
var/datum/status_effect/inebriated/inebriation = owner.has_status_effect(/datum/status_effect/inebriated)
inebriation?.iron_liver = FALSE
/datum/brain_trauma/severe/split_personality/blackout/proc/on_splashed()
SIGNAL_HANDLER
if(prob(20))//we don't want every single splash to wake them up now do we
qdel(src)
/datum/brain_trauma/severe/split_personality/blackout/on_life(seconds_per_tick, times_fired)
if(current_controller == OWNER && stranger_backseat)//we should only start transitioning after the other personality has entered
owner.overlay_fullscreen("fade_to_black", /atom/movable/screen/fullscreen/blind)
owner.clear_fullscreen("fade_to_black", animated = 4 SECONDS)
switch_personalities()
if(owner.stat == DEAD)
if(current_controller != OWNER)
switch_personalities(TRUE)
qdel(src)
return
if(duration_in_seconds <= 0)
qdel(src)
return
else if(duration_in_seconds <= 60 && !(duration_in_seconds % 20))
to_chat(owner, span_warning("You have [duration_in_seconds] seconds left before sobering up!"))
if(prob(10) && !HAS_TRAIT(owner, TRAIT_DISCOORDINATED_TOOL_USER))
ADD_TRAIT(owner, TRAIT_DISCOORDINATED_TOOL_USER, TRAUMA_TRAIT)
owner.balloon_alert(owner, "dexterity reduced temporarily!")
//We then send a callback to automatically re-add the trait
addtimer(TRAIT_CALLBACK_REMOVE(owner, TRAIT_DISCOORDINATED_TOOL_USER, TRAUMA_TRAIT), 10 SECONDS)
addtimer(CALLBACK(owner, TYPE_PROC_REF(/atom, balloon_alert), owner, "dexterity regained!"), 10 SECONDS)
if(prob(15))
playsound(owner,'sound/mobs/humanoids/human/hiccup/sf_hiccup_male_01.ogg', 50)
owner.emote("hiccup")
//too drunk to feel anything
//if they're to this point, they're likely dying of liver damage
//and not accounting for that, the split personality is temporary
owner.adjustStaminaLoss(-25)
duration_in_seconds -= seconds_per_tick
/mob/living/split_personality/blackout
name = "blacked-out drunkard"
real_name = "drunken consciousness"
/mob/living/split_personality/blackout/Login()
. = ..()
if(!. || !client)
return FALSE
to_chat(src, span_notice("You're the incredibly inebriated leftovers of your host's consciousness! Make sure to act the part and leave a trail of confusion and chaos in your wake."))
to_chat(src, span_boldwarning("While you're drunk, you're not suicidal. Do not commit suicide or put the body in danger. You have a minor license to grief just like a clown, but do not kill anyone or create a situation leading to the body being put in danger or at risk of being harmed."))
#undef OWNER
#undef STRANGER