VR, Remote Mechs and Remote Robots (#7523)

Adds VR functionality, subsystem and a command VR system.
This commit is contained in:
Geeves
2020-01-12 15:09:48 +02:00
committed by Matt Atlas
parent 8e71fe07c2
commit 2fed43a871
20 changed files with 579 additions and 49 deletions

View File

@@ -0,0 +1,149 @@
/var/global/datum/controller/subsystem/virtualreality/SSvirtualreality
/datum/controller/subsystem/virtualreality
name = "Virtual Reality"
init_order = SS_INIT_MISC_FIRST
flags = SS_NO_FIRE
// MECHA
var/list/mechnetworks = list("remotemechs", "prisonmechs") // A list of all the networks a mech can possibly connect to
var/list/mechs = list() // A list of lists, containing the mechs and their networks
// IPC BODIES
var/list/robotnetworks = list("remoterobots", "bunkerrobots")
var/list/robots = list()
/datum/controller/subsystem/virtualreality/New()
NEW_SS_GLOBAL(SSvirtualreality)
/datum/controller/subsystem/virtualreality/Initialize()
for(var/network in mechnetworks)
mechs[network] = list()
for(var/network in robotnetworks)
robots[network] = list()
..()
/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
/datum/controller/subsystem/virtualreality/proc/remove_robot(var/mob/living/robot, var/network)
if(robot && network)
robots[network].Remove(robot)
/mob/living/
var/mob/living/vr_mob = null // In which mob is our mind
var/mob/living/old_mob = null // Which mob is our old mob
// Return to our original body
/mob/living/proc/body_return()
set name = "Return to Body"
set category = "IC"
if(!vr_mob && !old_mob)
return
if(vr_mob)
ckey = vr_mob.ckey
vr_mob.ckey = null
vr_mob.old_mob = null
vr_mob.languages = list(LANGUAGE_TCB)
vr_mob = null
to_chat(src, span("notice", "System exited safely, we hope you enjoyed your stay."))
if(old_mob)
old_mob.ckey = ckey
ckey = null
old_mob.vr_mob = null
languages = list(LANGUAGE_TCB)
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."))
// 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]"
target.verbs += /mob/living/proc/body_return
target.languages = M.languages
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."))
/datum/controller/subsystem/virtualreality/proc/mech_selection(var/user, var/network)
var/list/mech = list()
mech["Return"] = null
for(var/mob/living/heavy_vehicle/R in mechs[network])
var/turf/T = get_turf(R)
if(!T)
continue
if(isNotStationLevel(T.z))
continue
if(!R.remote)
continue
if(!R.pilots.len)
continue
if(R.pilots[1].client || R.pilots[1].ckey)
continue
if(R.pilots[1].stat == DEAD)
continue
mech[R.name] = R
if(mech.len == 1)
to_chat(user, span("warning", "No active remote mechs are available."))
return
var/desc = input("Please select a remote control compatible mech to take over.", "Remote Mech Selection") in mech|null
if(!desc)
return
var/mob/living/heavy_vehicle/chosen_mech = mech[desc]
var/mob/living/remote_pilot = chosen_mech.pilots[1] // the first pilot
mind_transfer(user, remote_pilot)
return
/datum/controller/subsystem/virtualreality/proc/robot_selection(var/user, var/network)
var/list/robot = list()
robot["Return"] = null
for(var/mob/living/R in robots[network])
var/turf/T = get_turf(R)
if(!T)
continue
if(isNotStationLevel(T.z))
continue
if(R.client || R.ckey)
continue
if(R.stat == DEAD)
continue
robot[R.name] = R
if(robot.len == 1)
to_chat(user, span("warning", "No active remote robots are available."))
return
var/desc = input("Please select a remote control robot to take over.", "Remote Robot Selection") in robot|null
if(!desc)
return
mind_transfer(user, robot[desc])
return

View File

@@ -0,0 +1,26 @@
/obj/structure/bed/chair/remote
name = "virtual reality centre"
desc = "A comfortable chair with full audio-visual transposition centres."
icon_state = "shuttlechair_down"
can_dismantle = FALSE
var/list/remote_network // Which network does this remote control belong to?
/obj/structure/bed/chair/remote/update_icon()
return
/obj/structure/bed/chair/remote/user_buckle_mob(mob/user)
..()
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.old_mob)
to_chat(H, span("warning", "The chair rejects you! You cannot recursively control bodies."))
return
add_overlay(image('icons/obj/furniture.dmi', src, "vr_helmet", MOB_LAYER + 1))
// Return to our body in the unfortunate event that we get unbuckled while plugged in
/obj/structure/bed/chair/remote/user_unbuckle_mob(mob/user)
if(ishuman(user))
var/mob/living/carbon/human/H = user
H.body_return()
cut_overlays()
..()

View File

@@ -0,0 +1,15 @@
/obj/structure/bed/chair/remote/mech
name = "mech control centre"
desc = "A comfortable chair with full audio-visual transposition centres. This one gives you access to exosuits attached to the remote network."
remote_network = "remotemechs"
/obj/structure/bed/chair/remote/mech/user_buckle_mob(mob/user)
..()
if(ishuman(user))
var/mob/living/carbon/human/H = user
SSvirtualreality.mech_selection(H, remote_network)
/obj/structure/bed/chair/remote/mech/prison
name = "brig mech control centre"
desc = "A comfortable chair with full audio-visual transposition centres. This one gives you access to exosuits attached to the brig network."
remote_network = "prisonmechs"

View File

@@ -0,0 +1,15 @@
/obj/structure/bed/chair/remote/robot
name = "robot control centre"
desc = "A comfortable chair with full audio-visual transposition centres. This one gives you access to robots attached to the remote network."
remote_network = "remoterobots"
/obj/structure/bed/chair/remote/robot/user_buckle_mob(mob/user)
..()
if(ishuman(user))
var/mob/living/carbon/human/H = user
SSvirtualreality.robot_selection(H, remote_network)
/obj/structure/bed/chair/remote/robot/bunker
name = "bunker robot control centre"
desc = "A comfortable chair with full audio-visual transposition centres. This one gives you access to robots attached to the bunker network."
remote_network = "bunkerrobots"

View File

@@ -203,6 +203,9 @@
icon_state = "hardpoint_lock"
/obj/screen/movable/mecha/toggle/hardpoint/toggled()
if(owner.force_locked)
to_chat(usr, "<span class='warning'>The locking system cannot be operated due to software restriction. Contact the manufacturer for more details.</span>")
return
owner.hardpoints_locked = ..()
to_chat(usr, "<span class='notice'>Hardpoint system access is now [owner.hardpoints_locked ? "disabled" : "enabled"].</span>")
@@ -214,6 +217,9 @@
if(!owner.hatch_locked && !owner.hatch_closed)
to_chat(usr, "<span class='warning'>You cannot lock the hatch while it is open.</span>")
return
if(owner.force_locked)
to_chat(usr, "<span class='warning'>The locking system cannot be operated due to software restriction. Contact the manufacturer for more details.</span>")
return
owner.hatch_locked = ..()
to_chat(usr, "<span class='notice'>The [owner.body.hatch_descriptor] is [owner.hatch_locked ? "now" : "no longer" ] locked.</span>")
@@ -252,4 +258,4 @@
owner.head.active_sensors = ..()
to_chat(usr, "<span class='notice'>[owner.head.name] advanced sensor mode is [owner.head.active_sensors ? "now" : "no longer" ] active.</span>")
#undef BAR_CAP
#undef BAR_CAP

View File

@@ -175,7 +175,7 @@
selected_system = null
selected_hardpoint = null
/mob/living/heavy_vehicle/proc/enter(var/mob/user)
/mob/living/heavy_vehicle/proc/enter(var/mob/user, var/instant = FALSE)
if(!user || user.incapacitated())
return
if(!user.Adjacent(src))
@@ -189,9 +189,10 @@
if(LAZYLEN(pilots) >= LAZYLEN(body.pilot_positions))
to_chat(user, "<span class='warning'>\The [src] is occupied.</span>")
return
to_chat(user, "<span class='notice'>You start climbing into \the [src]...</span>")
if(!do_after(user, 30))
return
if(!instant)
to_chat(user, "<span class='notice'>You start climbing into \the [src]...</span>")
if(!do_after(user, 30))
return
if(!user || user.incapacitated())
return
if(hatch_locked)

View File

@@ -29,6 +29,11 @@
var/list/pilots
var/list/pilot_overlays
// Remote control stuff
var/remote = FALSE // Spawns a robotic pilot to be remote controlled
var/mob/living/carbon/human/industrial_xion_remote_mech/dummy // The remote controlled dummy
var/dummy_colour
// Visible external components. Not strictly accurately named for non-humanoid machines (submarines) but w/e
var/obj/item/mech_component/manipulators/arms
var/obj/item/mech_component/propulsion/legs
@@ -51,6 +56,7 @@
// Cockpit access vars.
var/hatch_closed = 0
var/hatch_locked = 0
var/force_locked = FALSE // Is it possible to unlock the hatch?
var/use_air = FALSE
@@ -74,6 +80,13 @@
pilots = null
QDEL_NULL_LIST(hud_elements)
if(remote_network)
SSvirtualreality.remove_mech(src, remote_network)
for(var/thing in hud_elements)
qdel(thing)
hud_elements.Cut()
hardpoint_hud_elements = null
@@ -218,3 +231,29 @@
/obj/item/device/radio/exosuit/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = mech_state)
. = ..()
/mob/living/heavy_vehicle/proc/become_remote()
for(var/mob/user in pilots)
eject(user, FALSE)
remote = TRUE
name = name + " \"[pick("Jaeger", "Reaver", "Templar", "Juggernaut", "Basilisk")]-[rand(0, 999)]\""
if(remote_network)
SSvirtualreality.add_mech(src, remote_network)
else
remote_network = "remotemechs"
SSvirtualreality.add_mech(src, remote_network)
if(hatch_closed)
hatch_closed = FALSE
dummy = new /mob/living/carbon/human/industrial_xion_remote_mech(get_turf(src))
if(dummy_colour)
dummy.color = dummy_colour
enter(dummy, TRUE)
if(!hatch_closed)
hatch_closed = TRUE
hatch_locked = TRUE
hardpoints_locked = TRUE
force_locked = TRUE

View File

@@ -24,6 +24,8 @@
update_icon()
. = ..()
spawn_mech_equipment()
if(remote_network)
become_remote()
/mob/living/heavy_vehicle/premade/proc/spawn_mech_equipment()
install_system(new /obj/item/mecha_equipment/light(src), HARDPOINT_HEAD)

View File

@@ -0,0 +1,36 @@
/mob/living/heavy_vehicle/premade/miner
name = "mining mecha"
desc = "A mining mecha of custom design, a closed cockpit with powerloader appendages."
/mob/living/heavy_vehicle/premade/miner/Initialize()
if(!arms)
arms = new /obj/item/mech_component/manipulators/ripley(src)
arms.color = "#ffbc37"
if(!legs)
legs = new /obj/item/mech_component/propulsion/ripley(src)
legs.color = "#ffbc37"
if(!head)
head = new /obj/item/mech_component/sensors/ripley(src)
head.color = "#ffbc37"
if(!body)
body = new /obj/item/mech_component/chassis/combat(src)
body.color = "#ffdc37"
body.armor = new /obj/item/robot_parts/robot_component/armor(src)
. = ..()
/mob/living/heavy_vehicle/premade/miner/spawn_mech_equipment()
..()
install_system(new /obj/item/mecha_equipment/drill(src), HARDPOINT_LEFT_HAND)
install_system(new /obj/item/mecha_equipment/clamp(src), HARDPOINT_RIGHT_HAND)
/mob/living/heavy_vehicle/premade/miner/remote
name = "remote mining mecha"
dummy_colour = "#ffc44f"
remote_network = "remotemechs"
/mob/living/heavy_vehicle/premade/miner/remote_prison
name = "penal mining mecha"
dummy_colour = "#302e2b"
remote_network = "prisonmechs"

View File

@@ -174,3 +174,13 @@
..()
software = new(src)
software.installed_software = list(MECH_SOFTWARE_UTILITY, MECH_SOFTWARE_WEAPONS)
/mob/living/heavy_vehicle/premade/ripley/remote
name = "remote power loader"
dummy_colour = "#ffc44f"
remote_network = "remotemechs"
/mob/living/heavy_vehicle/premade/ripley/remote_prison
name = "penal power loader"
dummy_colour = "#302e2b"
remote_network = "prisonmechs"

View File

@@ -1,4 +1,5 @@
/mob/living/carbon/human/gib()
vr_disconnect()
for(var/obj/item/organ/I in internal_organs)
I.removed()
@@ -18,6 +19,8 @@
gibs(loc, viruses, dna, null, species.flesh_color, species.blood_color)
/mob/living/carbon/human/dust()
vr_disconnect()
if(species)
..(species.dusted_anim, species.remains_type)
else
@@ -25,7 +28,10 @@
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD) return
if(stat == DEAD)
return
vr_disconnect()
BITSET(hud_updateflag, HEALTH_HUD)
BITSET(hud_updateflag, STATUS_HUD)
@@ -104,3 +110,13 @@
status_flags |= DISFIGURED
update_body(0)
return
/mob/living/carbon/human/proc/vr_disconnect()
// Come out of VR right before you die, how depressing - geeves
// Also come out of VR if your VR body dies
if(vr_mob || old_mob)
body_return()
if(remote_network)
SSvirtualreality.remove_robot(src, remote_network)
remote_network = null

View File

@@ -104,6 +104,44 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy/mannequin)
/mob/living/carbon/human/industrial_xion/Initialize(mapload)
. = ..(mapload, "Xion Industrial Frame")
/mob/living/carbon/human/industrial_xion_remote/Initialize(mapload)
. = ..(mapload, "Remote Xion Industrial Frame")
real_name = "Remote Robot [pick("Delta", "Theta", "Alpha")]-[rand(0, 999)]"
name = real_name
dna.real_name = real_name
if(mind)
mind.name = real_name
remote_network = "remoterobots"
SSvirtualreality.add_robot(src, remote_network)
/mob/living/carbon/human/industrial_xion_remote_mech/Initialize(mapload)
. = ..(mapload, "Remote Xion Industrial Frame")
real_name = "Remote Pilot [pick("Delta", "Theta", "Alpha")]-[rand(0, 999)]"
name = real_name
dna.real_name = real_name
if(mind)
mind.name = real_name
/mob/living/carbon/human/industrial_xion_remote_bunker/Initialize(mapload)
. = ..(mapload, "Remote Xion Industrial Frame")
real_name = "Remote Robot [pick("Greaves", "Chamberlain", "Slater")]-[rand(0, 999)]"
name = real_name
dna.real_name = real_name
if(mind)
mind.name = real_name
equip_to_slot_or_del(new /obj/item/clothing/under/assistantformal(src), slot_w_uniform)
equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit)
equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(src), slot_shoes)
equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_com(src), slot_l_ear)
remote_network = "bunkerrobots"
SSvirtualreality.add_robot(src, remote_network)
/mob/living/carbon/human/industrial_zenghu/Initialize(mapload)
. = ..(mapload, "Zeng-Hu Mobility Frame")
@@ -113,6 +151,35 @@ INITIALIZE_IMMEDIATE(/mob/living/carbon/human/dummy/mannequin)
/mob/living/carbon/human/unbranded_frame/Initialize(mapload)
. = ..(mapload, "Unbranded Frame")
/mob/living/carbon/human/unbranded_frame_remote/Initialize(mapload)
. = ..(mapload, "Remote Unbranded Frame")
real_name = "Remote Robot [pick("Delta", "Theta", "Alpha")]-[rand(0, 999)]"
name = real_name
dna.real_name = real_name
if(mind)
mind.name = real_name
remote_network = "remoterobots"
SSvirtualreality.add_robot(src, remote_network)
/mob/living/carbon/human/unbranded_frame_remote_bunker/Initialize(mapload)
. = ..(mapload, "Remote Unbranded Frame")
real_name = "Remote Robot [pick("Greaves", "Chamberlain", "Slater")]-[rand(0, 999)]"
name = real_name
dna.real_name = real_name
if(mind)
mind.name = real_name
equip_to_slot_or_del(new /obj/item/clothing/under/assistantformal(src), slot_w_uniform)
equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(src), slot_wear_suit)
equip_to_slot_or_del(new /obj/item/clothing/shoes/jackboots(src), slot_shoes)
equip_to_slot_or_del(new /obj/item/device/radio/headset/headset_com(src), slot_l_ear)
remote_network = "bunkerrobots"
SSvirtualreality.add_robot(src, remote_network)
/mob/living/carbon/human/terminator/Initialize(mapload)
. = ..(mapload, "Military Frame")
add_language(LANGUAGE_SOL_COMMON, 1)

View File

@@ -380,6 +380,17 @@
BP_R_FOOT = list("path" = /obj/item/organ/external/foot/right/industrial/xion)
)
/datum/species/machine/industrial/xion/remote
name = "Remote Xion Industrial Frame"
short_name = "rem_xmf"
has_organ = list(
BP_BRAIN = /obj/item/organ/internal/mmi_holder/circuit,
BP_CELL = /obj/item/organ/internal/cell,
BP_OPTICS = /obj/item/organ/internal/eyes/optical_sensor,
BP_IPCTAG = /obj/item/organ/internal/ipc_tag
)
/datum/species/machine/industrial/xion/get_light_color(mob/living/carbon/human/H)
if (istype(H))
return rgb(H.r_eyes, H.g_eyes, H.b_eyes)
@@ -511,6 +522,18 @@
/mob/living/carbon/human/proc/self_diagnostics
)
/datum/species/machine/unbranded/remote
name = "Remote Unbranded Frame"
short_name = "rem_unbran"
name_plural = "Remote Unbranded Frames"
has_organ = list(
BP_BRAIN = /obj/item/organ/internal/mmi_holder/circuit,
BP_CELL = /obj/item/organ/internal/cell,
BP_OPTICS = /obj/item/organ/internal/eyes/optical_sensor,
BP_IPCTAG = /obj/item/organ/internal/ipc_tag
)
/datum/species/machine/unbranded/get_light_color(mob/living/carbon/human/H)
if (istype(H))
return rgb(H.r_eyes, H.g_eyes, H.b_eyes)

View File

@@ -8,6 +8,9 @@
var/hud_updateflag = 0
// Virtual Reality
var/remote_network // The network this mob is attached to, used in virtual reality and remote control things
var/hallucination = 0 //Directly affects how long a mob will hallucinate for
var/list/atom/hallucinations = list() //A list of hallucinated people that try to attack the mob. See /obj/effect/fake_attacker in hallucinations.dm

View File

@@ -192,6 +192,22 @@
stored_mmi.forceMove(get_turf(src))
qdel(src)
/obj/item/organ/internal/mmi_holder/circuit/Initialize()
robotize()
stored_mmi = new /obj/item/device/mmi/digital/robot(src)
. = ..()
addtimer(CALLBACK(src, .proc/setup_brain), 1)
/obj/item/organ/internal/mmi_holder/circuit/proc/setup_brain()
if(owner)
stored_mmi.name = "robotic intelligence circuit ([owner.name])"
stored_mmi.brainmob.real_name = owner.name
stored_mmi.brainmob.name = stored_mmi.brainmob.real_name
update_from_mmi()
else
stored_mmi.forceMove(get_turf(src))
qdel(src)
//////////////
//Terminator//
//////////////

View File

@@ -40,5 +40,9 @@
qdel(aiming)
aiming = null
aimed.Cut()
if(vr_mob)
vr_mob = null
if(old_mob)
old_mob = null
return ..()