mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-07-12 16:37:19 +01:00
201592f6bd
Refactoring the entire destroy proc path from Mob Human all the way down to Atom while trying to find the causes for the damn mob human hard deletes. This PR comprehensively reorganizes every single stray snowflake var used by /atom/ all the way to /mob/living/carbon/human, and makes sure that every var that COULD store a reference, is now cleared during the entirety of the Mob Destroy() parent hierarchy. This may very well be the end of the lag war. In total, I've hunted down and cleared 39 hanging references between /atom and /mob/living/carbon/human --------- Signed-off-by: VMSolidus <evilexecutive@gmail.com>
301 lines
10 KiB
Plaintext
301 lines
10 KiB
Plaintext
SUBSYSTEM_DEF(virtualreality)
|
|
name = "Virtual Reality"
|
|
init_order = INIT_ORDER_MISC_FIRST
|
|
flags = SS_NO_FIRE
|
|
|
|
// MECHA
|
|
var/list/mechnetworks = list(REMOTE_GENERIC_MECH, REMOTE_AI_MECH, REMOTE_PRISON_MECH) // A list of all the networks a mech can possibly connect to
|
|
var/list/list/mechs = list() // A list of lists, containing the mechs and their networks
|
|
|
|
// IPC BODIES
|
|
var/list/robotnetworks = list(REMOTE_GENERIC_ROBOT, REMOTE_BUNKER_ROBOT, REMOTE_PRISON_ROBOT, REMOTE_WARDEN_ROBOT)
|
|
var/list/list/robots = list()
|
|
|
|
// STATIONBOUND BODIES
|
|
var/list/boundnetworks = list(REMOTE_AI_ROBOT)
|
|
var/list/list/bounded = list()
|
|
|
|
/datum/controller/subsystem/virtualreality/Initialize()
|
|
for(var/network in mechnetworks)
|
|
mechs[network] = list()
|
|
for(var/network in robotnetworks)
|
|
robots[network] = list()
|
|
for(var/network in boundnetworks)
|
|
bounded[network] = list()
|
|
|
|
return SS_INIT_SUCCESS
|
|
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/add_mech(var/mob/living/heavy_vehicle/mech, var/network)
|
|
if(mech && network)
|
|
mechs[network] += mech
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/remove_mech(var/mob/living/heavy_vehicle/mech, var/network)
|
|
if(mech && network)
|
|
mechs[network].Remove(mech)
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/add_robot(var/mob/living/robot, var/network)
|
|
if(robot && network)
|
|
robots[network] += robot
|
|
RegisterSignal(robot, COMSIG_QDELETING, PROC_REF(remove_robot), TRUE)
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/remove_robot(var/mob/living/robot, var/network)
|
|
if(robot)
|
|
if(network in robots) //This is because signals cannot pass parameters, and QDEL passes the force parameter here
|
|
robots[network].Remove(robot)
|
|
else
|
|
for(var/k in robots)
|
|
robots[k].Remove(robot)
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/add_bound(var/mob/living/silicon/bound, var/network)
|
|
if(bound && network)
|
|
bounded[network] += bound
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/remove_bound(var/mob/living/silicon/bound, var/network)
|
|
if(bound && network)
|
|
bounded[network].Remove(bound)
|
|
|
|
/// Return to original body
|
|
/mob/proc/body_return()
|
|
set name = "Return to Body"
|
|
set category = "IC"
|
|
|
|
if(old_mob)
|
|
ckey_transfer(old_mob)
|
|
languages = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
if(old_mob.client)
|
|
old_mob.client.init_verbs() // We need to have the stat panel to update, so we call this directly
|
|
to_chat(old_mob, SPAN_NOTICE("System exited safely, we hope you enjoyed your stay."))
|
|
old_mob = null
|
|
else
|
|
to_chat(src, SPAN_DANGER("Interface error, you cannot exit the system at this time."))
|
|
to_chat(src, SPAN_WARNING("Ahelp to get back into your body, a bug has occurred."))
|
|
|
|
/mob/living/silicon/body_return()
|
|
set name = "Return to Body"
|
|
set category = "IC"
|
|
|
|
if(old_mob)
|
|
ckey_transfer(old_mob)
|
|
speech_synthesizer_langs = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
if(old_mob.client)
|
|
old_mob.client.init_verbs()
|
|
to_chat(old_mob, SPAN_NOTICE("System exited safely, we hope you enjoyed your stay."))
|
|
old_mob = null
|
|
else
|
|
to_chat(src, SPAN_DANGER("Interface error, you cannot exit the system at this time."))
|
|
to_chat(src, SPAN_WARNING("Ahelp to get back into your body, a bug has occurred."))
|
|
|
|
/mob/living/simple_animal/spiderbot/body_return()
|
|
set name = "Return to Body"
|
|
set category = "IC"
|
|
|
|
if(old_mob)
|
|
ckey_transfer(old_mob)
|
|
languages = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
internal_id.access = list()
|
|
if(old_mob.client)
|
|
old_mob.client.init_verbs()
|
|
to_chat(old_mob, SPAN_NOTICE("System exited safely, we hope you enjoyed your stay."))
|
|
old_mob = null
|
|
else
|
|
to_chat(src, SPAN_DANGER("Interface error, you cannot exit the system at this time."))
|
|
to_chat(src, SPAN_WARNING("Ahelp to get back into your body, a bug has occurred."))
|
|
|
|
/mob/living/carbon/human/virtual_reality/body_return()
|
|
set name = "Return to Body"
|
|
set category = "IC"
|
|
|
|
if(old_mob)
|
|
ckey_transfer(old_mob)
|
|
languages = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
if(old_mob.client)
|
|
old_mob.client.init_verbs()
|
|
to_chat(old_mob, SPAN_NOTICE("System exited safely, we hope you enjoyed your stay."))
|
|
old_mob = null
|
|
qdel(src)
|
|
else
|
|
to_chat(src, SPAN_DANGER("Interface error, you cannot exit the system at this time."))
|
|
to_chat(src, SPAN_WARNING("Ahelp to get back into your body, a bug has occurred."))
|
|
|
|
/mob/living/proc/vr_mob_exit_languages()
|
|
languages = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
|
|
/mob/living/silicon/vr_mob_exit_languages()
|
|
..()
|
|
speech_synthesizer_langs = list(GLOB.all_languages[LANGUAGE_TCB])
|
|
|
|
// Handles saving of the original mob and assigning the new mob
|
|
/datum/controller/subsystem/virtualreality/proc/mind_transfer(var/mob/living/M, var/mob/living/target)
|
|
var/new_ckey = M.ckey
|
|
target.old_mob = M
|
|
M.vr_mob = target
|
|
target.ckey = new_ckey
|
|
M.ckey = "@[new_ckey]"
|
|
add_verb(target, /mob/proc/body_return)
|
|
|
|
target.get_vr_name(M)
|
|
M.swap_languages(target)
|
|
|
|
if(target.client)
|
|
target.client.screen |= GLOB.global_hud.vr_control
|
|
|
|
if(istype(target, /mob/living/simple_animal/spiderbot) && !istype(target, /mob/living/simple_animal/spiderbot/ai))
|
|
var/mob/living/simple_animal/spiderbot/spider = target
|
|
var/obj/item/card/id/original_id = M.GetIdCard()
|
|
if(original_id)
|
|
var/mob/living/simple_animal/spiderbot/SB = target
|
|
SB.internal_id.access = original_id.access
|
|
// Update radio
|
|
var/obj/item/encryptionkey/Key = spider.radio.keyslot
|
|
var/obj/item/radio/Radio = M.get_radio()
|
|
if(Key && Radio)
|
|
Key.channels = Radio.channels
|
|
spider.radio.recalculateChannels()
|
|
|
|
target.client.init_verbs()
|
|
to_chat(target, SPAN_NOTICE("Connection established, system suite active and calibrated."))
|
|
to_chat(target, SPAN_WARNING("To exit this mode, use the \"Return to Body\" verb in the IC tab."))
|
|
|
|
/mob/living/proc/swap_languages(var/mob/target)
|
|
target.languages = languages
|
|
if(issilicon(target))
|
|
var/mob/living/silicon/T = target
|
|
T.speech_synthesizer_langs = languages
|
|
|
|
/mob/living/silicon/swap_languages(mob/target)
|
|
target.languages = speech_synthesizer_langs
|
|
if(issilicon(target))
|
|
var/mob/living/silicon/T = target
|
|
T.speech_synthesizer_langs = speech_synthesizer_langs
|
|
|
|
/mob/proc/get_vr_name(var/mob/user)
|
|
return
|
|
|
|
/mob/living/simple_animal/spiderbot/get_vr_name(mob/user)
|
|
real_name = "Remote-Bot ([user.real_name])"
|
|
name = real_name
|
|
voice_name = user.real_name // name that'll display on radios
|
|
|
|
/mob/proc/ckey_transfer(var/mob/target, var/null_vr_mob = TRUE)
|
|
target.ckey = src.ckey
|
|
src.ckey = null
|
|
if(null_vr_mob)
|
|
target.vr_mob = null
|
|
|
|
/// Returns a list with all remote controlable exosuits on the given network
|
|
/datum/controller/subsystem/virtualreality/proc/mech_choices(var/user, var/network)
|
|
var/list/mech = list()
|
|
|
|
for(var/mob/living/heavy_vehicle/R in mechs[network])
|
|
var/turf/T = get_turf(R)
|
|
if(!T)
|
|
continue
|
|
if(!is_station_level(T.z))
|
|
continue
|
|
if(!R.remote)
|
|
continue
|
|
if(!R.pilots.len)
|
|
continue
|
|
var/mob/living/mech_pilot = R.pilots[1]
|
|
if(mech_pilot.client || mech_pilot.ckey)
|
|
continue
|
|
if(mech_pilot.stat == DEAD)
|
|
continue
|
|
mech[R.name] = R
|
|
|
|
return mech
|
|
|
|
/// Retrieves a list returned by mech_choices and prompts user to select an option to transfer to
|
|
/datum/controller/subsystem/virtualreality/proc/mech_selection(var/user, var/network)
|
|
var/list/remote = mech_choices(user, network)
|
|
if(!length(remote))
|
|
to_chat(user, SPAN_WARNING("No active remote mechs are available."))
|
|
return
|
|
|
|
var/choice = tgui_input_list(usr, "Please select a remote control compatible mech to take over.", "Remote Mech Selection", remote)
|
|
if(!choice)
|
|
return
|
|
|
|
var/mob/living/heavy_vehicle/chosen_mech = remote[choice]
|
|
var/mob/living/remote_pilot = chosen_mech.pilots[1] // the first pilot
|
|
mind_transfer(user, remote_pilot)
|
|
|
|
|
|
/// Returns a list with all remote controlable robots on the given network
|
|
/datum/controller/subsystem/virtualreality/proc/robot_choices(var/user, var/network)
|
|
var/list/robot = list()
|
|
|
|
for(var/mob/living/R in robots[network])
|
|
var/turf/T = get_turf(R)
|
|
if(!T)
|
|
continue
|
|
if(!is_station_level(T.z))
|
|
continue
|
|
if(R.client || R.ckey)
|
|
continue
|
|
if(R.stat == DEAD)
|
|
continue
|
|
robot[R.name] = R
|
|
|
|
return robot
|
|
|
|
/// Retrieves a list returned by robot_choices and prompts user to select an option to transfer to
|
|
/datum/controller/subsystem/virtualreality/proc/robot_selection(var/user, var/network)
|
|
var/list/remote = robot_choices(user, network)
|
|
if(!length(remote))
|
|
to_chat(user, SPAN_WARNING("No active remote units are available."))
|
|
|
|
var/choice = tgui_input_list(usr, "Please select a remote control unit to take over.", "Remote Unit Selection", remote)
|
|
if(!(choice in remote))
|
|
return
|
|
|
|
mind_transfer(user, choice)
|
|
|
|
/// Returns a list with all remote controlable bound on the given network
|
|
/datum/controller/subsystem/virtualreality/proc/bound_choices(var/user, var/network)
|
|
var/list/bound = list()
|
|
|
|
for(var/mob/living/silicon/R in bounded[network])
|
|
var/turf/T = get_turf(R)
|
|
if(!T)
|
|
continue
|
|
if(!is_station_level(T.z))
|
|
continue
|
|
if(R.client || R.ckey)
|
|
continue
|
|
if(R.stat == DEAD)
|
|
continue
|
|
bound += R
|
|
|
|
return bound
|
|
|
|
/// Retrieves a list returned by bound_choices and prompts user to select an option to transfer to
|
|
/datum/controller/subsystem/virtualreality/proc/bound_selection(var/user, var/network)
|
|
var/list/remote = bound_choices(user, network)
|
|
if(!length(remote))
|
|
to_chat(user, SPAN_WARNING("No active remote units are available."))
|
|
|
|
var/choice = tgui_input_list(usr, "Please select a remote control unit to take over.", "Remote Unit Selection", remote)
|
|
if(!(choice in remote))
|
|
return
|
|
|
|
mind_transfer(user, choice)
|
|
|
|
|
|
/datum/controller/subsystem/virtualreality/proc/create_virtual_reality_avatar(var/mob/living/carbon/human/user)
|
|
if(GLOB.virtual_reality_spawn.len)
|
|
var/mob/living/carbon/human/virtual_reality/H = new /mob/living/carbon/human/virtual_reality(pick(GLOB.virtual_reality_spawn))
|
|
H.set_species(user.species.name, 1)
|
|
|
|
H.gender = user.gender
|
|
H.dna = user.dna.Clone()
|
|
H.real_name = user.real_name
|
|
H.UpdateAppearance()
|
|
|
|
H.preEquipOutfit(/obj/outfit/admin/virtual_reality, FALSE)
|
|
H.equipOutfit(/obj/outfit/admin/virtual_reality, FALSE)
|
|
|
|
mind_transfer(user, H)
|
|
to_chat(H, SPAN_NOTICE("You are now in control of a virtual reality body. Dying will return you to your original body."))
|