From f852d982358e938ee1c09af70541919162215936 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Wed, 4 May 2016 15:52:34 +0100 Subject: [PATCH 001/129] Datum Emotes MK II --- code/__HELPERS/global_lists.dm | 8 + code/_globalvars/lists/mobs.dm | 1 + code/datums/Emote system/emote.dm | 368 ++++++++++++++++++ code/datums/Emote system/emote_handler.dm | 84 ++++ code/datums/Emote system/emotes.dm | 91 +++++ code/game/gamemodes/blob/overmind.dm | 2 + code/game/gamemodes/miniantags/borer/borer.dm | 2 + code/modules/mob/dead/observer/say.dm | 21 +- code/modules/mob/emote.dm | 8 +- .../mob/living/carbon/alien/humanoid/emote.dm | 4 +- .../mob/living/carbon/alien/larva/emote.dm | 4 +- code/modules/mob/living/carbon/brain/emote.dm | 4 +- code/modules/mob/living/carbon/human/emote.dm | 3 +- code/modules/mob/living/carbon/slime/emote.dm | 4 +- code/modules/mob/living/say.dm | 5 +- code/modules/mob/living/silicon/emote.dm | 4 +- code/modules/mob/living/silicon/pai/emote.dm | 2 + .../modules/mob/living/silicon/robot/emote.dm | 4 +- code/modules/mob/living/silicon/say.dm | 4 +- .../mob/living/simple_animal/bot/emote.dm | 4 +- .../living/simple_animal/friendly/diona.dm | 14 +- code/modules/mob/mob.dm | 1 + code/modules/mob/mob_defines.dm | 2 + code/modules/mob/say.dm | 16 +- paradise.dme | 3 + 25 files changed, 620 insertions(+), 43 deletions(-) create mode 100644 code/datums/Emote system/emote.dm create mode 100644 code/datums/Emote system/emote_handler.dm create mode 100644 code/datums/Emote system/emotes.dm diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 36bb824e642..a8c548bdd7a 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -46,6 +46,14 @@ if(S.flags & IS_WHITELISTED) whitelisted_species += S.name + paths = subtypesof(/datum/emote) + for(var/T in paths) + var/datum/emote/E = new T + if(istype(T, /datum/emote/custom)) + continue + emotes += E + + init_subtypes(/datum/table_recipe, table_recipes) return 1 diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index b6dc1c58b8f..e1e8b818356 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -4,6 +4,7 @@ var/global/list/all_languages[0] var/global/list/language_keys[0] // Table of say codes for all languages var/global/list/all_superheroes[0] var/global/list/all_nations[0] +var/global/list/emotes[0] var/global/list/whitelisted_species = list() var/list/clients = list() //list of all clients diff --git a/code/datums/Emote system/emote.dm b/code/datums/Emote system/emote.dm new file mode 100644 index 00000000000..62c3c6a14d8 --- /dev/null +++ b/code/datums/Emote system/emote.dm @@ -0,0 +1,368 @@ +/******************************************************************************************************* + Emotes +Remember, only 1 instance of each emote is made, and used by all mobs that can access it. As such, the +ONLY place you can safely set object variables during runtime is in New(). Otherwise override the emote. +The only exception to this is custom emotes, which are created as needed and only last until they are finished +VampyrBytes + +*******************************************************************************************************/ + +/datum/emote + var/name = "" + var/desc = "" + var/list/commands[0] // commands that trigger the emote. Set these in New() + var/text = "" + var/selfText = "" // the version of text that you should see - eg, if text is screams, you want scream here, as You screams is bad grammer + var/startText = "" // if you need to put something in before [user]. Should end with a space + var/mimeText = "" + var/sound // sound file + var/vol = 50 + var/audible = 0 + var/muzzledNoise = "" // if the emote is audible and you're muzzled, this is what type of noise you make (eg weak, loud). End with a space + var/restrained = "" // 1 if being restrained prevents this emote + var/cooldown = 0 + + var/canTarget = 0 // 1 if the emote accepts a target Emotes only recieve 1 parameter, so its either or with these 2 + var/takesParam = 0 // 1 if the emote uses a non target parameter + + var/targetMob = 0 // 0 if target can be any atom, 1 if it has to be a mob + var/targetText = "at" // what goes inbetween user and target + var/spanClass = "notice" + var/baseLevel = 1 + var/baseSet = 0 + + +/datum/emote/New() + var/pathString = "[type]" + var/count = 0 + for(var/i in 1 to lentext(pathString)) + var/char = copytext(pathString, i, i+1) + if(char == "/") + count++ + if(count == 4) + baseLevel = 0 + break + +/datum/emote/proc/doEmote(var/mob/user, var/param) + if(!istype(user)) + return 0 + if(cooldown) + if(handle_emote_CD(user)) + return 0 + + var/message = createMessage(user, param) + + if(canTarget && param) + param = getTarget(user, param) + + if(message) + message = addTarget(user, param, message) + message += "" + outputMessage(user, message) + + if(audible) + if(!(user.mind && user.mind.miming)) + playSound(user, vol) + + doAction(user, param) + return 1 + +// for things that the emote does that aren't text or sound based +/datum/emote/proc/doAction(var/mob/user, var/param) + return + +// returns the reason the user can't currently do the emote +/datum/emote/proc/prevented(var/mob/user) + if(user.stat == DEAD) + return "you are dead" + if(restrained && user.restrained()) + return "you are restrained" + +// return 1 if this emote can be used by this type of user +/datum/emote/proc/available(var/mob/user) + return + +/datum/emote/proc/createMessage(var/mob/user, var/param) + if(!text) + return + var/message + if(audible && user.mind && user.mind.miming) + message = mimeMessage(user) + else if(audible && user.is_muzzled()) + message = muzzleMessage(user) + else if(takesParam && param) + message = paramMessage(user, param) + else + message = "[startText + " "][user] [text]" + return message + +/datum/emote/proc/mimeMessage(var/mob/user) + if(!mimeText) + return + + var/message = "[startText + " "][user] [mimeText]" + return message + +/datum/emote/proc/muzzleMessage(var/mob/user) + var/message = "makes a [muzzledNoise + " "]noise" + return message + +// if the emote takes a non target parameter, set up and return the with parameter version in here +/datum/emote/proc/paramMessage(var/mob/user, var/param) + return + +/datum/emote/proc/addTarget(var/mob/user, var/target = "", var/message = "") + if(!canTarget) + return message + target = getTarget(user, target) + if(!target) + return message + if(ismob(target)) + message += " [targetText] [target]" + else + message += " [targetText] \the [target]" + return message + +/datum/emote/proc/getTarget(var/mob/user, var/target = "") + if(!target) + return + if(targetMob) + return getMobTarget(user, target) + else + return getAtomTarget(user, target) + +/datum/emote/proc/getMobTarget(var/mob/user, var/target = "") + for (var/mob/M in view(null, user)) + if (target == M.name) + return M + +/datum/emote/proc/getAtomTarget(var/mob/user, var/target = "") + if (target) + for (var/atom/A as mob|obj|turf in view(null, user)) + if (target == A.name) + return A + +/datum/emote/proc/outputMessage(var/mob/user, var/message = "") + if(!message) + return + log_emote("[user.name]/[user.key] : [message]") + if(audible) + audible_message(message, user) + else + visible_message(message, user) + sendToDead(message) + +// What you should see when you perform the emote +/datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") + var/selfMessage + if(startText) + selfMessage = replacetext(message, "[user]", "you") + else + selfMessage = replacetext(message, "[user]", "You") + if(selfText) + selfMessage = replacetext(selfMessage, text, selfText) + return selfMessage + +/datum/emote/proc/visible_message(var/message = "", var/mob/user) + var/selfMessage = createSelfMessage(user, message) + for(var/mob/M in viewers(user)) + if(M.see_invisible < user.invisibility) + continue //can't view the invisible + var/msg = message + if(selfMessage && M==user) + msg = selfMessage + if(M.sdisabilities & BLIND || M.blinded || M.paralysis) + if(M.sdisabilities & DEAF || M.ear_deaf) + continue + msg = createBlindMessage(message, user) + if(msg) + outputAudibleMessage(msg, M, user, 1) + else + outputVisibleMessage(msg, M, user) + +/datum/emote/proc/audible_message(var/message = "", var/mob/user) + var/selfMessage = createSelfMessage(user, message) + testing(selfMessage) + for(var/mob/M in get_mobs_in_view(7, user)) + var/msg = message + if(selfMessage && M==src) + msg = selfMessage + if(M.sdisabilities & DEAF || M.ear_deaf) + if(M.sdisabilities & BLIND || M.blinded || M.paralysis) + continue + msg = createDeafMessage(user, message) + if(msg) + outputVisibleMessage(msg, M, user, 1) + else + outputAudibleMessage(msg, M, user) + +/datum/emote/proc/outputVisibleMessage(var/message, var/mob/recipient, var/mob/user, var/retest = 0) + if(retest) + if(!user) + return + var/found = 0 + for(var/mob/M in viewers(user)) + if(M == recipient) + found = 1 + if(recipient.see_invisible < user.invisibility) + return + break + if(!found) + return + if(recipient.sdisabilities & DEAF || recipient.ear_deaf) + var/msg = createDeafMessage(user, message) + if(msg) + message = msg + if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) + to_chat(recipient, "... You can almost hear someone talking ...") + else + to_chat(recipient, message) + +/datum/emote/proc/outputAudibleMessage(var/message = "", var/mob/recipient, var/mob/user, var/retest = 0) + if(retest) + if(!user) + return + var/found = 0 + for(var/mob/M in get_mobs_in_view(7, user)) + if(M == recipient) + found = 1 + break + if(!found) + return + if(recipient.sdisabilities & BLIND || recipient.blinded || recipient.paralysis) + var/msg = createBlindMessage(user, message) + if(msg) + message = msg + if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) + to_chat(recipient, "... You can almost hear someone talking ...") + else + to_chat(recipient, message) + +// set up different messages for blind people here. Empty will mean no message for +//non-audible emotes and the standard message for audible ones +/datum/emote/proc/createBlindMessage(var/mob/user, var/message) + return + +// set up different messages for deaf people here. Empty will mean no message for +// audible emotes and standard for non-audible ones +/datum/emote/proc/createDeafMessage(var/mob/user, var/message) + return + +/datum/emote/proc/sendToDead(message) + for(var/mob/M in dead_mob_list) + if(!M.client || istype(M, /mob/new_player)) + continue //skip monkeys, leavers and new players + if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) + M.show_message(message) + +/datum/emote/proc/playSound(var/mob/user) + if(sound) + playsound(user, sound, vol) + +//Emote Cooldown System (it's so simple!) +/datum/emote/proc/handle_emote_CD(var/mob/user) + if(user.emote_cd == 2) return 1 // Cooldown emotes were disabled by an admin, prevent use + if(user.emote_cd == 1) return 1 // Already on CD, prevent use + + user.emote_cd = 1 // Starting cooldown + spawn(cooldown) + if(user.emote_cd == 2) return 1 // Don't reset if cooldown emotes were disabled by an admin during the cooldown + user.emote_cd = 0 // Cooldown complete, ready for more! + + return 0 // Proceed with emote +//--FalseIncarnate + +/datum/emote/proc/addVerbs(var/mob/user) + if(!istype(user)) + return + new /obj/emoteVerb(user, src, commands) + +// Dummy object to allow access to the verb, needed as verbs require a valid loc for setting the src +/obj/emoteVerb + var/datum/emote/emote + var/mob/owner + +/obj/emoteVerb/New(var/mob/user, var/datum/emote/toAccess) + if(!(istype(user))) + return + if(!(istype(toAccess))) + return + if(!toAccess.commands) + return + owner = user + emote = toAccess + name = emote.name + loc = user + user.verbs += new/obj/emoteVerb/proc/runEmote(src, emote.commands[1], emote.desc) + +/obj/emoteVerb/proc/runEmote() + set src = usr.contents + set category = "Emotes" + usr.emoteHandler.runEmote(emote.commands[1]) + +/obj/emoteVerb/Destroy() + owner.verbs -= new/obj/emoteVerb/proc/runEmote(src, emote.commands[1]) + ..() + +/obj/emoteVerb/custom + +obj/emoteVerb/custom/New(var/mob/user) + if(!(istype(user))) + return + owner = user + name = "custom" + user.verbs += new/obj/emoteVerb/proc/runEmote(src, "custom", "Make your own emote") + +/obj/emoteVerb/custom/runEmote(message as text, audible as num) + set src = usr.contents + set category = "Emotes" + usr.emoteHandler.runEmote("me", null, message, audible) + +/************************************************************************************************************************** + Custom Emotes +As these are made as needed, they aren't searched for the appropriate one. As such, you need to specify conditions for which +one is used in /datum/emote_handler/customEmote(). As the checks for the type are done there, you chouldn't need to override +available, but if you do, make sure you return ..() so the check for use_me is still done - VampyrBytes + +***************************************************************************************************************************/ + +/datum/emote/custom + name = "Custom emote" + baseLevel = 0 + +/datum/emote/custom/New(var/mob/user, var/message = "", var/isAudible) + if(!message) + message = getMessage(user) + text = message + audible = isAudible + if(user.mind && user.mind.miming) + audible = 0 + +/datum/emote/custom/proc/getMessage(var/mob/user) + var/input = sanitize(copytext(input(user,"Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN)) + return input + +/datum/emote/custom/available(var/mob/user) + if(user.use_me) + return 1 + +/datum/emote/custom/ghost + name = "Ghost emote" + startText = "DEAD: " + spanClass = "game deadsay" + +/datum/emote/custom/ghost/prevented(var/mob/user) + if(user.client.prefs.muted & MUTE_DEADCHAT) + return "you are muted from deadchat" + if(!(user.client.prefs.toggles & CHAT_DEAD)) + return "you have deadchat muted" + if(!user.client.holder) + if(!config.dsay_allowed) + return "deadchat is globally muted" + +/datum/emote/custom/ghost/outputMessage(var/mob/user, var/message = "") + if(!message) + return + log_emote("Ghost/[user.key] : [message]") + sendToDead(message) + diff --git a/code/datums/Emote system/emote_handler.dm b/code/datums/Emote system/emote_handler.dm new file mode 100644 index 00000000000..afcb4f0253b --- /dev/null +++ b/code/datums/Emote system/emote_handler.dm @@ -0,0 +1,84 @@ +/datum/emoteHandler + var/mob/owner + var/list/commands + +/datum/emoteHandler/New(var/mob/user) + owner = user + setupCommands() + +/datum/emoteHandler/proc/setupCommands(var/reset = 0) + if(reset) + deleteEmoteVerbs() + commands = new/list() + for(var/e in emotes) + var/datum/emote/emote = e + if(emote.baseLevel) + var/datum/emote/found = searchTree(emote) + if(found) + for(var/command in found.commands) + commands[command] = found + found.addVerbs(owner) + +/datum/emoteHandler/proc/deleteEmoteVerbs() + for(var/obj/emoteVerb/E in owner.contents) + qdel(E) + +/datum/emoteHandler/proc/runEmote(var/command = "", var/param = "", var/message = "", var/audible = 0) // message and audible only used in custom emotes + if(!command) + return 0 + if(command == "help") + showCommands() + return 1 + + var/datum/emote/emote + //testing("[command]") + if(command == "me") + emote = customEmote(message, audible) + if(!emote) + return 0 + if(!commands[command] && !(command == "me")) + to_chat(owner, "Unknown emote, please check *help for emotes available to your character") + return 0 + if(!emote) + emote = commands[command] + if(!emote.available(owner)) // something's changed, remake the commands list, then try again to see if they've got a different version + setupCommands() + return runEmote(command, param, message) + + var/prevented = emote.prevented(owner) + if(prevented) + to_chat(owner, "You can't do that because [prevented]!") + return 0 + return emote.doEmote(owner) + +/datum/emoteHandler/proc/showCommands() + var/emoteList = "Available emotes are " + var/commandAdded = 0 + for (var/c in commands) + if(commandAdded) + emoteList += ", " + emoteList += c + commandAdded = 1 + + to_chat(owner, emoteList) + +// recursive search of subtypes - starts checking at the lowest level and breaks out if it finds one that can be done +/datum/emoteHandler/proc/searchTree(var/datum/emote/emote) + var/list/subtypes = subtypesof(emote.type) + var/datum/emote/found + for(var/t in subtypes) + var/datum/emote/em = new t // not keen on this, but it's this or loop through the emotes list and the + found = searchTree(em) // thought of a nested for loop in a recursive proc makes me want to *cry - VB + if(found) + return (found) + if(emote.available(owner)) + return emote + +/datum/emoteHandler/proc/customEmote(var/custom, var/audible) + var/datum/emote/custom/emote + if(isobserver(owner)) + emote = new /datum/emote/custom/ghost + else + emote = new /datum/emote/custom(owner, custom, audible) + if (emote.available(owner)) + return emote diff --git a/code/datums/Emote system/emotes.dm b/code/datums/Emote system/emotes.dm new file mode 100644 index 00000000000..5ab3b76b56d --- /dev/null +++ b/code/datums/Emote system/emotes.dm @@ -0,0 +1,91 @@ +/************************************************************************************ + Emotes +New() must call ..() to set the baseLevel for the emoteHandler search. As the commands +are set in New(), this means that the emote will pick up all the commands from the emotes +above it. If you don't want this, make the call to ..() then use commands = new /list() +*************************************************************************************/ + +/datum/emote/scream + name = "scream" + text = "screams!" + selfText = "scream!" + audible = 1 + mimeText = "acts out a scream" + muzzledNoise = "very loud " + cooldown = 50 + vol = 80 + +/datum/emote/scream/New() + ..() + commands += "scream" + commands += "screams" + +/datum/emote/scream/available(var/mob/user) + if(isliving(user)) + return 1 + +/datum/emote/scream/machine + name = "machine scream" + sound = 'sound/goonstation/voice/robot_scream.ogg' + +/datum/emote/scream/machine/available(var/mob/user) + if(issilicon(user)) + return 1 + if(istype(user, /mob/living/simple_animal/bot)) + return 1 + +/datum/emote/scream/human + name = "human scream" + +/datum/emote/scream/human/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/scream/human/playSound(var/mob/user) + var/mob/living/carbon/human/H = user + if(H.gender == FEMALE) + playsound(H, "[H.species.female_scream_sound]", vol, 1, 0, pitch = H.get_age_pitch()) + else + playsound(H, "[H.species.male_scream_sound]", vol, 1, 0, pitch = H.get_age_pitch()) + +/datum/emote/fart + name = "fart" + cooldown = 50 + +/datum/emote/fart/New() + ..() + commands += "fart" + commands += "farts" + +/datum/emote/fart/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/fart/doAction(var/mob/user) + // todo change this to work with superfarts + if(TOXIC_FARTS in user.mutations) + for(var/mob/M in range(get_turf(user),2)) + if (M.internal != null && M.wear_mask && (M.wear_mask.flags & AIRTIGHT)) + continue + if (M == user) + continue + M.reagents.add_reagent("space_drugs",rand(1,10)) + + if(locate(/obj/item/weapon/storage/bible) in get_turf(user)) + to_chat(viewers(user), "[user] farts on the Bible!") + to_chat(viewers(user), "A mysterious force smites [user]!") + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(3, 1, user) + s.start() + user.gib() + +/datum/emote/fart/createMessage(var/mob/user) + var/message + if(TOXIC_FARTS in user.mutations) + message = "[user] unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart." + else + message = "[user] [pick("passes wind","farts")]." + return message + + + diff --git a/code/game/gamemodes/blob/overmind.dm b/code/game/gamemodes/blob/overmind.dm index 1238adebcf5..8b3d599f50a 100644 --- a/code/game/gamemodes/blob/overmind.dm +++ b/code/game/gamemodes/blob/overmind.dm @@ -103,8 +103,10 @@ if(isovermind(M) || isobserver(M)) M.show_message(rendered, 2) +/* /mob/camera/blob/emote(var/act,var/m_type=1,var/message = null) return +*/ /mob/camera/blob/blob_act() return diff --git a/code/game/gamemodes/miniantags/borer/borer.dm b/code/game/gamemodes/miniantags/borer/borer.dm index 9e25a50a811..401a1731b7c 100644 --- a/code/game/gamemodes/miniantags/borer/borer.dm +++ b/code/game/gamemodes/miniantags/borer/borer.dm @@ -33,8 +33,10 @@ return 0 return B.host.say_understands(other, speaking) +/* /mob/living/captive_brain/emote(var/message) return +*/ /mob/living/captive_brain/resist_borer() var/mob/living/simple_animal/borer/B = loc diff --git a/code/modules/mob/dead/observer/say.dm b/code/modules/mob/dead/observer/say.dm index 7f63a8f1261..022fbb85a5d 100644 --- a/code/modules/mob/dead/observer/say.dm +++ b/code/modules/mob/dead/observer/say.dm @@ -16,29 +16,14 @@ . = src.say_dead(message) - +/* /mob/dead/observer/emote(var/act, var/type, var/message) message = sanitize(copytext(message, 1, MAX_MESSAGE_LEN)) - if(!message) - return + if(act = "me") + return ..() - if(act != "me") - return - log_emote("Ghost/[src.key] : [message]") - - if(src.client) - if(src.client.prefs.muted & MUTE_DEADCHAT) - to_chat(src, "\red You cannot emote in deadchat (muted).") - return - - if(src.client.handle_spam_prevention(message, MUTE_DEADCHAT)) - return - - . = src.emote_dead(message) - -/* for (var/mob/M in hearers(null, null)) if (!M.stat) if(M.job == "Chaplain") diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 8d03cdd969a..1c82e1c2755 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -1,6 +1,7 @@ #define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts //Emote Cooldown System (it's so simple!) +/* /mob/proc/handle_emote_CD(cooldown = EMOTE_COOLDOWN) if(emote_cd == 2) return 1 // Cooldown emotes were disabled by an admin, prevent use if(src.emote_cd == 1) return 1 // Already on CD, prevent use @@ -12,11 +13,13 @@ return 0 // Proceed with emote //--FalseIncarnate - +*/ // All mobs should have custom emote, really.. /mob/proc/custom_emote(var/m_type=1,var/message = null) - if(stat || !use_me && usr == src) + emoteHandler.runEmote("me", null, message, m_type) + +/* if(stat || !use_me && usr == src) to_chat(usr, "You are unable to emote.") return @@ -122,3 +125,4 @@ else if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_DEAD)) // Show the emote to regular ghosts with deadchat toggled on M.show_message(message, 2) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/humanoid/emote.dm b/code/modules/mob/living/carbon/alien/humanoid/emote.dm index caf3cc4e5ad..79445eec13a 100644 --- a/code/modules/mob/living/carbon/alien/humanoid/emote.dm +++ b/code/modules/mob/living/carbon/alien/humanoid/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/carbon/alien/humanoid/emote(var/act,var/m_type=1,var/message = null) var/param = null if (findtext(act, "-", 1, null)) @@ -112,4 +113,5 @@ playsound(src.loc, 'sound/voice/hiss5.ogg', 40, 1, 1) if (act == "deathgasp") playsound(src.loc, 'sound/voice/hiss6.ogg', 80, 1, 1) - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/alien/larva/emote.dm b/code/modules/mob/living/carbon/alien/larva/emote.dm index b617a1fc883..72be5c029fa 100644 --- a/code/modules/mob/living/carbon/alien/larva/emote.dm +++ b/code/modules/mob/living/carbon/alien/larva/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/carbon/alien/larva/emote(var/act,var/m_type=1,var/message = null) var/param = null if (findtext(act, "-", 1, null)) @@ -123,4 +124,5 @@ for(var/mob/O in hearers(src, null)) O.show_message(message, m_type) //Foreach goto(746) - return \ No newline at end of file + return +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/brain/emote.dm b/code/modules/mob/living/carbon/brain/emote.dm index fd2a4879c9d..b173ac63460 100644 --- a/code/modules/mob/living/carbon/brain/emote.dm +++ b/code/modules/mob/living/carbon/brain/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/carbon/brain/emote(var/act,var/m_type=1,var/message = null) if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes return @@ -47,4 +48,5 @@ to_chat(src, "alarm, alert, notice, flash,blink, whistle, beep, boop") if(message && !stat) - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index 657d40983de..96c05ee627a 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/carbon/human/emote(var/act,var/m_type=1,var/message = null,var/force) if (stat == DEAD) @@ -836,7 +837,7 @@ visible_message(message) if(2) audible_message(message) - +*/ /mob/living/carbon/human/verb/pose() set name = "Set Pose" set desc = "Sets a description which will be shown when someone examines you." diff --git a/code/modules/mob/living/carbon/slime/emote.dm b/code/modules/mob/living/carbon/slime/emote.dm index 64838a1704d..dfb0b9cada8 100644 --- a/code/modules/mob/living/carbon/slime/emote.dm +++ b/code/modules/mob/living/carbon/slime/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null) if (findtext(act, "-", 1, null)) var/t1 = findtext(act, "-", 1, null) @@ -71,4 +72,5 @@ for(var/mob/O in hearers(src, null)) O.show_message(message, m_type) //Foreach goto(746) - return \ No newline at end of file + return +*/ \ No newline at end of file diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 3260015f64b..28f30b58714 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -287,7 +287,8 @@ proc/get_radio_key_from_channel(var/channel) /mob/living/emote(var/act, var/type, var/message) //emote code is terrible, this is so that anything that isn't if(stat) return 0 //already snowflaked to shit can call the parent and handle emoting sanely - + return ..() +/* if(..(act, type, message)) return 1 @@ -312,7 +313,7 @@ proc/get_radio_key_from_channel(var/channel) else //everything else failed, emote is probably invalid if(act == "help") return //except help, because help is handled individually to_chat(src, "\blue Unusable emote '[act]'. Say *help for a list.") - +*/ /mob/living/whisper(message as text) message = trim_strip_html_properly(message) diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm index c5c3603466e..0b9d0a7bb0f 100644 --- a/code/modules/mob/living/silicon/emote.dm +++ b/code/modules/mob/living/silicon/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/silicon/emote(var/act, var/m_type=1, var/message = null) var/param = null if (findtext(act, "-", 1, null)) @@ -117,4 +118,5 @@ if("help") to_chat(src, "yes, no, beep, ping, buzz") - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/pai/emote.dm b/code/modules/mob/living/silicon/pai/emote.dm index a418c0972d5..40c32f9fcc3 100644 --- a/code/modules/mob/living/silicon/pai/emote.dm +++ b/code/modules/mob/living/silicon/pai/emote.dm @@ -1,2 +1,4 @@ +/* // what the hell was the point of this file! /mob/living/silicon/pai/emote(var/act, var/m_type=1, var/message = null) ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/robot/emote.dm b/code/modules/mob/living/silicon/robot/emote.dm index 30273aec02c..3d438296ec3 100644 --- a/code/modules/mob/living/silicon/robot/emote.dm +++ b/code/modules/mob/living/silicon/robot/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/silicon/robot/emote(var/act, var/m_type=1, var/message = null) var/param = null if (findtext(act, "-", 1, null)) @@ -159,4 +160,5 @@ if ("help") to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitches, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look,\n law, halt") - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/silicon/say.dm b/code/modules/mob/living/silicon/say.dm index a546e164901..be3b778cb3c 100644 --- a/code/modules/mob/living/silicon/say.dm +++ b/code/modules/mob/living/silicon/say.dm @@ -129,11 +129,13 @@ return 1 /mob/living/silicon/ai/emote(var/act, var/type, var/message) +/* var/obj/machinery/hologram/holopad/T = src.holo if(T && T.hologram && T.master == src) //Is the AI using a holopad? src.holopad_emote(message) else //Emote normally, then. - ..() +*/ + ..() #undef IS_AI #undef IS_ROBOT diff --git a/code/modules/mob/living/simple_animal/bot/emote.dm b/code/modules/mob/living/simple_animal/bot/emote.dm index 4054e520ecf..ba8b1d86daf 100644 --- a/code/modules/mob/living/simple_animal/bot/emote.dm +++ b/code/modules/mob/living/simple_animal/bot/emote.dm @@ -1,3 +1,4 @@ +/* /mob/living/simple_animal/bot/emote(var/act, var/m_type=1, var/message = null) var/param = null if (findtext(act, "-", 1, null)) @@ -116,4 +117,5 @@ playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0) m_type = 2 - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) +*/ \ No newline at end of file diff --git a/code/modules/mob/living/simple_animal/friendly/diona.dm b/code/modules/mob/living/simple_animal/friendly/diona.dm index 4606558d271..7a8a682e7af 100644 --- a/code/modules/mob/living/simple_animal/friendly/diona.dm +++ b/code/modules/mob/living/simple_animal/friendly/diona.dm @@ -250,18 +250,19 @@ return /mob/living/simple_animal/diona/emote(var/act, var/m_type=1, var/message = null) - if(stat) + if(stat) return - + ..() + /* var/on_CD = 0 switch(act) if("chirp") - on_CD = handle_emote_CD() + on_CD = handle_emote_CD() else - on_CD = 0 + on_CD = 0 if(on_CD == 1) - return + return switch(act) //IMPORTANT: Emotes MUST NOT CONFLICT anywhere along the chain. if("chirp") @@ -269,4 +270,5 @@ m_type = 2 //audible playsound(src, 'sound/misc/nymphchirp.ogg', 40, 1, 1) - ..(act, m_type, message) \ No newline at end of file + ..(act, m_type, message) + */ \ No newline at end of file diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 658959001a1..36c7d172488 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -21,6 +21,7 @@ else living_mob_list += src prepare_huds() + emoteHandler = new /datum/emoteHandler(src) ..() /atom/proc/prepare_huds() diff --git a/code/modules/mob/mob_defines.dm b/code/modules/mob/mob_defines.dm index 8b4b39e006a..5151d9adab9 100644 --- a/code/modules/mob/mob_defines.dm +++ b/code/modules/mob/mob_defines.dm @@ -232,3 +232,5 @@ var/datum/vision_override/vision_type = null //Vision override datum. var/list/permanent_huds = list() + + var/datum/emoteHandler/emoteHandler \ No newline at end of file diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index e5b12ed022b..43248d54db4 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -34,10 +34,7 @@ message = strip_html_properly(message) set_typing_indicator(0) - if(use_me) - custom_emote(usr.emote_type, message) - else - usr.emote(message) + emoteHandler.runEmote("me", null, message) /mob/proc/say_dead(var/message) if(!src.client.holder) @@ -98,8 +95,15 @@ /mob/proc/emote(var/act, var/type, var/message) - if(act == "me") - return custom_emote(type, message) + var/param + if (findtext(act, "-", 1, null)) + var/t1 = findtext(act, "-", 1, null) + param = copytext(act, t1 + 1, length(act) + 1) + act = copytext(act, 1, t1) + + emoteHandler.runEmote(act, param, message, type) + + /mob/proc/get_ear() // returns an atom representing a location on the map from which this diff --git a/paradise.dme b/paradise.dme index 3a5da1134eb..b8e3c3dd148 100644 --- a/paradise.dme +++ b/paradise.dme @@ -258,6 +258,9 @@ #include "code\datums\diseases\advance\symptoms\weakness.dm" #include "code\datums\diseases\advance\symptoms\weight.dm" #include "code\datums\diseases\advance\symptoms\youth.dm" +#include "code\datums\Emote system\emote.dm" +#include "code\datums\Emote system\emote_handler.dm" +#include "code\datums\Emote system\emotes.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\global_iterator.dm" From 974d09da59a9ed8d50dac838c3060b31ee674571 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Thu, 5 May 2016 17:40:08 +0100 Subject: [PATCH 002/129] Params Adds support for params. A few other little tweaks too --- .../{Emote system => Emote_system}/emote.dm | 137 +++++++++++------- .../emote_handler.dm | 5 +- .../{Emote system => Emote_system}/emotes.dm | 34 +++++ code/modules/mob/say.dm | 9 +- paradise.dme | 6 +- 5 files changed, 129 insertions(+), 62 deletions(-) rename code/datums/{Emote system => Emote_system}/emote.dm (81%) rename code/datums/{Emote system => Emote_system}/emote_handler.dm (92%) rename code/datums/{Emote system => Emote_system}/emotes.dm (78%) diff --git a/code/datums/Emote system/emote.dm b/code/datums/Emote_system/emote.dm similarity index 81% rename from code/datums/Emote system/emote.dm rename to code/datums/Emote_system/emote.dm index 62c3c6a14d8..f0a7e6ddb1b 100644 --- a/code/datums/Emote system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -22,11 +22,11 @@ VampyrBytes var/restrained = "" // 1 if being restrained prevents this emote var/cooldown = 0 - var/canTarget = 0 // 1 if the emote accepts a target Emotes only recieve 1 parameter, so its either or with these 2 - var/takesParam = 0 // 1 if the emote uses a non target parameter - - var/targetMob = 0 // 0 if target can be any atom, 1 if it has to be a mob + var/canTarget = 0 // 1 if the emote accepts a target + var/targetMob = 0 // 0 if target can be any atom, 1 if it has to be a mob, var/targetText = "at" // what goes inbetween user and target + var/takesNumber = 0 // 1 if the emote uses a number parameter + var/spanClass = "notice" var/baseLevel = 1 var/baseSet = 0 @@ -43,20 +43,31 @@ VampyrBytes baseLevel = 0 break -/datum/emote/proc/doEmote(var/mob/user, var/param) +/datum/emote/proc/doEmote(var/mob/user) if(!istype(user)) return 0 if(cooldown) if(handle_emote_CD(user)) return 0 - var/message = createMessage(user, param) + var/number + var/target - if(canTarget && param) - param = getTarget(user, param) + if(takesNumber) + number = getNumber(user) + + if(canTarget) + target = getTarget(user) + + if(number == "failed" || target == "failed") // If you need to test the input, override the appopriate get proc, call the parent, + return // then test it. If it fails, tell the user why, then return "failed" to halt the emote + + var/message = createMessage(user, number) + + if(canTarget && message) + message = addTarget(user, target, message) if(message) - message = addTarget(user, param, message) message += "" outputMessage(user, message) @@ -64,13 +75,30 @@ VampyrBytes if(!(user.mind && user.mind.miming)) playSound(user, vol) - doAction(user, param) + doAction(user, target, number) return 1 // for things that the emote does that aren't text or sound based -/datum/emote/proc/doAction(var/mob/user, var/param) +/datum/emote/proc/doAction(var/mob/user, var/atom/target, var/number) return +/datum/emote/proc/getNumber(var/mob/user) + var/number = input("How many") as null|num + return number + +/datum/emote/proc/getTarget(var/mob/user) + if(targetMob) + return getMobTarget() + return getAtomTarget() + +/datum/emote/proc/getMobTarget() + var/mob/target = input("Select target", "Target Mob") as null|mob in view() + return target + +/datum/emote/proc/getAtomTarget() + var/atom/target = input("Select target", "Target") as null|mob|obj|turf in oview() + return target + // returns the reason the user can't currently do the emote /datum/emote/proc/prevented(var/mob/user) if(user.stat == DEAD) @@ -82,39 +110,58 @@ VampyrBytes /datum/emote/proc/available(var/mob/user) return -/datum/emote/proc/createMessage(var/mob/user, var/param) +/datum/emote/proc/createMessage(var/mob/user, var/number) if(!text) return var/message - if(audible && user.mind && user.mind.miming) + if(takesNumber && number) + message = getParamMessage(user, number) + else if(audible && user.mind && user.mind.miming) message = mimeMessage(user) else if(audible && user.is_muzzled()) message = muzzleMessage(user) - else if(takesParam && param) - message = paramMessage(user, param) else - message = "[startText + " "][user] [text]" + message = "[user] [text]" + if(startText) + message = "[startText] [message]" + message = "[message]" return message /datum/emote/proc/mimeMessage(var/mob/user) if(!mimeText) return - var/message = "[startText + " "][user] [mimeText]" + var/message = "[user] [mimeText]" return message /datum/emote/proc/muzzleMessage(var/mob/user) - var/message = "makes a [muzzledNoise + " "]noise" + var/message = "[user] makes a " + if(muzzledNoise) + message += "[muzzledNoise] " + message += "noise" + return message + +/datum/emote/proc/getParamMessage(var/mob/user, var/param) + var/message + if(audible && user.mind && user.mind.miming) + message = paramMimeMessage(user, param) + else if (audible && user.is_muzzled()) + message = muzzleMessage(user) + else + message = paramMessage(user, param) return message // if the emote takes a non target parameter, set up and return the with parameter version in here /datum/emote/proc/paramMessage(var/mob/user, var/param) return -/datum/emote/proc/addTarget(var/mob/user, var/target = "", var/message = "") +// as above, but for mimes trying to do audible messages +/datum/emote/proc/paramMimeMessage(var/mob/user, var/param) + return + +/datum/emote/proc/addTarget(var/mob/user, var/atom/target, var/message = "") if(!canTarget) return message - target = getTarget(user, target) if(!target) return message if(ismob(target)) @@ -123,35 +170,6 @@ VampyrBytes message += " [targetText] \the [target]" return message -/datum/emote/proc/getTarget(var/mob/user, var/target = "") - if(!target) - return - if(targetMob) - return getMobTarget(user, target) - else - return getAtomTarget(user, target) - -/datum/emote/proc/getMobTarget(var/mob/user, var/target = "") - for (var/mob/M in view(null, user)) - if (target == M.name) - return M - -/datum/emote/proc/getAtomTarget(var/mob/user, var/target = "") - if (target) - for (var/atom/A as mob|obj|turf in view(null, user)) - if (target == A.name) - return A - -/datum/emote/proc/outputMessage(var/mob/user, var/message = "") - if(!message) - return - log_emote("[user.name]/[user.key] : [message]") - if(audible) - audible_message(message, user) - else - visible_message(message, user) - sendToDead(message) - // What you should see when you perform the emote /datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") var/selfMessage @@ -163,6 +181,16 @@ VampyrBytes selfMessage = replacetext(selfMessage, text, selfText) return selfMessage +/datum/emote/proc/outputMessage(var/mob/user, var/message = "") + if(!message) + return + log_emote("[user.name]/[user.key] : [message]") + if(audible) + audible_message(message, user) + else + visible_message(message, user) + sendToDead(message) + /datum/emote/proc/visible_message(var/message = "", var/mob/user) var/selfMessage = createSelfMessage(user, message) for(var/mob/M in viewers(user)) @@ -182,7 +210,6 @@ VampyrBytes /datum/emote/proc/audible_message(var/message = "", var/mob/user) var/selfMessage = createSelfMessage(user, message) - testing(selfMessage) for(var/mob/M in get_mobs_in_view(7, user)) var/msg = message if(selfMessage && M==src) @@ -272,6 +299,11 @@ VampyrBytes return 0 // Proceed with emote //--FalseIncarnate + +/****************************************************************************************** + Emote Verbs +******************************************************************************************/ + /datum/emote/proc/addVerbs(var/mob/user) if(!istype(user)) return @@ -318,6 +350,7 @@ obj/emoteVerb/custom/New(var/mob/user) set category = "Emotes" usr.emoteHandler.runEmote("me", null, message, audible) + /************************************************************************************************************************** Custom Emotes As these are made as needed, they aren't searched for the appropriate one. As such, you need to specify conditions for which @@ -346,6 +379,10 @@ available, but if you do, make sure you return ..() so the check for use_me is s if(user.use_me) return 1 +// Yeah, no +/datum/emote/custom/createSelfMessage(var/mob/user, var/message = "") + return message + /datum/emote/custom/ghost name = "Ghost emote" startText = "DEAD: " diff --git a/code/datums/Emote system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm similarity index 92% rename from code/datums/Emote system/emote_handler.dm rename to code/datums/Emote_system/emote_handler.dm index afcb4f0253b..a20199155d2 100644 --- a/code/datums/Emote system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -19,11 +19,12 @@ commands[command] = found found.addVerbs(owner) + /datum/emoteHandler/proc/deleteEmoteVerbs() for(var/obj/emoteVerb/E in owner.contents) qdel(E) -/datum/emoteHandler/proc/runEmote(var/command = "", var/param = "", var/message = "", var/audible = 0) // message and audible only used in custom emotes +/datum/emoteHandler/proc/runEmote(var/command = "", var/message = "", var/audible = 0) // message and audible only used in custom emotes if(!command) return 0 if(command == "help") @@ -43,7 +44,7 @@ emote = commands[command] if(!emote.available(owner)) // something's changed, remake the commands list, then try again to see if they've got a different version setupCommands() - return runEmote(command, param, message) + return runEmote(command, message, audible) var/prevented = emote.prevented(owner) if(prevented) diff --git a/code/datums/Emote system/emotes.dm b/code/datums/Emote_system/emotes.dm similarity index 78% rename from code/datums/Emote system/emotes.dm rename to code/datums/Emote_system/emotes.dm index 5ab3b76b56d..691ad7ab26e 100644 --- a/code/datums/Emote system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -88,4 +88,38 @@ above it. If you don't want this, make the call to ..() then use commands = new return message +/datum/emote/signal + name = "signal" + desc = "raise x number of fingers" + text = "raises" + selfText = "raise" + canTarget = 1 + restrained = 1 + targetMob = 1 + takesNumber = 1 +/datum/emote/signal/New() + ..() + commands += "signal" + commands += "signals" + +/datum/emote/signal/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/signal/getNumber(var/mob/user) + var/number = ..() + var/fingersAvailable = 0 + if(!user.r_hand) + fingersAvailable += 5 + if(!user.l_hand) + fingersAvailable += 5 + if(fingersAvailable < number) + to_chat(user, "You don't have enough fingers free") + return "failed" + return number + +/datum/emote/signal/paramMessage(var/mob/user, var/param) + var/message = "[user] raises [param] finger\s" + testing(message) + return message diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 43248d54db4..709c1d778b3 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -29,7 +29,7 @@ /mob/verb/me_verb(message as text) set name = "Me" - set category = "IC" + set category = "Emotes" message = strip_html_properly(message) @@ -95,13 +95,8 @@ /mob/proc/emote(var/act, var/type, var/message) - var/param - if (findtext(act, "-", 1, null)) - var/t1 = findtext(act, "-", 1, null) - param = copytext(act, t1 + 1, length(act) + 1) - act = copytext(act, 1, t1) - emoteHandler.runEmote(act, param, message, type) + emoteHandler.runEmote(act, message, type) diff --git a/paradise.dme b/paradise.dme index b8e3c3dd148..a1cfc939216 100644 --- a/paradise.dme +++ b/paradise.dme @@ -258,9 +258,9 @@ #include "code\datums\diseases\advance\symptoms\weakness.dm" #include "code\datums\diseases\advance\symptoms\weight.dm" #include "code\datums\diseases\advance\symptoms\youth.dm" -#include "code\datums\Emote system\emote.dm" -#include "code\datums\Emote system\emote_handler.dm" -#include "code\datums\Emote system\emotes.dm" +#include "code\datums\Emote_system\emote.dm" +#include "code\datums\Emote_system\emote_handler.dm" +#include "code\datums\Emote_system\emotes.dm" #include "code\datums\helper_datums\construction_datum.dm" #include "code\datums\helper_datums\events.dm" #include "code\datums\helper_datums\global_iterator.dm" From e61d774a7c8794ec38bf938d56d91b3cf9afe020 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Sun, 8 May 2016 05:34:31 +0100 Subject: [PATCH 003/129] Makes emotes case insensitive (#4386) Also prevents unconscious emoting --- code/datums/Emote_system/emote.dm | 2 ++ code/datums/Emote_system/emote_handler.dm | 2 +- code/modules/mob/say.dm | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index f0a7e6ddb1b..75c8314ce7a 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -103,6 +103,8 @@ VampyrBytes /datum/emote/proc/prevented(var/mob/user) if(user.stat == DEAD) return "you are dead" + if(user.stat == UNCONSCIOUS) + return "you are unconscious" if(restrained && user.restrained()) return "you are restrained" diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index a20199155d2..ef4441857e5 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -16,7 +16,7 @@ var/datum/emote/found = searchTree(emote) if(found) for(var/command in found.commands) - commands[command] = found + commands[lowertext(command)] = found found.addVerbs(owner) diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 709c1d778b3..8078a101861 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -96,6 +96,7 @@ /mob/proc/emote(var/act, var/type, var/message) + act = lowertext(act) emoteHandler.runEmote(act, message, type) From a642606d18271d1d9ba76359173a94c88ee47b0e Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Sun, 8 May 2016 09:23:30 +0100 Subject: [PATCH 004/129] fixes bug with species specific emotes Emotes were being allocated before a human's species was set --- code/datums/Emote_system/emote_handler.dm | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index ef4441857e5..c036954bbaa 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -7,17 +7,18 @@ setupCommands() /datum/emoteHandler/proc/setupCommands(var/reset = 0) - if(reset) - deleteEmoteVerbs() - commands = new/list() - for(var/e in emotes) - var/datum/emote/emote = e - if(emote.baseLevel) - var/datum/emote/found = searchTree(emote) - if(found) - for(var/command in found.commands) - commands[lowertext(command)] = found - found.addVerbs(owner) + spawn(0) // needed so at mob creation species is set before emotes are allocated + if(reset) + deleteEmoteVerbs() + commands = new/list() + for(var/e in emotes) + var/datum/emote/emote = e + if(emote.baseLevel) + var/datum/emote/found = searchTree(emote) + if(found) + for(var/command in found.commands) + commands[lowertext(command)] = found + found.addVerbs(owner) /datum/emoteHandler/proc/deleteEmoteVerbs() From bcfe01b03867b0ca01c216a1aafef03af4ba8f71 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Tue, 10 May 2016 03:19:00 +0100 Subject: [PATCH 005/129] 1st batch of emotes + tweaks --- code/datums/Emote_system/emote.dm | 6 +- code/datums/Emote_system/emote_handler.dm | 9 +- code/datums/Emote_system/emotes.dm | 195 ++++++++++++++++++++++ 3 files changed, 205 insertions(+), 5 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 75c8314ce7a..f6b8feaebbc 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -29,7 +29,7 @@ VampyrBytes var/spanClass = "notice" var/baseLevel = 1 - var/baseSet = 0 + var/allowParent = 0 // 1 if you want the parent available as well as this one /datum/emote/New() @@ -107,6 +107,10 @@ VampyrBytes return "you are unconscious" if(restrained && user.restrained()) return "you are restrained" + if(isbrain(user)) + var/mob/living/carbon/brain/brain = user + if(!(brain.container && istype(brain.container, /obj/item/device/mmi))) + return "you need to be in an mmi to do this" // return 1 if this emote can be used by this type of user /datum/emote/proc/available(var/mob/user) diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index c036954bbaa..422892b847b 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -13,7 +13,7 @@ commands = new/list() for(var/e in emotes) var/datum/emote/emote = e - if(emote.baseLevel) + if(emote.baseLevel || emote.allowParent) var/datum/emote/found = searchTree(emote) if(found) for(var/command in found.commands) @@ -33,7 +33,6 @@ return 1 var/datum/emote/emote - //testing("[command]") if(command == "me") emote = customEmote(message, audible) if(!emote) @@ -69,8 +68,10 @@ var/list/subtypes = subtypesof(emote.type) var/datum/emote/found for(var/t in subtypes) - var/datum/emote/em = new t // not keen on this, but it's this or loop through the emotes list and the - found = searchTree(em) // thought of a nested for loop in a recursive proc makes me want to *cry - VB + var/datum/emote/em = new t + if(em.allowParent) + continue + found = searchTree(em, 1) if(found) return (found) if(emote.available(owner)) diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index 691ad7ab26e..509ff9eca2a 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -5,6 +5,201 @@ are set in New(), this means that the emote will pick up all the commands from t above it. If you don't want this, make the call to ..() then use commands = new /list() *************************************************************************************/ +/datum/emote/airguitar + name = "airguitar" + desc = "Play an air guitar" + text = "is strumming the air and headbanging like a safari chimp." + selfText = "are strumming the air and headbanging like a safari chimp." + restrained = 1 + +/datum/emote/airguitar/New() + ..() + commands += "airguitar" + +/datum/emote/airguitar/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/alarm + name = "alarm" + desc = "Sound an alarm" + text = "sounds an alarm" + selfText = "sound an alarm" + audible = 1 + +/datum/emote/alarm/New() + ..() + commands += "alarm" + +/datum/emote/alarm/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/alarm/createBlindMessage(var/mob/user, var/messaage) + return "You hear an alarm" + +/datum/emote/alert + name = "alert" + desc = "Sound an alert" + text = "lets out a distressed noise" + selfText = "let out a distressed noise)" + audible = 1 + +/datum/emote/alert/New() + ..() + commands += "alert" + +/datum/emote/alert/available(var/mob/user) + if(isbrain(user)) + return 1 +/datum/emote/alert/createBlindMessage(var/mob/user, var/message) + return "you hear an alert" + +/datum/emote/beep + name = "beep" + desc = "let out a beep" + text = "beeps" + selfText = "beep" + audible = 1 + +/datum/emote/beep/New() + ..() + commands += "beep" + commands += "beeps" + +/datum/emote/beep/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/beep/createBlindMessage(var/mob/user, var/message) + return "You hear a beep" + +/datum/emote/beep/targetted + cooldown = 1 + sound = 'sound/machines/twobeep.ogg' + canTarget = 1 + targetMob = 1 + +/datum/emote/beep/targetted/available(var/mob/user) + if(issilicon(user)) + return 1 + if(isbot(user)) + return 1 + if(user.get_species() == "Machine") + return 1 + +/datum/emote/blink + name = "blink" + desc = "blink" + text = "blinks" + selfText = "blink" + +/datum/emote/blink/New() + ..() + commands += "blink" + commands += "blinks" + +/datum/emote/blink/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isbrain(user)) + return 1 + +/datum/emote/blink/rapid + name = "rapid blink" + desc = "blink rapidly" + allowParent = 1 + +/datum/emote/blink/rapid/New() + ..() + commands = new/list() + commands += "blink_r" + commands += "blinks_r" + +/datum/emote/blink/rapid/available(var/mob/user) + if(ishuman(user)) + return + +/datum/emote/blink/rapid/createMessage(var/mob/user, var/number) + var/message = ..() + message += " rapidly" + return message + +/datum/emote/blush + name = "blush" + desc = "blush" + text = "blushes" + selfText = "blush" + +/datum/emote/blush/New() + ..() + commands += "blush" + commands += "blushes" + +/datum/emote/blush/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/boop + name = "boop" + desc = "boop" + text = "boops" + selfText = "boop" + +/datum/emote/boop/New() + ..() + commands += "boop" + commands += "boops" + +/datum/emote/boop/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/bounce + name = "bounce" + desc = "bounce" + text = "bounces in place" + selfText = "bounce in place" + +/datum/emote/bounce/New() + ..() + commands += "bounce" + commands += "bounces" + +/datum/emote/bounce/available(var/mob/user) + if(isslime(user)) + return 1 + +/datum/emote/bow + name = "bow" + desc = "bow" + text = "bows" + selfText = "bow" + canTarget = 1 + targetMob = 1 + targetText = "to" + +/datum/emote/bow/New() + ..() + commands += "bow" + commands += "bows" + +/datum/emote/bow/available(var/mob/user) + if(isrobot(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/bow/prevented(var/mob/user) + . = ..() + if(!. && user.buckled) + return "you are buckled to something" + + + + /datum/emote/scream name = "scream" text = "screams!" From 06331768930bca71c2009ca2ea31fe5f40805dd2 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Tue, 10 May 2016 04:33:21 +0100 Subject: [PATCH 006/129] fixes derps in merge --- code/datums/Emote_system/emotes.dm | 2 +- .../carbon/human/species/{abdcutor.dm => abductor.dm} | 0 paradise.dme | 6 ++++++ 3 files changed, 7 insertions(+), 1 deletion(-) rename code/modules/mob/living/carbon/human/species/{abdcutor.dm => abductor.dm} (100%) diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index 7a3f9ea2b10..c00f5be5fd1 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -202,7 +202,7 @@ above it. If you don't want this, make the call to ..() then use commands = new desc = "burp" text = "burps" selfText = "burp" - muzzledNoise = "peculiar + muzzledNoise = "peculiar" /datum/emote/scream diff --git a/code/modules/mob/living/carbon/human/species/abdcutor.dm b/code/modules/mob/living/carbon/human/species/abductor.dm similarity index 100% rename from code/modules/mob/living/carbon/human/species/abdcutor.dm rename to code/modules/mob/living/carbon/human/species/abductor.dm diff --git a/paradise.dme b/paradise.dme index c3a14848062..dc3b70ad7bf 100644 --- a/paradise.dme +++ b/paradise.dme @@ -214,19 +214,23 @@ #include "code\datums\diseases\anxiety.dm" #include "code\datums\diseases\appendicitis.dm" #include "code\datums\diseases\beesease.dm" +#include "code\datums\diseases\berserker.dm" #include "code\datums\diseases\brainrot.dm" #include "code\datums\diseases\cold.dm" #include "code\datums\diseases\cold9.dm" #include "code\datums\diseases\fake_gbs.dm" #include "code\datums\diseases\flu.dm" #include "code\datums\diseases\fluspanish.dm" +#include "code\datums\diseases\food_poisoning.dm" #include "code\datums\diseases\gbs.dm" +#include "code\datums\diseases\kuru.dm" #include "code\datums\diseases\magnitis.dm" #include "code\datums\diseases\pierrot_throat.dm" #include "code\datums\diseases\retrovirus.dm" #include "code\datums\diseases\rhumba_beat.dm" #include "code\datums\diseases\transformation.dm" #include "code\datums\diseases\tuberculosis.dm" +#include "code\datums\diseases\vampire.dm" #include "code\datums\diseases\wizarditis.dm" #include "code\datums\diseases\advance\advance.dm" #include "code\datums\diseases\advance\presets.dm" @@ -773,6 +777,7 @@ #include "code\game\objects\items\stacks\tiles\tile_types.dm" #include "code\game\objects\items\weapons\AI_modules.dm" #include "code\game\objects\items\weapons\alien_specific.dm" +#include "code\game\objects\items\weapons\bee_briefcase.dm" #include "code\game\objects\items\weapons\cards_ids.dm" #include "code\game\objects\items\weapons\cash.dm" #include "code\game\objects\items\weapons\caution.dm" @@ -857,6 +862,7 @@ #include "code\game\objects\items\weapons\implants\implantuplink.dm" #include "code\game\objects\items\weapons\melee\energy.dm" #include "code\game\objects\items\weapons\melee\misc.dm" +#include "code\game\objects\items\weapons\storage\artistic_toolbox.dm" #include "code\game\objects\items\weapons\storage\backpack.dm" #include "code\game\objects\items\weapons\storage\bags.dm" #include "code\game\objects\items\weapons\storage\belt.dm" From 29152ceec04c9ba357a5ff670e7ce6ebb805d5e9 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Wed, 11 May 2016 14:42:05 +0100 Subject: [PATCH 007/129] tweaks Better mime support system returns 0,1 or 2(0 failed, 1 for visible and 2 for audible) cleaned up creating message --- code/datums/Emote_system/emote.dm | 119 ++++++++++++++++------------- code/datums/Emote_system/emotes.dm | 2 + code/modules/mob/emote.dm | 2 +- code/modules/mob/say.dm | 4 +- 4 files changed, 73 insertions(+), 54 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index f6b8feaebbc..3d3a2e669e4 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -45,43 +45,47 @@ VampyrBytes /datum/emote/proc/doEmote(var/mob/user) if(!istype(user)) - return 0 + return if(cooldown) if(handle_emote_CD(user)) - return 0 + return - var/number + var/message = "" + var/num var/target if(takesNumber) - number = getNumber(user) + num = getNumber(user) if(canTarget) target = getTarget(user) - if(number == "failed" || target == "failed") // If you need to test the input, override the appopriate get proc, call the parent, - return // then test it. If it fails, tell the user why, then return "failed" to halt the emote + if(num == "invalid" || target == "invalid") + return - var/message = createMessage(user, number) - - if(canTarget && message) - message = addTarget(user, target, message) + if(text) + message = createMessage(user, num, target) + if(message == "failed") + return if(message) - message += "" - outputMessage(user, message) + . = outputMessage(user, message) - if(audible) - if(!(user.mind && user.mind.miming)) - playSound(user, vol) + var/played = 0 + if(!doMime(user)) + played = playSound(user, vol) - doAction(user, target, number) - return 1 + if(played) + . = 2 + + doAction(user) + return // for things that the emote does that aren't text or sound based /datum/emote/proc/doAction(var/mob/user, var/atom/target, var/number) return +// return "invalid" from either of these getters if you've tested the input and it's failed /datum/emote/proc/getNumber(var/mob/user) var/number = input("How many") as null|num return number @@ -116,27 +120,43 @@ VampyrBytes /datum/emote/proc/available(var/mob/user) return -/datum/emote/proc/createMessage(var/mob/user, var/number) +/datum/emote/proc/createMessage(var/mob/user, var/param, var/target) if(!text) return var/message - if(takesNumber && number) - message = getParamMessage(user, number) - else if(audible && user.mind && user.mind.miming) - message = mimeMessage(user) - else if(audible && user.is_muzzled()) - message = muzzleMessage(user) - else - message = "[user] [text]" - if(startText) - message = "[startText] [message]" - message = "[message]" + + if(doMime(user)) + message = mimeMessage(user, param, target) + + if(!message) + if(muzzledNoise && user.is_muzzled()) + message = muzzleMessage(user) + + else if(takesNumber && param) + message = paramMessage(user, param) + else + message = "[user] [text]" + + if(message && target) + message = addTarget(user, target, message) + + message = addExtras(message) + return message -/datum/emote/proc/mimeMessage(var/mob/user) +/datum/emote/proc/addExtras(var/message) + if(!message) + return + if(startText) + message = "[startText] [message]" + message = "[message]" + return message + +/datum/emote/proc/mimeMessage(var/mob/user, var/param, var/target) if(!mimeText) return - + if(takesNumber) + return paramMimeMessage(user, param) var/message = "[user] [mimeText]" return message @@ -147,16 +167,6 @@ VampyrBytes message += "noise" return message -/datum/emote/proc/getParamMessage(var/mob/user, var/param) - var/message - if(audible && user.mind && user.mind.miming) - message = paramMimeMessage(user, param) - else if (audible && user.is_muzzled()) - message = muzzleMessage(user) - else - message = paramMessage(user, param) - return message - // if the emote takes a non target parameter, set up and return the with parameter version in here /datum/emote/proc/paramMessage(var/mob/user, var/param) return @@ -170,10 +180,7 @@ VampyrBytes return message if(!target) return message - if(ismob(target)) - message += " [targetText] [target]" - else - message += " [targetText] \the [target]" + message += " [targetText] \the [target]" return message // What you should see when you perform the emote @@ -191,11 +198,11 @@ VampyrBytes if(!message) return log_emote("[user.name]/[user.key] : [message]") - if(audible) - audible_message(message, user) - else - visible_message(message, user) sendToDead(message) + if(audible) + return audible_message(message, user) + else + return visible_message(message, user) /datum/emote/proc/visible_message(var/message = "", var/mob/user) var/selfMessage = createSelfMessage(user, message) @@ -213,8 +220,11 @@ VampyrBytes outputAudibleMessage(msg, M, user, 1) else outputVisibleMessage(msg, M, user) + return 1 /datum/emote/proc/audible_message(var/message = "", var/mob/user) + if(doMime(user)) + return visible_message(message, user) var/selfMessage = createSelfMessage(user, message) for(var/mob/M in get_mobs_in_view(7, user)) var/msg = message @@ -228,6 +238,7 @@ VampyrBytes outputVisibleMessage(msg, M, user, 1) else outputAudibleMessage(msg, M, user) + return 2 /datum/emote/proc/outputVisibleMessage(var/message, var/mob/recipient, var/mob/user, var/retest = 0) if(retest) @@ -252,6 +263,7 @@ VampyrBytes to_chat(recipient, message) /datum/emote/proc/outputAudibleMessage(var/message = "", var/mob/recipient, var/mob/user, var/retest = 0) + if(retest) if(!user) return @@ -291,6 +303,11 @@ VampyrBytes /datum/emote/proc/playSound(var/mob/user) if(sound) playsound(user, sound, vol) + return 1 + +/datum/emote/proc/doMime(var/mob/user) + if(mimeText && user.mind && user.mind.miming) + return 1 //Emote Cooldown System (it's so simple!) /datum/emote/proc/handle_emote_CD(var/mob/user) @@ -336,7 +353,7 @@ VampyrBytes /obj/emoteVerb/proc/runEmote() set src = usr.contents set category = "Emotes" - usr.emoteHandler.runEmote(emote.commands[1]) + return usr.emoteHandler.runEmote(emote.commands[1]) /obj/emoteVerb/Destroy() owner.verbs -= new/obj/emoteVerb/proc/runEmote(src, emote.commands[1]) @@ -354,7 +371,7 @@ obj/emoteVerb/custom/New(var/mob/user) /obj/emoteVerb/custom/runEmote(message as text, audible as num) set src = usr.contents set category = "Emotes" - usr.emoteHandler.runEmote("me", null, message, audible) + return usr.emoteHandler.runEmote("me", null, message, audible) /************************************************************************************************************************** diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index c00f5be5fd1..abbb89fce36 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -203,6 +203,8 @@ above it. If you don't want this, make the call to ..() then use commands = new text = "burps" selfText = "burp" muzzledNoise = "peculiar" + mimeText = "opens their mouth rather obnoxiously" + /datum/emote/scream diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 1c82e1c2755..201e54ef839 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -17,7 +17,7 @@ // All mobs should have custom emote, really.. /mob/proc/custom_emote(var/m_type=1,var/message = null) - emoteHandler.runEmote("me", null, message, m_type) + return emoteHandler.runEmote("me", null, message, m_type) /* if(stat || !use_me && usr == src) to_chat(usr, "You are unable to emote.") diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm index 8078a101861..7362cdd78ab 100644 --- a/code/modules/mob/say.dm +++ b/code/modules/mob/say.dm @@ -34,7 +34,7 @@ message = strip_html_properly(message) set_typing_indicator(0) - emoteHandler.runEmote("me", null, message) + return emoteHandler.runEmote("me", null, message) /mob/proc/say_dead(var/message) if(!src.client.holder) @@ -97,7 +97,7 @@ /mob/proc/emote(var/act, var/type, var/message) act = lowertext(act) - emoteHandler.runEmote(act, message, type) + return emoteHandler.runEmote(act, message, type) From 3de48b83f8d0d2eaa50e3d5b579ee883cf5b610c Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Fri, 13 May 2016 10:41:42 +0100 Subject: [PATCH 008/129] better param support --- code/datums/Emote_system/emote.dm | 84 ++++++++++++++--------- code/datums/Emote_system/emote_handler.dm | 1 - code/datums/Emote_system/emotes.dm | 17 +++-- 3 files changed, 63 insertions(+), 39 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 3d3a2e669e4..47311cc994b 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -51,22 +51,16 @@ VampyrBytes return var/message = "" - var/num - var/target + var/list/params[0] - if(takesNumber) - num = getNumber(user) + params = getParams(user) - if(canTarget) - target = getTarget(user) - - if(num == "invalid" || target == "invalid") - return + for(var/p in params) + if(params[p] == "invalid") + return if(text) - message = createMessage(user, num, target) - if(message == "failed") - return + message = createMessage(user, params) if(message) . = outputMessage(user, message) @@ -78,13 +72,25 @@ VampyrBytes if(played) . = 2 - doAction(user) + doAction(user, params) + return // for things that the emote does that aren't text or sound based -/datum/emote/proc/doAction(var/mob/user, var/atom/target, var/number) +/datum/emote/proc/doAction(var/mob/user, var/list/params) return +/datum/emote/proc/getParams(var/mob/user) + var/list/params[0] + + if(takesNumber) + params["num"] = getNumber(user) + + if(canTarget) + params["target"] = getTarget(user) + + return params + // return "invalid" from either of these getters if you've tested the input and it's failed /datum/emote/proc/getNumber(var/mob/user) var/number = input("How many") as null|num @@ -120,30 +126,37 @@ VampyrBytes /datum/emote/proc/available(var/mob/user) return -/datum/emote/proc/createMessage(var/mob/user, var/param, var/target) +/datum/emote/proc/createMessage(var/mob/user, var/list/params) if(!text) return var/message if(doMime(user)) - message = mimeMessage(user, param, target) + message = mimeMessage(user, params) if(!message) if(muzzledNoise && user.is_muzzled()) message = muzzleMessage(user) - else if(takesNumber && param) - message = paramMessage(user, param) + else if(checkForParams(params)) + message = paramMessage(user, params) else message = "[user] [text]" - if(message && target) - message = addTarget(user, target, message) + if(message && "target" in params) + if(params["target"]) + message = addTarget(user, params, message) message = addExtras(message) return message +/datum/emote/proc/checkForParams(var/list/params) + for(var/p in params) + if(params[p] == "target") + continue + return 1 + /datum/emote/proc/addExtras(var/message) if(!message) return @@ -152,12 +165,16 @@ VampyrBytes message = "[message]" return message -/datum/emote/proc/mimeMessage(var/mob/user, var/param, var/target) +/datum/emote/proc/mimeMessage(var/mob/user, var/list/params) if(!mimeText) return - if(takesNumber) - return paramMimeMessage(user, param) + if(takesNumber && "num" in params) + if(params["num"] != null) + return paramMimeMessage(user, params) var/message = "[user] [mimeText]" + if(message && "target" in params) + if(params["target"]) + message = addTarget(user, params, message) return message /datum/emote/proc/muzzleMessage(var/mob/user) @@ -168,31 +185,30 @@ VampyrBytes return message // if the emote takes a non target parameter, set up and return the with parameter version in here -/datum/emote/proc/paramMessage(var/mob/user, var/param) +/datum/emote/proc/paramMessage(var/mob/user, var/list/params) return -// as above, but for mimes trying to do audible messages -/datum/emote/proc/paramMimeMessage(var/mob/user, var/param) +// as above, but for mimes when there is mimeText +/datum/emote/proc/paramMimeMessage(var/mob/user, var/list/params) return -/datum/emote/proc/addTarget(var/mob/user, var/atom/target, var/message = "") +/datum/emote/proc/addTarget(var/mob/user, var/list/params, var/message = "") if(!canTarget) return message - if(!target) + if(!params["target"]) return message - message += " [targetText] \the [target]" + message += " [targetText] \the [params["target"]]" return message // What you should see when you perform the emote /datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") - var/selfMessage if(startText) - selfMessage = replacetext(message, "[user]", "you") + message = replacetext(message, "[user]", "you") else - selfMessage = replacetext(message, "[user]", "You") + message = replacetext(message, "[user]", "You") if(selfText) - selfMessage = replacetext(selfMessage, text, selfText) - return selfMessage + message = replacetext(message, text, selfText) + return message /datum/emote/proc/outputMessage(var/mob/user, var/message = "") if(!message) diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index 422892b847b..d30d542aaec 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -20,7 +20,6 @@ commands[lowertext(command)] = found found.addVerbs(owner) - /datum/emoteHandler/proc/deleteEmoteVerbs() for(var/obj/emoteVerb/E in owner.contents) qdel(E) diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index abbb89fce36..8a03a1febc9 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -207,6 +207,7 @@ above it. If you don't want this, make the call to ..() then use commands = new + /datum/emote/scream name = "scream" text = "screams!" @@ -252,6 +253,8 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/fart name = "fart" + text = "farts" + selfText = "fart" cooldown = 50 /datum/emote/fart/New() @@ -289,6 +292,11 @@ above it. If you don't want this, make the call to ..() then use commands = new message = "[user] [pick("passes wind","farts")]." return message +/datum/emote/fart/createSelfMessage(var/mob/user, var/message) + message = ..() + message = replacetext(message, "unleashes", "unleash") + message = replacetext(message, "passes", "pass") + return message /datum/emote/signal name = "signal" @@ -311,6 +319,8 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/signal/getNumber(var/mob/user) var/number = ..() + if(number == null) + return "invalid" var/fingersAvailable = 0 if(!user.r_hand) fingersAvailable += 5 @@ -318,10 +328,9 @@ above it. If you don't want this, make the call to ..() then use commands = new fingersAvailable += 5 if(fingersAvailable < number) to_chat(user, "You don't have enough fingers free") - return "failed" + return "invalid" return number -/datum/emote/signal/paramMessage(var/mob/user, var/param) - var/message = "[user] raises [param] finger\s" - testing(message) +/datum/emote/signal/paramMessage(var/mob/user, var/list/params) + var/message = "[user] raises [params["num"]] finger\s" return message From a355f84e1cf10859ad456bf92e846db8c6be4601 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Sat, 14 May 2016 07:59:21 +0100 Subject: [PATCH 009/129] Adds default blind and deaf messages + bug fixes --- code/datums/Emote_system/emote.dm | 55 +++++++++++++++--------------- code/datums/Emote_system/emotes.dm | 11 +++++- 2 files changed, 38 insertions(+), 28 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 47311cc994b..65a09d23ea3 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -63,7 +63,7 @@ VampyrBytes message = createMessage(user, params) if(message) - . = outputMessage(user, message) + . = outputMessage(user, message, params) var/played = 0 if(!doMime(user)) @@ -168,9 +168,8 @@ VampyrBytes /datum/emote/proc/mimeMessage(var/mob/user, var/list/params) if(!mimeText) return - if(takesNumber && "num" in params) - if(params["num"] != null) - return paramMimeMessage(user, params) + if(checkForParams(params)) + return paramMimeMessage(user, params) var/message = "[user] [mimeText]" if(message && "target" in params) if(params["target"]) @@ -210,17 +209,17 @@ VampyrBytes message = replacetext(message, text, selfText) return message -/datum/emote/proc/outputMessage(var/mob/user, var/message = "") +/datum/emote/proc/outputMessage(var/mob/user, var/message = "", var/list/params) if(!message) return log_emote("[user.name]/[user.key] : [message]") sendToDead(message) if(audible) - return audible_message(message, user) + return audible_message(message, user, params) else - return visible_message(message, user) + return visible_message(message, user, params) -/datum/emote/proc/visible_message(var/message = "", var/mob/user) +/datum/emote/proc/visible_message(var/message = "", var/mob/user, var/list/params) var/selfMessage = createSelfMessage(user, message) for(var/mob/M in viewers(user)) if(M.see_invisible < user.invisibility) @@ -228,25 +227,25 @@ VampyrBytes var/msg = message if(selfMessage && M==user) msg = selfMessage - if(M.sdisabilities & BLIND || M.blinded || M.paralysis) + else if(M.sdisabilities & BLIND || M.blinded || M.paralysis) if(M.sdisabilities & DEAF || M.ear_deaf) continue - msg = createBlindMessage(message, user) + msg = createBlindMessage(message, user, params) if(msg) outputAudibleMessage(msg, M, user, 1) else - outputVisibleMessage(msg, M, user) + outputVisibleMessage(msg, M, user, params) return 1 -/datum/emote/proc/audible_message(var/message = "", var/mob/user) +/datum/emote/proc/audible_message(var/message = "", var/mob/user, var/list/params) if(doMime(user)) return visible_message(message, user) var/selfMessage = createSelfMessage(user, message) for(var/mob/M in get_mobs_in_view(7, user)) var/msg = message - if(selfMessage && M==src) + if(selfMessage && M==user) msg = selfMessage - if(M.sdisabilities & DEAF || M.ear_deaf) + else if(M.sdisabilities & DEAF || M.ear_deaf) if(M.sdisabilities & BLIND || M.blinded || M.paralysis) continue msg = createDeafMessage(user, message) @@ -256,7 +255,7 @@ VampyrBytes outputAudibleMessage(msg, M, user) return 2 -/datum/emote/proc/outputVisibleMessage(var/message, var/mob/recipient, var/mob/user, var/retest = 0) +/datum/emote/proc/outputVisibleMessage(var/message, var/mob/recipient, var/mob/user, var/list/params, var/retest = 0) if(retest) if(!user) return @@ -270,16 +269,16 @@ VampyrBytes if(!found) return if(recipient.sdisabilities & DEAF || recipient.ear_deaf) - var/msg = createDeafMessage(user, message) - if(msg) - message = msg + if(!(recipient == user)) + var/msg = createDeafMessage(user, message, params) + if(msg) + message = msg if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) to_chat(recipient, "... You can almost hear someone talking ...") else to_chat(recipient, message) -/datum/emote/proc/outputAudibleMessage(var/message = "", var/mob/recipient, var/mob/user, var/retest = 0) - +/datum/emote/proc/outputAudibleMessage(var/message = "", var/mob/recipient, var/mob/user, var/list/params, var/retest = 0) if(retest) if(!user) return @@ -291,9 +290,10 @@ VampyrBytes if(!found) return if(recipient.sdisabilities & BLIND || recipient.blinded || recipient.paralysis) - var/msg = createBlindMessage(user, message) - if(msg) - message = msg + if(!(recipient == user)) + var/msg = createBlindMessage(user, message, params) + if(msg) + message = msg if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) to_chat(recipient, "... You can almost hear someone talking ...") else @@ -301,13 +301,14 @@ VampyrBytes // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones -/datum/emote/proc/createBlindMessage(var/mob/user, var/message) - return +/datum/emote/proc/createBlindMessage(var/mob/user, var/message, var/list/params) + if(audible && selfText) + return "You hear someone [selfText]" // set up different messages for deaf people here. Empty will mean no message for // audible emotes and standard for non-audible ones -/datum/emote/proc/createDeafMessage(var/mob/user, var/message) - return +/datum/emote/proc/createDeafMessage(var/mob/user, var/message, var/list/params) + return mimeMessage(user, params) /datum/emote/proc/sendToDead(message) for(var/mob/M in dead_mob_list) diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index 8a03a1febc9..12d30be4c26 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -204,9 +204,18 @@ above it. If you don't want this, make the call to ..() then use commands = new selfText = "burp" muzzledNoise = "peculiar" mimeText = "opens their mouth rather obnoxiously" + audible = 1 +/datum/emote/burp/New() + ..() + commands += "burp" + commands += "burps" - +/datum/emote/burp/available(var/mob/user) + if(ishuman(user)) + return 1 + if(istype(user, /mob/living/carbon/alien/larva) || istype(user, /mob/living/carbon/alien/humanoid)) + return 1 /datum/emote/scream name = "scream" From 636081e47e16e22cb9152286bb481d14ecd6cb0b Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Mon, 16 May 2016 22:56:03 +0100 Subject: [PATCH 010/129] Cleans up message output + bugfixes and tweaks --- code/datums/Emote_system/emote.dm | 179 +++++++++++++----------------- 1 file changed, 76 insertions(+), 103 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 65a09d23ea3..f12d0e20214 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -14,14 +14,18 @@ VampyrBytes var/text = "" var/selfText = "" // the version of text that you should see - eg, if text is screams, you want scream here, as You screams is bad grammer var/startText = "" // if you need to put something in before [user]. Should end with a space + var/selfStart = 1 // whether the start text is used in what you see + + var/audible = 0 var/mimeText = "" var/sound // sound file var/vol = 50 - var/audible = 0 - var/muzzledNoise = "" // if the emote is audible and you're muzzled, this is what type of noise you make (eg weak, loud). End with a space - var/restrained = "" // 1 if being restrained prevents this emote + var/muzzleAffected = 0 // whether being muzzled affects this emote + var/muzzledNoise = "" // if the emote is audible and you're muzzled, this is what type of noise you make (eg weak, loud). var/cooldown = 0 + var/restrained = 0 // 1 if being restrained prevents this emote + var/canTarget = 0 // 1 if the emote accepts a target var/targetMob = 0 // 0 if target can be any atom, 1 if it has to be a mob, var/targetText = "at" // what goes inbetween user and target @@ -65,12 +69,10 @@ VampyrBytes if(message) . = outputMessage(user, message, params) - var/played = 0 - if(!doMime(user)) - played = playSound(user, vol) - if(played) - . = 2 + if(!doMime(user)) + if(playSound(user, vol)) + . = 2 doAction(user, params) @@ -88,7 +90,6 @@ VampyrBytes if(canTarget) params["target"] = getTarget(user) - return params // return "invalid" from either of these getters if you've tested the input and it's failed @@ -97,15 +98,17 @@ VampyrBytes return number /datum/emote/proc/getTarget(var/mob/user) + if(user.sdisabilities & BLIND || user.blinded || user.paralysis) + return if(targetMob) - return getMobTarget() - return getAtomTarget() + return getMobTarget(user) + return getAtomTarget(user) -/datum/emote/proc/getMobTarget() +/datum/emote/proc/getMobTarget(var/mob/user) var/mob/target = input("Select target", "Target Mob") as null|mob in view() return target -/datum/emote/proc/getAtomTarget() +/datum/emote/proc/getAtomTarget(var/mob/user) var/atom/target = input("Select target", "Target") as null|mob|obj|turf in oview() return target @@ -135,25 +138,23 @@ VampyrBytes message = mimeMessage(user, params) if(!message) - if(muzzledNoise && user.is_muzzled()) + if(muzzleAffected && user.is_muzzled()) message = muzzleMessage(user) - else if(checkForParams(params)) message = paramMessage(user, params) else - message = "[user] [text]" + message = "[user] [text]" if(message && "target" in params) if(params["target"]) message = addTarget(user, params, message) - message = addExtras(message) return message /datum/emote/proc/checkForParams(var/list/params) for(var/p in params) - if(params[p] == "target") + if(p == "target") continue return 1 @@ -170,14 +171,14 @@ VampyrBytes return if(checkForParams(params)) return paramMimeMessage(user, params) - var/message = "[user] [mimeText]" + var/message = "[user] [mimeText]" if(message && "target" in params) if(params["target"]) message = addTarget(user, params, message) return message /datum/emote/proc/muzzleMessage(var/mob/user) - var/message = "[user] makes a " + var/message = "[user] makes a " if(muzzledNoise) message += "[muzzledNoise] " message += "noise" @@ -201,109 +202,81 @@ VampyrBytes // What you should see when you perform the emote /datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") - if(startText) + if(startText && selfStart) message = replacetext(message, "[user]", "you") else message = replacetext(message, "[user]", "You") if(selfText) message = replacetext(message, text, selfText) + if(!selfStart) + var/start = findtextEx(message, startText) + var/end = start + lentext(startText) + 1 + message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) + return message /datum/emote/proc/outputMessage(var/mob/user, var/message = "", var/list/params) - if(!message) - return + var/visualOrAudible = audible + 1 + if(doMime(user)) + visualOrAudible = 1 + var/selfMessage = createSelfMessage(user, message) + log_emote("[user.name]/[user.key] : [message]") sendToDead(message) - if(audible) - return audible_message(message, user, params) - else - return visible_message(message, user, params) -/datum/emote/proc/visible_message(var/message = "", var/mob/user, var/list/params) - var/selfMessage = createSelfMessage(user, message) - for(var/mob/M in viewers(user)) - if(M.see_invisible < user.invisibility) - continue //can't view the invisible - var/msg = message + for(var/mob/M in getRecipients(user, visualOrAudible)) + var/msg = "" + if(selfMessage && M==user) msg = selfMessage - else if(M.sdisabilities & BLIND || M.blinded || M.paralysis) - if(M.sdisabilities & DEAF || M.ear_deaf) + + else if(M.stat == UNCONSCIOUS || (M.sleeping > 0 && M.stat != 2)) + if (visualOrAudible == 2) + msg = "... You can almost hear someone talking ..." + else continue - msg = createBlindMessage(message, user, params) - if(msg) - outputAudibleMessage(msg, M, user, 1) - else - outputVisibleMessage(msg, M, user, params) - return 1 -/datum/emote/proc/audible_message(var/message = "", var/mob/user, var/list/params) - if(doMime(user)) - return visible_message(message, user) - var/selfMessage = createSelfMessage(user, message) - for(var/mob/M in get_mobs_in_view(7, user)) - var/msg = message - if(selfMessage && M==user) - msg = selfMessage else if(M.sdisabilities & DEAF || M.ear_deaf) if(M.sdisabilities & BLIND || M.blinded || M.paralysis) continue - msg = createDeafMessage(user, message) - if(msg) - outputVisibleMessage(msg, M, user, 1) - else - outputAudibleMessage(msg, M, user) - return 2 + if((!(M in getRecipients(user, 1))) || M.see_invisible < user.invisibility) + continue + msg = createDeafMessage(user, message, params) -/datum/emote/proc/outputVisibleMessage(var/message, var/mob/recipient, var/mob/user, var/list/params, var/retest = 0) - if(retest) - if(!user) - return - var/found = 0 - for(var/mob/M in viewers(user)) - if(M == recipient) - found = 1 - if(recipient.see_invisible < user.invisibility) - return - break - if(!found) - return - if(recipient.sdisabilities & DEAF || recipient.ear_deaf) - if(!(recipient == user)) - var/msg = createDeafMessage(user, message, params) - if(msg) - message = msg - if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) - to_chat(recipient, "... You can almost hear someone talking ...") - else - to_chat(recipient, message) + if(!msg && visualOrAudible == 2) + continue + + else if(M.sdisabilities & BLIND || M.blinded || M.paralysis || (M.see_invisible < user.invisibility && visualOrAudible == 2)) + if(!(M in getRecipients(user, 2))) + continue + msg = createBlindMessage(user, message, params) + if(!msg && visualOrAudible == 1) + continue + + else if(M.see_invisible < user.invisibility) + continue + + if(!msg) + msg = message + + to_chat(M, msg) + return visualOrAudible + +/datum/emote/proc/getRecipients(var/mob/user, var/visualOrAudible) + var/list/recipients[0] + switch(visualOrAudible) + if(1) + recipients = viewers(user) + if(2) + recipients = get_mobs_in_view(7, user) + return recipients -/datum/emote/proc/outputAudibleMessage(var/message = "", var/mob/recipient, var/mob/user, var/list/params, var/retest = 0) - if(retest) - if(!user) - return - var/found = 0 - for(var/mob/M in get_mobs_in_view(7, user)) - if(M == recipient) - found = 1 - break - if(!found) - return - if(recipient.sdisabilities & BLIND || recipient.blinded || recipient.paralysis) - if(!(recipient == user)) - var/msg = createBlindMessage(user, message, params) - if(msg) - message = msg - if(recipient.stat == UNCONSCIOUS || (recipient.sleeping > 0 && recipient.stat != 2)) - to_chat(recipient, "... You can almost hear someone talking ...") - else - to_chat(recipient, message) // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones /datum/emote/proc/createBlindMessage(var/mob/user, var/message, var/list/params) if(audible && selfText) - return "You hear someone [selfText]" + return "You hear someone [selfText]" // set up different messages for deaf people here. Empty will mean no message for // audible emotes and standard for non-audible ones @@ -318,9 +291,10 @@ VampyrBytes M.show_message(message) /datum/emote/proc/playSound(var/mob/user) - if(sound) - playsound(user, sound, vol) - return 1 + if(!sound) + return + playsound(user, sound, vol) + return 1 /datum/emote/proc/doMime(var/mob/user) if(mimeText && user.mind && user.mind.miming) @@ -408,8 +382,7 @@ available, but if you do, make sure you return ..() so the check for use_me is s message = getMessage(user) text = message audible = isAudible - if(user.mind && user.mind.miming) - audible = 0 + /datum/emote/custom/proc/getMessage(var/mob/user) var/input = sanitize(copytext(input(user,"Choose an emote to display.") as text|null,1,MAX_MESSAGE_LEN)) From 97d9831bd9482df317c56ce611719d203a1d4f62 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Tue, 17 May 2016 11:27:51 +0100 Subject: [PATCH 011/129] more tweaks --- code/datums/Emote_system/emote.dm | 37 ++++++++++++++++--------------- 1 file changed, 19 insertions(+), 18 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index f12d0e20214..6343c17c7c5 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -143,13 +143,12 @@ VampyrBytes else if(checkForParams(params)) message = paramMessage(user, params) else - message = "[user] [text]" + message = "\The [user] [text]" if(message && "target" in params) - if(params["target"]) - message = addTarget(user, params, message) - message = addExtras(message) + message = addTarget(user, params, message) + message = addExtras(user, params, message) return message /datum/emote/proc/checkForParams(var/list/params) @@ -158,7 +157,7 @@ VampyrBytes continue return 1 -/datum/emote/proc/addExtras(var/message) +/datum/emote/proc/addExtras(var/mob/user, var/list/params, var/message) if(!message) return if(startText) @@ -173,8 +172,7 @@ VampyrBytes return paramMimeMessage(user, params) var/message = "[user] [mimeText]" if(message && "target" in params) - if(params["target"]) - message = addTarget(user, params, message) + message = addTarget(user, params, message) return message /datum/emote/proc/muzzleMessage(var/mob/user) @@ -202,16 +200,20 @@ VampyrBytes // What you should see when you perform the emote /datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") - if(startText && selfStart) - message = replacetext(message, "[user]", "you") - else - message = replacetext(message, "[user]", "You") - if(selfText) - message = replacetext(message, text, selfText) - if(!selfStart) - var/start = findtextEx(message, startText) - var/end = start + lentext(startText) + 1 - message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) + if(!selfText) + return message + + message = replacetext(message, text, selfText) + + if(startText) + if(selfStart) + message = replacetext(message, "[user]", "you") + else + message = replacetext(message, "[user]", "You") + + var/start = findtextEx(message, startText) + var/end = start + lentext(startText) + 1 + message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) return message @@ -271,7 +273,6 @@ VampyrBytes recipients = get_mobs_in_view(7, user) return recipients - // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones /datum/emote/proc/createBlindMessage(var/mob/user, var/message, var/list/params) From 5c6474ffc0976e8b9384f926ae778a0184251fa0 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Wed, 18 May 2016 14:45:14 +0100 Subject: [PATCH 012/129] Adds better text macro support, default cooldown for emotes with sound and some cleaning --- code/datums/Emote_system/emote.dm | 92 ++++++++++++++++------- code/datums/Emote_system/emote_handler.dm | 2 +- code/modules/mob/emote.dm | 2 +- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 6343c17c7c5..09a111b009f 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -6,6 +6,7 @@ The only exception to this is custom emotes, which are created as needed and onl VampyrBytes *******************************************************************************************************/ +#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts /datum/emote var/name = "" @@ -18,11 +19,12 @@ VampyrBytes var/audible = 0 var/mimeText = "" + var/mimeSelf = "" //self version of mimeText var/sound // sound file var/vol = 50 var/muzzleAffected = 0 // whether being muzzled affects this emote var/muzzledNoise = "" // if the emote is audible and you're muzzled, this is what type of noise you make (eg weak, loud). - var/cooldown = 0 + var/cooldown = 0 // How long the cooldown should be on this emote. Defaults to EMOTE_COOLDOWN if not set and the emote plays a sound var/restrained = 0 // 1 if being restrained prevents this emote @@ -46,6 +48,8 @@ VampyrBytes if(count == 4) baseLevel = 0 break + if(sound && !cooldown) + cooldown = EMOTE_COOLDOWN /datum/emote/proc/doEmote(var/mob/user) if(!istype(user)) @@ -67,7 +71,8 @@ VampyrBytes message = createMessage(user, params) if(message) - . = outputMessage(user, message, params) + message = addExtras(user, params, message) + . = outputMessage(user, params, message) if(!doMime(user)) @@ -132,7 +137,7 @@ VampyrBytes /datum/emote/proc/createMessage(var/mob/user, var/list/params) if(!text) return - var/message + var/message = "" if(doMime(user)) message = mimeMessage(user, params) @@ -143,12 +148,11 @@ VampyrBytes else if(checkForParams(params)) message = paramMessage(user, params) else - message = "\The [user] [text]" + message = standardMessage(user) if(message && "target" in params) message = addTarget(user, params, message) - message = addExtras(user, params, message) return message /datum/emote/proc/checkForParams(var/list/params) @@ -157,7 +161,7 @@ VampyrBytes continue return 1 -/datum/emote/proc/addExtras(var/mob/user, var/list/params, var/message) +/datum/emote/proc/addExtras(var/mob/user, var/list/params, var/message = "") if(!message) return if(startText) @@ -165,18 +169,22 @@ VampyrBytes message = "[message]" return message +/datum/emote/proc/standardMessage(var/mob/user) + var/message = "\The [user] [text]" + return message + /datum/emote/proc/mimeMessage(var/mob/user, var/list/params) if(!mimeText) return if(checkForParams(params)) return paramMimeMessage(user, params) - var/message = "[user] [mimeText]" + var/message = "\The [user] [mimeText]" if(message && "target" in params) message = addTarget(user, params, message) return message /datum/emote/proc/muzzleMessage(var/mob/user) - var/message = "[user] makes a " + var/message = "\The [user] makes a " if(muzzledNoise) message += "[muzzledNoise] " message += "noise" @@ -195,37 +203,44 @@ VampyrBytes return message if(!params["target"]) return message - message += " [targetText] \the [params["target"]]" + if(params["target"] == user) + message += " [targetText] [getHimself(user)]" + else + message += " [targetText] \the [params["target"]]" return message // What you should see when you perform the emote -/datum/emote/proc/createSelfMessage(var/mob/user, var/message = "") +/datum/emote/proc/createSelfMessage(var/mob/user, var/list/params, var/message = "") if(!selfText) return message message = replacetext(message, text, selfText) + message = changeTextMacros(user, message) - if(startText) - if(selfStart) - message = replacetext(message, "[user]", "you") - else - message = replacetext(message, "[user]", "You") + if(mimeSelf) + message = replacetext(message, mimeText, mimeSelf) - var/start = findtextEx(message, startText) - var/end = start + lentext(startText) + 1 - message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) + if(selfStart && startText) + message = replacetext(message, "\The [user]", "you") + else + message = replacetext(message, "\The [user]", "You") + + if(startText && !selfStart) + var/start = findtextEx(message, startText) + var/end = start + lentext(startText) + 1 + message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) return message -/datum/emote/proc/outputMessage(var/mob/user, var/message = "", var/list/params) +/datum/emote/proc/outputMessage(var/mob/user, var/list/params, var/message = "") var/visualOrAudible = audible + 1 if(doMime(user)) visualOrAudible = 1 - var/selfMessage = createSelfMessage(user, message) + var/selfMessage = createSelfMessage(user, params, message) log_emote("[user.name]/[user.key] : [message]") sendToDead(message) - + testing(message) for(var/mob/M in getRecipients(user, visualOrAudible)) var/msg = "" @@ -243,7 +258,7 @@ VampyrBytes continue if((!(M in getRecipients(user, 1))) || M.see_invisible < user.invisibility) continue - msg = createDeafMessage(user, message, params) + msg = createDeafMessage(user, params, message) if(!msg && visualOrAudible == 2) continue @@ -251,7 +266,7 @@ VampyrBytes else if(M.sdisabilities & BLIND || M.blinded || M.paralysis || (M.see_invisible < user.invisibility && visualOrAudible == 2)) if(!(M in getRecipients(user, 2))) continue - msg = createBlindMessage(user, message, params) + msg = createBlindMessage(user, params, message) if(!msg && visualOrAudible == 1) continue @@ -275,16 +290,16 @@ VampyrBytes // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones -/datum/emote/proc/createBlindMessage(var/mob/user, var/message, var/list/params) +/datum/emote/proc/createBlindMessage(var/mob/user, var/list/params, var/message) if(audible && selfText) return "You hear someone [selfText]" // set up different messages for deaf people here. Empty will mean no message for // audible emotes and standard for non-audible ones -/datum/emote/proc/createDeafMessage(var/mob/user, var/message, var/list/params) +/datum/emote/proc/createDeafMessage(var/mob/user, var/list/params, var/message) return mimeMessage(user, params) -/datum/emote/proc/sendToDead(message) +/datum/emote/proc/sendToDead(var/message = "") for(var/mob/M in dead_mob_list) if(!M.client || istype(M, /mob/new_player)) continue //skip monkeys, leavers and new players @@ -307,6 +322,7 @@ VampyrBytes if(user.emote_cd == 1) return 1 // Already on CD, prevent use user.emote_cd = 1 // Starting cooldown + spawn(cooldown) if(user.emote_cd == 2) return 1 // Don't reset if cooldown emotes were disabled by an admin during the cooldown user.emote_cd = 0 // Cooldown complete, ready for more! @@ -314,6 +330,30 @@ VampyrBytes return 0 // Proceed with emote //--FalseIncarnate +/datum/emote/proc/changeTextMacros(var/mob/user, var/message = "") + message = swapHisToYour(user, message) + message = swapHimselfToYourself(user, message) + return message + +/datum/emote/proc/getHis(var/mob/user) + var/his = "[user]\his" + his = copytext(his, lentext("[user]") + 1) + return his + +/datum/emote/proc/swapHisToYour(var/mob/user, var/message = "") + var/his = getHis(user) + message = replacetext(message, his, "your") + return message + +/datum/emote/proc/getHimself(var/mob/user) + var/himself = "[user]\himself" + himself = copytext(himself, lentext("[user]") + 1) + return himself + +/datum/emote/proc/swapHimselfToYourself(var/mob/user, var/message) + var/himself = getHimself(user) + message = replacetext(message, himself, "yourself") + return message /****************************************************************************************** Emote Verbs diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index d30d542aaec..ca8c14914f3 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -70,7 +70,7 @@ var/datum/emote/em = new t if(em.allowParent) continue - found = searchTree(em, 1) + found = searchTree(em) if(found) return (found) if(emote.available(owner)) diff --git a/code/modules/mob/emote.dm b/code/modules/mob/emote.dm index 201e54ef839..2832d70c90a 100644 --- a/code/modules/mob/emote.dm +++ b/code/modules/mob/emote.dm @@ -1,4 +1,4 @@ -#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts + //Emote Cooldown System (it's so simple!) /* From 0661c056053305a84a2fcb0e41e45f5301cdc730 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Thu, 26 May 2016 12:13:29 +0100 Subject: [PATCH 013/129] tweaks and cleaning --- code/datums/Emote_system/emote.dm | 168 ++++++++++++++-------- code/datums/Emote_system/emote_handler.dm | 2 +- 2 files changed, 112 insertions(+), 58 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index 09a111b009f..a8da598c573 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -7,6 +7,7 @@ VampyrBytes *******************************************************************************************************/ #define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts +#define HEARING_RANGE 7 /datum/emote var/name = "" @@ -33,7 +34,8 @@ VampyrBytes var/targetText = "at" // what goes inbetween user and target var/takesNumber = 0 // 1 if the emote uses a number parameter - var/spanClass = "notice" + var/emoteSpanClass = "notice" + var/userSpanClass = "em" var/baseLevel = 1 var/allowParent = 0 // 1 if you want the parent available as well as this one @@ -48,10 +50,15 @@ VampyrBytes if(count == 4) baseLevel = 0 break + if(sound && !cooldown) cooldown = EMOTE_COOLDOWN -/datum/emote/proc/doEmote(var/mob/user) + if(targetText) + if(!findtextEx(targetText, " ", lentext(targetText))) + targetText += " " + +/datum/emote/proc/doEmote(var/mob/user, var/command = "") if(!istype(user)) return if(cooldown) @@ -72,15 +79,18 @@ VampyrBytes if(message) message = addExtras(user, params, message) - . = outputMessage(user, params, message) + . = processMessage(user, params, message) - - if(!doMime(user)) + if(!doMime(user) && (!muzzleAffected || !isMuzzled(user))) if(playSound(user, vol)) . = 2 doAction(user, params) + for (var/obj/item/weapon/implant/I in user) + if (I.implanted) + I.trigger(command, user) + return // for things that the emote does that aren't text or sound based @@ -99,7 +109,7 @@ VampyrBytes // return "invalid" from either of these getters if you've tested the input and it's failed /datum/emote/proc/getNumber(var/mob/user) - var/number = input("How many") as null|num + var/number = input("How many?", "Enter number") as null|num return number /datum/emote/proc/getTarget(var/mob/user) @@ -141,20 +151,30 @@ VampyrBytes if(doMime(user)) message = mimeMessage(user, params) + if(message) + return message - if(!message) - if(muzzleAffected && user.is_muzzled()) - message = muzzleMessage(user) - else if(checkForParams(params)) - message = paramMessage(user, params) - else - message = standardMessage(user) + if(muzzleAffected && isMuzzled(user)) + message = muzzleMessage(user, params) + return message - if(message && "target" in params) - message = addTarget(user, params, message) + if(checkForParams(params)) + message = paramMessage(user, params) + return message + + message = standardMessage(user, params) return message +/datum/emote/proc/isMuzzled(var/mob/user) + if(user.sdisabilities & MUTE || user.is_muzzled()) + return 1 + if(!isliving(user)) + return + var/mob/living/L = user + if (L.silent) + return 1 + /datum/emote/proc/checkForParams(var/list/params) for(var/p in params) if(p == "target") @@ -166,11 +186,13 @@ VampyrBytes return if(startText) message = "[startText] [message]" - message = "[message]" + message = "[message]" return message -/datum/emote/proc/standardMessage(var/mob/user) - var/message = "\The [user] [text]" +/datum/emote/proc/standardMessage(var/mob/user, var/list/params) + var/message = "\The [user] [text]" + if("target" in params) + message = addTarget(user, params, message) return message /datum/emote/proc/mimeMessage(var/mob/user, var/list/params) @@ -178,13 +200,13 @@ VampyrBytes return if(checkForParams(params)) return paramMimeMessage(user, params) - var/message = "\The [user] [mimeText]" + var/message = "\The [user] [mimeText]" if(message && "target" in params) message = addTarget(user, params, message) return message -/datum/emote/proc/muzzleMessage(var/mob/user) - var/message = "\The [user] makes a " +/datum/emote/proc/muzzleMessage(var/mob/user, var/list/params) + var/message = "\The [user] makes a " if(muzzledNoise) message += "[muzzledNoise] " message += "noise" @@ -204,11 +226,12 @@ VampyrBytes if(!params["target"]) return message if(params["target"] == user) - message += " [targetText] [getHimself(user)]" - else - message += " [targetText] \the [params["target"]]" + message += " [targetText][getHimself(user)]" + return message + message += " [targetText]\the [params["target"]]" return message + // What you should see when you perform the emote /datum/emote/proc/createSelfMessage(var/mob/user, var/list/params, var/message = "") if(!selfText) @@ -220,23 +243,26 @@ VampyrBytes if(mimeSelf) message = replacetext(message, mimeText, mimeSelf) - if(selfStart && startText) - message = replacetext(message, "\The [user]", "you") - else - message = replacetext(message, "\The [user]", "You") - if(startText && !selfStart) var/start = findtextEx(message, startText) var/end = start + lentext(startText) + 1 message = copytext(message, 1, start) + copytext(message, end, lentext(message) + 1) + message = replaceMobWithYou(user, message) + return message -/datum/emote/proc/outputMessage(var/mob/user, var/list/params, var/message = "") +/datum/emote/proc/replaceMobWithYou(var/mob/M, var/message = "", var/mob/user) // user passed in in case an override needs to do something different if M != user (see johnny) VB + + message = replacetext(message, "\The [M]", "You") + message = replacetext(message, "\the [M]", "you") + + return message + +/datum/emote/proc/processMessage(var/mob/user, var/list/params, var/message = "") var/visualOrAudible = audible + 1 if(doMime(user)) visualOrAudible = 1 - var/selfMessage = createSelfMessage(user, params, message) log_emote("[user.name]/[user.key] : [message]") sendToDead(message) @@ -244,55 +270,83 @@ VampyrBytes for(var/mob/M in getRecipients(user, visualOrAudible)) var/msg = "" - if(selfMessage && M==user) - msg = selfMessage - - else if(M.stat == UNCONSCIOUS || (M.sleeping > 0 && M.stat != 2)) - if (visualOrAudible == 2) - msg = "... You can almost hear someone talking ..." - else + if(M==user) + msg = createSelfMessage(user, params, message) + if(msg) + outputMessage(M, msg) continue - else if(M.sdisabilities & DEAF || M.ear_deaf) + if(M.stat == UNCONSCIOUS || (M.sleeping > 0 && M.stat != 2)) + if (!visualOrAudible == 2) + continue + msg = "... You can almost hear someone talking ..." + outputMessage(M, msg) + continue + + if(M.sdisabilities & DEAF || M.ear_deaf) if(M.sdisabilities & BLIND || M.blinded || M.paralysis) continue - if((!(M in getRecipients(user, 1))) || M.see_invisible < user.invisibility) + if(!(M in getRecipients(user, 1)) || M.see_invisible < user.invisibility) continue - msg = createDeafMessage(user, params, message) + msg = createDeafMessage(user, params, message) if(!msg && visualOrAudible == 2) continue + if(msg) + outputMessage(M, msg) + continue - else if(M.sdisabilities & BLIND || M.blinded || M.paralysis || (M.see_invisible < user.invisibility && visualOrAudible == 2)) + if(M.sdisabilities & BLIND || M.blinded || M.paralysis || (M.see_invisible < user.invisibility && visualOrAudible == 2)) if(!(M in getRecipients(user, 2))) continue + msg = createBlindMessage(user, params, message) if(!msg && visualOrAudible == 1) continue + if(msg) + outputMessage(M, msg) + continue - else if(M.see_invisible < user.invisibility) + if(M.see_invisible < user.invisibility && visualOrAudible == 1) continue - if(!msg) - msg = message + msg = message + outputMessage(M, msg) + + if(visualOrAudible == 2) + handleListeningObjects(user, message) - to_chat(M, msg) return visualOrAudible +/datum/emote/proc/outputMessage(var/mob/M, var/msg = "") + msg = replaceMobWithYou(M, msg, M) + to_chat(M, msg) + +/datum/emote/proc/handleListeningObjects(var/mob/user, var/message = "") + // based on say code + var/omsg = replacetext(message, "[user] ", "") + var/list/listening_obj = new + for(var/atom/movable/A in view(HEARING_RANGE, user)) + if(istype(A, /mob)) + var/mob/M = A + for(var/obj/O in M.contents) + listening_obj |= O + else if(istype(A, /obj)) + var/obj/O = A + listening_obj |= O + for(var/obj/O in listening_obj) + O.hear_message(user, omsg) + /datum/emote/proc/getRecipients(var/mob/user, var/visualOrAudible) - var/list/recipients[0] - switch(visualOrAudible) - if(1) - recipients = viewers(user) - if(2) - recipients = get_mobs_in_view(7, user) - return recipients + if(visualOrAudible == 1) + return viewers(user) + return get_mobs_in_view(HEARING_RANGE, user) // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones /datum/emote/proc/createBlindMessage(var/mob/user, var/list/params, var/message) if(audible && selfText) - return "You hear someone [selfText]" + return "You hear someone [selfText]" // set up different messages for deaf people here. Empty will mean no message for // audible emotes and standard for non-audible ones @@ -306,7 +360,7 @@ VampyrBytes if(M.stat == DEAD && (M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(src,null))) M.show_message(message) -/datum/emote/proc/playSound(var/mob/user) +/datum/emote/proc/playSound(var/mob/user, var/list/params) if(!sound) return playsound(user, sound, vol) @@ -440,7 +494,7 @@ available, but if you do, make sure you return ..() so the check for use_me is s /datum/emote/custom/ghost name = "Ghost emote" startText = "DEAD: " - spanClass = "game deadsay" + emoteSpanClass = "game deadsay" /datum/emote/custom/ghost/prevented(var/mob/user) if(user.client.prefs.muted & MUTE_DEADCHAT) @@ -451,7 +505,7 @@ available, but if you do, make sure you return ..() so the check for use_me is s if(!config.dsay_allowed) return "deadchat is globally muted" -/datum/emote/custom/ghost/outputMessage(var/mob/user, var/message = "") +/datum/emote/custom/ghost/processMessage(var/mob/user, var/message = "") if(!message) return log_emote("Ghost/[user.key] : [message]") diff --git a/code/datums/Emote_system/emote_handler.dm b/code/datums/Emote_system/emote_handler.dm index ca8c14914f3..1417e83f9a8 100644 --- a/code/datums/Emote_system/emote_handler.dm +++ b/code/datums/Emote_system/emote_handler.dm @@ -49,7 +49,7 @@ if(prevented) to_chat(owner, "You can't do that because [prevented]!") return 0 - return emote.doEmote(owner) + return emote.doEmote(owner, command) /datum/emoteHandler/proc/showCommands() var/emoteList = "Available emotes are " From 2bd66d86928b7ec692cf319ba6fe4bbaf57c9be3 Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Thu, 26 May 2016 12:14:52 +0100 Subject: [PATCH 014/129] Every emote added! Thank god that's over with! --- code/datums/Emote_system/emotes.dm | 1895 ++++++++++++++++++++++++++-- 1 file changed, 1801 insertions(+), 94 deletions(-) diff --git a/code/datums/Emote_system/emotes.dm b/code/datums/Emote_system/emotes.dm index 12d30be4c26..190759df693 100644 --- a/code/datums/Emote_system/emotes.dm +++ b/code/datums/Emote_system/emotes.dm @@ -2,12 +2,12 @@ Emotes New() must call ..() to set the baseLevel for the emoteHandler search. As the commands are set in New(), this means that the emote will pick up all the commands from the emotes -above it. If you don't want this, make the call to ..() then use commands = new /list() +above it. If you don't want this, make the call to ..() then use commands.cut() *************************************************************************************/ /datum/emote/airguitar name = "airguitar" - desc = "Play an air guitar" + desc = "Makes the mob play an air guitar" text = "is strumming the air and headbanging like a safari chimp." selfText = "are strumming the air and headbanging like a safari chimp." restrained = 1 @@ -24,7 +24,7 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/alarm name = "alarm" - desc = "Sound an alarm" + desc = "makes the mob sound an alarm" text = "sounds an alarm" selfText = "sound an alarm" audible = 1 @@ -37,14 +37,14 @@ above it. If you don't want this, make the call to ..() then use commands = new if(isbrain(user)) return 1 -/datum/emote/alarm/createBlindMessage(var/mob/user, var/messaage) +/datum/emote/alarm/createBlindMessage(var/mob/user, var/params, var/messaage) return "You hear an alarm" /datum/emote/alert name = "alert" - desc = "Sound an alert" + desc = "Makes the mob sound an alert" text = "lets out a distressed noise" - selfText = "let out a distressed noise)" + selfText = "let out a distressed noise" audible = 1 /datum/emote/alert/New() @@ -54,12 +54,10 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/alert/available(var/mob/user) if(isbrain(user)) return 1 -/datum/emote/alert/createBlindMessage(var/mob/user, var/message) - return "you hear an alert" /datum/emote/beep name = "beep" - desc = "let out a beep" + desc = "makes the mob let out a beep" text = "beeps" selfText = "beep" audible = 1 @@ -73,26 +71,19 @@ above it. If you don't want this, make the call to ..() then use commands = new if(isbrain(user)) return 1 -/datum/emote/beep/createBlindMessage(var/mob/user, var/message) - return "You hear a beep" - /datum/emote/beep/targetted - cooldown = 1 sound = 'sound/machines/twobeep.ogg' + cooldown = 50 canTarget = 1 targetMob = 1 /datum/emote/beep/targetted/available(var/mob/user) - if(issilicon(user)) - return 1 - if(isbot(user)) - return 1 - if(user.get_species() == "Machine") + if(user.is_mechanical()) return 1 /datum/emote/blink name = "blink" - desc = "blink" + desc = "Makes the mob blink" text = "blinks" selfText = "blink" @@ -109,27 +100,27 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/blink/rapid name = "rapid blink" - desc = "blink rapidly" + desc = "Makes the mob blink rapidly" allowParent = 1 /datum/emote/blink/rapid/New() ..() - commands = new/list() + commands = new /list() commands += "blink_r" commands += "blinks_r" /datum/emote/blink/rapid/available(var/mob/user) if(ishuman(user)) - return + return 1 -/datum/emote/blink/rapid/createMessage(var/mob/user, var/number) +/datum/emote/blink/rapid/standardMessage(var/mob/user) var/message = ..() message += " rapidly" return message /datum/emote/blush name = "blush" - desc = "blush" + desc = "Makes the mob blush" text = "blushes" selfText = "blush" @@ -144,7 +135,7 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/boop name = "boop" - desc = "boop" + desc = "Makes the mob boop" text = "boops" selfText = "boop" @@ -159,7 +150,7 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/bounce name = "bounce" - desc = "bounce" + desc = "Makes the mob bounce" text = "bounces in place" selfText = "bounce in place" @@ -174,7 +165,7 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/bow name = "bow" - desc = "bow" + desc = "Makes the mob bow" text = "bows" selfText = "bow" canTarget = 1 @@ -199,12 +190,14 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/burp name = "burp" - desc = "burp" + desc = "Makes the mob burp" text = "burps" selfText = "burp" - muzzledNoise = "peculiar" - mimeText = "opens their mouth rather obnoxiously" audible = 1 + mimeText = "opens their mouth rather obnoxiously" + mimeSelf = "open your mouth rather obnoxiously" + muzzleAffected = 1 + muzzledNoise = "peculiar" /datum/emote/burp/New() ..() @@ -214,16 +207,1194 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/burp/available(var/mob/user) if(ishuman(user)) return 1 - if(istype(user, /mob/living/carbon/alien/larva) || istype(user, /mob/living/carbon/alien/humanoid)) + if(islarva(user) || isalienadult(user)) + return 1 + +/datum/emote/buzz + name = "buzz" + desc = "Makes the mob buzz" + text = "buzzes" + selfText = "buzz" + audible = 1 + sound = 'sound/machines/buzz-sigh.ogg' + cooldown = 50 + canTarget = 1 + targetMob = 1 + +/datum/emote/buzz/New() + ..() + commands += "buzz" + commands += "buzzes" + commands += "buzzs" + +/datum/emote/buzz/available(var/mob/user) + if(user.is_mechanical()) + return 1 + +/datum/emote/chirp + name = "chirp" + desc = "Makes the mob chirp" + text = "chirps" + selfText = "chirp" + audible = 1 + sound = 'sound/misc/nymphchirp.ogg' + vol = 40 + cooldown = 50 + +/datum/emote/chirp/New() + ..() + commands += "chirp" + commands += "chirps" + +/datum/emote/chirp/available(var/mob/user) + if(istype(user, /mob/living/simple_animal/diona)) + return 1 + +/datum/emote/chirp/playSound(var/mob/user) + if (!sound) + return + playsound(user, sound, vol, 1, 1) + return 1 + +/datum/emote/choke + name = "choke" + desc = "Makes the mob choke" + text = "chokes" + selfText = "choke" + audible = 1 + mimeText = "clutches" + mimeSelf = "clutch" + muzzleAffected = 1 + muzzledNoise = "strong" + +/datum/emote/choke/New() + ..() + commands += "choke" + commands += "chokes" + +/datum/emote/choke/available(var/mob/user) + if(ishuman(user)) + return 1 + if(islarva(user) || isalienadult(user)) + return 1 + +// This has to be done here not mimeText because \his will throw a compile error +// instead of a runtime if there's not a valid target in the string *frown VB +/datum/emote/choke/mimeMessage(var/mob/user, var/list/params) + var/message = "[user] [mimeText] \his throat desperately" + return message + +/datum/emote/chuckle + name = "chuckle" + desc = "chuckle" + text = "chuckles" + selfText = "chuckle" + audible = 1 + mimeText = "appears to chuckle" + mimeSelf = "appear to chuckle" + muzzleAffected = 1 + +/datum/emote/chuckle/New() + ..() + commands += "chuckle" + commands += "chuckles" + +/datum/emote/chuckle/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/clap + name = "clap" + desc = "clap" + text = "claps" + selfText = "clap" + audible = 1 + mimeText = "claps silently" + restrained = 1 + +/datum/emote/clap/New() + ..() + commands += "clap" + commands += "claps" + +/datum/emote/clap/available(var/mob/user) + if(isrobot(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/collapse + name = "collapse" + desc = "Makes the mob collapse" + text = "collapses" + selfText = "collapse" + audible = 1 + mimeText = "collapses without a sound" + +/datum/emote/collapse/New() + ..() + commands += "collapse" + commands += "collapses" + +/datum/emote/collapse/available(var/mob/user) + if(islarva(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/collapse/doAction(var/mob/user, var/list/params) + user.Paralyse(2) + +/datum/emote/cough + name = "cough" + desc = "Makes the mob cough" + text = "coughs" + selfText = "cough" + audible = 1 + mimeText = "appears to cough" + mimeSelf = "appear to cough" + muzzleAffected = 1 + muzzledNoise = "strong" + +/datum/emote/cough/New() + ..() + commands += "cough" + commands += "coughs" + +/datum/emote/cough/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/cry + name = "cry" + desc = "Makes the mob cry" + text = "cries" + selfText = "cry" + audible = 1 + mimeText = "cries silently" + muzzleAffected = 1 + muzzledNoise = "weak" + +/datum/emote/cry/New() + ..() + commands += "cry" + commands += "cries" + +/datum/emote/cry/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/dance + name = "dance" + desc = "makes the mob dance around happily" + text = "dances around happily" + selfText = "dance around happily" + restrained = 1 + +/datum/emote/dance/New() + ..() + commands += "dance" + commands += "dances" + +/datum/emote/dance/available(var/mob/user) + if(islarva(user)) + return 1 + +/datum/emote/dap + name = "dap" + desc = "Makes the mob give daps" + text = "gives daps" + selfText = "give daps" + restrained = 1 + canTarget = 1 + targetMob = 1 + targetText = "to" + +/datum/emote/dap/New() + ..() + commands += "dap" + commands += "daps" + +/datum/emote/dap/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/dap/addTarget(var/mob/user, var/list/params, var/message = "") + if(!params["target"] || params["target"] == user) + message = "[user] sadly can't find anybody to give daps to, and daps \himself. Shameful." + return message + return ..() + +/datum/emote/deathgasp + name = "deathgasp" + desc = "Makes the mob let out it's final gasp" + audible = 1 + +/datum/emote/deathgasp/New() + ..() + commands += "deathgasp" + commands += "deathgasps" + +/datum/emote/deathgasp/alien + text = "lets out a waning guttural screech, green blood bubbling from its maw..." + selfText = "let out a waning guttural screech, green blood bubbling from your maw..." + +/datum/emote/deathgasp/alien/available(var/mob/user) + if(isalienadult(user)) + return 1 + +// sorry, no selftext for humans as we'd have to add a var to species for it and that's yuk - VB +/datum/emote/deathgasp/human + text = "dummytext" + +/datum/emote/deathgasp/human/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/deathgasp/human/standardMessage(var/mob/user, var/list/params) + var/mob/living/carbon/human/U = user + var/message = "\The [user] [U.species.death_message]" + return message + +/datum/emote/deathgasp/robot + text = "shudders violently for a moment, then becomes motionless, its eyes slowly darkening." + selfText = "shudder violently for a moment, then become motionless, your eyes slowly darkening." + audible = 0 + +/datum/emote/drone + name = "drone" + desc = "Makes the mob drone and rumble" + text = "rumbles" + selfText = "rumble" + audible = 1 + sound = 'sound/voice/DraskTalk.ogg' + canTarget = 1 + targetMob = 1 + +/datum/emote/drone/New() + ..() + commands += "drone" + commands += "drones" + commands += "rumble" + commands += "rumbles" + commands += "hum" + commands += "hums" + +/datum/emote/drone/available(var/mob/user) + if(!ishuman(user)) + return + var/mob/living/carbon/human/H = user + if(H.species == "Drask") + return 1 + +/datum/emote/drone/addTarget(var/mob/user, var/list/params, var/message) + var/msg = ..() + if(msg == message) + return message + message = replacetext(message, "rumbles", "drones") + return message + +/datum/emote/drone/createSelfMessage(var/mob/user, var/list/params, var/message) + message = ..() + message = replacetext(message, "drones", "drone") + return message + +/datum/emote/deathgasp/robot/available(var/mob/user) + if(isrobot(user)) + return 1 + +/datum/emote/drool + name = "drool" + desc = "Makes the mob drool" + text = "drools" + selfText = "drool" + +/datum/emote/drool/New() + ..() + commands += "drool" + commands += "drools" + +/datum/emote/drool/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/eyebrow + name = "eyebrow" + desc = "Makes the mob raise an eyebrow" + text = "raises an eyebrow" + selfText = "raise an eyebrow" + +/datum/emote/eyebrow/New() + ..() + commands += "eyebrow" + +/datum/emote/eyebrow/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/faint + name = "faint" + desc = "makes the mob faint" + text = "faints" + selfText = "faint" + +/datum/emote/faint/New() + ..() + commands += "faint" + commands += "faints" + +/datum/emote/faint/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/faint/doAction(var/mob/user, var/list/params) + if(!user.sleeping) + user.sleeping += 1 + +/datum/emote/fart + name = "fart" + text = "farts" + selfText = "fart" + cooldown = 50 + audible = 1 + +/datum/emote/fart/New() + ..() + commands += "fart" + commands += "farts" + +/datum/emote/fart/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/fart/standardMessage(var/mob/user) + var/message + if(SUPER_FART in user.mutations) + return // super fart will make the message when triggered + + if(TOXIC_FARTS in user.mutations) + message = "\The [user] unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart." + else + message = "\The [user] [pick("passes wind","farts")]." + return message + +/datum/emote/fart/createSelfMessage(var/mob/user, var/list/params, var/message) + message = ..() + message = replacetext(message, "unleashes", "unleash") + message = replacetext(message, "passes", "pass") + return message + +/datum/emote/fart/doAction(var/mob/user) + if(TOXIC_FARTS in user.mutations) + for(var/mob/M in range(get_turf(user),2)) + if (M.internal != null && M.wear_mask && (M.wear_mask.flags & AIRTIGHT)) + continue + if (M == user) + continue + M.reagents.add_reagent("space_drugs",rand(1,10)) + + if(SUPER_FART in user.mutations) + var/mob/living/U = user + for(var/datum/action/spell_action/spell in U.actions) + if (spell.name == "Super Fart") + spell.Trigger() + break + + if(locate(/obj/item/weapon/storage/bible) in get_turf(user)) + if(SUPER_FART in user.mutations) + sleep(30) // need to wait for them to finish the super fart before gibbing them + + to_chat(viewers(user), "[user] farted on the Bible!") + to_chat(viewers(user), "A mysterious force smites [user]!") + var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread + s.set_up(3, 1, user) + s.start() + user.gib() + +/datum/emote/flap + name = "flap" + desc = "Makes the mob flap their wings" + text = "flaps" + selfText = "flap" + restrained = 1 + audible = 1 + +/datum/emote/flap/New() + ..() + commands += "flap" + commands += "flaps" + +/datum/emote/flap/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/flap/standardMessage(var/mob/user, var/list/params) + var/message = "\The [user] [text] \his wings" + return message + +/datum/emote/flap/angry + name = "angry flap" + desc = "makes the mob flap their wings angrily" + allowParent = 1 + +/datum/emote/flap/angry/New() + ..() + commands = new /list() + commands += "a_flap" + commands += "a_flaps" + +/datum/emote/flap/angry/standardMessage(var/mob/user) + var/message = ..() + message += " angrily" + return message + +/datum/emote/flash + name = "flash" + desc = "Makes the lights on the mob flash quickly" + text = "flash quickly" + selfText = "flash quickly" + startText = "The lights on" + +/datum/emote/flash/New() + ..() + commands += "flash" + commands += "flashes" + +/datum/emote/flash/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/flip + name = "flip" + desc = "Makes the mob flip, possibly in the direction of someone" + text = "flips" + selfText = "flip" + canTarget = 1 + targetMob = 1 + targetText = "in" + +/datum/emote/flip/New() + ..() + commands += "flip" + commands += "flips" + +/datum/emote/flip/available(var/mob/user) + if(isrobot(user)) + return 1 + +/datum/emote/flip/prevented(var/mob/user) + . = ..() + if(!. && user.buckled) + return "you are buckled to something" + +/datum/emote/flip/createMessage(var/mob/user, var/list/params) + var/message = "" + if(user.lying || user.weakened) + message = "\The [user] flops and flails around on the floor." + else + message = ..() + return message + +/datum/emote/flip/addTarget(var/mob/user, var/list/params, var/message) + message = ..() + if(params["target"]) + message += "'s general direction" + return message + +/datum/emote/flip/createSelfMessage(var/mob/user, var/list/params, var/message) + message = ..() + message = replacetext(message, "flops", "flop") + message = replacetext(message, "flails", "flail") + return message + +/datum/emote/flip/doAction(var/mob/user, var/list/params, var/message) + if(user.lying || user.weakened) + return + user.SpinAnimation(5,1) + +/datum/emote/flip/flipOver + desc = "Makes the mob flip, possibly in the direction of, or even over someone" + +/datum/emote/flip/flipOver/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/flip/flipOver/createMessage(var/mob/user, var/params) + var/message = "" + var/obj/item/weapon/grab/G = user.get_active_hand() + if(istype(G) && G.affecting && !G.affecting.buckled) + params["target"] = G.affecting + message = "\The [user] [text] over [params["target"]]!" + return message + return ..() + +/datum/emote/flip/flipOver/doAction(var/mob/user, var/params, var/message) + var/obj/item/weapon/grab/G = user.get_active_hand() + if(G == params["target"]) + var/turf/oldloc = user.loc + var/turf/newloc = G.affecting.loc + if(isturf(oldloc) && isturf(newloc)) + user.SpinAnimation(5,1) + user.forceMove(newloc) + G.affecting.forceMove(oldloc) + return + ..() + +/datum/emote/frown + name = "frown" + desc = "Makes the mob frown" + text = "frowns" + selfText = "frown" + +/datum/emote/frown/New() + ..() + commands += "frown" + commands += "frowns" + +/datum/emote/frown/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/gasp + name = "gasp" + desc = "Makes the mob gasp" + text = "gasps" + selfText = "gasp" + audible = 1 + mimeText = "appears to be gasping" + mimeSelf = "appear to be gasping" + muzzleAffected = 1 + muzzledNoise = "weak" + +/datum/emote/gasp/New() + ..() + commands += "gasp" + commands += "gasps" + +/datum/emote/gasp/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/giggle + name = "giggle" + desc = "Makes the mob giggle" + text = "giggles" + selfText = "giggle" + audible = 1 + mimeText = "giggles silently" + muzzleAffected = 1 + +/datum/emote/giggle/New() + ..() + commands += "giggle" + commands += "giggles" + +/datum/emote/giggle/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/glare + name = "glare" + desc = "Makes the mob glare" + text = "glares" + selfText = "glare" + canTarget = 1 + targetMob = 1 + +/datum/emote/glare/New() + ..() + commands += "glare" + commands += "glares" + +/datum/emote/glare/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/gnarl + name = "gnarl" + desc = "Makes the mob grarl and show its teeth" + text = "gnarls and shows its teeth" + selfText = "gnarl and show your teeth" + audible = 1 + muzzleAffected = 1 + +/datum/emote/gnarl/New() + ..() + commands += "gnarl" + commands += "gnarls" + +/datum/emote/gnarl/available(var/mob/user) + if(islarva(user)) + return 1 + +/datum/emote/grin + name = "grin" + desc = "Makes the mob grin" + text = "grins" + selfText = "grin" + +/datum/emote/grin/New() + ..() + commands += "grin" + commands += "grins" + +/datum/emote/grin/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/groan + name = "groan" + desc = "Makes the mob groan" + text = "groans" + selfText = "groan" + audible = 1 + mimeText = "appears to groan" + mimeSelf = "appear to groan" + muzzleAffected = 1 + +/datum/emote/groan/New() + ..() + commands += "groan" + commands += "groans" + +/datum/emote/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/grumble + name = "grumble" + desc = "Makes the mob grumble" + text = "grumbles" + selfText = "grumble" + audible = 1 + mimeText = "grumbles" + muzzleAffected = 1 + +/datum/emote/grumble/New() + ..() + commands += "grumble" + commands += "grumbles" + +/datum/emote/grumble/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/halt + name = "halt" + desc = "Makes the mob sound a halt warning. Only available with a security module" + text = "'s speakers skreech, \"Halt! Security!\"." + selfText = " speakers skreech, \"Halt! Security!\"." + audible = 1 + sound = 'sound/voice/halt.ogg' + +/datum/emote/halt/New() + ..() + commands += "halt" + +/datum/emote/halt/available(var/mob/user) + if(isrobot(user)) + return 1 + +/datum/emote/halt/prevented(var/mob/user) + . = ..() + if(.) + return + var/mob/living/silicon/robot/U = user + if (!(istype(U.module, /obj/item/weapon/robot_module/security))) + return "you are not security" + +/datum/emote/halt/standardMessage(var/mob/user) + var/message = "\The [user][text]" + return message + +/datum/emote/handshake + name = "handshake" + desc = "Makes the mob shake hands with a target" + text = "shakes hands" + selfText = "shake hands" + canTarget = 1 + targetMob = 1 + targetText = "with" + restrained = 1 + +/datum/emote/handshake/New() + ..() + commands += "handshake" + +/datum/emote/handshake/prevented(var/mob/user) + . = ..() + if(!. && user.r_hand) + return "you need your right hand free" + +/datum/emote/handshake/getMobTarget(var/mob/user) + var/mob/target = ..() + if(!target) + to_chat(user, "You need someone to shake hands with") + return "invalid" + +/datum/emote/handshake/addTarget(var/mob/user, var/list/params, var/message) + var/mob/target = params["target"] + if(target.r_hand) + message = "\The [user] holds out his hand to [params["target"]]" + return message + return ..() + +/datum/emote/hiss + name = "hiss" + desc = "Makes the mob hiss" + text = "hisses" + selfText = "hiss" + audible = 1 + +/datum/emote/hiss/New() + ..() + commands += "hiss" + commands += "hisses" + +/datum/emote/hiss/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + +/datum/emote/hug + name = "hug" + desc = "Makes the mob hug a target or themselves" + text = "hugs" + selfText = "hug" + canTarget = 1 + targetMob = 1 + +/datum/emote/hug/New() + ..() + commands += "hug" + commands += "hugs" + +/datum/emote/hug/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/hug/getTarget(var/mob/user) + var/mob/target = input("Select target", "Target Mob") as null|mob in view(1) + if(target) + return target + return user + +/datum/emote/jiggle + name = "jiggle" + desc = "Makes the mob jiggle" + text = "jiggles" + selfText = "jiggle" + +/datum/emote/jiggle/New() + ..() + commands += "jiggle" + commands += "jiggles" + +/datum/emote/jiggle/available(var/mob/user) + if(isslime(user)) + return 1 + +/datum/emote/johnny + name = "johnny" + desc = "Yeah, just try it" + text = "takes a drag from a cigarette and blows their name out in smoke." + selfText = "take a drag from a cigarette and blow their name out in smoke." + audible = 1 + mimeText = "takes a drag from a cigarette and blows" + mimeSelf = "take a drag from a cigarette and blow" + canTarget = 1 + targetMob = 1 + targetText = "" + +/datum/emote/johnny/New() + ..() + commands += "johnny" + +/datum/emote/johnny/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/johnny/getTarget(var/mob/user) + var/mob/target = ..() + if(target && target != user) + return target + to_chat(user, "You need a target that isn't yourself") + return "invalid" + +/datum/emote/johnny/createMessage(var/mob/user, var/params) + if(doMime(user)) + return ..() + var/message = "\The [user] says \"[params["target"]], please. They had a family.\" [user] [text]" + return message + +/datum/emote/johnny/createSelfMessage(var/mob/user, var/list/params, var/message = "") + message = ..() + message = replacetext(message, "says", "say") + return message + +/datum/emote/johnny/createDeafMessage(var/mob/user, vap/list/params, var/message) + message = "\The [user] says something, then [text]" + return message + +/datum/emote/johnny/replaceMobWithYou(var/mob/M, var/message, var/mob/user) + if(user && M != user) + return message + return ..() + +/datum/emote/jump + name = "jump" + desc = "Makes the mob jump" + text = "jumps" + selfText = "jump" + +/datum/emote/jump/New() + ..() + commands += "jump" + commands += "jumps" + +/datum/emote/jump/available(var/mob/user) + if(islarva(user)) + return 1 + +/datum/emote/laugh + name = "laugh" + desc = "Makes the mob laugh" + text = "laughs" + selfText = "laugh" + audible = 1 + mimeText = "acts out a laugh" + mimeSelf = "act out a laugh" + muzzleAffected = 1 + +/datum/emote/laugh/New() + ..() + commands += "laugh" + commands += "laughs" + +/datum/emote/laugh/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/law + name = "law" + desc = "Makes the mob prove it is the law" + text = "shows its legal authorization barcode." + selfText = "show your legal authorization barcode." + audible = 1 + sound = 'sound/voice/biamthelaw.ogg' + +/datum/emote/law/New() + ..() + commands += "law" + +/datum/emote/law/available(var/mob/user) + if(isrobot(user)) + return 1 + +/datum/emote/law/prevented(var/mob/user) + . = ..() + if(.) + return + var/mob/living/silicon/robot/U = user + if (!(istype(U.module, /obj/item/weapon/robot_module/security))) + return "You are not THE LAW, pal." + +/datum/emote/light + name = "light" + desc = "makes the mob light up" + text = "lights up for a bit, then stops." + selfText = "light up for a bit, then stop." + +/datum/emote/light/New() + ..() + commands += "light" + commands += "lights" + +/datum/emote/light/available(var/mob/user) + if(isslime(user)) + return 1 + +/datum/emote/look + name = "look" + desc = "Makes the mob look" + text = "looks" + selfText = "look" + canTarget = 1 + targetMob = 1 + +/datum/emote/look/New() + ..() + commands += "look" + commands += "looks" + +/datum/emote/look/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/moan + name = "moan" + desc = "Makes the mob moan" + text = "moans" + selfText = "moan" + audible = 1 + +/datum/emote/moan/New() + ..() + commands += "moan" + commands += "moans" + +/datum/emote/moan/available(var/mob/user) + if(isslime(user)) + return 1 + if(islarva(user)) + return 1 + +/datum/emote/mumble + name = "mumble" + desc = "Makes the mob mumble" + text = "mumbles" + selfText = "mumble" + audible = 1 + mimeText = "mumbles" + +/datum/emote/mumble/New() + ..() + commands += "mumble" + commands += "mumbles" + +/datum/emote/mumble/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/no + name = "no" + desc = "Makes the mob let out a negative blip" + text = "emits a negative blip" + selfText = "emit a negative blip" + audible = 1 + sound = 'sound/machines/synth_no.ogg' + +/datum/emote/no/New() + ..() + commands += "no" + +/datum/emote/no/available(var/mob/user) + if(user.is_mechanical()) + return 1 + +/datum/emote/nod + name = "nod" + desc = "Makes the mob nod" + text = "nods" + selfText = "nod" + +/datum/emote/nod/New() + ..() + commands += "nod" + commands += "nods" + +/datum/emote/nod/available(var/mob/user) + if(islarva(user)) + return 1 + if(isrobot(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/notice + name = "notice" + desc = "Makes the mob play a loud tone" + text = "plays a loud tone" + selfText = "play a loud tone" + audible = 1 + +/datum/emote/notice/New() + ..() + commands += "notice" + +/datum/emote/notice/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/pale + name = "pale" + desc = "Makes the mob go pale" + text = "goes pale for a second." + selfText = "go pale for a second" + +/datum/emote/pale/New() + ..() + commands += "pale" + commands += "pales" + +/datum/emote/pale/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/ping + name = "ping" + desc = "Makes the mob ping" + text = "pings" + selfText = "ping" + audible = 1 + sound = 'sound/machines/ping.ogg' + canTarget = 1 + targetMob = 1 + +/datum/emote/ping/New() + ..() + commands += "ping" + commands += "pings" + +/datum/emote/ping/available(var/mob/user) + if(user.is_mechanical()) + return 1 + +/datum/emote/point + name = "point" + desc = "Makes the mob point" + text = "points" + selfText = "point" + canTarget = 1 + +/datum/emote/point/New() + ..() + commands += "point" + commands += "points" + +/datum/emote/point/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/point/createMessage(var/mob/user, var/list/params) + if(params["target"]) + return + return ..() + +/datum/emote/point/doAction(var/mob/user, var/list/params) + if(!params["target"]) + return + user.pointed(params["target"]) + +/datum/emote/quiver + name = "quiver" + desc = "Makes the mob quiver" + text = "quivers" + selfText = "quiver" + +/datum/emote/quiver/New() + ..() + commands += "quiver" + commands += "quivers" + +/datum/emote/quiver/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/raise + name = "raise" + desc = "Makes the mob raise a hand" + text = "raises a hand" + selfText = "raise a hand" + restrained = 1 + +/datum/emote/raise/New(var/mob/user) + ..() + commands += "raise" + commands += "raises" + +/datum/emote/raise/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/roar + name = "roar" + desc = "Makes the mob roar" + text = "roars" + selfText = "roar" + audible = 1 + muzzleAffected = 1 + muzzledNoise = "loud" + +/datum/emote/roar/New() + ..() + commands += "roar" + commands += "roars" + +/datum/emote/roar/available(var/mob/user) + if(isalienadult(user)) + return 1 + +/datum/emote/roll + name = "roll" + desc = "Makes the mob roll" + text = "rolls" + selfText = "roll" + +/datum/emote/roll/New() + ..() + commands += "roll" + commands += "rolls" + +/datum/emote/roll/available(var/mob/user) + if(islarva(user)) + return 1 + +/datum/emote/salute + name = "salute" + desc = "Makes the mob salute" + text = "salutes" + selfText = "salute" + canTarget = 1 + targetMob = 1 + targetText = "to" + +/datum/emote/salute/New() + ..() + commands += "salute" + commands += "salutes" + +/datum/emote/salute/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/salute/prevented(var/mob/user) + . = ..() + if(!. && user.buckled) + return "you are buckled to something" + +/datum/emote/scratch + name = "scratch" + desc = "Makes the mob scratch" + text = "scratches" + selfText = "scratch" + restrained = 1 + +/datum/emote/scratch/New() + ..() + commands += "scratch" + commands += "scratches" + +/datum/emote/scratch/available(var/mob/user) + if(islarva(user) || isalienadult(user)) return 1 /datum/emote/scream name = "scream" - text = "screams!" - selfText = "scream!" audible = 1 mimeText = "acts out a scream" - muzzledNoise = "very loud " + muzzledNoise = "very loud" cooldown = 50 vol = 80 @@ -232,18 +1403,12 @@ above it. If you don't want this, make the call to ..() then use commands = new commands += "scream" commands += "screams" -/datum/emote/scream/available(var/mob/user) - if(isliving(user)) - return 1 - /datum/emote/scream/machine name = "machine scream" sound = 'sound/goonstation/voice/robot_scream.ogg' /datum/emote/scream/machine/available(var/mob/user) - if(issilicon(user)) - return 1 - if(istype(user, /mob/living/simple_animal/bot)) + if(user.is_mechanical()) return 1 /datum/emote/scream/human @@ -255,80 +1420,147 @@ above it. If you don't want this, make the call to ..() then use commands = new /datum/emote/scream/human/playSound(var/mob/user) var/mob/living/carbon/human/H = user + if(H.gender == FEMALE) playsound(H, "[H.species.female_scream_sound]", vol, 1, 0, pitch = H.get_age_pitch()) else playsound(H, "[H.species.male_scream_sound]", vol, 1, 0, pitch = H.get_age_pitch()) + return 1 -/datum/emote/fart - name = "fart" - text = "farts" - selfText = "fart" - cooldown = 50 +/datum/emote/scretch + name = "scretch" + desc = "makes the mob scretch" //whatever that is! + text = "scretches" + selfText = "scretch" + audible = 1 + muzzleAffected = 1 -/datum/emote/fart/New() +/datum/emote/scretch/New() ..() - commands += "fart" - commands += "farts" + commands += "scretch" + commands += "scretches" -/datum/emote/fart/available(var/mob/user) +/datum/emote/scretch/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + +/datum/emote/shake + name = "shake" + desc = "Makes the mob shake its head" + text = "shakes" + selfText = "shake" + +/datum/emote/shake/New() + ..() + commands += "shake" + commands += "shakes" + +/datum/emote/shake/available(var/mob/user) + if(islarva(user)) + return 1 if(ishuman(user)) return 1 -/datum/emote/fart/doAction(var/mob/user) - // todo change this to work with superfarts - if(TOXIC_FARTS in user.mutations) - for(var/mob/M in range(get_turf(user),2)) - if (M.internal != null && M.wear_mask && (M.wear_mask.flags & AIRTIGHT)) - continue - if (M == user) - continue - M.reagents.add_reagent("space_drugs",rand(1,10)) - - if(locate(/obj/item/weapon/storage/bible) in get_turf(user)) - to_chat(viewers(user), "[user] farts on the Bible!") - to_chat(viewers(user), "A mysterious force smites [user]!") - var/datum/effect/system/spark_spread/s = new /datum/effect/system/spark_spread - s.set_up(3, 1, user) - s.start() - user.gib() - -/datum/emote/fart/createMessage(var/mob/user) - var/message - if(TOXIC_FARTS in user.mutations) - message = "[user] unleashes a [pick("horrible","terrible","foul","disgusting","awful")] fart." - else - message = "[user] [pick("passes wind","farts")]." +/datum/emote/shake/standardMessage(var/mob/user) + var/message = ..() + message += " [getHis(user)] head" return message -/datum/emote/fart/createSelfMessage(var/mob/user, var/message) - message = ..() - message = replacetext(message, "unleashes", "unleash") - message = replacetext(message, "passes", "pass") - return message +/datum/emote/shiver + name = "shiver" + desc = "Makes the mob shiver" + text = "shivers" + selfText = "shiver" + audible = 1 + mimeText = "shivers" -/datum/emote/signal - name = "signal" - desc = "raise x number of fingers" - text = "raises" - selfText = "raise" - canTarget = 1 +/datum/emote/shiver/New() + ..() + commands += "shiver" + commands += "shivers" + +/datum/emote/shiver/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + if(isslime(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/shrug + name = "shrug" + desc = "Makes the mob shrug" + text = "shrugs" + selfText = "shrug" + +/datum/emote/shrug/New() + ..() + commands += "shrug" + commands += "shrugs" + +/datum/emote/shrug/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/sigh + name = "sigh" + desc = "Makes the mob sigh" + text = "sighs" + selfText = "sigh" + audible = 1 + mimeText = "sighs" + muzzleAffected = 1 + muzzledNoise = "weak" + +/datum/emote/sigh/New() + ..() + commands += "sigh" + commands += "sighs" + +/datum/emote/sigh/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/sign + name = "sign" + desc = "Makes the mob sign a number" + text = "signs" + selfText = "sign" restrained = 1 - targetMob = 1 takesNumber = 1 -/datum/emote/signal/New() +/datum/emote/sign/New() ..() - commands += "signal" - commands += "signals" + commands += "sign" + commands += "signs" -/datum/emote/signal/available(var/mob/user) +/datum/emote/sign/available(var/mob/user) + if(isalienadult(user) || islarva(user)) + return 1 + +/datum/emote/sign/getNumber(var/mob/user) + var/number = ..() + if(number == null) + to_chat(user, "You need a number to sign") + return "invalid" + return number + +/datum/emote/sign/paramMessage(var/mob/user, var/list/params) + var/message = "\The [user] [text] [params["num"]]" + return message + +/datum/emote/sign/fingers + desc = "Makes the mob raise a number of fingers" + text = "raises" + selfText = "raise" + +/datum/emote/sign/fingers/available(var/mob/user) if(ishuman(user)) return 1 -/datum/emote/signal/getNumber(var/mob/user) +/datum/emote/sign/fingers/getNumber(var/mob/user) var/number = ..() - if(number == null) + if(number == "invalid") return "invalid" var/fingersAvailable = 0 if(!user.r_hand) @@ -340,6 +1572,481 @@ above it. If you don't want this, make the call to ..() then use commands = new return "invalid" return number -/datum/emote/signal/paramMessage(var/mob/user, var/list/params) - var/message = "[user] raises [params["num"]] finger\s" +/datum/emote/sign/fingers/paramMessage(var/mob/user, var/list/params) + var/message = "\The [user] [text] [params["num"]] finger\s" // no, we can't just add " finger\s" to the parent version because the text macro won't work then :( VB return message + +/datum/emote/slap + name = "slap" + desc = "makes the mob slap someone" + text = "slaps" + selfText = "slap" + audible = 1 + sound = 'sound/effects/snap.ogg' + canTarget = 1 + targetMob = 1 + targetText = "" + +/datum/emote/slap/New() + ..() + commands += "slap" + commands += "slaps" + +/datum/emote/slap/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/slap/getMobTarget(var/mob/user) + var/mob/target = input("Select target", "Target Mob") as null|mob in view(1) + if(!target) + target = user + return target + +/datum/emote/slap/doAction(var/mob/user, var/list/params) + if(user == params["target"]) + var/mob/living/U = user + U.adjustFireLoss(4) + +/datum/emote/smile + name = "smile" + desc = "Makes the mob smile" + text = "smiles" + selfText = "smile" + +/datum/emote/smile/New() + ..() + commands += "smile" + commands += "smiles" + +/datum/emote/smile/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/snap + name = "snap" + desc = "Makes the mob snap it's fingers" + text = "snaps" + selfText = "snap" + audible = 1 + sound = 'sound/effects/fingersnap.ogg' + +/datum/emote/snap/New() + ..() + commands += "snap" + commands += "snaps" + +/datum/emote/snap/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/snap/prevented(var/mob/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/H = user + var/obj/item/organ/external/L = H.get_organ("l_hand") + var/obj/item/organ/external/R = H.get_organ("r_hand") + var/left_hand_good = 0 + var/right_hand_good = 0 + if(L && (!(L.status & ORGAN_DESTROYED)) && (!(L.status & ORGAN_SPLINTED)) && (!(L.status & ORGAN_BROKEN))) + left_hand_good = 1 + if(R && (!(R.status & ORGAN_DESTROYED)) && (!(R.status & ORGAN_SPLINTED)) && (!(R.status & ORGAN_BROKEN))) + right_hand_good = 1 + + if (!left_hand_good && !right_hand_good) + return "You need at least one hand in good working order to snap your fingers." + +/datum/emote/snap/standardMessage(var/mob/user, var/list/params) + var/message = ..() + message += " [getHis(user)] fingers" + params["prob"] = prob(5) + if(!params["prob"]) + return message + message += " right off!" + +/datum/emote/snap/playSound(var/mob/user, var/list/params) + if(params["prob"]) + playsound(user.loc, 'sound/effects/snap.ogg', 50, 1) + return 1 + return ..() + +/datum/emote/sneeze + name = "sneeze" + desc = "Makes the mob sneezze" + text = "sneezes" + selfText = "sneeze" + audible = 1 + mimeText = "sneeze" + muzzleAffected = 1 + muzzledNoise = "strange" + +/datum/emote/sneeze/New() + ..() + commands += "sneeze" + commands += "sneezes" + +/datum/emote/sneeze/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/sniff + name = "sniff" + desc = "Makes the mob sniff" + text = "sniffs" + selfText = "sniff" + audible = 1 + mimeText = "sniffs" + +/datum/emote/sniff/New() + ..() + commands += "sniff" + commands += "sniffs" + +/datum/emote/sniff/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/snore + name = "snore" + desc = "Makes the mob snore" + text = "snores" + selfText = "snore" + audible = 1 + mimeText = "sleeps soundly" + mimeSelf = "sleep soundly" + muzzleAffected = 1 + +/datum/emote/snore/New() + ..() + commands += "snore" + commands += "snores" + +/datum/emote/snore/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/squish + name = "squish" + desc = "Makes the mob squish" + text = "squishes" + selfText = "squish" + audible = 1 + sound = 'sound/effects/slime_squish.ogg' + canTarget = 1 + targetMob = 1 + +/datum/emote/squish/New() + ..() + commands += "squish" + commands += "squishes" + +/datum/emote/available(var/mob/user) + if(isslime(user)) + return 1 + if(ishuman(user)) + var/mob/living/carbon/human/H = user + if(H.species.name == "Slime People") //Only Slime People can squish + return 1 + for(var/obj/item/organ/external/L in H.organs) // if your limbs are squishy you can squish too! + if(L.dna.species =="Slime People") + return 1 + +/datum/emote/stare + name = "stare" + desc = "Makes the mob stare" + text = "stares" + selfText = "stare" + canTarget = 1 + targetMob = 1 + +/datum/emote/stare/New() + ..() + commands += "stare" + commands += "stares" + +/datum/emote/stare/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/sulk + name = "sulk" + desc = "Makes the mob sulk" + text = "sulks down sadly" + selfText = "sulk down sadly" + +/datum/emote/sulk/New() + ..() + commands += "sulk" + commands += "sulks" + +/datum/emote/sulk/available(var/mob/user) + if(islarva(user)) + return 1 + +/datum/emote/sway + name = "sway" + desc = "Makes the mob sway" + text = "sways around dizzily" + selfText = "sway around dizzily" + +/datum/emote/sway/New() + ..() + commands += "sway" + commands += "sways" + +/datum/emote/sway/available(var/mob/user) + if(islarva(user)) + return 1 + if(isslime(user)) + return 1 + +/datum/emote/tail + name = "tail" + desc = "Makes the mob wave it's tail" + text = "waves it's tail" + selfText = "wave your tail" + +/datum/emote/tail/New() + ..() + commands += "tail" + +/datum/emote/tail/available(var/mob/user) + if(islarva(user) || isalienadult(user)) + return 1 + +/datum/emote/tail/wag + name = "wag" + desc = "Makes the mob start wagging its tail" + text = "starts" + selfText = "start" + +/datum/emote/tail/wag/New() + ..() + commands = new /list() + commands += "wag" + commands += "wags" + +/datum/emote/tail/wag/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/tail/wag/prevented(var/mob/user) + . = ..() + if(.) + return + var/mob/living/carbon/human/H = user + if(H.species.bodyflags & TAIL_WAGGING) + if(H.wear_suit && (H.wear_suit.flags_inv & HIDETAIL || istype(H.wear_suit, /obj/item/clothing/suit/space))) + return "your clothing is stopping you wag your tail" + return + if(!H.body_accessory) + return "you have no tail to wag!" + if(!H.body_accessory.try_restrictions()) + return "your clothing is stopping you wag your tail" + +/datum/emote/tail/wag/standardMessage(var/mob/user, var/list/params) + var/message = ..() + message += " wagging [getHis(user)] tail" + return message + +/datum/emote/tail/wag/doAction(var/mob/user, var/list/params) + var/mob/living/carbon/human/H = user + H.start_tail_wagging(1) + +/datum/emote/tail/wag/stop + name = "swag" + desc = "Makes the mob stop wagging its tail" + text = "stops" + selfText = "stop" + allowParent = 1 + +/datum/emote/tail/wag/stop/New() + ..() + commands = new /list() + commands += "swag" + commands += "swags" + +// seemingly no way to tell if a mob is wagging it's tail! VB +/datum/emote/tail/wag/stop/available(var/mob/user) + var/mob/living/carbon/human/H = user + if(!H.species.bodyflags & TAIL_WAGGING && !H.body_accessory) + return "you can't stop wagging a tail you don't have!" + +/datum/emote/tail/wag/stop/doAction(var/mob/user, var/list/params) + var/mob/living/carbon/human/H = user + H.stop_tail_wagging(1) + +/datum/emote/tremble + name = "tremble" + desc = "Makes the mob tremble" + text = "trembles" + selfText = "tremble" + +/datum/emote/tremble/New() + ..() + commands += "tremble" + commands += "trembles" + +/datum/emote/tremble/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/twitch_s + name = "twitch_s" + desc = "Makes the mob twitch" + text = "twitches" + selfText = "twitch" + +/datum/emote/twitch_s/New() + ..() + commands += "twitch_s" + commands += "twitches_s" + +/datum/emote/twitch_s/available(var/mob/user) + if(ishuman(user)) + return 1 + if(isrobot(user)) + return 1 + +/datum/emote/twitch_s/twitch + name = "twitch" + desc = "Makes the mob twitch violently" + allowParent = 1 + +/datum/emote/twitch_s/twitch/New() + ..() + commands = new /list() + commands += "twitch" + commands += "twitches" + +/datum/emote/twitch_s/twitch/available(var/mob/user) + if(isslime(user)) + return 1 + if(islarva(user)) + return 1 + return ..() + +/datum/emote/twitch_s/twitch/standardMessage(var/mob/user, var/list/params) + var/message = ..() + message += " violently" + return message + +/datum/emote/vibrate + name = "vibrate" + desc = "Makes the mob vibrate" + text = "vibrates" + selfText = "vibrate" + +/datum/emote/vibrate/New() + ..() + commands += "vibrate" + commands += "vibrates" + +/datum/emote/vibrate/available(var/mob/user) + if(isslime(user)) + return 1 + +/datum/emote/wave + name = "wave" + desc = "Makes the mob wave" + text = "waves" + selfText = "wave" + +/datum/emote/wave/New() + ..() + commands += "wave" + commands += "waves" + +/datum/emote/wave/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/whimper + name = "whimper" + desc = "Makes the mob whimper" + text = "whimpers" + selfText = "whimper" + audible = 1 + mimeText = "appears hurt" + mimeSelf = "appear hurt" + muzzleAffected = 1 + +/datum/emote/whimper/New() + ..() + commands += "whimper" + commands += "whimpers" + +/datum/emote/whimper/available(var/mob/user) + if(islarva(user) || isalienadult(user)) + return 1 + if(ishuman(user)) + return 1 + +/datum/emote/whistle + name = "whistle" + desc = "Makes the mob whistle" + text = "whistles" + selfText = "whistle" + audible = 1 + +/datum/emote/whistle/New() + ..() + commands += "whistle" + commands += "whistles" + +/datum/emote/whistle/available(var/mob/user) + if(isbrain(user)) + return 1 + +/datum/emote/wink + name = "wink" + desc = "Makes the mob wink" + text = "winks" + desc = "wink" + +/datum/emote/wink/New() + ..() + commands += "wink" + commands += "winks" + +/datum/emote/wink/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/yawn + name = "yawn" + desc = "makes the mob yawn" + text = "yawns" + selfText = "yawn" + audible = 1 + mimeText = "yawns" + muzzleAffected = 1 + +/datum/emote/yawn/New() + ..() + commands += "yawn" + commands += "yawns" + +/datum/emote/yawn/available(var/mob/user) + if(ishuman(user)) + return 1 + +/datum/emote/yes + name = "yes" + desc = "Makes the mob let out an affirmative beep" + text = "lets out an affirmative beep" + selfText = "let out an affirmative beep" + audible = 1 + sound = 'sound/machines/synth_yes.ogg' + canTarget = 1 + targetMob = 1 + +/datum/emote/yes/New() + ..() + commands += "yes" + +/datum/emote/yes/available(var/mob/user) + if(user.is_mechanical()) + return 1 \ No newline at end of file From ac9eac44a183785c4a74690ad0de624fc2e7540d Mon Sep 17 00:00:00 2001 From: VampyrBytes Date: Sat, 28 May 2016 05:55:59 +0100 Subject: [PATCH 015/129] Adds support for holopad emoting --- code/datums/Emote_system/emote.dm | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/code/datums/Emote_system/emote.dm b/code/datums/Emote_system/emote.dm index a8da598c573..3015d42f4ac 100644 --- a/code/datums/Emote_system/emote.dm +++ b/code/datums/Emote_system/emote.dm @@ -264,10 +264,14 @@ VampyrBytes if(doMime(user)) visualOrAudible = 1 + var/location = checkForHolopad(user) + if(!location) + location = user + log_emote("[user.name]/[user.key] : [message]") sendToDead(message) testing(message) - for(var/mob/M in getRecipients(user, visualOrAudible)) + for(var/mob/M in getRecipients(location, visualOrAudible)) var/msg = "" if(M==user) @@ -311,17 +315,27 @@ VampyrBytes continue msg = message - outputMessage(M, msg) + outputMessage(M, msg, user) if(visualOrAudible == 2) handleListeningObjects(user, message) return visualOrAudible -/datum/emote/proc/outputMessage(var/mob/M, var/msg = "") - msg = replaceMobWithYou(M, msg, M) +/datum/emote/proc/outputMessage(var/mob/M, var/msg = "", var/mob/user) + msg = replaceMobWithYou(M, msg, user) to_chat(M, msg) +/datum/emote/proc/checkForHolopad(var/mob/user, var/message) + if(!isAI(user)) + return + var/mob/living/silicon/ai/AI = user + var/obj/machinery/hologram/holopad/T = AI.holo + if(!(T && T.hologram && T.master == AI)) + return + to_chat(AI, "Holopad action relayed, [AI.real_name] [message]") + return T + /datum/emote/proc/handleListeningObjects(var/mob/user, var/message = "") // based on say code var/omsg = replacetext(message, "[user] ", "") @@ -337,10 +351,10 @@ VampyrBytes for(var/obj/O in listening_obj) O.hear_message(user, omsg) -/datum/emote/proc/getRecipients(var/mob/user, var/visualOrAudible) +/datum/emote/proc/getRecipients(var/location, var/visualOrAudible) if(visualOrAudible == 1) - return viewers(user) - return get_mobs_in_view(HEARING_RANGE, user) + return viewers(location) + return get_mobs_in_view(HEARING_RANGE, location) // set up different messages for blind people here. Empty will mean no message for //non-audible emotes and the standard message for audible ones From a547781fb166e02a5471d79ae3515352c1ebe3c5 Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 30 May 2016 16:55:59 +0200 Subject: [PATCH 016/129] Fixes a grave mistake --- code/game/machinery/recycler.dm | 6 +++--- sound/machines/recycler.ogg | Bin 0 -> 17157 bytes 2 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 sound/machines/recycler.ogg diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm index 9bcf3de53a8..2db551b67fa 100644 --- a/code/game/machinery/recycler.dm +++ b/code/game/machinery/recycler.dm @@ -129,7 +129,7 @@ var/const/SAFETY_COOLDOWN = 100 return if(sound) - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + playsound(src.loc, 'sound/machines/recycler.ogg', 100, 0) var/material_amount = materials.get_item_material_amount(I) if(!material_amount) qdel(I) @@ -155,7 +155,7 @@ var/const/SAFETY_COOLDOWN = 100 L.loc = src.loc if(issilicon(L)) - playsound(src.loc, 'sound/items/Welder.ogg', 50, 1) + playsound(src.loc, 'sound/machines/recycler.ogg', 100, 0) else playsound(src.loc, 'sound/effects/splat.ogg', 50, 1) @@ -219,4 +219,4 @@ var/const/SAFETY_COOLDOWN = 100 /obj/item/weapon/paper/recycler name = "paper - 'garbage duty instructions'" - info = "

New Assignment

You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.

There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!" \ No newline at end of file + info = "

New Assignment

You have been assigned to collect garbage from trash bins, located around the station. The crewmembers will put their trash into it and you will collect the said trash.

There is a recycling machine near your closet, inside maintenance; use it to recycle the trash for a small chance to get useful minerals. Then deliver these minerals to cargo or engineering. You are our last hope for a clean station, do not screw this up!" diff --git a/sound/machines/recycler.ogg b/sound/machines/recycler.ogg new file mode 100644 index 0000000000000000000000000000000000000000..d4f2c88408741eddd39f7e024456e9656303ab1c GIT binary patch literal 17157 zcmcJ0bx@p5^WZ{ow-AE6yGwxJu=wI0+#$gof(CcD;JWxCi-q9sZVB#$U_k=6yzlq@ zuCD6t&wHwNwtM=So|*2Ro}S)WRcmVv06gG7k2BuCz|>)(0vtJR%o&t#xfb+OVs-SW`OKnrZ*TnNoq0 zo0E&1lbe%=l2O&s$@Zg*rK_cr8`BG0IK+RO;z>$r!#KkMFhB%UbZ<3)<|wHk5ECMq zxtf6-nfaWMER_Y0#utURCBCZ6sk*=+T#zo444HD1)fZMPiL(wooEP+a45C*Hg&+8qltv$UKH?pnpq)F?cFL>mMP!M}Yfh%xExi zsA0&c2fYy9BLRW{1Tvop20xL?CDD$;|MSXwz>Dx1<9;$G(I_NY=%rcerImW8mA6%L zJk+os*PI?fu|mVE5dcE~08uzq#D>CHf<}S@J(Jd$5K6%{me4MN#SCa5!z@O9B0&R# z3y~{)iYW|dPDQ8$gBnFjKG$M`Qc?8ahuOX$4sioD;0vs`7>O9Ffdp3!AQF{JoWc;L z^n?&oZi*6+5!{rffXbG-K)s)nq5`BZX(9xT7N;yovLFHg2!gPWE=pKe+9s9w#h9BHnAHaJz*IJP%99M`a}LU+6? zk1|V-eM%3ZmB%X$N6>~-7#dZ{vRZmP(r`S|3?6Byv4>F$t5#}YZBIvD+Ezc59v?Ly zjX-Ng8qQXmYaSZF=$jGAi~h6j z?gpurt2&l?x0Xh?VR|k8>l#`H0!BKE%8T><28;ft&5oOIV5rveLYP*X`{shbWrlk$ zClofI=9A+}*5j_4;{ncNC}%a)@v#Ps-dlA%P!FqI>x#Eq?fP}p%+&#PB5kiD={|iJ zsIRDW%&w_AE@e4}IvjU7A45OIz|cz82k6nr3;OH0ivy$R_z2283awjds2zo}W3<0oqigOaU27O4NXg1t|+4 zJGRm}eT;%80-!B8Wk%nQsd*0M0At0yUkq!(Skj~ov}JNt0uFpF#*$<%DV_l;fGsB! zhQAig2+3Cz&wvyvAZkE+7%L#KzGMdI2<|5a+OieT=)(weAV)Anp9a=>jKpwGG6<+p z0qbKgCk0EGIWr^)$W)P<1gg$Ro{?ar3yA?Llt7YzEdR0!1L@m?=QBWxd?`sVR{gL( zzz|{$7QQew5IStdz=jLawzp$zR+F?ZC?-^7=7JEK!#XE|5sL8)m@4`S4PwC%T@6LP zv?MbJ@ca^xO=v;i9>}&Z1BwAdG7Oa3`gQFw>Hc8_8x;`Tzn~9(>72PfHA(-ag?)GPJFu{0N`8DE5Q38 zRLieZ38{eh1OUJX4D%QX8v>UxA*NW+gb)LrE0!b*ljVd23RTI35K2kYoDgzBN{S>C zQwf0qBVEaYJ}Ut5^&1?3@*9$JWIr4lrXDIl8io!q_7jB;P?ivdOc50kz?5A=1Y=b~ zU_K!+MC3Xl!SogeG0=tLNHUec3dWKYm=8iDg*iTlsT5sO*nnQc{W~Bt46blWH;^zB zZm1HFp(GJcADziE4H!i?Fs2^~?pu;a1&1wg+tUrqn8||sbj_FnfD_n&PQFPp@>XNE zlMV#|4_^pOC2lW-6cEgNGk*jCQ0mkzT!Rz8!rV1Hz#C@bTtJwxN@SS^D2oXUUM38( z1Djz;!t|sIv+j}wvlGhVIsF)j2aLcrpfB}8u%CD#RP!yq5cbx5UkI)fZ2-U;A~K-v z6^RT#0}(3oe+lg#a7+3jv0{5MEGN@iipj z1)7pLctKI9++cOEx&PlL@$+R8DIg$I39KkD`VRz8^@9FW_y4;{{XhEwP;R0j1D=sd ztaTNHSx7P2U*v!T+bW29i9%yugdNU>QsSlpRG{OFkzg!w#e=mEnbNm|t$GmfZD@)a zI#p_lJ{rs?*fUi?Qb3GM{ltpEijoEHecIwAeMN9{h7fW|@q)e`xF1InSPxkM+1I|OHga(Q)b&BBrB{SHnB1Q-NaQX-clCS#| zo?6`aefq~g_CN&(K;Q<#1pi`3RG=s>m>ymrX&~3$zjdK7RlS%M%%T$hu|^m*6eJ9* zQv;&DNc=@hFE$7QqEf*i*z$nQ4hH>46))@N-@5-So_}QbKXoa1|Jdq3FaOKsALTK= znDajnD&7BRmFj<>5|{H}~{8-d*LIbn5gI+55C- zDsUHY^NjiKu^+Xj?s;)j>J(qv;?e21|LHRn?E&_!@pp5xH}C;Bw&kL!TSoZOMx4_Q z!!!GYS%N00R$Ht+zLwFTdp=jZCE0to$>&*aK+q(?X_RsTJ%GKcv@L%%skCkTwA^X@ zap;^~xLalXx|KG4pvuMdTK;{n(UGYy|S0qko@roW= zpAqXSi$q*;ikmryh`uEH^p&zlpVTZ89Q~dsioy{(6nx5c+nJb!#=>XjzRO5|P-1sz zO(hQ(2p`8v6#UER(}d;y!RGGcLFtFqZsnsJY%a1X<_U~kJIuxW6gYs_`wPB=a(LEn z>Ae*2G)NqjtJ#dn@8t}?2)i805e z==qnXGgv%LPeTGQU+t1Q3sSs>ju`&ZNf#)i69st0&C#|4-BAv7hp{ym>U>>(E!glc z?w7PY3n1miRlvu`-!U2OB5%fIkzrmtpKl$OPpJ0}2@?}Vj?d7=tEUvDJEpi!_zo|6 z_mXD^;^C2=*B8fYS&?Qq!)d@p#rKIBxP5W|3h0BUgj*67RS?*;BNlDCGxT$ z+&5>@h7OcTqpU3C-`sPY0z%BulFd}>qkEvzJ()Ij^@Ih$hSSRp7v(rtDc_gokitMJzz(pkRWq#lx1j(Ppz!r)?n^EQsxXwP8MCnB%UJEwO1R+!|?-$l>)j_a{3 z*R2q{rOJy?FOsp|MJ<`yJ{T5<1^Bku&oG^o zVchPshdzc1h;S*qF2mK?ep@Oyrz$2 z2a;{0_Xa|>w+4NwuWAthcr;g3H0JD)GTjdyDo(&V|Y?+9;Gnr( zP9_(88|V(l*SL}rS!}JO6D#u*i1m1(dcSFw1e*3*ZyD&QN9>pcj;7<^i7J%fR2#FeV#Qf~pD2D#SN=Q_tI>PhGA_9eQ#lhMkz!QCYNGJm|kT3RbbHJJ-x+0F$~ zG(xy?b`CZ~Eb5F{=r=0Ixl3*|v$G={>{>ytkXNNton8SJp&d!c__E~4I}8oT=?Zb;ihdF47%E@Zx>G~+MZdH`xE5Zwk0nvVUF((< zy!3JNO45&Cl(dVo?=(blYI(L+6?veTS=1?Muw9oDDbauop74P#fj-frF#AxS-r34$ z*Y}RYarVza8(d}BE`{K6Ap6~ zxvO_9cA@cH(F3hI0+XJp=W}fxG@rK-Ul!`|s>&A7_c zB)#z>L_yyU3zEjpVU$Rgg)3iYpZloWo*bYssIW+DJbCg+oT}a6r>Rs2a@5(-meMP| z*mL^Jw-yzaz5xdavf2OGO=5q#w>#Ni(d|13I>qlrN)JI^pD zI_xG-o+L?(C_Iy>(5wHu?ix?KUaeRQgA6XK;7t;2v2w{iP~+CQb*A#Q*z#zp*qbmD z^iFb!wwVZAPCQcOnZT2sP4+8`8d3L3`Jq@#~JjNvqp%MM0Z|7>Iah5+G30T z%>F(wUi!#ZcBue#Ixn{1R-IK2@0&Ri%&W4!f`xMlUlM(X=_!rKW9dD^KN)Wtjt+dV ziA4FmlMycxw*PCOgk&V5mnLjUgRxedX#4|H>Fn3CU%p~>0wf5cgl$@8tu+n(g|+bE z@1#}ct1u`sDCb4vG!N|&)BO_2T(R*HVuk~_3#o*?H)btJtN_fyeKy&(=wZLZeG>C> zGQ;B*ufLjQ%v$By_O0($7VBvW$1&pR!tC41{el(89*7MFc3^C9)su%#Hk zzva7$-(jr5k&K#s4`9v8PNY3``(r{x>bNbz%yBv2=G6rtd=?d6-m^i>5U^DrP)HBQ zg|%{b=l;A9%@Thy`8_vlbz`6_KzlDe+*a(yd@u`w#8cEny}6fc6Q8evstY3dC`xNi zAR5Uie|b3AP)Lmk_K;i=!s+K9$3(_k=pw|5kG{h9;?JdmuQc_Vy`(9+;k9@rKZPTm zmZv!Q{H9r}pW@pADPc)xI-V(q+eDBwfc1+|&mjt-2n1J92h?AltwCi1Z$R9Wo9;Tnz-0w-)uQmHrBZvn@g4l6xClaq>M)F4vjBlpG*F{vQ~5R$4!LA3;qw?>Mmpn+;H`9 zg=T5x)W{ zWdl=3AG6ZzRoM@tX5;uyiL#S3Yv|^kf6ovC(+pgSu(-=Rke_n#05^;`Ts{c^ah z1&XQI!nuVDXrdA=umf+Z;peDNo0j%Wu73MBpbY{{EWTx_C!hIXAWh_@9U*imzZ*|=9a#63p93w$`1##m$$Y) z!JMyfSl$y{JnmXE{h<|hA%SYlich3{+;VjA(B`^nic7ObDvspOC93HmW0UCA(<*bq zwPEFOZ}$S?A=k!RzX`y?nybhnnf#uf&AoKt@h7rKKI}(!dW2gNpB58b7A2nlr*s8G z|6oOWN~D0U06t#QRF3C8&|b?NM!SmQNerD{(M~voWHoUn7Attl=)4G3Ou0wTi5aQ3 z`!+nryFREfhMC^k;LMP;k92%gkX!sHBoR zawYEn@qkaB8H9j?48Yla6Mc{tXrCvi-U=k^<~^y|&m0}TuM}w-W#}nEyjaVNiO_8K zTV;LodcISF_Av+f=YXAKwc{}(ZFV_hCsQuji0kBT9&YN7IoB@TcE!&(*;FyRA$FV; zP|w`|{(PnPl579~UNRQ2jS=wkGZT=}(bU}5+SbC_)X~A(!NJnb&dl1**3{9`!p_pp z(ZG=PbSIvy3#hTvgun}T@1AR&@{IE%LFPv?fHbJyx=fRD-i zCn1gT)l|h27aGR^bdJt0mHg2v^i0(<|15$7#;7-UTjQ2@-}?I%kOn_~VZ-wIu&J?c zEVtSd>YTs%6WUi1zLx=4Nd=kReB1GxQM`_(gK#V6q}0Y^+|Po_dTC`--J2>ag5*|)G-G!!?}O6#$}Ye^z6#Z!FFo4W~-QNJiIf`X`!c(x#>+LlW zw?<4NY7JHIF^~1Hn4bqWK}6E47yDl?W2-nz7jTy;da;ug*H*cbWX)V`?bb*PtbB&6 zUw2!@AXKOT<3bI5xUDb^L<5_<*35_%cZRsjb{TK4SJS|Mr`A+F1y zoK!e0lU7nmU1GSqD2G-dQr-txs5l$0TR#)|hw?qOkv<5-Ie75)w;NSi<{c=tF3Ttp z#9F+kyE3PI zeEvrQy&9YuV(ThzZPezCC0#>YM_|z%)CD@MUe#HItn>Q|`t>rZFhR$cNJmy;{n4b3 zgX*#C{0b=E1??`Bt?SFqXUpjw(^6L|OeR#|jaEZLLSLz!W9oI6$QQ;#;#1vJKq(dE z>Moz=Ad+(w(D!~lhJ`1G{nRE^B)(`kJ?5AsKKZg>H`-vhi#vn=UgV2rO--0TBi+7@ zD-GrphoxD?o8l?@*D2YL5fOJ<*uDNxkvQO~Z%SaP6sUJzKzIUbm?ml1R6|Lg}>yuNKW84ZbfS_kb)K4Wr(8dre(l_RLOU z{x^0fqG>@PfP2Qs<<%3GmJ%s2-#868h?Z*zAK7b&#SI(iCLCWTifBE68}5AeX29oE zJ`HXTYyaXN+4^L~o3lNG*V^EvkQC+YMOltmX+}eZTk6yibK)@%h`2MMY@yuSErIv%eJMdo>D8^QC%e zJZh28Bj)GR6YBlJ%c1fRU0}DeGmilk9+m@J;HUF(2*V3ky6C zPxI-U?WXWxKa64h6>q)Y2d#)P*`K?H)E?94i(cP<6rlyF@?yB|EPTv4c8+XL58wP` zB+LFOHPZwhBFI_iEG3Eio-stOyX3Q){CqiauoMawMRm63J1%qQGw1TJ0-ju9Q*Yp5 zF5&p{Q$h{ucZqNK=1seS+P>pGTGt*nLtG(q*U)9CFLz#TJpMV$Ih&o{9=v0QyA1Ig{Jg_+yTYVfiExWJ1>w_J-a$Gm|)$8OA3&LA*`79N?Cx zP#y)rB*px9_xA}w2XY$i{_ZBWF^mZ2P1R(Fv*AzV`pUb;tHP0Y^I{OxNGS+VO@*(21Q;b2Ylx1|#&9eE6!-uqF(3vWy%F5e@w7VaOm>I%5C6!kr$j%C$YjVdS%3w3vXil@9*tt~8;v-Ah}JmL#DJX+|hD_nN-E z=C+$8N`sxM5&(Uw#)h3g&kAU4+PI*#@%xR*^#`paLbX_{U@%>k`N)#dXiDVV{K>k+ za!TT#D75_x34XBe03paSh9}6R1d~*V3QvntBEUc{i#hCrWqPh+%2V zyxN$!QtBy$Z!LZEiKS=b736m#efoa`1}}D5dxFJRuQR>H>YuEQP~aar__PeLD?QP7 z2xhy|d-g0m_R9_C=pg3|mf((0U(!&jwDz)^WaqiF6cC+g5ZV!ZIdn=*Z8Tt0IexDM zcpdbn?H*-x|Eqs&n~U{MT23s1$H*Fqjrf~Lu-*{8UjKlf{_os_rSX!%+ghiaSI%86 z5nyKc8;Gvsgw~hT^^ch}m7jbUJ5R&Fh*v%HgpqCdj$FU0d~fr_jlz@{sx(vzsa(97 zM@X+iDfQu`6#df(|O;H|0{g3DL8h^Hb34eoRtA8j*yrETZ&EV?eUzhiPRY}?D9nh;C z@fpxZ)LZ1K`NSb+OYfL-RH+cYqa4-f7-W^05MmCO2Ob~&&%0-Dv_xF$~F5(L>4X<@GVT1Xi)ul-w6 z(18wsy<|e~cZ}aWZ)~@%yG`N=t zECc0E<)wy$ACOlpC3yD8+I$s#S1&YDH>m$Wm8IC=tN#~Uk^n943mKr4+9!K|QZ6)) z2*qp$hi%&9X}r8E&B$_IuSi^-sjzy6t)*l`mOovm-RUkn9HITS##9v~d!R&VBgPEX zHq1#_wj@?^!_iB$AxCuihN#6tnl;Rk<&&xJ32@_wP0si5KQ7f4r8H8*JZ%^?VV{xY zvE%_qOI47io11hej7Iv`?In{xr-hv&@9SE)c5*{?mhK9SSDYm490j}?r2^cuKiZ9# zwrja81qx(&21FJ|WC>wQ7gW>YK6%B8$oYg5^xr6Kcdydp#zDs%=#XLd49iwC2JOI3 z0ByC1QFZUg@>RzbuizcRMU>icyGu0P#U>O$bOTy8hhfaaz|s26C2@n@-I`D4cq}Az zckSD==m@s0-$fjHaL+k`BD=>wqD$lnE8E{mjPRkqNwfE3j~N{4;y4=7{Q!7L<^-t2 zb_BTh@L!IqdAwV5o!(W}3^+rOL&RMV1#)(5^z^ESzh+l|_vPW|V(10h+nDFS;~mk7 zkv-`sG}54x(j;#4oGGa6Cp!%7qU9H(kXwy8Nsf$3b6J#}I5zyatN9~!6i`Sd`|de; z3723-UNydO}Dh9BBjs$F9`>P`0w*49ng<5^UltG-K!|~$7>C;^%TTc_&Ml1(iNOn`w8F93I zV|r&!1nq)~+;8c-*2E$NXD=uD+ zxtvIs#%>}Kq^(CF+Bb_r8wdh;V1*Nq;oygfZ>~nB;L|!Ze7hKtRgxt4Ity5mAn#dZ zP$H9vF^H)A@;27tP$>T~f7(HW#Od}tVXX^#;d6!;5oN#MI;wD|XB z%EbzR0Li zdN0;DBV`b)e822JD8;h%Nk1yC+Pv^r7$tMm*iTBSFVA4QGp`eZh0Y#5vxA=u8zv&s z$9(;DU0iY2)toAZJ`U+;s_NKb6vQ1@N*D*4=R&}#0>176?FDglE<^yLEUFYSOGw+i z7D5(46Ly$uxO4ogy}ogE-Hh6%3(S7&GSZjX1U*dVJh-xL-&{|W)|qizO(d4kE?cPs z9g>SXR%TZe4FK};Ds+$<-lV3ir zR@j)6p0x~$Ah5Z1Ws{E-?nY^5my5Sm=C<7E7%>jl#lqJ28uMgm&Ll<6l%F`EaX;WCb1-q=YmWYNT?P%*Gq3NU*^Oi^CQ+2on0glq6Iv_e>W z6)8~c6y8ugtn`37Y?y$4fl-h=3H`8Xj_@RR7SVUYy~*UeUcZ(gI$VVJK?p3{FA&%p z3Xca+gM)X!nat)g*-d3k``&uI^!S|~$Njr@>?YEz)u>dXO2%*XioL2nVwTX9q143` zrfw$Ut2yPO?T9FeEK&y^c6th53lCE45i_tgFy4xAe?PeQcz`&_U+-7Dg3u_BY3o9!NQ!{H@OLKGc57r+n%`B~LO|3qdSXx*bTUwZ#S${Aw zGtV-%8Jt9L#ew&LMd@|`G@3xn$LpSX>ZGUhlTI$O%cFyL5Q_~}jC|FVhRVSE4tWb& z;FaT>@5)>)cOJ{*tGM(Oq^%v|>KO|=PZ;pYG)h~d9;_d+Bb%D39VK>~7a5crqoa}2 zNTn3`J;&q#Up}XvM4e5gp4<7XU9tMMHCfLrk$O#RmwEN%e{$x(XeF%#&TZjbRR&AB9%>A z7fHniOzXp~)%M>0)v&Un*~z_e*VGO3u4exvM#O&Z<0kY`d}xz*+j=HC&bO`@-)@+^ z+qx}gDB##3C48D8hSkZyQj{W0m5t}@6VcXYxDz>kbLX^ER-mIO`quk)e0}t&tUs;G z#djmcdUNXjA|7&O`5g{?pImM#!$#{FBgGMq&ueueeh2cx8OJALr`V)RzRd`9k0*>- zw}%kilTH)HdVhSPv-qj(i1{`-QUto>1DafmvvY$dcKnqmIZ((++^hzdrYoa}KPmu( zC+DhM6n?&m<9NE!%`$bp3A(XkI027-XurE&Py8!rdvE}#)1ryrHyf(fc)M%G0Jp%q zkfK_1&AsfFhuNv6TGj4gKcVh{*bMu2OQe37>`|`V+h4(n%r#s6E zmb=p1CO6`n$*V4=K+;f73?$L?PkxxtVN?UHBWULv`psm;+>?99nIf73r1|kmA(N`D zA^yqUPeOv}U9am&FVnGGvyg7(6K@ppynurrmi8 zPhgdGtb!f(!4H=c1QI&0<5f(QHhFEUOvN&|Ti-oFG=7tE$z6OA?-XRy{oX-?`iQ39$sS#Ixk~39=IsOKZ~{L9H_MKf0g!_eEq1m3}+Y`mB>mv(YLvv#>Rz!4UsZUbbL&2 z6Ft5^BoC7%MO0HZpeX{GA$*@}Z?Iqyhh2E^K53f4 zl;A3!79~}&kKLP;d6JZHjy!mXIvSu!)r~%&Qj3YN%Tl9xWYeD~y1@V?4b3t4GC_D&ctl%9-=i z=~5`fmf?fl1TeXu0M+nw>~aXssRRD36EeC&sZhl`elkN9IRz>GY+WY`{?RX?^Y(PE z-1;@~m(X81r}wKOODc)T;d*~&6-71KOyNlD;gA3ciBC-ydGW-=il^(xni_w(sf=j@ z7$}acimY;YwQPxtru14Ub{F2^i}sl&O$p{Uywl$- zoYo$oDz(4)NyO39>H%$|!jIDNHo-3<6y}V?bi3G$jP8`$>jYo6(TxY*;9es6J8 zmHxm068!^`l1Hf2LSeEkd*>_8`&9|Cm61@!3^(LMOET^>DL$^c-ub8M^=-#-h=-ZO z?nE+fRgvjMPWrar76=eWcX_8|VHgUT1>0Kd3tZ)Qz^p$h_VI%3Z?6oZ0V=ZHH2i?BKIgr5C+;NdhmOU#l zW?5S`JUri*IQ7FE5bpD*4a8XlOZz{Mr{`LoWp?$h191@bm3uZFpZxmU8LhATh8_*VK~#)#NqOtAj2wn=PxkY3lNunq|NWh^R)oI ztJb0Msnh58W2zoQzzm(gd~OhjTi&Yq?pb{gXp!a?vxvzVK4d{ns9zajic4YwmfxZD@nTLIQA6TC3c(`wKk?f7Q*JAYvl^SvRM4 zAZL2^vWFkbeI&^ov5S)wOBkskKoD(n4Fkr#lGK(^Eq0|-Ma|D8B7DU`GZN<4ZwH6mYFGb}@`=PdSZ2Jt~aJ&pUs+`s47KRYg zvO3N0I7^y$^(SUNQ6wc1MTl5%R1rm`9C_sR%%k#4_DaJQ6L~)URW!UWkARq!liqnS z44|LIB;Qd4h+XlfrKBuU&X1le>WenBSa343&aj6Fj-1x0(bjq-Znc<`B7KfnW-aK8 zvs%FYf<1fC6}kOw>taFuyh@N-0W(}n#$>Wa1QkH39rS0(Jh^L~Y*5ash~`qO2x`B& z;!}G~{iN{N%4sivKohazE$;3dHUAbR)xKujtmR8^pNh4x_Us2pO)zJa0Vk>T_vVVs z%m!|*A3lMkE17wGQLw8-Xbn3&1>}fPX+R;>Xa)%Y%CwI7+C6jBQTs7cR@l!#o(6Yk ziN)%@tCGJ@RK$<0@QF|%m(N)lBXn)w=CYNYa2(%Or@^A%c8=Gx)UHl#mx?-`l z4L_1Cl!5Fs#hj2L#LP}nqtb`_R1Acfk=Li+s{_iNYt{mlPW=-nk{@!<#l5eKAw(hz zO^)Y>S+%m0Y~i3h>38{03x;MM9^5dOfjz8`-Y-vLwtZ2O5dWqfEnN0jORHk_YkQTy z8^?}TABmv#f^3HG^wV(Kju$=R@~g` z3%)PS8rYfnQ(@^qNG>w4X9VHpj{r+MQk|?vmQ5%d@R)2TtWDsyZH*C!QFSc4{hhv+ z13sL6iKd849d^v+zb^;SkjGC4F7BUc-2JM`Z~8fuoEhP@L9ov|xsfKA<&h$M@fCiq z1kXy2O<}r8B^-aUA7O016Y*=n_ibM5m{$k8c;$}sy%q<4vwC)}s9W|pNfM#P5X3m` z-L4ycqg1Rke%64FyRF_w>q(Y}F7H*r2N%cJvsOkQu67&a_ka_!99qmg?emN5?pN{x zZ$$B(b!Gg6`*HXBb>CQ^<_#K|4kS3;T7C>wqx6vY#1zcL)?`h#s!UrU~h^j960^Ub# zRh?t()s!Vhj>y~(QPP+@wOpapr#+uzi%zD$ZL{aS(BzK$enndg3Y$!JkVXeycKBwV^NL0VP zj~b?afH2`vKSH5WhmdzZC`Gzs<1^C!gF9Q(jeTo$L0? zvI?eO^Zk9HF1`{L84~z5uJheaJ@AOpE=E2;v1>krpluHQvkb9sc23i96F& z_`QAyky0jJj_2HW*>bNFFH_M1lKSo~9j4%rKbruGN#DlDP24++#%x;UC_I}ABTn5M zTcJ$4OeT#T(#i4P%C)(YxsIDoygJ(+7k5 zEQpmd@4Argy5UuRCr%t~_JF3IcBEU)YX^y73p2^6_9C{xpyNaY9B%I!d$p1D9QRtr zGmd~->fTu)98!7!Zf=_5jq}Z@25cqq&i_B@``=;M}uH^CEmrzsHe*4scS>EomFLHHjdelBr*d%yt2H z(}NXDM>*Kf?5(zn_hK>0QEx>AXW_L<4HVAj;`KmHL^nt8-N34Qn7q1()q zbO*4@xqr%>gd#cyX5+SSjZ%K@=|LpTeeyf4mqU-tktMuwVrB#iY_&Xsv`@Lpq>7-=N1yON3b3wS^M2k*+LXJ7z3-lla&ZFB)->3W2Vcy6_k?Uv4 z>4T-thNy_lcXl4GX+NoPv$_Sck1KHO)rkg1Jb&-Aviv$YRBC$TJhJsYwj}>EOR4U{ ziR(gcA$0p3kb0 zlWnY|6#J$~=hxt+pf_MB@Aeb7Lnrp-&7;@t0&0!ohbmLO0e(b_yu1+hh-<+Vk?%4C z27V-HszQ^i+6`GL`ze6n#Nob2krOchtq+d>HA(vA(a4{`L{7O5a!;jw2y;3l+4$s? z?M=n;j$vV14EGLW`X92lq*+0ZF1X0!Y!3YL994cEeu;7^bo)Oo(_4AAYMjVV{wi=2 zF4J@E%*Y#$Rh0q4laD+D#_y4c7?;QbaEi9L#>bzxkvFt?&z=bi-=s)cUAzCW#VU0O z$!^h#Ks7Q;wp}MfR~wza$W53NgU!0n6EN`8A%Aw5p2~Jvw@N~u=4W;7>y?A?X3w9oV(?I47g1`(s*Sqc z?V&oKMqVe6YkMi$v8xCjiVEe>#w;vCt?>8~`q%D^PaU~Fe??#x)i5a2*tCl8@#*}# z`l|nVq^=4fOik~+hJoMU6eEIH=m>0qt>kvBsStUfQcnWZ5q3;*@ck;VSt-&7rzanc3#y?m+hR3tE` zu617gW|C}krI(CK8r0%_H(f>J=-hW_oh{ux+N{hK`T4ErQc-e6!n-)UE``u;>%GZ= zuC!BM6MAMxJD7GY`Ink=$te-L?06q|YC}0@V3(6ztQWY&*Bp~<+tZf+29Vq5#o&i> z^@4HIeuLd>@lCOuHJqlUK8zW*He#9G{Ft#_{c>>JonZJ?`~up#_?sl+dCrq+|ES)e zd(|7}ErwO{d1BxIGHP&hgYjqBE30qcIh2Jz_^AFw=Lt=$xjn8=Tzx*vge+)1KtvrY z>??eJ64T{{V}OXlZ=L*maE?5gC}vB#DOAr@bkN(V-WvSL?+yHfzkMVYDwftWDp|?t zVuXqso;cj!k}z7bED^C1e~Y*1;T+!`#b7`1s%kM_{8U^ug<65UX7o9Mg@raI=77!q z3!;2t;eJ@V*xKjU){!24YCD9d-ZIg9bO!7BX}$k zI3v~lFAjU=o7>y1vQ@j2Is`;y*ySwfT)rJGktsKSDvfkH3awsTTpn`&LD;yXSA|^p zm1Db@1!J#$W7Paf7|L^gT0-6ah0erb8DHOellEKt#E}1QVkm`LR8qeJ$&+a_N)Tmb z_sPRi1SI!KP?^;>^a@wPDq$iG!(HyATIj6 Date: Mon, 6 Jun 2016 17:12:28 -0400 Subject: [PATCH 017/129] Puts UI on it's own plane --- .travis.yml | 2 +- code/_onclick/_defines.dm | 4 +++- code/_onclick/hud/hud.dm | 2 ++ code/_onclick/hud/robot.dm | 1 + code/_onclick/hud/screen_objects.dm | 1 + code/_onclick/telekinesis.dm | 1 + code/datums/diseases/transformation.dm | 1 + code/game/gamemodes/gameticker.dm | 1 + code/game/gamemodes/sandbox/h_sandbox.dm | 8 ++++++++ code/game/machinery/overview.dm | 2 ++ code/game/objects/effects/biomass_rift.dm | 1 + code/game/objects/effects/decals/misc.dm | 1 + code/game/objects/effects/misc.dm | 1 + code/game/objects/items/devices/autopsy.dm | 2 ++ code/game/objects/items/weapons/storage/storage.dm | 6 ++++++ code/modules/admin/topic.dm | 5 +++++ code/modules/flufftext/Hallucination.dm | 1 + code/modules/mining/equipment_locker.dm | 1 + code/modules/mob/inventory.dm | 4 ++++ code/modules/mob/living/carbon/carbon.dm | 4 ++++ code/modules/mob/living/carbon/give.dm | 1 + code/modules/mob/living/carbon/human/inventory.dm | 3 +++ code/modules/mob/living/carbon/human/update_icons.dm | 1 + code/modules/mob/living/silicon/robot/inventory.dm | 3 +++ code/modules/mob/living/simple_animal/friendly/diona.dm | 1 + code/modules/mob/mob_grab.dm | 1 + code/modules/paperwork/paper.dm | 2 ++ code/modules/paperwork/paper_bundle.dm | 1 + code/modules/power/singularity/collector.dm | 1 + 29 files changed, 61 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 27dae76378e..17850e8d64f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ git: env: global: - BYOND_MAJOR="510" - - BYOND_MINOR="1336" + - BYOND_MINOR="1342" matrix: - DM_MAPFILE="cyberiad" - DM_MAPFILE="metastation" diff --git a/code/_onclick/_defines.dm b/code/_onclick/_defines.dm index 3c76c35e807..a02a1f43590 100644 --- a/code/_onclick/_defines.dm +++ b/code/_onclick/_defines.dm @@ -1 +1,3 @@ -#define CLICKCATCHER_PLANE -99 \ No newline at end of file +#define CLICKCATCHER_PLANE -99 + +#define HUD_PLANE 90 \ No newline at end of file diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm index 02c5bfc2ac3..c32d17a65a5 100644 --- a/code/_onclick/hud/hud.dm +++ b/code/_onclick/hud/hud.dm @@ -187,3 +187,5 @@ else to_chat(usr, "This mob type does not use a HUD.") +/image + plane = FLOAT_PLANE // I have no fucking clue why this isn't FLOAT_PLANE by default in BYOND. \ No newline at end of file diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 7aa9839d663..861209033af 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -209,6 +209,7 @@ else A.screen_loc = "CENTER+[x]:16,SOUTH+[y]:7" A.layer = 20 + A.plane = HUD_PLANE x++ if(x == 4) diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm index 1f0e6205200..14a860dd2e6 100644 --- a/code/_onclick/hud/screen_objects.dm +++ b/code/_onclick/hud/screen_objects.dm @@ -10,6 +10,7 @@ name = "" icon = 'icons/mob/screen_gen.dmi' layer = 20 + plane = HUD_PLANE unacidable = 1 var/obj/master = null //A reference to the object in the slot. Grabs or items, generally. var/datum/hud/hud = null diff --git a/code/_onclick/telekinesis.dm b/code/_onclick/telekinesis.dm index ee953edac3f..50b6716c977 100644 --- a/code/_onclick/telekinesis.dm +++ b/code/_onclick/telekinesis.dm @@ -69,6 +69,7 @@ var/const/tk_maxrange = 15 //item_state = null w_class = 10.0 layer = 20 + plane = HUD_PLANE var/last_throw = 0 var/atom/movable/focus = null diff --git a/code/datums/diseases/transformation.dm b/code/datums/diseases/transformation.dm index 062b8441a30..3cb965964b3 100644 --- a/code/datums/diseases/transformation.dm +++ b/code/datums/diseases/transformation.dm @@ -54,6 +54,7 @@ qdel(W) continue W.layer = initial(W.layer) + W.plane = initial(W.plane) W.loc = affected_mob.loc W.dropped(affected_mob) var/mob/living/new_mob = new new_form(affected_mob.loc) diff --git a/code/game/gamemodes/gameticker.dm b/code/game/gamemodes/gameticker.dm index 83d21e8cfad..a4c4656391c 100644 --- a/code/game/gamemodes/gameticker.dm +++ b/code/game/gamemodes/gameticker.dm @@ -253,6 +253,7 @@ var/round_start_time = 0 cinematic.icon = 'icons/effects/station_explosion.dmi' cinematic.icon_state = "station_intact" cinematic.layer = 20 + cinematic.plane = HUD_PLANE cinematic.mouse_opacity = 0 cinematic.screen_loc = "1,0" diff --git a/code/game/gamemodes/sandbox/h_sandbox.dm b/code/game/gamemodes/sandbox/h_sandbox.dm index 4d061d37eca..e4f7bc15657 100644 --- a/code/game/gamemodes/sandbox/h_sandbox.dm +++ b/code/game/gamemodes/sandbox/h_sandbox.dm @@ -64,27 +64,35 @@ datum/hSB if(P.wear_suit) P.wear_suit.loc = P.loc P.wear_suit.layer = initial(P.wear_suit.layer) + P.wear_suit.plane = initial(P.wear_suit.plane) P.wear_suit = null P.wear_suit = new/obj/item/clothing/suit/space(P) P.wear_suit.layer = 20 + P.wear_suit.plane = HUD_PLANE if(P.head) P.head.loc = P.loc P.head.layer = initial(P.head.layer) + P.head.plane = initial(P.head.plane) P.head = null P.head = new/obj/item/clothing/head/helmet/space(P) P.head.layer = 20 + P.head.plane = HUD_PLANE if(P.wear_mask) P.wear_mask.loc = P.loc P.wear_mask.layer = initial(P.wear_mask.layer) + P.wear_mask.plane = initial(P.wear_mask.plane) P.wear_mask = null P.wear_mask = new/obj/item/clothing/mask/gas(P) P.wear_mask.layer = 20 + P.wear_mask.plane = HUD_PLANE if(P.back) P.back.loc = P.loc P.back.layer = initial(P.back.layer) + P.back.plane = initial(P.back.plane) P.back = null P.back = new/obj/item/weapon/tank/jetpack(P) P.back.layer = 20 + P.back.plane = HUD_PLANE P.internal = P.back if("hsbmetal") var/obj/item/stack/sheet/hsb = new/obj/item/stack/sheet/metal diff --git a/code/game/machinery/overview.dm b/code/game/machinery/overview.dm index 2b56b71fc43..6a4da6412f3 100644 --- a/code/game/machinery/overview.dm +++ b/code/game/machinery/overview.dm @@ -184,6 +184,7 @@ qdel(J) H.icon = HI H.layer = 25 + H.plane = HUD_PLANE usr.mapobjs += H #else @@ -308,6 +309,7 @@ H.icon = I qdel(I) H.layer = 25 + H.plane = HUD_PLANE usr.mapobjs += H #endif diff --git a/code/game/objects/effects/biomass_rift.dm b/code/game/objects/effects/biomass_rift.dm index 247f485b570..5b4cf9970a5 100644 --- a/code/game/objects/effects/biomass_rift.dm +++ b/code/game/objects/effects/biomass_rift.dm @@ -6,6 +6,7 @@ density = 0 anchored = 1 layer = 20 //DEBUG + plane = HUD_PLANE //DEBUG var/health = 10 var/stage = 1 var/obj/effect/rift/originalRift = null //the originating rift of that biomass diff --git a/code/game/objects/effects/decals/misc.dm b/code/game/objects/effects/decals/misc.dm index 9445b5aa626..6bcfb253454 100644 --- a/code/game/objects/effects/decals/misc.dm +++ b/code/game/objects/effects/decals/misc.dm @@ -12,6 +12,7 @@ density = 0 anchored = 1 layer = 50 + plane = HUD_PLANE /obj/effect/decal/chempuff name = "chemicals" diff --git a/code/game/objects/effects/misc.dm b/code/game/objects/effects/misc.dm index bc697657b98..a635d2fdad9 100644 --- a/code/game/objects/effects/misc.dm +++ b/code/game/objects/effects/misc.dm @@ -31,6 +31,7 @@ icon_state = "blank" anchored = 1 layer = 99 + plane = HUD_PLANE mouse_opacity = 0 unacidable = 1//Just to be sure. diff --git a/code/game/objects/items/devices/autopsy.dm b/code/game/objects/items/devices/autopsy.dm index 25e4d12614d..be4009b0ed9 100644 --- a/code/game/objects/items/devices/autopsy.dm +++ b/code/game/objects/items/devices/autopsy.dm @@ -165,10 +165,12 @@ P.loc = usr usr.r_hand = P P.layer = 20 + P.plane = HUD_PLANE else if(!usr.l_hand) P.loc = usr usr.l_hand = P P.layer = 20 + P.plane = HUD_PLANE if(istype(usr,/mob/living/carbon/human)) usr:update_inv_l_hand() diff --git a/code/game/objects/items/weapons/storage/storage.dm b/code/game/objects/items/weapons/storage/storage.dm index d92ad2399b2..9bbc26017be 100644 --- a/code/game/objects/items/weapons/storage/storage.dm +++ b/code/game/objects/items/weapons/storage/storage.dm @@ -151,6 +151,7 @@ for(var/obj/O in src.contents) O.screen_loc = "[cx],[cy]" O.layer = 20 + O.plane = HUD_PLANE cx++ if (cx > mx) cx = tx @@ -170,6 +171,7 @@ ND.sample_object.screen_loc = "[cx]:16,[cy]:16" ND.sample_object.maptext = "[(ND.number > 1)? "[ND.number]" : ""]" ND.sample_object.layer = 20 + ND.sample_object.plane = HUD_PLANE cx++ if (cx > (4+cols)) cx = 4 @@ -180,6 +182,7 @@ O.screen_loc = "[cx]:16,[cy]:16" O.maptext = "" O.layer = 20 + O.plane = HUD_PLANE cx++ if (cx > (4+cols)) cx = 4 @@ -337,8 +340,10 @@ W.dropped(usr) if(ismob(new_location)) W.layer = 20 + W.plane = HUD_PLANE else W.layer = initial(W.layer) + W.plane = initial(W.plane) W.loc = new_location else W.loc = get_turf(src) @@ -445,6 +450,7 @@ src.closer.master = src src.closer.icon_state = "x" src.closer.layer = 20 + src.closer.plane = HUD_PLANE orient2hud() return diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 090955de57a..ad9e56b6016 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1205,6 +1205,7 @@ if(I) I.loc = locker I.layer = initial(I.layer) + I.plane = initial(I.plane) I.dropped(M) M.update_icons() @@ -1266,6 +1267,7 @@ if(I) I.loc = M.loc I.layer = initial(I.layer) + I.plane = initial(I.plane) I.dropped(M) M.Paralyse(5) @@ -1295,6 +1297,7 @@ if(I) I.loc = M.loc I.layer = initial(I.layer) + I.plane = initial(I.plane) I.dropped(M) M.Paralyse(5) @@ -1346,6 +1349,7 @@ if(I) I.loc = M.loc I.layer = initial(I.layer) + I.plane = initial(I.plane) I.dropped(M) if(istype(M, /mob/living/carbon/human)) @@ -2264,6 +2268,7 @@ W.loc = H.loc W.dropped(H) W.layer = initial(W.layer) + W.plane = initial(W.plane) //teleport person to cell H.loc = pick(prisonwarp) H.equip_to_slot_or_del(new /obj/item/clothing/under/color/orange(H), slot_w_uniform) diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index c4088d9a53f..4f4e344c7cd 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -693,6 +693,7 @@ var/list/non_fakeattack_weapons = list(/obj/item/weapon/gun/projectile, /obj/ite if(slots_free.len) halitem.screen_loc = pick(slots_free) halitem.layer = 50 + halitem.plane = HUD_PLANE switch(rand(1,6)) if(1) //revolver halitem.icon = 'icons/obj/gun.dmi' diff --git a/code/modules/mining/equipment_locker.dm b/code/modules/mining/equipment_locker.dm index ee84c1a5864..1320423a4e8 100644 --- a/code/modules/mining/equipment_locker.dm +++ b/code/modules/mining/equipment_locker.dm @@ -292,6 +292,7 @@ s.use(s.max_amount) s.forceMove(loc) s.layer = initial(s.layer) + s.plane = initial(s.plane) /obj/machinery/mineral/ore_redemption/power_change() ..() diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm index 8d68373e3f4..bbc313e0421 100644 --- a/code/modules/mob/inventory.dm +++ b/code/modules/mob/inventory.dm @@ -28,6 +28,7 @@ W.forceMove(src) //TODO: move to equipped? l_hand = W W.layer = 20 //TODO: move to equipped? + W.plane = HUD_PLANE //TODO: move to equipped? W.equipped(src,slot_l_hand) if(pulling == W) stop_pulling() @@ -43,6 +44,7 @@ W.forceMove(src) r_hand = W W.layer = 20 + W.plane = HUD_PLANE W.equipped(src,slot_r_hand) if(pulling == W) stop_pulling() @@ -72,6 +74,7 @@ /mob/proc/put_in_hands(obj/item/W) W.forceMove(get_turf(src)) W.layer = initial(W.layer) + W.plane = initial(W.plane) W.dropped() /mob/proc/drop_item_v() //this is dumb. @@ -124,6 +127,7 @@ I.dropped(src) if(I) I.layer = initial(I.layer) + I.plane = initial(I.plane) return 1 diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 5a641a81689..69f95a4ff97 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -455,6 +455,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, for(var/obj/machinery/atmospherics/A in totalMembers) if(!A.pipe_image) A.pipe_image = image(A, A.loc, layer = 20, dir = A.dir) //the 20 puts it above Byond's darkness (not its opacity view) + A.pipe_image.plane = HUD_PLANE pipes_shown += A.pipe_image client.images += A.pipe_image @@ -563,6 +564,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, //actually throw it! if (item) item.layer = initial(item.layer) + item.plane = initial(item.plane) visible_message("\red [src] has thrown [item].") newtonian_move(get_dir(target, src)) @@ -914,6 +916,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, W.dropped(src) if (W) W.layer = initial(W.layer) + W.plane = initial(W.plane) if (legcuffed) var/obj/item/weapon/W = legcuffed legcuffed = null @@ -925,6 +928,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump, W.dropped(src) if (W) W.layer = initial(W.layer) + W.plane = initial(W.plane) /mob/living/carbon/proc/slip(var/description, var/stun, var/weaken, var/tilesSlipped, var/walkSafely, var/slipAny) diff --git a/code/modules/mob/living/carbon/give.dm b/code/modules/mob/living/carbon/give.dm index 13e8fe153ea..9dfa6efac89 100644 --- a/code/modules/mob/living/carbon/give.dm +++ b/code/modules/mob/living/carbon/give.dm @@ -49,6 +49,7 @@ target.l_hand = I I.loc = target I.layer = 20 + I.plane = HUD_PLANE I.add_fingerprint(target) src.update_inv_l_hand() src.update_inv_r_hand() diff --git a/code/modules/mob/living/carbon/human/inventory.dm b/code/modules/mob/living/carbon/human/inventory.dm index f9d9ae27442..bde2c900636 100644 --- a/code/modules/mob/living/carbon/human/inventory.dm +++ b/code/modules/mob/living/carbon/human/inventory.dm @@ -218,6 +218,7 @@ W.loc = src W.equipped(src, slot) W.layer = 20 + W.plane = HUD_PLANE switch(slot) if(slot_back) @@ -260,6 +261,7 @@ O.loc = src r_ear = O O.layer = 20 + O.plane = HUD_PLANE update_inv_ears(redraw_mob) if(slot_r_ear) r_ear = W @@ -268,6 +270,7 @@ O.loc = src l_ear = O O.layer = 20 + O.plane = HUD_PLANE update_inv_ears(redraw_mob) if(slot_glasses) glasses = W diff --git a/code/modules/mob/living/carbon/human/update_icons.dm b/code/modules/mob/living/carbon/human/update_icons.dm index 45bc15b1d51..a00d59503d9 100644 --- a/code/modules/mob/living/carbon/human/update_icons.dm +++ b/code/modules/mob/living/carbon/human/update_icons.dm @@ -636,6 +636,7 @@ var/global/list/damage_icon_parts = list() thing.loc = loc // thing.dropped(src) // thing.layer = initial(thing.layer) + thing.plane = initial(thing.plane) if(update_icons) update_icons() /mob/living/carbon/human/update_inv_wear_id(var/update_icons=1) diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm index 97b15ecda1a..12b5b062f03 100644 --- a/code/modules/mob/living/silicon/robot/inventory.dm +++ b/code/modules/mob/living/silicon/robot/inventory.dm @@ -56,6 +56,7 @@ O.mouse_opacity = initial(O.mouse_opacity) module_state_1 = O O.layer = 20 + O.plane = HUD_PLANE O.screen_loc = inv1.screen_loc contents += O if(istype(module_state_1,/obj/item/borg/sight)) @@ -64,6 +65,7 @@ O.mouse_opacity = initial(O.mouse_opacity) module_state_2 = O O.layer = 20 + O.plane = HUD_PLANE O.screen_loc = inv2.screen_loc contents += O if(istype(module_state_2,/obj/item/borg/sight)) @@ -72,6 +74,7 @@ O.mouse_opacity = initial(O.mouse_opacity) module_state_3 = O O.layer = 20 + O.plane = HUD_PLANE O.screen_loc = inv3.screen_loc contents += O if(istype(module_state_3,/obj/item/borg/sight)) diff --git a/code/modules/mob/living/simple_animal/friendly/diona.dm b/code/modules/mob/living/simple_animal/friendly/diona.dm index f62176ee926..c62243a23f4 100644 --- a/code/modules/mob/living/simple_animal/friendly/diona.dm +++ b/code/modules/mob/living/simple_animal/friendly/diona.dm @@ -243,6 +243,7 @@ /mob/living/simple_animal/diona/put_in_hands(obj/item/W) W.loc = get_turf(src) W.layer = initial(W.layer) + W.plane = initial(W.plane) W.dropped() /mob/living/simple_animal/diona/put_in_active_hand(obj/item/W) diff --git a/code/modules/mob/mob_grab.dm b/code/modules/mob/mob_grab.dm index 98437a53ffd..e4dcd59a62d 100644 --- a/code/modules/mob/mob_grab.dm +++ b/code/modules/mob/mob_grab.dm @@ -23,6 +23,7 @@ var/dancing //determines if assailant and affecting keep looking at each other. Basically a wrestling position layer = 21 + plane = HUD_PLANE item_state = "nothing" icon = 'icons/mob/screen_gen.dmi' w_class = 5.0 diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm index bf847a06c0a..4ebd93adc07 100644 --- a/code/modules/paperwork/paper.dm +++ b/code/modules/paperwork/paper.dm @@ -398,12 +398,14 @@ h_user.unEquip(src) B.loc = h_user B.layer = 20 + B.plane = HUD_PLANE h_user.l_store = B h_user.update_inv_pockets() else if (h_user.r_store == src) h_user.unEquip(src) B.loc = h_user B.layer = 20 + B.plane = HUD_PLANE h_user.r_store = B h_user.update_inv_pockets() else if (h_user.head == src) diff --git a/code/modules/paperwork/paper_bundle.dm b/code/modules/paperwork/paper_bundle.dm index a99efb09294..0cd00015af4 100644 --- a/code/modules/paperwork/paper_bundle.dm +++ b/code/modules/paperwork/paper_bundle.dm @@ -204,6 +204,7 @@ for(var/obj/O in src) O.loc = usr.loc O.layer = initial(O.layer) + O.plane = initial(O.plane) O.add_fingerprint(usr) usr.unEquip(src) qdel(src) diff --git a/code/modules/power/singularity/collector.dm b/code/modules/power/singularity/collector.dm index 5dd8f2e36ea..dd15f904614 100644 --- a/code/modules/power/singularity/collector.dm +++ b/code/modules/power/singularity/collector.dm @@ -113,6 +113,7 @@ var/global/list/rad_collectors = list() return Z.loc = get_turf(src) Z.layer = initial(Z.layer) + Z.plane = initial(Z.plane) src.P = null if(active) toggle_power() From a31c87e2e01c79aa1dc9b5ed5bb4e67843c7a4cb Mon Sep 17 00:00:00 2001 From: monster860 Date: Wed, 8 Jun 2016 21:14:14 -0400 Subject: [PATCH 018/129] Makes RnD console use NanoUI --- .../research/designs/weapon_designs.dm | 8 +- code/modules/research/protolathe.dm | 2 +- code/modules/research/rdconsole.dm | 846 ++++++------------ nano/templates/r_n_d.tmpl | 260 ++++++ 4 files changed, 541 insertions(+), 575 deletions(-) create mode 100644 nano/templates/r_n_d.tmpl diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 64ad0c962fc..f44e96ae78b 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -128,7 +128,7 @@ //WT550 Mags /datum/design/mag_oldsmg - name = "WT-550 Auto Gun Magazine (4.6×30mm)" + name = "WT-550 Auto Gun Magazine (4.6x30mm)" desc = "A 20 round magazine for the out of date security WT-550 Auto Rifle" id = "mag_oldsmg" req_tech = list("combat" = 1, "materials" = 1) @@ -138,21 +138,21 @@ category = list("Weapons") /datum/design/mag_oldsmg/ap_mag - name = "WT-550 Auto Gun Armour Piercing Magazine (4.6×30mm AP)" + name = "WT-550 Auto Gun Armour Piercing Magazine (4.6x30mm AP)" desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle" id = "mag_oldsmg_ap" materials = list(MAT_METAL = 6000, MAT_SILVER = 600) build_path = /obj/item/ammo_box/magazine/wt550m9/wtap /datum/design/mag_oldsmg/ic_mag - name = "WT-550 Auto Gun Incendiary Magazine (4.6×30mm IC)" + name = "WT-550 Auto Gun Incendiary Magazine (4.6x30mm IC)" desc = "A 20 round armour piercing magazine for the out of date security WT-550 Auto Rifle" id = "mag_oldsmg_ic" materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_GLASS = 1000) build_path = /obj/item/ammo_box/magazine/wt550m9/wtic /datum/design/mag_oldsmg/tx_mag - name = "WT-550 Auto Gun Urnaium Magazine (4.6×30mm TX)" + name = "WT-550 Auto Gun Urnaium Magazine (4.6x30mm TX)" desc = "A 20 round urnaium tipped magazine for the out of date security WT-550 Auto Rifle" id = "mag_oldsmg_tx" materials = list(MAT_METAL = 6000, MAT_SILVER = 600, MAT_URANIUM = 2000) diff --git a/code/modules/research/protolathe.dm b/code/modules/research/protolathe.dm index 3c8b89ea2a0..cff54b3bd32 100644 --- a/code/modules/research/protolathe.dm +++ b/code/modules/research/protolathe.dm @@ -41,7 +41,7 @@ Note: Must be placed west/left of and R&D console to function. component_parts += new /obj/item/weapon/stock_parts/manipulator(null) component_parts += new /obj/item/weapon/reagent_containers/glass/beaker/large(null) component_parts += new /obj/item/weapon/reagent_containers/glass/beaker/large(null) - materials = new(src, list(MAT_METAL=1, MAT_GLASS=1, MAT_SILVER=1, MAT_GOLD=1, MAT_DIAMOND=1, MAT_PLASMA=1, MAT_URANIUM=1, MAT_BANANIUM=1)) + materials = new(src, list(MAT_METAL=1, MAT_GLASS=1, MAT_SILVER=1, MAT_GOLD=1, MAT_DIAMOND=1, MAT_PLASMA=1, MAT_URANIUM=1, MAT_BANANIUM=1, MAT_TRANQUILLITE=1)) RefreshParts() reagents.my_atom = src diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 9e8b29f94c1..c5f27ba30a2 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -46,6 +46,11 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/obj/machinery/r_n_d/circuit_imprinter/linked_imprinter = null //Linked Circuit Imprinter var/screen = 1.0 //Which screen is currently showing. + + var/menu = 0 // Current menu. + var/submenu = 0 + var/wait_message = 0 + var/id = 0 //ID of the computer (for server restrictions). var/sync = 1 //If sync = 0, it doesn't show up on Server Control Console @@ -173,7 +178,7 @@ proc/CallMaterialName(ID) to_chat(user, "You add the disk to the machine!") else if(!(linked_destroy && linked_destroy.busy) && !(linked_lathe && linked_lathe.busy) && !(linked_imprinter && linked_imprinter.busy)) ..() - src.updateUsrDialog() + nanomanager.update_uis(src) return /obj/machinery/computer/rdconsole/emag_act(user as mob) @@ -195,17 +200,36 @@ proc/CallMaterialName(ID) usr.set_machine(src) if(href_list["menu"]) //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code. var/temp_screen = text2num(href_list["menu"]) - screen = temp_screen + menu = temp_screen + if(href_list["submenu"]) //Switches menu screens. Converts a sent text string into a number. Saves a LOT of code. + var/temp_screen = text2num(href_list["submenu"]) + submenu = temp_screen if(href_list["category"]) - selected_category = href_list["category"] + var/compare + + matching_designs.Cut() + + if(menu == 4) + compare = PROTOLATHE + else + compare = IMPRINTER + + for(var/datum/design/D in files.known_designs) + if(!(D.build_type & compare)) + continue + if(href_list["category"] in D.category) + matching_designs.Add(D) + submenu = 1 + + selected_category = "Viewing Category [href_list["category"]]" else if(href_list["updt_tech"]) //Update the research holder with information from the technology disk. - screen = 0.0 + wait_message = "Updating Database...." spawn(50) - screen = 1.2 + wait_message = 0 files.AddTech2Known(t_disk.stored) - updateUsrDialog() + nanomanager.update_uis(src) griefProtection() //Update centcom too else if(href_list["clear_tech"]) //Erase data on the technology disk. @@ -216,21 +240,23 @@ proc/CallMaterialName(ID) if(t_disk) t_disk.loc = src.loc t_disk = null - screen = 1.0 + menu = 0 + submenu = 0 else if(href_list["copy_tech"]) //Copy some technology data from the research holder to the disk. for(var/datum/tech/T in files.known_tech) if(href_list["copy_tech_ID"] == T.id) t_disk.stored = T break - screen = 1.2 + menu = 2 + submenu = 0 else if(href_list["updt_design"]) //Updates the research holder with design data from the design disk. - screen = 0.0 + wait_message = "Updating Database...." spawn(50) - screen = 1.4 + wait_message = 0 files.AddDesign2Known(d_disk.blueprint) - updateUsrDialog() + nanomanager.update_uis(src) griefProtection() //Update centcom too else if(href_list["clear_design"]) //Erases data on the design disk. @@ -241,7 +267,8 @@ proc/CallMaterialName(ID) if(d_disk) d_disk.loc = src.loc d_disk = null - screen = 1.0 + menu = 0 + submenu = 0 else if(href_list["copy_design"]) //Copy design data from the research holder to the design disk. for(var/datum/design/D in files.known_designs) @@ -259,7 +286,8 @@ proc/CallMaterialName(ID) D.category |= "Imported" d_disk.blueprint = D break - screen = 1.4 + menu = 2 + submenu = 0 else if(href_list["eject_item"]) //Eject the item inside the destructive analyzer. if(linked_destroy) @@ -270,20 +298,20 @@ proc/CallMaterialName(ID) linked_destroy.loaded_item.loc = linked_destroy.loc linked_destroy.loaded_item = null linked_destroy.icon_state = "d_analyzer" - screen = 2.1 + menu = 3 else if(href_list["maxresearch"]) //Eject the item inside the destructive analyzer. if(!check_rights(R_ADMIN)) return - screen = 0.0 + wait_message = "Updating Database...." if(alert("Are you sure you want to maximize research levels?","Confirmation","Yes","No")=="No") return log_admin("[key_name(usr)] has maximized the research levels.") message_admins("[key_name_admin(usr)] has maximized the research levels.") spawn(30) Maximize() - screen = 1.0 - updateUsrDialog() + wait_message = "" + nanomanager.update_uis(src) griefProtection() //Update centcomm too else if(href_list["deconstruct"]) //Deconstruct the item in the destructive analyzer and update the research holder. @@ -294,8 +322,8 @@ proc/CallMaterialName(ID) var/choice = input("Proceeding will destroy loaded item.") in list("Proceed", "Cancel") if(choice == "Cancel" || !linked_destroy) return linked_destroy.busy = 1 - screen = 0.1 - updateUsrDialog() + wait_message = "Processing and Updating Database..." + nanomanager.update_uis(src) flick("d_analyzer_process", linked_destroy) spawn(24) if(linked_destroy) @@ -303,7 +331,9 @@ proc/CallMaterialName(ID) if(!linked_destroy.hacked) if(!linked_destroy.loaded_item) to_chat(usr, "The destructive analyzer appears to be empty.") - screen = 1.0 + wait_message = 0 + menu = 0 + submenu = 0 return if((linked_destroy.loaded_item.reliability >= 99 - (linked_destroy.decon_mod * 3)) || linked_destroy.loaded_item.crit_fail) var/list/temp_tech = linked_destroy.ConvertReqString2List(linked_destroy.loaded_item.origin_tech) @@ -311,15 +341,21 @@ proc/CallMaterialName(ID) if(prob(linked_destroy.loaded_item.reliability)) //If deconstructed item is not reliable enough its just being wasted, else it is pocessed files.UpdateTech(T, temp_tech[T]) //Check if deconstructed item has research levels higher/same/one less than current ones files.UpdateDesigns(linked_destroy.loaded_item, temp_tech, src) //If if such reseach type found all the known designs are checked for having this research type in them - screen = 1.0 //If design have it it gains some reliability + wait_message = 0 //If design have it it gains some reliability + menu = 0 + submenu = 0 else //Same design always gain quality - screen = 2.3 //Crit fail gives the same design a lot of reliability, like really a lot + wait_message = 0 //Crit fail gives the same design a lot of reliability, like really a lot + menu = 2 + submenu = 0 if(linked_lathe) //Also sends salvaged materials to a linked protolathe, if any. for(var/material in linked_destroy.loaded_item.materials) linked_lathe.materials.insert_amount(min((linked_lathe.materials.max_amount - linked_lathe.materials.total_amount), (linked_destroy.loaded_item.materials[material]*(linked_destroy.decon_mod/10))), material) linked_destroy.loaded_item = null else - screen = 1.0 + wait_message = 0 + menu = 0 + submenu = 0 for(var/obj/I in linked_destroy.contents) for(var/mob/M in I.contents) M.death() @@ -336,10 +372,10 @@ proc/CallMaterialName(ID) qdel(I) linked_destroy.icon_state = "d_analyzer" use_power(250) - updateUsrDialog() + nanomanager.update_uis(src) else if(href_list["sync"]) //Sync the research holder with all the R&D consoles in the game that aren't sync protected. - screen = 0.0 + wait_message = "Updating Database...." if(!sync) to_chat(usr, "You must connect to the network first!") else @@ -366,8 +402,8 @@ proc/CallMaterialName(ID) server_processed = 1 if(!istype(S, /obj/machinery/r_n_d/server/centcom) && server_processed) S.produce_heat(100) - screen = 1.6 - updateUsrDialog() + wait_message = 0 + nanomanager.update_uis(src) else if(href_list["togglesync"]) //Prevents the console from being synced by other consoles. Can still send data. sync = !sync @@ -388,12 +424,11 @@ proc/CallMaterialName(ID) if(being_built) var/power = 2000 var/amount=text2num(href_list["amount"]) - var/old_screen = screen amount = max(1, min(10, amount)) for(var/M in being_built.materials) power += round(being_built.materials[M] * amount / 5) power = max(2000, power) - screen = 0.3 + wait_message = "Constructing Prototype. Please Wait..." if(linked_lathe.busy) g2g = 0 var/key = usr.key //so we don't lose the info during the spawn delay @@ -453,8 +488,8 @@ proc/CallMaterialName(ID) else new_item.loc = linked_lathe.loc linked_lathe.busy = 0 - screen = old_screen - updateUsrDialog() + wait_message = 0 + nanomanager.update_uis(src) else if(href_list["imprint"]) //Causes the Circuit Imprinter to build something. var/coeff = linked_imprinter.efficiency_coeff @@ -467,11 +502,10 @@ proc/CallMaterialName(ID) break if(being_built) var/power = 2000 - var/old_screen = screen for(var/M in being_built.materials) power += round(being_built.materials[M] / 5) power = max(2000, power) - screen = 0.4 + wait_message = "Imprinting Circuit. Please Wait..." if (linked_imprinter.busy) g2g = 0 if (!(being_built.build_type & IMPRINTER)) @@ -505,8 +539,8 @@ proc/CallMaterialName(ID) new_item.reliability = 100 new_item.loc = linked_imprinter.loc linked_imprinter.busy = 0 - screen = old_screen - updateUsrDialog() + wait_message = 0 + nanomanager.update_uis(src) else if(href_list["disposeI"] && linked_imprinter) //Causes the circuit imprinter to dispose of a single reagent (all of it) linked_imprinter.reagents.del_reagent(href_list["disposeI"]) @@ -530,27 +564,7 @@ proc/CallMaterialName(ID) desired_num_sheets = round(desired_num_sheets) // No partial-sheet goofery else desired_num_sheets = text2num(href_list["lathe_ejectsheet_amt"]) - var/MAT - switch(href_list["lathe_ejectsheet"]) - if("metal") - MAT = MAT_METAL - if("glass") - MAT = MAT_GLASS - if("gold") - MAT = MAT_GOLD - if("silver") - MAT = MAT_SILVER - if("plasma") - MAT = MAT_PLASMA - if("uranium") - MAT = MAT_URANIUM - if("diamond") - MAT = MAT_DIAMOND - if("clown") - MAT = MAT_BANANIUM - if("mime") - MAT = "Tranquillite" - linked_lathe.materials.retrieve_sheets(desired_num_sheets, MAT) + linked_lathe.materials.retrieve_sheets(desired_num_sheets, href_list["lathe_ejectsheet"]) else if(href_list["imprinter_ejectsheet"] && linked_imprinter) //Causes the protolathe to eject a sheet of material var/desired_num_sheets = text2num(href_list["imprinter_ejectsheet_amt"]) @@ -564,13 +578,13 @@ proc/CallMaterialName(ID) desired_num_sheets = text2num(href_list["imprinter_ejectsheet_amt"]) var/res_amount, type switch(href_list["imprinter_ejectsheet"]) - if("glass") + if(MAT_GLASS) type = /obj/item/stack/sheet/glass res_amount = "g_amount" - if("gold") + if(MAT_GOLD) type = /obj/item/stack/sheet/mineral/gold res_amount = "gold_amount" - if("diamond") + if(MAT_DIAMOND) type = /obj/item/stack/sheet/mineral/diamond res_amount = "diamond_amount" if(ispath(type) && hasvar(linked_imprinter, res_amount)) @@ -583,11 +597,11 @@ proc/CallMaterialName(ID) qdel(sheet) else if(href_list["find_device"]) //The R&D console looks for devices nearby to link up with. - screen = 0.0 + wait_message = "Updating Database...." spawn(20) SyncRDevices() - screen = 1.7 - updateUsrDialog() + wait_message = 0 + nanomanager.update_uis(src) else if(href_list["disconnect"]) //The R&D console disconnects with a specific device. switch(href_list["disconnect"]) @@ -603,34 +617,35 @@ proc/CallMaterialName(ID) else if(href_list["reset"]) //Reset the R&D console's database. griefProtection() - var/choice = alert("R&D Console Database Reset", "Are you sure you want to reset the R&D console's database? Data lost cannot be recovered.", "Continue", "Cancel") + var/choice = alert("Are you sure you want to reset the R&D console's database? Data lost cannot be recovered.", "R&D Console Database Reset", "Continue", "Cancel") if(choice == "Continue") - screen = 0.0 + wait_message = "Updating Database...." qdel(files) files = new /datum/research(src) spawn(20) - screen = 1.6 - updateUsrDialog() + wait_message = 0 + nanomanager.update_uis(src) else if(href_list["search"]) //Search for designs with name matching pattern var/compare matching_designs.Cut() - if(href_list["type"] == "proto") + if(menu == 4) compare = PROTOLATHE - screen = 3.17 else compare = IMPRINTER - screen = 4.17 for(var/datum/design/D in files.known_designs) if(!(D.build_type & compare)) continue if(findtext(D.name,href_list["to_search"])) matching_designs.Add(D) + submenu = 1 + + selected_category = "Search Results for '[href_list["to_search"]]'" - updateUsrDialog() + nanomanager.update_uis(src) return @@ -640,530 +655,221 @@ proc/CallMaterialName(ID) if(!allowed(user) && !isobserver(user)) to_chat(user, "Access denied.") return 1 - interact(user) - -/obj/machinery/computer/rdconsole/interact(mob/user) + ui_interact(user) +/obj/machinery/computer/rdconsole/ui_interact(mob/user, ui_key="main", var/datum/nanoui/ui = null, var/force_open = 1) user.set_machine(src) - var/dat = "" + var/data = list() + files.RefreshResearch() - switch(screen) //A quick check to make sure you get the right screen when a device is disconnected. - if(2 to 2.9) - if(screen == 2.3) - ; - else if(linked_destroy == null) - screen = 2.0 - else if(linked_destroy.loaded_item == null) - screen = 2.1 - else - screen = 2.2 - if(3 to 3.9) - if(linked_lathe == null) - screen = 3.0 - if(4 to 4.9) - if(linked_imprinter == null) - screen = 4.0 - - switch(screen) - - //////////////////////R&D CONSOLE SCREENS////////////////// - if(0.0) dat += "
Updating Database....
" - - if(0.1) dat += "
Processing and Updating Database...
" - - if(0.3) - dat += "
Constructing Prototype. Please Wait...
" - - if(0.4) - dat += "
Imprinting Circuit. Please Wait...
" - - if(1.0) //Main Menu - dat += "
" - dat += "

Main Menu:


" - dat += "Current Research Levels
" - if(t_disk) - dat += "Disk Operations
" - else if(d_disk) - dat += "Disk Operations
" - else - dat += "Disk Operations
" - if(linked_destroy) - dat += "Destructive Analyzer Menu
" - else - dat += "Destructive Analyzer Menu
" - if(linked_lathe) - dat += "Protolathe Construction Menu
" - else - dat += "Protolathe Construction Menu
" - if(linked_imprinter) - dat += "Circuit Construction Menu
" - else - dat += "Circuit Construction Menu
" - dat += "Settings" - dat += "
" - - if(1.1) //Research viewer - dat += "Main Menu" - dat += "

Current Research Levels:


" + + data["menu"] = menu + data["submenu"] = submenu + data["wait_message"] = wait_message + data["src_ref"] = "\ref[src]" + + data["linked_destroy"] = linked_destroy ? 1 : 0 + data["linked_lathe"] = linked_lathe ? 1 : 0 + data["linked_imprinter"] = linked_imprinter ? 1 : 0 + data["sync"] = sync + data["admin"] = check_rights(R_ADMIN,0) + data["disk_type"] = d_disk ? 2 : (t_disk ? 1 : 0) + data["category"] = selected_category + + if(menu == 1) + var/list/tech_levels = list() + data["tech_levels"] = tech_levels + for(var/datum/tech/T in files.known_tech) + if(T.level <= 0) + continue + var/list/this_tech_list = list() + this_tech_list["name"] = T.name + this_tech_list["level"] = T.level + this_tech_list["desc"] = T.desc + tech_levels[++tech_levels.len] = this_tech_list + + if(menu == 2) + + if(t_disk != null && t_disk.stored != null && submenu == 0) //Technology Disk Menu + var/list/disk_data = list() + data["disk_data"] = disk_data + disk_data["name"] = t_disk.stored.name + disk_data["level"] = t_disk.stored.level + disk_data["desc"] = t_disk.stored.desc + + if(t_disk != null && submenu == 1) + var/list/to_copy = list() + data["to_copy"] = to_copy for(var/datum/tech/T in files.known_tech) + var/list/item = list() + to_copy[++to_copy.len] = item if(T.level <= 0) continue - dat += "[T.name]
" - dat += "* Level: [T.level]
" - dat += "* Summary: [T.desc]
" - dat += "
" - - if(1.2) //Technology Disk Menu - - dat += "Main Menu
" - dat += "
Technology Data Disk Contents:

" - if(t_disk.stored == null) - dat += "The disk has no data stored on it.
" - dat += "Operations: " - dat += "Load Tech to Disk" - else - dat += "Name: [t_disk.stored.name]
" - dat += "Level: [t_disk.stored.level]
" - dat += "Description: [t_disk.stored.desc]" - dat += "Operations: " - dat += "Upload to Database" - dat += "Clear Disk" - dat += "Eject Disk" - - if(1.3) //Technology Disk submenu - dat += "Main Menu" - dat += "Return to Disk Operations
" - dat += "

Load Technology to Disk:


" - for(var/datum/tech/T in files.known_tech) - if(T.level <= 0) - continue - dat += "[T.name] " - dat += "Copy to Disk
" - dat += "
" - - if(1.4) //Design Disk menu. - dat += "Main Menu
" - if(d_disk.blueprint == null) - dat += "The disk has no data stored on it.
" - dat += "Operations: " - dat += "Load Design to Disk" - else - dat += "Name: [d_disk.blueprint.name]
" - dat += "Level: [d_disk.blueprint.reliability]
" - var/b_type = d_disk.blueprint.build_type - if(b_type) - dat += "Lathe Types:
" - if(b_type & IMPRINTER) dat += "Circuit Imprinter
" - if(b_type & PROTOLATHE) dat += "Proto-lathe
" - if(b_type & AUTOLATHE) dat += "Auto-lathe
" - if(b_type & MECHFAB) dat += "Mech Fabricator
" - dat += "Required Materials:
" - for(var/M in d_disk.blueprint.materials) - if(copytext(M, 1, 2) == "$") dat += "* [copytext(M, 2)] x [d_disk.blueprint.materials[M]]
" - else dat += "* [M] x [d_disk.blueprint.materials[M]]
" - dat += "Operations: " - dat += "Upload to Database" - dat += "Clear Disk" - dat += "Eject Disk" - - if(1.5) //Technology disk submenu - dat += "Main Menu" - dat += "Return to Disk Operations
" - dat += "

Load Design to Disk:


" + item["name"] = T.name + item["id"] = T.id + + if(d_disk != null && d_disk.blueprint != null && submenu == 0) + var/list/disk_data = list() + data["disk_data"] = disk_data + disk_data["name"] = d_disk.blueprint.name + disk_data["reliability"] = d_disk.blueprint.reliability + var/b_type = d_disk.blueprint.build_type + var/list/lathe_types = list() + disk_data["lathe_types"] = lathe_types + if(b_type) + if(b_type & IMPRINTER) lathe_types += "Circuit Imprinter" + if(b_type & PROTOLATHE) lathe_types += "Protolathe" + if(b_type & AUTOLATHE) lathe_types += "Autolathe" + if(b_type & MECHFAB) lathe_types += "Mech Fabricator" + if(b_type & PODFAB) lathe_types += "Spacepod Fabricator" + var/list/materials = list() + disk_data["materials"] = materials + for(var/M in d_disk.blueprint.materials) + var/list/material = list() + materials[++materials.len] = material + material["name"] = CallMaterialName(M) + material["amount"] = d_disk.blueprint.materials[M] + + if(d_disk != null && submenu == 1) + var/list/to_copy = list() + data["to_copy"] = to_copy for(var/datum/design/D in files.known_designs) - dat += "[D.name] " - dat += "Copy to Disk
" - dat += "
" - - if(1.6) //R&D console settings - dat += "Main Menu
" - dat += "

R&D Console Setting:


" - if(sync) - dat += "Sync Database with Network
" - dat += "Connect to Research Network
" - dat += "Disconnect from Research Network
" - else - dat += "Sync Database with Network
" - dat += "Connect to Research Network
" - dat += "Disconnect from Research Network
" - dat += "Device Linkage Menu
" - if(check_rights(R_ADMIN,0)) - dat += "\[ADMIN\] Maximize Research Levels
" - dat += "Reset R&D Database
" - - if(1.7) //R&D device linkage - dat += "Main Menu" - dat += "Settings Menu
" - dat += "

R&D Console Device Linkage Menu:


" - dat += "Re-sync with Nearby Devices

" - dat += "

Linked Devices:


" - if(linked_destroy) - dat += "* Destructive Analyzer Disconnect
" - else - dat += "* No Destructive Analyzer Linked
" - if(linked_lathe) - dat += "* Protolathe Disconnect
" - else - dat += "* No Protolathe Linked
" - if(linked_imprinter) - dat += "* Circuit Imprinter Disconnect
" - else - dat += "* No Circuit Imprinter Linked
" - dat += "
" - - ////////////////////DESTRUCTIVE ANALYZER SCREENS//////////////////////////// - if(2.0) - dat += "Main Menu" - dat += "
NO DESTRUCTIVE ANALYZER LINKED TO CONSOLE
" - - if(2.1) - dat += "Main Menu" - dat += "
No Item Loaded. Standing-by...
" - - if(2.2) - dat += "Main Menu
" - dat += "

Deconstruction Menu


" - dat += "Name: [linked_destroy.loaded_item.name]
" - dat += "Reliability: [linked_destroy.loaded_item.reliability]
" - dat += "Origin Tech:
" - var/list/temp_tech = linked_destroy.ConvertReqString2List(linked_destroy.loaded_item.origin_tech) - for(var/T in temp_tech) - dat += "* [CallTechName(T)] [temp_tech[T]]" - for(var/datum/tech/F in files.known_tech) - if(F.name == CallTechName(T)) - dat += " (Current: [F.level])" - break - dat += "
" - dat += "
Options: " - dat += "Deconstruct Item" - dat += "Eject Item" - if(2.3) - dat += "Main Menu" - dat += "
Item is neither reliable enough or broken enough to learn from.
" - - /////////////////////PROTOLATHE SCREENS///////////////////////// - if(3.0) - dat += "Main Menu
" - dat += "
NO PROTOLATHE LINKED TO CONSOLE
" - - if(3.1) - dat += "Main Menu " - dat += "Material Storage" - dat += "Chemical Storage
" - dat += "

Protolathe Menu:


" - dat += "Material Amount: [linked_lathe.materials.total_amount] / [linked_lathe.materials.max_amount]
" - dat += "Chemical Volume: [linked_lathe.reagents.total_volume] / [linked_lathe.reagents.maximum_volume]
" - - dat += "
\ - \ - \ - \ - \ - \ -

" - - dat += list_categories(linked_lathe.categories, 3.15) - - //Grouping designs by categories, to improve readability - if(3.15) - dat += "Main Menu" - dat += "Protolathe Menu" - dat += "

Browsing [selected_category]:


" - dat += "Material Amount: [linked_lathe.materials.total_amount] / [linked_lathe.materials.max_amount]
" - dat += "Chemical Volume: [linked_lathe.reagents.total_volume] / [linked_lathe.reagents.maximum_volume]
" - - for(var/datum/design/D in files.known_designs) - if(!(selected_category in D.category)|| !(D.build_type & PROTOLATHE)) - continue - var/temp_material - var/c = 50 - var/t - for(var/M in D.materials) - t = linked_lathe.check_mat(D, M) - temp_material += " | " - if (t < 1) - temp_material += "[D.materials[M]] [CallMaterialName(M)]" - else - temp_material += " [D.materials[M]] [CallMaterialName(M)]" - c = min(c,t) - - - for(var/R in D.reagents) - t = linked_lathe.check_mat(D, R) - temp_material += " | " - if (t < 1) - temp_material += "[D.reagents[R]] [CallMaterialName(R)]" - else - temp_material += " [D.reagents[R]] [CallMaterialName(R)]" - c = min(c,t) - - if (c >= 1) - dat += "[D.name]" - if(c >= 5) - dat += "x5" - if(c >= 10) - dat += "x10" - dat += "[temp_material]" - else - dat += "[D.name][temp_material]" - if(D.locked) - dat += " | LOCKED" - dat += "
" - dat += "
" - - if(3.17) //Display search result - dat += "Main Menu" - dat += "Protolathe Menu" - dat += "

Search results:


" - dat += "Material Amount: [linked_lathe.materials.total_amount] / [linked_lathe.materials.max_amount]
" - dat += "Chemical Volume: [linked_lathe.reagents.total_volume] / [linked_lathe.reagents.maximum_volume]
" + var/list/item = list() + to_copy[++to_copy.len] = item + item["name"] = D.name + item["id"] = D.id + if(menu == 3 && linked_destroy && linked_destroy.loaded_item) + var/list/loaded_item_list = list() + data["loaded_item"] = loaded_item_list + loaded_item_list["name"] = linked_destroy.loaded_item.name + loaded_item_list["reliability"] = linked_destroy.loaded_item.reliability + var/list/temp_tech = linked_destroy.ConvertReqString2List(linked_destroy.loaded_item.origin_tech) + var/list/tech_list = list() + loaded_item_list["origin_tech"] = tech_list + for(var/T in temp_tech) + var/list/tech_item = list() + tech_list[++tech_list.len] = tech_item + tech_item["name"] = CallTechName(T) + tech_item["object_level"] = temp_tech[T] + for(var/datum/tech/F in files.known_tech) + if(F.name == CallTechName(T)) + tech_item["current_level"] = F.level + break + + if(menu == 4 && linked_lathe) + data["total_materials"] = linked_lathe.materials.total_amount + data["max_materials"] = linked_lathe.materials.max_amount + data["total_chemicals"] = linked_lathe.reagents.total_volume + data["max_chemicals"] = linked_lathe.reagents.maximum_volume + data["categories"] = linked_lathe.categories + if(submenu == 1) + var/list/designs_list = list() + data["matching_designs"] = designs_list for(var/datum/design/D in matching_designs) - var/temp_material + var/list/design_list = list() + designs_list[++designs_list.len] = design_list + var/list/materials_list = list() + design_list["materials"] = materials_list + design_list["id"] = D.id + design_list["name"] = sanitize(D.name) var/c = 50 - var/t for(var/M in D.materials) - t = linked_lathe.check_mat(D, M) - temp_material += " | " - if (t < 1) - temp_material += "[D.materials[M]] [CallMaterialName(M)]" + var/list/material_list = list() + materials_list[++materials_list.len] = material_list + material_list["name"] = CallMaterialName(M) + material_list["amount"] = D.materials[M] + var/t = linked_lathe.check_mat(D, M) + + if(t < 1) + material_list["is_red"] = 1 else - temp_material += " [D.materials[M]] [CallMaterialName(M)]" - c = min(c,t) + material_list["is_red"] = 0 + c = min(c, t) for(var/R in D.reagents) - t = linked_lathe.check_mat(D, R) - temp_material += " | " - if (t < 1) - temp_material += "[D.reagents[R]] [CallMaterialName(R)]" + var/list/material_list = list() + materials_list[++materials_list.len] = material_list + material_list["name"] = CallMaterialName(R) + material_list["amount"] = D.reagents[R] + var/t = linked_lathe.check_mat(D, R) + + if(t < 1) + material_list["is_red"] = 1 else - temp_material += " [D.reagents[R]] [CallMaterialName(R)]" - c = min(c,t) - - if (c >= 1) - dat += "[D.name]" - if(c >= 5) - dat += "x5" - if(c >= 10) - dat += "x10" - dat += "[temp_material]" - else - dat += "[D.name][temp_material]" - dat += "
" - dat += "
" - - if(3.2) //Protolathe Material Storage Sub-menu - dat += "Main Menu" - dat += "Protolathe Menu
" - dat += "

Material Storage:



" - //Metal - var/m_amount = linked_lathe.materials.amount(MAT_METAL) - dat += "* [m_amount] of Metal, [round(m_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(m_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(m_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(m_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Glass - var/g_amount = linked_lathe.materials.amount(MAT_GLASS) - dat += "* [g_amount] of Glass, [round(g_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(g_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(g_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(g_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Gold - var/gold_amount = linked_lathe.materials.amount(MAT_GOLD) - dat += "* [gold_amount] of Gold, [round(gold_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(gold_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(gold_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(gold_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Silver - var/silver_amount = linked_lathe.materials.amount(MAT_SILVER) - dat += "* [silver_amount] of Silver, [round(silver_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(silver_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(silver_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(silver_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Plasma - var/plasma_amount = linked_lathe.materials.amount(MAT_PLASMA) - dat += "* [plasma_amount] of Solid Plasma, [round(plasma_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(plasma_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(plasma_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(plasma_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Uranium - var/uranium_amount = linked_lathe.materials.amount(MAT_URANIUM) - dat += "* [uranium_amount] of Uranium, [round(uranium_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(uranium_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(uranium_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(uranium_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Diamond - var/diamond_amount = linked_lathe.materials.amount(MAT_DIAMOND) - dat += "* [diamond_amount] of Diamond, [round(diamond_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(diamond_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(diamond_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(diamond_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Bananium - var/bananium_amount = linked_lathe.materials.amount(MAT_BANANIUM) - dat += "* [bananium_amount] of Bananium, [round(bananium_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(bananium_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(bananium_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(bananium_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Tranquillite - var/tranquillite_amount = linked_lathe.materials.amount(MAT_TRANQUILLITE) - dat += "* [tranquillite_amount] of Tranquillite, [round(tranquillite_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(tranquillite_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(tranquillite_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(tranquillite_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - - if(3.3) - dat += "Main Menu" - dat += "Protolathe Menu" - dat += "Disposal All Chemicals in Storage
" - dat += "

Chemical Storage:



" + material_list["is_red"] = 0 + c = min(c, t) + design_list["can_build"] = c + if(submenu == 2) + var/list/materials_list = list() + data["loaded_materials"] = materials_list + materials_list[++materials_list.len] = list("name" = "Metal", "id" = MAT_METAL, "amount" = linked_lathe.materials.amount(MAT_METAL)) + materials_list[++materials_list.len] = list("name" = "Glass", "id" = MAT_GLASS, "amount" = linked_lathe.materials.amount(MAT_GLASS)) + materials_list[++materials_list.len] = list("name" = "Gold", "id" = MAT_GOLD, "amount" = linked_lathe.materials.amount(MAT_GOLD)) + materials_list[++materials_list.len] = list("name" = "Silver", "id" = MAT_SILVER, "amount" = linked_lathe.materials.amount(MAT_SILVER)) + materials_list[++materials_list.len] = list("name" = "Plasma", "id" = MAT_PLASMA, "amount" = linked_lathe.materials.amount(MAT_PLASMA)) + materials_list[++materials_list.len] = list("name" = "Uranium", "id" = MAT_URANIUM, "amount" = linked_lathe.materials.amount(MAT_URANIUM)) + materials_list[++materials_list.len] = list("name" = "Diamond", "id" = MAT_DIAMOND, "amount" = linked_lathe.materials.amount(MAT_DIAMOND)) + materials_list[++materials_list.len] = list("name" = "Bananium", "id" = MAT_BANANIUM, "amount" = linked_lathe.materials.amount(MAT_BANANIUM)) + materials_list[++materials_list.len] = list("name" = "Tranquillite", "id" = MAT_TRANQUILLITE, "amount" = linked_lathe.materials.amount(MAT_TRANQUILLITE)) + if(submenu == 3) + var/list/loaded_chemicals = list() + data["loaded_chemicals"] = loaded_chemicals for(var/datum/reagent/R in linked_lathe.reagents.reagent_list) - dat += "[R.name]: [R.volume]" - dat += "Purge
" - - ///////////////////CIRCUIT IMPRINTER SCREENS//////////////////// - if(4.0) - dat += "Main Menu
" - dat += "
NO CIRCUIT IMPRINTER LINKED TO CONSOLE
" - - if(4.1) - dat += "Main Menu" - dat += "Material Storage" - dat += "Chemical Storage
" - dat += "

Circuit Imprinter Menu:


" - dat += "Material Amount: [linked_imprinter.TotalMaterials()]
" - dat += "Chemical Volume: [linked_imprinter.reagents.total_volume]
" - - dat += "
\ - \ - \ - \ - \ - \ -

" - - dat += list_categories(linked_imprinter.categories, 4.15) - - if(4.15) - dat += "Main Menu" - dat += "Circuit Imprinter Menu" - dat += "

Browsing [selected_category]:


" - dat += "Material Amount: [linked_imprinter.TotalMaterials()]
" - dat += "Chemical Volume: [linked_imprinter.reagents.total_volume]
" - - var/coeff = linked_imprinter.efficiency_coeff - for(var/datum/design/D in files.known_designs) - if(!(selected_category in D.category) || !(D.build_type & IMPRINTER)) - continue - var/temp_materials - var/check_materials = 1 - for(var/M in D.materials) - temp_materials += " | " - if (!linked_imprinter.check_mat(D, M)) - check_materials = 0 - temp_materials += " [D.materials[M]/coeff] [CallMaterialName(M)]" - else - temp_materials += " [D.materials[M]/coeff] [CallMaterialName(M)]" - if (check_materials) - dat += "[D.name][temp_materials]
" - else - dat += "[D.name][temp_materials]
" - if(D.locked) - dat += " | LOCKED" - dat += "
" - - if(4.17) - dat += "Main Menu" - dat += "Circuit Imprinter Menu" - dat += "

Search results:


" - dat += "Material Amount: [linked_imprinter.TotalMaterials()]
" - dat += "Chemical Volume: [linked_imprinter.reagents.total_volume]
" - + var/list/loaded_chemical = list() + loaded_chemicals[++loaded_chemicals.len] = loaded_chemical + loaded_chemical["name"] = R.name + loaded_chemical["volume"] = R.volume + loaded_chemical["id"] = R.id + + if(menu == 5 && linked_imprinter) + data["total_materials"] = linked_imprinter.TotalMaterials() + data["total_chemicals"] = linked_imprinter.reagents.total_volume + data["categories"] = linked_imprinter.categories + if(submenu == 1) + var/list/designs_list = list() + data["matching_designs"] = designs_list var/coeff = linked_imprinter.efficiency_coeff for(var/datum/design/D in matching_designs) - var/temp_materials + var/list/design_list = list() + designs_list[++designs_list.len] = design_list + var/list/materials_list = list() + design_list["materials"] = materials_list + design_list["id"] = D.id + design_list["name"] = sanitize(D.name) var/check_materials = 1 for(var/M in D.materials) - temp_materials += " | " + var/list/material_list = list() + materials_list[++materials_list.len] = material_list + material_list["name"] = CallMaterialName(M) + material_list["amount"] = D.materials[M] / coeff if (!linked_imprinter.check_mat(D, M)) check_materials = 0 - temp_materials += " [D.materials[M]/coeff] [CallMaterialName(M)]" + material_list["is_red"] = 1 else - temp_materials += " [D.materials[M]/coeff] [CallMaterialName(M)]" - if (check_materials) - dat += "[D.name][temp_materials]
" - else - dat += "[D.name][temp_materials]
" - dat += "
" - - if(4.2) - dat += "Main Menu" - dat += "Imprinter Menu" - dat += "Disposal All Chemicals in Storage
" - dat += "

Chemical Storage:



" + material_list["is_red"] = 0 + design_list["can_build"] = check_materials + if(submenu == 2) + var/list/materials_list = list() + data["loaded_materials"] = materials_list + materials_list[++materials_list.len] = list("name" = "Glass", "id" = MAT_GLASS, "amount" = linked_imprinter.g_amount) + materials_list[++materials_list.len] = list("name" = "Gold", "id" = MAT_GOLD, "amount" = linked_imprinter.gold_amount) + materials_list[++materials_list.len] = list("name" = "Diamond", "id" = MAT_DIAMOND, "amount" = linked_imprinter.diamond_amount) + if(submenu == 3) + var/list/loaded_chemicals = list() + data["loaded_chemicals"] = loaded_chemicals for(var/datum/reagent/R in linked_imprinter.reagents.reagent_list) - dat += "[R.name]: [R.volume]" - dat += "Purge
" - - if(4.3) - dat += "Main Menu" - dat += "Circuit Imprinter Menu
" - dat += "

Material Storage:



" - //Glass - dat += "* [linked_imprinter.g_amount] glass, [round(linked_imprinter.g_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(linked_imprinter.g_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(linked_imprinter.g_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(linked_imprinter.g_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Gold - dat += "* [linked_imprinter.gold_amount] gold, [round(linked_imprinter.gold_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(linked_imprinter.gold_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(linked_imprinter.gold_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(linked_imprinter.gold_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - //Diamond - dat += "* [linked_imprinter.diamond_amount] diamond, [round(linked_imprinter.diamond_amount / MINERAL_MATERIAL_AMOUNT,0.1)] sheets: " - if(linked_imprinter.diamond_amount >= MINERAL_MATERIAL_AMOUNT) - dat += "Eject " - dat += "C " - if(linked_imprinter.diamond_amount >= MINERAL_MATERIAL_AMOUNT*5) dat += "5x " - if(linked_imprinter.diamond_amount >= MINERAL_MATERIAL_AMOUNT) dat += "All" - dat += "
" - - var/datum/browser/popup = new(user, "rndconsole", name, 700, 550) - popup.set_content(dat) - popup.open() - return + var/list/loaded_chemical = list() + loaded_chemicals[++loaded_chemicals.len] = loaded_chemical + loaded_chemical["name"] = R.name + loaded_chemical["volume"] = R.volume + loaded_chemical["id"] = R.id + + ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) + if (!ui) + ui = new(user, src, ui_key, "r_n_d.tmpl", src.name, 700, 550) + ui.set_initial_data(data) + ui.open() //helper proc, which return a table containing categories /obj/machinery/computer/rdconsole/proc/list_categories(var/list/categories, var/menu_num as num) diff --git a/nano/templates/r_n_d.tmpl b/nano/templates/r_n_d.tmpl new file mode 100644 index 00000000000..5d29c399550 --- /dev/null +++ b/nano/templates/r_n_d.tmpl @@ -0,0 +1,260 @@ +{{if data.menu > 0 && !data.wait_message}} +
+ {{:helper.link('Main Menu', 'reply', {'menu': 0, 'submenu': 0})}} + {{if data.submenu > 0}} + {{if data.menu == 2}} + {{:helper.link('Disk Operations Menu', 'reply', {'submenu': 0})}} + {{else data.menu == 4}} + {{:helper.link('Protolathe Menu', 'reply', {'submenu': 0})}} + {{else data.menu == 5}} + {{:helper.link('Circuit Imprinter Menu', 'reply', {'submenu': 0})}} + {{else data.menu == 6}} + {{:helper.link('Settings Menu', 'reply', {'submenu': 0})}} + {{/if}} + {{else data.menu == 4 || data.menu == 5}} + {{:helper.link('Material Storage', 'arrow-up', {'submenu': 2})}} + {{:helper.link('Chemical Storage', 'arrow-up', {'submenu': 3})}} + {{/if}} +
+{{/if}} +
+ {{if data.wait_message}} + {{:data.wait_message}} + {{else data.menu == 0}} +

Main Menu:

+
{{:helper.link('Current Research Levels', 'folder-open', {'menu': 1, 'submenu': 0})}}
+
{{:helper.link('Disk Operations', 'save', {'menu': 2, 'submenu': 0}, data.disk_type ? null : 'disabled')}}
+
{{:helper.link('Destructive Analyzer Menu', 'chain-broken', {'menu': 3, 'submenu': 0}, data.linked_destroy ? null : 'disabled')}}
+
{{:helper.link('Protolathe Menu', 'print', {'menu': 4, 'submenu': 0}, data.linked_lathe ? null : 'disabled')}}
+
{{:helper.link('Circuit Imprinter Menu', 'print', {'menu': 5, 'submenu': 0}, data.linked_imprinter ? null : 'disabled')}}
+
{{:helper.link('Settings', 'gear', {'menu': 6, 'submenu': 0})}}
+ {{else data.menu == 1}} +

Current Research Levels:

+ {{for data.tech_levels}} + {{if index > 0}} +
+ {{/if}} +
{{:value.name}}
+
* Level: {{:value.level}}
+
* Summary: {{:value.desc}}
+ {{/for}} + {{else data.menu == 2 && data.disk_type}} + {{if data.submenu == 0}} +

Data Disk Contents:

+ {{if data.disk_data}} + {{if data.disk_type == 1}} +
Name: {{:data.disk_data.name}}
+
Level: {{:data.disk_data.level}}
+
Description: {{:data.disk_data.desc}}
+ {{:helper.link('Upload to Database', 'arrow-up', {'updt_tech': 1})}} + {{:helper.link('Clear Disk', 'trash', {'clear_tech': 1})}} + {{else}} +
Name: {{:data.disk_data.name}}
+
Reliability: {{:data.disk_data.reliability}}
+
+ {{for data.disk_data.lathe_types}} + {{if index == 0}} + Lathe Types: + {{else}} + , + {{/if}} + {{:value}} + {{/for}} +
+
Required Materials:
+ {{for data.disk_data.materials}} +
{{:value.name}} x {{:value.amount}}
+ {{/for}} + {{:helper.link('Upload to Database', 'arrow-up', {'updt_design': 1})}} + {{:helper.link('Clear Disk', 'trash', {'clear_design': 1})}} + {{/if}} + {{else}} +
This disk is empty.
+ {{:helper.link(data.disk_type == 1 ? 'Load Tech to Disk' : 'Load Design to Disk', 'arrow-down', {'submenu': 1})}} + {{/if}} + {{:helper.link('Eject Disk', 'eject', data.disk_type == 1 ? {'eject_tech': 1} : {'eject_design': 1})}} + {{else data.submenu == 1}} + {{for data.to_copy}} +
+
{{:value.name}}
+ {{:helper.link('Copy to Disk', 'arrow-down', data.disk_type == 1 ? {'copy_tech': 1, 'copy_tech_ID': value.id} : {'copy_design': 1, 'copy_design_ID': value.id})}} +
+ {{/for}} + {{/if}} + {{else data.menu == 3 && !data.linked_destroy}} + NO DESTRUCTIVE ANALYZER LINKED TO CONSOLE + {{else data.menu == 4 && !data.linked_lathe}} + NO PROTOLATHE LINKED TO CONSOLE + {{else data.menu == 5 && !data.linked_imprinter}} + NO CIRCUIT IMPRITER LINKED TO CONSOLE + {{else data.menu == 3}} + {{if !data.loaded_item}} + No item loaded. Standing by... + {{else}} +

Deconstruction Menu:

+
Name: {{:data.loaded_item.name}}
+
Reliability: {{:data.loaded_item.reliability}}
+

Origin Tech:

+ {{for data.loaded_item.origin_tech}} +
+
* {{:value.name}}:
+
+ {{:value.object_level}} + {{if value.current_level}} + (Current: {{:value.current_level}}) + {{/if}} +
+
+ {{/for}} +

Options:

+ {{:helper.link('Deconstruct Item', 'chain-broken', {'deconstruct': 1})}} + {{:helper.link('Eject Item', 'eject', {'eject_item': 1})}} + {{/if}} + {{else data.menu == 4 || data.menu == 5}} + {{if data.submenu == 0}} +

{{:(data.menu == 4 ? 'Protolathe' : 'Circuit Imprinter')}} Menu:

+ {{else data.submenu == 1}} +

{{:data.category}}:

+ {{else data.submenu == 2}} +

Material Storage:

+ {{else data.submenu == 3}} +

Chemical Storage:

+ {{/if}} + + {{if data.submenu < 2}} +
+ + + {{if data.max_materials}} + + {{/if}} + + + + {{if data.max_chemicals}} + + {{/if}} + +
Material Amount:{{:data.total_materials}} / {{:data.max_materials}}
Chemical Amount:{{:data.total_chemicals}} / {{:data.max_chemicals}}
+ {{/if}} + + {{if data.submenu == 0}} +
+ + + + +
+ +
+ + {{for data.categories}} + {{if (index & 1) == 0 && index != 0}} + + {{/if}} + + {{/for}} +
{{:helper.link(value, 'arrow-right', {'category': value})}}
+ {{else data.submenu == 1}} + + {{for data.matching_designs}} + + + + + + + {{/for}} +
{{:helper.link(value.name, 'print', data.menu == 4 ? {'build': value.id, 'amount': 1} : {'imprint': value.id}, value.can_build ? null : 'disabled')}}{{if value.can_build >= 5}} + {{:helper.link('x5', null, data.menu == 4 ? {'build': value.id, 'amount': 5} : {'imprint': value.id})}} + {{/if}}{{if value.can_build >= 10}} + {{:helper.link('x10', null, data.menu == 4 ? {'build': value.id, 'amount': 10} : {'imprint': value.id})}} + {{/if}} + {{for value.materials : material : i}} + | + {{if material.is_red}} + + {{/if}} + {{:material.amount}} {{:material.name}} + {{if material.is_red}} + + {{/if}} + {{/for}} +
+ {{else data.submenu == 2}} + {{for data.loaded_materials}} +
+
* {{:value.amount}} of {{:value.name}}
({{:Math.round((value.amount / 2000) * 10) / 10}} sheets)
+ {{if value.amount >= 2000}} + {{if data.menu == 4}} + {{:helper.link('1x', 'eject', {'lathe_ejectsheet': value.id, 'lathe_ejectsheet_amt': 1})}} + {{:helper.link('C', 'eject', {'lathe_ejectsheet': value.id, 'lathe_ejectsheet_amt': 'custom'})}} + {{if value.amount >= 2000*5}} + {{:helper.link('5x', 'eject', {'lathe_ejectsheet': value.id, 'lathe_ejectsheet_amt': 5})}} + {{/if}} + {{:helper.link('All', 'eject', {'lathe_ejectsheet': value.id, 'lathe_ejectsheet_amt': 50})}} + {{else}} + {{:helper.link('1x', 'eject', {'imprinter_ejectsheet': value.id, 'imprinter_ejectsheet_amt': 1})}} + {{:helper.link('C', 'eject', {'imprinter_ejectsheet': value.id, 'imprinter_ejectsheet_amt': 'custom'})}} + {{if value.amount >= 2000*5}} + {{:helper.link('5x', 'eject', {'imprinter_ejectsheet': value.id, 'imprinter_ejectsheet_amt': 5})}} + {{/if}} + {{:helper.link('All', 'eject', {'imprinter_ejectsheet': value.id, 'imprinter_ejectsheet_amt': 50})}} + {{/if}} + {{/if}} +
+ {{/for}} + {{else data.submenu == 3}} +
+ + {{:helper.link('Purge All', 'trash', data.menu == 4 ? {'disposeallP': 1} : {'disposeallI' : 1})}} +
+ {{for data.loaded_chemicals}} +
+
* {{:value.volume}} of {{:value.name}}
+ {{:helper.link('Purge', 'trash', data.menu == 4 ? {'disposeP': value.id} : {'disposeI': value.id})}} +
+ {{/for}} + {{/if}} + {{else data.menu == 6}} + {{if data.submenu == 0}} +

Settings:

+
{{:helper.link('Sync Database with Network', 'refresh', {'sync': 1}, data.sync ? null : 'disabled')}}
+
{{:helper.link('Connect to Research Network', 'plug', {'togglesync': 1}, data.sync ? 'selected' : null)}}
+
{{:helper.link('Disconnect from Research Network', 'chain-broken', {'togglesync': 1}, data.sync ? null : 'selected')}}
+
{{:helper.link('Device Linkage Menu', 'chain', {'menu': 6, 'submenu': 1})}}
+ {{if data.admin}} +
{{:helper.link('[ADMIN] Maximize Research Levels', 'exclamation', {'maxresearch': 1})}}
+ {{/if}} +
{{:helper.link('Reset Database', 'trash-o', {'reset': 1})}}
+ {{else data.submenu == 1}} +

Device Linkage Menu:

+
{{:helper.link('Re-sync with Nearby Devices', 'chain', {'find_device': 1})}}
+

Linked Devices:

+
+ {{if data.linked_destroy}} +
* Destructive Analyzer
+ {{:helper.link('Unlink', 'chain-broken', {'disconnect': 'destroy'})}} + {{else}} +
* No Destructive Analyzer Linked
+ {{/if}} +
+
+ {{if data.linked_lathe}} +
* Protolathe
+ {{:helper.link('Unlink', 'chain-broken', {'disconnect': 'lathe'})}} + {{else}} +
* No Protolathe Linked
+ {{/if}} +
+
+ {{if data.linked_imprinter}} +
* Circuit Imprinter
+ {{:helper.link('Unlink', 'chain-broken', {'disconnect': 'imprinter'})}} + {{else}} +
* No Circuit Imprinter Linked
+ {{/if}} +
+ {{/if}} + {{/if}} +
\ No newline at end of file From 18a49a481700688abec1652c802dea9ae029e860 Mon Sep 17 00:00:00 2001 From: monster860 Date: Wed, 8 Jun 2016 21:22:24 -0400 Subject: [PATCH 019/129] Adds a bit of width to the console --- code/modules/research/rdconsole.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index c5f27ba30a2..6a0e3fc9f4d 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -867,7 +867,7 @@ proc/CallMaterialName(ID) ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open) if (!ui) - ui = new(user, src, ui_key, "r_n_d.tmpl", src.name, 700, 550) + ui = new(user, src, ui_key, "r_n_d.tmpl", src.name, 800, 550) ui.set_initial_data(data) ui.open() From c814156ca882d6d6120d5a09aa2299d464459c00 Mon Sep 17 00:00:00 2001 From: monster860 Date: Fri, 10 Jun 2016 16:22:26 -0400 Subject: [PATCH 020/129] Makes stock parts build 5x faster --- code/modules/research/rdconsole.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 9e8b29f94c1..41240dd623d 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -431,6 +431,10 @@ proc/CallMaterialName(ID) var/P = being_built.build_path //lets save these values before the spawn() just in case. Nobody likes runtimes. var/O = being_built.locked + + if(ispath(P, /obj/item/weapon/stock_parts)) + coeff *= 5 + spawn(32*amount/coeff) if(g2g) //And if we only fail the material requirements, we still spend time and power for(var/i = 0, i Date: Sun, 12 Jun 2016 02:28:25 -0400 Subject: [PATCH 021/129] Fixes Zeng-Hu Leg Sprite (#4634) * Fixes Zeng-Hu Leg Sprite You can no longer see the left leg through clothes while facing northward. * Bishop Cybernetics feet are now the right length Chopped off a pixel on the toes of the Bishop feet. They should now fit into shoes. --- .../cyberlimbs/bishop/bishop_main.dmi | Bin 4617 -> 4591 bytes .../cyberlimbs/zenghu/zenghu_main.dmi | Bin 1431 -> 1428 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi b/icons/mob/human_races/cyberlimbs/bishop/bishop_main.dmi index 3bf83ae98cdbbd0e831099ab3889796c85783601..819b01edafe6b13676619d8a5c5baf8f3131f5c2 100644 GIT binary patch delta 4207 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 From ab1f40481d41e640606c178b41d1c40f47cc064f Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 12 Jun 2016 02:28:27 -0400 Subject: [PATCH 022/129] Automatic changelog generation for PR #4634 --- html/changelogs/AutoChangeLog-pr-4634.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4634.yml diff --git a/html/changelogs/AutoChangeLog-pr-4634.yml b/html/changelogs/AutoChangeLog-pr-4634.yml new file mode 100644 index 00000000000..99a67345dde --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4634.yml @@ -0,0 +1,5 @@ +author: Glorken +delete-after: True +changes: + - bugfix: "Shifts Zeng-Hu left leg over in order to regain thigh gap." + - bugfix: "Chops off a pixel on Bishop feet so that they fit into shoes." From 4e31600491d63591bc20cc58342c4932ddd2eb97 Mon Sep 17 00:00:00 2001 From: Tom Heeren Date: Sun, 12 Jun 2016 01:30:49 -0500 Subject: [PATCH 023/129] Gives synthetics a more irritated buzz noise. (#4561) * Adds the ability to make the sad trombone noise for synthetics. Also moves the sound file itself into the sound/machines folder. * No wait I can't do that Moves the sadtrombone noise back to where it came from. * Changes the sad trombone to buzz-two Do I win a prize --- code/modules/mob/living/carbon/human/emote.dm | 9 +++++++-- code/modules/mob/living/silicon/emote.dm | 10 ++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/code/modules/mob/living/carbon/human/emote.dm b/code/modules/mob/living/carbon/human/emote.dm index b1d7e356b39..a57764ed47a 100644 --- a/code/modules/mob/living/carbon/human/emote.dm +++ b/code/modules/mob/living/carbon/human/emote.dm @@ -28,8 +28,8 @@ act = lowertext(act) switch(act) //Cooldown-inducing emotes - if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no") - if (species.name == "Machine") //Only Machines can beep, ping, and buzz + if("ping", "pings", "buzz", "buzzes", "beep", "beeps", "yes", "no", "buzz2") + if (species.name == "Machine") //Only Machines can beep, ping, and buzz, yes, no, and make a silly sad trombone noise. on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm else //Everyone else fails, skip the emote attempt return @@ -86,6 +86,11 @@ playsound(src.loc, 'sound/machines/ping.ogg', 50, 0) m_type = 2 + if("buzz2") + message = "[src] emits an irritated buzzing sound." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + m_type = 2 + if("buzz", "buzzes") var/M = null if(param) diff --git a/code/modules/mob/living/silicon/emote.dm b/code/modules/mob/living/silicon/emote.dm index c70979c5947..233df91eb55 100644 --- a/code/modules/mob/living/silicon/emote.dm +++ b/code/modules/mob/living/silicon/emote.dm @@ -13,7 +13,7 @@ //Cooldown-inducing emotes if("scream", "screams") on_CD = handle_emote_CD(50) //longer cooldown - if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no") + if("ping","pings","buzz","buzzs","buzzes","beep","beeps","yes","no", "buzz2") //halt is exempt because it's used to stop criminal scum //WHOEVER THOUGHT THAT WAS A GOOD IDEA IS GOING TO GET SHOT. on_CD = handle_emote_CD() //proc located in code\modules\mob\emote.dm //Everything else, including typos of the above emotes @@ -115,7 +115,13 @@ playsound(src.loc, 'sound/goonstation/voice/robot_scream.ogg', 80, 0) m_type = 2 + if("buzz2") + message = "[src] emits an irritated buzzing sound." + playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0) + m_type = 2 + + if("help") - to_chat(src, "yes, no, beep, ping, buzz") + to_chat(src, "yes, no, beep, ping, buzz, scream, buzz2") ..(act, m_type, message) \ No newline at end of file From 3b40bdf2b83c5230f0b47ccd8685443a2c4d7177 Mon Sep 17 00:00:00 2001 From: ParadiseSS13-Bot Date: Sun, 12 Jun 2016 02:30:51 -0400 Subject: [PATCH 024/129] Automatic changelog generation for PR #4561 --- html/changelogs/AutoChangeLog-pr-4561.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-4561.yml diff --git a/html/changelogs/AutoChangeLog-pr-4561.yml b/html/changelogs/AutoChangeLog-pr-4561.yml new file mode 100644 index 00000000000..f8ba2896b74 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-4561.yml @@ -0,0 +1,4 @@ +author: Spacemanspark +delete-after: True +changes: + - rscadd: "Adds the ability to make a more irritated buzz noise at people as a synthetic. The original buzz is still there." From 1b0426125943a1c4d34ce6a8ee2395c4b3cfd673 Mon Sep 17 00:00:00 2001 From: Fox-McCloud Date: Sun, 12 Jun 2016 03:28:01 -0400 Subject: [PATCH 025/129] Adds in Ability to make Latex Gloves Balloons --- code/game/objects/items/latexballoon.dm | 35 ++++++++++++------ .../game/objects/items/weapons/tanks/tanks.dm | 4 -- code/modules/crafting/recipes.dm | 7 ++++ icons/mob/inhands/clothing_lefthand.dmi | Bin 74670 -> 74788 bytes 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/code/game/objects/items/latexballoon.dm b/code/game/objects/items/latexballoon.dm index 9b02799e496..575680f28ac 100644 --- a/code/game/objects/items/latexballoon.dm +++ b/code/game/objects/items/latexballoon.dm @@ -1,38 +1,45 @@ /obj/item/latexballon - name = "Latex glove" + name = "latex glove" desc = "" //todo icon_state = "latexballon" item_state = "lgloves" force = 0 throwforce = 0 - w_class = 1.0 + w_class = 1 throw_speed = 1 - throw_range = 15 + throw_range = 7 var/state var/datum/gas_mixture/air_contents = null -/obj/item/latexballon/proc/blow(obj/item/weapon/tank/tank) - if (icon_state == "latexballon_bursted") +/obj/item/latexballon/proc/blow(obj/item/weapon/tank/tank, mob/user) + if(icon_state == "latexballon_bursted") return - src.air_contents = tank.remove_air_volume(3) icon_state = "latexballon_blow" item_state = "latexballon" + user.update_inv_r_hand() + user.update_inv_l_hand() + to_chat(user, "You blow up [src] with [tank].") + air_contents = tank.remove_air_volume(3) /obj/item/latexballon/proc/burst() - if (!air_contents) + if(!air_contents || icon_state != "latexballon_blow") return playsound(src, 'sound/weapons/Gunshot.ogg', 100, 1) icon_state = "latexballon_bursted" item_state = "lgloves" + if(isliving(loc)) + var/mob/living/user = loc + user.update_inv_r_hand() + user.update_inv_l_hand() loc.assume_air(air_contents) /obj/item/latexballon/ex_act(severity) burst() switch(severity) - if (1) + if(1) qdel(src) - if (2) - if (prob(50)) + if(2) + if(prob(50)) qdel(src) /obj/item/latexballon/bullet_act() @@ -43,6 +50,10 @@ burst() return -/obj/item/latexballon/attackby(obj/item/W as obj, mob/user as mob, params) - if (can_puncture(W)) +/obj/item/latexballon/attackby(obj/item/W, mob/user, params) + if(istype(W, /obj/item/weapon/tank)) + var/obj/item/weapon/tank/T = W + blow(T, user) + return + if(is_sharp(W) || is_hot(W) || can_puncture(W)) burst() \ No newline at end of file diff --git a/code/game/objects/items/weapons/tanks/tanks.dm b/code/game/objects/items/weapons/tanks/tanks.dm index 46342d78a99..b86ccbff3cf 100644 --- a/code/game/objects/items/weapons/tanks/tanks.dm +++ b/code/game/objects/items/weapons/tanks/tanks.dm @@ -89,10 +89,6 @@ if ((istype(W, /obj/item/device/analyzer)) && get_dist(user, src) <= 1) atmosanalyzer_scan(air_contents, user) - else if (istype(W,/obj/item/latexballon)) - var/obj/item/latexballon/LB = W - LB.blow(src) - if(istype(W, /obj/item/device/assembly_holder)) bomb_assemble(W,user) diff --git a/code/modules/crafting/recipes.dm b/code/modules/crafting/recipes.dm index bbdb526c70a..d8586b6c0d8 100644 --- a/code/modules/crafting/recipes.dm +++ b/code/modules/crafting/recipes.dm @@ -219,3 +219,10 @@ /obj/item/stack/sheet/wood = 5) tools = list(/obj/item/weapon/weldingtool, /obj/item/weapon/screwdriver) + +/datum/table_recipe/glove_balloon + name = "Latex Glove Balloon" + result = /obj/item/latexballon + time = 15 + reqs = list(/obj/item/clothing/gloves/color/latex = 1, + /obj/item/stack/cable_coil = 5) \ No newline at end of file diff --git a/icons/mob/inhands/clothing_lefthand.dmi b/icons/mob/inhands/clothing_lefthand.dmi index 27acdc6a1562e85a9e061f1e8919d5084afbf776..763e2f0710c4b7c636dffbbf958f4ce83f40fdf7 100644 GIT binary patch delta 16063 zcmch-2UHY6*ETo^Vj>6vl941JL6MvhBc#(pecnO$bC?qljN%YHi{4JRKK%xMc# zq~7ix0U|SRT{64KM&ct~&(7)rYQPO2PE&8m@l3!SwRe5?95%>Sci{lPI&g13U>llV z2fnGVI>7xu6S^XSZwtCCbGyx`T?=L+y=H$;PpOlTucMjJ9{HAr31Mu|xrksrP4#YQ0-Q&o*U!@An2prl>MWim0Ntn#4=PgF;Fq9zj_LHpTnY>2Rhf z@k4@ampRg4B4G^%b9bH)ZUp8rC1#&P>boy;3~Lc2%{BJPrNTo zL@B_+#9RjqGZO`yowC&a`olG4Hpk>EB%Kj|bj}J8{+7NiDBh1b_?Y90_DR=1arT@* zZPjfn77RbhaNU^jmCBc!d)U3&IJaAlTJAqtunfwpBxLMMCprHq>7l5il1Bx7tukiZ zHa?MEHKs`f%jaqkWix~cI~5OEauD6h^>R?D_r}u&jAPTB&7Q;%v9Qxiqc&IcKkpXt z-5X$NC50>JIe*N^LIw+JUjzkJYWS%1)tPDe3{P&!;aR;?a-I#+uZ}=GPX|duuMi$)a~&-Tdzz;uD!RJ!+~Wwz(jfh5lg9*cap)|6b$;1#({ac)o1Ck~>wA;8Q;hyBX# z@|s4PkV(?F9gn^Fh~K~8xOuoQy*6j8vxkK~N=ez+*^+Q_dU11aWMm|uOCuPD&CSFl zv$C=hK3ii6Gm(vjQ_Swn)<}7I@w>RVX#U~@?|uji>!=m2u^c9G*_|M7=9A}rZAmg2 z#TB)6Wjb`CT3e-mdHe@>`2{=1d9F}~Lmt}OcVI{*;=}!0=N$a-)2RxBJCHPfXF8JS z#yF6M%fnw?oe__2L&^>6l~c)CW*_=rw%c~~pqqK$tT#Td2eO&e$=hDZ%{mv^`>bkQ z5As2p&`Yu3u!k6j5S^yKXtv zaQ`TAM~Rfmdi7+Rc;Sdg;k=Gm@8hU?)_Z`UL5k*Si}4VcU%=(#yP_V3HN>jlJ$iS_ z^=hhIR^`hL8wuGfDwr3WAA`lIeT~JSgp`z2`*KO10cLtq5`AJ~VtjJ)hd+OuZu$>4 zS657X@hSztO8(}sAV@$>jVA!`kiY7==ry|^)n!b>)3XSQ@Rmj(g;gO#j2 zT`KSmuPigsd1SAme!kxQEPXKE@ypFtBE>ktwG|#qCDeJmIo|lw^9LwA0&?=mm6dmf z0mxN40RghSyu6tv_c9J7^M52aVc_rs7Z7W_Zzs{L5WuBkcfIZ`OyqXEA4rakLwiguY0=3ONcIkLaf^GV(w7FpL)KHR0sV3A9_xnZg)A1OhG;$z%i zFo_);nGAkzJcY=AEY>Ac`zx!?n|wciZuNYlOC_rg<8j7_c;P=FPUvI;;yj+BFLZ8A zEekC~lvcUnbiB|ssgXPqP6nkP!Nk#i>4E`?di=Z_?81`0a7`m> zuesp%1Crc^hMC>#ba+Uj^QksPs_K}fiQFO{E6SRMwA*K*y+AqHEl}Z%TB`Scjbd)(oXGs z?;bUu6gVkN%Y=ka;5xA>4GvUbbt2$yfK-GJ>rzdXlQ02MNP9u-j|!bj5+TdsN1m-t znwRYE08aMZ$e)&PmqdG-w?pzx*LS>^r&t3Xm>@pIjGbt|SI1R%bT+j1@6u^)F|7{2 z6CZQur6>mEax>fK=5M!nSCO!;&}b1Gg8$C%{hj!VKJS{tBIk+e%vaLV*oy$#f8OsG zJ0vi}vGMkPJ6iPR%a^JquGoRQ&+6N{H6-Hzpp=Z;>fzS*HmAcp|0K4~Sd;s9XM;0B z)x;$3RWSA|2f|5pJ-vu8Ul=sCw3hZv7O*t6Xjxd~PMm#BZNt-@Cr8|J@12*P{0Rx& z2=C#nYCd-iaAmi-CL%k_)MF#I(aDl)qoSxa?Oj)wWDT zED#6Npw#H^m6nd!g~9!e98l7?obnRTSylEKtQcev`IldV5+$@W^c$Ss)?@PlY-~7| zHp6sBV%M1K1_m#%g>yOL2DnCz$D!`wY62bEcH*Ss0UGbt>*t_+q zlQAISLflk$DzCZP1YJoXs=?$ywAit2ashOVJMICi%dJ3IcU40JX;)Vl2x$2puKd+s zsZlv$bBphKm5MHTs{Lp_K1ZvU>sCwDTrf{Q1+Y~yo(wP9j)y?sxo(iEx@-{= z-QoG2RS(C8WC|OF*%xuV>gLQ{wz+btp%%UinVH5`JiJVQRNBQUls^G%D$3k(Ks6Dd zr5OXP9KJKcwN00&W4y}pF|Dz~EqO!B;{K{YIS1b^du+tOSN(#MkK0&~ORQPu?!-*A2Z+Rx(@k%J=qJ2czuGu%z7mEm8`t{ z&u{|z9dut9dW&{%#BCxM+ayaM8mf<I1*|Ve-qBZ5(*8Y9&X;Ir8+_JOGjT{t=k1MBD z6YXKz%;pHD-tPIt?W(qwCI?(~6KBH{qMm3Ay^1lmGOhlh-a7Y1vhQIu0pX2R{)4@B z_P@YOaP8g9`}gmEIY0O6?CHs`uDu<62VWYHm%rct>zDIAhUC;#dPc^-7tL%REF%!U zMio1(*=23Z-amJx!YT31Q*=aQ+HT$dZhhNrzQMWF=tFO7sd+{YXlkDPY_pxIF% z&dXW{Y0pu8crAYA1c2CV5O~_O@^&J$ci@@BaLVUOxgUI^EWNU=x74P;Z0K)?L_JnO ziC)|VWvo{F24hH5C*S7BErX=vQ5oF^uWFe_7UG_rX!W9McP7r=)yH4JG9mrtty#+^ z)w%h=9WEnTC9nk48us`>lt1Ni` z{#HqDuDHCM+$%jjvX@+3qmz>%A3u_~xx3SHaXm6OHmZSUzRdE|1@9M+eZN)u~^+fd~o-jn2+m!=diV#P#d)YB}o>l0A^um}>Mvk!7=f zrJI9gu8c@01Cb#BeN))zilB~!f#>uK`_Q|+kSJ#zCQeO@7o6I z?`5N@w+3^WBt3QYjfp2$b|b?rw(;|wv>Azs z55j)`ochoX`b`|~W@Uj%p3IIG?;}-B%@3!i9uRR~U!h1KGV+DvqHs&&c=LmIO;JUm z4!9d2S@{Ce>Zp5qkg;JM7G77Do9#)|JZ2-d;*qm-KzGB;-6mws`DdUtx~cU zHdtsGtqK$+IJUC8i&km+xg9UdyvP#pB;ofY;lrVRp8)vwl~Ja|TJlOmK_i%GOIdJq zEW(3n^~5e^nDy+?M101c zzF=TvwC442jGlVfI}}6dwh}fV7^NO zkc`v$;g4KREy&EIbYAYfrzAE$rsEQv2~u`myO}2?{& zXW2vH2H-XT>wbIZ?>QP!n#EEgFr>9RSNBp}b%q_l;)uN@Q7Ua9vC&~70nz9E>&seMNVZ52e<*zMu9={I` zt_JUY2o2rJdU`t^MPtB7?SGo$5EceU&pgW+lJxLwm&x&$Iwv2tORn?;{IBDsaCF~p z@}92ayTjM4g@I{%Ol{o{(1QW#O`k_BeWulSqY8jwDMr(@PinULD=h~CzjKl^0mkLx zf_5a*2vZ*%tX_@9+tvOQ-9{HieSHJ97SHEku?qu3l90&A`$mUlg5K)Kr!`Z~0|U%F zP3USZI-eP*&d#SlYFQ$wdFQtaWn4^wQ-T|D2L!a`*_c)9zP7M<3Yu@!)tX_S?w72~OFvF~ zV2)dA4IV!1{E0Abe4ktuqFZBuD=#mvs;>Ti7@z7E#4lhY-XE6EW9!yewzVS1={&|z z4{MD878kzN zdQYoq@oIGjhn8W?8m`2IX3U;FafGG=bOMW9&DSv*%GbY;qO=KjkDqF8`mkEhQF-R( zQVo$f6}fr%UnKDf&ReFK976dXa)ZGgQ|*liT z_NUODiJ>*7r_msH-G!qrgueIwLzW}?NXUc79vRV9RWCA2M4|@J=lGe9_CH2|8Cr*Z z9aYubzDF-X!GICihLtse<<`~Jos8mVTMFpFQzU&-CeieXao zJv1{E6uu`ZdAfYvBT7Qn2RD6#QaQNllgFXVp74yPUT#%w&`#DgjE!D#9G%@T5Ux=J zQTTFQfXMP)?w2oEWHf+S2!-hRgKU@?L6nMpkBr7o)x)HogoFf)XpRGx?A2_p<;D-q zZv<+oXq5U6ME|N`3O}#xjS%Na1s3;CrcEpnn;1RV3mN)ldF@I?a|Z)I!`)}ovVy*u zK;zRR?Epf9YSY{D=rverOJeoFRzj^ULDENTh^e{7(=9+=;b7piRMXm*m7}p6HB@gz zDq%h=1F`ozT=phVupG|rDpt!^)xPFYmx+<~_7>2F8pmM#_`$DZ5|^9%M9IZPnDV%0 zSQHbYIX&^_jTgTtYKIGqaLqsk^{*TNso+4gZhm(x2Sj}OY;q&InP9X-aAej`ps7>^ z0~qVN@&PSS{-n%Z80tOx6KUxBeqT=m&-WvhRRr+tXFM~<-ZX3W?75l0uzmQkaVr<* zRQz%L>9${At(+pN))BOoW}ha3!JIfTyZMb{S6$igSh9rr%R&rxX6E=6tr0HEp(m?j zOQgbHFa8_ThWr_vtpUR0;_BflWt1kqCtCcJqEVaUMMCyxPlrGSvPB169B&pE7yl8A z{lubWTkx%(JCEL(TUiGP!!E%sl42G#<&gB9EDF5|)Jle53YlNUcao1A3++9)ke&hV(W4DCG zA$qK<2os|Z#USN<1`a?S%zSBUhYk!Vf_yixpy0NVkx}o!z-y2SgSU3-C!f`WNw#-} zo>YlRN!1`XyP1TZSSrXH_?{9aMA?}VaYwMgrXo2sJ?SnPX++I>n{>=w$>XY}VuH8) zzQCUC2b}2R3%}O|AfFlCa;?IX4ToGKpZ>|0OljclK0V2CoU5ZLALq-StrC6xI*4_5 z8maDs5=Fi3D*z0hjls^UtQv;c%_t9EjCEQA>{dHCq>6P zJISnr9@^b!VsvIp0D@LC|8e$t1^0eLdwAuABLtE)nZxhDTZ+a$%07?sT8e=CBqxEq zw%h6?!oVV>R7bCq)Jo#y!ebooX z*qvZ5$ax2t;ndX8K|q14GB>#YSwuqve>9~4A(zF#_uoH)c>s060O4NOVUe(|sK>u( z9xQ8Vd;#+{T>3E}%^-GOYyRp03p4&0DaP?>)m;<}zv zU()BMLTs^%(YP7hW|gc1OBHT7TSxmlSFOoS{Cd-E{;}*mY1_tzw1kMFtao_M<&NLquBMn zzW&GL>PHWkF3)0*XlD4)L4#ID=#{9r@O3f2CfJNh+j+POvY{D%L?g=X7jxqZo7>k` z21xKZd~;zlt}Yg+n|Fyc>|iX}3IjE2rHh4NPU~qeNd1uQ*5idIvy=jh%Gbl3)B>(L zG%8!=-@uL#5EF-NY*;m1=aUi>ubzlSx(LfCd}JdS9Uc8g;OxKo@uOQ2m#)_W=%8Q! z=~2UqE{;M>u&oABD&@BO4WT=}3{#1ETjKm*tPcSD6IJ|*AUrzaJ=lzg`R6}&_`@7O zyf=+G2Tc4Wp70uBKI0PushsPD8CKXGGNB=u#d;2DJybU>vAMvOA4K$rjz}U;|#hRtqieFBU z(Lch5uga*9CBXYS76vX7-2>S|V{_c3P0GsCZ$+p?t{(l>^>rA<*y2_>b`OA)pP#=A zLm&_s5F;bN$jZ*{m?ay*`+GU#p(8llu@hc>(MNJ_ zk`d`v6RuI+QzA8E(BCm`+xKG=iPr<6qef;W-Ts&{1U8dnWAEqY^gFw|KQ}g#fpHui zH#ZRh0m12RTem^gn;TOntE>FC-kg27w{Y0#j1GWi$5b8|uESwo7Wn|U5;Ee~f=Rre zC4RU;^tzomhN(xGuAAmlVE@^&CImvmBlr51W*tmI?cjt@mO5+MwZ#)Y_Y^OBHts;? zY3^Db-VH{^PWGTvp&k=j6Le2`N%$ut1O#fN6n$~xpX61Z{`8p z1=@y}J<`3fLZDde43}HFSW8Cc4kQ;Gb}%-sgr+7DHZJ*xwKa>PzvKWhx$Xx=_M%Qe z33r#`o1o`j>ie%)8mJ)8Pq%b9{-*2Jg|;9NEvENQd#6^Nj6KWqyQ9T|1faKodRc(p z!p)-=1CpL0^y1BHtk2j|Z@!1$<>vF`-vw^C1+!jGpe{zru)@T0TTnN1t&O9jjGY}D zxF|3>H5CfxNE?hz0y9L{>onxC%cGYw1MxLLJr*K0#o?5kn|IFRBWR`*eV0{;^4 zZAnZqs}0X<;TleTf5ADyhdeuk6JXM%wSvq(FZBuc1tE9NpWV2(H&(u2tAkiIWS_z+ zTD7dZTl&L?54m-9BocSQe!aRI1cC^>;&oLhyZLwUPS>^O-!A^=qo&RTou3owmKabb zf%t9~t`I8)7RBiD`%A$cEuu7P{~qL?;-ly1CXL}a*+|xZ$isXqOZ@@4?Up^PRoFxW zY?A-ZUvWB6ze3v@Gz+H>mKv_hr$8vH*$@*FzE{fNm7}Gl4UdVDl90GXPC=0nA0Id~ zqYKVy=Z&8VJA$(31OJNu9A%<6I?-82(G1dVblz_F#~hW!-KE%X3J{zB^&AuPC1Fd$ zk~s@lc6N5tT}P7M^b;(=Gr`?y`Wuo=(`Qp#n!%aSPwn*^V{~Eyln0iZn_F&mHG!I% z+Fd-n?h=inhh${;B2Koaedmc-sZyWZ!5{&0i1$Sp^xHN%wGchaelk?0tTqIxlu>_v zllr;;R=}a;gZy&5aEv=r``gpDVZK{@*gOfVT$lj{lu`Vl>lqhnmbo_4Ay{-pH z;DG(_j*3J1vIo>d3E>(?E3pLfb1Z!Yk*A3Zg`|9FPS1P0J+Lv^RNz4lI7 zrvj%YCov!aXU%W{+~td!BA-b5xJMhwmH$V#Y+`JT2brm}&lo?i1jKwxi}(-ugOoRY z&UEbU*&!z;=zpiEes`(8eb%EL#D03axK}gXS${H%>72XRkNJ{%`heL><9)>QGC%ne zHnB+B<}<{|A1g|7YFr3uPU3s_M&Mx?wLTr>H+VI()%jNF&SG5uVSdxf<_u9YYBs?X z*Gf?l$HfJ3nQtRCtUr@#Yu%1w0rw|#c6J`~X=$i_U9?#>tM*%fB2)MG8?ufZ^WU{j z_Jgy2a^A6xwv8$(={9>*#D9q@qV5|UnX9#J?U!k5HREEG zBb=%C zmA#BHO@y(WG@p_fslh)bg~2E4GCv>GY5{@rx<56vWX~gm@z>E86Jzo`YvY&GDYlKA zd)870U>-3Nr{&F$Tj2JA*s-xO2NZZ10hJAxg7?_l)J|DBHat3dhjR#dv|bH>+YH+I ze`qVoPr|H_PS+wGNPN3Y^mmJINZ=Z|E(IFg>xEN?djCg~j@@7sR&6!L8+H4;G5gE+4Y!@kjS+5M)I9^>j1e|9H93`TVoArfe}=U| z@hN2(uze{Nz$JphcdaNyYO3@TQ}1ks9JF^!A-Ni6mJa+Q+i+64<-${Abempv+TpHn zj5T)bAPmS`8s+~`O)B<;+%i3#lUwk92xmuN@?QPqn6J5vv)(%5?$wnw<-9BDw6d~{ z!NKssVhY;H*SAY7bQQJVeh2ccu8xk4P4Ns|ocJc_eB)C7+i@4QVFnT3eT*AU^|->9 zvW81POF6)m95Q0)OHEL{)CBZ!3bk$@Uz`o5-Ts}PgxkAU-hGJuJMyhFf51huy_Cb5 zGivvOVtiru*6bO4>bLKN;r#EaWenPi&|Y4}Mgg7Xpx_#4(=R5rPI#;xZ+yWnJd z#H9S%)|M5_h9!LbXn_t`?u=;a1Q%8(`#5tdD}{(Yp|Ag*MnHiZE2jgx-cuZvpxDw&_Jn)Y%kfVl!;?;kS@v&S5aUqBs9H#{k_2Vx$4rP(S^ z{h|iwNC;lA8VU(ef#P@GU2&6@0Ybj0=`^*rnyv@lszaP5B_^us=!Ai^2jm-1o<7A+ zNl7uLimTN8D@<@-(`)yWT`PN$h_yAf@Ni}sT`;NJ)w+3d$w~mOwrMl9{hgCla8nel ztjzgqEwSF<;0zH#(9+wtUR)f&&^A(sE_PO6%39NvtKYqH95fwWVEQP|tS2_Fun-&E z$I{W8K(A(KxHE|im%mw_p6oj~8wHgY)bGW8IQlBW%tN|#yoS}K3!EW0Sit6LMRn&h(ks#_R0Ig}#88dnG&rEnQIiZ{28dKsnbUkoT!?TJ#abW5HwaMxv()`rV$3_%`m_y=UU>k%u-_$sTf^$q1 zBlozG_mi}hAl1o~o1pqJ-MPr9Z_V z|8ngU2Mx{6#@yS2PMtG7ow#`*lD+m6ns&eb=((5-rDNIZ<+eau>LCFJ1zjYv zh3i6*#3S%yb)4%Iw0n1}r-8knZwxvLg0?HFNnP6r#wd1~ugxm#&G3)#XBH_H9KV?j zAf-_>Y!iiN=QiW6*CJ$Mz|nR_=X}VI)9D;PgNhB2wz=bMfR2uSnYQ8SnW+KS+6QTV z`=pE~U}j>djJKvNl;tLujUC{oDp$L6L*L2#Xth) zF&ghdAlAmsyU$OTw$?0jfUIsEgM-#uapD(eS#RvJ=P)j3>iqYBpKn@b3a?#n1RB3q zYo=_4wZ`$y9%eYQ=G7jt-`P4Qvh$+ zubUJdOnw6wFz<=Ad2Q4P-^p0_fT*GcZq_udJ0EqtV0nrGUYhC2YJM>z+LjsIqSUqk zVk_E9;;O^sgxW+&It|^{o$6X8#>X+g=3@)6{V_Wk)&o(-vnhfm(*3MaQ}8@4`Lo+F zd6&*~yRdqxo2-W1{bz)@<{=U>a~Wh5s&q+7!xic%QTZ`nKgM?sHB=UsV#mafDcISG z;RaES8Nv3f(f;v{I)0A!IrUn>phn2;BhNhidi)RlS4j0oKtSJo%IoG+-+(@R)@zxJ z(s3o(`_B$x)1T*_HNPy_n6N837O!0_IVYxmPw|Aeo>$o346!HvRty(9-WxQqkUlM{BYaxsOfl0i0!xq z^}vfQlXLB$3lfsFciejy0olWG?=L%F)Zg8Lo}E74 z2)r= zz@Tdb*SB?l!7%`QyCK?!E%Ggj{`*=4M2Pf?Y`B)&Z%zcK%ZsYZIIKt~I39OU+O{y;sWm&po zgNk?hlP}H9RpO!;TOHY7nfjI3JPsUFP*+Vj2O9t&3bcF`4Ka9VO|;?1#vvdQ8Of|q z9tB?gl=P2rgzr1OdcwX93Qd0NK;Vz^pRNZI)&gxEu8<6g-56>JYPhoY4tHrgXs5nA z9l?9f4?PwF(A&aoW1tNd%Y2mu z*qrokUjg=YN6!~_|C&h#SD4c08PnzlW$1~HT6MuxfM}KmUYxORNV}86+#1^q{xC<~ z#An&E8)-@T47bZ5m^{$Hm4R?A$&5!5a}!GB1pWC29b>-NeU~ol!$goO^YIo3R;RRnVs>>hXLukhvLCXWQ5#V-X9+FG>Nr@)_l;;k>Pb zfbq2hq&cMisNH;A7^3Qb%~&=$XOGw-{?)mkde*YCIDIWH^IL_-<*IxTw5v3Y6u0E)D7#oX95QjcmE7^ zrOJ|GFaRq$~?9{U(f&6ndM{JqYlwCnP0Ca?{RpCN%-`0NCGbsA^-y|rUC z(jr;UxtO?bJ+I^GNKGKacnmBb&$@L1|@O+gPpREfxG>+ zhoUMJbUj{XJzw$|ISAzR@<#|QFMsiR?ikVPFB2ZPDuiwUO1YHnX8ZS1qy@fH;bWMS zrF`wN!k^Iaffka*0d%U2eBR_`v%UBuPnz#wbdA_@jH9=CgLU2ZQlu z;=!;dnk)bEy0cn(+XemP<}OGo0|{)C&$?~L687}R7O+Xi))}a0!1d7Gxaa#Z z(+ntpm=ul?DQzO$Sz&eTOSo9=-|lS_wuamkX(RCgEi(eMs(sY6ygD<(i?(yKPJgX% z{apXW&|C{4vW+@@AuyG-k_mbONhO(HhW&B11CA94C2!G@ksu<^(;5=L#z$k;6- zaZUR1rt0mBS8UeOU#aN(=%t5Zx(~htKCv zfX|1>@mHbuDe*h@we}w3k+c5T<*!3MH_EpI(+Oo?>iGn}FRO$4=r- zU!vo>PtUt`laSNSeg&jH*T@Tr&=gFR892DJ+J{c$d$*K)ug1hQ;e3(ChjhC zwed*C9#~kk27*S)+G6TKVzwFZHI1OuNRwB^6bEAv1s3}yxpXz<=!^EBiDmTi*)I?!p%)0dd zQfb6_Zlt#F+klj8fIcc{TH{%aL2Jb45m^>0s8czALrcJjYEHz&9a>Zbb5q8iXW zRt^ehe&T%lzi$5c-%Cxr)fB+1li#hFBdzj;}&092sk200J&X0+P!6+EQg;1<&U|Ah}gi3a@WHP6kVYH zUtD4nRf%Mq-9}xmDHS6w*X`%&PW7!h~k9!&L z4t9W6Gl5rh2)Zuz&=`GqR8_RzB#h2(BRS-CNLWEW7g4p(L4P}N?tfZI2;>j68{@tJ z;df#mIEEo3AH(lK-ur7Gsq~4^$9Fun-Z_e!%eJr=mR2(LN7=gN# z&nh|yq)PyeNTY&d=XYT1S$h^*-0SL>0O+1sTv8XqH#FBdSCMx-d^Pcr_zyv$aWaY2bv6T1&)c>zTOP7*H z%HDJ*joZ)r3lU~n*$823F%og`ar?4N;G^02y2Ev?mFTMQO7;98+8!U8cta_`v27e& z{u(wy3X22(Ml{@UP_EH~$Y22jHGb*~U7uX?dXX0SlLO!W zo`cWypgk5{r)|HNlJSr|z3F<)<=T924eqin3)RU+mDMBBg9Ek+q%@nO8E=sXy|}FF zaFP7B>(!??PCz!`NTG^E{z7^}!Hn|JXemZYM&4Iwdv|?GN+e%yDib5E`>_>o-eYDh z$D7Q=h3XFF$PGtvv#I+siS#_oiv#_aI>=DQo{F&vv>^wKeDa@qLmtC%{@QxD--QnW z`9C8s4IHtEdGzq*=x1WC38GQ*D!IUxTN1}$Q8RKF)*$6${p%HUXel{E1;|8;16Oy@ zZjCVH*|ALnXi6mlt}n(fG3!EM%tuf;LcFo@@dCjAoK{`NQw+!Co}Fk`iIF26oqFo> zW72VyqLa!$?3IDovgt|zpRquGQ5{1>N&HvS^NangOW#~DYEo;mRH`4oZx1?yeFFs? zAluUM+jWPWV+;V&EcLmSu$x%e=2Tc#MJ08@CUhct7pnV+jt*V0A&@JL@KR39_CEI^ zAmnjXPakywSE&Pcy&(-~gv5t-8nmSZ+OF3{TUjC1CsT%VLlhG)DUP^)Zs**1kjzg$e;r3J)y>+@retl@ l!+)NPK;ZvsZ}2&KnA-94?qa1K1pLWKDZj?5lz8+0e*j_XOjG~> delta 15964 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 From 47fcc690d2a5938458046f8695059b838c1c4832 Mon Sep 17 00:00:00 2001 From: Tastyfish Date: Sun, 12 Jun 2016 03:36:24 -0400 Subject: [PATCH 026/129] Changelog Generation (#4642) --- html/changelog.html | 105 ++++++++++++++++++++++ html/changelogs/.all_changelog.yml | 97 ++++++++++++++++++++ html/changelogs/AutoChangeLog-pr-4515.yml | 21 ----- html/changelogs/AutoChangeLog-pr-4547.yml | 4 - html/changelogs/AutoChangeLog-pr-4551.yml | 5 -- html/changelogs/AutoChangeLog-pr-4558.yml | 5 -- html/changelogs/AutoChangeLog-pr-4561.yml | 4 - html/changelogs/AutoChangeLog-pr-4562.yml | 4 - html/changelogs/AutoChangeLog-pr-4573.yml | 4 - html/changelogs/AutoChangeLog-pr-4574.yml | 4 - html/changelogs/AutoChangeLog-pr-4576.yml | 4 - html/changelogs/AutoChangeLog-pr-4577.yml | 4 - html/changelogs/AutoChangeLog-pr-4584.yml | 4 - html/changelogs/AutoChangeLog-pr-4586.yml | 4 - html/changelogs/AutoChangeLog-pr-4591.yml | 4 - html/changelogs/AutoChangeLog-pr-4593.yml | 4 - html/changelogs/AutoChangeLog-pr-4595.yml | 5 -- html/changelogs/AutoChangeLog-pr-4597.yml | 4 - html/changelogs/AutoChangeLog-pr-4605.yml | 4 - html/changelogs/AutoChangeLog-pr-4608.yml | 6 -- html/changelogs/AutoChangeLog-pr-4611.yml | 5 -- html/changelogs/AutoChangeLog-pr-4613.yml | 5 -- html/changelogs/AutoChangeLog-pr-4619.yml | 6 -- html/changelogs/AutoChangeLog-pr-4620.yml | 4 - html/changelogs/AutoChangeLog-pr-4621.yml | 4 - html/changelogs/AutoChangeLog-pr-4623.yml | 5 -- html/changelogs/AutoChangeLog-pr-4625.yml | 4 - html/changelogs/AutoChangeLog-pr-4626.yml | 5 -- html/changelogs/AutoChangeLog-pr-4627.yml | 4 - html/changelogs/AutoChangeLog-pr-4628.yml | 4 - html/changelogs/AutoChangeLog-pr-4634.yml | 5 -- html/changelogs/AutoChangeLog-pr-4637.yml | 6 -- 32 files changed, 202 insertions(+), 151 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-4515.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4547.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4551.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4558.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4561.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4562.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4573.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4574.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4576.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4577.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4584.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4586.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4591.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4593.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4595.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4597.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4605.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4608.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4611.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4613.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4619.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4620.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4621.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4623.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4625.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4626.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4627.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4628.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4634.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-4637.yml diff --git a/html/changelog.html b/html/changelog.html index 8265f956302..56ad627eb86 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -55,6 +55,111 @@ -->
+

12 June 2016

+

CrAzYPiLoT updated:

+
    +
  • Fixed the long-lasting bug of handcuffed people keeping their chainsaws.
  • +
+

Crazylemon64 updated:

+
    +
  • No more language message-spam on roundstart
  • +
+

DaveTheHeadcrab updated:

+
    +
  • Adds a new icon for the detective's scanner.
  • +
  • Detectives scanner now has access to DNA and fingerprint records.
  • +
+

Fox McCloud updated:

+
    +
  • Adds three new chaplain weapons: pirate saber, multiverse sword, and possessed/talking sword
  • +
  • Fixes not being able to sheath the claymore in the Crusader Armor
  • +
  • Adds in a mocha drink
  • +
  • Fixes ice being unobtainable for the jobs that use it most
  • +
  • Fixes laser armor losing its reflecting ability
  • +
  • Fixes the lack of progress bars for more stack-based construction
  • +
  • Fixes Experimentor producing coffee machines instead of cups
  • +
  • Can deconvert mindslaves by removing their mindslave implant
  • +
  • Can deconvert Vampire thralls by feeding them holy water
  • +
  • Fixes mindslaves not having a HUD for the master and mindslave
  • +
  • Fixes being able to duplicate just about anything in the Experimentor
  • +
  • Fixes not being able to use tank transfer valves or one tank bombs in the Experimentor.
  • +
  • Fixes infinite-throw spam
  • +
  • Fixes being able to resist out of grabs by moving (that is to say, it'll actually work now)
  • +
  • Fixes passive grabs using the wrong HUD icon
  • +
  • Tabling duration reduced from 5 to 2
  • +
  • Can no longer wield double-bladed energy swords as a hulk
  • +
  • Fixes on map stools having the wrong offsets, making it look like you're not sitting on them
  • +
+

FreeStylaLT updated:

+
    +
  • Added (Enabled) Mind Batterer for Traitors
  • +
  • Fixed uplink implant description (Said 5 when actually gave you 10 TCs)
  • +
+

Glorken updated:

+
    +
  • Shifts Zeng-Hu left leg over in order to regain thigh gap.
  • +
  • Chops off a pixel on Bishop feet so that they fit into shoes.
  • +
+

KasparoVy updated:

+
    +
  • Old placeholder IPC butt sprite replaced with the finished QR-code sprite.
  • +
+

Krausus updated:

+
    +
  • Fixes ghosts failing to follow mobs that move in unusual ways
  • +
  • Fixed tape allowing mobs with sufficient access to move through solid objects.
  • +
+

Many -tg-station Coders, TheDZD updated:

+
    +
  • Old gun code is now gone.
  • +
  • Ports the vast majority of TG's gun code and their guns (any previously unavailable guns, and newly-added guns will remain unavailable to players). Expect some changes that might not be listed here due to the sheer scope of this refactor.
  • +
  • Probably some new bugs.
  • +
  • A lot of old gun bugs.
  • +
  • Mouth suiciding with a gun no longer instantly kills you, you fire the gun at yourself at 5x damage (assuming it even did damage to begin with).
  • +
  • Mouth suicide shooting does not work on harm intent.
  • +
  • You can now bash people with guns while on harm intent instead of shooting them point-blank.
  • +
  • You can now mouth suicide other people, doing so still takes the full 12 seconds to mouth suicide, but has the same 5x damage multiplier.
  • +
  • Vox spike throwers are real guns that fire spike bullets now, instead of just being fake guns that threw spikes. They do 25 damage per hit, have 30 armor piercing, cause a 1 second stun (not the kind that drops you to the floor), and cause some bleeding. They have 2 round burst fire as well, and have 10 shots per clip. A new should should recharge every 20 or so seconds.
  • +
  • Xray lasers now have a maximum range of 15 tiles.
  • +
  • Zoomed guns now actually fire accurately while zoomed.
  • +
  • Using Suicide with guns now actually does gun-like things.
  • +
  • The clown no longer deletes guns if he fucks up with them due to being clumsy.
  • +
  • Emitters no longer become inaccurate over long ranges.
  • +
  • Power gloves now override middle-click and alt-click when worn.
  • +
  • Power gloves give a notification when worn.
  • +
  • Power gloves now have special examine text when examined by an antagonist.
  • +
  • Proto SMGs now only have a 21 shot clip.
  • +
+

Spacemanspark updated:

+
    +
  • Adds the ability to make a more irritated buzz noise at people as a synthetic. The original buzz is still there.
  • +
+

Tauka Usanake updated:

+
    +
  • Adds more belt icon overlays
  • +
+

Twinmold updated:

+
    +
  • Nar'Sie AI Hologram and Error Sprite
  • +
  • Fixes space pod equipment variable. Can now properly install/uninstall equipment.
  • +
  • Check Seat verb no longer pulls out installed equipment.
  • +
  • You can now have a passenger in your pod if you have a passenger seat.
  • +
+

monster860 updated:

+
    +
  • Adds comical implant. It is an implant that causes you to have a comic sans voice. It can be made in the protolathe using bananium.
  • +
  • The comical implant now spawns by default inside IPC clowns
  • +
  • Fixes the window getting stuck when you try to drag or resize a NanoUI window too fast with Fancy NanoUI enabled
  • +
  • Fixes a small quirk with the resize handle.
  • +
  • Fix javascript error in cargo UI
  • +
+

pinatacolada updated:

+
    +
  • removes atmos tech SOP from supply SOP
  • +
  • Fixes defibing people without a heart
  • +
  • Fixes defib saying it didn't work stopping a heart attack when they do
  • +
+

02 June 2016

CrAzYPiLoT updated: