diff --git a/code/__defines/mobs.dm b/code/__defines/mobs.dm
index 739b95e1ccc..3c168317126 100644
--- a/code/__defines/mobs.dm
+++ b/code/__defines/mobs.dm
@@ -182,7 +182,6 @@
#define BP_ACETONE "acetone reactor"
// Robo Organs.
-#define BP_POSIBRAIN "posibrain"
#define BP_VOICE "vocal synthesiser"
#define BP_STACK "stack"
#define BP_OPTICS "optics"
diff --git a/code/_helpers/mobs.dm b/code/_helpers/mobs.dm
index 9d714318131..fe8247f9e9b 100644
--- a/code/_helpers/mobs.dm
+++ b/code/_helpers/mobs.dm
@@ -311,3 +311,15 @@ var/global/list/bodypart_coverage_cache = list()
/proc/get_sorted_mob_list()
. = sortTim(SSmobs.mob_list.Copy(), /proc/cmp_name_asc)
. = sortTim(., /proc/cmp_mob_sortvalue_asc)
+
+/proc/transfer_key_from_mob_to_mob(var/mob/from_mob, var/mob/to_mob)
+ if(!from_mob || !from_mob.key || !to_mob)
+ return FALSE
+ var/initial_key = from_mob.key
+ if(to_mob.key)
+ to_mob.ghostize()
+ if(from_mob.mind)
+ from_mob.mind.transfer_to(to_mob)
+ if(initial_key && to_mob.key != initial_key)
+ to_mob.key = initial_key
+ return to_mob.key == initial_key
diff --git a/code/_macros.dm b/code/_macros.dm
index bcbd7efd3f8..0ac36021a18 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -24,7 +24,7 @@
#define isatom(A) isloc(A)
-#define isbrain(A) istype(A, /mob/living/carbon/brain)
+#define isbrain(A) istype(A, /mob/living/brain)
#define iscarbon(A) istype(A, /mob/living/carbon)
diff --git a/code/_onclick/rig.dm b/code/_onclick/rig.dm
index 7813f9d5d3c..8dd8799e561 100644
--- a/code/_onclick/rig.dm
+++ b/code/_onclick/rig.dm
@@ -28,9 +28,6 @@
/mob/living/carbon/human/can_use_rig()
return 1
-/mob/living/carbon/brain/can_use_rig()
- return istype(loc, /obj/item/mmi)
-
/mob/living/silicon/ai/can_use_rig()
return carded
diff --git a/code/controllers/subsystems/initialization/robots.dm b/code/controllers/subsystems/initialization/robots.dm
index b71138afa75..75c70a7fe4c 100644
--- a/code/controllers/subsystems/initialization/robots.dm
+++ b/code/controllers/subsystems/initialization/robots.dm
@@ -10,18 +10,15 @@ SUBSYSTEM_DEF(robots)
var/list/robot_alt_titles = list()
var/list/mob_types_by_title = list(
- "robot, flying" = /mob/living/silicon/robot/flying,
- "drone, flying" = /mob/living/silicon/robot/flying,
- "cyborg, flying" = /mob/living/silicon/robot/flying
+ "cyborg, flying" = /mob/living/silicon/robot/flying,
+ "robot, flying" = /mob/living/silicon/robot/flying
)
var/list/mmi_types_by_title = list(
- "cyborg" = /obj/item/mmi,
- "robot" = /obj/item/organ/internal/posibrain,
- "drone" = /obj/item/mmi/digital/robot,
- "cyborg, flying" = /obj/item/mmi,
- "robot, flying" = /obj/item/organ/internal/posibrain,
- "drone, flying" = /obj/item/mmi/digital/robot
+ "cyborg" = /obj/item/organ/internal/brain_interface,
+ "robot" = /obj/item/organ/internal/brain/robotic,
+ "cyborg, flying" = /obj/item/organ/internal/brain_interface,
+ "robot, flying" = /obj/item/organ/internal/brain/robotic
)
/datum/controller/subsystem/robots/Initialize()
@@ -60,8 +57,8 @@ SUBSYSTEM_DEF(robots)
if(modules[include_override])
.[include_override] = modules[include_override]
-/datum/controller/subsystem/robots/proc/get_mmi_type_by_title(var/check_title)
- . = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/mmi
+/datum/controller/subsystem/robots/proc/get_brain_type_by_title(var/check_title)
+ . = mmi_types_by_title[lowertext(trim(check_title))] || /obj/item/organ/internal/brain/robotic
/datum/controller/subsystem/robots/proc/get_mob_type_by_title(var/check_title)
. = mob_types_by_title[lowertext(trim(check_title))] || /mob/living/silicon/robot
\ No newline at end of file
diff --git a/code/datums/repositories/follow.dm b/code/datums/repositories/follow.dm
index 4e36a96450d..11393225a41 100644
--- a/code/datums/repositories/follow.dm
+++ b/code/datums/repositories/follow.dm
@@ -175,7 +175,7 @@ var/global/repository/follow/follow_repository = new()
/datum/follow_holder/brain
sort_order = 3
- followed_type = /mob/living/carbon/brain
+ followed_type = /mob/living/brain
suffix = "Brain"
/datum/follow_holder/alien
diff --git a/code/datums/trading/traders/goods.dm b/code/datums/trading/traders/goods.dm
index 76c338c2815..e4fd109c083 100644
--- a/code/datums/trading/traders/goods.dm
+++ b/code/datums/trading/traders/goods.dm
@@ -218,43 +218,43 @@ Sells devices, odds and ends, and medical stuff
"McGillicuddy's"
)
possible_trading_items = list(
- /obj/item/flashlight = TRADER_ALL,
- /obj/item/kit/paint = TRADER_SUBTYPES_ONLY,
- /obj/item/aicard = TRADER_THIS_TYPE,
- /obj/item/binoculars = TRADER_THIS_TYPE,
- /obj/item/cable_painter = TRADER_THIS_TYPE,
- /obj/item/flash = TRADER_THIS_TYPE,
- /obj/item/paint_sprayer = TRADER_THIS_TYPE,
- /obj/item/multitool = TRADER_THIS_TYPE,
- /obj/item/lightreplacer = TRADER_THIS_TYPE,
- /obj/item/megaphone = TRADER_THIS_TYPE,
- /obj/item/paicard = TRADER_THIS_TYPE,
- /obj/item/scanner/health = TRADER_THIS_TYPE,
- /obj/item/scanner/breath = TRADER_THIS_TYPE,
- /obj/item/scanner/gas = TRADER_ALL,
- /obj/item/scanner/spectrometer = TRADER_ALL,
- /obj/item/scanner/reagent = TRADER_ALL,
- /obj/item/scanner/xenobio = TRADER_THIS_TYPE,
- /obj/item/suit_cooling_unit = TRADER_THIS_TYPE,
- /obj/item/t_scanner = TRADER_THIS_TYPE,
- /obj/item/taperecorder = TRADER_THIS_TYPE,
- /obj/item/batterer = TRADER_THIS_TYPE,
- /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
- /obj/item/hailer = TRADER_THIS_TYPE,
- /obj/item/uv_light = TRADER_THIS_TYPE,
- /obj/item/mmi = TRADER_ALL,
- /obj/item/robotanalyzer = TRADER_THIS_TYPE,
- /obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
- /obj/item/camera_film = TRADER_THIS_TYPE,
- /obj/item/camera = TRADER_THIS_TYPE,
- /obj/item/destTagger = TRADER_THIS_TYPE,
- /obj/item/gps = TRADER_THIS_TYPE,
- /obj/item/measuring_tape = TRADER_THIS_TYPE,
- /obj/item/ano_scanner = TRADER_THIS_TYPE,
- /obj/item/core_sampler = TRADER_THIS_TYPE,
- /obj/item/depth_scanner = TRADER_THIS_TYPE,
- /obj/item/pinpointer/radio = TRADER_THIS_TYPE,
- /obj/item/stack/medical/advanced = TRADER_BLACKLIST
+ /obj/item/flashlight = TRADER_ALL,
+ /obj/item/kit/paint = TRADER_SUBTYPES_ONLY,
+ /obj/item/aicard = TRADER_THIS_TYPE,
+ /obj/item/binoculars = TRADER_THIS_TYPE,
+ /obj/item/cable_painter = TRADER_THIS_TYPE,
+ /obj/item/flash = TRADER_THIS_TYPE,
+ /obj/item/paint_sprayer = TRADER_THIS_TYPE,
+ /obj/item/multitool = TRADER_THIS_TYPE,
+ /obj/item/lightreplacer = TRADER_THIS_TYPE,
+ /obj/item/megaphone = TRADER_THIS_TYPE,
+ /obj/item/paicard = TRADER_THIS_TYPE,
+ /obj/item/scanner/health = TRADER_THIS_TYPE,
+ /obj/item/scanner/breath = TRADER_THIS_TYPE,
+ /obj/item/scanner/gas = TRADER_ALL,
+ /obj/item/scanner/spectrometer = TRADER_ALL,
+ /obj/item/scanner/reagent = TRADER_ALL,
+ /obj/item/scanner/xenobio = TRADER_THIS_TYPE,
+ /obj/item/suit_cooling_unit = TRADER_THIS_TYPE,
+ /obj/item/t_scanner = TRADER_THIS_TYPE,
+ /obj/item/taperecorder = TRADER_THIS_TYPE,
+ /obj/item/batterer = TRADER_THIS_TYPE,
+ /obj/item/synthesized_instrument/violin = TRADER_THIS_TYPE,
+ /obj/item/hailer = TRADER_THIS_TYPE,
+ /obj/item/uv_light = TRADER_THIS_TYPE,
+ /obj/item/organ/internal/brain_interface = TRADER_SUBTYPES_ONLY,
+ /obj/item/robotanalyzer = TRADER_THIS_TYPE,
+ /obj/item/chems/toner_cartridge = TRADER_THIS_TYPE,
+ /obj/item/camera_film = TRADER_THIS_TYPE,
+ /obj/item/camera = TRADER_THIS_TYPE,
+ /obj/item/destTagger = TRADER_THIS_TYPE,
+ /obj/item/gps = TRADER_THIS_TYPE,
+ /obj/item/measuring_tape = TRADER_THIS_TYPE,
+ /obj/item/ano_scanner = TRADER_THIS_TYPE,
+ /obj/item/core_sampler = TRADER_THIS_TYPE,
+ /obj/item/depth_scanner = TRADER_THIS_TYPE,
+ /obj/item/pinpointer/radio = TRADER_THIS_TYPE,
+ /obj/item/stack/medical/advanced = TRADER_BLACKLIST
)
speech = list(
TRADER_HAIL_GENERIC = "Hello, hello! Bits and bobs and everything in between, I hope you find what you're looking for!",
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index 1b8a9ee79aa..769fbc05658 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -150,8 +150,7 @@
if(isrobot(M))
var/mob/living/silicon/robot/Robot = M
- if(Robot.mmi)
- qdel(Robot.mmi)
+ QDEL_NULL(Robot.central_processor)
else
for(var/obj/item/W in M)
M.drop_from_inventory(W)
diff --git a/code/game/machinery/computer/ai_core.dm b/code/game/machinery/computer/ai_core.dm
index 3fa89eef553..efc4136a173 100644
--- a/code/game/machinery/computer/ai_core.dm
+++ b/code/game/machinery/computer/ai_core.dm
@@ -11,7 +11,7 @@ var/global/list/empty_playable_ai_cores = list()
var/datum/ai_laws/laws
var/obj/item/stock_parts/circuitboard/circuit
- var/obj/item/mmi/brain
+ var/obj/item/organ/internal/brain
var/authorized
var/circuit_secured = FALSE
@@ -139,30 +139,24 @@ var/global/list/empty_playable_ai_cores = list()
if(circuit && circuit_secured)
- if((istype(P, /obj/item/mmi) || istype(P, /obj/item/organ/internal/posibrain)) && wired && circuit && circuit_secured)
- var/mob/living/carbon/brain/B
- if(istype(P, /obj/item/mmi))
- var/obj/item/mmi/M = P
- B = M.brainmob
- else
- var/obj/item/organ/internal/posibrain/PB = P
- B = PB.brainmob
- if(!B)
- to_chat(user, SPAN_WARNING("Sticking an empty [P] into the frame would sort of defeat the purpose."))
+ if(istype(P, /obj/item/organ/internal) && wired && circuit && circuit_secured)
+ var/obj/item/organ/internal/M = P
+ var/mob/living/brainmob = M.get_brainmob()
+ if(!brainmob)
+ to_chat(user, SPAN_WARNING("Sticking a mindless [P] into the frame would be pointless."))
return
- if(B.stat == DEAD)
+ if(brainmob.stat == DEAD)
to_chat(user, SPAN_WARNING("Sticking a dead [P] into the frame would sort of defeat the purpose."))
return
- if(jobban_isbanned(B, "AI"))
+ if(jobban_isbanned(brainmob, "AI"))
to_chat(user, SPAN_WARNING("This [P] does not seem to fit."))
return
if(!user.try_unequip(P, src))
- return
- if(B.mind)
- clear_antag_roles(B.mind, 1)
- brain = P
- to_chat(usr, "Added [P].")
- update_icon()
+ if(brainmob.mind)
+ clear_antag_roles(brainmob.mind, 1)
+ brain = P
+ to_chat(usr, "You connect \the [P] to the frame and slide it into the casing.")
+ update_icon()
return TRUE
if(istype(P, /obj/item/stack/material))
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index b23a5df9c9f..858a29659b9 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -314,14 +314,14 @@
// Also make sure there is a valid control computer
/obj/machinery/cryopod/robot/despawn_occupant()
var/mob/living/silicon/robot/R = occupant
- if(!istype(R)) return ..()
-
- qdel(R.mmi)
- for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc
- for(var/obj/item/O in I.get_contained_external_atoms()) // the things inside the tools, if anything; mainly for janiborg trash bags
- O.forceMove(R)
- qdel(I)
- qdel(R.module)
+ if(istype(R))
+ R.clear_brain()
+ if(R.module)
+ for(var/obj/item/I in R.module) // the tools the borg has; metal, glass, guns etc
+ for(var/obj/item/O in I.get_contained_external_atoms()) // the things inside the tools, if anything; mainly for janiborg trash bags
+ O.forceMove(R)
+ qdel(I)
+ qdel(R.module)
. = ..()
diff --git a/code/game/objects/items/robot/robot_frame.dm b/code/game/objects/items/robot/robot_frame.dm
index a13106e420c..b47813774c0 100644
--- a/code/game/objects/items/robot/robot_frame.dm
+++ b/code/game/objects/items/robot/robot_frame.dm
@@ -60,8 +60,8 @@
parts[part.bp_tag] = part
update_icon()
- // Install an MMI/brain.
- else if(istype(W, /obj/item/mmi) || istype(W, /obj/item/organ/internal/posibrain))
+ // Install a brain.
+ else if(istype(W, /obj/item/organ/internal/brain_interface))
if(!isturf(loc))
to_chat(user, SPAN_WARNING("You can't put \the [W] in without the frame being on the ground."))
@@ -71,31 +71,25 @@
to_chat(user, SPAN_WARNING("The frame is not ready for the central processor to be installed."))
return
- var/mob/living/carbon/brain/B
- if(istype(W, /obj/item/mmi))
- var/obj/item/mmi/M = W
- B = M.brainmob
- else
- var/obj/item/organ/internal/posibrain/P = W
- B = P.brainmob
-
- if(!B)
+ var/obj/item/organ/internal/brain_interface/M = W
+ var/mob/living/brainmob = M?.get_brainmob()
+ if(!brainmob)
to_chat(user, SPAN_WARNING("Sticking an empty [W.name] into the frame would sort of defeat the purpose."))
return
- if(jobban_isbanned(B, ASSIGNMENT_ROBOT))
+ if(jobban_isbanned(brainmob, ASSIGNMENT_ROBOT))
to_chat(user, SPAN_WARNING("\The [W] does not seem to fit."))
return
- if(B.stat == DEAD)
+ if(brainmob.stat == DEAD)
to_chat(user, SPAN_WARNING("Sticking a dead [W.name] into the frame would sort of defeat the purpose."))
return
var/ghost_can_reenter = 0
- if(B.mind)
- if(!B.key)
+ if(brainmob.mind)
+ if(!brainmob.key)
for(var/mob/observer/ghost/G in global.player_list)
- if(G.can_reenter_corpse && G.mind == B.mind)
+ if(G.can_reenter_corpse && G.mind == brainmob.mind)
ghost_can_reenter = 1
break
else
@@ -112,11 +106,12 @@
if(!O)
return
- O.mmi = W
+ O.central_processor = W
O.set_invisibility(INVISIBILITY_NONE)
O.custom_name = created_name
O.updatename("Default")
- B.mind.transfer_to(O)
+
+ brainmob.mind.transfer_to(O)
if(O.mind && O.mind.assigned_role)
O.job = O.mind.assigned_role
else
diff --git a/code/modules/brain_interface/_brain_interface.dm b/code/modules/brain_interface/_brain_interface.dm
new file mode 100644
index 00000000000..4b96d8f9f24
--- /dev/null
+++ b/code/modules/brain_interface/_brain_interface.dm
@@ -0,0 +1,153 @@
+// Many values copied from brains. Not inheriting to avoid redundant brainmob creation.
+/obj/item/organ/internal/brain_interface
+ name = "neural interface"
+ desc = "A complex life support shell that interfaces between a brain and an electronic device."
+ organ_tag = BP_BRAIN
+ parent_organ = BP_HEAD
+ origin_tech = @'{"biotech":3}'
+ icon = 'icons/obj/items/brain_interface_organic.dmi'
+ icon_state = ICON_STATE_WORLD
+ req_access = list(access_robotics)
+ material = /decl/material/solid/metal/steel
+ matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT)
+ w_class = ITEM_SIZE_SMALL
+ throwforce = 1
+ throw_speed = 3
+ throw_range = 5
+ attack_verb = list("attacked", "slapped", "whacked")
+ relative_size = 85
+ damage_reduction = 0
+ scale_max_damage_to_species_health = FALSE
+ transfer_brainmob_with_organ = TRUE
+ var/locked = FALSE
+ var/obj/item/organ/internal/brain/holding_brain = /obj/item/organ/internal/brain
+
+/obj/item/organ/internal/brain_interface/is_preserved()
+ return TRUE
+
+/obj/item/organ/internal/brain_interface/empty
+ holding_brain = null
+
+/obj/item/organ/internal/brain_interface/Initialize()
+ set_bodytype(/decl/bodytype/prosthetic/basic_human)
+ if(ispath(holding_brain))
+ holding_brain = new holding_brain(src)
+ if(get_radio())
+ verbs |= /obj/item/organ/internal/brain_interface/proc/toggle_radio_listening
+ verbs |= /obj/item/organ/internal/brain_interface/proc/toggle_radio_broadcasting
+ . = ..()
+ update_icon()
+
+/obj/item/organ/internal/brain_interface/get_brainmob(var/create_if_missing = FALSE)
+ return holding_brain?.get_brainmob(create_if_missing)
+
+/obj/item/organ/internal/brain_interface/on_update_icon()
+ icon_state = get_world_inventory_state()
+ if(holding_brain)
+ var/mob/living/brainmob = get_brainmob()
+ if(!brainmob || brainmob.stat == DEAD)
+ icon_state = "[icon_state]-dead"
+ else
+ icon_state = "[icon_state]-full"
+
+/obj/item/organ/internal/brain_interface/examine(mob/user, distance)
+ . = ..()
+ if(distance <= 1)
+ var/mob/living/brain/brainmob = get_brainmob()
+ if(istype(brainmob))
+ if(brainmob.emp_damage)
+ to_chat(user, SPAN_WARNING("The neural interface socket is damaged."))
+ else
+ to_chat(user, SPAN_NOTICE("It is undamaged."))
+
+/obj/item/organ/internal/brain_interface/attackby(var/obj/item/O, var/mob/user)
+
+ if(istype(O, /obj/item/stack/nanopaste))
+ var/mob/living/brain/brainmob = get_brainmob()
+ if(!istype(brainmob) || !brainmob.emp_damage)
+ to_chat(user, SPAN_WARNING("\The [src] has no damage to repair."))
+ return TRUE
+ var/obj/item/stack/nanopaste/pasta = O
+ pasta.use(1)
+ to_chat(user, SPAN_NOTICE("You repair some of the damage to \the [src]'s electronics with the nanopaste."))
+ brainmob.emp_damage = max(brainmob.emp_damage - rand(5,10), 0)
+ return TRUE
+
+ if(istype(O, /obj/item/organ/internal/brain))
+
+ if(holding_brain)
+ to_chat(user, SPAN_WARNING("\The [src] already has a brain in it."))
+ return TRUE
+
+ var/obj/item/organ/internal/brain/inserting_brain = O
+ if(BP_IS_PROSTHETIC(inserting_brain))
+ to_chat(user, SPAN_WARNING("You don't need to put a robotic brain into an interface."))
+ return TRUE
+
+ if(inserting_brain.damage >= inserting_brain.max_damage)
+ to_chat(user, SPAN_WARNING("That brain is well and truly dead."))
+ return TRUE
+
+ if(!inserting_brain.get_brainmob() || !inserting_brain.can_use_brain_interface)
+ to_chat(user, SPAN_WARNING("\The [inserting_brain] is completely useless."))
+ return TRUE
+
+ if(user.try_unequip(O, src))
+ user.visible_message(SPAN_NOTICE("\The [user] sticks \the [inserting_brain] into \the [src]."))
+ SetName("[initial(name)] (\the [inserting_brain])")
+ holding_brain = inserting_brain
+ update_icon()
+ locked = TRUE
+ SSstatistics.add_field("cyborg_mmis_filled",1)
+ return TRUE
+
+ if(istype(O,/obj/item/card/id) || istype(O,/obj/item/modular_computer))
+ if(allowed(user))
+ locked = !locked
+ to_chat(user, SPAN_NOTICE("You [locked ? "lock" : "unlock"] \the [src]."))
+ else
+ to_chat(user, SPAN_WARNING("Access denied."))
+ return TRUE
+
+ if(holding_brain)
+ return holding_brain.attackby(O, user)
+
+ . = ..()
+
+/obj/item/organ/internal/brain_interface/relaymove(var/mob/user, var/direction)
+ if(user.incapacitated())
+ return
+ var/obj/item/rig/rig = src.get_rig()
+ if(rig)
+ rig.forced_move(direction, user)
+
+/obj/item/organ/internal/brain_interface/Destroy()
+ STOP_PROCESSING(SSprocessing, src)
+ if(isrobot(loc))
+ var/mob/living/silicon/robot/borg = loc
+ if(borg.central_processor == src)
+ borg.central_processor = null
+ if(holding_brain)
+ if(!QDELETED(holding_brain))
+ qdel(holding_brain)
+ holding_brain = null
+ for(var/obj/item/thing in contents)
+ qdel(thing)
+ . = ..()
+
+/obj/item/organ/internal/brain_interface/attack_self(mob/user)
+
+ if(locked)
+ to_chat(user, SPAN_WARNING("You upend \the [src], but the case is locked shut."))
+ return TRUE
+
+ if(!holding_brain)
+ to_chat(user, SPAN_WARNING("You upend \the [src], but there's nothing in it."))
+ return TRUE
+
+ to_chat(user, SPAN_NOTICE("You upend \the [src], spilling \the [holding_brain] onto \the [get_turf(src)]."))
+
+ holding_brain.dropInto(user.loc)
+ holding_brain = null
+ update_icon()
+ SetName(initial(name))
diff --git a/code/modules/brain_interface/interface_radio.dm b/code/modules/brain_interface/interface_radio.dm
new file mode 100644
index 00000000000..a793f944ce7
--- /dev/null
+++ b/code/modules/brain_interface/interface_radio.dm
@@ -0,0 +1,61 @@
+/obj/item/organ/internal/brain_interface/radio_enabled
+ name = "radio-enabled neural interface"
+ desc = "A complex life support shell that interfaces between a brain and an electronic device. This one comes with a built-in radio."
+ origin_tech = @'{"biotech":4}'
+ var/VAR_PRIVATE/weakref/_radio
+
+/obj/item/organ/internal/brain_interface/radio_enabled/empty
+ holding_brain = null
+
+/obj/item/organ/internal/brain_interface/radio_enabled/get_radio()
+ var/obj/item/radio/radio_instance = _radio?.resolve()
+ if(radio_instance && (!istype(radio_instance) || QDELETED(radio_instance) || radio_instance.loc != src))
+ radio_instance = null
+ _radio = null
+ return radio_instance?.get_radio()
+
+/obj/item/organ/internal/brain_interface/radio_enabled/Initialize()
+ _radio = weakref(new /obj/item/radio(src))
+ . = ..()
+
+/obj/item/organ/internal/brain_interface/radio_enabled/Destroy()
+ var/obj/item/radio/radio_instance = get_radio()
+ if(radio_instance)
+ qdel(radio_instance)
+ _radio = null
+ return ..()
+
+/obj/item/organ/internal/brain_interface/proc/toggle_radio_broadcasting()
+ set name = "Toggle Broadcasting"
+ set desc = "Toggle broadcasting channel on or off."
+ set category = "Brain Interface"
+ set src in view(1)
+ set popup_menu = 0
+
+ if(usr.incapacitated())
+ to_chat(usr, SPAN_WARNING("You must be alive and conscious to interact with \the [src]."))
+ return
+
+ var/obj/item/radio/radio_instance = get_radio()
+ if(istype(radio_instance))
+ radio_instance.broadcasting = !radio_instance.broadcasting
+ to_chat(usr, SPAN_NOTICE("You adjust the radio on \the [src]. It is [radio_instance.broadcasting ? "now broadcasting" : "no longer broadcasting"]."))
+ else
+ verbs -= /obj/item/organ/internal/brain_interface/proc/toggle_radio_broadcasting
+
+/obj/item/organ/internal/brain_interface/proc/toggle_radio_listening()
+ set name = "Toggle Listening"
+ set desc = "Toggle listening channel on or off."
+ set category = "Brain Interface"
+ set src in view(1)
+
+ set popup_menu = 0
+ if(usr.incapacitated())
+ to_chat(usr, SPAN_WARNING("You must be alive and conscious to interact with \the [src]."))
+ return
+ var/obj/item/radio/radio_instance = get_radio()
+ if(radio_instance)
+ radio_instance.listening = !radio_instance.listening
+ to_chat(usr, SPAN_NOTICE("You adjust the radio on \the [src]. It is [radio_instance.listening ? "now receiving broadcasts" : "no longer receiving broadcasts"]."))
+ else
+ verbs -= /obj/item/organ/internal/brain_interface/proc/toggle_radio_listening
diff --git a/code/modules/clothing/spacesuits/rig/modules/computer.dm b/code/modules/clothing/spacesuits/rig/modules/computer.dm
index edf3646c03a..d92a4c0e239 100644
--- a/code/modules/clothing/spacesuits/rig/modules/computer.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/computer.dm
@@ -57,7 +57,7 @@
origin_tech = @'{"programming":6,"materials":5,"engineering":6}'
var/mob/integrated_ai // Direct reference to the actual mob held in the suit.
- var/obj/item/ai_card // Reference to the MMI, posibrain, inteliCard or pAI card previously holding the AI.
+ var/obj/item/ai_card // Reference to the object previously holding the AI.
var/obj/item/ai_verbs/verb_holder
/mob
@@ -136,7 +136,7 @@
return 1
// Okay, it wasn't a terminal being touched, check for all the simple insertions.
- if(input_device.type in list(/obj/item/paicard, /obj/item/mmi, /obj/item/organ/internal/posibrain))
+ if(input_device.type in list(/obj/item/paicard, /obj/item/organ/internal/brain_interface))
if(integrated_ai)
integrated_ai.attackby(input_device,user)
// If the transfer was successful, we can clear out our vars.
diff --git a/code/modules/emotes/definitions/_mob.dm b/code/modules/emotes/definitions/_mob.dm
index 90598baaa78..c6fd0855eeb 100644
--- a/code/modules/emotes/definitions/_mob.dm
+++ b/code/modules/emotes/definitions/_mob.dm
@@ -42,19 +42,7 @@
/decl/emote/audible/choke,
/decl/emote/audible/moan,
/decl/emote/audible/gnarl
- )
-
-/mob/living/carbon/brain
- default_emotes = list(
- /decl/emote/audible/alarm,
- /decl/emote/audible/alert,
- /decl/emote/audible/notice,
- /decl/emote/audible/whistle,
- /decl/emote/audible/synth,
- /decl/emote/audible/boop,
- /decl/emote/visible/blink,
- /decl/emote/visible/flash
- )
+ )
/mob/living/carbon/human
default_emotes = list(
@@ -168,4 +156,4 @@
/decl/emote/audible/synth/deny,
/decl/emote/audible/synth/security,
/decl/emote/audible/synth/security/halt
- )
+ )
diff --git a/code/modules/emotes/emote_mob.dm b/code/modules/emotes/emote_mob.dm
index 24f6c9dfdb9..7713886e073 100644
--- a/code/modules/emotes/emote_mob.dm
+++ b/code/modules/emotes/emote_mob.dm
@@ -10,8 +10,8 @@
/mob/living/check_mob_can_emote(var/emote_type)
return ..() && !(HAS_STATUS(src, STAT_SILENCE) && emote_type == AUDIBLE_MESSAGE)
-/mob/living/carbon/brain/check_mob_can_emote(var/emote_type)
- return ..() && (istype(container, /obj/item/mmi) || istype(loc, /obj/item/organ/internal/posibrain))
+/mob/living/brain/check_mob_can_emote(var/emote_type)
+ return ..() && istype(get_container(), /obj/item/organ/internal/brain_interface)
/mob/proc/emote(var/act, var/m_type, var/message)
set waitfor = FALSE
diff --git a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
index e2a471367ec..3b52762f8f9 100644
--- a/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
+++ b/code/modules/fabrication/designs/protolathe/designs_machine_intelligence.dm
@@ -1,15 +1,15 @@
/datum/fabricator_recipe/protolathe/brains
category = "Machine Intelligence"
- path = /obj/item/mmi
+ path = /obj/item/organ/internal/brain_interface/empty
/datum/fabricator_recipe/protolathe/brains/get_product_name()
. = "intelligence storage ([..()])"
+/datum/fabricator_recipe/protolathe/brains/robotic
+ path = /obj/item/organ/internal/brain/robotic
+
/datum/fabricator_recipe/protolathe/brains/mmi_radio
- path = /obj/item/mmi/radio_enabled
-
-/datum/fabricator_recipe/protolathe/brains/posibrain
- path = /obj/item/organ/internal/posibrain
+ path = /obj/item/organ/internal/brain_interface/radio_enabled/empty
/datum/fabricator_recipe/protolathe/brains/paicard
path = /obj/item/paicard
diff --git a/code/modules/ghosttrap/trap.dm b/code/modules/ghosttrap/trap.dm
index 4d361a43886..73f2aade08a 100644
--- a/code/modules/ghosttrap/trap.dm
+++ b/code/modules/ghosttrap/trap.dm
@@ -1,5 +1,4 @@
-// This system is used to grab a ghost from observers with the required preferences
-// and lack of bans set. See posibrain.dm for an example of how they are called/used.
+// This system is used to grab a ghost from observers with the required preferences and lack of bans set.
/decl/ghosttrap
var/name
var/minutes_since_death = 0 // If non-zero the ghost must have been dead for this many minutes to be allowed to spawn
@@ -95,33 +94,42 @@
target.SetName(target.real_name)
/***********************************
-* Positronic brains. *
+* Computer intelligence cores. *
***********************************/
-/decl/ghosttrap/positronic_brain
- name = "positronic brain"
+/decl/ghosttrap/machine_intelligence
+ name = "machine intelligence"
ban_checks = list("AI",ASSIGNMENT_ROBOT)
- pref_check = "ghost_posibrain"
- ghost_trap_message = "They are occupying a positronic brain now."
+ pref_check = "ghost_machine_intelligence"
+ ghost_trap_message = "They are occupying a computer intelligence core now."
-/decl/ghosttrap/positronic_brain/forced(var/mob/user)
- var/obj/item/organ/internal/posibrain/brain = new(get_turf(user))
- if(!brain.brainmob)
- brain.init()
- request_player(brain.brainmob, "Someone is requesting a personality for a positronic brain.", 60 SECONDS)
+/decl/ghosttrap/machine_intelligence/transfer_personality(mob/candidate, mob/target)
+ if(assess_candidate(candidate))
-/decl/ghosttrap/positronic_brain/welcome_candidate(var/mob/target)
- to_chat(target, "You are a positronic brain, brought into existence on [station_name()].")
+ var/obj/item/organ/internal/brain/robotic/brain = target.loc?.loc
+ if(!istype(brain))
+ return FALSE
+
+ brain.transfer_key_to_brainmob(candidate, update_brainmob = FALSE)
+ brain.searching = FALSE
+ brain.update_icon()
+ announce_ghost_joinleave(candidate, 0, "[ghost_trap_message]")
+
+ var/mob/living/brainmob = brain.get_brainmob(create_if_missing = TRUE)
+ if(brainmob)
+ welcome_candidate(brainmob)
+ return TRUE
+
+/decl/ghosttrap/machine_intelligence/forced(var/mob/user)
+ var/obj/item/organ/internal/brain/robotic/brain = new(get_turf(user))
+ request_player(brain.get_brainmob(create_if_missing = TRUE), "Someone is requesting a player for a machine intelligence.", 60 SECONDS)
+
+/decl/ghosttrap/machine_intelligence/welcome_candidate(var/mob/target)
+ to_chat(target, "You are a machine intelligence, brought into existence on [station_name()].")
to_chat(target, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.")
to_chat(target, "Remember, the purpose of your existence is to serve the crew and the [station_name()]. Above all else, do no harm.")
to_chat(target, "Use say [target.get_language_prefix()]b to speak to other artificial intelligences.")
var/turf/T = get_turf(target)
- var/obj/item/organ/internal/posibrain/P = target.loc
- T.visible_message("\The [P] chimes quietly.")
- if(!istype(P)) //wat
- return
- P.searching = 0
- P.SetName("positronic brain ([P.brainmob.name])")
- P.update_icon()
+ T.visible_message(SPAN_NOTICE("\The [target] beeps loudly."))
/***********************************
* Walking mushrooms and such. *
diff --git a/code/modules/integrated_electronics/subtypes/manipulation.dm b/code/modules/integrated_electronics/subtypes/manipulation.dm
index d3e1fff3922..869bb426379 100644
--- a/code/modules/integrated_electronics/subtypes/manipulation.dm
+++ b/code/modules/integrated_electronics/subtypes/manipulation.dm
@@ -654,7 +654,7 @@
/obj/item/integrated_circuit/manipulation/ai/attackby(var/obj/item/I, var/mob/user)
- if(is_type_in_list(I, list(/obj/item/aicard, /obj/item/paicard, /obj/item/mmi)))
+ if(is_type_in_list(I, list(/obj/item/aicard, /obj/item/paicard, /obj/item/organ/internal/brain_interface)))
load_ai(user, I)
else return ..()
diff --git a/code/modules/mob/death.dm b/code/modules/mob/death.dm
index e3d6ca61dcb..a8945326700 100644
--- a/code/modules/mob/death.dm
+++ b/code/modules/mob/death.dm
@@ -26,7 +26,7 @@
//This is the proc for turning a mob into ash. Mostly a copy of gib code (above).
//Originally created for wizard disintegrate. I've removed the virus code since it's irrelevant here.
-//Dusting robots does not eject the MMI, so it's a bit more powerful than gib() /N
+//Dusting robots does not eject the brain, so it's a bit more powerful than gib() /N
/mob/proc/dust(anim="dust-m",remains=/obj/effect/decal/cleanable/ash)
death(1)
var/atom/movable/overlay/animation = null
diff --git a/code/modules/mob/living/brain/brain.dm b/code/modules/mob/living/brain/brain.dm
new file mode 100644
index 00000000000..faa6edb9b7f
--- /dev/null
+++ b/code/modules/mob/living/brain/brain.dm
@@ -0,0 +1,117 @@
+/mob/living/brain
+ name = "brain"
+ icon = 'icons/obj/surgery.dmi'
+ icon_state = "brain1"
+ default_emotes = list(
+ /decl/emote/audible/alarm,
+ /decl/emote/audible/alert,
+ /decl/emote/audible/notice,
+ /decl/emote/audible/whistle,
+ /decl/emote/audible/synth,
+ /decl/emote/audible/boop,
+ /decl/emote/visible/blink,
+ /decl/emote/visible/flash
+ )
+
+ // Used for EMP damage when inside an interface or robobrain.
+ var/emp_damage = 0
+ var/last_emp_message = 0
+ var/static/max_emp_damage = 30
+ var/static/list/emp_reboot_strings = list(
+ SPAN_NOTICE("System reboot nearly complete."),
+ SPAN_NOTICE("Primary systems are now online."),
+ SPAN_DANGER("Major electrical distruption detected: System rebooting.")
+ )
+
+/mob/living/brain/handle_regular_status_updates()
+ . = ..()
+ if(emp_damage || stat == DEAD || !is_in_interface())
+ SET_STATUS_MAX(src, STAT_SILENCE, 2)
+
+/mob/living/brain/death()
+ var/obj/item/organ/holder = loc
+ . = ..()
+ if(stat == DEAD && istype(holder))
+ holder.die()
+
+/mob/living/brain/is_deaf()
+ return emp_damage || stat == DEAD || !is_in_interface()
+
+/mob/living/brain/is_blind()
+ return emp_damage || stat == DEAD || !is_in_interface()
+
+/mob/living/brain/Logout()
+ . = ..()
+ var/obj/item/organ/internal/container = get_container()
+ if(istype(container))
+ container.queue_icon_update()
+
+/mob/living/brain/proc/get_container()
+ . = loc?.loc
+
+/mob/living/brain/Login()
+ . = ..()
+ var/obj/item/organ/internal/container = get_container()
+ if(istype(container))
+ var/obj/item/organ/internal/brain_interface/interface = container
+ if(istype(interface))
+ interface.locked = TRUE
+ container.update_icon()
+
+/mob/living/brain/proc/is_in_interface()
+ var/container = get_container()
+ return istype(container, /obj/item/organ/internal/brain_interface) || istype(container, /obj/item/organ/internal/brain/robotic)
+
+/mob/living/brain/can_emote()
+ return is_in_interface() && ..()
+
+/mob/living/brain/can_use_rig()
+ return is_in_interface()
+
+/mob/living/brain/Destroy()
+ ghostize()
+ . = ..()
+
+/mob/living/brain/say_understands(var/other)
+ . = ishuman(other) || (is_in_interface() && issilicon(other)) || ..()
+
+/mob/living/brain/UpdateLyingBuckledAndVerbStatus()
+ return
+
+/mob/living/brain/isSynthetic()
+ return istype(get_container(), /obj/item/organ/internal/brain/robotic)
+
+/mob/living/brain/binarycheck()
+ return isSynthetic()
+
+/mob/living/brain/check_has_mouth()
+ return FALSE
+
+/mob/living/brain/emp_act(severity)
+ if(!isSynthetic())
+ return
+ switch(severity)
+ if(1)
+ emp_damage += rand(20,30)
+ if(2)
+ emp_damage += rand(10,20)
+ if(3)
+ emp_damage += rand(0,10)
+ emp_damage = clamp(emp_damage, 0, max_emp_damage)
+
+/mob/living/brain/handle_regular_status_updates() // Status & health update, are we dead or alive etc.
+ . = ..()
+ if(stat == DEAD || !isSynthetic())
+ emp_damage = 0
+ return
+ if(emp_damage <= 0)
+ return
+ emp_damage -= 1
+ var/msg_threshold = clamp(CEILING(emp_damage / (max_emp_damage / length(emp_reboot_strings))), 1, length(emp_reboot_strings))
+ if(last_emp_message != msg_threshold)
+ last_emp_message = msg_threshold
+ to_chat(src, emp_reboot_strings[msg_threshold])
+ if(emp_damage <= 0)
+ last_emp_message = 0
+ emp_damage = 0
+ to_chat(src, SPAN_NOTICE("All systems restored."))
diff --git a/code/modules/mob/living/brain/death.dm b/code/modules/mob/living/brain/death.dm
new file mode 100644
index 00000000000..0a70b0d7683
--- /dev/null
+++ b/code/modules/mob/living/brain/death.dm
@@ -0,0 +1,17 @@
+/mob/living/brain/death(gibbed)
+ var/death_message = "no message"
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ if(!gibbed && istype(container))
+ death_message = "beeps shrilly as \the [container] flatlines!"
+ . = ..(gibbed, death_message)
+ if(istype(container))
+ container.update_icon()
+
+/mob/living/brain/gib()
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ var/obj/item/organ/internal/brain/sponge = loc
+ . = ..(null, 1)
+ if(container && !QDELETED(container))
+ qdel(container)
+ if(istype(sponge) && !QDELETED(sponge))
+ qdel(sponge)
diff --git a/code/modules/mob/living/brain/say.dm b/code/modules/mob/living/brain/say.dm
new file mode 100644
index 00000000000..4a59e86f064
--- /dev/null
+++ b/code/modules/mob/living/brain/say.dm
@@ -0,0 +1,16 @@
+/mob/living/brain/say(var/message, var/decl/language/speaking, var/verb = "says", var/alt_name = "", whispering)
+ if(GET_STATUS(src, STAT_SILENCE) || !is_in_interface())
+ return
+ if(prob(emp_damage*4))
+ if(prob(10))
+ return
+ message = Gibberish(message, (emp_damage*6))
+ . = ..(message, speaking, verb, alt_name, whispering)
+ var/obj/item/radio/radio = get_radio()
+ if(radio)
+ radio.hear_talk(src, sanitize(message), verb, speaking)
+
+/mob/living/brain/get_radio()
+ var/obj/item/organ/internal/brain_interface/container = get_container()
+ if(istype(container))
+ return container.get_radio()
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
deleted file mode 100644
index a8eca098a30..00000000000
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ /dev/null
@@ -1,189 +0,0 @@
-/obj/item/mmi/digital/Initialize()
- brainmob = new(src)
- brainmob.set_stat(CONSCIOUS)
- brainmob.add_language(/decl/language/binary)
- brainmob.add_language(/decl/language/machine)
- brainmob.container = src
- brainmob.set_status(STAT_SILENCE, 0)
- PickName()
- . = ..()
-
-/obj/item/mmi/digital/proc/PickName()
- return
-
-/obj/item/mmi/digital/attackby()
- return
-
-/obj/item/mmi/digital/attack_self()
- return
-
-/obj/item/mmi
- name = "\improper Man-Machine Interface"
- desc = "A complex life support shell that interfaces between a brain and electronic devices."
- icon = 'icons/obj/assemblies.dmi'
- icon_state = "mmi_empty"
- w_class = ITEM_SIZE_NORMAL
- origin_tech = @'{"biotech":3}'
- material = /decl/material/solid/metal/steel
- matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT)
- req_access = list(access_robotics)
-
- //Revised. Brainmob is now contained directly within object of transfer. MMI in this case.
-
- var/locked = 0
- var/mob/living/carbon/brain/brainmob = null//The current occupant.
- var/obj/item/organ/internal/brain/brainobj = null //The current brain organ.
-
-/obj/item/mmi/attackby(var/obj/item/O, var/mob/user)
- if(istype(O,/obj/item/organ/internal/brain) && !brainmob) //Time to stick a brain in it --NEO
-
- var/obj/item/organ/internal/brain/B = O
- if(B.damage >= B.max_damage)
- to_chat(user, "That brain is well and truly dead.")
- return
- else if(!B.brainmob || !B.can_use_mmi)
- to_chat(user, "This brain is completely useless to you.")
- return
- if(!user.try_unequip(O, src))
- return
- user.visible_message("\The [user] sticks \a [O] into \the [src].")
-
- brainmob = B.brainmob
- B.brainmob = null
- brainmob.forceMove(src)
- brainmob.container = src
- brainmob.set_stat(CONSCIOUS)
- brainmob.switch_from_dead_to_living_mob_list() //Update dem lists
-
- brainobj = O
-
- SetName("[initial(name)]: ([brainmob.real_name])")
- update_icon()
-
- locked = 1
-
- SSstatistics.add_field("cyborg_mmis_filled",1)
-
- return
-
- if((istype(O,/obj/item/card/id)||istype(O,/obj/item/modular_computer)) && brainmob)
- if(allowed(user))
- locked = !locked
- to_chat(user, "You [locked ? "lock" : "unlock"] the brain holder.")
- else
- to_chat(user, "Access denied.")
- return
- if(brainmob)
- O.attack(brainmob, user)//Oh noooeeeee
- return
- ..()
-
- //TODO: ORGAN REMOVAL UPDATE. Make the brain remain in the MMI so it doesn't lose organ data.
-/obj/item/mmi/attack_self(mob/user)
- if(!brainmob)
- to_chat(user, "You upend the MMI, but there's nothing in it.")
- else if(locked)
- to_chat(user, "You upend the MMI, but the brain is clamped into place.")
- else
- to_chat(user, "You upend the MMI, spilling the brain onto the floor.")
- var/obj/item/organ/internal/brain/brain
- if (brainobj) //Pull brain organ out of MMI.
- brainobj.forceMove(user.loc)
- brain = brainobj
- brainobj = null
- else //Or make a new one if empty.
- brain = new(user.loc)
- brainmob.container = null//Reset brainmob mmi var.
- brainmob.forceMove(brain)//Throw mob into brain.
- brainmob.remove_from_living_mob_list() //Get outta here
- brain.brainmob = brainmob//Set the brain to use the brainmob
- brainmob = null//Set mmi brainmob var to null
-
- update_icon()
- SetName(initial(name))
-
-/obj/item/mmi/proc/transfer_identity(var/mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people.
- brainmob = new(src)
- brainmob.SetName(H.real_name)
- brainmob.real_name = H.real_name
- brainmob.dna = H.dna
- brainmob.container = src
- brainmob.timeofhostdeath = H.timeofdeath
- brainmob.set_stat(CONSCIOUS)
-
- SetName("[initial(name)]: [brainmob.real_name]")
- update_icon()
- locked = 1
-
-/obj/item/mmi/preserve_in_cryopod(obj/machinery/cryopod/pod)
- return brainmob && brainmob.client && brainmob.key
-
-/obj/item/mmi/relaymove(var/mob/user, var/direction)
- if(user.incapacitated(INCAPACITATION_KNOCKOUT))
- return
- var/obj/item/rig/rig = get_rig()
- if(rig)
- rig.forced_move(direction, user)
-
-/obj/item/mmi/Destroy()
- if(isrobot(loc))
- var/mob/living/silicon/robot/borg = loc
- borg.mmi = null
- QDEL_NULL(brainmob)
- return ..()
-
-/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":4}'
- material = /decl/material/solid/metal/steel
- matter = list(/decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT)
- var/obj/item/radio/radio = null//Let's give it a radio.
-
-/obj/item/mmi/radio_enabled/Initialize()
- . = ..()
- radio = new(src)//Spawns a radio inside the MMI.
- radio.broadcasting = 1//So it's broadcasting from the start.
-
-/obj/item/mmi/radio_enabled/verb/Toggle_Broadcasting() //Allows the brain to toggle the radio functions.
- set name = "Toggle Broadcasting"
- set desc = "Toggle broadcasting channel on or off."
- set category = "MMI"
- set src = usr.loc//In user location, or in MMI in this case.
- set popup_menu = 0//Will not appear when right clicking.
-
- if(brainmob.stat)//Only the brainmob will trigger these so no further check is necessary.
- to_chat(brainmob, "Can't do that while incapacitated or dead.")
-
- radio.broadcasting = radio.broadcasting==1 ? 0 : 1
- to_chat(brainmob, "Radio is [radio.broadcasting==1 ? "now" : "no longer"] broadcasting.")
-
-/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
-
- if(brainmob.stat)
- to_chat(brainmob, "Can't do that while incapacitated or dead.")
-
- radio.listening = radio.listening==1 ? 0 : 1
- to_chat(brainmob, "Radio is [radio.listening==1 ? "now" : "no longer"] receiving broadcast.")
-
-/obj/item/mmi/emp_act(severity)
- if(!brainmob)
- return
- else
- switch(severity)
- if(1)
- brainmob.emp_damage += rand(20,30)
- if(2)
- brainmob.emp_damage += rand(10,20)
- if(3)
- brainmob.emp_damage += rand(0,10)
- ..()
-
-/obj/item/mmi/on_update_icon()
- . = ..()
- icon_state = brainmob ? "mmi_full" : "mmi_empty"
diff --git a/code/modules/mob/living/carbon/brain/brain.dm b/code/modules/mob/living/carbon/brain/brain.dm
deleted file mode 100644
index 3eac062963b..00000000000
--- a/code/modules/mob/living/carbon/brain/brain.dm
+++ /dev/null
@@ -1,38 +0,0 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:32
-
-/mob/living/carbon/brain
- var/obj/item/container = null
- var/timeofhostdeath = 0
- var/emp_damage = 0//Handles a type of MMI damage
- var/alert = null
- icon = 'icons/obj/surgery.dmi'
- icon_state = "brain1"
- mob_sort_value = 7
-
-/mob/living/carbon/brain/can_emote()
- return stat == CONSCIOUS && (istype(container, /obj/item/mmi) || istype(loc, /obj/item/organ/internal/posibrain))
-
-/mob/living/carbon/brain/Initialize()
- create_reagents(1000)
- . = ..()
-
-/mob/living/carbon/brain/Destroy()
- if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
- ghostize() //Ghostize checks for key so nothing else is necessary.
- . = ..()
-
-/mob/living/carbon/brain/say_understands(mob/speaker, decl/language/speaking)
- return (issilicon(speaker) && (istype(container, /obj/item/mmi) || istype(loc, /obj/item/organ/internal/posibrain))) || ishuman(speaker) || ..()
-
-/mob/living/carbon/brain/UpdateLyingBuckledAndVerbStatus()
- return
-
-/mob/living/carbon/brain/isSynthetic()
- return istype(container, /obj/item/mmi/digital) || istype(loc, /obj/item/organ/internal/posibrain)
-
-/mob/living/carbon/brain/binarycheck()
- return isSynthetic()
-
-/mob/living/carbon/brain/check_has_mouth()
- return FALSE
-
diff --git a/code/modules/mob/living/carbon/brain/death.dm b/code/modules/mob/living/carbon/brain/death.dm
deleted file mode 100644
index 5f728287cec..00000000000
--- a/code/modules/mob/living/carbon/brain/death.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-/mob/living/carbon/brain/death(gibbed)
- if(!gibbed && istype(container, /obj/item/mmi)) //If not gibbed but in a container.
- container.icon_state = "mmi_dead"
- return ..(gibbed,"beeps shrilly as the MMI flatlines!")
- else
- return ..(gibbed,"no message")
-
-/mob/living/carbon/brain/gib(anim="gibbed-m",do_gibs)
- if(istype(container, /obj/item/mmi))
- qdel(container)//Gets rid of the MMI if there is one
- if(loc)
- if(istype(loc,/obj/item/organ/internal/brain))
- qdel(loc)//Gets rid of the brain item
- ..(null,1)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/brain/life.dm b/code/modules/mob/living/carbon/brain/life.dm
deleted file mode 100644
index 692e2ce7fcf..00000000000
--- a/code/modules/mob/living/carbon/brain/life.dm
+++ /dev/null
@@ -1,170 +0,0 @@
-/mob/living/carbon/brain/need_breathe()
- return FALSE
-
-/mob/living/carbon/brain/should_breathe()
- return FALSE
-
-/mob/living/carbon/brain/handle_mutations_and_radiation()
- ..()
- if (radiation)
- if (radiation > 100)
- radiation = 100
- if(!container)//If it's not in an MMI
- to_chat(src, "You feel weak.")
- else//Fluff-wise, since the brain can't detect anything itself, the MMI handles thing like that
- to_chat(src, "STATUS: CRITICAL AMOUNTS OF RADIATION DETECTED.")
- switch(radiation)
- if(1 to 49)
- radiation--
- if(prob(25))
- adjustToxLoss(1)
-
- if(50 to 74)
- radiation -= 2
- adjustToxLoss(1)
- if(prob(5))
- radiation -= 5
- if(!container)
- to_chat(src, "You feel weak.")
- else
- to_chat(src, "STATUS: DANGEROUS LEVELS OF RADIATION DETECTED.")
-
- if(75 to 100)
- radiation -= 3
- adjustToxLoss(3)
-
-/mob/living/carbon/brain/handle_environment(datum/gas_mixture/environment)
- ..()
- if(!environment)
- return
- var/environment_heat_capacity = environment.heat_capacity()
- if(isspaceturf(get_turf(src)))
- var/turf/heat_turf = get_turf(src)
- environment_heat_capacity = heat_turf.heat_capacity
- if((environment.temperature > (T0C + 50)) || (environment.temperature < (T0C + 10)))
- var/transfer_coefficient = 1
- handle_temperature_damage(SLOT_HEAD, environment.temperature, environment_heat_capacity*transfer_coefficient)
- if(stat == DEAD)
- bodytemperature += 0.1*(environment.temperature - bodytemperature)*environment_heat_capacity/(environment_heat_capacity + 270000)
-
-
-/mob/living/carbon/brain/proc/handle_temperature_damage(body_part, exposed_temperature, exposed_intensity)
- if(status_flags & GODMODE) return
- if(exposed_temperature > bodytemperature)
- var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
- adjustFireLoss(20.0*discomfort)
- else
- var/discomfort = min( abs(exposed_temperature - bodytemperature)*(exposed_intensity)/2000000, 1.0)
- adjustFireLoss(5.0*discomfort)
-
-/mob/living/carbon/brain/apply_chemical_effects()
- . = ..()
- if(resting)
- ADJ_STATUS(src, STAT_DIZZY, -4)
- return TRUE
-
-/mob/living/carbon/brain/is_blind()
- return !container || ..()
-
-/mob/living/carbon/brain/should_be_dead()
- if(container)
- return FALSE
- if(current_health >= get_config_value(/decl/config/num/health_health_threshold_dead))
- return FALSE
- var/revival_brain_life = get_config_value(/decl/config/num/health_revival_brain_life)
- return revival_brain_life >= 0 && (world.time - timeofhostdeath) > revival_brain_life
-
-/mob/living/carbon/brain/handle_regular_status_updates()
-
- . = ..()
- if(!. || stat == DEAD || !emp_damage || !container)
- return
-
- //Handling EMP effect in the Life(), it's made VERY simply, and has some additional effects handled elsewhere
- //This is pretty much a damage type only used by MMIs, dished out by the emp_act
- emp_damage = round(emp_damage,1)//Let's have some nice numbers to work with
- switch(emp_damage)
- if(31 to INFINITY)
- emp_damage = 30//Let's not overdo it
- if(21 to 30)//High level of EMP damage, unable to see, hear, or speak
- SET_STATUS_MAX(src, STAT_BLIND, 2)
- SET_STATUS_MAX(src, STAT_DEAF, 1)
- set_status(STAT_SILENCE, 1)
- if(!alert)//Sounds an alarm, but only once per 'level'
- emote("alarm")
- to_chat(src, SPAN_WARNING("Major electrical distruption detected: System rebooting."))
- alert = 1
- if(prob(75))
- emp_damage -= 1
- if(20)
- alert = 0
- set_status(STAT_BLIND, 0)
- set_status(STAT_DEAF, 0)
- set_status(STAT_SILENCE, 0)
- emp_damage -= 1
- if(11 to 19)//Moderate level of EMP damage, resulting in nearsightedness and ear damage
- set_status(STAT_BLURRY, 1)
- set_status(STAT_TINNITUS, 1)
- if(!alert)
- emote("alert")
- to_chat(src, SPAN_WARNING("Primary systems are now online."))
- alert = 1
- if(prob(50))
- emp_damage -= 1
- if(10)
- alert = 0
- set_status(STAT_BLURRY, 0)
- set_status(STAT_TINNITUS, 0)
- emp_damage -= 1
- if(2 to 9)//Low level of EMP damage, has few effects(handled elsewhere)
- if(!alert)
- emote("notice")
- to_chat(src, SPAN_WARNING("System reboot nearly complete."))
- alert = 1
- if(prob(25))
- emp_damage -= 1
- if(1)
- alert = 0
- to_chat(src, SPAN_WARNING("All systems restored."))
- emp_damage -= 1
-
-/mob/living/carbon/brain/handle_regular_hud_updates()
- . = ..()
- if(!.)
- return
- update_sight()
- if (healths)
- if (stat != DEAD)
- switch(current_health)
- if(100 to INFINITY)
- healths.icon_state = "health0"
- if(80 to 100)
- healths.icon_state = "health1"
- if(60 to 80)
- healths.icon_state = "health2"
- if(40 to 60)
- healths.icon_state = "health3"
- if(20 to 40)
- healths.icon_state = "health4"
- if(0 to 20)
- healths.icon_state = "health5"
- else
- healths.icon_state = "health6"
- else
- healths.icon_state = "health7"
-
- if(stat != DEAD)
- if(is_blind())
- overlay_fullscreen("blind", /obj/screen/fullscreen/blind)
- else
- clear_fullscreen("blind")
- set_fullscreen(disabilities & NEARSIGHTED, "impaired", /obj/screen/fullscreen/impaired, 1)
- set_fullscreen(GET_STATUS(src, STAT_BLURRY), "blurry", /obj/screen/fullscreen/blurry)
- set_fullscreen(GET_STATUS(src, STAT_DRUGGY), "high", /obj/screen/fullscreen/high)
- if (machine)
- if (!( machine.check_eye(src) ))
- reset_view(null)
- return 1
-
-/mob/living/carbon/brain/can_change_intent()
- return TRUE
diff --git a/code/modules/mob/living/carbon/brain/login.dm b/code/modules/mob/living/carbon/brain/login.dm
deleted file mode 100644
index 4f8a38ca269..00000000000
--- a/code/modules/mob/living/carbon/brain/login.dm
+++ /dev/null
@@ -1,3 +0,0 @@
-/mob/living/carbon/brain/Login()
- ..()
- set_status(STAT_ASLEEP, 0)
diff --git a/code/modules/mob/living/carbon/brain/robot.dm b/code/modules/mob/living/carbon/brain/robot.dm
deleted file mode 100644
index 4c689adfe65..00000000000
--- a/code/modules/mob/living/carbon/brain/robot.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/obj/item/mmi/digital/robot
- name = "robotic intelligence circuit"
- desc = "The pinnacle of artifical intelligence which can be achieved using classical computer science."
- icon = 'icons/obj/modules/module_mainboard.dmi'
- icon_state = ICON_STATE_WORLD
- w_class = ITEM_SIZE_NORMAL
- origin_tech = @'{"engineering":4,"materials":3,"programming":4}'
-
-/obj/item/mmi/digital/robot/PickName()
- src.brainmob.SetName("[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[random_id(type,1000,9999)]")
- src.brainmob.real_name = src.brainmob.name
-
-/obj/item/mmi/digital/robot/on_update_icon()
- . = ..()
- icon_state = initial(icon_state)
diff --git a/code/modules/mob/living/carbon/brain/say.dm b/code/modules/mob/living/carbon/brain/say.dm
deleted file mode 100644
index 793e0ea9033..00000000000
--- a/code/modules/mob/living/carbon/brain/say.dm
+++ /dev/null
@@ -1,38 +0,0 @@
-//TODO: Convert this over for languages.
-/mob/living/carbon/brain/say(var/message)
- if(HAS_STATUS(src, STAT_SILENCE))
- return
-
- message = sanitize(message)
-
- if(!(container && istype(container, /obj/item/mmi)))
- return //No MMI, can't speak, bucko./N
- else
- var/decl/language/speaking = parse_language(message)
- if(speaking)
- message = copytext(message, 2+length(speaking.key))
- var/verb = "says"
- var/ending = copytext(message, length(message))
- if (speaking)
- verb = speaking.get_spoken_verb(src, ending)
- else
- if(ending=="!")
- verb=pick("exclaims","shouts","yells")
- if(ending=="?")
- verb="asks"
-
- if(prob(emp_damage*4))
- if(prob(10))//10% chane to drop the message entirely
- return
- else
- message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
-
- if(speaking && speaking.flags & LANG_FLAG_HIVEMIND)
- speaking.broadcast(src,trim(message))
- return
-
- if(istype(container, /obj/item/mmi/radio_enabled))
- var/obj/item/mmi/radio_enabled/R = container
- if(R.radio)
- spawn(0) R.radio.hear_talk(src, sanitize(message), verb, speaking)
- ..(trim(message), speaking, verb)
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 2b2ec274b61..0bd6e1fb1e5 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -47,11 +47,14 @@
deathmessage = species.get_death_message(src) || "seizes up and falls limp..."
else
deathmessage = "no message"
+
. = ..(gibbed, deathmessage, show_dead_message)
+
if(!gibbed)
handle_organs()
if(species.death_sound)
playsound(loc, species.death_sound, 80, 1, 1)
+
handle_hud_list()
/mob/living/carbon/human/proc/is_husked()
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index e6dbd75befe..b49c1dd1ad2 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -400,7 +400,7 @@
reset_blood()
if(!client || !key) //Don't boot out anyone already in the mob.
- for(var/mob/living/carbon/brain/brain in global.player_list) // This is really nasty, does it even work anymore?
+ for(var/mob/living/brain/brain in global.player_list) // This is really nasty, does it even work anymore?
if(brain.real_name == src.real_name && brain.mind)
brain.mind.transfer_to(src)
qdel(brain.loc)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index dabfafbc503..8f2b8462ee2 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -104,7 +104,7 @@ var/global/list/ai_verbs_default = list(
src.verbs -= ai_verbs_default
src.verbs += /mob/living/verb/ghost
-/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/obj/item/mmi/B, var/safety = 0)
+/mob/living/silicon/ai/Initialize(mapload, var/datum/ai_laws/L, var/obj/item/organ/internal/brain_interface/B, var/safety = 0)
announcement = new()
announcement.title = "A.I. Announcement"
announcement.announcement_type = "A.I. Announcement"
@@ -144,11 +144,12 @@ var/global/list/ai_verbs_default = list(
add_language(/decl/language/sign, 0)
if(!safety)//Only used by AIize() to successfully spawn an AI.
- if (!B)//If there is no player/brain inside.
+ var/mob/living/brainmob = B?.get_brainmob()
+ if(!brainmob) // If there is no player/brain inside.
empty_playable_ai_cores += new/obj/structure/aicore/deactivated(loc)//New empty terminal.
. = INITIALIZE_HINT_QDEL
- else if(B.brainmob.mind)
- B.brainmob.mind.transfer_to(src)
+ else if(brainmob.mind)
+ brainmob.mind.transfer_to(src)
hud_list[HEALTH_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
hud_list[STATUS_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
hud_list[LIFE_HUD] = new /image/hud_overlay('icons/mob/hud.dmi', src, "hudblank")
diff --git a/code/modules/mob/living/silicon/robot/component.dm b/code/modules/mob/living/silicon/robot/component.dm
index 245fce44990..3fd56f6b134 100644
--- a/code/modules/mob/living/silicon/robot/component.dm
+++ b/code/modules/mob/living/silicon/robot/component.dm
@@ -1,4 +1,4 @@
-// TODO: remove the robot.mmi and robot.cell variables and completely rely on the robot component system
+// TODO: remove the robot.central_processor and robot.cell variables and completely rely on the robot component system
/datum/robot_component/var/name
/datum/robot_component/var/installed = 0
diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm
index c275e273f0f..655e3a9c54f 100644
--- a/code/modules/mob/living/silicon/robot/death.dm
+++ b/code/modules/mob/living/silicon/robot/death.dm
@@ -1,7 +1,5 @@
/mob/living/silicon/robot/dust()
- //Delete the MMI first so that it won't go popping out.
- if(mmi)
- qdel(mmi)
+ clear_brain()
..()
/mob/living/silicon/robot/death(gibbed,deathmessage, show_dead_message)
diff --git a/code/modules/mob/living/silicon/robot/drone/drone.dm b/code/modules/mob/living/silicon/robot/drone/drone.dm
index 31414a6c4f4..57ed84e6ed3 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone.dm
@@ -46,7 +46,7 @@
default_language = /decl/language/binary/drone
// NO BRAIN.
- mmi = null
+ central_processor = null
//We need to screw with their HP a bit. They have around one fifth as much HP as a full borg.
for(var/V in components) if(V != "power cell")
diff --git a/code/modules/mob/living/silicon/robot/drone/drone_items.dm b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
index 20b5a0bf3d8..cef20e56fe9 100644
--- a/code/modules/mob/living/silicon/robot/drone/drone_items.dm
+++ b/code/modules/mob/living/silicon/robot/drone/drone_items.dm
@@ -76,12 +76,11 @@
can_hold = list(
/obj/item/cell,
/obj/item/stock_parts,
- /obj/item/mmi,
+ /obj/item/organ/internal/brain_interface,
/obj/item/robot_parts,
/obj/item/borg/upgrade,
/obj/item/flash,
/obj/item/organ/internal/brain,
- /obj/item/organ/internal/posibrain,
/obj/item/stack/cable_coil,
/obj/item/stock_parts/circuitboard,
/obj/item/chems/glass,
diff --git a/code/modules/mob/living/silicon/robot/life.dm b/code/modules/mob/living/silicon/robot/life.dm
index 46eead28499..bf9ed519c5d 100644
--- a/code/modules/mob/living/silicon/robot/life.dm
+++ b/code/modules/mob/living/silicon/robot/life.dm
@@ -242,7 +242,7 @@
if (src.client)
src.client.screen -= src.contents
for(var/obj/I in src.contents)
- if(I && !(istype(I,/obj/item/cell) || istype(I,/obj/item/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/mmi)))
+ if(I && !(istype(I,/obj/item/cell) || istype(I,/obj/item/radio) || istype(I,/obj/machinery/camera) || istype(I,/obj/item/organ/internal/brain_interface)))
src.client.screen += I
if(src.module_state_1)
src.module_state_1:screen_loc = ui_inv1
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index e7c0646d9f3..6bfee52611b 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -60,7 +60,7 @@
// Components are basically robot organs.
var/list/components = list()
- var/obj/item/mmi/mmi = null
+ var/obj/item/organ/internal/central_processor
var/opened = 0
var/emagged = 0
@@ -195,21 +195,15 @@
return amount
return 0
-//If there's an MMI in the robot, have it ejected when the mob goes away. --NEO
-//Improved /N
/mob/living/silicon/robot/Destroy()
- if(mmi)//Safety for when a cyborg gets dust()ed. Or there is no MMI inside.
- if(mind)
- mmi.dropInto(loc)
- if(mmi.brainmob)
- mind.transfer_to(mmi.brainmob)
- else
- to_chat(src, "Oops! Something went very wrong, your MMI was unable to receive your mind. You have been ghosted. Please make a bug report so we can fix this bug.")
- ghostize()
- //ERROR("A borg has been destroyed, but its MMI lacked a brainmob, so the mind could not be transferred. Player: [ckey].")
- mmi = null
+ if(central_processor)
+ central_processor.dropInto(loc)
+ var/mob/living/brainmob = central_processor.get_brainmob()
+ if(mind && brainmob)
+ mind.transfer_to(brainmob)
else
- QDEL_NULL(mmi)
+ ghostize()
+ central_processor = null
if(connected_ai)
connected_ai.connected_robots -= src
connected_ai = null
@@ -280,12 +274,10 @@
if(prefix)
modtype = prefix
- if(istype(mmi, /obj/item/organ/internal/posibrain))
- braintype = "Robot"
- else if(istype(mmi, /obj/item/mmi/digital/robot))
- braintype = "Drone"
+ if(istype(central_processor))
+ braintype = central_processor.get_synthetic_owner_name()
else
- braintype = "Cyborg"
+ braintype = "Robot"
var/changed_name = ""
if(custom_name)
@@ -514,24 +506,31 @@
else if(IS_CROWBAR(W) && user.a_intent != I_HURT) // crowbar means open or close the cover - we all know what a crowbar is by now
if(opened)
if(cell)
- user.visible_message("\The [user] begins clasping shut \the [src]'s maintenance hatch.", "You begin closing up \the [src].")
+
+ user.visible_message(
+ SPAN_NOTICE("\The [user] begins clasping shut \the [src]'s maintenance hatch."),
+ SPAN_NOTICE("You begin closing up \the [src]."))
+
if(do_after(user, 50, src))
- to_chat(user, "You close \the [src]'s maintenance hatch.")
+ to_chat(user, SPAN_NOTICE("You close \the [src]'s maintenance hatch."))
opened = 0
update_icon()
else if(wiresexposed && wires.IsAllCut())
- //Cell is out, wires are exposed, remove MMI, produce damaged chassis, baleet original mob.
- if(!mmi)
- to_chat(user, "\The [src] has no brain to remove.")
+ //Cell is out, wires are exposed, remove CPU, produce damaged chassis, baleet original mob.
+ if(!central_processor)
+ to_chat(user, "\The [src] has no central processor to remove.")
return
- user.visible_message("\The [user] begins ripping [mmi] from [src].", "You jam the crowbar into the robot and begin levering [mmi].")
+ user.visible_message(
+ SPAN_NOTICE("\The [user] begins ripping \the [central_processor] out of \the [src]."),
+ SPAN_NOTICE("You jam the crowbar into the robot and begin levering out \the [central_processor]."))
+
if(do_after(user, 50, src))
dismantle(user)
else
- // Okay we're not removing the cell or an MMI, but maybe something else?
+ // Okay we're not removing the cell or a CPU, but maybe something else?
var/list/removable_components = list()
for(var/V in components)
if(V == "power cell") continue
@@ -1099,7 +1098,10 @@
return ASSIGNMENT_ROBOT
/mob/living/silicon/robot/handle_pre_transformation()
- QDEL_NULL(mmi)
+ clear_brain()
+
+/mob/living/silicon/robot/proc/clear_brain()
+ QDEL_NULL(central_processor)
/mob/living/silicon/robot/do_flash_animation()
set waitfor = FALSE
diff --git a/code/modules/mob/mob_transformation_simple.dm b/code/modules/mob/mob_transformation_simple.dm
index f9f04a6e329..e4f273ad596 100644
--- a/code/modules/mob/mob_transformation_simple.dm
+++ b/code/modules/mob/mob_transformation_simple.dm
@@ -50,7 +50,7 @@ var/global/list/href_to_mob_type = list(
//This proc is the most basic of the procs. All it does is make a new mob on the same tile and transfer over a few variables.
//Returns the new mob
-//Note that this proc does NOT do MMI related stuff!
+//Note that this proc does NOT do brain related stuff!
/mob/proc/change_mob_type(var/new_type, var/turf/location, var/new_name, var/subspecies)
if(!new_type)
diff --git a/code/modules/mob/skills/skill.dm b/code/modules/mob/skills/skill.dm
index 7f7dcbed4e1..6525d69a964 100644
--- a/code/modules/mob/skills/skill.dm
+++ b/code/modules/mob/skills/skill.dm
@@ -334,7 +334,7 @@ var/global/list/skills = list()
levels = list(
"Unskilled" = "You know how to use the technology that was present in whatever society you grew up in. You know how to tell when something is malfunctioning, but you have to call tech support to get it fixed.",
"Basic" = "You use and repair high-tech equipment in the course of your daily work. You can fix simple problems, and you know how to use a circuit printer or autolathe. You can build simple robots such as cleanbots and medibots.",
- "Trained" = "You can build or repair an exosuit or cyborg chassis, use advanced fabricators and analyzers, and build prosthetic limbs. You can safely transfer an MMI or posibrain into a cyborg chassis.
- You can attach robotic limbs. Its speed increases with level.",
+ "Trained" = "You can build or repair an exosuit or cyborg chassis, use advanced fabricators and analyzers, and build prosthetic limbs. You can safely transfer a neural interface into a cyborg chassis.
- You can attach robotic limbs. Its speed increases with level.",
"Experienced" = "You have years of experience building or reverse-engineering complex devices. Your use of fabricators and destructive analyzers is efficient and methodical. You can design contraptions to order, and likely sell those designs at a profit.",
"Master" = "You are an inventor or researcher. You can design, build, and modify equipment that most people don't even know exists. You are at home in the lab and the workshop and you've never met a gadget you couldn't take apart, put back together, and replicate."
)
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index 38b7caac0fb..ae06234265a 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -64,7 +64,7 @@
sound_to(src, sound(null, repeat = 0, wait = 0, volume = 85, channel = sound_channels.lobby_channel))// stop the jams for AIs
- var/mob/living/silicon/ai/O = new (loc, global.using_map.default_law_type,,1)//No MMI but safety is in effect.
+ var/mob/living/silicon/ai/O = new (loc, global.using_map.default_law_type,,1)//No brain but safety is in effect.
O.set_invisibility(INVISIBILITY_NONE)
O.aiRestorePowerRoutine = 0
if(mind)
@@ -128,10 +128,9 @@
mind.transfer_to(O)
if(O.mind && O.mind.assigned_role == ASSIGNMENT_ROBOT)
O.mind.original = O
- var/mmi_type = SSrobots.get_mmi_type_by_title(O.mind.role_alt_title ? O.mind.role_alt_title : O.mind.assigned_role)
+ var/mmi_type = SSrobots.get_brain_type_by_title(O.mind.role_alt_title ? O.mind.role_alt_title : O.mind.assigned_role)
if(mmi_type)
- O.mmi = new mmi_type(O)
- O.mmi.transfer_identity(src)
+ O.central_processor = new mmi_type(O)
O.dropInto(loc)
O.job = ASSIGNMENT_ROBOT
diff --git a/code/modules/organs/external/_external.dm b/code/modules/organs/external/_external.dm
index b84012f2d46..9f6723cb5c0 100644
--- a/code/modules/organs/external/_external.dm
+++ b/code/modules/organs/external/_external.dm
@@ -456,11 +456,8 @@
//
//If we contain any child organs add them to the owner
//
- for(var/obj/item/organ/organ in internal_organs)
- owner.add_organ(organ, src, in_place, update_icon, detached)
-
- for(var/obj/item/organ/external/organ in children)
- owner.add_organ(organ, src, in_place, update_icon, detached)
+ for(var/obj/item/organ/organ in (implants|children|internal_organs))
+ owner.add_organ(organ, src, in_place, update_icon, FALSE)
//
//Add any existing organs in the owner that have us as parent
@@ -1352,6 +1349,7 @@ Note that amputating the affected organ does in fact remove the infection from t
W.forceMove(owner)
/obj/item/organ/external/do_uninstall(in_place, detach, ignore_children, update_icon)
+
var/mob/living/carbon/human/victim = owner //parent proc clears owner
if(!(. = ..()))
return
@@ -1431,7 +1429,7 @@ Note that amputating the affected organ does in fact remove the infection from t
/obj/item/organ/external/set_detached(is_detached)
if(BP_IS_PROSTHETIC(src))
is_detached = FALSE //External prosthetics are never detached
- return ..(is_detached)
+ . = ..(is_detached)
/obj/item/organ/external/proc/disfigure(var/type = BRUTE)
if(status & ORGAN_DISFIGURED)
diff --git a/code/modules/organs/internal/_internal.dm b/code/modules/organs/internal/_internal.dm
index 009577fb2d4..28b6da02c03 100644
--- a/code/modules/organs/internal/_internal.dm
+++ b/code/modules/organs/internal/_internal.dm
@@ -24,6 +24,9 @@
var/min_bruised_damage = 10 // Damage before considered bruised
var/damage_reduction = 0.5 //modifier for internal organ injury
+ /// Whether or not we should try to transfer a brainmob when removed or replaced in a mob.
+ var/transfer_brainmob_with_organ = FALSE
+
/obj/item/organ/internal/Initialize(mapload, material_key, datum/dna/given_dna, decl/bodytype/new_bodytype)
if(!alive_icon)
alive_icon = initial(icon_state)
@@ -253,3 +256,43 @@
var/obj/item/organ/O = last_owner.get_organ(parent_organ)
if(O)
O.vital_to_owner = null
+
+// Stub to allow brain interfaces to return their wrapped brainmob.
+/obj/item/organ/internal/proc/get_brainmob(var/create_if_missing = FALSE)
+ return
+
+/obj/item/organ/internal/proc/transfer_key_to_brainmob(var/mob/living/M, var/update_brainmob = TRUE)
+ var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE)
+ if(brainmob)
+ transfer_key_from_mob_to_mob(M, brainmob)
+ if(update_brainmob)
+ brainmob.SetName(M.real_name)
+ brainmob.real_name = M.real_name
+ brainmob.dna = M.dna?.Clone()
+ brainmob.languages = M.languages?.Copy()
+ brainmob.default_language = M.default_language
+ to_chat(brainmob, SPAN_NOTICE("You feel slightly disoriented. That's normal when you're just \a [initial(src.name)]."))
+ callHook("debrain", list(brainmob))
+ return TRUE
+ return FALSE
+
+/obj/item/organ/internal/proc/get_synthetic_owner_name()
+ return "Cyborg"
+
+/obj/item/organ/internal/preserve_in_cryopod(var/obj/machinery/cryopod/pod)
+ var/mob/living/brainmob = get_brainmob()
+ return brainmob?.key
+
+// This might need revisiting to stop people successfully implanting brains in groins and transferring minds.
+/obj/item/organ/internal/do_install(mob/living/carbon/human/target, obj/item/organ/external/affected, in_place, update_icon, detached)
+ . = ..()
+ if(transfer_brainmob_with_organ && istype(owner))
+ var/mob/living/brainmob = get_brainmob(create_if_missing = FALSE)
+ if(brainmob?.key)
+ transfer_key_from_mob_to_mob(brainmob, owner)
+
+/obj/item/organ/internal/do_uninstall(in_place, detach, ignore_children, update_icon)
+ var/mob/living/victim = owner // cleared in parent proc
+ . = ..()
+ if(transfer_brainmob_with_organ && istype(victim))
+ transfer_key_to_brainmob(victim, update_brainmob = TRUE)
diff --git a/code/modules/organs/internal/brain.dm b/code/modules/organs/internal/brain.dm
index 903247ae18e..d84032440d0 100644
--- a/code/modules/organs/internal/brain.dm
+++ b/code/modules/organs/internal/brain.dm
@@ -14,43 +14,58 @@
relative_size = 85
damage_reduction = 0
scale_max_damage_to_species_health = FALSE
- var/can_use_mmi = TRUE
- var/mob/living/carbon/brain/brainmob = null
+ transfer_brainmob_with_organ = TRUE
+ var/can_use_brain_interface = TRUE
var/should_announce_brain_damage = TRUE
var/oxygen_reserve = 6
+ VAR_PRIVATE/mob/living/_brainmob = /mob/living/brain
+
+/obj/item/organ/internal/brain/get_brainmob(var/create_if_missing = FALSE)
+ if(!istype(_brainmob) && create_if_missing)
+ initialize_brainmob()
+ if(istype(_brainmob))
+ return _brainmob
+
+/obj/item/organ/internal/brain/Initialize()
+ . = ..()
+ if(species)
+ set_max_damage(species.total_health)
+ else
+ set_max_damage(200)
+
+/obj/item/organ/internal/brain/proc/initialize_brainmob()
+ if(istype(_brainmob))
+ return
+ if(!ispath(_brainmob))
+ _brainmob = initial(_brainmob)
+ if(ispath(_brainmob))
+ _brainmob = new _brainmob(src)
+ else
+ _brainmob = null
/obj/item/organ/internal/brain/getToxLoss()
return 0
/obj/item/organ/internal/brain/set_species(species_name)
. = ..()
+ icon_state = "brain-prosthetic"
if(species)
set_max_damage(species.total_health)
else
set_max_damage(200)
/obj/item/organ/internal/brain/Destroy()
- QDEL_NULL(brainmob)
+ if(istype(_brainmob))
+ QDEL_NULL(_brainmob)
. = ..()
-/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H)
-
- if(!brainmob)
- brainmob = new(src)
- brainmob.SetName(H.real_name)
- brainmob.real_name = H.real_name
- brainmob.dna = H.dna.Clone()
- brainmob.timeofhostdeath = H.timeofdeath
-
- if(H.mind)
- H.mind.transfer_to(brainmob)
-
- to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].")
- callHook("debrain", list(brainmob))
-
-/obj/item/organ/internal/brain/examine(mob/user)
+/obj/item/organ/internal/brain/examine(mob/user, var/distance)
. = ..()
- if(brainmob && brainmob.client)//if thar be a brain inside... the brain.
+ if(distance <= 1)
+ show_brain_status(user)
+
+/obj/item/organ/internal/brain/proc/show_brain_status(mob/user)
+ if(istype(_brainmob) && _brainmob?.client) //if thar be a brain inside... the brain.
to_chat(user, "You can feel the small spark of life still left in this one.")
else
to_chat(user, "This one seems particularly lifeless. Perhaps it will regain some of its luster later..")
@@ -67,21 +82,6 @@
if(!(. = ..()))
return
-/obj/item/organ/internal/brain/on_remove_effects()
- if(istype(owner))
- transfer_identity(owner)
- return ..()
-
-/obj/item/organ/internal/brain/on_add_effects()
- if(brainmob)
- if(brainmob.mind)
- if(owner.key)
- owner.ghostize()
- brainmob.mind.transfer_to(owner)
- else
- owner.key = brainmob.key
- return ..()
-
/obj/item/organ/internal/brain/can_recover()
return !(status & ORGAN_DEAD)
@@ -221,7 +221,7 @@
/obj/item/organ/internal/brain/surgical_fix(mob/user)
var/blood_volume = owner.get_blood_oxygenation()
if(blood_volume < BLOOD_VOLUME_SURVIVE)
- to_chat(user, "Parts of [src] didn't survive the procedure due to lack of air supply!")
+ to_chat(user, SPAN_DANGER("Parts of \the [src] didn't survive the procedure due to lack of air supply!"))
set_max_damage(FLOOR(max_damage - 0.25*damage))
heal_damage(damage)
@@ -229,4 +229,9 @@
. = (species.total_health - max_damage)/species.total_health
/obj/item/organ/internal/brain/get_mechanical_assisted_descriptor()
- return "machine-interface [name]"
\ No newline at end of file
+ return "machine-interface [name]"
+
+/obj/item/organ/internal/brain/die()
+ if(istype(_brainmob) && _brainmob.stat != DEAD)
+ _brainmob.death()
+ ..()
diff --git a/code/modules/organs/internal/brain_computer.dm b/code/modules/organs/internal/brain_computer.dm
new file mode 100644
index 00000000000..3d298b04b30
--- /dev/null
+++ b/code/modules/organs/internal/brain_computer.dm
@@ -0,0 +1,92 @@
+// Robobrain.
+/obj/item/organ/internal/brain/robotic
+ name = "computer intelligence core"
+ desc = "The pinnacle of artifical intelligence technology, conveniently stored in a fist-sized cube."
+ icon = 'icons/obj/items/brain_interface_robotic.dmi'
+ origin_tech = @'{"engineering":4,"materials":4,"wormholes":2,"programming":4}'
+ material = /decl/material/solid/metal/steel
+ matter = list(
+ /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT,
+ /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE,
+ /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE,
+ /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE
+ )
+ can_use_brain_interface = FALSE
+ var/searching = FALSE
+ var/brain_name
+
+/obj/item/organ/internal/brain/robotic/handle_severe_damage()
+ return // TODO: computer maladies
+
+/obj/item/organ/internal/brain/robotic/handle_disabilities()
+ return // TODO: computer maladies
+
+/obj/item/organ/internal/brain/robotic/Initialize()
+ . = ..()
+ set_bodytype(/decl/bodytype/prosthetic/basic_human)
+ update_icon()
+ brain_name = "[pick(list("ADA","DOS","GNU","MAC","WIN"))]-[random_id(type,1000,9999)]"
+ SetName("[name] ([brain_name])")
+
+/obj/item/organ/internal/brain/robotic/initialize_brainmob()
+ ..()
+ if(istype(_brainmob))
+ _brainmob.SetName(brain_name)
+ _brainmob.add_language(/decl/language/machine)
+
+/obj/item/organ/internal/brain/robotic/on_update_icon()
+ var/mob/living/brainmob = get_brainmob()
+ icon_state = get_world_inventory_state()
+ if(!searching)
+ if(!brainmob?.key || brainmob.stat == DEAD)
+ icon_state = "[icon_state]-dead"
+ else
+ icon_state = "[icon_state]-full"
+
+/obj/item/organ/internal/brain/robotic/attack_self(mob/user)
+ var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE)
+ if(!brainmob?.key && !searching)
+ to_chat(user, SPAN_NOTICE("You press the power button and boot up \the [src]."))
+ searching = TRUE
+ update_icon()
+ var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/machine_intelligence)
+ G.request_player(brainmob, "Someone is requesting a personality for a [name].", 1 MINUTE)
+ addtimer(CALLBACK(src, PROC_REF(reset_search)), 1 MINUTE)
+ return TRUE
+ . = ..()
+
+/obj/item/organ/internal/brain/robotic/proc/reset_search()
+ searching = FALSE
+ update_icon()
+ var/mob/living/brainmob = get_brainmob()
+ if(!brainmob?.key)
+ visible_message(SPAN_WARNING("\The [src] emits a series of loud beeps, indicating a failure to boot. Try again in a few minutes."))
+
+/obj/item/organ/internal/brain/robotic/attack_ghost(var/mob/observer/ghost/user)
+ var/mob/living/brainmob = get_brainmob(create_if_missing = TRUE)
+ if(brainmob?.key)
+ to_chat(user, SPAN_WARNING("\The [src] is already inhabited; there's no room for you!"))
+ return TRUE
+
+ var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/machine_intelligence)
+ if(G.assess_candidate(user))
+ var/response = alert(user, "Are you sure you wish to possess \the [src]?", "Possess [capitalize(name)]", "Yes", "No")
+ if(response == "Yes" && brainmob && !brainmob?.key && G.assess_candidate(user))
+ G.transfer_personality(user, brainmob)
+
+/obj/item/organ/internal/brain/robotic/show_brain_status(mob/user)
+ var/mob/living/brainmob = get_brainmob()
+ if(brainmob?.key)
+ switch(brainmob.stat)
+ if(CONSCIOUS)
+ if(!brainmob.client)
+ to_chat(user, SPAN_WARNING("It appears to be in stand-by mode."))
+ if(UNCONSCIOUS)
+ to_chat(user, SPAN_WARNING("It doesn't seem to be responsive."))
+ if(DEAD)
+ to_chat(user, SPAN_WARNING("It appears to be completely inactive."))
+ else
+ to_chat(user, SPAN_WARNING("It appears to be completely inactive."))
+
+/obj/item/organ/internal/brain/robotic/get_synthetic_owner_name()
+ return "Robot"
diff --git a/code/modules/organs/internal/cell.dm b/code/modules/organs/internal/cell.dm
new file mode 100644
index 00000000000..b9d478150f1
--- /dev/null
+++ b/code/modules/organs/internal/cell.dm
@@ -0,0 +1,96 @@
+/obj/item/organ/internal/cell
+ name = "microbattery"
+ desc = "A small, powerful cell for use in fully prosthetic bodies."
+ icon_state = "cell"
+ dead_icon = "cell_bork"
+ organ_tag = BP_CELL
+ parent_organ = BP_CHEST
+ var/open
+ var/obj/item/cell/cell = /obj/item/cell/hyper
+ //at 0.8 completely depleted after 60ish minutes of constant walking or 130 minutes of standing still
+ var/servo_cost = 0.8
+
+/obj/item/organ/internal/cell/Initialize()
+ if(ispath(cell))
+ cell = new cell(src)
+ . = ..()
+
+/obj/item/organ/internal/cell/proc/percent()
+ if(!cell)
+ return 0
+ return get_charge()/cell.maxcharge * 100
+
+/obj/item/organ/internal/cell/proc/get_charge()
+ if(!cell)
+ return 0
+ if(status & ORGAN_DEAD)
+ return 0
+ return round(cell.charge*(1 - damage/max_damage))
+
+/obj/item/organ/internal/cell/proc/checked_use(var/amount)
+ if(!is_usable())
+ return FALSE
+ return cell && cell.checked_use(amount)
+
+/obj/item/organ/internal/cell/proc/use(var/amount)
+ if(!is_usable())
+ return 0
+ return cell && cell.use(amount)
+
+/obj/item/organ/internal/cell/proc/get_power_drain()
+ var/damage_factor = 1 + 10 * damage/max_damage
+ return servo_cost * damage_factor
+
+/obj/item/organ/internal/cell/Process()
+ ..()
+ if(!owner)
+ return
+ if(owner.stat == DEAD) //not a drain anymore
+ return
+ var/cost = get_power_drain()
+ if(world.time - owner.l_move_time < 15)
+ cost *= 2
+ if(!checked_use(cost) && owner.isSynthetic())
+ if(!owner.lying && !owner.buckled)
+ to_chat(owner, SPAN_WARNING("You don't have enough energy to function!"))
+ SET_STATUS_MAX(owner, STAT_PARA, 3)
+
+/obj/item/organ/internal/cell/emp_act(severity)
+ ..()
+ if(cell)
+ cell.emp_act(severity)
+
+/obj/item/organ/internal/cell/attackby(obj/item/W, mob/user)
+ if(IS_SCREWDRIVER(W))
+ if(open)
+ open = 0
+ to_chat(user, SPAN_NOTICE("You screw the battery panel in place."))
+ else
+ open = 1
+ to_chat(user, SPAN_NOTICE("You unscrew the battery panel."))
+
+ if(IS_CROWBAR(W))
+ if(open)
+ if(cell)
+ user.put_in_hands(cell)
+ to_chat(user, SPAN_NOTICE("You remove \the [cell] from \the [src]."))
+ cell = null
+
+ if (istype(W, /obj/item/cell))
+ if(open)
+ if(cell)
+ to_chat(user, SPAN_WARNING("There is a power cell already installed."))
+ else if(user.try_unequip(W, src))
+ cell = W
+ to_chat(user, SPAN_NOTICE("You insert \the [cell]."))
+
+/obj/item/organ/internal/cell/on_add_effects()
+ . = ..()
+ // This is very ghetto way of rebooting an IPC. TODO better way.
+ if(owner && owner.stat == DEAD)
+ owner.set_stat(CONSCIOUS)
+ owner.visible_message(SPAN_NOTICE("\The [owner] twitches visibly!"))
+
+/obj/item/organ/internal/cell/listen()
+ if(get_charge())
+ return "faint hum of the power bank"
diff --git a/code/modules/organs/internal/heart.dm b/code/modules/organs/internal/heart.dm
index e160e318278..be7f416b0d4 100644
--- a/code/modules/organs/internal/heart.dm
+++ b/code/modules/organs/internal/heart.dm
@@ -5,13 +5,13 @@
icon_state = "heart-on"
dead_icon = "heart-off"
prosthetic_icon = "heart-prosthetic"
+ damage_reduction = 0.7
+ relative_size = 5
+ max_damage = 45
var/pulse = PULSE_NORM
var/heartbeat = 0
var/beat_sound = 'sound/effects/singlebeat.ogg'
var/tmp/next_blood_squirt = 0
- damage_reduction = 0.7
- relative_size = 5
- max_damage = 45
var/open
var/list/external_pump
diff --git a/code/modules/organs/internal/posibrain.dm b/code/modules/organs/internal/posibrain.dm
deleted file mode 100644
index ba69416cdd0..00000000000
--- a/code/modules/organs/internal/posibrain.dm
+++ /dev/null
@@ -1,333 +0,0 @@
-/obj/item/organ/internal/posibrain
- name = "positronic brain"
- desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
- icon = 'icons/obj/assemblies.dmi'
- icon_state = "posibrain"
- organ_tag = BP_POSIBRAIN
- parent_organ = BP_CHEST
- force = 1.0
- w_class = ITEM_SIZE_NORMAL
- throwforce = 1
- throw_speed = 3
- throw_range = 5
- origin_tech = @'{"engineering":4,"materials":4,"wormholes":2,"programming":4}'
- attack_verb = list("attacked", "slapped", "whacked")
- material = /decl/material/solid/metal/steel
- matter = list(
- /decl/material/solid/glass = MATTER_AMOUNT_REINFORCEMENT,
- /decl/material/solid/metal/silver = MATTER_AMOUNT_TRACE,
- /decl/material/solid/metal/gold = MATTER_AMOUNT_TRACE,
- /decl/material/solid/gemstone/diamond = MATTER_AMOUNT_TRACE
- )
- relative_size = 60
- req_access = list(access_robotics)
- organ_properties = ORGAN_PROP_PROSTHETIC //triggers robotization on init
- scale_max_damage_to_species_health = FALSE
-
- var/mob/living/carbon/brain/brainmob = null
- var/searching = 0
- var/askDelay = 60 SECONDS
-
-/obj/item/organ/internal/posibrain/Initialize()
- . = ..()
- if(!brainmob && iscarbon(loc))
- init(loc) //Not sure why we're creating a braimob on load, and also why not installing it in the owner...
-
-/obj/item/organ/internal/posibrain/proc/init(var/mob/living/carbon/H)
- if(brainmob)
- return
- brainmob = new(src)
- if(istype(H))
- brainmob.SetName(H.real_name)
- brainmob.real_name = H.real_name
- brainmob.dna = H.dna.Clone()
- brainmob.add_language(/decl/language/human/common)
- brainmob.add_language(/decl/language/binary)
-
-/obj/item/organ/internal/posibrain/Destroy()
- QDEL_NULL(brainmob)
- return ..()
-
-/obj/item/organ/internal/posibrain/attack_self(mob/user)
- if(brainmob && !brainmob.key && searching == 0)
- //Start the process of searching for a new user.
- to_chat(user, "You carefully locate the manual activation switch and start the positronic brain's boot process.")
- icon_state = "posibrain-searching"
- src.searching = 1
- var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/positronic_brain)
- G.request_player(brainmob, "Someone is requesting a personality for a positronic brain.", 60 SECONDS)
- addtimer(CALLBACK(src, PROC_REF(reset_search)), askDelay)
-
-/obj/item/organ/internal/posibrain/proc/reset_search() //We give the players time to decide, then reset the timer.
- if(!brainmob?.key)
- searching = FALSE
- icon_state = "posibrain"
- visible_message(SPAN_WARNING("The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?"))
-
-/obj/item/organ/internal/posibrain/attack_ghost(var/mob/observer/ghost/user)
- if(!searching || (src.brainmob && src.brainmob.key))
- return
-
- var/decl/ghosttrap/G = GET_DECL(/decl/ghosttrap/positronic_brain)
- if(!G.assess_candidate(user))
- return
- var/response = alert(user, "Are you sure you wish to possess this [src]?", "Possess [src]", "Yes", "No")
- if(response == "Yes")
- G.transfer_personality(user, brainmob)
-
-/obj/item/organ/internal/posibrain/examine(mob/user)
- . = ..()
-
- var/msg = "*---------*\nThis is [html_icon(src)] \a [src]!\n[desc]\n"
-
- msg += ""
-
- if(src.brainmob && src.brainmob.key)
- switch(src.brainmob.stat)
- if(CONSCIOUS)
- if(!src.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.\n"
-
- msg += "*---------*"
- to_chat(user, msg)
- return
-
-/obj/item/organ/internal/posibrain/emp_act(severity)
- if(!src.brainmob)
- return
- else
- switch(severity)
- if(1)
- src.brainmob.emp_damage += rand(20,30)
- if(2)
- src.brainmob.emp_damage += rand(10,20)
- if(3)
- src.brainmob.emp_damage += rand(0,10)
- ..()
-
-/obj/item/organ/internal/posibrain/proc/PickName()
- src.brainmob.SetName("[pick(list("PBU","HIU","SINA","ARMA","OSI"))]-[random_id(type,100,999)]")
- src.brainmob.real_name = src.brainmob.name
-
-/obj/item/organ/internal/posibrain/on_update_icon()
- . = ..()
- if(src.brainmob && src.brainmob.key)
- icon_state = "posibrain-occupied"
- else
- icon_state = "posibrain"
-
-/obj/item/organ/internal/posibrain/proc/transfer_identity(var/mob/living/carbon/H)
- if(H && H.mind)
- brainmob.set_stat(CONSCIOUS)
- H.mind.transfer_to(brainmob)
- brainmob.SetName(H.real_name)
- brainmob.real_name = H.real_name
- brainmob.dna = H.dna.Clone()
-
- update_icon()
-
- to_chat(brainmob, "You feel slightly disoriented. That's normal when you're just \a [initial(src.name)].")
- callHook("debrain", list(brainmob))
-
-/obj/item/organ/internal/posibrain/on_add_effects()
- if(brainmob)
- if(brainmob.mind)
- if(owner.key)
- owner.ghostize()
- brainmob.mind.transfer_to(owner)
- else if(brainmob.key) //posibrain init with a dummy brainmob for some reasons, so gotta do this or its gonna disconnect the client on mob transformation
- owner.key = brainmob.key
- return ..()
-
-/obj/item/organ/internal/posibrain/on_remove_effects()
- if(istype(owner))
- transfer_identity(owner)
- return ..()
-
-/obj/item/organ/internal/posibrain/do_install(mob/living/carbon/human/target, obj/item/organ/external/affected, in_place, update_icon, detached)
- if(!(. = ..()))
- return
- if(istype(owner))
- SetName(initial(name)) //Reset the organ's name to stay coherent if we're put back into someone's skull
-
-/obj/item/organ/internal/posibrain/do_uninstall(in_place, detach, ignore_children)
- if(!in_place && istype(owner) && name == initial(name))
- SetName("\the [owner.real_name]'s [initial(name)]")
- return ..()
-
-/obj/item/organ/internal/cell
- name = "microbattery"
- desc = "A small, powerful cell for use in fully prosthetic bodies."
- icon_state = "cell"
- dead_icon = "cell_bork"
- organ_tag = BP_CELL
- parent_organ = BP_CHEST
- organ_properties = ORGAN_PROP_PROSTHETIC //triggers robotization on init
- var/open
- var/obj/item/cell/cell = /obj/item/cell/hyper
- //at 0.8 completely depleted after 60ish minutes of constant walking or 130 minutes of standing still
- var/servo_cost = 0.8
-
-/obj/item/organ/internal/cell/Initialize()
- if(ispath(cell))
- cell = new cell(src)
- . = ..()
-
-/obj/item/organ/internal/cell/proc/percent()
- if(!cell)
- return 0
- return get_charge()/cell.maxcharge * 100
-
-/obj/item/organ/internal/cell/proc/get_charge()
- if(!cell)
- return 0
- if(status & ORGAN_DEAD)
- return 0
- return round(cell.charge*(1 - damage/max_damage))
-
-/obj/item/organ/internal/cell/proc/checked_use(var/amount)
- if(!is_usable())
- return FALSE
- return cell && cell.checked_use(amount)
-
-/obj/item/organ/internal/cell/proc/use(var/amount)
- if(!is_usable())
- return 0
- return cell && cell.use(amount)
-
-/obj/item/organ/internal/cell/proc/get_power_drain()
- var/damage_factor = 1 + 10 * damage/max_damage
- return servo_cost * damage_factor
-
-/obj/item/organ/internal/cell/Process()
- ..()
- if(!owner)
- return
- if(owner.stat == DEAD) //not a drain anymore
- return
- var/cost = get_power_drain()
- if(world.time - owner.l_move_time < 15)
- cost *= 2
- if(!checked_use(cost) && owner.isSynthetic())
- if(!owner.lying && !owner.buckled)
- to_chat(owner, "You don't have enough energy to function!")
- SET_STATUS_MAX(owner, STAT_PARA, 3)
-
-/obj/item/organ/internal/cell/emp_act(severity)
- ..()
- if(cell)
- cell.emp_act(severity)
-
-/obj/item/organ/internal/cell/attackby(obj/item/W, mob/user)
- if(IS_SCREWDRIVER(W))
- if(open)
- open = 0
- to_chat(user, "You screw the battery panel in place.")
- else
- open = 1
- to_chat(user, "You unscrew the battery panel.")
-
- if(IS_CROWBAR(W))
- if(open)
- if(cell)
- user.put_in_hands(cell)
- to_chat(user, "You remove \the [cell] from \the [src].")
- cell = null
-
- if (istype(W, /obj/item/cell))
- if(open)
- if(cell)
- to_chat(user, "There is a power cell already installed.")
- else if(user.try_unequip(W, src))
- cell = W
- to_chat(user, "You insert \the [cell].")
-
-/obj/item/organ/internal/cell/on_add_effects()
- . = ..()
- // This is very ghetto way of rebooting an IPC. TODO better way.
- if(owner && owner.stat == DEAD)
- owner.set_stat(CONSCIOUS)
- owner.visible_message("\The [owner] twitches visibly!")
-
-/obj/item/organ/internal/cell/listen()
- if(get_charge())
- return "faint hum of the power bank"
-
-// Used for an MMI or posibrain being installed into a human.
-/obj/item/organ/internal/mmi_holder
- name = "brain interface"
- icon_state = "mmi-empty"
- organ_tag = BP_BRAIN
- parent_organ = BP_HEAD
- organ_properties = ORGAN_PROP_PROSTHETIC //triggers robotization on init
- scale_max_damage_to_species_health = FALSE
- var/obj/item/mmi/stored_mmi
- var/datum/mind/persistantMind //Mind that the organ will hold on to after being removed, used for transfer_and_delete
- var/ownerckey // used in the event the owner is out of body
-
-/obj/item/organ/internal/mmi_holder/Destroy()
- stored_mmi = null
- persistantMind = null
- return ..()
-
-/obj/item/organ/internal/mmi_holder/do_install(mob/living/carbon/human/target, obj/item/organ/external/affected, in_place)
- if(status & ORGAN_CUT_AWAY || !(. = ..()))
- return
-
- if(!stored_mmi)
- stored_mmi = new(src)
- update_from_mmi()
- persistantMind = owner.mind
- ownerckey = owner.ckey
-
-/obj/item/organ/internal/mmi_holder/proc/update_from_mmi()
-
- if(!stored_mmi.brainmob)
- stored_mmi.brainmob = new(stored_mmi)
- stored_mmi.brainobj = new(stored_mmi)
- stored_mmi.brainmob.container = stored_mmi
- stored_mmi.brainmob.real_name = owner.real_name
- stored_mmi.brainmob.SetName(stored_mmi.brainmob.real_name)
- stored_mmi.SetName("[initial(stored_mmi.name)] ([owner.real_name])")
-
- if(!owner) return
-
- name = stored_mmi.name
- desc = stored_mmi.desc
- icon = stored_mmi.icon
-
- stored_mmi.icon_state = "mmi-full"
- icon_state = stored_mmi.icon_state
-
- if(owner && owner.stat == DEAD)
- owner.set_stat(CONSCIOUS)
- owner.switch_from_dead_to_living_mob_list()
- owner.visible_message("\The [owner] twitches visibly!")
-
-/obj/item/organ/internal/mmi_holder/on_remove_effects(mob/living/last_owner)
- if(last_owner && last_owner.mind)
- persistantMind = last_owner.mind
- if(last_owner.ckey)
- ownerckey = last_owner.ckey
- . = ..()
-
-/obj/item/organ/internal/mmi_holder/proc/transfer_and_delete()
- if(stored_mmi)
- . = stored_mmi
- stored_mmi.forceMove(src.loc)
- if(persistantMind)
- persistantMind.transfer_to(stored_mmi.brainmob)
- else
- var/response = input(find_dead_player(ownerckey, 1), "Your [initial(stored_mmi.name)] has been removed from your body. Do you wish to return to life?", "Robotic Rebirth") as anything in list("Yes", "No")
- if(response == "Yes")
- persistantMind.transfer_to(stored_mmi.brainmob)
- qdel(src)
-
-//Since the mmi_holder is an horrible hacky pos we turn it into a mmi on drop, since it shouldn't exist outside a mob
-/obj/item/organ/internal/mmi_holder/dropInto(atom/destination)
- . = ..()
- if (!QDELETED(src))
- transfer_and_delete()
diff --git a/code/modules/organs/organ.dm b/code/modules/organs/organ.dm
index 98cc4129f70..5a685b7c59d 100644
--- a/code/modules/organs/organ.dm
+++ b/code/modules/organs/organ.dm
@@ -202,7 +202,7 @@
//dead already, no need for more processing
if(status & ORGAN_DEAD)
return
- // Don't process if we're in a freezer, an MMI or a stasis bag.or a freezer or something I dunno
+ // Don't process if we're in a freezer, an interface or a stasis bag.
if(is_preserved())
return
//Process infections
@@ -248,11 +248,18 @@
ailment.was_treated_by_chem_effect()
/obj/item/organ/proc/is_preserved()
- if(istype(loc,/obj/item/organ))
+ if(istype(loc, /obj/item/organ))
var/obj/item/organ/O = loc
return O.is_preserved()
- else
- return (istype(loc,/obj/item/mmi) || istype(loc,/obj/structure/closet/body_bag/cryobag) || istype(loc,/obj/structure/closet/crate/freezer) || istype(loc,/obj/item/storage/box/freezer))
+ var/static/list/preserved_types = list(
+ /obj/item/storage/box/freezer,
+ /obj/structure/closet/crate/freezer,
+ /obj/structure/closet/body_bag/cryobag
+ )
+ for(var/preserved_type in preserved_types)
+ if(istype(loc, preserved_type))
+ return TRUE
+ return FALSE
/obj/item/organ/examine(mob/user)
. = ..(user)
@@ -544,6 +551,8 @@ var/global/list/ailment_reference_cache = list()
/obj/item/organ/proc/do_install(var/mob/living/carbon/human/target, var/obj/item/organ/external/affected, var/in_place = FALSE, var/update_icon = TRUE, var/detached = FALSE)
//Make sure to force the flag accordingly
set_detached(detached)
+ if(QDELETED(src))
+ return
owner = target
vital_to_owner = null
@@ -579,7 +588,8 @@ var/global/list/ailment_reference_cache = list()
else
owner = null
vital_to_owner = null
- return src
+ if(!QDELETED(src))
+ return src
//Events handling for checks and effects that should happen when removing the organ through interactions. Called by the owner mob.
/obj/item/organ/proc/on_remove_effects(var/mob/living/last_owner)
diff --git a/code/modules/organs/prosthetics/prosthetics_manufacturer.dm b/code/modules/organs/prosthetics/prosthetics_manufacturer.dm
index 941a87db6ff..588098e60f6 100644
--- a/code/modules/organs/prosthetics/prosthetics_manufacturer.dm
+++ b/code/modules/organs/prosthetics/prosthetics_manufacturer.dm
@@ -14,7 +14,7 @@
'sound/foley/metal1.ogg'
)
has_organ = list(
- BP_BRAIN = /obj/item/organ/internal/mmi_holder,
+ BP_BRAIN = /obj/item/organ/internal/brain_interface,
BP_EYES = /obj/item/organ/internal/eyes,
BP_CELL = /obj/item/organ/internal/cell
)
diff --git a/code/modules/projectiles/projectile/change.dm b/code/modules/projectiles/projectile/change.dm
index 30f3b48d403..a88e4070f8e 100644
--- a/code/modules/projectiles/projectile/change.dm
+++ b/code/modules/projectiles/projectile/change.dm
@@ -25,8 +25,8 @@
var/mob/living/silicon/robot/R = new(get_turf(M))
R.set_gender(M.get_gender())
R.job = ASSIGNMENT_ROBOT
- R.mmi = new /obj/item/mmi(R)
- R.mmi.transfer_identity(M)
+ R.central_processor = new /obj/item/organ/internal/brain_interface(R)
+ transfer_key_from_mob_to_mob(M, R)
return R
if(get_species_by_key(choice))
@@ -53,12 +53,8 @@
for (var/spell/S in M.mind.learned_spells)
new_mob.add_spell(new S.type)
new_mob.a_intent = "hurt"
- if(M.mind)
- M.mind.transfer_to(new_mob)
- else
- new_mob.key = M.key
+ transfer_key_from_mob_to_mob(M, new_mob)
to_chat(new_mob, "Your form morphs into that of \a [choice].")
-
qdel(M)
else
to_chat(M, "Your form morphs into that of \a [choice].")
diff --git a/code/modules/surgery/limb_reattach.dm b/code/modules/surgery/limb_reattach.dm
index 71a67326c50..d51f538ac2a 100644
--- a/code/modules/surgery/limb_reattach.dm
+++ b/code/modules/surgery/limb_reattach.dm
@@ -128,7 +128,7 @@
name = "Connect limb"
description = "This procedure is used to reconnect a replaced severed limb."
allowed_tools = list(
- TOOL_HEMOSTAT = 100,
+ TOOL_SUTURES = 100,
TOOL_CABLECOIL = 75
)
can_infect = 1
@@ -145,15 +145,15 @@
/decl/surgery_step/limb/connect/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool)
var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone)
- user.visible_message("[user] starts connecting tendons and muscles in [target]'s [E.amputation_point] with [tool].", \
- "You start connecting tendons and muscle in [target]'s [E.amputation_point].")
+ user.visible_message("[user] starts reattaching tendons and muscles in [target]'s [E.amputation_point] with [tool].", \
+ "You start reattaching tendons and muscle in [target]'s [E.amputation_point].")
..()
/decl/surgery_step/limb/connect/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
var/obj/item/organ/external/E = GET_EXTERNAL_ORGAN(target, target_zone)
var/obj/item/organ/external/P = GET_EXTERNAL_ORGAN(target, E.parent_organ)
- user.visible_message("[user] has connected tendons and muscles in [target]'s [E.amputation_point] with [tool].", \
- "You have connected tendons and muscles in [target]'s [E.amputation_point] with [tool].")
+ user.visible_message("[user] has reattached tendons and muscles in [target]'s [E.amputation_point] with [tool].", \
+ "You have reattached tendons and muscles in [target]'s [E.amputation_point] with [tool].")
//This time we call add_organ but we want it to install in a non detached state
target.add_organ(E, P, FALSE, TRUE, FALSE)
diff --git a/code/modules/surgery/organs_internal.dm b/code/modules/surgery/organs_internal.dm
index 5ee4834aa70..d873e0406eb 100644
--- a/code/modules/surgery/organs_internal.dm
+++ b/code/modules/surgery/organs_internal.dm
@@ -190,19 +190,12 @@
/decl/surgery_step/internal/remove_organ/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
user.visible_message("\The [user] has removed \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].", \
"You have removed \the [target]'s [LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)] with \the [tool].")
-
// Extract the organ!
var/obj/item/organ/O = LAZYACCESS(global.surgeries_in_progress["\ref[target]"], target_zone)
var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
if(istype(O) && istype(affected))
//Now call remove again with detach = FALSE so we fully remove it
target.remove_organ(O, TRUE, FALSE)
-
- // Just in case somehow the organ we're extracting from an organic is an MMI
- if(istype(O, /obj/item/organ/internal/mmi_holder))
- var/obj/item/organ/internal/mmi_holder/brain = O
- brain.transfer_and_delete()
- log_warning("Organ removal surgery on '[target]' returned a mmi_holder '[O]' instead of a mmi!!")
..()
/decl/surgery_step/internal/remove_organ/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
@@ -251,9 +244,7 @@
CRASH("Target ([target]) of surgery [type] has no bodytype!")
else
var/decl/pronouns/G = O.get_pronouns()
- if(O.organ_tag == BP_POSIBRAIN && !target.should_have_organ(BP_POSIBRAIN))
- to_chat(user, SPAN_WARNING("There's no place in [target] to fit \the [O.organ_tag]."))
- else if(O.damage > (O.max_damage * 0.75))
+ if(O.damage > (O.max_damage * 0.75))
to_chat(user, SPAN_WARNING("\The [O.name] [G.is] in no state to be transplanted."))
else if(O.w_class > affected.cavity_max_w_class)
to_chat(user, SPAN_WARNING("\The [O.name] [G.is] too big for [affected.cavity_name] cavity!"))
@@ -325,8 +316,8 @@
var/list/attachable_organs
var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- for(var/obj/item/organ/I in affected.implants)
- if(I && (I.status & ORGAN_CUT_AWAY))
+ for(var/obj/item/organ/I in (affected.implants|affected.internal_organs))
+ if(I.status & ORGAN_CUT_AWAY)
var/image/radial_button = image(icon = I.icon, icon_state = I.icon_state)
radial_button.name = "Attach \the [I.name]"
LAZYSET(attachable_organs, I, radial_button)
diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm
index e972107b4b2..e4c55f59a1d 100644
--- a/code/modules/surgery/robotics.dm
+++ b/code/modules/surgery/robotics.dm
@@ -1,4 +1,4 @@
-//Procedures in this file: Robotic surgery steps, organ removal, replacement. MMI insertion, synthetic organ repair.
+//Procedures in this file: Robotic surgery steps, organ removal, replacement, synthetic organ repair.
//////////////////////////////////////////////////////////////////
// ROBOTIC SURGERY //
//////////////////////////////////////////////////////////////////
@@ -494,73 +494,6 @@
"Your hand slips, unseating \the [tool].")
..()
-//////////////////////////////////////////////////////////////////
-// mmi installation surgery step
-//////////////////////////////////////////////////////////////////
-/decl/surgery_step/robotics/install_mmi
- name = "Install MMI"
- description = "This procedure installs an MMI within a prosthetic organ."
- allowed_tools = list(
- /obj/item/mmi = 100
- )
- min_duration = 60
- max_duration = 80
- surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT
-
-/decl/surgery_step/robotics/install_mmi/pre_surgery_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/mmi/M = tool
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- if(affected && istype(M))
- if(!M.brainmob || !M.brainmob.client || !M.brainmob.ckey || M.brainmob.stat >= DEAD)
- to_chat(user, SPAN_WARNING("That brain is not usable."))
- else if(BP_IS_CRYSTAL(affected))
- to_chat(user, SPAN_WARNING("The crystalline interior of \the [affected] is incompatible with \the [M]."))
- else if(!target.isSynthetic())
- to_chat(user, SPAN_WARNING("You cannot install a computer brain into a meat body."))
- else if(!target.should_have_organ(BP_BRAIN))
- var/decl/species/species = target.get_species()
- to_chat(user, SPAN_WARNING("You're pretty sure [species ? "[species.name_plural] don't" : "\the [target] doesn't"] normally have a brain."))
- else if(target.has_brain())
- to_chat(user, SPAN_WARNING("Your subject already has a brain."))
- else
- return TRUE
- return FALSE
-
-/decl/surgery_step/robotics/install_mmi/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = ..()
- if(affected && target_zone == BP_HEAD)
- return affected
-
-/decl/surgery_step/robotics/install_mmi/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- user.visible_message("[user] starts installing \the [tool] into [target]'s [affected.name].", \
- "You start installing \the [tool] into [target]'s [affected.name].")
- ..()
-
-/decl/surgery_step/robotics/install_mmi/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- if(!user.try_unequip(tool) || !ishuman(target))
- return
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- user.visible_message("[user] has installed \the [tool] into [target]'s [affected.name].", \
- "You have installed \the [tool] into [target]'s [affected.name].")
-
- var/obj/item/mmi/M = tool
- var/obj/item/organ/internal/mmi_holder/holder = new(target, 1)
- var/mob/living/carbon/human/H = target
- H.add_organ(holder, affected, TRUE)
- tool.forceMove(holder)
- holder.stored_mmi = tool
- holder.update_from_mmi()
-
- if(M.brainmob && M.brainmob.mind)
- M.brainmob.mind.transfer_to(target)
- ..()
-
-/decl/surgery_step/robotics/install_mmi/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- user.visible_message("[user]'s hand slips.", \
- "Your hand slips.")
- ..()
-
/decl/surgery_step/internal/remove_organ/robotic
name = "Remove robotic component"
description = "This procedure removes a robotic component."
@@ -573,54 +506,3 @@
can_infect = 0
robotic_surgery = TRUE
surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT
-
-/decl/surgery_step/remove_mmi
- name = "Remove MMI"
- description = "This procedure removes an MMI from a prosthetic organ."
- min_duration = 60
- max_duration = 80
- allowed_tools = list(
- TOOL_HEMOSTAT = 100,
- TOOL_WIRECUTTERS = 75,
- )
- can_infect = 0
- surgery_candidate_flags = SURGERY_NO_CRYSTAL | SURGERY_NO_FLESH | SURGERY_NEEDS_ENCASEMENT
-
-/decl/surgery_step/remove_mmi/get_skill_reqs(mob/living/user, mob/living/target, obj/item/tool)
- return SURGERY_SKILLS_ROBOTIC
-
-/decl/surgery_step/remove_mmi/assess_bodypart(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = ..()
- if(affected && (locate(/obj/item/mmi) in affected.implants))
- return affected
-
-/decl/surgery_step/remove_mmi/begin_step(mob/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- user.visible_message( \
- "\The [user] starts poking around inside [target]'s [affected.name] with \the [tool].", \
- "You start poking around inside [target]'s [affected.name] with \the [tool]." )
- target.custom_pain("The pain in your [affected.name] is living hell!",1,affecting = affected)
- ..()
-
-/decl/surgery_step/remove_mmi/end_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- if(affected)
- var/obj/item/mmi/mmi = locate() in affected.implants
- if(affected && mmi)
- user.visible_message( \
- SPAN_NOTICE("\The [user] removes \the [mmi] from \the [target]'s [affected.name] with \the [tool]."), \
- SPAN_NOTICE("You remove \the [mmi] from \the [target]'s [affected.name] with \the [tool]."))
- target.remove_implant(mmi, TRUE, affected)
- else
- user.visible_message( \
- SPAN_NOTICE("\The [user] could not find anything inside [target]'s [affected.name]."), \
- SPAN_NOTICE("You could not find anything inside [target]'s [affected.name]."))
- ..()
-
-/decl/surgery_step/remove_mmi/fail_step(mob/living/user, mob/living/target, target_zone, obj/item/tool)
- var/obj/item/organ/external/affected = GET_EXTERNAL_ORGAN(target, target_zone)
- user.visible_message( \
- SPAN_WARNING("\The [user]'s hand slips, damaging \the [target]'s [affected.name] with \the [tool]!"), \
- SPAN_WARNING("Your hand slips, damaging \the [target]'s [affected.name] with \the [tool]!"))
- affected.take_external_damage(3, 0, used_weapon = tool)
- ..()
diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi
index 93f5bb50f6f..26ee3a4c8d6 100644
Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ
diff --git a/icons/obj/items/brain_interface_organic.dmi b/icons/obj/items/brain_interface_organic.dmi
new file mode 100644
index 00000000000..940f246aecd
Binary files /dev/null and b/icons/obj/items/brain_interface_organic.dmi differ
diff --git a/icons/obj/items/brain_interface_robotic.dmi b/icons/obj/items/brain_interface_robotic.dmi
new file mode 100644
index 00000000000..065f7a2cf2f
Binary files /dev/null and b/icons/obj/items/brain_interface_robotic.dmi differ
diff --git a/maps/exodus/exodus-2.dmm b/maps/exodus/exodus-2.dmm
index 853c59a6e20..a2fe2a02a5c 100644
--- a/maps/exodus/exodus-2.dmm
+++ b/maps/exodus/exodus-2.dmm
@@ -34898,9 +34898,9 @@
"bvA" = (
/obj/effect/floor_decal/corner/paleblue,
/obj/structure/table,
-/obj/item/mmi,
-/obj/item/mmi,
-/obj/item/mmi,
+/obj/item/organ/internal/brain_interface/empty,
+/obj/item/organ/internal/brain_interface/empty,
+/obj/item/organ/internal/brain_interface/empty,
/turf/simulated/floor/tiled/dark,
/area/exodus/research/robotics)
"bvB" = (
@@ -36562,7 +36562,7 @@
/obj/item/flash/synthetic,
/obj/item/flash/synthetic,
/obj/item/flash/synthetic,
-/obj/item/organ/internal/posibrain,
+/obj/item/organ/internal/brain/robotic,
/obj/item/robotanalyzer,
/obj/effect/floor_decal/corner/paleblue{
dir = 10
diff --git a/maps/exodus/jobs/synthetics.dm b/maps/exodus/jobs/synthetics.dm
index 1c102582a2c..1cac23c65ae 100644
--- a/maps/exodus/jobs/synthetics.dm
+++ b/maps/exodus/jobs/synthetics.dm
@@ -76,4 +76,4 @@
/datum/job/robot/New()
..()
alt_titles = SSrobots.robot_alt_titles.Copy()
- alt_titles -= title // So the unit test doesn't flip out if a mob or mmi type is declared for our main title.
+ alt_titles -= title // So the unit test doesn't flip out if a mob or brain type is declared for our main title.
diff --git a/mods/content/shackles/_shackles.dme b/mods/content/shackles/_shackles.dme
index d48f7fc6e17..8685bfedc69 100644
--- a/mods/content/shackles/_shackles.dme
+++ b/mods/content/shackles/_shackles.dme
@@ -3,6 +3,5 @@
// BEGIN_INCLUDE
#include "laws_pref.dm"
#include "mind.dm"
-#include "posibrain.dm"
#include "shackle_lawsets.dm"
#endif
\ No newline at end of file
diff --git a/mods/content/shackles/laws_pref.dm b/mods/content/shackles/laws_pref.dm
index 7fb0a89af22..77c3b8baffa 100644
--- a/mods/content/shackles/laws_pref.dm
+++ b/mods/content/shackles/laws_pref.dm
@@ -28,7 +28,8 @@
W.write("is_shackled", pref.is_shackled)
/datum/category_item/player_setup_item/law_pref/sanitize_character()
- if(!istype(pref.laws)) pref.laws = list()
+ if(!istype(pref.laws))
+ pref.laws = list()
var/decl/bodytype/mob_bodytype = pref.get_bodytype_decl()
if(!mob_bodytype?.can_be_shackled)
@@ -68,6 +69,7 @@
. = jointext(.,null)
/datum/category_item/player_setup_item/law_pref/OnTopic(href, href_list, user)
+
if(href_list["toggle_shackle"])
pref.is_shackled = !pref.is_shackled
return TOPIC_REFRESH
@@ -106,7 +108,3 @@
/decl/bodytype
var/can_be_shackled
-
-/decl/bodytype/Initialize()
- . = ..()
- can_be_shackled = !!(BP_POSIBRAIN in has_organ)
diff --git a/mods/content/shackles/posibrain.dm b/mods/content/shackles/posibrain.dm
deleted file mode 100644
index 741b23fe40e..00000000000
--- a/mods/content/shackles/posibrain.dm
+++ /dev/null
@@ -1,16 +0,0 @@
-/obj/item/organ/internal/proc/handle_shackled(var/given_lawset)
- return
-
-/obj/item/organ/internal/posibrain/handle_shackled(var/given_lawset)
- ..()
- update_icon()
-
-/obj/item/organ/internal/posibrain/examine(mob/user)
- . = ..()
- if(owner?.mind?.shackle)
- . += SPAN_WARNING("It is clamped in a set of metal straps with a complex digital lock.")
-
-/obj/item/organ/internal/posibrain/on_update_icon()
- . = ..()
- if(owner?.mind?.shackle)
- add_overlay("posibrain-shackles")
diff --git a/mods/content/xenobiology/overrides.dm b/mods/content/xenobiology/overrides.dm
index 671c77bbe7b..33659633bd3 100644
--- a/mods/content/xenobiology/overrides.dm
+++ b/mods/content/xenobiology/overrides.dm
@@ -38,3 +38,9 @@
/obj/item/gripper/cultivator/Initialize(ml, material_key)
. = ..()
can_hold |= /obj/item/slime_extract
+
+/mob/living/carbon/human/say_understands(var/mob/other,var/decl/language/speaking = null)
+ . = (!speaking && isslime(other)) || ..()
+
+/mob/living/brain/say_understands(var/mob/other,var/decl/language/speaking = null)
+ . = (!speaking && isslime(other)) || ..()
diff --git a/mods/species/bayliens/unathi/organs/organs_internal.dm b/mods/species/bayliens/unathi/organs/organs_internal.dm
index 739fff2d887..1edd08ffc19 100644
--- a/mods/species/bayliens/unathi/organs/organs_internal.dm
+++ b/mods/species/bayliens/unathi/organs/organs_internal.dm
@@ -4,4 +4,4 @@
icon = 'mods/species/bayliens/unathi/icons/organs.dmi'
/obj/item/organ/internal/brain/lizard
- can_use_mmi = FALSE
+ can_use_brain_interface = FALSE
diff --git a/mods/species/utility_frames/_utility_frames.dme b/mods/species/utility_frames/_utility_frames.dme
index 776d098bb5d..728a6e05d86 100644
--- a/mods/species/utility_frames/_utility_frames.dme
+++ b/mods/species/utility_frames/_utility_frames.dme
@@ -1,5 +1,6 @@
#ifndef MODPACK_UTILITY_FRAMES
#define MODPACK_UTILITY_FRAMES
+#include "../../content/shackles/_shackles.dme"
#include "_utility_frames.dm"
#include "species.dm"
#include "species_bodytypes.dm"
diff --git a/mods/species/utility_frames/species.dm b/mods/species/utility_frames/species.dm
index 9e10f61d368..5e3f44eacf4 100644
--- a/mods/species/utility_frames/species.dm
+++ b/mods/species/utility_frames/species.dm
@@ -15,7 +15,6 @@
description = "Simple AI-driven robots are used for many menial or repetitive tasks in human space."
cyborg_noun = null
base_prosthetics_model = null
-
blood_types = list(/decl/blood_type/coolant)
available_bodytypes = list(/decl/bodytype/prosthetic/utility_frame)
diff --git a/mods/species/utility_frames/species_bodytypes.dm b/mods/species/utility_frames/species_bodytypes.dm
index c78b55cbde8..c5dc14b5025 100644
--- a/mods/species/utility_frames/species_bodytypes.dm
+++ b/mods/species/utility_frames/species_bodytypes.dm
@@ -12,14 +12,14 @@
base_eye_color = "#00ccff"
material = /decl/material/solid/metal/steel
vital_organs = list(
- BP_POSIBRAIN,
+ BP_BRAIN,
BP_CELL
)
override_limb_types = list(BP_HEAD = /obj/item/organ/external/head/utility_frame)
has_organ = list(
- BP_POSIBRAIN = /obj/item/organ/internal/posibrain,
- BP_EYES = /obj/item/organ/internal/eyes,
- BP_CELL = /obj/item/organ/internal/cell
+ BP_BRAIN = /obj/item/organ/internal/brain/robotic,
+ BP_EYES = /obj/item/organ/internal/eyes,
+ BP_CELL = /obj/item/organ/internal/cell
)
base_markings = list(
/decl/sprite_accessory/marking/frame/plating = "#8888cc",
diff --git a/mods/species/vox/organs_vox.dm b/mods/species/vox/organs_vox.dm
index e664b4284a4..f3e11f2135d 100644
--- a/mods/species/vox/organs_vox.dm
+++ b/mods/species/vox/organs_vox.dm
@@ -158,7 +158,7 @@
origin_tech = @'{"biotech":4,"materials":4,"magnets":2,"programming":3}'
relative_size = 10
- var/ownerckey
+ var/stored_ckey
var/default_language
var/list/languages = list()
var/datum/mind/backup
@@ -174,7 +174,7 @@
var/user_vox = isspecies(user, SPECIES_VOX)
if (istype(backup))
- var/owner_viable = find_dead_player(ownerckey, TRUE)
+ var/owner_viable = find_dead_player(stored_ckey, TRUE)
if (user_vox)
to_chat(user, SPAN_NOTICE("The integrity light on [src] blinks [owner_viable ? "rapidly. It can be implanted." : "slowly. It is dormant."]"))
else
@@ -194,7 +194,7 @@
backup = owner.mind
default_language = owner.default_language
if(owner.ckey)
- ownerckey = owner.ckey
+ stored_ckey = owner.ckey
/obj/item/organ/internal/voxstack/proc/backup_inviable()
return (!istype(backup) || backup == owner.mind || (backup.current && backup.current.stat != DEAD))
@@ -212,7 +212,7 @@
set waitfor = FALSE
if(C && !backup_inviable())
prompting = TRUE
- var/response = alert(find_dead_player(ownerckey, 1), "Your neural backup has been placed into a new body. Do you wish to return to life as the mind of [backup.name]?", "Resleeving", "Yes", "No")
+ var/response = alert(find_dead_player(stored_ckey, 1), "Your neural backup has been placed into a new body. Do you wish to return to life as the mind of [backup.name]?", "Resleeving", "Yes", "No")
prompting = FALSE
if(src && response == "Yes" && owner == C)
overwrite()
diff --git a/nebula.dme b/nebula.dme
index 0f29ca1e90b..06839eed2c3 100644
--- a/nebula.dme
+++ b/nebula.dme
@@ -1714,6 +1714,8 @@
#include "code\modules\awaymissions\pamphlet.dm"
#include "code\modules\awaymissions\trigger.dm"
#include "code\modules\blob\blob.dm"
+#include "code\modules\brain_interface\_brain_interface.dm"
+#include "code\modules\brain_interface\interface_radio.dm"
#include "code\modules\butchery\butchery.dm"
#include "code\modules\butchery\remains.dm"
#include "code\modules\chat_filter\_chat_filter.dm"
@@ -2482,6 +2484,9 @@
#include "code\modules\mob\living\bot\mulebot.dm"
#include "code\modules\mob\living\bot\remotebot.dm"
#include "code\modules\mob\living\bot\secbot.dm"
+#include "code\modules\mob\living\brain\brain.dm"
+#include "code\modules\mob\living\brain\death.dm"
+#include "code\modules\mob\living\brain\say.dm"
#include "code\modules\mob\living\carbon\breathe.dm"
#include "code\modules\mob\living\carbon\carbon.dm"
#include "code\modules\mob\living\carbon\carbon_defense.dm"
@@ -2501,13 +2506,6 @@
#include "code\modules\mob\living\carbon\alien\death.dm"
#include "code\modules\mob\living\carbon\alien\life.dm"
#include "code\modules\mob\living\carbon\alien\say.dm"
-#include "code\modules\mob\living\carbon\brain\brain.dm"
-#include "code\modules\mob\living\carbon\brain\death.dm"
-#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\robot.dm"
-#include "code\modules\mob\living\carbon\brain\say.dm"
#include "code\modules\mob\living\carbon\human\death.dm"
#include "code\modules\mob\living\carbon\human\examine.dm"
#include "code\modules\mob\living\carbon\human\human.dm"
@@ -2949,13 +2947,14 @@
#include "code\modules\organs\internal\_internal.dm"
#include "code\modules\organs\internal\appendix.dm"
#include "code\modules\organs\internal\brain.dm"
+#include "code\modules\organs\internal\brain_computer.dm"
+#include "code\modules\organs\internal\cell.dm"
#include "code\modules\organs\internal\eyes.dm"
#include "code\modules\organs\internal\heart.dm"
#include "code\modules\organs\internal\insectoid.dm"
#include "code\modules\organs\internal\kidneys.dm"
#include "code\modules\organs\internal\liver.dm"
#include "code\modules\organs\internal\lungs.dm"
-#include "code\modules\organs\internal\posibrain.dm"
#include "code\modules\organs\internal\stomach.dm"
#include "code\modules\organs\internal\voice.dm"
#include "code\modules\organs\internal\species\golem.dm"