diff --git a/code/__DEFINES/preferences.dm b/code/__DEFINES/preferences.dm
index bc0dd8fc2b4..9c2e1ccb84a 100644
--- a/code/__DEFINES/preferences.dm
+++ b/code/__DEFINES/preferences.dm
@@ -34,7 +34,7 @@
#define BE_MALF 16
#define BE_REV 32
#define BE_ALIEN 64
-#define BE_PAI 128
+#define BE_PAI 128 //Includes Positronic brains, but the flag is already maxed.
#define BE_CULTIST 256
#define BE_BLOB 512
#define BE_NINJA 1024
diff --git a/code/_globalvars/configuration.dm b/code/_globalvars/configuration.dm
index 0db83ac6adb..d42d812db7a 100644
--- a/code/_globalvars/configuration.dm
+++ b/code/_globalvars/configuration.dm
@@ -41,7 +41,7 @@ var/list/be_special_flags = list(
"Malf AI" = BE_MALF,
"Revolutionary" = BE_REV,
"Alien Lifeform" = BE_ALIEN,
- "pAI" = BE_PAI,
+ "pAI/Positronic Brain" = BE_PAI,
"Cultist" = BE_CULTIST,
"Blob" = BE_BLOB,
"Ninja" = BE_NINJA,
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 42d25b93a92..8061b162c74 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -666,9 +666,9 @@ obj/mecha/proc/can_use(mob/user)
if(istype(W, /obj/item/device/mmi))
if(mmi_move_inside(W,user))
- user << "[src]-MMI interface initialized successfuly"
+ user << "[src]-[W] interface initialized successfuly"
else
- user << "[src]-MMI interface initialization failed."
+ user << "[src]-[W] interface initialization failed."
return
if(istype(W, /obj/item/mecha_parts/mecha_equipment))
@@ -1137,6 +1137,7 @@ obj/mecha/proc/can_use(mob/user)
if(mmi.brainmob)
occupant.loc = mmi
mmi.mecha = null
+ mmi.update_icon()
src.occupant.canmove = 0
src.verbs += /obj/mecha/verb/eject
src.occupant = null
@@ -1518,7 +1519,7 @@ var/year_integer = text2num(year) // = 2013???
return
if(href_list["dna_lock"])
if(usr != src.occupant) return
- if(src.occupant)
+ if(src.occupant && occupant.dna)
src.dna = src.occupant.dna.unique_enzymes
src.occupant_message("You feel a prick as the needle takes your DNA sample.")
return
diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm
index 25b475b3d8f..3b9868babac 100644
--- a/code/game/objects/items/robot/robot_parts.dm
+++ b/code/game/objects/items/robot/robot_parts.dm
@@ -222,6 +222,7 @@
chest.cell = null
W.loc = O//Should fix cybros run time erroring when blown up. It got deleted before, along with the frame.
O.mmi = W
+ O.updatename()
feedback_inc("cyborg_birth",1)
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 316a37de246..d6399ed88d6 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -649,11 +649,38 @@
jobs += "
"
counter = 0
- //pAI isn't technically a job, but it goes in here.
+ jobs += "
"
+
+ //Ghost Roles (light light gray)
+ jobs += ""
+ jobs += "| Ghost Roles |
|---|
"
+
+ //pAI
if(jobban_isbanned(M, "pAI"))
- jobs += "| pAI | "
+ jobs += "[replacetext("pAI", " ", " ")] | "
else
- jobs += "pAI | "
+ jobs += "[replacetext("pAI", " ", " ")] | "
+
+
+ //Drones
+ if(jobban_isbanned(M, "drone"))
+ jobs += "[replacetext("Drone", " ", " ")] | "
+ else
+ jobs += "[replacetext("Drone", " ", " ")] | "
+
+
+ //Positronic Brains
+ if(jobban_isbanned(M, "posibrain"))
+ jobs += "[replacetext("Posibrain", " ", " ")] | "
+ else
+ jobs += "[replacetext("Posibrain", " ", " ")] | "
+
+
+ //Deathsquad
+ if(jobban_isbanned(M, "deathsquad"))
+ jobs += "[replacetext("Deathsquad", " ", " ")] | "
+ else
+ jobs += "[replacetext("Deathsquad", " ", " ")] | "
jobs += "
"
@@ -712,12 +739,6 @@
else
jobs += "[replacetext("Abductor", " ", " ")] | "
- //Deathsquad
- if(jobban_isbanned(M, "deathsquad") || isbanned_dept)
- jobs += "[replacetext("Deathsquad", " ", " ")] | "
- else
- jobs += "[replacetext("Deathsquad", " ", " ")] | "
-
/* //Malfunctioning AI //Removed Malf-bans because they're a pain to impliment
if(jobban_isbanned(M, "malf AI") || isbanned_dept)
jobs += "[replacetext("Malf AI", " ", " ")] | "
@@ -807,6 +828,8 @@
var/datum/job/temp = SSjob.GetJob(jobPos)
if(!temp) continue
joblist += temp.title
+ if("ghostroles")
+ joblist += list("pAI", "posibrain", "drone", "deathsquad")
else
joblist += href_list["jobban3"]
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 554851aae22..9d5fa2ec38b 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -11,7 +11,7 @@ var/global/list/special_roles = list( //keep synced with the defines BE_* in set
"malf AI" = /datum/game_mode/malfunction, //4
"revolutionary" = /datum/game_mode/revolution, //5
"alien", //6
- "pAI", //7
+ "pAI/posibrain", //7
"cultist" = /datum/game_mode/cult, //8
"blob" = /datum/game_mode/blob, //9
"ninja", //10
diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm
index e961b11c215..95838e1b90d 100644
--- a/code/modules/mob/living/carbon/brain/MMI.dm
+++ b/code/modules/mob/living/carbon/brain/MMI.dm
@@ -7,6 +7,7 @@
icon_state = "mmi_empty"
w_class = 3
origin_tech = "biotech=3"
+ var/braintype = "Cyborg"
req_access = list(access_robotics)
@@ -18,6 +19,17 @@
var/obj/mecha = null //This does not appear to be used outside of reference in mecha.dm.
var/obj/item/organ/brain/brain = null //The actual brain
+/obj/item/device/mmi/update_icon()
+ if(brain)
+ if(istype(brain,/obj/item/organ/brain/alien))
+ icon_state = "mmi_alien"
+ braintype = "Xenoborg" //HISS....Beep.
+ else
+ icon_state = "mmi_full"
+ braintype = "Cyborg"
+ else
+ icon_state = "mmi_empty"
+
/obj/item/device/mmi/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
user.changeNext_move(CLICK_CD_MELEE)
if(istype(O,/obj/item/organ/brain)) //Time to stick a brain in it --NEO
@@ -51,10 +63,7 @@
brain = newbrain
name = "Man-Machine Interface: [brainmob.real_name]"
- if(istype(newbrain,/obj/item/organ/brain/alien))
- icon_state = "mmi_alien"
- else
- icon_state = "mmi_full"
+ update_icon()
locked = 1
@@ -91,7 +100,7 @@
brain.loc = usr.loc
brain = null //No more brain in here
- icon_state = "mmi_empty"
+ update_icon()
name = "Man-Machine Interface"
/obj/item/device/mmi/proc/transfer_identity(var/mob/living/carbon/human/H) //Same deal as the regular brain proc. Used for human-->robot people.
@@ -108,7 +117,7 @@
brain = newbrain
name = "Man-Machine Interface: [brainmob.real_name]"
- icon_state = "mmi_full"
+ update_icon()
locked = 1
return
diff --git a/code/modules/mob/living/carbon/brain/posibrain.dm b/code/modules/mob/living/carbon/brain/posibrain.dm
new file mode 100644
index 00000000000..9a788562cdb
--- /dev/null
+++ b/code/modules/mob/living/carbon/brain/posibrain.dm
@@ -0,0 +1,146 @@
+/obj/item/device/mmi/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"
+ w_class = 3
+ origin_tech = "biotech=3;programming=2"
+ var/searching = 0
+ var/askDelay = 10 * 60 * 1
+ brainmob = null
+ req_access = list(access_robotics)
+ locked = 0
+ mecha = null//This does not appear to be used outside of reference in mecha.dm.
+ braintype = "Android"
+
+
+/obj/item/device/mmi/posibrain/attack_self(mob/user as mob)
+ if(brainmob && !brainmob.key && searching == 0)
+ //Start the process of searching for a new user.
+ user << "You carefully locate the manual activation switch and start the positronic brain's boot process."
+ searching = 1
+ update_icon()
+ request_player()
+ spawn(600)
+ reset_search()
+
+/obj/item/device/mmi/posibrain/proc/request_player()
+ for(var/mob/dead/observer/O in player_list)
+ if(jobban_isbanned(O, "posibrain"))
+ continue
+ if(O.client)
+ if(O.client.prefs.be_special & BE_PAI)
+ question(O.client)
+
+/obj/item/device/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")
+ 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)
+ else if (response == "Never for this round")
+ C.prefs.be_special ^= BE_PAI
+
+
+/obj/item/device/mmi/posibrain/transfer_identity(var/mob/living/carbon/H)
+ name = "positronic brain ([H])"
+ brainmob.name = H.real_name
+ brainmob.real_name = H.real_name
+ brainmob.dna = H.dna
+ brainmob.timeofhostdeath = H.timeofdeath
+ brainmob.stat = 0
+ if(brainmob.mind)
+ brainmob.mind.assigned_role = "Positronic Brain"
+ if(H.mind)
+ H.mind.transfer_to(brainmob)
+
+ brainmob.mind.remove_all_antag()
+ brainmob.mind.wipe_memory()
+
+ brainmob << "ALL PAST LIVES ARE FORGOTTEN."
+
+ brainmob << "Hello World!"
+ update_icon()
+ return
+
+/obj/item/device/mmi/posibrain/proc/transfer_personality(var/mob/candidate)
+
+ searching = 0
+ brainmob.mind = candidate.mind
+ brainmob.ckey = candidate.ckey
+ name = "positronic brain ([brainmob.name])"
+
+ brainmob.mind.remove_all_antag()
+ brainmob.mind.wipe_memory()
+
+ brainmob << "ALL PAST LIVES ARE FORGOTTEN."
+
+ brainmob << "You are a positronic brain, brought into existence on [station_name()]."
+ brainmob << "As a synthetic intelligence, you answer to all crewmembers, as well as the AI."
+ brainmob << "Remember, the purpose of your existence is to serve the crew and the station. Above all else, do no harm."
+ brainmob.mind.assigned_role = "Positronic Brain"
+
+ visible_message("The positronic brain chimes quietly.")
+ update_icon()
+
+/obj/item/device/mmi/posibrain/proc/reset_search() //We give the players sixty seconds to decide, then reset the timer.
+
+ if(brainmob && brainmob.key) return
+
+ searching = 0
+ update_icon()
+
+ visible_message("The positronic brain buzzes quietly, and the golden lights fade away. Perhaps you could try again?")
+
+/obj/item/device/mmi/posibrain/examine()
+
+ set src in oview()
+
+ if(!usr || !src) return
+ if( (usr.disabilities & BLIND || usr.stat) && !istype(usr,/mob/dead/observer) )
+ usr << "Something is there but you can't see it."
+ return
+
+ var/msg = "*---------*\nThis is \icon[src] \a [src]!\n[desc]\n"
+ msg += ""
+
+ if(brainmob && brainmob.key)
+ switch(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 += "*---------*"
+ usr << msg
+ return
+
+/obj/item/device/mmi/posibrain/New()
+
+ brainmob = new(src)
+ brainmob.name = "[pick(list("PBU","HIU","SINA","ARMA","OSI","HBL","MSO","RR"))]-[rand(100, 999)]"
+ brainmob.real_name = brainmob.name
+ brainmob.loc = src
+ brainmob.container = src
+ brainmob.stat = 0
+ brainmob.silent = 0
+ dead_mob_list -= brainmob
+
+ ..()
+
+
+/obj/item/device/mmi/posibrain/attackby(var/obj/item/O as obj, var/mob/user as mob)
+ return
+
+
+/obj/item/device/mmi/posibrain/update_icon()
+ if(searching)
+ icon_state = "posibrain-searching"
+ return
+ if(brainmob && brainmob.key)
+ icon_state = "posibrain-occupied"
+ else
+ icon_state = "posibrain"
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index 067dc31c6e8..1842c6f157f 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -59,6 +59,7 @@
var/toner = 0
var/tonermax = 40
var/jetpackoverlay = 0
+ var/braintype = "Cyborg"
/mob/living/silicon/robot/New(loc)
spark_system = new /datum/effect/effect/system/spark_spread()
@@ -72,7 +73,6 @@
robot_modules_background.layer = 19 //Objects that appear on screen are on layer 20, UI should be just below it.
ident = rand(1, 999)
- updatename()
update_icons()
if(!cell)
@@ -100,17 +100,20 @@
..()
//MMI stuff. Held togheter by magic. ~Miauw
- mmi = new(src)
- mmi.brain = new /obj/item/organ/brain(mmi)
- mmi.brain.name = "[real_name]'s brain"
- mmi.locked = 1
- mmi.icon_state = "mmi_full"
- mmi.name = "Man-Machine Interface: [real_name]"
- mmi.brainmob = new(src)
- mmi.brainmob.name = src.real_name
- mmi.brainmob.real_name = src.real_name
- mmi.brainmob.container = mmi
- mmi.contents += mmi.brainmob
+ if(!mmi || !mmi.brainmob)
+ mmi = new(src)
+ mmi.brain = new /obj/item/organ/brain(mmi)
+ mmi.brain.name = "[real_name]'s brain"
+ mmi.locked = 1
+ mmi.icon_state = "mmi_full"
+ mmi.name = "Man-Machine Interface: [real_name]"
+ mmi.brainmob = new(src)
+ mmi.brainmob.name = src.real_name
+ mmi.brainmob.real_name = src.real_name
+ mmi.brainmob.container = mmi
+ mmi.contents += mmi.brainmob
+
+ updatename()
playsound(loc, 'sound/voice/liveagain.ogg', 75, 1)
aicamera = new/obj/item/device/camera/siliconcam/robot_camera(src)
@@ -123,6 +126,7 @@
if(T) mmi.loc = T
if(mmi.brainmob)
mind.transfer_to(mmi.brainmob)
+ mmi.update_icon()
else
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()
@@ -236,7 +240,7 @@
if(custom_name)
changed_name = custom_name
else
- changed_name = "[(designation ? "[designation] " : "")]Cyborg-[num2text(ident)]"
+ changed_name = "[(designation ? "[designation] " : "")][mmi.braintype]-[num2text(ident)]"
real_name = changed_name
name = real_name
if(camera)
diff --git a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
index cd4c33c7ee1..930dff33f2e 100644
--- a/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
+++ b/code/modules/mob/living/simple_animal/friendly/drone/drones_as_items.dm
@@ -16,7 +16,7 @@
var/drone_type = /mob/living/simple_animal/drone //Type of drone that will be spawned
/obj/item/drone_shell/attack_ghost(mob/user)
- if(jobban_isbanned(user,"pAI"))
+ if(jobban_isbanned(user,"drone"))
return
var/be_drone = alert("Become a drone? (Warning, You can no longer be cloned!)",,"Yes","No")
diff --git a/code/modules/research/designs/medical_designs.dm b/code/modules/research/designs/medical_designs.dm
index 14f20655f4b..22bf227cd59 100644
--- a/code/modules/research/designs/medical_designs.dm
+++ b/code/modules/research/designs/medical_designs.dm
@@ -48,6 +48,19 @@ datum/design/mmi_radio
build_path = /obj/item/device/mmi/radio_enabled
category = list("Misc","Medical Designs")
+datum/design/posibrain
+ name = "Positronic Brain"
+ desc = "The latest in Artificial Intelligences."
+ id = "mmi_posi"
+ req_tech = list("programming" = 5, "biotech" = 4)
+ build_type = PROTOLATHE | MECHFAB
+ materials = list("$metal" = 1700, "$glass" = 1350, "$gold" = 500) //Gold, because SWAG.
+ reliability = 74
+ construction_time = 75
+ build_path = /obj/item/device/mmi/posibrain
+ category = list("Misc", "Medical Designs")
+
+
datum/design/synthetic_flash
name = "Flash"
desc = "When a problem arises, SCIENCE is the solution."
diff --git a/html/changelogs/Gun-Hog-PR-9147-Blood-Tithe-to-Jordie.yml b/html/changelogs/Gun-Hog-PR-9147-Blood-Tithe-to-Jordie.yml
new file mode 100644
index 00000000000..78035d54353
--- /dev/null
+++ b/html/changelogs/Gun-Hog-PR-9147-Blood-Tithe-to-Jordie.yml
@@ -0,0 +1,37 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# spellcheck (typo fixes)
+# experiment
+# tgs (TG-ported fixes?)
+#################################
+
+# Your name.
+author: Gun Hog
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, this gets changed to [] after reading. Just remove the brackets when you add new shit.
+# Please surround your changes in double quotes ("). It works without them, but if you use certain characters it screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "Top scientists at Nanotrasen have made strong progress in Artificial Intelligence technology, and have completed a design for replicating a human mind: Positronic Brains. Prototypes produced on your research station should be compatible with all Man-Machine Interface compliant machines, be it Mechs, AIs, and even Cyborg bodies. Please note that Cyborgs created from artificial brains are called Androids."
+ - tweak: "The pAI role preference and related jobbans have been renamed to properly reflect that they are not soley for pAI, but include drones and positroinc prains."
diff --git a/icons/obj/assemblies.dmi b/icons/obj/assemblies.dmi
index 8325e86e0f1..b2bbe321a2f 100644
Binary files a/icons/obj/assemblies.dmi and b/icons/obj/assemblies.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 7a35fa2dc48..58aeede23dd 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1125,6 +1125,7 @@
#include "code\modules\mob\living\carbon\brain\emote.dm"
#include "code\modules\mob\living\carbon\brain\life.dm"
#include "code\modules\mob\living\carbon\brain\MMI.dm"
+#include "code\modules\mob\living\carbon\brain\posibrain.dm"
#include "code\modules\mob\living\carbon\brain\say.dm"
#include "code\modules\mob\living\carbon\human\blood.dm"
#include "code\modules\mob\living\carbon\human\death.dm"