diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index d96df8be171..68a7ea6b7d8 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -62,6 +62,8 @@
//Simple animals
#define isanimal(A) (istype(A, /mob/living/simple_animal))
+#define isborer(A) (istype(A, /mob/living/simple_animal/borer))
+
#define isbot(A) (istype(A, /mob/living/simple_animal/bot))
#define iscrab(A) (istype(A, /mob/living/simple_animal/crab))
diff --git a/code/__DEFINES/role_preferences.dm b/code/__DEFINES/role_preferences.dm
index 51502947f6b..94995eeb23e 100644
--- a/code/__DEFINES/role_preferences.dm
+++ b/code/__DEFINES/role_preferences.dm
@@ -23,6 +23,7 @@
#define ROLE_REVENANT "revenant"
#define ROLE_DEVIL "devil"
#define ROLE_SERVANT_OF_RATVAR "servant of Ratvar"
+#define ROLE_BORER "borer"
//Missing assignment means it's not a gamemode specific role, IT'S NOT A BUG OR ERROR.
//The gamemode specific ones are just so the gamemodes can query whether a player is old enough
@@ -45,6 +46,7 @@ var/global/list/special_roles = list(
ROLE_ABDUCTOR = /datum/game_mode/abduction,
ROLE_DEVIL = /datum/game_mode/devil,
ROLE_SERVANT_OF_RATVAR = /datum/game_mode/clockwork_cult,
+ ROLE_BORER,
)
//Job defines for what happens when you fail to qualify for any job during job selection
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 8973a6de132..093196f0512 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -442,6 +442,22 @@ var/datum/subsystem/ticker/ticker
for(var/i in total_antagonists)
log_game("[i]s[total_antagonists[i]].")
+ if(borers.len)
+ var/total_borers = 0
+ for(var/mob/living/simple_animal/borer/B in borers)
+ if(B.stat != DEAD)
+ total_borers++
+ if(total_borers)
+ var/total_borer_hosts = 0
+ for(var/mob/living/carbon/C in mob_list)
+ var/mob/living/simple_animal/borer/D = C.has_brain_worms()
+ var/turf/location = get_turf(C)
+ if(location.z == ZLEVEL_CENTCOM && C.has_brain_worms() && D.stat != DEAD)
+ total_borer_hosts++
+ world << "There were [total_borers] borers alive at round end!"
+ world << "A total of [total_borer_hosts] borers with hosts escaped on the shuttle alive. The borers needed [total_borer_hosts_needed] hosts on the shuttle so they [(total_borer_hosts_needed <= total_borer_hosts) ? "won!" : "lost!"]"
+ return TRUE
+
mode.declare_station_goal_completion()
//Adds the del() log to world.log in a format condensable by the runtime condenser found in tools
diff --git a/code/datums/mutations.dm b/code/datums/mutations.dm
index 3cf6f187749..8e17dc87617 100644
--- a/code/datums/mutations.dm
+++ b/code/datums/mutations.dm
@@ -377,6 +377,9 @@
time_coeff = 2
/datum/mutation/human/race/on_acquiring(mob/living/carbon/human/owner)
+ if(owner.has_brain_worms())
+ owner << "You feel something strongly clinging to your humanity!"
+ return
if(..())
return
. = owner.monkeyize(TR_KEEPITEMS | TR_KEEPIMPLANTS | TR_KEEPORGANS | TR_KEEPDAMAGE | TR_KEEPVIRUS | TR_KEEPSE)
diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm
index 32f6133ee0e..4fafd007042 100644
--- a/code/game/data_huds.dm
+++ b/code/game/data_huds.dm
@@ -162,11 +162,14 @@
var/image/holder = hud_list[STATUS_HUD]
var/icon/I = icon(icon, icon_state, dir)
var/virus_state = check_virus()
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
holder.pixel_y = I.Height() - world.icon_size
if(status_flags & XENO_HOST)
holder.icon_state = "hudxeno"
else if(stat == DEAD || (status_flags & FAKEDEATH))
holder.icon_state = "huddead"
+ else if(has_brain_worms() && B != null && B.controlling)
+ holder.icon_state = "hudbrainworm"
else if(virus_state == 2)
holder.icon_state = "hudill"
else if(virus_state == 1)
diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/game/gamemodes/changeling/powers/panacea.dm
index d4c60625f27..65d20900d8c 100644
--- a/code/game/gamemodes/changeling/powers/panacea.dm
+++ b/code/game/gamemodes/changeling/powers/panacea.dm
@@ -10,6 +10,15 @@
/obj/effect/proc_holder/changeling/panacea/sting_action(mob/user)
user << "We begin cleansing impurities from our form."
+ var/mob/living/simple_animal/borer/B = user.has_brain_worms()
+ if(B)
+ if(B.controlling)
+ B.detatch()
+ B.leave_victim()
+ if(iscarbon(user))
+ var/mob/living/carbon/C = user
+ C.vomit(0)
+ user << "A parasite exits our form."
var/obj/item/organ/body_egg/egg = user.getorgan(/obj/item/organ/body_egg)
if(egg)
egg.Remove(user)
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index e4e2ce466b5..78ed43bbbf2 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -131,6 +131,12 @@ MASS SPECTROMETER
var/mob/living/carbon/human/H = M
if(H.heart_attack && H.stat != DEAD)
user << "Subject suffering from heart attack: Apply defibrillator immediately!"
+
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.has_brain_worms())
+ user << "Foreign organism detected in subject's cranium. Recommended treatment: Dosage of sucrose solution and removal of object via surgery."
+
user << "Analyzing results for [M]:\n\tOverall status: [mob_status]"
// Damage descriptions
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index 633bcbc3994..a7924868435 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -832,6 +832,12 @@
else
dat += "
Alien | "
+ //Borer
+ if(jobban_isbanned(M, "borer") || isbanned_dept)
+ dat += "Borer | "
+ else
+ dat += "Borer | "
+
dat += ""
usr << browse(dat, "window=jobban2;size=800x450")
return
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 1877439b3fb..82d81bbe9a2 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -289,7 +289,10 @@ Pipelines + Other Objects -> Pipe network
return list()
/obj/machinery/atmospherics/update_remote_sight(mob/user)
- user.sight |= (SEE_TURFS|BLIND)
+ if(isborer(user))
+ user.sight |= (SEE_PIXELS)
+ else
+ user.sight |= (SEE_TURFS|BLIND)
//Used for certain children of obj/machinery/atmospherics to not show pipe vision when mob is inside it.
/obj/machinery/atmospherics/proc/can_see_pipes()
diff --git a/code/modules/client/verbs/suicide.dm b/code/modules/client/verbs/suicide.dm
index fd2e6364ba5..3dee26565f4 100644
--- a/code/modules/client/verbs/suicide.dm
+++ b/code/modules/client/verbs/suicide.dm
@@ -157,7 +157,7 @@
/mob/living/proc/canSuicide()
if(stat == CONSCIOUS)
- return 1
+ return TRUE
else if(stat == DEAD)
src << "You're already dead!"
else if(stat == UNCONSCIOUS)
@@ -170,4 +170,7 @@
if(!canmove || restrained()) //just while I finish up the new 'fun' suiciding verb. This is to prevent metagaming via suicide
src << "You can't commit suicide whilst restrained! ((You can type Ghost instead however.))"
return
- return 1
+ if(has_brain_worms())
+ src << "You can't bring yourself to commit suicide!"
+ return
+ return TRUE
diff --git a/code/modules/mob/living/brain/brain_item.dm b/code/modules/mob/living/brain/brain_item.dm
index 4bccb03c2d8..74c2c0e0818 100644
--- a/code/modules/mob/living/brain/brain_item.dm
+++ b/code/modules/mob/living/brain/brain_item.dm
@@ -31,10 +31,17 @@
C.update_hair()
/obj/item/organ/brain/Remove(mob/living/carbon/C, special = 0)
- ..()
if(!special)
- transfer_identity(C)
- C.update_hair()
+ var/mob/living/simple_animal/borer/B = owner.has_brain_worms()
+ if(B)
+ B.leave_victim() //Should remove borer if the brain is removed - RR
+ if(owner.mind)
+ src.transfer_identity(C)
+
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.update_hair()
+ . = ..()
/obj/item/organ/brain/prepare_eat()
return // Too important to eat.
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index f89f7a2c094..b644ba2ae39 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -76,6 +76,11 @@
stat("Internal Atmosphere Info", internal.name)
stat("Tank Pressure", internal.air_contents.return_pressure())
stat("Distribution Pressure", internal.distribute_pressure)
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+ if(B && B.controlling)
+ stat("Chemicals", B.chemicals)
+
if(mind)
if(mind.changeling)
stat("Chemical Storage", "[mind.changeling.chem_charges]/[mind.changeling.chem_storage]")
diff --git a/code/modules/mob/living/simple_animal/borer/borer.dm b/code/modules/mob/living/simple_animal/borer/borer.dm
new file mode 100644
index 00000000000..68236d17596
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer/borer.dm
@@ -0,0 +1,1018 @@
+/mob/living/captive_brain
+ name = "host brain"
+ real_name = "host brain"
+
+/mob/living/captive_brain/say(var/message)
+
+ if(client)
+ if(client.prefs.muted & MUTE_IC)
+ src << "You cannot speak in IC (muted)."
+ return
+ if(client.handle_spam_prevention(message,MUTE_IC))
+ return
+
+ if(isborer(loc))
+
+ message = sanitize(message)
+ if(!message)
+ return
+ log_say("[key_name(src)] : [message]")
+ if(stat == 2)
+ return say_dead(message)
+
+ var/mob/living/simple_animal/borer/B = loc
+ src << "You whisper silently, \"[message]\""
+ B.victim << "The captive mind of [src] whispers, \"[message]\""
+
+ for (var/mob/M in player_list)
+ if(isnewplayer(M))
+ continue
+ else if(M.stat == 2 && M.client.prefs.toggles & CHAT_GHOSTEARS)
+ M << "Thought-speech, [src] -> [B.truename]: [message]"
+
+/mob/living/captive_brain/emote(var/message)
+ return
+
+/mob/living/captive_brain/resist()
+
+ var/mob/living/simple_animal/borer/B = loc
+
+ src << "You begin doggedly resisting the parasite's control (this will take approximately 40 seconds)."
+ B.victim << "You feel the captive mind of [src] begin to resist your control."
+
+ var/delay = rand(150,250) + B.victim.brainloss
+ addtimer(src, "return_control", delay, FALSE, src.loc)
+
+/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/borer/B)
+ if(!B || !B.controlling)
+ return
+
+ B.victim.adjustBrainLoss(rand(5,10))
+ src << "With an immense exertion of will, you regain control of your body!"
+ B.victim << "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you."
+ B.detatch()
+
+var/list/mob/living/simple_animal/borer/borers = list()
+var/total_borer_hosts_needed = 10
+
+/mob/living/simple_animal/borer
+ name = "cortical borer"
+ real_name = "cortical borer"
+ desc = "A small, quivering, slug-like creature."
+ icon_state = "brainslug"
+ icon_living = "brainslug"
+ icon_dead = "brainslug_dead"
+ health = 20
+ maxHealth = 20
+ melee_damage_lower = 5
+ melee_damage_upper = 5
+ stop_automated_movement = TRUE
+ attacktext = "chomps"
+ attack_sound = 'sound/weapons/bite.ogg'
+ pass_flags = PASSTABLE | PASSMOB
+ mob_size = MOB_SIZE_SMALL
+ faction = list("creature")
+ ventcrawler = 2
+ atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
+ minbodytemp = 0
+ maxbodytemp = 1500
+
+ var/generation = 1
+ var/static/list/borer_names = list(
+ "Primary", "Secondary", "Tertiary", "Quaternary", "Quinary", "Senary",
+ "Septenary", "Octonary", "Novenary", "Decenary", "Undenary", "Duodenary",
+ )
+
+ var/mob/living/carbon/victim = null
+ var/mob/living/captive_brain/host_brain = null
+ var/truename
+ var/docile = FALSE
+ var/bonding = FALSE
+ var/controlling = FALSE
+ var/chemicals = 10
+ var/used_dominate
+ var/borer_chems = list()
+ var/leaving = FALSE
+ var/hiding = FALSE
+
+ var/datum/action/innate/borer/talk_to_host/talk_to_host_action = new
+ var/datum/action/innate/borer/infest_host/infest_host_action = new
+ var/datum/action/innate/borer/toggle_hide/toggle_hide_action = new
+ var/datum/action/innate/borer/talk_to_borer/talk_to_borer_action = new
+ var/datum/action/innate/borer/talk_to_brain/talk_to_brain_action = new
+ var/datum/action/innate/borer/take_control/take_control_action = new
+ var/datum/action/innate/borer/give_back_control/give_back_control_action = new
+ var/datum/action/innate/borer/leave_body/leave_body_action = new
+ var/datum/action/innate/borer/make_chems/make_chems_action = new
+ var/datum/action/innate/borer/make_larvae/make_larvae_action = new
+ var/datum/action/innate/borer/freeze_victim/freeze_victim_action = new
+ var/datum/action/innate/borer/punish_victim/punish_victim_action = new
+ var/datum/action/innate/borer/jumpstart_host/jumpstart_host_action = new
+
+/mob/living/simple_animal/borer/New(atom/newloc, var/gen=1)
+ ..(newloc)
+ generation = gen
+ notify_ghosts("A cortical borer has been created in [get_area(src)]!", enter_link = "(Click to enter)", source = src, action = NOTIFY_ATTACK)
+ real_name = "Cortical Borer [rand(1000,9999)]"
+ truename = "[borer_names[min(generation, borer_names.len)]] [rand(1000,9999)]"
+ borer_chems += /datum/borer_chem/epinephrine
+ borer_chems += /datum/borer_chem/leporazine
+ borer_chems += /datum/borer_chem/mannitol
+ borer_chems += /datum/borer_chem/bicaridine
+ borer_chems += /datum/borer_chem/kelotane
+ borer_chems += /datum/borer_chem/charcoal
+ borer_chems += /datum/borer_chem/methamphetamine
+ borer_chems += /datum/borer_chem/salbutamol
+ borer_chems += /datum/borer_chem/spacedrugs
+ //borer_chems += /datum/borer_chem/creagent
+ borer_chems += /datum/borer_chem/ethanol
+ borer_chems += /datum/borer_chem/rezadone
+
+ borers += src
+
+ GrantBorerActions()
+
+/mob/living/simple_animal/borer/attack_ghost(mob/user)
+ if(jobban_isbanned(user, ROLE_BORER) || jobban_isbanned(user, "Syndicate"))
+ return
+ if(ckey)
+ return
+ if(stat != CONSCIOUS)
+ return
+ var/be_swarmer = alert("Become a cortical borer? (Warning, You can no longer be cloned!)",,"Yes","No")
+ if(be_swarmer == "No")
+ return
+ if(src && !qdeleted(src))
+ transfer_personality(user.client)
+
+/mob/living/simple_animal/borer/Stat()
+ ..()
+
+ if(statpanel("Status"))
+ stat(null, "Chemicals: [chemicals]")
+
+ src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals")
+
+/mob/living/simple_animal/borer/verb/Communicate()
+ set category = "Borer"
+ set name = "Converse with Host"
+ set desc = "Send a silent message to your host."
+
+ if(!victim)
+ src << "You do not have a host to communicate with!"
+ return
+
+ if(stat)
+ src << "You cannot do that in your current state."
+ return
+
+ var/input = stripped_input(src, "Please enter a message to tell your host.", "Borer", null)
+ if(!input)
+ return
+
+ if(src && !qdeleted(src) && !qdeleted(victim))
+ var/say_string = (docile) ? "slurs" :"states"
+ if(victim)
+ victim << "[truename] [say_string]: [input]"
+ log_say("Borer Communication: [key_name(src)] -> [key_name(victim)] : [input]")
+ for(var/M in dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Borer Communication from [truename] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ M << "[link] [rendered]"
+ src << "[truename] [say_string]: [input]"
+ victim.verbs += /mob/living/proc/borer_comm
+ talk_to_borer_action.Grant(victim)
+
+/mob/living/proc/borer_comm()
+ set name = "Converse with Borer"
+ set category = "Borer"
+ set desc = "Communicate mentally with your borer."
+
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+ if(!B)
+ return
+
+ var/input = stripped_input(src, "Please enter a message to tell the borer.", "Message", null)
+ if(!input)
+ return
+
+ B << "[src] says: [input]"
+ log_say("Borer Communication: [key_name(src)] -> [key_name(B)] : [input]")
+
+ for(var/M in dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Borer Communication from [src] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ M << "[link] [rendered]"
+ src << "[src] says: [input]"
+
+/mob/living/proc/trapped_mind_comm()
+ set name = "Converse with Trapped Mind"
+ set category = "Borer"
+ set desc = "Communicate mentally with the trapped mind of your host."
+
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+ if(!B || !B.host_brain)
+ return
+ var/mob/living/captive_brain/CB = B.host_brain
+ var/input = stripped_input(src, "Please enter a message to tell the trapped mind.", "Message", null)
+ if(!input)
+ return
+
+ CB << "[B.truename] says: [input]"
+ log_say("Borer Communication: [key_name(B)] -> [key_name(CB)] : [input]")
+
+ for(var/M in dead_mob_list)
+ if(isobserver(M))
+ var/rendered = "Borer Communication from [B] : [input]"
+ var/link = FOLLOW_LINK(M, src)
+ M << "[link] [rendered]"
+ src << "[B.truename] says: [input]"
+
+/mob/living/simple_animal/borer/Life()
+
+ ..()
+
+ if(victim)
+ if(stat != DEAD)
+ if(victim.stat == DEAD)
+ chemicals++
+ else if(chemicals < 250)
+ chemicals+=2
+ chemicals = min(250, chemicals)
+
+
+ if(stat != DEAD && victim.stat != DEAD)
+
+ if(victim.reagents.has_reagent("sugar"))
+ if(!docile)
+ if(controlling)
+ victim << "You feel the soporific flow of sugar in your host's blood, lulling you into docility."
+ else
+ src << "You feel the soporific flow of sugar in your host's blood, lulling you into docility."
+ docile = TRUE
+ else
+ if(docile)
+ if(controlling)
+ victim << "You shake off your lethargy as the sugar leaves your host's blood."
+ else
+ src << "You shake off your lethargy as the sugar leaves your host's blood."
+ docile = FALSE
+ if(controlling)
+
+ if(docile)
+ victim << "You are feeling far too docile to continue controlling your host..."
+ victim.release_control()
+ return
+
+ if(prob(5))
+ victim.adjustBrainLoss(rand(1,2))
+
+ if(prob(victim.brainloss/20))
+ victim.say("*[pick(list("blink","blink_r","choke","aflap","drool","twitch","twitch_s","gasp"))]")
+
+/mob/living/simple_animal/borer/say(message)
+ if(dd_hasprefix(message, ";"))
+ message = copytext(message,2)
+ for(var/borer in borers)
+ borer << "Cortical Link: [truename] sings, \"[message]\""
+ for(var/mob/dead in dead_mob_list)
+ dead << "Cortical Link: [truename] sings, \"[message]\""
+ return
+ if(!victim)
+ src << "You cannot speak without a host!"
+ return
+ if(message == "")
+ return
+
+/mob/living/simple_animal/borer/UnarmedAttack(mob/living/M)
+ healthscan(usr, M)
+ chemscan(usr, M)
+ return
+
+/mob/living/simple_animal/borer/ex_act()
+ if(victim)
+ return
+
+ ..()
+
+/mob/living/simple_animal/borer/verb/infect_victim()
+ set name = "Infest"
+ set category = "Borer"
+ set desc = "Infest a suitable humanoid host."
+
+ if(victim)
+ src << "You are already within a host."
+
+ if(stat == DEAD)
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/carbon/H in view(1,src))
+ if(H!=src && Adjacent(H))
+ choices += H
+
+ var/mob/living/carbon/H = input(src,"Who do you wish to infest?") in null|choices
+ if(!H || !src)
+ return
+
+ if(!Adjacent(H))
+ return FALSE
+
+ if(stat != CONSCIOUS)
+ src << "You cannot do that in your current state."
+ return FALSE
+
+ if(H.has_brain_worms())
+ src << "[victim] is already infested!"
+ return
+
+ src << "You slither up [H] and begin probing at their ear canal..."
+ layer = MOB_LAYER
+ if(!do_mob(src, H, 30))
+ src << "As [H] moves away, you are dislodged and fall to the ground."
+ return
+
+ if(!H || !src)
+ return
+
+ Infect(H)
+
+/mob/living/simple_animal/borer/proc/Infect(mob/living/carbon/C)
+ if(!C)
+ return
+
+ if(C.has_brain_worms())
+ src << "[C] is already infested!"
+ return
+
+ if(!C.key || !C.mind)
+ src << "[C]'s mind seems unresponsive. Try someone else!"
+ return
+
+ if(C && C.dna && istype(C.dna.species, /datum/species/skeleton))
+ src << "[C] does not possess the vital systems needed to support us."
+ return
+
+ victim = C
+ forceMove(victim)
+
+ RemoveBorerActions()
+ GrantInfestActions()
+
+ log_game("[src]/([src.ckey]) has infested [victim]/([victim.ckey]")
+
+/mob/living/simple_animal/borer/verb/secrete_chemicals()
+ set category = "Borer"
+ set name = "Secrete Chemicals"
+ set desc = "Push some chemicals into your host's bloodstream."
+
+ if(!victim)
+ src << "You are not inside a host body."
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot secrete chemicals in your current state."
+
+ if(docile)
+ src << "You are feeling far too docile to do that."
+ return
+
+ var content = ""
+ content += "Chemicals: [chemicals]
"
+
+ content += ""
+
+ for(var/datum in typesof(/datum/borer_chem))
+ var/datum/borer_chem/C = new datum()
+ if(C.chemname)
+ content += "| [C.chemname] ([C.chemuse]) [C.chem_desc] |
"
+
+ content += "
"
+
+ var/html = get_html_template(content)
+
+ usr << browse(null, "window=ViewBorer\ref[src]Chems;size=600x800")
+ usr << browse(html, "window=ViewBorer\ref[src]Chems;size=600x800")
+
+ return
+
+/mob/living/simple_animal/borer/verb/hide()
+ set category = "Borer"
+ set name = "Hide"
+ set desc = "Become invisible to the common eye."
+
+ if(victim)
+ src << "You cannot do this while you're inside a host."
+
+ if(stat != CONSCIOUS)
+ return
+
+ if(!hiding)
+ layer = LATTICE_LAYER
+ visible_message("[src] scurries to the ground!", \
+ "You are now hiding.")
+ hiding = TRUE
+ else
+ layer = MOB_LAYER
+ visible_message("[src] slowly peaks up from the ground...", \
+ "You stop hiding.")
+ hiding = FALSE
+
+/mob/living/simple_animal/borer/verb/dominate_victim()
+ set category = "Borer"
+ set name = "Paralyze Victim"
+ set desc = "Freeze the limbs of a potential host with supernatural fear."
+
+ if(world.time - used_dominate < 150)
+ src << "You cannot use that ability again so soon."
+ return
+
+ if(victim)
+ src << "You cannot do that from within a host body."
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot do that in your current state."
+ return
+
+ var/list/choices = list()
+ for(var/mob/living/carbon/C in view(1,src))
+ if(C.stat == CONSCIOUS)
+ choices += C
+
+ var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices
+
+
+ if(!M || !src)
+ return
+ if(!Adjacent(M))
+ return
+
+ if(M.has_brain_worms())
+ src << "You cannot paralyze someone who is already infested!"
+ return
+
+ layer = MOB_LAYER
+
+ src << "You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread."
+ M << "You feel a creeping, horrible sense of dread come over you, freezing your limbs and setting your heart racing."
+ M.Stun(4)
+
+ used_dominate = world.time
+
+/mob/living/simple_animal/borer/verb/release_victim()
+ set category = "Borer"
+ set name = "Release Host"
+ set desc = "Slither out of your host."
+
+ if(!victim)
+ src << "You are not inside a host body."
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot leave your host in your current state."
+
+ if(leaving)
+ leaving = FALSE
+ src << "You decide against leaving your host."
+ return
+
+ src << "You begin disconnecting from [victim]'s synapses and prodding at their internal ear canal."
+
+ if(victim.stat != DEAD)
+ victim << "An odd, uncomfortable pressure begins to build inside your skull, behind your ear..."
+
+ leaving = TRUE
+
+ addtimer(src, "release_host", 100, FALSE)
+
+/mob/living/simple_animal/borer/proc/release_host()
+ if(!victim || !src || qdeleted(victim) || qdeleted(src))
+ return
+ if(!leaving)
+ return
+ if(controlling)
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot release your host in your current state."
+ return
+
+ src << "You wiggle out of [victim]'s ear and plop to the ground."
+ if(victim.mind)
+ victim << "Something slimy wiggles out of your ear and plops to the ground!"
+ victim << "As though waking from a dream, you shake off the insidious mind control of the brain worm. Your thoughts are your own again."
+
+ leaving = FALSE
+
+ leave_victim()
+
+/mob/living/simple_animal/borer/proc/leave_victim()
+ if(!victim)
+ return
+
+ if(controlling)
+ detatch()
+
+ GrantBorerActions()
+ RemoveInfestActions()
+
+ forceMove(get_turf(victim))
+
+ reset_perspective(null)
+ machine = null
+
+ victim.reset_perspective(null)
+ victim.machine = null
+
+ var/mob/living/V = victim
+ V.verbs -= /mob/living/proc/borer_comm
+ talk_to_borer_action.Remove(victim)
+ victim = null
+ return
+
+/mob/living/simple_animal/borer/verb/jumpstart()
+ set category = "Borer"
+ set name = "Jumpstart Host"
+ set desc = "Bring your host back to life."
+
+ if(!victim)
+ src << "You need a host to be able to use this."
+ return
+
+ if(docile)
+ src << "You are feeling too docile to use this!"
+ return
+
+ if(victim.stat != DEAD)
+ src << "Your host is already alive!"
+ return
+
+ if(chemicals < 250)
+ src << "You need 250 chemicals to use this!"
+ return
+
+ if(victim.stat == DEAD)
+ victim.tod = null
+ victim.setToxLoss(0)
+ victim.setOxyLoss(0)
+ victim.setCloneLoss(0)
+ victim.SetParalysis(0)
+ victim.SetStunned(0)
+ victim.SetWeakened(0)
+ victim.radiation = 0
+ victim.heal_overall_damage(victim.getBruteLoss(), victim.getFireLoss())
+ victim.reagents.clear_reagents()
+ if(ishuman(victim))
+ var/mob/living/carbon/human/H = victim
+ H.restore_blood()
+ H.remove_all_embedded_objects()
+ victim.revive()
+ log_game("[src]/([src.ckey]) has revived [victim]/([victim.ckey]")
+ chemicals -= 250
+ src << "You send a jolt of energy to your host, reviving them!"
+ victim.grab_ghost(force = TRUE) //brings the host back, no eggscape
+ victim <<"You bolt upright, gasping for breath!"
+
+/mob/living/simple_animal/borer/verb/bond_brain()
+ set category = "Borer"
+ set name = "Assume Control"
+ set desc = "Fully connect to the brain of your host."
+
+ if(!victim)
+ src << "You are not inside a host body."
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot do that in your current state."
+ return
+
+ if(docile)
+ src << "You are feeling far too docile to do that."
+ return
+
+ if(victim.stat == DEAD)
+ src << "This host lacks enough brain function to control."
+ return
+
+ if(bonding)
+ bonding = FALSE
+ src << "You stop attempting to take control of your host."
+ return
+
+ src << "You begin delicately adjusting your connection to the host brain..."
+
+ if(qdeleted(src) || qdeleted(victim))
+ return
+
+ bonding = TRUE
+
+ var/delay = 200+(victim.brainloss*5)
+ addtimer(src, "assume_control", delay, FALSE)
+
+/mob/living/simple_animal/borer/proc/assume_control()
+ if(!victim || !src || controlling || victim.stat == DEAD)
+ return
+ if(docile)
+ src <<"You are feeling far too docile to do that."
+ return
+ else
+
+
+ log_game("[src]/([src.ckey]) assumed control of [victim]/([victim.ckey] with borer powers.")
+ src << "You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system."
+ victim << "You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours."
+
+ // host -> brain
+ var/h2b_id = victim.computer_id
+ var/h2b_ip= victim.lastKnownIP
+ victim.computer_id = null
+ victim.lastKnownIP = null
+
+ qdel(host_brain)
+ host_brain = new(src)
+
+ host_brain.ckey = victim.ckey
+
+ host_brain.name = victim.name
+
+ if(victim.mind)
+ host_brain.mind = victim.mind
+
+ if(!host_brain.computer_id)
+ host_brain.computer_id = h2b_id
+
+ if(!host_brain.lastKnownIP)
+ host_brain.lastKnownIP = h2b_ip
+
+ host_brain << "You are trapped in your own mind. You feel that there must be a way to resist!"
+
+ // self -> host
+ var/s2h_id = src.computer_id
+ var/s2h_ip= src.lastKnownIP
+ src.computer_id = null
+ src.lastKnownIP = null
+
+ victim.ckey = src.ckey
+ victim.mind = src.mind
+
+ if(!victim.computer_id)
+ victim.computer_id = s2h_id
+
+ if(!victim.lastKnownIP)
+ victim.lastKnownIP = s2h_ip
+
+ controlling = TRUE
+
+ bonding = FALSE
+
+ victim.verbs += /mob/living/carbon/proc/release_control
+ victim.verbs += /mob/living/carbon/proc/spawn_larvae
+ victim.verbs -= /mob/living/proc/borer_comm
+ victim.verbs += /mob/living/proc/trapped_mind_comm
+ GrantControlActions()
+ talk_to_borer_action.Remove(victim)
+
+ victim.med_hud_set_status()
+
+/mob/living/simple_animal/borer/verb/punish()
+ set category = "Borer"
+ set name = "Punish"
+ set desc = "Punish your victim."
+
+ if(!victim)
+ src << "You are not inside a host body."
+ return
+
+ if(stat != CONSCIOUS)
+ src << "You cannot do that in your current state."
+ return
+
+ if(docile)
+ src << "You are feeling far too docile to do that."
+ return
+
+ if(chemicals < 75)
+ src << "You need 75 chems to punish your host."
+ return
+
+ var/punishment = input("Select a punishment:.", "Punish") as null|anything in list("Blindness","Deafness","Stun")
+
+ if(!punishment)
+ return
+
+ if(chemicals < 75)
+ src << "You need 75 chems to punish your host."
+ return
+
+ switch(punishment) //Hardcoding this stuff.
+ if("Blindness")
+ victim.blind_eyes(2)
+ if("Deafness")
+ victim.ear_deaf = 20
+ if("Stun")
+ victim.Weaken(10)
+
+ log_game("[src]/([src.ckey]) punished [victim]/([victim.ckey] with [punishment]")
+
+ chemicals -= 75
+
+
+mob/living/carbon/proc/release_control()
+
+ set category = "Borer"
+ set name = "Release Control"
+ set desc = "Release control of your host's body."
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+ if(B && B.host_brain)
+ src << "You withdraw your probosci, releasing control of [B.host_brain]"
+
+ B.detatch()
+
+//Check for brain worms in head.
+/mob/proc/has_brain_worms()
+
+ for(var/I in contents)
+ if(isborer(I))
+ return I
+
+ return FALSE
+
+/mob/living/carbon/proc/spawn_larvae()
+ set category = "Borer"
+ set name = "Reproduce"
+ set desc = "Spawn several young."
+
+ var/mob/living/simple_animal/borer/B = has_brain_worms()
+
+ if(isbrain(src))
+ src << "You need a mouth to be able to do this."
+ return
+ if(!B)
+ return
+
+ if(B.chemicals >= 100)
+ visible_message("[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), B.generation + 1)
+ log_game("[src]/([src.ckey]) has spawned a new borer via reproducing.")
+ else
+ src << "You do not have enough chemicals stored to reproduce."
+ return
+
+
+/mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate)
+ if(!candidate || !candidate.mob)
+ return
+
+ if(!qdeleted(candidate) || !qdeleted(candidate.mob))
+ var/datum/mind/M = create_borer_mind(candidate.ckey)
+ M.transfer_to(src)
+
+ candidate.mob = src
+ ckey = candidate.ckey
+
+ if(mind)
+ mind.store_memory("You must escape with at least [total_borer_hosts_needed] borers with hosts on the shuttle.")
+
+ src << "You are a cortical borer! You are a brain slug that worms its way \
+ into the head of its victim. Use stealth, persuasion and your powers of mind control to keep you, \
+ your host and your eventual spawn safe and warm."
+ src << "Sugar nullifies your abilities, avoid it at all costs!"
+ src << "You can speak to your fellow borers by prefixing your messages with ';'. Check out your Borer tab to see your abilities."
+ src << "You must escape with at least [total_borer_hosts_needed] borers with hosts on the shuttle. To reproduce you must have 100 chemicals and be controlling a host."
+
+/mob/living/simple_animal/borer/proc/detatch()
+ if(!victim || !controlling)
+ return
+
+ controlling = FALSE
+
+ victim.verbs -= /mob/living/carbon/proc/release_control
+ victim.verbs -= /mob/living/carbon/proc/spawn_larvae
+ victim.verbs += /mob/living/proc/borer_comm
+ victim.verbs -= /mob/living/proc/trapped_mind_comm
+ RemoveControlActions()
+ talk_to_borer_action.Grant(victim)
+
+ victim.med_hud_set_status()
+
+ if(host_brain)
+
+ // these are here so bans and multikey warnings are not triggered on the wrong people when ckey is changed.
+ // computer_id and IP are not updated magically on their own in offline mobs -walter0o
+
+ // host -> self
+ var/h2s_id = victim.computer_id
+ var/h2s_ip= victim.lastKnownIP
+ victim.computer_id = null
+ victim.lastKnownIP = null
+
+ ckey = victim.ckey
+ mind = victim.mind
+
+
+ if(!computer_id)
+ computer_id = h2s_id
+
+ if(!host_brain.lastKnownIP)
+ lastKnownIP = h2s_ip
+
+ // brain -> host
+ var/b2h_id = host_brain.computer_id
+ var/b2h_ip= host_brain.lastKnownIP
+ host_brain.computer_id = null
+ host_brain.lastKnownIP = null
+
+ victim.ckey = host_brain.ckey
+
+ victim.mind = host_brain.mind
+
+ if(!victim.computer_id)
+ victim.computer_id = b2h_id
+
+ if(!victim.lastKnownIP)
+ victim.lastKnownIP = b2h_ip
+
+ log_game("[src]/([src.ckey]) released control of [victim]/([victim.ckey]")
+
+ qdel(host_brain)
+
+/proc/create_borer_mind(key)
+ var/datum/mind/M = new /datum/mind(key)
+ M.assigned_role = "Cortical Borer"
+ M.special_role = "Cortical Borer"
+ return M
+
+/mob/living/simple_animal/borer/proc/GrantBorerActions()
+ infest_host_action.Grant(src)
+ toggle_hide_action.Grant(src)
+ freeze_victim_action.Grant(src)
+
+/mob/living/simple_animal/borer/proc/RemoveBorerActions()
+ infest_host_action.Remove(src)
+ toggle_hide_action.Remove(src)
+ freeze_victim_action.Remove(src)
+
+/mob/living/simple_animal/borer/proc/GrantInfestActions()
+ talk_to_host_action.Grant(src)
+ leave_body_action.Grant(src)
+ take_control_action.Grant(src)
+ punish_victim_action.Grant(src)
+ make_chems_action.Grant(src)
+ jumpstart_host_action.Grant(src)
+
+/mob/living/simple_animal/borer/proc/RemoveInfestActions()
+ talk_to_host_action.Remove(src)
+ take_control_action.Remove(src)
+ leave_body_action.Remove(src)
+ punish_victim_action.Remove(src)
+ make_chems_action.Remove(src)
+ jumpstart_host_action.Remove(src)
+
+/mob/living/simple_animal/borer/proc/GrantControlActions()
+ talk_to_brain_action.Grant(victim)
+ give_back_control_action.Grant(victim)
+ make_larvae_action.Grant(victim)
+
+/mob/living/simple_animal/borer/proc/RemoveControlActions()
+ talk_to_brain_action.Remove(victim)
+ make_larvae_action.Remove(victim)
+ give_back_control_action.Remove(victim)
+
+/datum/action/innate/borer
+ background_icon_state = "bg_alien"
+
+/datum/action/innate/borer/talk_to_host
+ name = "Converse with Host"
+ desc = "Send a silent message to your host."
+ button_icon_state = "alien_whisper"
+
+/datum/action/innate/borer/talk_to_host/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.Communicate()
+
+/datum/action/innate/borer/infest_host
+ name = "Infest"
+ desc = "Infest a suitable humanoid host."
+ button_icon_state = "infest"
+
+/datum/action/innate/borer/infest_host/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.infect_victim()
+
+/datum/action/innate/borer/toggle_hide
+ name = "Toggle Hide"
+ desc = "Become invisible to the common eye. Toggled on or off."
+ button_icon_state = "borer_hiding_false"
+
+/datum/action/innate/borer/toggle_hide/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.hide()
+ button_icon_state = "borer_hiding_[B.hiding ? "true" : "false"]"
+ UpdateButtonIcon()
+
+/datum/action/innate/borer/talk_to_borer
+ name = "Converse with Borer"
+ desc = "Communicate mentally with your borer."
+ button_icon_state = "alien_whisper"
+
+/datum/action/innate/borer/talk_to_borer/Activate()
+ var/mob/living/simple_animal/borer/B = owner.has_brain_worms()
+ B.victim = owner
+ B.victim.borer_comm()
+
+
+/datum/action/innate/borer/talk_to_brain
+ name = "Converse with Trapped Mind"
+ desc = "Communicate mentally with the trapped mind of your host."
+ button_icon_state = "alien_whisper"
+
+/datum/action/innate/borer/talk_to_brain/Activate()
+ var/mob/living/simple_animal/borer/B = owner.has_brain_worms()
+ B.victim = owner
+ B.victim.trapped_mind_comm()
+
+/datum/action/innate/borer/take_control
+ name = "Assume Control"
+ desc = "Fully connect to the brain of your host."
+ button_icon_state = "borer_brain"
+
+/datum/action/innate/borer/take_control/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.bond_brain()
+
+/datum/action/innate/borer/give_back_control
+ name = "Release Control"
+ desc = "Release control of your host's body."
+ button_icon_state = "borer_leave"
+
+/datum/action/innate/borer/give_back_control/Activate()
+ var/mob/living/simple_animal/borer/B = owner.has_brain_worms()
+ B.victim = owner
+ B.victim.release_control()
+
+/datum/action/innate/borer/leave_body
+ name = "Release Host"
+ desc = "Slither out of your host."
+ button_icon_state = "borer_leave"
+
+/datum/action/innate/borer/leave_body/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.release_victim()
+
+/datum/action/innate/borer/make_chems
+ name = "Secrete Chemicals"
+ desc = "Push some chemicals into your host's bloodstream."
+ icon_icon = 'icons/obj/chemical.dmi'
+ button_icon_state = "minidispenser"
+
+/datum/action/innate/borer/make_chems/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.secrete_chemicals()
+
+/datum/action/innate/borer/make_larvae
+ name = "Reproduce"
+ desc = "Spawn several young."
+ button_icon_state = "borer_reproduce"
+
+/datum/action/innate/borer/make_larvae/Activate()
+ var/mob/living/simple_animal/borer/B = owner.has_brain_worms()
+ B.victim = owner
+ B.victim.spawn_larvae()
+
+/datum/action/innate/borer/freeze_victim
+ name = "Paralyze Victim"
+ desc = "Freeze the limbs of a potential host with supernatural fear."
+ button_icon_state = "freeze"
+
+/datum/action/innate/borer/freeze_victim/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.dominate_victim()
+
+/datum/action/innate/borer/punish_victim
+ name = "Punish"
+ desc = "Punish your victim."
+ button_icon_state = "blind"
+
+/datum/action/innate/borer/punish_victim/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.punish()
+
+/datum/action/innate/borer/jumpstart_host
+ name = "Jumpstart Host"
+ desc = "Bring your host back to life."
+ icon_icon = 'icons/obj/weapons.dmi'
+ button_icon_state = "defibpaddles0"
+
+/datum/action/innate/borer/jumpstart_host/Activate()
+ var/mob/living/simple_animal/borer/B = owner
+ B.jumpstart()
diff --git a/code/modules/mob/living/simple_animal/borer/borer_chemicals.dm b/code/modules/mob/living/simple_animal/borer/borer_chemicals.dm
new file mode 100644
index 00000000000..c45de465246
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer/borer_chemicals.dm
@@ -0,0 +1,59 @@
+/datum/borer_chem
+ var/chemname
+ var/chem_desc = "This is a chemical"
+ var/chemuse = 30
+ var/quantity = 10
+
+/datum/borer_chem/epinephrine
+ chemname = "epinephrine"
+ chem_desc = "Stabilizes critical condition and slowly restores oxygen damage. If overdosed, it will deal toxin and oxyloss damage."
+
+/datum/borer_chem/leporazine
+ chemname = "leporazine"
+ chem_desc = "This keeps a patient's body temperature stable. High doses can allow short periods of unprotected EVA."
+ chemuse = 75
+
+/datum/borer_chem/mannitol
+ chemname = "mannitol"
+ chem_desc = "Heals brain damage."
+
+/datum/borer_chem/bicaridine
+ chemname = "bicaridine"
+ chem_desc = "Heals brute damage."
+
+/datum/borer_chem/kelotane
+ chemname = "kelotane"
+ chem_desc = "Heals burn damage."
+
+/datum/borer_chem/charcoal
+ chemname = "charcoal"
+ chem_desc = "Slowly heals toxin damage, will also slowly remove any other chemicals."
+
+/datum/borer_chem/methamphetamine
+ chemname = "methamphetamine"
+ chem_desc = "Reduces stun times, increases stamina and run speed while dealing brain damage. If overdosed it will deal toxin and brain damage."
+ chemuse = 50
+ quantity = 9
+
+/datum/borer_chem/salbutamol
+ chemname = "salbutamol"
+ chem_desc = "Heals suffocation damage."
+
+/datum/borer_chem/spacedrugs
+ chemname = "space_drugs"
+ chem_desc = "Get your host high as a kite."
+ chemuse = 75
+
+/*/datum/borer_chem/creagent
+ chemname = "colorful_reagent"
+ chem_desc = "Change the colour of your host."
+ chemuse = 50*/
+
+/datum/borer_chem/ethanol
+ chemname = "ethanol"
+ chem_desc = "The most potent alcoholic 'beverage', with the fastest toxicity."
+ chemuse = 50
+
+/datum/borer_chem/rezadone
+ chemname = "rezadone"
+ chem_desc = "Heals cellular damage."
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/borer/borer_event.dm b/code/modules/mob/living/simple_animal/borer/borer_event.dm
new file mode 100644
index 00000000000..f72a92bfe8e
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer/borer_event.dm
@@ -0,0 +1,49 @@
+/datum/round_event_control/borer
+ name = "Borer"
+ typepath = /datum/round_event/borer
+ weight = 20
+ max_occurrences = 1
+ min_players = 15
+ earliest_start = 12000
+
+/datum/round_event/borer
+ announceWhen = 3000 //Borers get 5 minutes till the crew tries to murder them.
+ var/successSpawn = 0
+
+ var/spawncount = 2
+
+/datum/round_event/borer/setup()
+ spawncount = rand(2, 4)
+
+/datum/round_event/borer/announce()
+ if(successSpawn)
+ priority_announce("Unidentified lifesigns detected coming aboard [station_name()]. Secure any exterior access, including ducting and ventilation.", "Lifesign Alert", 'sound/AI/aliens.ogg') //Borers seem like normal xenomorphs.
+
+
+/datum/round_event/borer/start()
+
+ var/list/vents = list()
+ for(var/obj/machinery/atmospherics/components/unary/vent_pump/temp_vent in machines)
+ if(qdeleted(temp_vent))
+ continue
+ if(temp_vent.loc.z == ZLEVEL_STATION && !temp_vent.welded)
+ var/datum/pipeline/temp_vent_parent = temp_vent.PARENT1
+ if(temp_vent_parent.other_atmosmch.len > 20)
+ vents += temp_vent
+
+ if(!vents.len)
+ message_admins("An event attempted to spawn a borer but no suitable vents were found. Shutting down.")
+ return kill()
+
+ var/total_humans = 0
+ for(var/mob/living/carbon/human/H in mob_list)
+ if(H.stat != DEAD)
+ total_humans++
+
+ total_borer_hosts_needed = round(6 + total_humans/7)
+
+ while(spawncount >= 1 && vents.len)
+ var/obj/vent = pick_n_take(vents)
+ new /mob/living/simple_animal/borer(vent.loc)
+ successSpawn = TRUE
+ spawncount--
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/borer/borer_html.dm b/code/modules/mob/living/simple_animal/borer/borer_html.dm
new file mode 100644
index 00000000000..e2544a1d0b8
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer/borer_html.dm
@@ -0,0 +1,125 @@
+
+/mob/living/simple_animal/borer/proc/get_html_template(content)
+ var/html = {"
+
+
+ Borer Chemicals
+
+
+
+
+
+
+
+
+
+
+
+ [content]
+
+
"}
+ return html
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/borer/borer_topic.dm b/code/modules/mob/living/simple_animal/borer/borer_topic.dm
new file mode 100644
index 00000000000..c9c3c055a7c
--- /dev/null
+++ b/code/modules/mob/living/simple_animal/borer/borer_topic.dm
@@ -0,0 +1,37 @@
+
+/mob/living/simple_animal/borer/Topic(href, href_list, hsrc)
+ if(href_list["borer_use_chem"])
+ locate(href_list["src"])
+ if(!istype(src, /mob/living/simple_animal/borer))
+ return
+
+ var/topic_chem = href_list["borer_use_chem"]
+ var/datum/borer_chem/C
+
+ for(var/datum in typesof(/datum/borer_chem))
+ var/datum/borer_chem/test = new datum()
+ if(test.chemname == topic_chem)
+ C = test
+ break
+
+ if(!istype(C, /datum/borer_chem))
+ return
+
+ if(!C || !victim || controlling || !src || stat)
+ return
+
+ if(!istype(C, /datum/borer_chem))
+ return
+
+ if(chemicals < C.chemuse)
+ src << "You need [C.chemuse] chemicals stored to use this chemical!"
+ return
+
+ src << "You squirt a measure of [C.chemname] from your reservoirs into [victim]'s bloodstream."
+ victim.reagents.add_reagent(C.chemname, C.quantity)
+ chemicals -= C.chemuse
+ log_game("[src]/([src.ckey]) has injected [C.chemname] into their host [victim]/([victim.ckey])")
+
+ src << output(chemicals, "ViewBorer\ref[src]Chems.browser:update_chemicals")
+
+ ..()
\ No newline at end of file
diff --git a/code/modules/surgery/organ_manipulation.dm b/code/modules/surgery/organ_manipulation.dm
index f2ccd41e270..912fab5caa7 100644
--- a/code/modules/surgery/organ_manipulation.dm
+++ b/code/modules/surgery/organ_manipulation.dm
@@ -67,6 +67,11 @@
else if(implement_type in implements_extract)
current_type = "extract"
var/list/organs = target.getorganszone(target_zone)
+ var/mob/living/simple_animal/borer/B = target.has_brain_worms()
+ if(target.has_brain_worms())
+ user.visible_message("[user] begins to extract [B] from [target]'s [parse_zone(target_zone)].",
+ "You begin to extract [B] from [target]'s [parse_zone(target_zone)]...")
+ return TRUE
if(!organs.len)
user << "There is no removeable organs in [target]'s [parse_zone(target_zone)]!"
return -1
@@ -107,6 +112,13 @@
"You insert [tool] into [target]'s [parse_zone(target_zone)].")
else if(current_type == "extract")
+ var/mob/living/simple_animal/borer/B = target.has_brain_worms()
+ if(B && B.victim == target)
+ user.visible_message("[user] successfully extracts [B] from [target]'s [parse_zone(target_zone)]!",
+ "You successfully extract [B] from [target]'s [parse_zone(target_zone)].")
+ add_logs(user, target, "surgically removed [B] from", addition="INTENT: [uppertext(user.a_intent)]")
+ B.leave_victim()
+ return FALSE
if(I && I.owner == target)
user.visible_message("[user] successfully extracts [I] from [target]'s [parse_zone(target_zone)]!",
"You successfully extract [I] from [target]'s [parse_zone(target_zone)].")
diff --git a/code/modules/surgery/remove_embedded_object.dm b/code/modules/surgery/remove_embedded_object.dm
index fa9db1ae8ed..a4b0b67a1a8 100644
--- a/code/modules/surgery/remove_embedded_object.dm
+++ b/code/modules/surgery/remove_embedded_object.dm
@@ -30,7 +30,7 @@
L.embedded_objects -= I
if(objects > 0)
- user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L]!", "You sucessfully remove [objects] objects from [H]'s [L.name].")
+ user.visible_message("[user] sucessfully removes [objects] objects from [H]'s [L]!", "You successfully remove [objects] objects from [H]'s [L.name].")
else
user << "You find no objects embedded in [H]'s [L]!"
diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi
index af6a75e2c6b..7454b654225 100644
Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 84ee80c19f0..7f297a5dd49 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/hud.dmi b/icons/mob/hud.dmi
index be5760d7cf5..105f56cc8ce 100644
Binary files a/icons/mob/hud.dmi and b/icons/mob/hud.dmi differ
diff --git a/interface/stylesheet.dm b/interface/stylesheet.dm
index 797a77653a8..eee280eaf83 100644
--- a/interface/stylesheet.dm
+++ b/interface/stylesheet.dm
@@ -119,6 +119,8 @@ h1.alert, h2.alert {color: #000000;}
.alien {color: #543354;}
.noticealien {color: #00c000;}
.alertalien {color: #00c000; font-weight: bold;}
+.borer {color: #543354; font-style: italic;}
+.changeling {color: #800080; font-style: italic;}
.interface {color: #330033;}
diff --git a/tgstation.dme b/tgstation.dme
index 32702e7dca2..0bbec815afe 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1502,6 +1502,11 @@
#include "code\modules\mob\living\simple_animal\simple_animal.dm"
#include "code\modules\mob\living\simple_animal\spawner.dm"
#include "code\modules\mob\living\simple_animal\status_procs.dm"
+#include "code\modules\mob\living\simple_animal\borer\borer.dm"
+#include "code\modules\mob\living\simple_animal\borer\borer_chemicals.dm"
+#include "code\modules\mob\living\simple_animal\borer\borer_event.dm"
+#include "code\modules\mob\living\simple_animal\borer\borer_html.dm"
+#include "code\modules\mob\living\simple_animal\borer\borer_topic.dm"
#include "code\modules\mob\living\simple_animal\bot\bot.dm"
#include "code\modules\mob\living\simple_animal\bot\cleanbot.dm"
#include "code\modules\mob\living\simple_animal\bot\construction.dm"