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"