diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm
index cb2c3adab5c..ef8a55e7d2e 100644
--- a/code/__DEFINES/atom_hud.dm
+++ b/code/__DEFINES/atom_hud.dm
@@ -14,8 +14,9 @@
#define DIAG_BATT_HUD "10"// Borg/Mech power meter
#define DIAG_MECH_HUD "11"// Mech health bar
#define DIAG_BOT_HUD "12"// Bot HUDs
+#define DIAG_TRACK_HUD "13"// Mech tracking beacon
//for antag huds. these are used at the /mob level
-#define ANTAG_HUD "13"
+#define ANTAG_HUD "14"
//data HUD (medhud, sechud) defines
//Don't forget to update human/New() if you change these!
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 4fafd007042..af2a1912730 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -45,7 +45,7 @@
hud_icons = list(ID_HUD, IMPTRACK_HUD, IMPLOYAL_HUD, IMPCHEM_HUD, WANTED_HUD)
/datum/atom_hud/data/diagnostic
- hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD)
+ hud_icons = list (DIAG_HUD, DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_BOT_HUD, DIAG_TRACK_HUD)
/* MED/SEC/DIAG HUD HOOKS */
@@ -326,6 +326,19 @@
if(internal_damage)
holder.icon_state = "hudwarn"
+/obj/mecha/proc/diag_hud_set_mechtracking() //Shows tracking beacons on the mech
+ var/image/holder = hud_list[DIAG_TRACK_HUD]
+ var/icon/I = icon(icon, icon_state, dir)
+ holder.pixel_y = I.Height() - world.icon_size
+ var/new_icon_state //This var exists so that the holder's icon state is set only once in the event of multiple mech beacons.
+ for(var/obj/item/mecha_parts/mecha_tracking/T in trackers)
+ if(T.ai_beacon) //Beacon with AI uplink
+ new_icon_state = "hudtrackingai"
+ break //Immediately terminate upon finding an AI beacon to ensure it is always shown over the normal one, as mechs can have several trackers.
+ else
+ new_icon_state = "hudtracking"
+ holder.icon_state = new_icon_state
+
/*~~~~~~~~~
Bots!
~~~~~~~~~~*/
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index a1ab848cc8d..03eff51f755 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -49,7 +49,6 @@
var/lights_power = 6
var/last_user_hud = 1 // used to show/hide the mecha hud while preserving previous preference
-
var/bumpsmash = 0 //Whether or not the mech destroys walls by running into it.
//inner atmos
var/use_internal_tank = 0
@@ -117,7 +116,7 @@
var/occupant_sight_flags = 0 //sight flags to give to the occupant (e.g. mech mining scanner gives meson-like vision)
- hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD)
+ hud_possible = list (DIAG_STAT_HUD, DIAG_BATT_HUD, DIAG_MECH_HUD, DIAG_TRACK_HUD)
/obj/mecha/New()
@@ -142,6 +141,7 @@
diag_hud_set_mechhealth()
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+ diag_hud_set_mechtracking()
/obj/mecha/Destroy()
@@ -373,6 +373,7 @@
diag_hud_set_mechhealth()
diag_hud_set_mechcell()
diag_hud_set_mechstat()
+ diag_hud_set_mechtracking()
/obj/mecha/proc/drop_item()//Derpfix, but may be useful in future for engineering exosuits.
@@ -627,6 +628,21 @@
break
//Nothing like a big, red link to make the player feel powerful!
user << "ASSUME DIRECT CONTROL?
"
+ else
+ examine(user)
+ if(occupant)
+ user << "This exosuit has a pilot and cannot be controlled."
+ return
+ var/can_control_mech = 0
+ for(var/obj/item/mecha_parts/mecha_tracking/ai_control/A in trackers)
+ can_control_mech = 1
+ user << "\icon[src] Status of [name]:\n\
+ [A.get_mecha_info()]"
+ break
+ if(!can_control_mech)
+ user << "You cannot control exosuits without AI control beacons installed."
+ return
+ user << "Take control of exosuit?
"
/obj/mecha/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/device/aicard/card)
if(!..())
@@ -654,12 +670,13 @@
AI << "You have been downloaded to a mobile storage device. Wireless connection offline."
user << "Transfer successful: [AI.name] ([rand(1000,9999)].exe) removed from [name] and stored within local memory."
- if(AI_MECH_HACK) //Called by Malf AI mob on the mech.
- new /obj/structure/AIcore/deactivated(AI.loc)
- if(occupant) //Oh, I am sorry, were you using that?
- AI << "Pilot detected! Forced ejection initiated!"
- occupant << "You have been forcibly ejected!"
- go_out(1) //IT IS MINE, NOW. SUCK IT, RD!
+ if(AI_MECH_HACK) //Called by AIs on the mech
+ AI.linked_core = new /obj/structure/AIcore/deactivated(AI.loc)
+ if(AI.can_dominate_mechs)
+ if(occupant) //Oh, I am sorry, were you using that?
+ AI << "Pilot detected! Forced ejection initiated!"
+ occupant << "You have been forcibly ejected!"
+ go_out(1) //IT IS MINE, NOW. SUCK IT, RD!
ai_enter_mech(AI, interaction)
if(AI_TRANS_FROM_CARD) //Using an AI card to upload to a mech.
@@ -693,10 +710,10 @@
AI.remote_control = src
AI.canmove = 1 //Much easier than adding AI checks! Be sure to set this back to 0 if you decide to allow an AI to leave a mech somehow.
AI.can_shunt = 0 //ONE AI ENTERS. NO AI LEAVES.
- AI << "[interaction == AI_MECH_HACK ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" \
+ AI << "[AI.can_dominate_mechs ? "Takeover of [name] complete! You are now loaded onto the onboard computer. Do not attempt to leave the station sector!" \
: "You have been uploaded to a mech's onboard computer."]"
AI << "Use Middle-Mouse to activate mech functions and equipment. Click normally for AI interactions."
- GrantActions(AI)
+ GrantActions(AI, !AI.can_dominate_mechs)
//An actual AI (simple_animal mecha pilot) entering the mech
@@ -916,11 +933,25 @@
var/mob/living/brain/brain = occupant
RemoveActions(brain)
mob_container = brain.container
- else if(isAI(occupant) && forced) //This should only happen if there are multiple AIs in a round, and at least one is Malf.
- RemoveActions(occupant)
- occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced.
- occupant = null
- return
+ else if(isAI(occupant))
+ var/mob/living/silicon/ai/AI = occupant
+ if(forced)//This should only happen if there are multiple AIs in a round, and at least one is Malf.
+ RemoveActions(occupant)
+ occupant.gib() //If one Malf decides to steal a mech from another AI (even other Malfs!), they are destroyed, as they have nowhere to go when replaced.
+ occupant = null
+ return
+ else
+ if(!AI.linked_core)
+ AI << "Inactive core destroyed. Unable to return."
+ AI.linked_core = null
+ return
+ AI << "Returning to core..."
+ AI.controlled_mech = null
+ AI.remote_control = null
+ RemoveActions(occupant, 1)
+ mob_container = AI
+ newloc = get_turf(AI.linked_core)
+ qdel(AI.linked_core)
else
return
var/mob/living/L = occupant
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index 869801152e4..9d9505a01ef 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -37,7 +37,7 @@
button_icon_state = "mech_eject"
/datum/action/innate/mecha/mech_eject/Activate()
- if(!owner || !iscarbon(owner))
+ if(!owner)
return
if(!chassis || chassis.occupant != owner)
return
diff --git a/code/game/mecha/mecha_control_console.dm b/code/game/mecha/mecha_control_console.dm
index 2f4eab7b37e..97b3cd959b4 100644
--- a/code/game/mecha/mecha_control_console.dm
+++ b/code/game/mecha/mecha_control_console.dm
@@ -68,6 +68,7 @@
icon_state = "motion2"
w_class = WEIGHT_CLASS_SMALL
origin_tech = "programming=2;magnets=2"
+ var/ai_beacon = FALSE //If this beacon allows for AI control. Exists to avoid using istype() on checking.
/obj/item/mecha_parts/mecha_tracking/proc/get_mecha_info()
if(!in_mecha())
@@ -115,6 +116,13 @@
return M.get_log_html()
+/obj/item/mecha_parts/mecha_tracking/ai_control
+ name = "exosuit AI control beacon"
+ desc = "A device used to transmit exosuit data. Also allows active AI units to take control of said exosuit."
+ origin_tech = "programming=3;magnets=2;engineering=2"
+ ai_beacon = TRUE
+
+
/obj/item/weapon/storage/box/mechabeacons
name = "exosuit tracking beacons"
diff --git a/code/game/mecha/mecha_defense.dm b/code/game/mecha/mecha_defense.dm
index 07f71f838ae..2a27a20cde4 100644
--- a/code/game/mecha/mecha_defense.dm
+++ b/code/game/mecha/mecha_defense.dm
@@ -264,6 +264,7 @@
W.forceMove(src)
trackers += W
user.visible_message("[user] attaches [W] to [src].", "You attach [W] to [src].")
+ diag_hud_set_mechtracking()
return
else
return ..()
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 10817470c91..76677b2ac95 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -900,7 +900,7 @@
//Mobs on Fire end
// used by secbot and monkeys Crossed
-/mob/living/proc/knockOver(var/mob/living/carbon/C)
+/mob/living/proc/knockOver(var/mob/living/carbon/C)
C.visible_message("[pick( \
"[C] dives out of [src]'s way!", \
"[C] stumbles over [src]!", \
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index f6365f5a23b..c3eea0e6dd2 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -82,6 +82,8 @@ var/list/ai_list = list()
var/obj/machinery/camera/portable/builtInCamera
+ var/obj/structure/AIcore/deactivated/linked_core //For exosuit control
+
/mob/living/silicon/ai/New(loc, datum/ai_laws/L, mob/target_ai)
..()
if(!target_ai) //If there is no player/brain inside.
@@ -419,7 +421,16 @@ var/list/ai_list = list()
if (href_list["ai_take_control"]) //Mech domination
var/obj/mecha/M = locate(href_list["ai_take_control"])
if(controlled_mech)
- src << "You are already loaded into an onboard computer!"
+ src << "You are already loaded into an onboard computer!"
+ return
+ if(!cameranet.checkCameraVis(M))
+ src << "Exosuit is no longer near active cameras."
+ return
+ if(lacks_power())
+ src << "You're depowered!"
+ return
+ if(!isturf(loc))
+ src << "You aren't in your core!"
return
if(M)
M.transfer_ai(AI_MECH_HACK,src, usr) //Called om the mech itself.
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 3cf340ba549..6ce54089fea 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -728,6 +728,16 @@
construction_time = 50
category = list("Misc")
+/datum/design/mecha_tracking_ai_control
+ name = "AI Control Beacon"
+ id = "mecha_tracking_ai_control"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/mecha_tracking/ai_control
+ materials = list(MAT_METAL = 1000, MAT_GLASS = 500, MAT_SILVER = 200)
+ req_tech = list("programming" = 3, "magnets" = 2, "engineering" = 2)
+ construction_time = 50
+ category = list("Misc")
+
/datum/design/drone_shell
name = "Drone Shell"
desc = "A shell of a maintenance drone, an expendable robot built to perform station repairs."
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index 105f56cc8ce..ce8da26271c 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ