Files
Bubberstation/code/datums/brain_damage/split_personality.dm
SkyratBot c1163dff19 [MIRROR] EVEN MORE HARDDEL FIXES (#7017)
* EVEN MORE HARDDEL FIXES (#60228)

Fixes a ton of harddels, sourced from #59996
I think this brings us down to like, ~100 per round from ~200, with only like 20 of those being proper hell failures. I've seen harddel profiles below 1 second of total cost. Feeling good.

See you on the other side

Makes the cryopod control computer into a weakref, never trust bee code
Converts brig door timer internal lists to weakrefs
Fixes a harddel caused by qdeling a motion sensitive camera after it had left its source area, jesus christ why didn't we do this already holy shit
Converts the radio implant ref held by the antenna mutation to weakrefs because it isn't reliably cleaned up, makes the radio implant actually qdel its fucking radio
Removes the target var from the throwing datum, it does literally nothing and just exists to cause harddels, mostly for the singularity
 Fixes a cable harddel sourced from things that try to enter blueprints after smoothing, but before roundstart. IE, shuttles. Removes shuttles from the blueprints
Fixes emmisive blockers being added post qdel
Removes some manual ghosting from cryopods, I initially did this for harddel reasons, but I figured out a better fix for that. I'm now doing it because it's got this really strange logic for like "re-entering the game" that doesn't actually link to what the ghostize proc does. We should remove this at some point
Fixes robot hud objects harddeling due to hanging refs
Fixes buildmode related hanging refs, I'm coming for you admin team
Fixes a few instances of trying to add the forensics component post qdel, hhhhhhhhhhh
Fixes some split personality harddels/weirdness
Replaces a use of disconnect_duct with an init qdel hint, I suspect there's more issues with duct harddels, I've seen some odd logs about ahhh the area_contents list, but we can worry about that later
Makes teleporter targets into weakrefs, properly types them as /atom
Makes frequency devices into weakrefs
Makes cameras remove themselves from camera nets on Destroy
Makes tgui ui datums implement destroy, this means if I ever see one hang a ref to user or whatever, I know there's an error with calling close() properly. I've seen this harddel once, but not after this change so I assume there was some error with close(). IDK maybe this is a papering over? Would have to ask @ stylemistake
I've seen logs of beartraps being in world post del, putting a return there just in case. The same is true of nerf darts, but I haven't really looked into that yet
Makes a shoe's ref to untying alerts a weakref, yes this is needed.
Moves clearing client_in_contents to the Login of the new mob. This prevents doing things like ghosting someone before a mob qdel causing harddels
Fixes a harddel set sourced from adding a status effect to a qdeleted thing. Is this an error? I'm honestly not sure.
Converts bsa code to weakrefs
Converts the partner var of heat exchangers to weakrefs
Converts camera assemblies to weakrefs
Fixes some dumb behavior with ammo casings and assuming you'll be on a turf post Destroy parent call
Fixes? merger related harddels, you were never cleared from your own members list, so origin objects would end up making a new list, creating harddels. Potential input from @ ninjanomnom about the logic
Chasms store a static list of "falling atoms", which only exists for chasms that go somewhere else. This list wasn't being cleared of qdeleted objects, which is what happens when you fall in most chasms. Fixes this, and converts the list to weakrefs.
Fixes some runtimes in both sheet code, and the weather listener element. This is here because runtime spam made testing more of a pain, didn't think it needed its own pr
Fixes colorful reagent harddels sourced from reagents that were qdel'd before roundstart. I'm only like 50% sure this actually got it, but the issue may have been solved by #60174, so eh
Turns the nuke op antag datum's ref to the war button into a weakref
Fixes some holopad code that was not nulling refs all the time
Converts camera bugs to weakrefs, this was the result of the bug being "reworked" like 6 years back without taking the existing ref clearing into account. Whole item needs a redo, but this'll do for now.
Ensures that the both pulling and pullee refs are cleared on Destroy
The crew monitor held all users in a non clearing list, makes that list a weakref because I hate everything

Oh and I removed all sources of gas_mixture qdeletion, I'm kinda unsure on this since it's not technically supported, but any harddels from it might? indicate something going wrong with like, gas passing logic. I'd like @ MrStonedOne's thoughts, since I trust him to call me an idiot if I'm wrong.

<!-- Please add a short description of why you think these changes would benefit the game. If you can't justify it in words, it might not be worth adding. -->

## Why it's not good for the game

I crashed sybil like 10 times to get this data, I'm gonna put it to good use. Don't think you're safe sybilites, I'm coming for you.

* EVEN MORE HARDDEL FIXES

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
2021-07-20 12:59:41 +02:00

248 lines
9.0 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 class='warning'>You feel like your mind was split in two.</span>"
lose_text = "<span class='notice'>You feel alone again.</span>"
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
/datum/brain_trauma/severe/split_personality/on_gain()
var/mob/living/M = owner
if(M.stat == DEAD || !M.client) //No use assigning people to a corpse or braindead
qdel(src)
return
..()
make_backseats()
get_ghost()
/datum/brain_trauma/severe/split_personality/proc/make_backseats()
stranger_backseat = new(owner, src)
var/obj/effect/proc_holder/spell/targeted/personality_commune/stranger_spell = new(src)
stranger_backseat.AddSpell(stranger_spell)
owner_backseat = new(owner, src)
var/obj/effect/proc_holder/spell/targeted/personality_commune/owner_spell = new(src)
owner_backseat.AddSpell(owner_spell)
/datum/brain_trauma/severe/split_personality/proc/get_ghost()
set waitfor = FALSE
var/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner.real_name]'s split personality?", ROLE_PAI, null, 75, stranger_backseat, POLL_IGNORE_SPLITPERSONALITY)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
log_game("[key_name(stranger_backseat)] became [key_name(owner)]'s split personality.")
message_admins("[ADMIN_LOOKUPFLW(stranger_backseat)] became [ADMIN_LOOKUPFLW(owner)]'s split personality.")
else
qdel(src)
/datum/brain_trauma/severe/split_personality/on_life(delta_time, times_fired)
if(owner.stat == DEAD)
if(current_controller != OWNER)
switch_personalities(TRUE)
qdel(src)
else if(DT_PROB(1.5, delta_time))
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/Destroy()
if(stranger_backseat)
QDEL_NULL(stranger_backseat)
if(owner_backseat)
QDEL_NULL(owner_backseat)
return ..()
/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
log_game("[key_name(current_backseat)] assumed control of [key_name(owner)] due to [src]. (Original owner: [current_controller == OWNER ? owner.key : current_backseat.key])")
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(delta_time = 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/say(message, bubble_type, list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
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)
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 class='notice'>You are free of your brainwashing.</span>"
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/list/mob/dead/observer/candidates = pollCandidatesForMob("Do you want to play as [owner.real_name]'s brainwashed mind?", null, null, 75, stranger_backseat)
if(LAZYLEN(candidates))
var/mob/dead/observer/C = pick(candidates)
stranger_backseat.key = C.key
else
qdel(src)
/datum/brain_trauma/severe/split_personality/brainwashing/on_life(delta_time, times_fired)
return //no random switching
/datum/brain_trauma/severe/split_personality/brainwashing/handle_hearing(datum/source, list/hearing_args)
if(HAS_TRAIT(owner, TRAIT_DEAF) || owner == hearing_args[HEARING_SPEAKER])
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, /datum/brain_trauma/severe/split_personality.proc/switch_personalities), 10)
/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."))
#undef OWNER
#undef STRANGER