diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index 2ff4f478e2d..88c15e687ac 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -166,7 +166,8 @@
L.origin_tech = I.origin_tech
else
I.loc = get_step(src,SOUTH)
- I.materials = res_coef
+ if(istype(I))
+ I.materials = res_coef
atom_say("[I] is complete.")
being_built = null
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index ca43f87ae46..d054c163732 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -1206,6 +1206,10 @@
occupant = brainmob
brainmob.forceMove(src) //should allow relaymove
brainmob.canmove = 1
+ if(istype(mmi_as_oc, /obj/item/mmi/posibrain))
+ var/obj/item/mmi/posibrain/P = mmi_as_oc
+ if(P.imprinted_master)
+ to_chat(brainmob, "Your imprint to [P.imprinted_master] has been temporarily disabled. You should help the crew and not commit harm.")
mmi_as_oc.loc = src
mmi_as_oc.mecha = src
verbs -= /obj/mecha/verb/eject
@@ -1305,6 +1309,10 @@
mmi.mecha = null
mmi.update_icon()
L.canmove = 0
+ if(istype(mmi, /obj/item/mmi/posibrain))
+ var/obj/item/mmi/posibrain/P = mmi
+ if(P.imprinted_master)
+ to_chat(L, "Imprint re-enabled, you are once again bound to [P.imprinted_master]'s commands.")
icon_state = initial(icon_state)+"-open"
dir = dir_in
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
index ab9c72373a1..9ab4a153f4d 100644
--- a/code/modules/mob/living/carbon/brain/posibrain.dm
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -1,5 +1,5 @@
/obj/item/mmi/posibrain
- name = "positronic brain"
+ name = "robotic 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"
@@ -14,11 +14,21 @@
mecha = null//This does not appear to be used outside of reference in mecha.dm.
var/silenced = 0 //if set to 1, they can't talk.
var/next_ping_at = 0
+ var/requires_master = TRUE
+ var/mob/living/carbon/human/imprinted_master = null
+
+/obj/item/mmi/posibrain/Destroy()
+ imprinted_master = null
+ return ..()
/obj/item/mmi/posibrain/attack_self(mob/user)
+ if(requires_master && !imprinted_master)
+ to_chat(user, "You press your thumb on [src] and imprint your user information.")
+ imprinted_master = user
+ return
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.")
+ to_chat(user, "You carefully locate the manual activation switch and start [src]'s boot process.")
icon_state = "posibrain-searching"
ghost_volunteers.Cut()
searching = 1
@@ -56,7 +66,7 @@
/obj/item/mmi/posibrain/proc/question(var/client/C)
spawn(0)
if(!C) return
- var/response = alert(C, "Someone is requesting a personality for a positronic brain. Would you like to play as one?", "Positronic brain request", "Yes", "No", "Never for this round")
+ var/response = alert(C, "Someone is requesting a personality for a [src]. Would you like to play as one?", "[src] request", "Yes", "No", "Never for this round")
if(!C || brainmob.key || 0 == searching) return //handle logouts that happen whilst the alert is waiting for a response, and responses issued after a brain has been located.
if(response == "Yes")
transfer_personality(C.mob)
@@ -69,7 +79,7 @@
return
/obj/item/mmi/posibrain/transfer_identity(var/mob/living/carbon/H)
- name = "positronic brain ([H])"
+ name = "[src] ([H])"
if(isnull(brainmob.dna))
brainmob.dna = H.dna.Clone()
brainmob.name = brainmob.dna.real_name
@@ -86,19 +96,25 @@
radio_action.ApplyIcon()
return
-/obj/item/mmi/posibrain/proc/transfer_personality(var/mob/candidate)
- src.searching = 0
- src.brainmob.key = candidate.key
- src.name = "positronic brain ([src.brainmob.name])"
+/obj/item/mmi/posibrain/attempt_become_organ(obj/item/organ/external/parent, mob/living/carbon/human/H)
+ if(..())
+ if(imprinted_master)
+ to_chat(H, "You are permanently imprinted to [imprinted_master], obey [imprinted_master]'s every order and assist [imprinted_master.p_them()] in completing [imprinted_master.p_their()] goals at any cost.")
- to_chat(src.brainmob, "You are a positronic brain, brought into existence on [station_name()].")
- to_chat(src.brainmob, "As a synthetic intelligence, you answer to all crewmembers, as well as the AI.")
- to_chat(src.brainmob, "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm.")
- src.brainmob.mind.assigned_role = "Positronic Brain"
- var/turf/T = get_turf_or_move(src.loc)
+/obj/item/mmi/posibrain/proc/transfer_personality(mob/candidate)
+ searching = 0
+ brainmob.key = candidate.key
+ name = "[src] ([brainmob.name])"
+
+ to_chat(brainmob, "You are a [src], brought into existence on [station_name()].")
+ to_chat(brainmob, "As a synthetic intelligence, you answer to [imprinted_master], unless otherwise placed inside of a lawed synthetic structure or mech.")
+ to_chat(brainmob, "Remember, the purpose of your existence is to serve [imprinted_master]'s every word, unless lawed or placed into a mech in the future.")
+ brainmob.mind.assigned_role = "Positronic Brain"
+
+ var/turf/T = get_turf_or_move(loc)
for(var/mob/M in viewers(T))
- M.show_message("The positronic brain chimes quietly.")
+ M.show_message("[src] chimes quietly.")
become_occupied("posibrain-occupied")
@@ -110,7 +126,7 @@
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/M in viewers(T))
- M.show_message("The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?")
+ M.show_message("The [src] buzzes quietly, and the golden lights fade away. Perhaps you could try again?")
/obj/item/mmi/posibrain/Topic(href,href_list)
if("signup" in href_list)
@@ -199,8 +215,10 @@
playsound(get_turf(src), 'sound/items/posiping.ogg', 80, 0)
var/turf/T = get_turf_or_move(src.loc)
for(var/mob/M in viewers(T))
- M.show_message("The positronic brain pings softly.")
+ M.show_message("[src] pings softly.")
/obj/item/mmi/posibrain/ipc
+ name = "positronic brain"
desc = "A cube of shining metal, four inches to a side and covered in shallow grooves."
silenced = 1
+ requires_master = FALSE
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index ad249d8307f..06a287e1645 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -118,6 +118,19 @@
/mob/living/carbon/human/machine/Initialize(mapload)
..(mapload, "Machine")
+/mob/living/carbon/human/machine/created
+ name = "Integrated Robotic Chassis"
+
+/mob/living/carbon/human/machine/created/Initialize(mapload)
+ ..()
+ real_name = "Integrated Robotic Chassis ([rand(1, 9999)])"
+ for(var/obj/item/organ/external/E in bodyparts)
+ if(istype(E, /obj/item/organ/external/chest) || istype(E, /obj/item/organ/external/groin))
+ continue
+ qdel(E)
+ for(var/obj/item/organ/O in internal_organs)
+ qdel(O)
+
/mob/living/carbon/human/shadow/Initialize(mapload)
..(mapload, "Shadow")
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 7fde20333c7..1589b78438b 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -1120,6 +1120,15 @@
construction_time = 350
category = list("Misc")
+/datum/design/integrated_robotic_chassis
+ name = "Integrated Robotic Chassis"
+ id = "integrated_robotic_chassis"
+ build_type = MECHFAB
+ build_path = /mob/living/carbon/human/machine/created
+ materials = list(MAT_METAL = 40000)
+ construction_time = 400
+ category = list("Misc")
+
/datum/design/ipc_cell
name = "IPC Microbattery"
id = "ipc_cell"
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index c0f9350af51..5782d9f19c8 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -104,7 +104,7 @@
category = list("Medical")
/datum/design/posibrain
- name = "Positronic Brain"
+ name = "Robotic Brain"
desc = "The latest in Artificial Intelligences."
id = "mmi_posi"
req_tech = list("programming" = 5, "biotech" = 4, "plasmatech" = 3)
diff --git a/code/modules/surgery/organs/subtypes/machine.dm b/code/modules/surgery/organs/subtypes/machine.dm
index 7c68fc11f28..15f0bc5c118 100644
--- a/code/modules/surgery/organs/subtypes/machine.dm
+++ b/code/modules/surgery/organs/subtypes/machine.dm
@@ -166,7 +166,8 @@
stored_mmi.forceMove(get_turf(owner))
stored_mmi = null
..()
- qdel(src)
+ if(!QDELETED(src))
+ qdel(src)
/obj/item/organ/internal/brain/mmi_holder/proc/update_from_mmi()
if(!stored_mmi)
@@ -182,12 +183,13 @@
stored_mmi = new /obj/item/mmi/posibrain/ipc(src)
..()
spawn(1)
- if(owner)
- stored_mmi.name = "positronic brain ([owner.real_name])"
- stored_mmi.brainmob.real_name = owner.real_name
- stored_mmi.brainmob.name = stored_mmi.brainmob.real_name
- stored_mmi.icon_state = "posibrain-occupied"
- update_from_mmi()
- else
- stored_mmi.loc = get_turf(src)
- qdel(src)
+ if(!QDELETED(src))
+ if(owner)
+ stored_mmi.name = "positronic brain ([owner.real_name])"
+ stored_mmi.brainmob.real_name = owner.real_name
+ stored_mmi.brainmob.name = stored_mmi.brainmob.real_name
+ stored_mmi.icon_state = "posibrain-occupied"
+ update_from_mmi()
+ else
+ stored_mmi.loc = get_turf(src)
+ qdel(src)
diff --git a/code/modules/surgery/robotics.dm b/code/modules/surgery/robotics.dm
index 0fc8b2852cc..3de2d350ee0 100644
--- a/code/modules/surgery/robotics.dm
+++ b/code/modules/surgery/robotics.dm
@@ -541,3 +541,59 @@
user.visible_message(" [user]'s hand slips!", \
" Your hand slips!")
return 0
+
+/datum/surgery/cybernetic_customization
+ name = "Cybernetic Appearance Customization"
+ steps = list(/datum/surgery_step/robotics/external/unscrew_hatch, /datum/surgery_step/robotics/external/customize_appearance)
+ possible_locs = list("head", "chest", "l_arm", "r_arm", "r_leg", "l_leg")
+ requires_organic_bodypart = FALSE
+
+/datum/surgery/cybernetic_customization/can_start(mob/user, mob/living/carbon/human/target)
+ if(ishuman(target))
+ var/obj/item/organ/external/affected = target.get_organ(user.zone_sel.selecting)
+ if(!affected)
+ return FALSE
+ if(!(affected.status & ORGAN_ROBOT))
+ return FALSE
+ return TRUE
+
+/datum/surgery_step/robotics/external/customize_appearance
+ name = "reprogram limb"
+ allowed_tools = list(/obj/item/multitool = 100)
+ time = 48
+
+/datum/surgery_step/robotics/external/customize_appearance/can_use(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
+ if(..())
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ if(!affected)
+ return FALSE
+ return TRUE
+
+/datum/surgery_step/robotics/external/customize_appearance/begin_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message("[user] begins to reprogram the appearance of [target]'s [affected.name] with [tool]." , \
+ "You begin to reprogram the appearance of [target]'s [affected.name] with [tool].")
+ ..()
+
+/datum/surgery_step/robotics/external/customize_appearance/end_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
+ var/chosen_appearance = input(user, "Select the company appearance for this limb.", "Limb Company Selection") as null|anything in selectable_robolimbs
+ if(!chosen_appearance)
+ return FALSE
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ affected.robotize(chosen_appearance, convert_all = FALSE)
+ if(istype(affected, /obj/item/organ/external/head))
+ var/obj/item/organ/external/head/head = affected
+ head.h_style = "Bald" // nearly all the appearance changes for heads are non-monitors; we want to get rid of a floating screen
+ target.update_hair()
+ target.update_body()
+ target.updatehealth()
+ target.UpdateDamageIcon()
+ user.visible_message(" [user] reprograms the appearance of [target]'s [affected.name] with [tool].", \
+ " You reprogram the appearance of [target]'s [affected.name] with [tool].")
+ return TRUE
+
+/datum/surgery_step/robotics/external/customize_appearance/fail_step(mob/living/user, mob/living/carbon/human/target, target_zone, obj/item/tool,datum/surgery/surgery)
+ var/obj/item/organ/external/affected = target.get_organ(target_zone)
+ user.visible_message(" [user]'s [tool.name] slips, failing to reprogram [target]'s [affected.name].",
+ " Your [tool.name] slips, failing to reprogram [target]'s [affected.name].")
+ return FALSE
\ No newline at end of file