diff --git a/SQL/paradise_schema.sql b/SQL/paradise_schema.sql index ed0845ed33f..6e227b211a5 100644 --- a/SQL/paradise_schema.sql +++ b/SQL/paradise_schema.sql @@ -275,6 +275,7 @@ CREATE TABLE `player` ( `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', `windowflashing` smallint(4) DEFAULT '1', + `ghost_anonsay` tinyint(1) NOT NULL DEFAULT '0', `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) diff --git a/SQL/paradise_schema_prefixed.sql b/SQL/paradise_schema_prefixed.sql index 216082157d4..a7ad598a143 100644 --- a/SQL/paradise_schema_prefixed.sql +++ b/SQL/paradise_schema_prefixed.sql @@ -274,6 +274,7 @@ CREATE TABLE `SS13_player` ( `show_ghostitem_attack` smallint(4) DEFAULT '1', `lastchangelog` varchar(32) NOT NULL DEFAULT '0', `windowflashing` smallint(4) DEFAULT '1', + `ghost_anonsay` tinyint(1) NOT NULL DEFAULT '0', `exp` mediumtext, PRIMARY KEY (`id`), UNIQUE KEY `ckey` (`ckey`) diff --git a/code/__HELPERS/lists.dm b/code/__HELPERS/lists.dm index 9fa27c93356..1cad4d1a9df 100644 --- a/code/__HELPERS/lists.dm +++ b/code/__HELPERS/lists.dm @@ -625,3 +625,15 @@ proc/dd_sortedObjectList(list/incoming) /datum/alarm/dd_SortValue() return "[sanitize(last_name)]" + +//Picks from the list, with some safeties, and returns the "default" arg if it fails +#define DEFAULTPICK(L, default) ((istype(L, /list) && L:len) ? pick(L) : default) + +#define LAZYINITLIST(L) if (!L) L = list() + +#define UNSETEMPTY(L) if (L && !L.len) L = null +#define LAZYREMOVE(L, I) if(L) { L -= I; if(!L.len) { L = null; } } +#define LAZYADD(L, I) if(!L) { L = list(); } L += I; +#define LAZYACCESS(L, I) (L ? (isnum(I) ? (I > 0 && I <= L.len ? L[I] : null) : L[I]) : null) +#define LAZYLEN(L) length(L) +#define LAZYCLEARLIST(L) if(L) L.Cut() diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 46368def984..4c9f57d4e4e 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -161,13 +161,13 @@ for(var/mob/O in viewers(messagesource, null)) if(attack_verb.len) - O.show_message("[M] has been [pick(attack_verb)] with [src][showname] ", 1) + O.show_message("[M] has been [pick(attack_verb)] with [src][showname] ", 1) else - O.show_message("[M] has been attacked with [src][showname] ", 1) + O.show_message("[M] has been attacked with [src][showname] ", 1) if(!showname && user) if(user.client) - to_chat(user, "You attack [M] with [src]. ") + to_chat(user, "You attack [M] with [src]. ") diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index dbd9f92f533..6a73d9108dd 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -135,7 +135,7 @@ proc/get_id_photo(var/mob/living/carbon/human/H) if(H.gender == FEMALE) g = "f" - var/icon/icobase = H.species.icobase + var/icon/icobase = head_organ.icobase //At this point all the organs would have the same icobase, so this is just recycling. preview_icon = new /icon(icobase, "torso_[g]") var/icon/temp @@ -153,8 +153,8 @@ proc/get_id_photo(var/mob/living/carbon/human/H) if(H.body_accessory && istype(H.body_accessory, /datum/body_accessory/tail)) temp = new/icon("icon" = H.body_accessory.icon, "icon_state" = H.body_accessory.icon_state) preview_icon.Blend(temp, ICON_OVERLAY) - else if(H.species.tail && H.species.bodyflags & HAS_TAIL) - temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.species.tail]_s") + else if(H.tail && H.species.bodyflags & HAS_TAIL) + temp = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[H.tail]_s") preview_icon.Blend(temp, ICON_OVERLAY) for(var/obj/item/organ/external/E in H.organs) diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm index acac430399b..2c0956f4fbb 100644 --- a/code/datums/progressbar.dm +++ b/code/datums/progressbar.dm @@ -1,9 +1,12 @@ +#define PROGRESSBAR_HEIGHT 6 + /datum/progressbar var/goal = 1 var/image/bar var/shown = 0 var/mob/user var/client/client + var/listindex /datum/progressbar/New(mob/User, goal_number, atom/target) . = ..() @@ -11,15 +14,21 @@ EXCEPTION("Invalid target given") if(goal_number) goal = goal_number - bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0") + bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0", HUD_LAYER) + bar.plane = HUD_PLANE bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA - bar.pixel_y = 32 user = User if(user) client = user.client + LAZYINITLIST(user.progressbars) + LAZYINITLIST(user.progressbars[bar.loc]) + var/list/bars = user.progressbars[bar.loc] + bars.Add(src) + listindex = bars.len + bar.pixel_y = 32 + (PROGRESSBAR_HEIGHT * (listindex - 1)) + /datum/progressbar/proc/update(progress) -// to_chat(world, "Update [progress] - [goal] - [(progress / goal)] - [((progress / goal) * 100)] - [round(((progress / goal) * 100), 5)]") if(!user || !user.client) shown = 0 return @@ -35,8 +44,24 @@ user.client.images += bar shown = 1 +/datum/progressbar/proc/shiftDown() + --listindex + bar.pixel_y -= PROGRESSBAR_HEIGHT + /datum/progressbar/Destroy() + for(var/I in user.progressbars[bar.loc]) + var/datum/progressbar/P = I + if(P != src && P.listindex > listindex) + P.shiftDown() + + var/list/bars = user.progressbars[bar.loc] + bars.Remove(src) + if(!bars.len) + LAZYREMOVE(user.progressbars, bar.loc) + if(client) client.images -= bar qdel(bar) - . = ..() \ No newline at end of file + . = ..() + +#undef PROGRESSBAR_HEIGHT \ No newline at end of file diff --git a/code/game/data_huds.dm b/code/game/data_huds.dm index 59557caea6a..240c53b0025 100644 --- a/code/game/data_huds.dm +++ b/code/game/data_huds.dm @@ -139,6 +139,7 @@ /mob/living/carbon/proc/med_hud_set_status() var/image/holder = hud_list[STATUS_HUD] //var/image/holder2 = hud_list[STATUS_HUD_OOC] + var/mob/living/simple_animal/borer/B = has_brain_worms() if(stat == 2) holder.icon_state = "huddead" //holder2.icon_state = "huddead" @@ -146,13 +147,8 @@ holder.icon_state = "hudxeno" else if(check_virus()) holder.icon_state = "hudill" - else if(has_brain_worms()) - var/mob/living/simple_animal/borer/B = has_brain_worms() - if(B.controlling) - holder.icon_state = "hudbrainworm" - else - holder.icon_state = "hudhealthy" - //holder2.icon_state = "hudhealthy" + else if(has_brain_worms() && B != null && B.controlling) + holder.icon_state = "hudbrainworm" else holder.icon_state = "hudhealthy" //holder2.icon_state = "hudhealthy" diff --git a/code/game/gamemodes/blob/powers.dm b/code/game/gamemodes/blob/powers.dm index 166f3f590ac..cfd72f71a7e 100644 --- a/code/game/gamemodes/blob/powers.dm +++ b/code/game/gamemodes/blob/powers.dm @@ -333,7 +333,7 @@ if(ticker && ticker.mode.name == "blob") var/datum/game_mode/blob/BL = ticker.mode - BL.blobwincount = initial(BL.blobwincount) * 2 + BL.blobwincount += initial(BL.blobwincount) /mob/camera/blob/verb/blob_broadcast() diff --git a/code/game/gamemodes/changeling/powers/panacea.dm b/code/game/gamemodes/changeling/powers/panacea.dm index dd15a313701..4b8e002d576 100644 --- a/code/game/gamemodes/changeling/powers/panacea.dm +++ b/code/game/gamemodes/changeling/powers/panacea.dm @@ -11,6 +11,16 @@ to_chat(user, "We cleanse impurities from our form.") + var/mob/living/simple_animal/borer/B = user.has_brain_worms() + if(B) + if(B.controlling) + B.detatch() + B.leave_host() + if(iscarbon(user)) + var/mob/living/carbon/C = user + C.vomit(0) + to_chat(user, "We expel a parasite from our form.") + var/obj/item/organ/internal/body_egg/egg = user.get_int_organ(/obj/item/organ/internal/body_egg) if(egg) egg.remove(user) diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index 56c52797c0d..075e0e7a09b 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -4,33 +4,33 @@ /mob/living/captive_brain/say(var/message) - if(src.client) + if(client) if(client.prefs.muted & MUTE_IC) to_chat(src, "\red You cannot speak in IC (muted).") return - if(src.client.handle_spam_prevention(message,MUTE_IC)) + if(client.handle_spam_prevention(message,MUTE_IC)) return - if(istype(src.loc,/mob/living/simple_animal/borer)) + if(istype(loc,/mob/living/simple_animal/borer)) message = trim(sanitize(copytext(message, 1, MAX_MESSAGE_LEN))) if(!message) return log_say("[key_name(src)] : [message]") if(stat == DEAD) return say_dead(message) - var/mob/living/simple_animal/borer/B = src.loc + var/mob/living/simple_animal/borer/B = loc to_chat(src, "You whisper silently, \"[message]\"") - to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") + to_chat(B.host, "The captive mind of [src] whispers, \"[message]\"") for(var/mob/M in mob_list) - if(M.mind && (istype(M, /mob/dead/observer))) + if(M.mind && isobserver(M)) to_chat(M, "Thought-speech, [src] -> [B.truename]: [message]") /mob/living/captive_brain/say_understands(var/mob/other, var/datum/language/speaking = null) - var/mob/living/simple_animal/borer/B = src.loc + var/mob/living/simple_animal/borer/B = loc if(!istype(B)) log_runtime(EXCEPTION("Trapped mind found without a borer!"), src) - return 0 + return FALSE return B.host.say_understands(other, speaking) /mob/living/captive_brain/emote(var/message) @@ -42,20 +42,18 @@ to_chat(src, "You begin doggedly resisting the parasite's control (this will take approximately sixty seconds).") to_chat(B.host, "You feel the captive mind of [src] begin to resist your control.") - spawn(rand(350,450) + B.host.brainloss) + var/delay = (rand(350,450) + B.host.brainloss) + addtimer(src, "return_control", delay) - if(!B || !B.controlling) - return +/mob/living/captive_brain/proc/return_control(mob/living/simple_animal/borer/B) + if(!B || !B.controlling) + return - B.host.adjustBrainLoss(rand(5,10)) - to_chat(src, "With an immense exertion of will, you regain control of your body!") - to_chat(B.host, "You feel control of the host brain ripped from your grasp, and retract your probosci before the wild neural impulses can damage you.") + B.host.adjustBrainLoss(rand(5,10)) + to_chat(src, "With an immense exertion of will, you regain control of your body!") + to_chat(B.host, "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() - - verbs -= /mob/living/carbon/proc/release_control - verbs -= /mob/living/carbon/proc/punish_host - verbs -= /mob/living/carbon/proc/spawn_larvae + B.detatch() /mob/living/simple_animal/borer name = "cortical borer" @@ -78,20 +76,83 @@ wander = 0 mob_size = MOB_SIZE_TINY density = 0 - pass_flags = PASSTABLE + 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) - - var/talk_inside_host = 0 // So that borers don't accidentally give themselves away on a botched message + 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/talk_inside_host = FALSE // So that borers don't accidentally give themselves away on a botched message var/used_dominate - var/chemicals = 10 // Chemicals used for reproduction and chemical injection. - var/max_chems = 250 // How many chemicals that can be stored in total - var/mob/living/carbon/human/host // Human host for the brain worm. - var/truename // Name used for brainworm-speak. - var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. - var/controlling // Used in human death check. - var/docile = 0 // Sugar can stop borers from acting. - var/list/borer_injection_chems = list("mannitol","salglu_solution","methamphetamine", "hydrocodone", "spaceacillin", "mitocholide", "charcoal", "salbutamol", "capulettium_plus") + var/chemicals = 10 // Chemicals used for reproduction and chemical injection. + var/max_chems = 250 + var/mob/living/carbon/human/host // Human host for the brain worm. + var/truename // Name used for brainworm-speak. + var/mob/living/captive_brain/host_brain // Used for swapping control of the body back and forth. + var/controlling // Used in human death check. + var/docile = FALSE // Sugar can stop borers from acting. + var/bonding = FALSE + 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/torment/torment_action = new + +/mob/living/simple_animal/borer/New(atom/newloc, var/gen=1) + ..(newloc) + generation = gen + add_language("Cortical Link") + 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)]" + GrantBorerActions() + +/mob/living/simple_animal/borer/attack_ghost(mob/user) + if(jobban_isbanned(user, "Syndicate")) + return + if(key) + return + if(stat != CONSCIOUS) + return + var/be_borer = alert("Become a cortical borer? (Warning, You can no longer be cloned!)",,"Yes","No") + if(be_borer == "No" || !src || qdeleted(src)) + return + if(key) + return + transfer_personality(user.client) + +/mob/living/simple_animal/borer/Stat() + ..() + statpanel("Status") + + show_stat_emergency_shuttle_eta() + + if(client.statpanel == "Status") + stat("Chemicals", chemicals) + +/mob/living/simple_animal/borer/say(message) + var/datum/language/dialect = parse_language(message) + if(!dialect) + dialect = get_default_language() + if(!istype(dialect, /datum/language/corticalborer) && loc == host && !talk_inside_host) + to_chat(src, "You've disabled audible speech while inside a host! Re-enable it under the borer tab, or stick to borer communications.") + return + ..() /mob/living/simple_animal/borer/verb/Communicate() set category = "Borer" @@ -107,18 +168,20 @@ return var/input = stripped_input(src, "Please enter a message to tell your host.", "Borer", "") - if(!input) return + if(!input) + return - - var/say_string = (docile) ? "slurs" :"states" - if(host) - to_chat(host, "[src.truename] [say_string]: [input]") - log_say("Borer Communication: [key_name(src)] -> [key_name(host)] : [input]") - for(var/M in dead_mob_list) - if(istype(M, /mob/dead/observer)) - to_chat(M, "Borer Communication from [src.truename] ([ghost_follow_link(src, ghost=M)]): [input]") - to_chat(src, "[src.truename] [say_string]: [input]") - host.verbs += /mob/living/proc/borer_comm + if(src && !qdeleted(src) && !qdeleted(host)) + var/say_string = (docile) ? "slurs" :"states" + if(host) + to_chat(host, "[truename] [say_string]: [input]") + log_say("Borer Communication: [key_name(src)] -> [key_name(host)] : [input]") + for(var/M in dead_mob_list) + if(isobserver(M)) + to_chat(M, "Borer Communication from [truename] ([ghost_follow_link(src, ghost=M)]): [input]") + to_chat(src, "[truename] [say_string]: [input]") + host.verbs += /mob/living/proc/borer_comm + talk_to_borer_action.Grant(host) /mob/living/simple_animal/borer/verb/toggle_silence_inside_host() set name = "Toggle speech inside Host" @@ -126,10 +189,10 @@ set desc = "Toggle whether you will be able to say audible messages while inside your host." if(talk_inside_host) - talk_inside_host = 0 + talk_inside_host = FALSE to_chat(src, "You will no longer talk audibly while inside a host.") else - talk_inside_host = 1 + talk_inside_host = TRUE to_chat(src, "You will now be able to audibly speak from inside of a host.") /mob/living/proc/borer_comm() @@ -138,18 +201,19 @@ set desc = "Communicate mentally with your borer." - var/mob/living/simple_animal/borer/B = src.has_brain_worms() + 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", "") - if(!input) return + if(!input) + return to_chat(B, "[src] says: [input]") log_say("Borer Communication: [key_name(src)] -> [key_name(B)] : [input]") for(var/M in dead_mob_list) - if(istype(M, /mob/dead/observer)) + if(isobserver(M)) to_chat(M, "Borer Communication from [src] ([ghost_follow_link(src, ghost=M)]): [input]") to_chat(src, "[src] says: [input]") @@ -159,18 +223,19 @@ set desc = "Communicate mentally with the trapped mind of your host." - var/mob/living/simple_animal/borer/B = src.has_brain_worms() + 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", "") - if(!input) return + if(!input) + return to_chat(CB, "[B.truename] says: [input]") log_say("Borer Communication: [key_name(B)] -> [key_name(CB)] : [input]") for(var/M in dead_mob_list) - if(istype(M, /mob/dead/observer)) + if(isobserver(M)) to_chat(M, "Borer Communication from [B] ([ghost_follow_link(src, ghost=M)]): [input]") to_chat(src, "[B.truename] says: [input]") @@ -188,14 +253,14 @@ to_chat(host, "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility.") else to_chat(src, "\blue You feel the soporific flow of sugar in your host's blood, lulling you into docility.") - docile = 1 + docile = TRUE else if(docile) if(controlling) to_chat(host, "\blue You shake off your lethargy as the sugar leaves your host's blood.") else to_chat(src, "\blue You shake off your lethargy as the sugar leaves your host's blood.") - docile = 0 + docile = FALSE if(chemicals < max_chems) chemicals++ @@ -218,36 +283,190 @@ else return ..() -/mob/living/simple_animal/borer/New(var/by_gamemode=0) +/mob/living/simple_animal/borer/UnarmedAttack(mob/living/M) + chemscan(usr, M) + return + +/mob/living/simple_animal/borer/verb/infest() + set category = "Borer" + set name = "Infest" + set desc = "Infest a suitable humanoid host." + + if(host) + to_chat(src, "You are already within a host.") + return + + if(stat) + to_chat(src, "You cannot infest a target in your current state.") + return + + var/list/choices = list() + for(var/mob/living/carbon/human/H in view(1,src)) + var/obj/item/organ/external/head/head = H.get_organ("head") + if(head.status & ORGAN_ROBOT) + continue + if(H.stat != DEAD && Adjacent(H) && !H.has_brain_worms()) + choices += H + + var/mob/living/carbon/human/M = input(src,"Who do you wish to infest?") in null|choices + + if(!M || !src) + return + + if(!Adjacent(M)) + return + + if(M.has_brain_worms()) + to_chat(src, "You cannot infest someone who is already infested!") + return + + to_chat(src, "You slither up [M] and begin probing at their ear canal...") + + if(!do_after(src,50, target = M)) + to_chat(src, "As [M] moves away, you are dislodged and fall to the ground.") + return + + if(!M || !src) + return + + if(stat) + to_chat(src, "You cannot infest a target in your current state.") + return + + if(M.stat == DEAD) + to_chat(src, "That is not an appropriate target.") + return + + if(M in view(1, src)) + to_chat(src, "You wiggle into [M]'s ear.") + /* + if(!M.stat) + to_chat(M, "Something disgusting and slimy wiggles into your ear!") + */ // Let's see how stealthborers work out + + perform_infestation(M) + + return + else + to_chat(src, "They are no longer in range!") + return + +/mob/living/simple_animal/borer/proc/perform_infestation(var/mob/living/carbon/M) + if(!M) + return + + if(M.has_brain_worms()) + to_chat(src, "[M] is already infested!") + return + host = M + forceMove(M) + + if(ishuman(M)) + var/mob/living/carbon/human/H = M + var/obj/item/organ/external/head = H.get_organ("head") + head.implants += src + + host.status_flags |= PASSEMOTES + + RemoveBorerActions() + GrantInfestActions() + +/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(!host) + to_chat(src, "You are not inside a host body.") + return + + if(stat) + to_chat(src, "You cannot secrete chemicals in your current state.") + + if(docile) + to_chat(src, " You are feeling far too docile to do that.") + return + + var content = "" + + content += "" + + for(var/datum in typesof(/datum/borer_chem)) + var/datum/borer_chem/C = new datum() + var/datum/reagent/R = chemical_reagents_list[C.chemname] + if(C.chemname) + content += "" + + content += "
[R.name] ([C.chemuse])

[C.chemdesc]

" + + var/html = get_html_template(content) + + usr << browse(null, "window=ViewBorer[UID()]Chems;size=585x400") + usr << browse(html, "window=ViewBorer[UID()]Chems;size=585x400") + + return + +/mob/living/simple_animal/borer/Topic(href, href_list, hsrc) + if(href_list["ghostjoin"]) + var/mob/dead/observer/ghost = usr + if(istype(ghost)) + attack_ghost(ghost) + 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 + + var/datum/reagent/R = chemical_reagents_list[C.chemname] + if(!istype(C, /datum/borer_chem)) + return + if(!C || !host || controlling || !src || stat) + return + if(chemicals < C.chemuse) + to_chat(src, "You need [C.chemuse] chemicals stored to secrete [R.name]!") + return + + to_chat(src, "You squirt a measure of [R.name] from your reservoirs into [host]'s bloodstream.") + host.reagents.add_reagent(C.chemname, C.quantity) + chemicals -= C.chemuse + log_game("[src]/([src.ckey]) has injected [R.name] into their host [host]/([host.ckey])") + ..() - add_language("Cortical Link") - updatename() - if(!by_gamemode) - request_player() +/mob/living/simple_animal/borer/verb/hide_borer() + set category = "Borer" + set name = "Hide" + set desc = "Become invisible to the common eye." -/mob/living/simple_animal/borer/proc/updatename() - var/index_num = rand(1000,9999) - real_name = "Cortical Borer ([index_num])" - truename = "[pick("Primary","Secondary","Tertiary","Quaternary")] [index_num]" + if(host) + to_chat(usr, "You cannot do this while you're inside a host.") -/mob/living/simple_animal/borer/Stat() - ..() - statpanel("Status") + if(stat != CONSCIOUS) + return - show_stat_emergency_shuttle_eta() - - if(client.statpanel == "Status") - stat("Chemicals", chemicals) - -// VERBS! + if(!hiding) + layer = TURF_LAYER+0.2 + to_chat(src, "\green You are now hiding.") + hiding = TRUE + else + layer = MOB_LAYER + to_chat(src, "\green You stop hiding.") + hiding = FALSE /mob/living/simple_animal/borer/verb/dominate_victim() set category = "Borer" set name = "Dominate Victim" set desc = "Freeze the limbs of a potential host with supernatural fear." - if(world.time - used_dominate < 300) + if(world.time - used_dominate < 150) to_chat(src, "You cannot use that ability again so soon.") return @@ -255,7 +474,7 @@ to_chat(src, "You cannot do that from within a host body.") return - if(src.stat) + if(stat) to_chat(src, "You cannot do that in your current state.") return @@ -270,10 +489,11 @@ var/mob/living/carbon/M = input(src,"Who do you wish to dominate?") in null|choices - if(!M || !src) return + if(!M || !src) + return if(M.has_brain_worms()) - to_chat(src, "You cannot infest someone who is already infested!") + to_chat(src, "You cannot dominate someone who is already infested!") return to_chat(src, "\red You focus your psychic lance on [M] and freeze their limbs with a wave of terrible dread.") @@ -282,125 +502,6 @@ used_dominate = world.time -/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(!host) - to_chat(src, "You are not inside a host body.") - return - - if(host.stat == DEAD) - to_chat(src, "This host is in no condition to be controlled.") - return - - if(src.stat) - to_chat(src, "You cannot do that in your current state.") - return - - if(docile) - to_chat(src, "\blue You are feeling far too docile to do that.") - return - - to_chat(src, "You begin delicately adjusting your connection to the host brain...") - - spawn(300+(host.getBrainLoss()*5)) - - if(!host || !src || controlling) - return - else - to_chat(src, "You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.") - to_chat(host, "You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.") - var/borer_key = src.key - host.create_attack_log("[key_name(src)] has assumed control of [key_name(host)]") - msg_admin_attack("[key_name_admin(src)] has assumed control of [key_name_admin(host)]") - // host -> brain - var/h2b_id = host.computer_id - var/h2b_ip= host.lastKnownIP - host.computer_id = null - host.lastKnownIP = null - - qdel(host_brain) - host_brain = new(src) - - host_brain.ckey = host.ckey - - host_brain.name = host.name - - if(!host_brain.computer_id) - host_brain.computer_id = h2b_id - - if(!host_brain.lastKnownIP) - host_brain.lastKnownIP = h2b_ip - - // self -> host - var/s2h_id = src.computer_id - var/s2h_ip= src.lastKnownIP - src.computer_id = null - src.lastKnownIP = null - - host.ckey = src.ckey - - if(!host.computer_id) - host.computer_id = s2h_id - - if(!host.lastKnownIP) - host.lastKnownIP = s2h_ip - - controlling = 1 - - host.verbs += /mob/living/carbon/proc/release_control - host.verbs += /mob/living/carbon/proc/punish_host - host.verbs += /mob/living/carbon/proc/spawn_larvae - host.verbs -= /mob/living/proc/borer_comm - host.verbs += /mob/living/proc/trapped_mind_comm - - if(src && !src.key) - src.key = "@[borer_key]" - return - -/mob/living/simple_animal/borer/verb/secrete_chemicals() - set category = "Borer" - set name = "Secrete Chemicals (30)" - set desc = "Push some chemicals into your host's bloodstream." - - var/injection_amount = 9 - var/chem_cost = 30 - if(!host) - to_chat(src, "You are not inside a host body.") - return - - if(stat) - to_chat(src, "You cannot secrete chemicals in your current state.") - - if(docile) - to_chat(src, "\blue You are feeling far too docile to do that.") - return - - if(chemicals < chem_cost) - to_chat(src, "You don't have enough chemicals!") - - var/list/nice_name_chem_list = list() - for(var/rgnt in borer_injection_chems) - var/datum/reagent/R2 = chemical_reagents_list[rgnt] - nice_name_chem_list[R2.name] = rgnt - var/chem_name = input("Select a chemical to secrete.", "Chemicals") as null|anything in nice_name_chem_list - var/chem = nice_name_chem_list[chem_name] - - if(!chem || chemicals < chem_cost || !host || controlling || !src || stat) //Sanity check. - return - - var/chem_amount = host.reagents.get_reagent_amount(chem) - var/datum/reagent/R = chemical_reagents_list[chem] - if(R.overdose_threshold && chem_amount + injection_amount > R.overdose_threshold) - to_chat(src, "Doing so would cause grievous harm to your host, reducing ability to reproduce. Aborting.") - return - - to_chat(src, "You squirt a measure of [chem_name] from your reservoirs into [host]'s bloodstream.") - host.reagents.add_reagent(chem, injection_amount) - chemicals -= chem_cost - /mob/living/simple_animal/borer/verb/release_host() set category = "Borer" set name = "Release Host" @@ -418,34 +519,235 @@ to_chat(src, "\blue You are feeling far too docile to do that.") return - if(!host || !src) return + if(!host || !src) + return + + if(leaving) + leaving = FALSE + to_chat(src, "You decide against leaving your host.") + return to_chat(src, "You begin disconnecting from [host]'s synapses and prodding at their internal ear canal.") - spawn(200) + leaving = TRUE - if(!host || !src) return + addtimer(src, "let_go", 200) - if(src.stat) - to_chat(src, "You cannot release a target in your current state.") - return +/mob/living/simple_animal/borer/proc/let_go() - to_chat(src, "You wiggle out of [host]'s ear and plop to the ground.") + if(!host || !src || qdeleted(host) || qdeleted(src)) + return + if(!leaving) + return + if(controlling) + return + if(stat) + to_chat(src, "You cannot release a target in your current state.") + return + to_chat(src, "You wiggle out of [host]'s ear and plop to the ground.") + + leaving = FALSE + leave_host() + +/mob/living/simple_animal/borer/proc/leave_host() + + if(!host) + return + if(controlling) detatch() - leave_host() + GrantBorerActions() + RemoveInfestActions() + forceMove(get_turf(host)) + + reset_perspective(null) + machine = null + + host.reset_perspective(null) + host.machine = null + + var/mob/living/H = host + H.verbs -= /mob/living/proc/borer_comm + talk_to_borer_action.Remove(host) + H.status_flags &= ~PASSEMOTES + host = null + return + +/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(!host) + to_chat(src, "You are not inside a host body.") + return + + if(host.stat == DEAD) + to_chat(src, "This host is in no condition to be controlled.") + return + + if(stat) + to_chat(src, "You cannot do that in your current state.") + return + + if(docile) + to_chat(src, "\blue You are feeling far too docile to do that.") + return + + if(bonding) + bonding = FALSE + to_chat(src, "You stop attempting to take control of your host.") + return + + to_chat(src, "You begin delicately adjusting your connection to the host brain...") + + if(qdeleted(src) || qdeleted(host)) + return + + bonding = TRUE + + var/delay = 300+(host.getBrainLoss()*5) + addtimer(src, "assume_control", delay) + +/mob/living/simple_animal/borer/proc/assume_control() + if(!host || !src || controlling) + return + if(!bonding) + return + if(docile) + to_chat(src,"You are feeling far too docile to do that.") + return + else + to_chat(src, "You plunge your probosci deep into the cortex of the host brain, interfacing directly with their nervous system.") + to_chat(host, "You feel a strange shifting sensation behind your eyes as an alien consciousness displaces yours.") + var/borer_key = src.key + host.create_attack_log("[key_name(src)] has assumed control of [key_name(host)]") + msg_admin_attack("[key_name_admin(src)] has assumed control of [key_name_admin(host)]") + // host -> brain + var/h2b_id = host.computer_id + var/h2b_ip= host.lastKnownIP + host.computer_id = null + host.lastKnownIP = null + + qdel(host_brain) + host_brain = new(src) + + host_brain.ckey = host.ckey + + host_brain.name = host.name + + if(!host_brain.computer_id) + host_brain.computer_id = h2b_id + + if(!host_brain.lastKnownIP) + host_brain.lastKnownIP = h2b_ip + + // self -> host + var/s2h_id = src.computer_id + var/s2h_ip= src.lastKnownIP + src.computer_id = null + src.lastKnownIP = null + + host.ckey = src.ckey + + if(!host.computer_id) + host.computer_id = s2h_id + + if(!host.lastKnownIP) + host.lastKnownIP = s2h_ip + + bonding = FALSE + controlling = TRUE + + host.verbs += /mob/living/carbon/proc/release_control + host.verbs += /mob/living/carbon/proc/punish_host + host.verbs += /mob/living/carbon/proc/spawn_larvae + host.verbs -= /mob/living/proc/borer_comm + host.verbs += /mob/living/proc/trapped_mind_comm + + GrantControlActions() + talk_to_borer_action.Remove(host) + host.med_hud_set_status() + + if(src && !src.key) + src.key = "@[borer_key]" + return + +/mob/living/carbon/proc/punish_host() + set category = "Borer" + set name = "Torment Host" + set desc = "Punish your host with agony." + + var/mob/living/simple_animal/borer/B = has_brain_worms() + + if(!B) + return + + if(B.host_brain) + to_chat(src, "You send a punishing spike of psychic agony lancing into your host's brain.") + to_chat(B.host_brain, "Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!") + +//Brain slug proc for voluntary removal of control. +/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) + to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]") + + B.detatch() + + else + to_chat(src, "ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !") + +//Check for brain worms in head. +/mob/proc/has_brain_worms() + + for(var/I in contents) + if(istype(I,/mob/living/simple_animal/borer)) + 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(!B) + return + + if(B.chemicals >= 100) + to_chat(src, "Your host twitches and quivers as you rapdly excrete several larvae from your sluglike body.") + 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) + + else + to_chat(src, "You need 100 chemicals to reproduce!") + return /mob/living/simple_animal/borer/proc/detatch() - if(!host) return + if(!host || !controlling) + return - if(istype(host,/mob/living/carbon/human)) + controlling = FALSE + + if(ishuman(host)) var/mob/living/carbon/human/H = host var/obj/item/organ/external/head = H.get_organ("head") head.implants -= src - controlling = 0 - reset_perspective(null) machine = null @@ -455,10 +757,13 @@ host.verbs += /mob/living/proc/borer_comm host.verbs -= /mob/living/proc/trapped_mind_comm + RemoveControlActions() + talk_to_borer_action.Grant(host) + host.med_hud_set_status() if(host_brain) - host.create_attack_log("[host_brain.name] ([host_brain.ckey]) has taken control back from [src.name] ([host.ckey])") - msg_admin_attack("[host_brain.name] ([host_brain.ckey]) has taken control back from [src.name] ([host.ckey]) (JMP)") + host.create_attack_log("[host_brain.name] ([host_brain.ckey]) has taken control back from [name] ([host.ckey])") + msg_admin_attack("[host_brain.name] ([host_brain.ckey]) has taken control back from [name] ([host.ckey]) (JMP)") // host -> self var/h2s_id = host.computer_id var/h2s_ip= host.lastKnownIP @@ -491,213 +796,179 @@ return - -//Brain slug proc for voluntary removal of control. -/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) - to_chat(src, "You withdraw your probosci, releasing control of [B.host_brain]") - - B.detatch() - - else - to_chat(src, "ERROR NO BORER OR BRAINMOB DETECTED IN THIS MOB, THIS IS A BUG !") - -//Brain slug proc for tormenting the host. -/mob/living/carbon/proc/punish_host() - set category = "Borer" - set name = "Torment host" - set desc = "Punish your host with agony." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) - return - - if(B.host_brain.ckey) - to_chat(src, "You send a punishing spike of psychic agony lancing into your host's brain.") - to_chat(B.host_brain, "Horrific, burning agony lances through you, ripping a soundless scream from your trapped mind!") - -//Check for brain worms in head. -/mob/proc/has_brain_worms() - - for(var/I in contents) - if(istype(I,/mob/living/simple_animal/borer)) - return I - - return 0 - -/mob/living/carbon/proc/spawn_larvae() - set category = "Borer" - set name = "Reproduce (100)" - set desc = "Spawn several young." - - var/mob/living/simple_animal/borer/B = has_brain_worms() - - if(!B) - return - - if(B.chemicals >= 100) - to_chat(src, "Your host twitches and quivers as you rapdly excrete several larvae from your sluglike body.") - 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)) - - else - to_chat(src, "You do not have enough chemicals stored to reproduce.") - return - -/mob/living/simple_animal/borer/proc/leave_host() - - if(!host) return - - src.forceMove(get_turf(host)) - - reset_perspective(null) - machine = null - - host.reset_perspective(null) - host.machine = null - - var/mob/living/H = host - H.verbs -= /mob/living/proc/borer_comm - H.status_flags &= ~PASSEMOTES - host = null - return - -/mob/living/simple_animal/borer/verb/infest() - set category = "Borer" - set name = "Infest" - set desc = "Infest a suitable humanoid host." - - if(host) - to_chat(src, "You are already within a host.") - return - - if(stat) - to_chat(src, "You cannot infest a target in your current state.") - return - - var/list/choices = list() - for(var/mob/living/carbon/human/H in view(1,src)) - var/obj/item/organ/external/head/head = H.get_organ("head") - if(head.status & ORGAN_ROBOT) - continue - if(H.stat != DEAD && src.Adjacent(H) && !H.has_brain_worms()) - choices += H - - var/mob/living/carbon/human/M = input(src,"Who do you wish to infest?") in null|choices - - if(!M || !src) return - - if(!(src.Adjacent(M))) return - - if(M.has_brain_worms()) - to_chat(src, "You cannot infest someone who is already infested!") - return - - to_chat(src, "You slither up [M] and begin probing at their ear canal...") - - if(!do_after(src,50, target = M)) - to_chat(src, "As [M] moves away, you are dislodged and fall to the ground.") - return - - if(!M || !src) return - - if(src.stat) - to_chat(src, "You cannot infest a target in your current state.") - return - - if(M.stat == DEAD) - to_chat(src, "That is not an appropriate target.") - return - - if(M in view(1, src)) - to_chat(src, "You wiggle into [M]'s ear.") - /* - if(!M.stat) - to_chat(M, "Something disgusting and slimy wiggles into your ear!") - */ // Let's see how stealthborers work out - - perform_infestation(M) - - return - else - to_chat(src, "They are no longer in range!") - return - -/mob/living/simple_animal/borer/proc/perform_infestation(var/mob/living/carbon/M) - src.host = M - src.forceMove(M) - - if(istype(M,/mob/living/carbon/human)) - var/mob/living/carbon/human/H = M - var/obj/item/organ/external/head = H.get_organ("head") - head.implants += src - - host.status_flags |= PASSEMOTES - /mob/living/simple_animal/borer/can_use_vents() return -//Procs for grabbing players. -/mob/living/simple_animal/borer/proc/request_player() - for(var/mob/O in respawnable_list) - if(jobban_isbanned(O, "Syndicate")) - continue - if(O.client) - if((ROLE_BORER in O.client.prefs.be_special) && !jobban_isbanned(O, ROLE_BORER)) - question(O.client) - -/mob/living/simple_animal/borer/proc/question(var/client/C) - spawn(0) - if(!C) return - var/response = alert(C, "A cortical borer needs a player. Are you interested?", "Cortical borer request", "Yes", "No", "Never for this round") - if(!C || ckey) - return - if(response == "Yes") - transfer_personality(C) - else if(response == "Never for this round") - C.prefs.be_special -= ROLE_BORER - /mob/living/simple_animal/borer/proc/transfer_personality(var/client/candidate) - if(!candidate) + if(!candidate || !candidate.mob) return - src.key = candidate.key - if(src.mind) - src.mind.assigned_role = "Cortical Borer" + 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 + to_chat(src, "You are a cortical borer!") + to_chat(src, "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.") + to_chat(src, "Sugar nullifies your abilities, avoid it at all costs!") + to_chat(src, "You can speak to your fellow borers by prefixing your messages with ':x'. Check out your Borer tab to see your abilities.") -/mob/living/simple_animal/borer/verb/borerhide() - set category = "Borer" - set name = "Hide" - set desc = "Allows to hide beneath tables or certain items. Toggled on or off." +/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 - if(stat != CONSCIOUS) - return +/mob/living/simple_animal/borer/proc/GrantBorerActions() + infest_host_action.Grant(src) + toggle_hide_action.Grant(src) + freeze_victim_action.Grant(src) - if(layer != TURF_LAYER+0.2) - layer = TURF_LAYER+0.2 - to_chat(src, "\green You are now hiding.") - else - layer = MOB_LAYER - to_chat(src, "\green You have stopped hiding.") +/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/say(var/message) - var/datum/language/dialect = parse_language(message) - if(!dialect) - dialect = get_default_language() - if(!istype(dialect, /datum/language/corticalborer) && loc == host && !talk_inside_host) - to_chat(src, "You've disabled audible speech while inside a host! Re-enable it under the borer tab, or stick to borer communications.") - return - ..() +/mob/living/simple_animal/borer/proc/GrantInfestActions() + talk_to_host_action.Grant(src) + leave_body_action.Grant(src) + take_control_action.Grant(src) + make_chems_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) + make_chems_action.Remove(src) + +/mob/living/simple_animal/borer/proc/GrantControlActions() + talk_to_brain_action.Grant(host) + give_back_control_action.Grant(host) + make_larvae_action.Grant(host) + torment_action.Grant(host) + +/mob/living/simple_animal/borer/proc/RemoveControlActions() + talk_to_brain_action.Remove(host) + make_larvae_action.Remove(host) + give_back_control_action.Remove(host) + torment_action.Remove(host) + +/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.infest() + +/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_borer() + 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.host = owner + B.host.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.host = owner + B.host.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.host = owner + B.host.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_host() + +/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.host = owner + B.host.spawn_larvae() + +/datum/action/innate/borer/freeze_victim + name = "Dominate Victim" + desc = "Freeze the limbs of a potential host with supernatural fear." + button_icon_state = "genetic_cryo" + +/datum/action/innate/borer/freeze_victim/Activate() + var/mob/living/simple_animal/borer/B = owner + B.dominate_victim() + +/datum/action/innate/borer/torment + name = "Torment Host" + desc = "Punish your host with agony." + button_icon_state = "blind" + +/datum/action/innate/borer/torment/Activate() + var/mob/living/simple_animal/borer/B = owner.has_brain_worms() + B.host = owner + B.host.punish_host() diff --git a/code/game/gamemodes/miniantags/borer/borer_chemicals.dm b/code/game/gamemodes/miniantags/borer/borer_chemicals.dm new file mode 100644 index 00000000000..4176ca15e73 --- /dev/null +++ b/code/game/gamemodes/miniantags/borer/borer_chemicals.dm @@ -0,0 +1,51 @@ +/datum/borer_chem + var/chemname + var/chemdesc = "This is a chemical" + var/chemuse = 30 + var/quantity = 10 + +/datum/borer_chem/capulettium_plus + chemname = "capulettium_plus" + chemdesc = "Silences and masks pulse." + +/datum/borer_chem/charcoal + chemname = "charcoal" + chemdesc = "Slowly heals toxin damage, also slowly removes other chemicals." + +/datum/borer_chem/epinephrine + chemname = "epinephrine" + chemdesc = "Stabilizes critical condition and slowly heals suffocation damage." + +/datum/borer_chem/fliptonium + chemname = "fliptonium" + chemdesc = "Causes uncontrollable flipping." + chemuse = 50 + +/datum/borer_chem/hydrocodone + chemname = "hydrocodone" + chemdesc = "An extremely strong painkiller." + +/datum/borer_chem/mannitol + chemname = "mannitol" + chemdesc = "Heals brain damage." + +/datum/borer_chem/methamphetamine + chemname = "methamphetamine" + chemdesc = "Reduces stun times and increases stamina. Deals small amounts of brain damage." + chemuse = 50 + +/datum/borer_chem/mitocholide + chemname = "mitocholide" + chemdesc = "Heals internal organ damage." + +/datum/borer_chem/salbutamol + chemname = "salbutamol" + chemdesc = "Heals suffocation damage." + +/datum/borer_chem/salglu_solution + chemname = "salglu_solution" + chemdesc = "Slowly heals brute and burn damage, also slowly restores blood." + +/datum/borer_chem/spaceacillin + chemname = "spaceacillin" + chemdesc = "Slows progression of diseases and fights infections." diff --git a/code/game/gamemodes/miniantags/borer/borer_event.dm b/code/game/gamemodes/miniantags/borer/borer_event.dm index b0df1749403..f925a59d9fc 100644 --- a/code/game/gamemodes/miniantags/borer/borer_event.dm +++ b/code/game/gamemodes/miniantags/borer/borer_event.dm @@ -4,11 +4,11 @@ announceWhen = 400 var/spawncount = 5 - var/successSpawn = 0 //So we don't make a command report if nothing gets spawned. + var/successSpawn = FALSE //So we don't make a command report if nothing gets spawned. /datum/event/borer_infestation/setup() announceWhen = rand(announceWhen, announceWhen + 50) - spawncount = rand(1, 3) + spawncount = rand(2, 3) /datum/event/borer_infestation/announce() if(successSpawn) @@ -22,14 +22,8 @@ if(temp_vent.parent.other_atmosmch.len > 50) vents += temp_vent - spawn(0) - var/list/candidates = pollCandidates("Do you want to play as a cortical borer?", ROLE_BORER, 1) - while(spawncount > 0 && vents.len && candidates.len) - var/obj/vent = pick_n_take(vents) - var/mob/C = pick_n_take(candidates) - - var/mob/living/simple_animal/borer/new_borer = new(vent.loc) - new_borer.key = C.key - - spawncount-- - successSpawn = 1 + while(spawncount >= 1 && vents.len) + var/obj/vent = pick_n_take(vents) + new /mob/living/simple_animal/borer(vent.loc) + successSpawn = TRUE + spawncount-- diff --git a/code/game/gamemodes/miniantags/borer/borer_html.dm b/code/game/gamemodes/miniantags/borer/borer_html.dm new file mode 100644 index 00000000000..415438884e9 --- /dev/null +++ b/code/game/gamemodes/miniantags/borer/borer_html.dm @@ -0,0 +1,69 @@ +/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/game/gamemodes/wizard/soulstone.dm b/code/game/gamemodes/wizard/soulstone.dm index 5a2d4ebb411..733c19bc337 100644 --- a/code/game/gamemodes/wizard/soulstone.dm +++ b/code/game/gamemodes/wizard/soulstone.dm @@ -8,7 +8,7 @@ slot_flags = SLOT_BELT origin_tech = "bluespace=4;materials=4" var/imprinted = "empty" - + var/usability = TRUE // Can this soul stone be used by anyone, or only cultists/wizards? var/reusable = TRUE // Can this soul stone be used more than once? var/spent = FALSE // If the soul stone can only be used once, has it been used? @@ -18,7 +18,7 @@ return TRUE return FALSE - + /obj/item/device/soulstone/proc/was_used() if(!reusable) spent = TRUE @@ -26,21 +26,21 @@ desc = "A fragment of the legendary treasure known simply as \ the 'Soul Stone'. The shard lies still, dull and lifeless; \ whatever spark it once held long extinguished." - + /obj/item/device/soulstone/anybody usability = TRUE /obj/item/device/soulstone/anybody/chaplain name = "mysterious old shard" reusable = FALSE - + /obj/item/device/soulstone/pickup(mob/living/user) ..() if(!can_use(user)) to_chat(user, "An overwhelming feeling of dread comes over you as you pick up the soulstone. It would be wise to be rid of this quickly.") user.Dizzy(120) - -//////////////////////////////Capturing//////////////////////////////////////////////////////// + +//////////////////////////////Capturing//////////////////////////////////////////////////////// /obj/item/device/soulstone/attack(mob/living/carbon/human/M as mob, mob/user as mob) if(!can_use(user)) user.Paralyse(5) @@ -53,7 +53,7 @@ if(!ishuman(M) || istype(M, /mob/living/carbon/human/dummy)) //If target is not a human or a dummy return ..() - + if(M.has_brain_worms()) //Borer stuff - RR to_chat(user, "This being is corrupted by an alien intelligence and cannot be soul trapped.") return ..() @@ -62,6 +62,13 @@ to_chat(user, "A mysterious force prevents you from trapping this being's soul.") return ..() + if(iscultist(M)) + to_chat(user, "This soul is already MINE.") + return ..() + + M.create_attack_log("Has had their soul captured with [src.name] by [key_name(user)]") + user.create_attack_log("Used the [src.name] to capture the soul of [key_name(M)]") + M.create_attack_log("Has had their soul captured with [src.name] by [key_name(user)]") user.create_attack_log("Used the [src.name] to capture the soul of [key_name(M)]") log_attack("[key_name(user)] used the [src.name] to capture the soul of [key_name(M)]") @@ -69,7 +76,7 @@ transfer_soul("VICTIM", M, user) return -///////////////////Options for using captured souls/////////////////////////////////////// +///////////////////Options for using captured souls/////////////////////////////////////// /obj/item/device/soulstone/attack_self(mob/user) if(!in_range(src, user)) return @@ -77,8 +84,8 @@ if(!can_use(user)) user.Paralyse(5) to_chat(user, "Your body is wracked with debilitating pain!") - return - + return + user.set_machine(src) var/dat = "Soul Stone
" for(var/mob/living/simple_animal/shade/A in src) @@ -127,7 +134,7 @@ icon = 'icons/obj/wizard.dmi' icon_state = "construct" desc = "A wicked machine used by those skilled in magical arts. It is inactive" - + /obj/structure/constructshell/examine(mob/user) if(..(user, 0)) if(iscultist(user) || iswizard(user) || user.stat == DEAD) diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm index 8ba7558d69b..af452dbdbcd 100644 --- a/code/game/machinery/cloning.dm +++ b/code/game/machinery/cloning.dm @@ -124,6 +124,9 @@ buf.dna.unique_enzymes = md5(buf.dna.real_name) buf.dna.UI=list(0x066,0x000,0x033,0x000,0x000,0x000,0xAF0,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x000,0x033,0x066,0x0FF,0x4DB,0x002,0x690,0x000,0x000) //buf.dna.UI=list(0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x0C8,0x000,0x000,0x000,0x000,0x161,0xFBD,0xDEF) // Farmer Jeff + for(var/i in buf.dna.UI.len to DNA_UI_LENGTH) + buf.dna.UI += 0x000 + buf.dna.ResetSE() buf.dna.UpdateUI() /obj/item/weapon/disk/data/monkey diff --git a/code/game/machinery/computer/camera_advanced.dm b/code/game/machinery/computer/camera_advanced.dm index 3d1df935cf8..e91286fe422 100644 --- a/code/game/machinery/computer/camera_advanced.dm +++ b/code/game/machinery/computer/camera_advanced.dm @@ -37,18 +37,19 @@ off_action.Activate() /obj/machinery/computer/camera_advanced/attack_hand(mob/user) - if(..()) - return - if(!iscarbon(user)) - return if(current_user) to_chat(user, "The console is already in use!") return - + if(!iscarbon(user)) + return + if(..()) + return user.set_machine(src) + if(!eyeobj) CreateEye() - if(!eyeobj.initialized) + + if(!eyeobj.eye_initialized) var/camera_location for(var/obj/machinery/camera/C in cameranet.cameras) if(!C.can_use()) @@ -57,7 +58,7 @@ camera_location = get_turf(C) break if(camera_location) - eyeobj.initialized = 1 + eyeobj.eye_initialized = 1 give_eye_control(user) eyeobj.setLoc(camera_location) else @@ -66,6 +67,7 @@ user.unset_machine() else give_eye_control(user) + eyeobj.setLoc(eyeobj.loc) /obj/machinery/computer/camera_advanced/proc/give_eye_control(mob/user) @@ -77,7 +79,6 @@ user.remote_view = 1 user.remote_control = eyeobj user.reset_perspective(eyeobj) - eyeobj.setLoc(eyeobj.loc) /mob/camera/aiEye/remote name = "Inactive Camera Eye" @@ -86,10 +87,15 @@ var/acceleration = 1 var/mob/living/carbon/human/eye_user = null var/obj/machinery/computer/camera_advanced/origin - var/initialized = 0 + var/eye_initialized = 0 var/visible_icon = 0 var/image/user_image = null +/mob/camera/aiEye/remote/Destroy() + eye_user = null + origin = null + return ..() + /mob/camera/aiEye/remote/GetViewerClient() if(eye_user) return eye_user.client @@ -102,12 +108,11 @@ T = get_turf(T) loc = T cameranet.visibility(src) - if(eye_user.client) - if(visible_icon) + if(visible_icon) + if(eye_user.client) eye_user.client.images -= user_image user_image = image(icon,loc,icon_state,FLY_LAYER) eye_user.client.images += user_image - eye_user.client.eye = src /mob/camera/aiEye/remote/relaymove(mob/user,direct) var/initial = initial(sprint) @@ -140,14 +145,16 @@ remote_eye.origin.current_user = null remote_eye.origin.jump_action.Remove(C) remote_eye.eye_user = null - C.reset_perspective(null) if(C.client) - C.client.images -= remote_eye.user_image + C.reset_perspective(null) + if(remote_eye.visible_icon) + C.client.images -= remote_eye.user_image for(var/datum/camerachunk/chunk in remote_eye.visibleCameraChunks) C.client.images -= chunk.obscured C.remote_control = null C.unset_machine() src.Remove(C) + playsound(remote_eye.origin, 'sound/machines/terminal_off.ogg', 25, 0) /datum/action/innate/camera_jump name = "Jump To Camera" @@ -175,7 +182,14 @@ T[text("[][]", netcam.c_tag, (netcam.can_use() ? null : " (Deactivated)"))] = netcam + playsound(origin, 'sound/machines/terminal_prompt.ogg', 25, 0) var/camera = input("Choose which camera you want to view", "Cameras") as null|anything in T var/obj/machinery/camera/final = T[camera] + playsound(origin, "terminal_type", 25, 0) if(final) + playsound(origin, 'sound/machines/terminal_prompt_confirm.ogg', 25, 0) remote_eye.setLoc(get_turf(final)) + C.overlay_fullscreen("flash", /obj/screen/fullscreen/flash/noise) + C.clear_fullscreen("flash", 3) //Shorter flash than normal since it's an ~~advanced~~ console! + else + playsound(origin, 'sound/machines/terminal_prompt_deny.ogg', 25, 0) diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm index 67f15bb3fe1..bb57a4a2cc2 100644 --- a/code/game/objects/items/weapons/RCD.dm +++ b/code/game/objects/items/weapons/RCD.dm @@ -28,6 +28,7 @@ RCD var/canRwall = 0 var/menu = 1 var/door_type = /obj/machinery/door/airlock + var/door_name = "Airlock" req_access = list(access_engine) var/list/door_accesses = list() var/list/door_accesses_list = list() @@ -85,7 +86,7 @@ RCD /obj/item/weapon/rcd/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1, var/datum/topic_state/state = inventory_state) ui = nanomanager.try_update_ui(user, src, ui_key, ui, force_open) if(!ui) - ui = new(user, src, ui_key, "rcd.tmpl", "[name]", 400, 400, state = state) + ui = new(user, src, ui_key, "rcd.tmpl", "[name]", 450, 400, state = state) ui.open() ui.set_auto_update(1) @@ -93,6 +94,7 @@ RCD var/data[0] data["mode"] = mode data["door_type"] = door_type + data["door_name"] = door_name data["menu"] = menu data["matter"] = matter data["max_matter"] = max_matter @@ -164,6 +166,11 @@ RCD door_accesses_list[++door_accesses_list.len] = list("name" = get_access_desc(access), "id" = access, "enabled" = (access in door_accesses)) . = 1 + if(href_list["choice"] && !locked) + var/temp_t = sanitize(copytext(input("Enter a custom Airlock Name.","Airlock Name"),1,MAX_MESSAGE_LEN)) + if(temp_t) + door_name = temp_t + /obj/item/weapon/rcd/proc/activate() playsound(loc, 'sound/items/Deconstruct.ogg', 50, 1) @@ -207,6 +214,7 @@ RCD if(!useResource(10, user)) return 0 activate() var/obj/machinery/door/airlock/T = new door_type(A) + T.name = door_name T.autoclose = 1 if(one_access) T.req_one_access = door_accesses.Copy() diff --git a/code/game/objects/items/weapons/tanks/tank_types.dm b/code/game/objects/items/weapons/tanks/tank_types.dm index 122643238ec..428c4885814 100644 --- a/code/game/objects/items/weapons/tanks/tank_types.dm +++ b/code/game/objects/items/weapons/tanks/tank_types.dm @@ -184,7 +184,6 @@ name = "vox specialized nitrogen tank" desc = "A high-tech nitrogen tank designed specifically for Vox." icon_state = "emergency_vox" - item_state = "emergency_vox" volume = 25 /obj/item/weapon/tank/emergency_oxygen/vox/New() diff --git a/code/game/objects/items/weapons/tools.dm b/code/game/objects/items/weapons/tools.dm index 402453f8007..b3950e9cb4a 100644 --- a/code/game/objects/items/weapons/tools.dm +++ b/code/game/objects/items/weapons/tools.dm @@ -130,6 +130,7 @@ name = "welding tool" icon = 'icons/obj/tools.dmi' icon_state = "welder" + item_state = "welder" flags = CONDUCT slot_flags = SLOT_BELT force = 3 @@ -151,7 +152,6 @@ create_reagents(max_fuel) reagents.add_reagent("fuel", max_fuel) update_icon() - return /obj/item/weapon/weldingtool/examine(mob/user) if(..(user, 0)) @@ -178,7 +178,6 @@ else icon_state = "[initial(icon_state)][ratio]" update_torch() - return /obj/item/weapon/weldingtool/attackby(obj/item/I, mob/user, params) if(isscrewdriver(I)) @@ -361,7 +360,6 @@ name = "Industrial Welding Tool" desc = "A slightly larger welder with a larger tank." icon_state = "indwelder" - icon_state = "welder" max_fuel = 40 materials = list(MAT_METAL=70, MAT_GLASS=60) origin_tech = "engineering=2" @@ -387,6 +385,7 @@ name = "Upgraded Welding Tool" desc = "An upgraded welder based off the industrial welder." icon_state = "upindwelder" + item_state = "upindwelder" max_fuel = 80 w_class = 3 materials = list(MAT_METAL=70, MAT_GLASS=120) @@ -396,6 +395,7 @@ name = "Experimental Welding Tool" desc = "An experimental welder capable of self-fuel generation and less harmful to the eyes." icon_state = "exwelder" + item_state = "exwelder" max_fuel = 40 w_class = 3 materials = list(MAT_METAL=70, MAT_GLASS=120) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index e859c0348f1..89aef25f24f 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -1,6 +1,7 @@ /obj/structure/closet/cardboard name = "large cardboard box" desc = "Just a box..." + icon = 'icons/obj/cardboard_boxes.dmi' icon_state = "cardboard" icon_opened = "cardboard_open" icon_closed = "cardboard" @@ -43,7 +44,7 @@ /mob/living/proc/do_alert_animation(atom/A) var/image/I - I = image('icons/obj/closet.dmi', A, "cardboard_special", A.layer+1) + I = image('icons/obj/cardboard_boxes.dmi', A, "cardboard_special", A.layer+1) var/list/viewing = list() for(var/mob/M in viewers(A)) if(M.client) @@ -52,6 +53,7 @@ I.alpha = 0 animate(I, pixel_z = 32, alpha = 255, time = 5, easing = ELASTIC_EASING) + /obj/structure/closet/cardboard/attackby(obj/item/weapon/W as obj, mob/user as mob, params) if(src.opened) if(istype(W, /obj/item/weapon/weldingtool)) @@ -62,3 +64,25 @@ for(var/mob/M in viewers(src)) M.show_message("\The [src] has been cut apart by [user] with \the [WC].", 3, "You hear cutting.", 2) qdel(src) + return + if(istype(W, /obj/item/weapon/pen)) + var/decalselection = input("Please select a decal") as null|anything in list("Atmospherics", "Bartender", "Barber", "Blueshield", "Brig Physician", "Captain", + "Cargo", "Chief Engineer", "Chaplain", "Chef", "Chemist", "Civilian", "Clown", "CMO", "Coroner", "Detective", "Engineering", "Genetics", "HOP", + "HOS", "Hydroponics", "Internal Affairs Agent", "Janitor", "Magistrate", "Mechanic", "Medical", "Mime", "Mining", "NT Representative", "Paramedic", "Pod Pilot", + "Prisoner", "Research Director", "Security", "Syndicate", "Therapist", "Virology", "Warden", "Xenobiology") + if(!decalselection) + return + if(user.incapacitated()) + to_chat(user, "You're in no condition to perform this action.") + return + if(W != user.get_active_hand()) + to_chat(user, "You must be holding the pen to perform this action.") + return + if(! Adjacent(user)) + to_chat(user, "You have moved too far away from the cardboard box.") + return + decalselection = replacetext(decalselection, " ", "_") + decalselection = lowertext(decalselection) + icon_opened = ("cardboard_open_"+decalselection) + icon_closed = ("cardboard_"+decalselection) + update_icon() // a proc declared in the closets parent file used to update opened/closed sprites on normal closets diff --git a/code/game/response_team.dm b/code/game/response_team.dm index 3eccf7774d4..1ce1165a8a5 100644 --- a/code/game/response_team.dm +++ b/code/game/response_team.dm @@ -5,6 +5,9 @@ #define ERT_TYPE_RED 2 #define ERT_TYPE_GAMMA 3 +/datum/game_mode + var/list/datum/mind/ert = list() + var/list/response_team_members = list() var/responseteam_age = 21 // Minimum account age to play as an ERT member var/datum/response_team/active_team = null @@ -187,6 +190,7 @@ var/ert_request_answered = 0 M.mind.special_role = SPECIAL_ROLE_ERT if(!(M.mind in ticker.minds)) ticker.minds += M.mind //Adds them to regular mind list. + ticker.mode.ert += M.mind M.forceMove(spawn_location) active_team.equip_officer(class, M) diff --git a/code/game/sound.dm b/code/game/sound.dm index ed5f0d15b4c..14269acb81f 100644 --- a/code/game/sound.dm +++ b/code/game/sound.dm @@ -12,6 +12,9 @@ var/list/page_sound = list('sound/effects/pageturn1.ogg', 'sound/effects/pagetur var/list/gun_sound = list('sound/weapons/Gunshot.ogg', 'sound/weapons/Gunshot2.ogg','sound/weapons/Gunshot3.ogg','sound/weapons/Gunshot4.ogg') var/list/computer_ambience = list('sound/goonstation/machines/ambicomp1.ogg', 'sound/goonstation/machines/ambicomp2.ogg', 'sound/goonstation/machines/ambicomp3.ogg') var/list/ricochet = list('sound/weapons/effects/ric1.ogg', 'sound/weapons/effects/ric2.ogg','sound/weapons/effects/ric3.ogg','sound/weapons/effects/ric4.ogg','sound/weapons/effects/ric5.ogg') +var/list/terminal_type = list('sound/machines/terminal_button01.ogg', 'sound/machines/terminal_button02.ogg', 'sound/machines/terminal_button03.ogg', + 'sound/machines/terminal_button04.ogg', 'sound/machines/terminal_button05.ogg', 'sound/machines/terminal_button06.ogg', + 'sound/machines/terminal_button07.ogg', 'sound/machines/terminal_button08.ogg') /proc/playsound(var/atom/source, soundin, vol as num, vary, extrarange as num, falloff, var/is_global, var/pitch) @@ -137,4 +140,6 @@ var/list/ricochet = list('sound/weapons/effects/ric1.ogg', 'sound/weapons/effect soundin = pick(computer_ambience) if("ricochet") soundin = pick(ricochet) + if("terminal_type") + soundin = pick(terminal_type) return soundin diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 6b2224962f5..ac419bcb592 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -166,7 +166,7 @@ var/list/admin_verbs_debug = list( /client/proc/admin_serialize, /client/proc/admin_deserialize, /client/proc/jump_to_ruin, - /client/proc/toggle_medal_disable + /client/proc/toggle_medal_disable ) var/list/admin_verbs_possess = list( /proc/possess, @@ -213,6 +213,10 @@ var/list/admin_verbs_snpc = list( /client/proc/hide_snpc_verbs ) +/client/proc/on_holder_add() + if(chatOutput && chatOutput.loaded) + chatOutput.loadAdmin() + /client/proc/add_admin_verbs() if(holder) verbs += admin_verbs_default diff --git a/code/modules/admin/holder2.dm b/code/modules/admin/holder2.dm index 7ee714090cc..de22d5ea098 100644 --- a/code/modules/admin/holder2.dm +++ b/code/modules/admin/holder2.dm @@ -32,6 +32,7 @@ var/list/admin_datums = list() if(istype(C)) owner = C owner.holder = src + owner.on_holder_add() owner.add_admin_verbs() //TODO owner.verbs -= /client/proc/readmin admins |= C diff --git a/code/modules/admin/player_panel.dm b/code/modules/admin/player_panel.dm index 8e98e238fee..1f76781b90d 100644 --- a/code/modules/admin/player_panel.dm +++ b/code/modules/admin/player_panel.dm @@ -538,6 +538,9 @@ spider_minds += S.mind dat += check_role_table("Terror Spiders", spider_minds) + if(ticker.mode.ert.len) + dat += check_role_table("ERT", ticker.mode.ert) + dat += "" usr << browse(dat, "window=roundstatus;size=400x500") else diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 4a01b1161e8..c8a9bb78926 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1710,6 +1710,103 @@ to_chat(src.owner, "You sent a [eviltype] fax to [H]") log_admin("[key_name(src.owner)] sent [key_name(H)] a [eviltype] fax") message_admins("[key_name_admin(src.owner)] replied to [key_name_admin(H)] with a [eviltype] fax") + else if(href_list["Bless"]) + if(!check_rights(R_ADMIN)) + return + var/mob/living/M = locateUID(href_list["Bless"]) + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob/living") + return + var/btypes = list("To Arrivals", "Moderate Heal") + var/mob/living/carbon/human/H + if(ishuman(M)) + H = M + btypes += "Heal Over Time" + btypes += "Permanent Regeneration" + btypes += "Super Powers" + var/blessing = input(src.owner, "How would you like to bless [M]?", "Its good to be good...", "") as null|anything in btypes + if(!(blessing in btypes)) + return + switch(blessing) + if("To Arrivals") + M.forceMove(pick(latejoin)) + to_chat(M, "You are abruptly pulled through space!") + if("Moderate Heal") + M.adjustBruteLoss(-25) + M.adjustFireLoss(-25) + M.adjustToxLoss(-25) + M.adjustOxyLoss(-25) + to_chat(M,"You feel invigorated!") + if("Heal Over Time") + H.reagents.add_reagent("salglu_solution", 30) + H.reagents.add_reagent("salbutamol", 20) + H.reagents.add_reagent("spaceacillin", 20) + if("Permanent Regeneration") + H.dna.SetSEState(REGENERATEBLOCK, 1) + genemutcheck(H, REGENERATEBLOCK, null, MUTCHK_FORCED) + H.update_mutations() + if("Super Powers") + var/list/default_genes = list(REGENERATEBLOCK, NOBREATHBLOCK, COLDBLOCK) + for(var/gene in default_genes) + H.dna.SetSEState(gene, 1) + genemutcheck(H, gene, null, MUTCHK_FORCED) + H.update_mutations() + else if(href_list["Smite"]) + if(!check_rights(R_ADMIN)) + return + var/mob/living/M = locateUID(href_list["Smite"]) + var/mob/living/carbon/human/H + if(!istype(M)) + to_chat(usr, "This can only be used on instances of type /mob/living") + return + var/ptypes = list("Lightning bolt", "Fire Death", "Gib") + if(ishuman(M)) + H = M + ptypes += "Brain Damage" + ptypes += "Honk Tumor" + ptypes += "Cluwne" + ptypes += "Mutagen Cookie" + ptypes += "Hellwater Cookie" + var/punishment = input(src.owner, "How would you like to smite [M]?", "Its good to be baaaad...", "") as null|anything in ptypes + if(!(punishment in ptypes)) + return + switch(punishment) + if("Lightning bolt") + M.electrocute_act(5, "Lightning Bolt", safety=1) + playsound(get_turf(M), 'sound/magic/LightningShock.ogg', 50, 1, -1) + M.adjustFireLoss(75) + M.Weaken(5) + to_chat(M, "The gods have punished you for your sins!") + if("Brain Damage") + H.adjustBrainLoss(75) + if("Fire Death") + to_chat(M,"You feel hotter than usual. Maybe you should lowe-wait, is that your hand melting?") + var/turf/simulated/T = get_turf(M) + new /obj/effect/hotspot(T) + M.adjustFireLoss(150) + if("Honk Tumor") + if(!H.get_int_organ(/obj/item/organ/internal/honktumor)) + var/obj/item/organ/internal/organ = new /obj/item/organ/internal/honktumor + to_chat(H, "Life seems funnier, somehow.") + organ.insert(H) + if("Cluwne") + H.makeCluwne() + if("Mutagen Cookie") + var/obj/item/weapon/reagent_containers/food/snacks/cookie/evilcookie = new /obj/item/weapon/reagent_containers/food/snacks/cookie + evilcookie.reagents.add_reagent("mutagen", 10) + evilcookie.desc = "It has a faint green glow." + evilcookie.bitesize = 100 + H.drop_l_hand() + H.equip_to_slot_or_del(evilcookie, slot_l_hand) + if("Hellwater Cookie") + var/obj/item/weapon/reagent_containers/food/snacks/cookie/evilcookie = new /obj/item/weapon/reagent_containers/food/snacks/cookie + evilcookie.reagents.add_reagent("hell_water", 25) + evilcookie.desc = "Sulphur-flavored." + evilcookie.bitesize = 100 + H.drop_l_hand() + H.equip_to_slot_or_del(evilcookie, slot_l_hand) + if("Gib") + M.gib(FALSE) else if(href_list["FaxReplyTemplate"]) if(!check_rights(R_ADMIN)) return diff --git a/code/modules/admin/verbs/pray.dm b/code/modules/admin/verbs/pray.dm index 486b95f5a1b..ad926d61de7 100644 --- a/code/modules/admin/verbs/pray.dm +++ b/code/modules/admin/verbs/pray.dm @@ -13,7 +13,7 @@ return var/image/cross = image('icons/obj/storage.dmi',"bible") - msg = "\blue [bicon(cross)] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) ([admin_jump_link(src)]) (CA) (SC): [msg]" + msg = "\blue [bicon(cross)] PRAY: [key_name(src, 1)] (?) (PP) (VV) (SM) ([admin_jump_link(src)]) (CA) (SC) (BLESS) (SMITE): [msg]" for(var/client/X in admins) if(check_rights(R_EVENT,0,X.mob)) diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm index 02b4596a012..7313de43815 100644 --- a/code/modules/client/client procs.dm +++ b/code/modules/client/client procs.dm @@ -335,6 +335,7 @@ world.update_status() if(holder) + on_holder_add() add_admin_verbs() admin_memo_output("Show", 0, 1) diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm index 5408d6fcdfe..15af19c19e4 100644 --- a/code/modules/client/preference/preferences.dm +++ b/code/modules/client/preference/preferences.dm @@ -95,6 +95,8 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts var/UI_style_alpha = 255 var/windowflashing = TRUE + //ghostly preferences + var/ghost_anonsay = 0 //character preferences var/real_name //our character's name @@ -446,6 +448,7 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts dat += "Ghost ears: [(toggles & CHAT_GHOSTEARS) ? "Nearest Creatures" : "All Speech"]
" dat += "Ghost sight: [(toggles & CHAT_GHOSTSIGHT) ? "Nearest Creatures" : "All Emotes"]
" dat += "Ghost radio: [(toggles & CHAT_GHOSTRADIO) ? "Nearest Speakers" : "All Chatter"]
" + dat += "Deadchat anonymity: [ghost_anonsay ? "Anonymous" : "Not Anonymous"]
" dat += "" dat += "

Special Role Settings

" @@ -1997,6 +2000,9 @@ var/global/list/special_role_times = list( //minimum age (in days) for accounts if("ghost_radio") toggles ^= CHAT_GHOSTRADIO + if("ghost_anonsay") + ghost_anonsay = !ghost_anonsay + if("save") save_preferences(user) save_character(user) diff --git a/code/modules/client/preference/preferences_mysql.dm b/code/modules/client/preference/preferences_mysql.dm index c7716c33eed..a945af5ba2f 100644 --- a/code/modules/client/preference/preferences_mysql.dm +++ b/code/modules/client/preference/preferences_mysql.dm @@ -14,8 +14,9 @@ nanoui_fancy, show_ghostitem_attack, lastchangelog, - exp, - windowflashing + windowflashing, + ghost_anonsay, + exp FROM [format_table_name("player")] WHERE ckey='[C.ckey]'"} ) @@ -42,8 +43,9 @@ nanoui_fancy = text2num(query.item[11]) show_ghostitem_attack = text2num(query.item[12]) lastchangelog = query.item[13] - exp = query.item[14] - windowflashing = text2num(query.item[15]) + windowflashing = text2num(query.item[14]) + ghost_anonsay = text2num(query.item[15]) + exp = query.item[16] //Sanitize ooccolor = sanitize_hexcolor(ooccolor, initial(ooccolor)) @@ -58,8 +60,9 @@ nanoui_fancy = sanitize_integer(nanoui_fancy, 0, 1, initial(nanoui_fancy)) show_ghostitem_attack = sanitize_integer(show_ghostitem_attack, 0, 1, initial(show_ghostitem_attack)) lastchangelog = sanitize_text(lastchangelog, initial(lastchangelog)) - exp = sanitize_text(exp, initial(exp)) windowflashing = sanitize_integer(windowflashing, 0, 1, initial(windowflashing)) + ghost_anonsay = sanitize_integer(ghost_anonsay, 0, 1, initial(ghost_anonsay)) + exp = sanitize_text(exp, initial(exp)) return 1 /datum/preferences/proc/save_preferences(client/C) @@ -85,7 +88,8 @@ nanoui_fancy='[nanoui_fancy]', show_ghostitem_attack='[show_ghostitem_attack]', lastchangelog='[lastchangelog]', - windowflashing='[windowflashing]' + windowflashing='[windowflashing]', + ghost_anonsay='[ghost_anonsay]' WHERE ckey='[C.ckey]'"} ) diff --git a/code/modules/events/meaty_ops.dm b/code/modules/events/meaty_ops.dm index d92e79edea9..87d58ae7dbb 100644 --- a/code/modules/events/meaty_ops.dm +++ b/code/modules/events/meaty_ops.dm @@ -15,5 +15,5 @@ -/datum/event/meteor_wave/goreops/end() +/datum/event/meteor_wave/goreop/end() event_announcement.Announce("All MeteorOps are dead. Major Station Victory.", "MeteorOps") \ No newline at end of file diff --git a/code/modules/food_and_drinks/food/snacks.dm b/code/modules/food_and_drinks/food/snacks.dm index ff684c3296b..add4e7c474f 100644 --- a/code/modules/food_and_drinks/food/snacks.dm +++ b/code/modules/food_and_drinks/food/snacks.dm @@ -1218,13 +1218,6 @@ user.drop_item() forceMove(get_turf(O)) return Expand() - if(istype(O, /obj/machinery/computer/camera_advanced/xenobio)) - var/obj/machinery/computer/camera_advanced/xenobio/X = O - X.monkeys++ - to_chat(user, "You feed [src] to the [X]. It now has [X.monkeys] monkey cubes stored.") - user.drop_item() - qdel(src) - return ..() /obj/item/weapon/reagent_containers/food/snacks/monkeycube/water_act(volume, temperature) diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 7c2e1a55842..b6e4b8b066b 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -59,21 +59,14 @@ var/list/all_lighting_overlays = list() // Global list of lighting overlays. var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) - var/list/new_matrix = list( + color = list( cr.cache_r, cr.cache_g, cr.cache_b, 0, cg.cache_r, cg.cache_g, cg.cache_b, 0, cb.cache_r, cb.cache_g, cb.cache_b, 0, ca.cache_r, ca.cache_g, ca.cache_b, 0, 0, 0, 0, 1 - ) - var/lum = max > LIGHTING_SOFT_THRESHOLD - - if(lum) - luminosity = 1 - animate(src, color = new_matrix, time = 5) - else - animate(src, color = new_matrix, time = 5) - animate(luminosity = 0, time = 0) + ) + luminosity = max > LIGHTING_SOFT_THRESHOLD diff --git a/code/modules/mob/dead/observer/observer.dm b/code/modules/mob/dead/observer/observer.dm index db6ef63ad22..75ff52b6478 100644 --- a/code/modules/mob/dead/observer/observer.dm +++ b/code/modules/mob/dead/observer/observer.dm @@ -22,7 +22,6 @@ var/list/image/ghost_darkness_images = list() //this is a list of images for thi //Note that this is not a reliable way to determine if admins started as observers, since they change mobs a lot. universal_speak = 1 var/atom/movable/following = null - var/anonsay = 0 var/image/ghostimage = null //this mobs ghost image, for deleting and stuff var/ghostvision = 1 //is the ghost able to see things humans can't? var/seedarkness = 1 @@ -596,15 +595,12 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp //END TELEPORT HREF CODE /mob/dead/observer/verb/toggle_anonsay() + set name = "Toggle Anonymous Dead-chat" set category = "Ghost" - set name = "Toggle Anonymous Chat" set desc = "Toggles showing your key in dead chat." - - src.anonsay = !src.anonsay - if(anonsay) - to_chat(src, "Your key won't be shown when you speak in dead chat.") - else - to_chat(src, "Your key will be publicly visible again.") + client.prefs.ghost_anonsay = !client.prefs.ghost_anonsay + to_chat(src, "As a ghost, your key will [(client.prefs.ghost_anonsay) ? "no longer" : "now"] be shown when you speak in dead chat.
") + client.prefs.save_preferences(src) /mob/dead/observer/verb/toggle_ghostsee() set name = "Toggle Ghost Vision" diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index f9315966d27..ac1d98e848f 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -57,6 +57,10 @@ on_CD = handle_emote_CD(50) //longer cooldown if("fart", "farts", "flip", "flips", "snap", "snaps") on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm + if("cough", "coughs") + on_CD = handle_emote_CD() + if("sneeze", "sneezes") + on_CD = handle_emote_CD() //Everything else, including typos of the above emotes else on_CD = 0 //If it doesn't induce the cooldown, we won't check for the cooldown @@ -399,6 +403,12 @@ if(!muzzled) message = "[src] coughs!" m_type = 2 + if(gender == FEMALE) + if(species.female_cough_sounds) + playsound(src, pick(species.female_cough_sounds), 120) + else + if(species.male_cough_sounds) + playsound(src, pick(species.male_cough_sounds), 120) else message = "[src] makes a strong noise." m_type = 2 @@ -654,6 +664,10 @@ else if(!muzzled) message = "[src] sneezes." + if(gender == FEMALE) + playsound(src, species.female_sneeze_sound, 70) + else + playsound(src, species.male_sneeze_sound, 70) m_type = 2 else message = "[src] makes a strange noise." diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f9e2b42d68b..7e54aebf396 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1514,6 +1514,8 @@ if(oldspecies.default_genes.len) oldspecies.handle_dna(src,1) // Remove any genes that belong to the old species + tail = species.tail + if(vessel) vessel = null make_blood() @@ -2050,6 +2052,10 @@ return . +/mob/living/carbon/human/proc/change_icobase(var/new_icobase, var/new_deform, var/owner_sensitive) + for(var/obj/item/organ/external/O in organs) + O.change_organ_icobase(new_icobase, new_deform, owner_sensitive) //Change the icobase/deform of all our organs. If owner_sensitive is set, that means the proc won't mess with frankenstein limbs. + /mob/living/carbon/human/serialize() // Currently: Limbs/organs only var/list/data = ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 986a3ffb9c4..65361960042 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -57,7 +57,7 @@ emp_act organ.add_autopsy_data(P.name, P.damage) // Add the bullet's name to the autopsy data return (..(P , def_zone)) - + /mob/living/carbon/human/check_projectile_dismemberment(obj/item/projectile/P, def_zone) var/obj/item/organ/external/affecting = get_organ(check_zone(def_zone)) if(affecting && !affecting.cannot_amputate && affecting.get_damage() >= (affecting.max_damage - P.dismemberment)) @@ -67,7 +67,7 @@ emp_act damtype = DROPLIMB_BLUNT if(BURN) damtype = DROPLIMB_BURN - + affecting.droplimb(FALSE, damtype) /mob/living/carbon/human/getarmor(var/def_zone, var/type) @@ -226,9 +226,9 @@ emp_act if(! I.discrete) if(I.attack_verb.len) - visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!") + visible_message("[src] has been [pick(I.attack_verb)] in the [hit_area] with [I.name] by [user]!") else - visible_message("[src] has been attacked in the [hit_area] with [I.name] by [user]!") + visible_message("[src] has been attacked in the [hit_area] with [I.name] by [user]!") var/armor = run_armor_check(affecting, "melee", "Your armor has protected your [hit_area].", "Your armor has softened hit to your [hit_area].", armour_penetration = I.armour_penetration) var/weapon_sharp = is_sharp(I) @@ -264,8 +264,8 @@ emp_act if("head")//Harder to score a stun but if you do it lasts a bit longer if(stat == CONSCIOUS && armor < 50) if(prob(I.force)) - visible_message("[src] has been knocked down!", \ - "[src] has been knocked down!") + visible_message("[src] has been knocked down!", \ + "[src] has been knocked down!") apply_effect(5, WEAKEN, armor) AdjustConfused(15) if(prob(I.force + ((100 - health)/2)) && src != user && I.damtype == BRUTE) @@ -284,8 +284,8 @@ emp_act if("upper body")//Easier to score a stun but lasts less time if(stat == CONSCIOUS && I.force && prob(I.force + 10)) - visible_message("[src] has been knocked down!", \ - "[src] has been knocked down!") + visible_message("[src] has been knocked down!", \ + "[src] has been knocked down!") apply_effect(5, WEAKEN, armor) if(bloody) diff --git a/code/modules/mob/living/carbon/human/human_defines.dm b/code/modules/mob/living/carbon/human/human_defines.dm index 0d30c5c8265..63378d1a776 100644 --- a/code/modules/mob/living/carbon/human/human_defines.dm +++ b/code/modules/mob/living/carbon/human/human_defines.dm @@ -72,3 +72,4 @@ var/global/default_martial_art = new/datum/martial_art var/fire_sprite = "Standing" var/datum/body_accessory/body_accessory = null + var/tail // Name of tail image in species effects icon file. diff --git a/code/modules/mob/living/carbon/human/species/species.dm b/code/modules/mob/living/carbon/human/species/species.dm index d8769a3acea..54f68f2b101 100644 --- a/code/modules/mob/living/carbon/human/species/species.dm +++ b/code/modules/mob/living/carbon/human/species/species.dm @@ -128,6 +128,10 @@ var/scream_verb = "screams" var/male_scream_sound = 'sound/goonstation/voice/male_scream.ogg' var/female_scream_sound = 'sound/goonstation/voice/female_scream.ogg' + var/male_cough_sounds = list('sound/effects/mob_effects/m_cougha.ogg','sound/effects/mob_effects/m_coughb.ogg', 'sound/effects/mob_effects/m_coughc.ogg') + var/female_cough_sounds = list('sound/effects/mob_effects/f_cougha.ogg','sound/effects/mob_effects/f_coughb.ogg') + var/male_sneeze_sound = 'sound/effects/mob_effects/sneeze.ogg' + var/female_sneeze_sound = 'sound/effects/mob_effects/f_sneeze.ogg' //Default hair/headacc style vars. var/default_hair //Default hair style for newly created humans unless otherwise set. @@ -676,4 +680,4 @@ It'll return null if the organ doesn't correspond, so include null checks when u H.see_invisible = SEE_INVISIBLE_MINIMUM if(H.see_override) //Override all - H.see_invisible = H.see_override \ No newline at end of file + H.see_invisible = H.see_override diff --git a/code/modules/mob/living/carbon/human/species/station.dm b/code/modules/mob/living/carbon/human/species/station.dm index 661c861385d..c07a3667a02 100644 --- a/code/modules/mob/living/carbon/human/species/station.dm +++ b/code/modules/mob/living/carbon/human/species/station.dm @@ -360,34 +360,35 @@ //H.verbs += /mob/living/carbon/human/proc/leap ..() -/datum/species/vox/updatespeciescolor(var/mob/living/carbon/human/H) //Handling species-specific skin-tones for the Vox race. +/datum/species/vox/updatespeciescolor(var/mob/living/carbon/human/H, var/owner_sensitive = 1) //Handling species-specific skin-tones for the Vox race. if(H.species.name == "Vox") //Making sure we don't break Armalis. + var/new_icobase = 'icons/mob/human_races/vox/r_vox.dmi' //Default Green Vox. + var/new_deform = 'icons/mob/human_races/vox/r_def_vox.dmi' //Default Green Vox. switch(H.s_tone) if(6) //Azure Vox. - icobase = 'icons/mob/human_races/vox/r_voxazu.dmi' - deform = 'icons/mob/human_races/vox/r_def_voxazu.dmi' - tail = "voxtail_azu" + new_icobase = 'icons/mob/human_races/vox/r_voxazu.dmi' + new_deform = 'icons/mob/human_races/vox/r_def_voxazu.dmi' + H.tail = "voxtail_azu" if(5) //Emerald Vox. - icobase = 'icons/mob/human_races/vox/r_voxemrl.dmi' - deform = 'icons/mob/human_races/vox/r_def_voxemrl.dmi' - tail = "voxtail_emrl" + new_icobase = 'icons/mob/human_races/vox/r_voxemrl.dmi' + new_deform = 'icons/mob/human_races/vox/r_def_voxemrl.dmi' + H.tail = "voxtail_emrl" if(4) //Grey Vox. - icobase = 'icons/mob/human_races/vox/r_voxgry.dmi' - deform = 'icons/mob/human_races/vox/r_def_voxgry.dmi' - tail = "voxtail_gry" + new_icobase = 'icons/mob/human_races/vox/r_voxgry.dmi' + new_deform = 'icons/mob/human_races/vox/r_def_voxgry.dmi' + H.tail = "voxtail_gry" if(3) //Brown Vox. - icobase = 'icons/mob/human_races/vox/r_voxbrn.dmi' - deform = 'icons/mob/human_races/vox/r_def_voxbrn.dmi' - tail = "voxtail_brn" + new_icobase = 'icons/mob/human_races/vox/r_voxbrn.dmi' + new_deform = 'icons/mob/human_races/vox/r_def_voxbrn.dmi' + H.tail = "voxtail_brn" if(2) //Dark Green Vox. - icobase = 'icons/mob/human_races/vox/r_voxdgrn.dmi' - deform = 'icons/mob/human_races/vox/r_def_voxdgrn.dmi' - tail = "voxtail_dgrn" + new_icobase = 'icons/mob/human_races/vox/r_voxdgrn.dmi' + new_deform = 'icons/mob/human_races/vox/r_def_voxdgrn.dmi' + H.tail = "voxtail_dgrn" else //Default Green Vox. - icobase = 'icons/mob/human_races/vox/r_vox.dmi' - deform = 'icons/mob/human_races/vox/r_def_vox.dmi' - tail = "voxtail" //Ensures they get an appropriately coloured tail depending on the skin-tone. + H.tail = "voxtail" //Ensures they get an appropriately coloured tail depending on the skin-tone. + H.change_icobase(new_icobase, new_deform, owner_sensitive) //Update the icobase/deform of all our organs, but make sure we don't mess with frankenstein limbs in doing so. H.update_dna() /datum/species/vox/armalis/handle_post_spawn(var/mob/living/carbon/human/H) @@ -519,6 +520,11 @@ butt_sprite = "slime" //Has default darksight of 2. + male_cough_sounds = null //slime people don't have lungs + female_cough_sounds = null + male_sneeze_sound = null + female_sneeze_sound = null + has_organ = list( "brain" = /obj/item/organ/internal/brain/slime ) @@ -738,6 +744,12 @@ slowdown = 5 remains_type = /obj/effect/decal/cleanable/ash + male_cough_sounds = null //diona don't have lungs + female_cough_sounds = null + male_sneeze_sound = null + female_sneeze_sound = null + + warning_low_pressure = 50 hazard_low_pressure = -1 @@ -827,7 +839,7 @@ if(H.nutrition > NUTRITION_LEVEL_WELL_FED) H.nutrition = NUTRITION_LEVEL_WELL_FED - + if(light_amount > 0) H.clear_alert("nolight") else @@ -881,6 +893,10 @@ reagent_tag = PROCESS_SYN male_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' female_scream_sound = 'sound/goonstation/voice/robot_scream.ogg' + male_cough_sounds = list('sound/effects/mob_effects/m_machine_cougha.ogg','sound/effects/mob_effects/m_machine_coughb.ogg', 'sound/effects/mob_effects/m_machine_coughc.ogg') + female_cough_sounds = list('sound/effects/mob_effects/f_machine_cougha.ogg','sound/effects/mob_effects/f_machine_coughb.ogg') + male_sneeze_sound = 'sound/effects/mob_effects/machine_sneeze.ogg' + female_sneeze_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg' butt_sprite = "machine" has_organ = list( @@ -940,6 +956,10 @@ speech_chance = 20 male_scream_sound = 'sound/voice/DraskTalk2.ogg' female_scream_sound = 'sound/voice/DraskTalk2.ogg' + male_cough_sounds = null //whale cough when + female_cough_sounds = null + male_sneeze_sound = null + female_sneeze_sound = null burn_mod = 2 //exotic_blood = "cryoxadone" @@ -1022,4 +1042,4 @@ H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_2, BURN, "head", used_weapon = "Excessive Heat") if(heat_level_3_breathe to INFINITY) - H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") \ No newline at end of file + H.apply_damage(hot_env_multiplier*HEAT_GAS_DAMAGE_LEVEL_3, BURN, "head", used_weapon = "Excessive Heat") diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 48555229aad..d24471dc7e2 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -298,9 +298,9 @@ var/global/list/damage_icon_parts = list() base_icon.MapColors(rgb(tone[1],0,0),rgb(0,tone[2],0),rgb(0,0,tone[3])) //Handle husk overlay. - if(husk && ("overlay_husk" in icon_states(species.icobase))) + if(husk && ("overlay_husk" in icon_states(chest.icobase))) var/icon/mask = new(base_icon) - var/icon/husk_over = new(species.icobase,"overlay_husk") + var/icon/husk_over = new(chest.icobase,"overlay_husk") mask.MapColors(0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,1, 0,0,0,0) husk_over.Blend(mask, ICON_ADD) base_icon.Blend(husk_over, ICON_OVERLAY) @@ -1197,9 +1197,9 @@ var/global/list/damage_icon_parts = list() else // Otherwise, since the user's tail isn't overlapped by limbs, go ahead and use default icon generation. overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) - else if(species.tail && species.bodyflags & HAS_TAIL) //no tailless tajaran + else if(tail && species.bodyflags & HAS_TAIL) //no tailless tajaran if(!wear_suit || !(wear_suit.flags_inv & HIDETAIL) && !istype(wear_suit, /obj/item/clothing/suit/space)) - var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]_s") + var/icon/tail_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[tail]_s") if(species.bodyflags & HAS_SKIN_COLOR) tail_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) if(tail_marking_icon) @@ -1266,8 +1266,8 @@ var/global/list/damage_icon_parts = list() else // Otherwise, since the user's tail isn't overlapped by limbs, go ahead and use default icon generation. overlays_standing[TAIL_LAYER] = image(accessory_s, "pixel_x" = body_accessory.pixel_x_offset, "pixel_y" = body_accessory.pixel_y_offset) - else if(species.tail && species.bodyflags & HAS_TAIL) - var/icon/tailw_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[species.tail]w_s") + else if(tail && species.bodyflags & HAS_TAIL) + var/icon/tailw_s = new/icon("icon" = 'icons/effects/species.dmi', "icon_state" = "[tail]w_s") if(species.bodyflags & HAS_SKIN_COLOR) tailw_s.Blend(rgb(r_skin, g_skin, b_skin), ICON_ADD) if(tail_marking_icon) diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 962987dcc3f..2988363ffb9 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -196,3 +196,5 @@ var/list/permanent_huds = list() var/list/actions = list() + + var/list/progressbars = null //for stacking do_after bars diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 9922fed8789..2e83e9b9a95 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -442,9 +442,9 @@ var/list/intents = list(I_HELP,I_DISARM,I_GRAB,I_HARM) if(istype(subject, /mob/dead/observer)) DM = subject if(check_rights(R_ADMIN|R_MOD,0,M)) // What admins see - lname = "[keyname][(DM && DM.anonsay) ? "*" : (DM ? "" : "^")] ([name])" + lname = "[keyname][(DM && DM.client && DM.client.prefs.ghost_anonsay) ? "*" : (DM ? "" : "^")] ([name])" else - if(DM && DM.anonsay) // If the person is actually observer they have the option to be anonymous + if(DM && DM.client && DM.client.prefs.ghost_anonsay) // If the person is actually observer they have the option to be anonymous lname = "Ghost of [name]" else if(DM) // Non-anons lname = "[keyname] ([name])" diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index efaf84798d1..15473caf5f2 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -241,11 +241,12 @@ var/mob/living/carbon/human/H = new H.species = current_species H.s_tone = s_tone - H.species.updatespeciescolor(H) - - icobase = H.species.icobase + H.species.updatespeciescolor(H, 0) //The mob's species wasn't set, so it's almost certainly different than the character's species at the moment. Thus, we need to be owner-insensitive. + var/obj/item/organ/external/chest/C = H.get_organ("chest") + icobase = C.icobase ? C.icobase : C.species.icobase if(H.species.bodyflags & HAS_TAIL) - coloured_tail = H.species.tail + coloured_tail = H.tail ? H.tail : H.species.tail + qdel(H) else icobase = current_species.icobase diff --git a/code/modules/reagents/chemistry/reagents/misc.dm b/code/modules/reagents/chemistry/reagents/misc.dm index f755f61219f..e8505d64653 100644 --- a/code/modules/reagents/chemistry/reagents/misc.dm +++ b/code/modules/reagents/chemistry/reagents/misc.dm @@ -417,15 +417,15 @@ var/newsize = current_size switch(volume) if(0 to 19) - newsize = 1.25 + newsize = 1.1 if(20 to 49) - newsize = 1.5 + newsize = 1.2 if(50 to 99) - newsize = 2 + newsize = 1.25 if(100 to 199) - newsize = 2.5 + newsize = 1.3 if(200 to INFINITY) - newsize = 3.5 + newsize = 1.5 H.resize = newsize/current_size current_size = newsize diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm index 416eac1ba2a..9e0e26a0252 100644 --- a/code/modules/research/xenobiology/xenobio_camera.dm +++ b/code/modules/research/xenobiology/xenobio_camera.dm @@ -67,6 +67,26 @@ return return ..() +/obj/machinery/computer/camera_advanced/xenobio/attackby(obj/item/O, mob/user, params) + if(istype(O, /obj/item/weapon/reagent_containers/food/snacks/monkeycube)) + monkeys++ + to_chat(user, "You feed [O] to [src]. It now has [monkeys] monkey cubes stored.") + user.drop_item() + qdel(O) + return + else if(istype(O, /obj/item/weapon/storage/bag)) + var/obj/item/weapon/storage/P = O + var/loaded = 0 + for(var/obj/G in P.contents) + if(istype(G, /obj/item/weapon/reagent_containers/food/snacks/monkeycube)) + loaded = 1 + monkeys++ + qdel(G) + if(loaded) + to_chat(user, "You fill [src] with the monkey cubes stored in [O]. [src] now has [monkeys] monkey cubes stored.") + return + ..() + /datum/action/innate/camera_off/xenobio/Activate() if(!target || !ishuman(target)) return @@ -82,9 +102,8 @@ origin.monkey_recycle_action.Remove(C) //All of this stuff below could probably be a proc for all advanced cameras, only the action removal needs to be camera specific remote_eye.eye_user = null + C.reset_perspective(null) if(C.client) - C.client.perspective = MOB_PERSPECTIVE - C.client.eye = src C.client.images -= remote_eye.user_image for(var/datum/camerachunk/chunk in remote_eye.visibleCameraChunks) C.client.images -= chunk.obscured @@ -109,6 +128,8 @@ S.forceMove(remote_eye.loc) S.visible_message("[S] warps in!") X.stored_slimes -= S + else + to_chat(owner, "Target is not near a camera. Cannot proceed.") /datum/action/innate/slime_pick_up name = "Pick up Slime" @@ -132,7 +153,8 @@ S.visible_message("[S] vanishes in a flash of light!") S.forceMove(X) X.stored_slimes += S - + else + to_chat(owner, "Target is not near a camera. Cannot proceed.") /datum/action/innate/feed_slime name = "Feed Slimes" @@ -151,7 +173,8 @@ food.LAssailant = C X.monkeys -- to_chat(owner, "[X] now has [X.monkeys] monkeys left.") - + else + to_chat(owner, "Target is not near a camera. Cannot proceed.") /datum/action/innate/monkey_recycle name = "Recycle Monkeys" @@ -168,5 +191,7 @@ for(var/mob/living/carbon/human/M in remote_eye.loc) if(issmall(M) && M.stat) M.visible_message("[M] vanishes as they are reclaimed for recycling!") - X.monkeys += 0.2 + X.monkeys = round(X.monkeys + 0.2,0.1) qdel(M) + else + to_chat(owner, "Target is not near a camera. Cannot proceed.") \ No newline at end of file diff --git a/code/modules/surgery/organs/organ_external.dm b/code/modules/surgery/organs/organ_external.dm index ce4b55efb11..110584d5d2a 100644 --- a/code/modules/surgery/organs/organ_external.dm +++ b/code/modules/surgery/organs/organ_external.dm @@ -18,6 +18,9 @@ var/model var/force_icon + var/icobase = 'icons/mob/human_races/r_human.dmi' // Normal icon set. + var/deform = 'icons/mob/human_races/r_def_human.dmi' // Mutated icon set. + var/damage_state = "00" var/brute_dam = 0 var/burn_dam = 0 @@ -127,9 +130,12 @@ /obj/item/organ/external/New(var/mob/living/carbon/holder) ..() - if(istype(holder, /mob/living/carbon/human)) - replaced(holder) - sync_colour_to_human(holder) + var/mob/living/carbon/human/H = holder + icobase = species.icobase + deform = species.deform + if(istype(H)) + replaced(H) + sync_colour_to_human(H) spawn(1) get_icon() diff --git a/code/modules/surgery/organs/organ_icon.dm b/code/modules/surgery/organs/organ_icon.dm index 03690ef3279..e174ed55a3f 100644 --- a/code/modules/surgery/organs/organ_icon.dm +++ b/code/modules/surgery/organs/organ_icon.dm @@ -14,6 +14,16 @@ var/global/list/limb_icon_cache = list() overlays += organ.mob_icon child_icons += organ.mob_icon +/obj/item/organ/external/proc/change_organ_icobase(var/new_icobase, var/new_deform, var/owner_sensitive) //Change the icobase/deform of this organ. If owner_sensitive is set, that means the proc won't mess with frankenstein limbs. + if(owner_sensitive) //This and the below statements mean that the icobase/deform will only get updated if the limb is the same species as and is owned by the mob it's attached to. + if(species && owner.species && species.name != owner.species.name) + return + if(dna.unique_enzymes != owner.dna.unique_enzymes) // This isn't MY arm + return + + icobase = new_icobase ? new_icobase : icobase + deform = new_deform ? new_deform : deform + /obj/item/organ/external/proc/sync_colour_to_human(var/mob/living/carbon/human/H) if(status & ORGAN_ROBOT && !(species && species.name == "Machine")) //machine people get skin color return @@ -29,6 +39,9 @@ var/global/list/limb_icon_cache = list() if(H.species.bodyflags & HAS_SKIN_COLOR) s_tone = null s_col = list(H.r_skin, H.g_skin, H.b_skin) + if(H.species.bodyflags & HAS_ICON_SKIN_TONE) + var/obj/item/organ/external/chest/C = H.get_organ("chest") + change_organ_icobase(C.icobase, C.deform) /obj/item/organ/external/proc/sync_colour_to_dna() if(status & ORGAN_ROBOT) @@ -171,10 +184,10 @@ var/global/list/limb_icon_cache = list() icon_file = 'icons/mob/human_races/robotic.dmi' else if(status & ORGAN_MUTATED) - icon_file = species.deform + icon_file = deform else // Congratulations, you are normal - icon_file = species.icobase + icon_file = icobase return list(icon_file, new_icon_state) /obj/item/organ/external/chest/get_icon_state(skeletal) diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css index f954af6dc9c..77984467afb 100644 --- a/goon/browserassets/css/browserOutput.css +++ b/goon/browserassets/css/browserOutput.css @@ -258,7 +258,7 @@ em {font-style: normal; font-weight: bold;} .srvradio {color: #6eaa2c;} .admin_channel {color: #9A04D1; font-weight: bold;} .mentor_channel {color: #775BFF; font-weight: bold;} -.mentor_channel_admin {color: #9A04D1; font-weight: bold;} +.mentor_channel_admin {color: #A35CFF; font-weight: bold;} .djradio {color: #663300;} .binaryradio {color: #0B0050; font-family: 'Courier New', Courier, monospace;} .mommiradio {color: navy;} @@ -377,4 +377,4 @@ h1.alert, h2.alert {color: #000000;} .hierophant_warning {color: #660099; font-weight: bold; font-style: italic;} /* EMOJI STUFF */ -.emoji {max-height: 16px; max-width: 16px} \ No newline at end of file +.emoji {max-height: 16px; max-width: 16px} diff --git a/goon/browserassets/html/adminOutput.html b/goon/browserassets/html/adminOutput.html new file mode 100644 index 00000000000..baf8bc00b3b --- /dev/null +++ b/goon/browserassets/html/adminOutput.html @@ -0,0 +1,104 @@ + \ No newline at end of file diff --git a/goon/browserassets/js/browserOutput.js b/goon/browserassets/js/browserOutput.js index 538452dc472..88b9a5425af 100644 --- a/goon/browserassets/js/browserOutput.js +++ b/goon/browserassets/js/browserOutput.js @@ -396,7 +396,7 @@ function ehjaxCallback(data) { dataJ = $.parseJSON(data); } catch (e) { //But...incorrect :sadtrombone: - window.onerror('JSON: '+e+'. '+data, 'browserOutput.html', 327); + window.onerror('JSON: '+e+'. '+data+'; data.length = '+data.length, 'browserOutput.html', 327); return; } data = dataJ; diff --git a/goon/code/datums/browserOutput.dm b/goon/code/datums/browserOutput.dm index aefb719afa4..27307cbccdb 100644 --- a/goon/code/datums/browserOutput.dm +++ b/goon/code/datums/browserOutput.dm @@ -99,6 +99,8 @@ var/list/chatResources = list( loaded = TRUE winset(owner, "browseroutput", "is-disabled=false") + if(owner.holder) + loadAdmin() for(var/message in messageQueue) to_chat(owner, message) @@ -119,6 +121,9 @@ var/list/chatResources = list( data = json_encode(data) C << output("[data]", "[window]:ehjaxCallback") +/datum/chatOutput/proc/loadAdmin() + var/data = json_encode(list("loadAdminCode" = replacetext(replacetext(file2text("goon/browserassets/html/adminOutput.html"), "\n", ""), "\t", ""))) + ehjax_send(data = url_encode(data)) /datum/chatOutput/proc/sendClientData() var/list/deets = list("clientData" = list()) diff --git a/html/changelog.html b/html/changelog.html index e4ae03dde1f..08b124beaf3 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,63 @@ -->
+

15 February 2017

+

Alexshreds updated:

+
    +
  • Coughing and sneezing now plays sounds.
  • +
+

Ausops updated:

+
    +
  • Internals and plasma tanks have been resprited.
  • +
+

FlimFlamm updated:

+
    +
  • New decals for boxes. Just apply a pen to change them (while they're open)!
  • +
+

KasparoVy updated:

+
    +
  • You can now choose to speak anonymously in deadchat from round-start game preferences.
  • +
  • Your decision to speak anonymously in deadchat now persists between ghostings.
  • +
  • Vox tails won't change colour when other Vox spawn in anymore.
  • +
+

Twinmold93 updated:

+
    +
  • Blob Conscious Split now properly scales the requirement of blob tiles to win.
  • +
+

uraniummeltdown updated:

+
    +
  • Borers now have action buttons
  • +
  • Borer names are now dependent on generation
  • +
+ +

14 February 2017

+

Developed by Cyberboss, ported by Markolie updated:

+
    +
  • Progress bars will now stack vertically.
  • +
  • Progress bars will no longer be affected by lighting.
  • +
+

DrunkDwarf updated:

+
    +
  • Adds a section to the Airlock menu of the RCD to allow specifying the name of the new Airlock
  • +
+

Fethas updated:

+
    +
  • You can no longer put anything THAT IS ALREADY A CULTIST IN A SOULSTONE....AT ALL.
  • +
  • Readds missing beserker robe sprite.
  • +
  • Cap growth serum at 1.5
  • +
+

Fox McCloud updated:

+
    +
  • Xenobiology console should be more responsive when using/exiting using it
  • +
  • Xenobiology console can now be loaded with a bag
  • +
  • Using monkey cubes on the Xenobiology console no longer makes you attempt to utilize the console
  • +
+

Markolie updated:

+
    +
  • The kinetic accelerator sprite modkits now apply properly when the kinetic accelerator is empty.
  • +
  • Welding tools now once again have a proper in-hand when turned on.
  • +
+

13 February 2017

Crazylemon64 updated:

    diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index e4e78e06518..4cdd47de027 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -3690,3 +3690,43 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. uraniummeltdown: - rscadd: Nuclear Operatives can customize the Declaration of War. - rscadd: The RSF has a unique sprite. +2017-02-14: + Developed by Cyberboss, ported by Markolie: + - tweak: Progress bars will now stack vertically. + - bugfix: Progress bars will no longer be affected by lighting. + DrunkDwarf: + - rscadd: Adds a section to the Airlock menu of the RCD to allow specifying the + name of the new Airlock + Fethas: + - bugfix: You can no longer put anything THAT IS ALREADY A CULTIST IN A SOULSTONE....AT + ALL. + - bugfix: Readds missing beserker robe sprite. + - tweak: Cap growth serum at 1.5 + Fox McCloud: + - tweak: Xenobiology console should be more responsive when using/exiting using + it + - tweak: Xenobiology console can now be loaded with a bag + - bugfix: Using monkey cubes on the Xenobiology console no longer makes you attempt + to utilize the console + Markolie: + - bugfix: The kinetic accelerator sprite modkits now apply properly when the kinetic + accelerator is empty. + - bugfix: Welding tools now once again have a proper in-hand when turned on. +2017-02-15: + Alexshreds: + - rscadd: Coughing and sneezing now plays sounds. + Ausops: + - rscadd: Internals and plasma tanks have been resprited. + FlimFlamm: + - rscadd: New decals for boxes. Just apply a pen to change them (while they're open)! + KasparoVy: + - rscadd: You can now choose to speak anonymously in deadchat from round-start game + preferences. + - tweak: Your decision to speak anonymously in deadchat now persists between ghostings. + - bugfix: Vox tails won't change colour when other Vox spawn in anymore. + Twinmold93: + - bugfix: Blob Conscious Split now properly scales the requirement of blob tiles + to win. + uraniummeltdown: + - rscadd: Borers now have action buttons + - tweak: Borer names are now dependent on generation diff --git a/icons/mob/actions.dmi b/icons/mob/actions.dmi index 0e2faafa2f5..3d0c7233c98 100644 Binary files a/icons/mob/actions.dmi and b/icons/mob/actions.dmi differ diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi index a05e783b307..7764cd6d0c5 100644 Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ diff --git a/icons/mob/belt.dmi b/icons/mob/belt.dmi index 68a273305a8..b6089236f2a 100644 Binary files a/icons/mob/belt.dmi and b/icons/mob/belt.dmi differ diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi index 5c12ccecd5b..0c9090c5b81 100644 Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi index 2a9a6774d27..0f889055ad0 100644 Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi index d56a42ca099..d915f6941a7 100644 Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ diff --git a/icons/obj/cardboard_boxes.dmi b/icons/obj/cardboard_boxes.dmi new file mode 100644 index 00000000000..3ef52c11bfb Binary files /dev/null and b/icons/obj/cardboard_boxes.dmi differ diff --git a/icons/obj/clothing/suits.dmi b/icons/obj/clothing/suits.dmi index b98c786872a..be68443c2bf 100644 Binary files a/icons/obj/clothing/suits.dmi and b/icons/obj/clothing/suits.dmi differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index 39b73d8052b..9b38b205075 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ diff --git a/icons/obj/tank.dmi b/icons/obj/tank.dmi index 1154fe08e33..ef5f6ad194e 100644 Binary files a/icons/obj/tank.dmi and b/icons/obj/tank.dmi differ diff --git a/nano/templates/rcd.tmpl b/nano/templates/rcd.tmpl index 073171a4ba7..e72b6253a17 100644 --- a/nano/templates/rcd.tmpl +++ b/nano/templates/rcd.tmpl @@ -12,6 +12,21 @@
{{else data.menu == 2}}
{{:helper.link('Back', 'reply', {'menu': 1})}}
+
+
+
+
+ {{if !data.locked}}{{:helper.link("Rename", '', {'choice' : 'airlock_name'})}}{{else}}LOCKED{{/if}} +
+
+ Airlock Name: +
+
+ {{:data.door_name}} +
+
+
+

Type

{{for data.allowed_door_types}} diff --git a/paradise.dme b/paradise.dme index b6e9c548620..c06882cd10d 100644 --- a/paradise.dme +++ b/paradise.dme @@ -435,7 +435,9 @@ #include "code\game\gamemodes\miniantags\abduction\machinery\experiment.dm" #include "code\game\gamemodes\miniantags\abduction\machinery\pad.dm" #include "code\game\gamemodes\miniantags\borer\borer.dm" +#include "code\game\gamemodes\miniantags\borer\borer_chemicals.dm" #include "code\game\gamemodes\miniantags\borer\borer_event.dm" +#include "code\game\gamemodes\miniantags\borer\borer_html.dm" #include "code\game\gamemodes\miniantags\bot_swarm\swarmer.dm" #include "code\game\gamemodes\miniantags\bot_swarm\swarmer_event.dm" #include "code\game\gamemodes\miniantags\guardian\guardian.dm" diff --git a/sound/effects/mob_effects/f_cougha.ogg b/sound/effects/mob_effects/f_cougha.ogg new file mode 100644 index 00000000000..f53e0f5bd2c Binary files /dev/null and b/sound/effects/mob_effects/f_cougha.ogg differ diff --git a/sound/effects/mob_effects/f_coughb.ogg b/sound/effects/mob_effects/f_coughb.ogg new file mode 100644 index 00000000000..2626f8d6621 Binary files /dev/null and b/sound/effects/mob_effects/f_coughb.ogg differ diff --git a/sound/effects/mob_effects/f_machine_cougha.ogg b/sound/effects/mob_effects/f_machine_cougha.ogg new file mode 100644 index 00000000000..e0a8441e3d4 Binary files /dev/null and b/sound/effects/mob_effects/f_machine_cougha.ogg differ diff --git a/sound/effects/mob_effects/f_machine_coughb.ogg b/sound/effects/mob_effects/f_machine_coughb.ogg new file mode 100644 index 00000000000..b70b6d16c14 Binary files /dev/null and b/sound/effects/mob_effects/f_machine_coughb.ogg differ diff --git a/sound/effects/mob_effects/f_machine_sneeze.ogg b/sound/effects/mob_effects/f_machine_sneeze.ogg new file mode 100644 index 00000000000..9649c862449 Binary files /dev/null and b/sound/effects/mob_effects/f_machine_sneeze.ogg differ diff --git a/sound/effects/mob_effects/f_sneeze.ogg b/sound/effects/mob_effects/f_sneeze.ogg new file mode 100644 index 00000000000..e6c4a49ade8 Binary files /dev/null and b/sound/effects/mob_effects/f_sneeze.ogg differ diff --git a/sound/effects/mob_effects/m_cougha.ogg b/sound/effects/mob_effects/m_cougha.ogg new file mode 100644 index 00000000000..146beefdf87 Binary files /dev/null and b/sound/effects/mob_effects/m_cougha.ogg differ diff --git a/sound/effects/mob_effects/m_coughb.ogg b/sound/effects/mob_effects/m_coughb.ogg new file mode 100644 index 00000000000..745fb50e19c Binary files /dev/null and b/sound/effects/mob_effects/m_coughb.ogg differ diff --git a/sound/effects/mob_effects/m_coughc.ogg b/sound/effects/mob_effects/m_coughc.ogg new file mode 100644 index 00000000000..abfe70d2769 Binary files /dev/null and b/sound/effects/mob_effects/m_coughc.ogg differ diff --git a/sound/effects/mob_effects/m_machine_cougha.ogg b/sound/effects/mob_effects/m_machine_cougha.ogg new file mode 100644 index 00000000000..3e803f64b1e Binary files /dev/null and b/sound/effects/mob_effects/m_machine_cougha.ogg differ diff --git a/sound/effects/mob_effects/m_machine_coughb.ogg b/sound/effects/mob_effects/m_machine_coughb.ogg new file mode 100644 index 00000000000..d1287070922 Binary files /dev/null and b/sound/effects/mob_effects/m_machine_coughb.ogg differ diff --git a/sound/effects/mob_effects/m_machine_coughc.ogg b/sound/effects/mob_effects/m_machine_coughc.ogg new file mode 100644 index 00000000000..67e13314934 Binary files /dev/null and b/sound/effects/mob_effects/m_machine_coughc.ogg differ diff --git a/sound/effects/mob_effects/machine_sneeze.ogg b/sound/effects/mob_effects/machine_sneeze.ogg new file mode 100644 index 00000000000..f0ba0ab8170 Binary files /dev/null and b/sound/effects/mob_effects/machine_sneeze.ogg differ diff --git a/sound/effects/mob_effects/sneeze.ogg b/sound/effects/mob_effects/sneeze.ogg new file mode 100644 index 00000000000..e7587bab20f Binary files /dev/null and b/sound/effects/mob_effects/sneeze.ogg differ diff --git a/sound/machines/terminal_alert.ogg b/sound/machines/terminal_alert.ogg new file mode 100644 index 00000000000..0f5006ee42c Binary files /dev/null and b/sound/machines/terminal_alert.ogg differ diff --git a/sound/machines/terminal_button01.ogg b/sound/machines/terminal_button01.ogg new file mode 100644 index 00000000000..362d81f3c57 Binary files /dev/null and b/sound/machines/terminal_button01.ogg differ diff --git a/sound/machines/terminal_button02.ogg b/sound/machines/terminal_button02.ogg new file mode 100644 index 00000000000..6df9b289b55 Binary files /dev/null and b/sound/machines/terminal_button02.ogg differ diff --git a/sound/machines/terminal_button03.ogg b/sound/machines/terminal_button03.ogg new file mode 100644 index 00000000000..3bd1e2c4259 Binary files /dev/null and b/sound/machines/terminal_button03.ogg differ diff --git a/sound/machines/terminal_button04.ogg b/sound/machines/terminal_button04.ogg new file mode 100644 index 00000000000..f9020380d0a Binary files /dev/null and b/sound/machines/terminal_button04.ogg differ diff --git a/sound/machines/terminal_button05.ogg b/sound/machines/terminal_button05.ogg new file mode 100644 index 00000000000..0bbfefe5273 Binary files /dev/null and b/sound/machines/terminal_button05.ogg differ diff --git a/sound/machines/terminal_button06.ogg b/sound/machines/terminal_button06.ogg new file mode 100644 index 00000000000..ecb521f272c Binary files /dev/null and b/sound/machines/terminal_button06.ogg differ diff --git a/sound/machines/terminal_button07.ogg b/sound/machines/terminal_button07.ogg new file mode 100644 index 00000000000..a6ed66bbf26 Binary files /dev/null and b/sound/machines/terminal_button07.ogg differ diff --git a/sound/machines/terminal_button08.ogg b/sound/machines/terminal_button08.ogg new file mode 100644 index 00000000000..2d35c62cc4c Binary files /dev/null and b/sound/machines/terminal_button08.ogg differ diff --git a/sound/machines/terminal_insert_disc.ogg b/sound/machines/terminal_insert_disc.ogg new file mode 100644 index 00000000000..07313dabaca Binary files /dev/null and b/sound/machines/terminal_insert_disc.ogg differ diff --git a/sound/machines/terminal_off.ogg b/sound/machines/terminal_off.ogg new file mode 100644 index 00000000000..4882aa924af Binary files /dev/null and b/sound/machines/terminal_off.ogg differ diff --git a/sound/machines/terminal_on.ogg b/sound/machines/terminal_on.ogg new file mode 100644 index 00000000000..95164b5b774 Binary files /dev/null and b/sound/machines/terminal_on.ogg differ diff --git a/sound/machines/terminal_prompt.ogg b/sound/machines/terminal_prompt.ogg new file mode 100644 index 00000000000..1ff4930a263 Binary files /dev/null and b/sound/machines/terminal_prompt.ogg differ diff --git a/sound/machines/terminal_prompt_confirm.ogg b/sound/machines/terminal_prompt_confirm.ogg new file mode 100644 index 00000000000..b838a764e8c Binary files /dev/null and b/sound/machines/terminal_prompt_confirm.ogg differ diff --git a/sound/machines/terminal_prompt_deny.ogg b/sound/machines/terminal_prompt_deny.ogg new file mode 100644 index 00000000000..c408c21625f Binary files /dev/null and b/sound/machines/terminal_prompt_deny.ogg differ