diff --git a/baystation12.dme b/baystation12.dme
index 9348f106ce0..b82ce97a578 100644
--- a/baystation12.dme
+++ b/baystation12.dme
@@ -1005,6 +1005,7 @@
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\say.dm"
#include "code\modules\mob\living\silicon\robot\wires.dm"
+#include "code\modules\mob\living\simple_animal\borer.dm"
#include "code\modules\mob\living\simple_animal\constructs.dm"
#include "code\modules\mob\living\simple_animal\corpse.dm"
#include "code\modules\mob\living\simple_animal\parrot.dm"
diff --git a/code/game/gamemodes/heist/heist.dm b/code/game/gamemodes/heist/heist.dm
index 935e0974c75..5a1e12a191b 100644
--- a/code/game/gamemodes/heist/heist.dm
+++ b/code/game/gamemodes/heist/heist.dm
@@ -7,6 +7,9 @@ VOX HEIST ROUNDTYPE
var/global/vox_kills = 0 //Used to check the Inviolate.
+/datum/game_mode/
+ var/list/datum/mind/raiders = list() //Antags.
+
/datum/game_mode/heist
name = "heist"
config_tag = "heist"
@@ -19,7 +22,6 @@ var/global/vox_kills = 0 //Used to check the Inviolate.
var/const/waittime_h = 1800 //upper bound on time before intercept arrives (in tenths of seconds)
var/list/raid_objectives = list() //Raid objectives.
- var/list/datum/mind/raiders = list() //Antags.
var/list/obj/cortical_stacks = list() //Stacks for 'leave nobody behind' objective.
/datum/game_mode/heist/announce()
@@ -102,6 +104,9 @@ var/global/vox_kills = 0 //Used to check the Inviolate.
vox.set_species("Vox")
vox.add_language("Vox-pidgin")
vox.h_style = "Short Vox Quills"
+ vox.flavor_text = ""
+ for(var/datum/organ/external/limb in vox.organs)
+ limb.status &= ~(ORGAN_DESTROYED | ORGAN_ROBOT)
vox.equip_vox_raider()
vox.regenerate_icons()
diff --git a/code/game/machinery/podmen.dm b/code/game/machinery/podmen.dm
index 2fe409dcfb5..1e8eb4e5368 100644
--- a/code/game/machinery/podmen.dm
+++ b/code/game/machinery/podmen.dm
@@ -12,7 +12,7 @@ Growing it to term with nothing injected will grab a ghost from the observers. *
productname = "/mob/living/carbon/human" //verrry special -- Urist
lifespan = 50 //no idea what those do
endurance = 8
- maturation = 10
+ maturation = 5
production = 10
yield = 1 //seeds if there isn't a dna inside
oneharvest = 1
diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm
index e932ab856eb..44f1cfdd820 100644
--- a/code/modules/admin/player_panel.dm
+++ b/code/modules/admin/player_panel.dm
@@ -469,6 +469,13 @@
dat += "
| Wizard not found! |
"
dat += ""
+ if(ticker.mode.raiders.len > 0)
+ for(var/datum/mind/raider in ticker.mode.raiders)
+ var/mob/M = raider.current
+ if(M)
+ dat += "| [M.real_name][M.client ? "" : " (logged out)"][M.stat == 2 ? " (DEAD)" : ""] | "
+ dat += "PM | "
+ dat += "Show Objective |
"
/*
if(ticker.mode.ninjas.len > 0)
dat += "
| Ninjas | | |
"
diff --git a/code/modules/admin/verbs/vox_raiders.dm b/code/modules/admin/verbs/vox_raiders.dm
index 65a0f65ad2c..4b6e2271599 100644
--- a/code/modules/admin/verbs/vox_raiders.dm
+++ b/code/modules/admin/verbs/vox_raiders.dm
@@ -32,7 +32,7 @@ var/global/vox_tick = 1
equip_to_slot_or_del(new /obj/item/clothing/head/helmet/space/vox/pressure(src), slot_head)
equip_to_slot_or_del(new /obj/item/weapon/storage/belt/utility/full(src), slot_belt)
equip_to_slot_or_del(new /obj/item/clothing/glasses/meson(src), slot_glasses) // REPLACE WITH CODED VOX ALTERNATIVE.
- equip_to_slot_or_del(new /obj/item/weapon/storage/box/emps(src), slot_l_store)
+ equip_to_slot_or_del(new /obj/item/weapon/storage/box/emps(src), slot_r_hand)
equip_to_slot_or_del(new /obj/item/device/multitool(src), slot_l_hand)
diff --git a/code/modules/clothing/spacesuits/alien.dm b/code/modules/clothing/spacesuits/alien.dm
index 0115eef3113..250935d61ad 100644
--- a/code/modules/clothing/spacesuits/alien.dm
+++ b/code/modules/clothing/spacesuits/alien.dm
@@ -92,6 +92,9 @@
return ..()
+/obj/item/clothing/under/vox
+ has_sensor = 0
+
/obj/item/clothing/under/vox/vox_casual
name = "alien clothing"
desc = "This doesn't look very comfortable."
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index e20829aab85..095695e23d8 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -54,6 +54,25 @@
dizziness = 0
jitteriness = 0
+ //Handle brain slugs.
+ var/datum/organ/external/head = get_organ("head")
+ var/mob/living/simple_animal/borer/B
+
+ for(var/I in head.implants)
+ if(istype(I,/mob/living/simple_animal/borer))
+ B = I
+ if(B)
+ if(!B.ckey && ckey && B.controlling)
+ B.ckey = ckey
+ B.controlling = 0
+ if(B.host_brain.ckey)
+ ckey = B.host_brain.ckey
+ B.host_brain.ckey = null
+ B.host_brain.name = "host brain"
+ B.host_brain.real_name = "host brain"
+
+ verbs -= /mob/living/carbon/human/proc/release_control
+
//Check for heist mode kill count.
if(ticker.mode && ( istype( ticker.mode,/datum/game_mode/heist) ) )
//Check for last assailant's mutantrace.
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index df8dec56156..f70d3956b03 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1274,3 +1274,83 @@ mob/living/carbon/human/yank_out_object()
return 1
else
return 0
+
+//Brain slug proc for voluntary removal of control.
+/mob/living/carbon/human/proc/release_control()
+
+ set category = "Alien"
+ set name = "Release Control"
+ set desc = "Release control of your host's body."
+
+ var/datum/organ/external/head = get_organ("head")
+ var/mob/living/simple_animal/borer/B
+
+ for(var/I in head.implants)
+ if(istype(I,/mob/living/simple_animal/borer))
+ B = I
+ if(!B)
+ return
+
+ if(B.controlling)
+ src << "\red You withdraw your probosci, releasing control of [B.host_brain]"
+ B.host_brain << "\red Your vision swims as the alien parasite releases control of your body."
+ B.ckey = ckey
+ B.controlling = 0
+ if(B.host_brain.ckey)
+ ckey = B.host_brain.ckey
+ B.host_brain.ckey = null
+ B.host_brain.name = "host brain"
+ B.host_brain.real_name = "host brain"
+
+ verbs -= /mob/living/carbon/human/proc/release_control
+ verbs -= /mob/living/carbon/human/proc/punish_host
+ verbs -= /mob/living/carbon/human/proc/spawn_larvae
+
+//Brain slug proc for tormenting the host.
+/mob/living/carbon/human/proc/punish_host()
+ set category = "Alien"
+ set name = "Torment host"
+ set desc = "Punish your host with agony."
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+
+ if(!B)
+ return
+
+ if(B.host_brain.ckey)
+ src << "\red You send a punishing spike of psychic agony lancing into your host's brain."
+ B.host_brain << "\red Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!"
+
+//Check for brain worms in head.
+/mob/living/carbon/human/proc/has_brain_worms()
+
+ var/datum/organ/external/head = get_organ("head")
+
+ for(var/I in head.implants)
+ if(istype(I,/mob/living/simple_animal/borer))
+ return I
+
+ return 0
+
+/mob/living/carbon/human/proc/spawn_larvae()
+ set category = "Alien"
+ set name = "Reproduce"
+ set desc = "Spawn several young."
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+
+ if(!B)
+ return
+
+ if(B.chemicals >= 100)
+ src << "\red Your host twitches and quivers as you rapdly excrete several larvae from your sluglike body."
+ visible_message("\red [src] heaves violently, expelling a rush of vomit and a wriggling, sluglike creature!")
+ B.chemicals -= 100
+
+ new /obj/effect/decal/cleanable/vomit(get_turf(src))
+ playsound(loc, 'sound/effects/splat.ogg', 50, 1)
+ new /mob/living/simple_animal/borer(get_turf(src))
+
+ else
+ src << "You do not have enough chemicals stored to reproduce."
+ return
\ No newline at end of file
diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm
index b7ac6233556..a73e7230bf1 100644
--- a/code/modules/mob/living/say.dm
+++ b/code/modules/mob/living/say.dm
@@ -384,6 +384,12 @@ var/list/department_radio_keys = list(
if(understood || P.universal_speak)
//world << "[M] understood [src] (1)."
heard_a += M
+ else if(istype(P,/mob/living/carbon/human))
+ var/mob/living/carbon/human/H = P
+ if(H.has_brain_worms()) // Brain worms act like Babelfish.
+ heard_a += M
+ else
+ heard_b += M
else
//world << "[M] didn't understand [src]."
heard_b += M
diff --git a/code/modules/mob/living/simple_animal/borer.dm b/code/modules/mob/living/simple_animal/borer.dm
new file mode 100644
index 00000000000..46ff70493c9
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer.dm
@@ -0,0 +1,268 @@
+/mob/living/captive_brain
+ name = "host brain"
+ real_name = "host brain"
+
+/mob/living/captive_brain/say(var/message)
+
+ if (src.client)
+ if(client.prefs.muted & MUTE_IC)
+ src << "\red You cannot speak in IC (muted)."
+ return
+ if (src.client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ if(istype(src.loc,/mob/living/simple_animal/borer))
+ var/mob/living/simple_animal/borer/B = src.loc
+ src << "You whisper silently, \"[message]\""
+ B.host << "The captive mind of [src] whispers, \"[message]\""
+
+/mob/living/captive_brain/emote(var/message)
+ return
+
+/mob/living/simple_animal/borer
+ name = "cortical borer"
+ real_name = "cortical borer"
+ desc = "A small, quivering sluglike creature."
+ speak_emote = list("chirrups")
+ emote_hear = list("chirrups")
+ response_help = "pokes the"
+ response_disarm = "prods the"
+ response_harm = "stomps on the"
+ icon_state = "brainslug"
+ icon_living = "brainslug"
+ icon_dead = "brainslug_dead"
+ speed = 5
+ a_intent = "harm"
+ stop_automated_movement = 1
+ status_flags = CANPUSH
+ attacktext = "nips"
+ friendly = "prods"
+ wander = 0
+
+ var/chemicals = 10 // Chemicals used for reproduction and spitting neurotoxin.
+ var/mob/living/carbon/human/host // Human host for the brain worm.
+ var/truename // Name used for brainworm-speak.
+ var/bonded // Var for full bonding with the host brain.
+ var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth.
+ var/controlling // Used in human death check.
+
+/mob/living/simple_animal/borer/Life()
+
+ ..()
+ if(host)
+ if(!stat && !host.stat)
+ if(chemicals < 250)
+ chemicals++
+ if(controlling)
+ if(prob(5))
+ host.adjustBrainLoss(rand(1,2))
+
+ if(prob(host.brainloss/20))
+ host.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]")
+
+ //if(host.brainloss > 100)
+
+/mob/living/simple_animal/borer/New()
+ ..()
+ truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [rand(1000,9999)]"
+ host_brain = new/mob/living/captive_brain(src)
+
+ for(var/mob/M in player_list)
+ if(istype(M,/mob/dead/observer))
+ var/mob/dead/observer/O = M
+ if(O.client)
+ if(O.client.prefs.be_special & BE_ALIEN)
+ src.ckey = O.ckey
+ break
+
+
+/mob/living/simple_animal/borer/say(var/message)
+
+ message = trim(copytext(sanitize(message), 1, MAX_MESSAGE_LEN))
+ message = capitalize(message)
+
+ if(!message)
+ return
+
+ if (stat == 2)
+ return say_dead(message)
+
+ if (stat)
+ return
+
+ if (src.client)
+ if(client.prefs.muted & MUTE_IC)
+ src << "\red You cannot speak in IC (muted)."
+ return
+ if (src.client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ if (copytext(message, 1, 2) == "*")
+ return emote(copytext(message, 2))
+
+ if (copytext(message, 1, 2) == ";") //Brain borer hivemind.
+ return borer_speak(message)
+
+ if(!host)
+ src << "You have no host to speak to."
+ return //No host, no audible speech.
+
+ src << "You drop words into [host]'s mind: \"[message]\""
+ host << "Your own thoughts speak: \"[message]\""
+
+/mob/living/simple_animal/borer/proc/borer_speak(var/message)
+ if(!message)
+ return
+
+ for(var/mob/M in mob_list)
+ if(M.mind && (istype(M, /mob/living/simple_animal/borer) || istype(M, /mob/dead/observer)))
+ M << "Cortical link, [truename]: [copytext(message, 2)]"
+
+/mob/living/simple_animal/borer/verb/bond_brain()
+ set category = "Alien"
+ set name = "Assume Control"
+ set desc = "Fully connect to the brain of your host."
+
+ if(!host)
+ src << "You are not inside a host body."
+ return
+
+ if(src.stat)
+ src << "You cannot do that in your current state."
+ return
+
+ src << "You begin delicately adjusting your connection to the host brain..."
+
+ spawn(300+(host.brainloss*5))
+
+ if(!host || !src) return
+
+ else
+ src << "\red You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system."
+ host << "\red You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours."
+
+ host_brain.ckey = host.ckey
+ host.ckey = src.ckey
+ controlling = 1
+
+ host.verbs += /mob/living/carbon/human/proc/release_control
+ host.verbs += /mob/living/carbon/human/proc/punish_host
+ host.verbs += /mob/living/carbon/human/proc/spawn_larvae
+
+mob/living/simple_animal/borer/verb/release_host()
+ set category = "Alien"
+ set name = "Release Host"
+ set desc = "Slither out of your host."
+
+ if(!host)
+ src << "You are not inside a host body."
+ return
+
+ if(stat)
+ src << "You cannot leave your host in your current state."
+
+
+ if(!host || !src) return
+
+ src << "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal."
+ bonded = 0
+
+ if(!host.stat)
+ host << "An odd, uncomfortable pressure begins to build inside your skull, behind your ear..."
+
+ spawn(200)
+
+ if(!host || !src) return
+
+ if(src.stat)
+ src << "You cannot infest a target in your current state."
+ return
+
+ src << "You wiggle out of [host]'s ear and plop to the ground."
+ if(!host.stat)
+ host << "Something slimy wiggles out of your ear and plops to the ground!"
+
+ detatch()
+
+mob/living/simple_animal/borer/proc/detatch()
+
+ if(!host) return
+
+ var/datum/organ/external/head = host.get_organ("head")
+ head.implants -= src
+ src.loc = get_turf(host)
+ controlling = 0
+
+ host.verbs -= /mob/living/carbon/human/proc/release_control
+ host.verbs -= /mob/living/carbon/human/proc/punish_host
+ host.verbs -= /mob/living/carbon/human/proc/spawn_larvae
+
+ if(host_brain.ckey)
+ src.ckey = host.ckey
+ host.ckey = host_brain.ckey
+ host_brain.ckey = null
+ host_brain.name = "host brain"
+ host_brain.real_name = "host brain"
+
+ host = null
+
+/mob/living/simple_animal/borer/verb/infest(var/mob/living/carbon/human/H)
+ set category = "Alien"
+ set name = "Infest"
+ set desc = "Infest a suitable humanoid host."
+
+ if(host)
+ src << "You are already within a host."
+ return
+
+ if(stat)
+ src << "You cannot infest a target in your current state."
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/C in view(1,src))
+ if(istype(C,/mob/living/carbon/human) && C.stat != 2)
+ choices += C
+
+ var/mob/living/carbon/human/M = input(src,"Who do you wish to infest?") in null|choices
+
+ if(!M || !src) return
+
+ if(M.has_brain_worms())
+ src << "You cannot infest someone who is already infested!"
+
+ M << "Something slimy begins probing at the opening of your ear canal..."
+ src << "You slither up [M] and begin probing at their ear canal..."
+
+ if(!do_after(src,50))
+ src << "As [M] moves away, you are dislodged and fall to the ground."
+ return
+
+ if(!M || !src) return
+
+ if(src.stat)
+ src << "You cannot infest a target in your current state."
+ return
+
+ if(M.stat == 2)
+ src << "That is not an appropriate target."
+ return
+
+ if(M in view(1, src))
+ src << "You wiggle into [M]'s ear."
+ if(!M.stat)
+ M << "Something disgusting and slimy wiggles into your ear!"
+
+ src.host = M
+ var/datum/organ/external/head = M.get_organ("head")
+ head.implants += src
+ src.loc = M
+ bonded = 0
+
+ host_brain.name = M.name
+ host_brain.real_name = M.real_name
+
+ return
+ else
+ src << "They are no longer in range!"
+ return
\ No newline at end of file
diff --git a/code/modules/mob/screen.dm b/code/modules/mob/screen.dm
index 514872db379..c83ba829a9d 100644
--- a/code/modules/mob/screen.dm
+++ b/code/modules/mob/screen.dm
@@ -606,6 +606,33 @@
var/mob/living/L = usr
+ //Resisting control by an alien mind.
+ if(istype(src.loc,/mob/living/simple_animal/borer))
+ var/mob/living/simple_animal/borer/B = src.loc
+ var/mob/living/captive_brain/H = src
+
+ H << "\red You begin doggedly resisting the parasite's control (this will take approximately sixty seconds)."
+ B.host << "\red You feel the captive mind of [src] begin to resist your control."
+
+ spawn(rand(350,450)+B.host.brainloss)
+
+ if(!B || !B.controlling)
+ return
+
+ B.host.adjustBrainLoss(rand(5,10))
+ H << "\red With an immense exertion of will, you regain control of your body!"
+ B.host << "\red You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you."
+ B.controlling = 0
+
+ B.ckey = B.host.ckey
+ B.host.ckey = H.ckey
+
+ H.ckey = null
+ H.name = "host brain"
+ H.real_name = "host brain"
+
+ return
+
//resisting grabs (as if it helps anyone...)
if ((!( L.stat ) && L.canmove && !( L.restrained() )))
var/resisting = 0
diff --git a/code/modules/surgery/implant.dm b/code/modules/surgery/implant.dm
index 0d67881f242..7e240f737e3 100644
--- a/code/modules/surgery/implant.dm
+++ b/code/modules/surgery/implant.dm
@@ -166,7 +166,7 @@
if (affected.implants.len)
- var/obj/item/weapon/obj = affected.implants[1]
+ var/obj/item/obj = affected.implants[1]
if(istype(obj,/obj/item/weapon/implant))
var/obj/item/weapon/implant/imp = obj
@@ -181,6 +181,11 @@
user.visible_message("\blue [user] takes something out of incision on [target]'s [affected.display_name] with \the [tool].", \
"\blue You take [obj] out of incision on [target]'s [affected.display_name]s with \the [tool]." )
affected.implants -= obj
+
+ //Handle possessive brain borers.
+ if(istype(obj,/mob/living/simple_animal/borer))
+ target.release_control()
+
obj.loc = get_turf(target)
if(istype(obj,/obj/item/weapon/implant))
var/obj/item/weapon/implant/imp = obj
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 88fb1e19fcf..e269d169aa7 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ