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 += "" + + content += "
[C.chemname] ([C.chemuse])

[C.chem_desc]

" + + 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 + + + + + + + +
+

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"