diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index 99d5c795eb5..7b0e58ba5eb 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -16,6 +16,9 @@
var/obj/mecha/mecha = null//This does not appear to be used outside of reference in mecha.dm.
// I'm using this for mechs giving MMIs HUDs now
+ var/obj/item/radio/radio = null // For use with the radio MMI upgrade
+ var/datum/action/generic/configure_mmi_radio/radio_action = null
+
/obj/item/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
if(istype(O, /obj/item/organ/internal/brain/crystal ))
to_chat(user, " This brain is too malformed to be able to use with the [src].")
@@ -29,34 +32,70 @@
to_chat(user, "Somehow, this MMI still has a brain in it. Report this to the bug tracker.")
log_runtime(EXCEPTION("[user] tried to stick a [O] into [src] in [get_area(src)], but the held brain variable wasn't cleared"), src)
return
- for(var/mob/V in viewers(src, null))
- V.show_message("[user] sticks \a [O] into \the [src].")
- brainmob = B.brainmob
- B.brainmob = null
- brainmob.loc = src
- brainmob.container = src
- brainmob.stat = CONSCIOUS
- respawnable_list -= brainmob
- dead_mob_list -= brainmob//Update dem lists
- living_mob_list += brainmob
+ if(user.drop_item())
+ B.forceMove(src)
+ visible_message("[user] sticks \a [O] into \the [src].")
+ brainmob = B.brainmob
+ B.brainmob = null
+ brainmob.loc = src
+ brainmob.container = src
+ brainmob.stat = CONSCIOUS
+ respawnable_list -= brainmob
+ dead_mob_list -= brainmob//Update dem lists
+ living_mob_list += brainmob
- user.drop_item()
- B.forceMove(src)
- held_brain = B
- if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff
- name = "Man-Machine Interface: Alien - [brainmob.real_name]"
- icon = 'icons/mob/alien.dmi'
- icon_state = "AlienMMI"
- alien = 1
+ held_brain = B
+ if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff
+ name = "Man-Machine Interface: Alien - [brainmob.real_name]"
+ icon = 'icons/mob/alien.dmi'
+ become_occupied("AlienMMI")
+ alien = 1
+ else
+ name = "Man-Machine Interface: [brainmob.real_name]"
+ icon = B.mmi_icon
+ become_occupied("[B.mmi_icon_state]")
+ alien = 0
+
+ if(radio_action)
+ radio_action.UpdateButtonIcon()
+ feedback_inc("cyborg_mmis_filled",1)
else
- name = "Man-Machine Interface: [brainmob.real_name]"
- icon = B.mmi_icon
- icon_state = "[B.mmi_icon_state]"
- alien = 0
- feedback_inc("cyborg_mmis_filled",1)
+ to_chat(user, "You can't drop [B]!")
return
+ if(istype(O, /obj/item/mmi_radio_upgrade))
+ if(radio)
+ to_chat(user, "[src] already has a radio installed.")
+ else
+ user.visible_message("[user] begins to install the [O] into [src]...", \
+ "You start to install the [O] into [src]...")
+ if(do_after(user, 20, target=src))
+ if(user.drop_item())
+ user.visible_message("[user] installs [O] in [src].", \
+ "You install [O] in [src].")
+ if(brainmob)
+ to_chat(brainmob, "MMI radio capability installed.")
+ install_radio()
+ qdel(O)
+ else
+ to_chat(user, "You can't drop [O]!")
+ return
+
+ // Maybe later add encryption key support, but that's a pain in the neck atm
+ if(isscrewdriver(O))
+ if(radio)
+ user.visible_message("[user] begins to uninstall the radio from [src]...", \
+ "You start to uninstall the radio from [src]...")
+ if(do_after(user, 40 * O.toolspeed, target = src))
+ uninstall_radio()
+ new /obj/item/mmi_radio_upgrade(get_turf(src))
+ user.visible_message("[user] uninstalls the radio from [src].", \
+ "You uninstall the radio from [src].")
+ else
+ to_chat(user, "There is no radio in [src]!")
+ return
+
if(brainmob)
O.attack(brainmob, user)//Oh noooeeeee
// Brainmobs can take damage, but they can't actually die. Maybe should fix.
@@ -93,8 +132,7 @@
held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]"
name = "Man-Machine Interface: [brainmob.real_name]"
- icon_state = "mmi_full"
- return
+ become_occupied("mmi_full")
//I made this proc as a way to have a brainmob be transferred to any created brain, and to solve the
//problem i was having with alien/nonalien brain drops.
@@ -116,31 +154,54 @@
held_brain.forceMove(dropspot)
held_brain = null
+/obj/item/mmi/proc/become_occupied(var/new_icon)
+ icon_state = new_icon
+ if(radio)
+ radio_action.ApplyIcon()
-/obj/item/mmi/radio_enabled
- name = "Radio-enabled Man-Machine Interface"
- desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio."
- origin_tech = "biotech=2;programming=3;engineering=2;magnets=2"
+/obj/item/mmi/examine(mob/user)
+ . = ..()
+ if(radio)
+ to_chat(user, "A radio is installed on [src].")
- var/obj/item/radio/radio = null//Let's give it a radio.
+/obj/item/mmi/proc/install_radio()
+ radio = new(src)
+ radio.broadcasting = TRUE
+ radio_action = new(radio, src)
+ if(brainmob && brainmob.loc == src)
+ radio_action.Grant(brainmob)
-/obj/item/mmi/radio_enabled/New()
- ..()
- radio = new(src)//Spawns a radio inside the MMI.
- radio.broadcasting = 1//So it's broadcasting from the start.
+/obj/item/mmi/proc/uninstall_radio()
+ QDEL_NULL(radio)
+ QDEL_NULL(radio_action)
-/obj/item/mmi/radio_enabled/verb/Toggle_Listening()
- set name = "Toggle Listening"
- set desc = "Toggle listening channel on or off."
- set category = "MMI"
- set src = usr.loc
- set popup_menu = 0
+/datum/action/generic/configure_mmi_radio
+ name = "Configure MMI Radio"
+ desc = "Configure the radio installed in your MMI."
+ check_flags = AB_CHECK_CONSCIOUS
+ procname = "ui_interact"
+ var/obj/item/mmi = null
- if(brainmob.stat)
- to_chat(brainmob, "Can't do that while incapacitated or dead.")
+/datum/action/generic/configure_mmi_radio/New(var/Target, var/obj/item/mmi/M)
+ . = ..()
+ mmi = M
- radio.listening = radio.listening==1 ? 0 : 1
- to_chat(brainmob, "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast.")
+/datum/action/generic/configure_mmi_radio/Destroy()
+ mmi = null
+ return ..()
+
+/datum/action/generic/configure_mmi_radio/ApplyIcon(obj/screen/movable/action_button/current_button)
+ // A copy/paste of the item action icon code
+ current_button.overlays.Cut()
+ if(target)
+ var/obj/item/I = mmi
+ var/old_layer = I.layer
+ var/old_plane = I.plane
+ I.layer = 21
+ I.plane = HUD_PLANE
+ current_button.overlays += I
+ I.layer = old_layer
+ I.plane = old_plane
/obj/item/mmi/emp_act(severity)
if(!brainmob)
@@ -168,8 +229,22 @@
borg.mmi = null
QDEL_NULL(brainmob)
QDEL_NULL(held_brain)
+ QDEL_NULL(radio)
+ QDEL_NULL(radio_action)
return ..()
+// These two procs are important for when an MMI pilots a mech
+// (Brainmob "enters/leaves" the MMI when piloting)
+// Also neatly handles basically every case where a brain
+// is inserted or removed from an MMI
+/obj/item/mmi/Entered(atom/movable/A)
+ if(radio && istype(A, /mob/living/carbon/brain))
+ radio_action.Grant(A)
+
+/obj/item/mmi/Exited(atom/movable/A)
+ if(radio && istype(A, /mob/living/carbon/brain))
+ radio_action.Remove(A)
+
/obj/item/mmi/syndie
name = "Syndicate Man-Machine Interface"
desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores."
@@ -197,3 +272,20 @@
holder.insert(H)
return 1
+
+// As a synthetic, the only limit on visibility is view range
+/obj/item/mmi/contents_nano_distance(var/src_object, var/mob/living/user)
+ if((src_object in view(src)) && get_dist(src_object, src) <= user.client.view)
+ return STATUS_INTERACTIVE // interactive (green visibility)
+ return user.shared_living_nano_distance(src_object)
+
+// For now the only thing that is helped by this is radio access
+// Later a more intricate system for MMI UI interaction can be established
+/obj/item/mmi/contents_nano_interact(var/src_object, var/mob/living/user)
+ if(!istype(user, /mob/living/carbon/brain))
+ log_runtime(EXCEPTION("Somehow a non-brain mob is inside an MMI!"), user)
+ return ..()
+ var/mob/living/carbon/brain/BM = user
+ if(BM.container == src && src_object == radio)
+ return STATUS_INTERACTIVE
+ return ..()
diff --git a/code/modules/mob/living/carbon/brain/MMI_radio.dm b/code/modules/mob/living/carbon/brain/MMI_radio.dm
new file mode 100644
index 00000000000..6eeaa44a42c
--- /dev/null
+++ b/code/modules/mob/living/carbon/brain/MMI_radio.dm
@@ -0,0 +1,5 @@
+/obj/item/mmi_radio_upgrade
+ name = "MMI radio upgrade"
+ desc = "Enables radio capability on MMIs when either installed directly on the MMI, or through a cyborg's chassis."
+ icon = 'icons/obj/module.dmi'
+ icon_state = "cyborg_upgrade1"
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index b7188a0286a..ab9c72373a1 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -81,7 +81,9 @@
if(H.mind)
H.mind.transfer_to(brainmob)
to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just a metal cube.")
- icon_state = "posibrain-occupied"
+ become_occupied("posibrain-occupied")
+ if(radio)
+ radio_action.ApplyIcon()
return
/obj/item/mmi/posibrain/proc/transfer_personality(var/mob/candidate)
@@ -97,7 +99,8 @@
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/M in viewers(T))
M.show_message("The positronic brain chimes quietly.")
- icon_state = "posibrain-occupied"
+ become_occupied("posibrain-occupied")
+
/obj/item/mmi/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
if(src.brainmob && src.brainmob.key) return
@@ -142,22 +145,23 @@
/obj/item/mmi/posibrain/examine(mob/user)
to_chat(user, "Its speaker is turned [silenced ? "off" : "on"].")
to_chat(user, "*---------*")
- if(!..(user))
+ . = ..()
+ if(!.)
to_chat(user, "*---------*")
return
- var/list/msg = ""
+ var/list/msg = list("")
if(brainmob && brainmob.key)
switch(brainmob.stat)
if(CONSCIOUS)
- if(!brainmob.client) msg += "It appears to be in stand-by mode." //afk
- if(UNCONSCIOUS) msg += "It doesn't seem to be responsive."
- if(DEAD) msg += "It appears to be completely inactive."
+ if(!brainmob.client) msg += "It appears to be in stand-by mode.\n" //afk
+ if(UNCONSCIOUS) msg += "It doesn't seem to be responsive.\n"
+ if(DEAD) msg += "It appears to be completely inactive.\n"
else
- msg += "It appears to be completely inactive."
+ msg += "It appears to be completely inactive.\n"
msg += "*---------*"
- to_chat(user, msg.Join("\n"))
+ to_chat(user, msg.Join(""))
/obj/item/mmi/posibrain/emp_act(severity)
if(!src.brainmob)
diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm
index e8e2dd00c45..4a34d2d1b05 100644
--- a/code/modules/mob/living/carbon/brain/say.dm
+++ b/code/modules/mob/living/carbon/brain/say.dm
@@ -2,7 +2,7 @@
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null)
if(!can_speak(warning = TRUE))
return
-
+
if(prob(emp_damage * 4))
if(prob(10)) //10% chance to drop the message entirely
return
@@ -10,13 +10,13 @@
message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
..(message)
-
+
/mob/living/carbon/brain/whisper(message as text)
if(!can_speak(warning = TRUE))
return
..()
-
+
/mob/living/carbon/brain/can_speak(var/warning = FALSE)
. = ..()
@@ -41,12 +41,10 @@
if(metalgear.radio)
radio_worked = metalgear.radio.talk_into(src, message, message_mode, verb, speaking)
- else if(!radio_worked && istype(c, /obj/item/mmi/radio_enabled))
- var/obj/item/mmi/radio_enabled/R = c
- if(R.radio)
- radio_worked = R.radio.talk_into(src, message, message_mode, verb, speaking)
+ else if(!radio_worked && c.radio)
+ radio_worked = c.radio.talk_into(src, message, message_mode, verb, speaking)
return radio_worked
if("whisper")
whisper_say(message, speaking, alt_name)
return 1
- else return 0
\ No newline at end of file
+ else return 0
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 5fb42f5f121..4f6707e93f0 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -738,7 +738,7 @@ var/list/robot_verbs_default = list(
else if(istype(W, /obj/item/borg/upgrade/))
var/obj/item/borg/upgrade/U = W
if(!opened)
- to_chat(user, "You must access the borgs internals!")
+ to_chat(user, "You must access the borg's internals!")
else if(!src.module && U.require_module)
to_chat(user, "The borg must choose a module before it can be upgraded!")
else if(U.locked)
@@ -752,6 +752,21 @@ var/list/robot_verbs_default = list(
else
to_chat(user, "Upgrade error.")
+ else if(istype(W, /obj/item/mmi_radio_upgrade))
+ if(!opened)
+ to_chat(user, "You must access the borg's internals!")
+ return
+ else if(!mmi)
+ to_chat(user, "This cyborg does not have an MMI to augment!")
+ return
+ else if(mmi.radio)
+ to_chat(user, "A radio upgrade is already installed in the MMI!")
+ return
+ else if(user.drop_item())
+ to_chat(user, "You apply the upgrade to [src].")
+ to_chat(src, "MMI radio capability installed.")
+ mmi.install_radio()
+ qdel(W)
else
return ..()
@@ -1442,4 +1457,4 @@ var/list/robot_verbs_default = list(
return eye_protection
/mob/living/silicon/robot/check_ear_prot()
- return ear_protection
\ No newline at end of file
+ return ear_protection
diff --git a/code/modules/nano/interaction/default.dm b/code/modules/nano/interaction/default.dm
index 3f9155ed162..e5062bc0b12 100644
--- a/code/modules/nano/interaction/default.dm
+++ b/code/modules/nano/interaction/default.dm
@@ -59,10 +59,14 @@
return STATUS_CLOSE
-//Some atoms such as vehicles might have special rules for how mobs inside them interact with NanoUI.
+//Some atoms such as vehicles might have special limitations for how mobs inside them interact with NanoUI.
/atom/proc/contents_nano_distance(var/src_object, var/mob/living/user)
return user.shared_living_nano_distance(src_object)
+//Some atoms such as vehicles might have special benefits for how mobs inside them interact with NanoUI.
+/atom/proc/contents_nano_interact(var/src_object, var/mob/living/user)
+ return STATUS_CLOSE // No help at all by default
+
/mob/living/proc/shared_living_nano_distance(var/atom/movable/src_object)
if(!(src_object in view(4, src))) // If the src object is not in visable, disable updates
return STATUS_CLOSE
@@ -84,6 +88,16 @@
if(STATUS_INTERACTIVE)
return STATUS_UPDATE
+/mob/living/carbon/brain/default_can_use_topic(var/src_object)
+ . = shared_nano_interaction(src_object)
+ if(. <= STATUS_DISABLED)
+ return
+ // Maybe add a handler here to call an "interaction state" thing on the MMI,
+ // later
+ if(loc)
+ . = max(., loc.contents_nano_interact(src_object, src)) // This is an "augment" on interaction
+ . = min(., loc.contents_nano_distance(src_object, src)) // This is a "limit" on interaction
+
/mob/living/carbon/human/default_can_use_topic(var/src_object)
. = shared_nano_interaction(src_object)
if(. != STATUS_CLOSE)
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 49a1a7d0eba..82f23c52d5e 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -114,15 +114,15 @@
build_path = /obj/item/mmi/posibrain
category = list("Misc","Medical")
-/datum/design/mmi_radio
- name = "Radio-Enabled Man-Machine Interface"
- desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity. This one comes with a built-in radio."
- id = "mmi_radio"
+/datum/design/mmi_radio_upgrade
+ name = "Man-Machine Interface Radio Upgrade"
+ desc = "Enables radio capability on MMIs when either installed directly on the MMI, or through a cyborg's chassis."
+ id = "mmi_radio_upgrade"
req_tech = list("programming" = 3, "biotech" = 2, "engineering" = 2)
build_type = PROTOLATHE | MECHFAB
- materials = list(MAT_METAL = 1200, MAT_GLASS = 500)
- construction_time = 75
- build_path = /obj/item/mmi/radio_enabled
+ materials = list(MAT_METAL = 200)
+ construction_time = 50
+ build_path = /obj/item/mmi_radio_upgrade
category = list("Misc","Medical")
/datum/design/nanopaste
diff --git a/paradise.dme b/paradise.dme
index 095e5ad2a78..e6715951e99 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -1619,6 +1619,7 @@
#include "code\modules\mob\living\carbon\brain\life.dm"
#include "code\modules\mob\living\carbon\brain\login.dm"
#include "code\modules\mob\living\carbon\brain\MMI.dm"
+#include "code\modules\mob\living\carbon\brain\MMI_radio.dm"
#include "code\modules\mob\living\carbon\brain\posibrain.dm"
#include "code\modules\mob\living\carbon\brain\say.dm"
#include "code\modules\mob\living\carbon\brain\update_status.dm"