Skip to content

Commit

Permalink
AI Remote Control Fixes (#20198)
Browse files Browse the repository at this point in the history
Fixes #13267
Fixes #16881
Fixes #14039
Fixes #14062

Also adds QoL where pressing eject on remote controlled mechs exits
remote control.

---------

Co-authored-by: Ben10083 <[email protected]>
  • Loading branch information
Ben10083 and Ben10083 authored Dec 3, 2024
1 parent 0c3e762 commit 534a077
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 111 deletions.
150 changes: 71 additions & 79 deletions code/__HELPERS/lists.dm

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion code/_onclick/hud/screen_object_types/ai_screen_objs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 158,7 @@
if(isAI(usr))
var/mob/living/silicon/ai/AI = usr
if(AI.anchored)
AI.remote_control_shell()
AI.remote_control()
else
to_chat(AI, SPAN_WARNING("You are unable to get a good connection while unanchored from the station systems."))

Expand Down
69 changes: 51 additions & 18 deletions code/controllers/subsystems/virtual_reality.dm
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 60,16 @@ SUBSYSTEM_DEF(virtualreality)
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
/// 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
Expand All @@ -81,6 83,8 @@ SUBSYSTEM_DEF(virtualreality)
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
Expand All @@ -95,6 99,8 @@ SUBSYSTEM_DEF(virtualreality)
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
Expand All @@ -108,6 114,8 @@ SUBSYSTEM_DEF(virtualreality)
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)
Expand Down Expand Up @@ -137,11 145,18 @@ SUBSYSTEM_DEF(virtualreality)
if(target.client)
target.client.screen |= global_hud.vr_control

if(istype(target, /mob/living/simple_animal/spiderbot))
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/device/encryptionkey/Key = spider.radio.keyslot
var/obj/item/device/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."))
Expand Down Expand Up @@ -173,7 188,8 @@ SUBSYSTEM_DEF(virtualreality)
if(null_vr_mob)
target.vr_mob = null

/datum/controller/subsystem/virtualreality/proc/mech_selection(var/user, var/network)
/// 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])
Expand All @@ -193,19 209,26 @@ SUBSYSTEM_DEF(virtualreality)
continue
mech[R.name] = R

if(!length(mech))
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", mech)
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 = mech[choice]
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)

/datum/controller/subsystem/virtualreality/proc/robot_selection(var/user, var/network)

/// 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])
Expand All @@ -220,17 243,22 @@ SUBSYSTEM_DEF(virtualreality)
continue
robot[R.name] = R

if(!length(robot))
to_chat(user, SPAN_WARNING("No active remote robots are available."))
return
return robot

var/choice = tgui_input_list(usr, "Please select a remote control robot to take over.", "Remote Robot Selection", robot)
if(!choice)
/// 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, robot[choice])
mind_transfer(user, choice)

/datum/controller/subsystem/virtualreality/proc/bound_selection(var/user, var/network)
/// 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])
Expand All @@ -245,16 273,21 @@ SUBSYSTEM_DEF(virtualreality)
continue
bound = R

if(!length(bound))
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."))
return

var/choice = tgui_input_list(usr, "Please select a remote control unit to take over.", "Remote Unit Selection", bound)
if(!(choice in bound))
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))
Expand Down
13 changes: 7 additions & 6 deletions code/game/objects/items/devices/radio/radio.dm
Original file line number Diff line number Diff line change
Expand Up @@ -636,12 636,13 @@ var/global/list/default_interrogation_channels = list(
channels = list(CHANNEL_COMMON = TRUE, CHANNEL_ENTERTAINMENT = TRUE)
syndie = FALSE

var/mob/living/silicon/robot/D = loc
if(D.module)
for(var/ch_name in D.module.channels)
if(ch_name in channels)
continue
channels[ch_name] = D.module.channels[ch_name]
if(isrobot(loc))
var/mob/living/silicon/robot/D = loc
if(D.module)
for(var/ch_name in D.module.channels)
if(ch_name in channels)
continue
channels[ch_name] = D.module.channels[ch_name]
if(keyslot)
for(var/ch_name in keyslot.channels)
if(ch_name in channels)
Expand Down
4 changes: 3 additions & 1 deletion code/modules/heavy_vehicle/mech_interaction.dm
Original file line number Diff line number Diff line change
Expand Up @@ -233,11 233,13 @@
LAZYDISTINCTADD(user.additional_vision_handlers, src)
update_icon()
GLOB.move_manager.stop_looping(src) // stop it from auto moving when the pilot gets in
return 1
return TRUE

/mob/living/heavy_vehicle/proc/eject(var/mob/user, var/silent)
if(!user || !(user in src.contents))
return
if(remote)
usr.body_return()
if(hatch_closed)
if(hatch_locked)
if(!silent) to_chat(user, SPAN_WARNING("The [body.hatch_descriptor] is locked."))
Expand Down
5 changes: 4 additions & 1 deletion code/modules/heavy_vehicle/mecha.dm
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 131,7 @@
. = ..()

/mob/living/heavy_vehicle/IsAdvancedToolUser()
return 1
return TRUE

/mob/living/heavy_vehicle/get_examine_text(mob/user, distance, is_adjacent, infix, suffix)
SHOULD_CALL_PARENT(FALSE) //Special snowflake case
Expand Down Expand Up @@ -321,6 321,9 @@
dummy = new dummy_type(get_turf(src))
dummy.real_name = "Remote-Bot"
dummy.name = dummy.real_name
// Give dummy a blank encryption key for later editing if spiderbot
if(istype(dummy, /mob/living/simple_animal/spiderbot) && !istype(dummy, /mob/living/simple_animal/spiderbot/ai))
dummy.radio.keyslot = new /obj/item/device/encryptionkey
remove_verb(dummy, /mob/living/proc/ventcrawl)
remove_verb(dummy, /mob/living/proc/hide)
if(dummy_colour)
Expand Down
29 changes: 24 additions & 5 deletions code/modules/mob/living/silicon/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 21,7 @@ var/list/ai_verbs_default = list(
/mob/living/silicon/ai/proc/core,
/mob/living/silicon/ai/proc/pick_icon,
/mob/living/silicon/ai/proc/sensor_mode,
/mob/living/silicon/ai/proc/remote_control_shell,
/mob/living/silicon/ai/proc/remote_control,
/mob/living/silicon/ai/proc/show_laws_verb,
/mob/living/silicon/ai/proc/toggle_acceleration,
/mob/living/silicon/ai/proc/toggle_camera_light,
Expand Down Expand Up @@ -800,14 800,33 @@ var/list/ai_verbs_default = list(
set desc = "Augment visual feed with internal sensor overlays"
toggle_sensor_mode()

/mob/living/silicon/ai/proc/remote_control_shell()
set name = "Remote Control Shell"
/// Retrieves all mobs assigned to REMOTE_AI_ROBOT or REMOTE_AI_MECH and allows the user to select one to control using SSvirtualreality
/mob/living/silicon/ai/proc/remote_control()
set name = "Remote Control"
set category = "AI Commands"
set desc = "Remotely control any active shells on your AI shell network."
set desc = "Remotely control any active shells or mechs on your AI network."

if(check_unable(AI_CHECK_WIRELESS))
return
SSvirtualreality.bound_selection(src, REMOTE_AI_ROBOT)

// Grab from relevant networks
var/list/remote_shell = SSvirtualreality.bound_choices(src, REMOTE_AI_ROBOT)
var/list/remote_mech = SSvirtualreality.mech_choices(src, REMOTE_AI_MECH)
var/list/remote = flatten_list(list(remote_shell, remote_mech))

if(!length(remote))
to_chat(usr, SPAN_WARNING("No active remote units are available."))
return
var/choice = tgui_input_list(usr, "Please select what to take over.", "Remote Control Selection", remote)
if(!choice)
return

// Transfer
if(choice in remote_mech)
var/mob/living/heavy_vehicle/chosen_mech = remote_mech[choice]
SSvirtualreality.mind_transfer(src, chosen_mech.pilots[1]) // the first pilot
else
SSvirtualreality.mind_transfer(src, choice)

/mob/living/silicon/ai/proc/toggle_hologram_movement()
set name = "Toggle Hologram Movement"
Expand Down
7 changes: 7 additions & 0 deletions code/modules/mob/living/simple_animal/friendly/spiderbot.dm
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 332,13 @@
spawn(3)//A slight delay to let us finish walking out from under the door
layer = initial(layer)

/mob/living/simple_animal/spiderbot/zMove(direction)
if(istype(loc, /mob/living/heavy_vehicle))
var/mob/living/heavy_vehicle/mech = loc
mech.zMove(direction)
return
..()

/mob/living/simple_animal/spiderbot/get_bullet_impact_effect_type(var/def_zone)
return BULLET_IMPACT_METAL

Expand Down
5 changes: 5 additions & 0 deletions code/modules/tgui/states/default.dm
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 59,8 @@ GLOBAL_DATUM_INIT(default_state, /datum/ui_state/default, new)
to_chat(src, SPAN_WARNING("Access denied."))

return min(..(), UI_UPDATE)

/mob/living/simple_animal/spiderbot/default_can_use_topic(src_object)
if(ismech(src_object))
return UI_INTERACTIVE
return ..()
63 changes: 63 additions & 0 deletions html/changelogs/Ben10083 - Remote Fixes.yml
Original file line number Diff line number Diff line change
@@ -0,0 1,63 @@
################################
# Example Changelog File
#
# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
#
# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
# When it is, any changes listed below will disappear.
#
# Valid Prefixes:
# bugfix
# - (fixes bugs)
# wip
# - (work in progress)
# qol
# - (quality of life)
# soundadd
# - (adds a sound)
# sounddel
# - (removes a sound)
# rscadd
# - (adds a feature)
# rscdel
# - (removes a feature)
# imageadd
# - (adds an image or sprite)
# imagedel
# - (removes an image or sprite)
# spellcheck
# - (fixes spelling or grammar)
# experiment
# - (experimental change)
# balance
# - (balance changes)
# code_imp
# - (misc internal code change)
# refactor
# - (refactors code)
# config
# - (makes a change to the config files)
# admin
# - (makes changes to administrator tools)
# server
# - (miscellaneous changes to server)
#################################

# Your name.
author: Ben10083

# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
delete-after: True

# Any changes you've made. See valid prefix list above.
# INDENT WITH TWO SPACES. NOT TABS. SPACES.
# SCREW THIS UP AND IT WON'T WORK.
# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
changes:
- bugfix: "AI can remote control mechs again."
- bugfix: "Remote controlled exosuits now can travel between zlevels if capable."
- bugfix: "Remote control no longer makes the client lose verbs until restart."
- bugfix: "Remote controlled exosuit radios now will use the channels the user has access to."
- qol: "Pressing eject in a remotely controlled mech now exits remote control."
- code_imp: "DMdoced lists.dm"

0 comments on commit 534a077

Please sign in to comment.