mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-21 19:17:50 +01:00
Merge branch 'master' of https://github.com/ParadiseSS13/Paradise into space_ruins
This commit is contained in:
@@ -0,0 +1,587 @@
|
||||
/*******************************************************************************************************
|
||||
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
|
||||
|
||||
*******************************************************************************************************/
|
||||
#define EMOTE_COOLDOWN 20 //Time in deciseconds that the cooldown lasts
|
||||
#define HEARING_RANGE 7
|
||||
#define INVALID -1 //Using -1 as I can't see how a negative number could be a valid input
|
||||
|
||||
/datum/emote
|
||||
var/name = ""
|
||||
var/desc = ""
|
||||
var/list/commands[0] // list of commands that trigger the emote.
|
||||
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]
|
||||
var/selfStart = 1 // whether the start text is used in what you see
|
||||
|
||||
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 // 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
|
||||
|
||||
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/mustTarget = 0 // 1 if the emote needs a target to work (won't get None as an option)
|
||||
var/targetText = "at" // what goes inbetween user and target
|
||||
var/takesNumber = 0 // 1 if the emote uses a number parameter
|
||||
|
||||
var/emoteSpanClass = "notice"
|
||||
var/userSpanClass = "em"
|
||||
var/baseLevel = 1
|
||||
var/allowParent = 0 // 1 if you want the parent available as well as this one
|
||||
|
||||
|
||||
/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
|
||||
|
||||
if(sound && !cooldown)
|
||||
cooldown = EMOTE_COOLDOWN
|
||||
|
||||
if(targetText)
|
||||
if(!findtextEx(targetText, " ", lentext(targetText)))
|
||||
targetText += " "
|
||||
|
||||
/datum/emote/proc/doEmote(var/mob/user, var/command = "")
|
||||
if(!istype(user))
|
||||
return
|
||||
if(cooldown)
|
||||
if(handle_emote_CD(user))
|
||||
return
|
||||
|
||||
var/message = ""
|
||||
var/list/params[0]
|
||||
|
||||
params = getParams(user)
|
||||
|
||||
for(var/p in params)
|
||||
if(params[p] == INVALID)
|
||||
return
|
||||
|
||||
if(text)
|
||||
message = createMessage(user, params)
|
||||
|
||||
if(message)
|
||||
message = addExtras(user, params, message)
|
||||
. = processMessage(user, params, message)
|
||||
|
||||
if(!doMime(user) && (!muzzleAffected || !isMuzzled(user)))
|
||||
if(playSound(user, params))
|
||||
. = 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
|
||||
/datum/emote/proc/doAction(var/mob/user, var/list/params)
|
||||
return
|
||||
|
||||
/datum/emote/proc/getParams(var/mob/user)
|
||||
var/list/params[0]
|
||||
|
||||
if(takesNumber)
|
||||
user.set_typing_indicator(1)
|
||||
user.hud_typing = 1
|
||||
params["num"] = getNumber(user)
|
||||
user.hud_typing = 0
|
||||
user.set_typing_indicator(0)
|
||||
|
||||
if(canTarget)
|
||||
user.set_typing_indicator(1)
|
||||
user.hud_typing = 1
|
||||
params["target"] = getTarget(user)
|
||||
user.hud_typing = 0
|
||||
user.set_typing_indicator(0)
|
||||
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?", "Enter number") as null|num
|
||||
return number
|
||||
|
||||
/datum/emote/proc/getTarget(var/mob/user)
|
||||
if(user.sdisabilities & BLIND || user.blinded || user.paralysis)
|
||||
return
|
||||
var/list/targets = list()
|
||||
if(!mustTarget)
|
||||
targets += "None"
|
||||
var/target
|
||||
if(targetMob)
|
||||
target = getMobTarget(user, targets)
|
||||
else
|
||||
target = getAtomTarget(user, targets)
|
||||
if(!target)
|
||||
return INVALID
|
||||
if(target == "None")
|
||||
return
|
||||
return target
|
||||
|
||||
/datum/emote/proc/getMobTarget(var/mob/user, var/list/targets)
|
||||
for(var/mob/M in view(getLoc(user)))
|
||||
targets += M
|
||||
var/mob/target = input("Select target", "Target Mob") as null|anything in targets
|
||||
return target
|
||||
|
||||
|
||||
/datum/emote/proc/getAtomTarget(var/mob/user, var/list/targets)
|
||||
for(var/A in oview(getLoc(user)))
|
||||
if(ismob(A) || isobj(A) || isturf(A))
|
||||
targets += A
|
||||
var/atom/target = input("Select target", "Target") as null|anything in targets
|
||||
return target
|
||||
|
||||
// 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(user.stat == UNCONSCIOUS)
|
||||
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)
|
||||
return
|
||||
|
||||
/datum/emote/proc/createMessage(var/mob/user, var/list/params)
|
||||
if(!text)
|
||||
return
|
||||
var/message = ""
|
||||
|
||||
if(doMime(user))
|
||||
message = mimeMessage(user, params)
|
||||
if(message)
|
||||
return message
|
||||
|
||||
if(muzzleAffected && isMuzzled(user))
|
||||
message = muzzleMessage(user, params)
|
||||
return 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")
|
||||
continue
|
||||
return 1
|
||||
|
||||
/datum/emote/proc/addExtras(var/mob/user, var/list/params, var/message = "")
|
||||
if(!message)
|
||||
return
|
||||
if(startText)
|
||||
message = "[startText] [message]"
|
||||
message = addPunc(message)
|
||||
message = "<span class='[emoteSpanClass]'>[message]</span>"
|
||||
return message
|
||||
|
||||
/datum/emote/proc/addPunc(var/message = "")
|
||||
var/regex/endingPunc = new("\[\\.!\\?\"]$")
|
||||
if(!endingPunc.Find(message))
|
||||
message += "."
|
||||
return message
|
||||
|
||||
/datum/emote/proc/standardMessage(var/mob/user, var/list/params)
|
||||
var/message = "<span class='[userSpanClass]'>\The [user]</span> [text]"
|
||||
if("target" in params)
|
||||
message = addTarget(user, params, message)
|
||||
return message
|
||||
|
||||
/datum/emote/proc/mimeMessage(var/mob/user, var/list/params)
|
||||
if(!mimeText)
|
||||
return
|
||||
if(checkForParams(params))
|
||||
return paramMimeMessage(user, params)
|
||||
var/message = "<span class='[userSpanClass]'>\The [user]</span> [mimeText]"
|
||||
if(message && "target" in params)
|
||||
message = addTarget(user, params, message)
|
||||
return message
|
||||
|
||||
/datum/emote/proc/muzzleMessage(var/mob/user, var/list/params)
|
||||
var/message = "<span class='[userSpanClass]'>\The [user]</span> makes a "
|
||||
if(muzzledNoise)
|
||||
message += "[muzzledNoise] "
|
||||
message += "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/list/params)
|
||||
return
|
||||
|
||||
// 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/list/params, var/message = "")
|
||||
if(!canTarget)
|
||||
return message
|
||||
if(!params["target"])
|
||||
return message
|
||||
if(params["target"] == user)
|
||||
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)
|
||||
return message
|
||||
|
||||
message = replacetext(message, text, selfText)
|
||||
message = changeTextMacros(user, message)
|
||||
|
||||
if(mimeSelf)
|
||||
message = replacetext(message, mimeText, mimeSelf)
|
||||
|
||||
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, user)
|
||||
|
||||
return 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
|
||||
|
||||
log_emote("[user.name]/[user.key] : [message]")
|
||||
sendToDead(user, message)
|
||||
for(var/mob/M in getRecipients(getLoc(user, message), visualOrAudible))
|
||||
var/msg = ""
|
||||
|
||||
if(M==user)
|
||||
msg = createSelfMessage(user, params, message)
|
||||
if(msg)
|
||||
outputMessage(M, msg, user)
|
||||
continue
|
||||
|
||||
if(M.stat == UNCONSCIOUS || (M.sleeping && M.stat != DEAD))
|
||||
if(!visualOrAudible == 2)
|
||||
continue
|
||||
msg = "<span class='italics'>... You can almost hear someone talking ...</span>"
|
||||
outputMessage(M, msg, user)
|
||||
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)
|
||||
continue
|
||||
|
||||
msg = createDeafMessage(user, params, message)
|
||||
if(!msg && visualOrAudible == 2)
|
||||
continue
|
||||
if(msg)
|
||||
outputMessage(M, msg, user)
|
||||
continue
|
||||
|
||||
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, user)
|
||||
continue
|
||||
|
||||
if(M.see_invisible < user.invisibility && visualOrAudible == 1)
|
||||
continue
|
||||
|
||||
msg = message
|
||||
outputMessage(M, msg, user)
|
||||
|
||||
if(visualOrAudible == 2)
|
||||
handleListeningObjects(user, message)
|
||||
|
||||
return visualOrAudible
|
||||
|
||||
/datum/emote/proc/outputMessage(var/mob/M, var/msg = "", var/mob/user)
|
||||
msg = replaceMobWithYou(M, msg, user)
|
||||
to_chat(M, msg)
|
||||
|
||||
/datum/emote/proc/getLoc(var/mob/user, var/message = "")
|
||||
var/loc = checkForHolopad(user, message)
|
||||
if(loc)
|
||||
return loc
|
||||
return user
|
||||
|
||||
/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
|
||||
if(message)
|
||||
to_chat(AI, "<span class='game say'>Holopad action relayed, <span class='message'>[message]</span></span>")
|
||||
return T
|
||||
|
||||
/datum/emote/proc/handleListeningObjects(var/mob/user, var/message = "")
|
||||
// based on say code
|
||||
var/omsg = replacetext(message, "<B>[user]</B> ", "")
|
||||
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/location, var/visualOrAudible)
|
||||
if(visualOrAudible == 1)
|
||||
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
|
||||
/datum/emote/proc/createBlindMessage(var/mob/user, var/list/params, var/message)
|
||||
if(audible && selfText)
|
||||
message = "<span class='[userSpanClass]'>You</span> hear someone [selfText]"
|
||||
message = addExtras(message)
|
||||
return message
|
||||
|
||||
// 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/list/params, var/message)
|
||||
message = mimeMessage(user, params)
|
||||
message = addExtras(message)
|
||||
return message
|
||||
|
||||
/datum/emote/proc/sendToDead(var/mob/user, var/message = "", var/ghostEmote)
|
||||
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)
|
||||
if(ghostEmote && ((M.client.prefs.toggles & CHAT_GHOSTSIGHT) || (M in viewers(user))))
|
||||
M.show_message(message)
|
||||
else if((M.client.prefs.toggles & CHAT_GHOSTSIGHT) && !(M in viewers(user)))
|
||||
M.show_message(message)
|
||||
|
||||
/datum/emote/proc/playSound(var/mob/user, var/list/params)
|
||||
if(!sound)
|
||||
return
|
||||
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)
|
||||
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/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
|
||||
******************************************************************************************/
|
||||
|
||||
/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]"
|
||||
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"
|
||||
return 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()
|
||||
set src = usr.contents
|
||||
set category = "Emotes"
|
||||
return usr.emoteHandler.runEmote("me")
|
||||
|
||||
|
||||
|
||||
/**************************************************************************************************************************
|
||||
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().
|
||||
|
||||
***************************************************************************************************************************/
|
||||
|
||||
/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
|
||||
|
||||
/datum/emote/custom/proc/getMessage(var/mob/user)
|
||||
// user.set_typing_indicator(1)
|
||||
// user.hud_typing = 1
|
||||
var/input = copytext(input(user,"What do you want to emote?", "Custom emote") as text|null,1,MAX_MESSAGE_LEN)
|
||||
// user.hud_typing = 0
|
||||
// user.set_typing_indicator(0)
|
||||
input = trim_strip_html_properly(input)
|
||||
return input
|
||||
|
||||
/datum/emote/custom/available(var/mob/user)
|
||||
return 1
|
||||
|
||||
/datum/emote/custom/prevented(var/mob/user)
|
||||
if(!user.use_me)
|
||||
return "you are prevented from using custom emotes"
|
||||
|
||||
// Yeah, no
|
||||
/datum/emote/custom/createSelfMessage(var/mob/user, var/list/params, var/message = "")
|
||||
return
|
||||
|
||||
/datum/emote/custom/replaceMobWithYou(var/mob/M, var/message = "", var/mob/user)
|
||||
return message
|
||||
|
||||
/datum/emote/custom/ghost
|
||||
name = "Ghost emote"
|
||||
startText = "<span class='prefix'>DEAD: </span>"
|
||||
emoteSpanClass = "game deadsay"
|
||||
|
||||
/datum/emote/custom/ghost/prevented(var/mob/user)
|
||||
. = ..()
|
||||
if(.)
|
||||
return
|
||||
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/getMessage(var/mob/user)
|
||||
var/input = copytext(input(user,"What do you want to emote?", "Custom emote") as text|null,1,MAX_MESSAGE_LEN)
|
||||
input = trim_strip_html_properly(input)
|
||||
return input
|
||||
|
||||
/datum/emote/custom/ghost/processMessage(var/mob/user, var/list/params, var/message = "")
|
||||
if(!message)
|
||||
return
|
||||
log_emote("Ghost/[user.key] : [message]")
|
||||
sendToDead(user, message, ghostEmote = 1)
|
||||
|
||||
@@ -0,0 +1,90 @@
|
||||
/datum/emoteHandler
|
||||
var/mob/owner
|
||||
var/list/commands
|
||||
|
||||
/datum/emoteHandler/New(var/mob/user)
|
||||
owner = user
|
||||
setupCommands()
|
||||
|
||||
/datum/emoteHandler/proc/setupCommands(var/reset = 0)
|
||||
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 || emote.allowParent)
|
||||
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()
|
||||
for(var/obj/emoteVerb/E in owner.contents)
|
||||
qdel(E)
|
||||
|
||||
/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")
|
||||
showCommands()
|
||||
return 1
|
||||
|
||||
var/datum/emote/emote
|
||||
|
||||
if(copytext(command, 1, 3) == "me" && !message && lentext(command) >= 4)
|
||||
message = copytext(command, 4)
|
||||
command = "me"
|
||||
|
||||
if(command == "me")
|
||||
emote = customEmote(message, audible)
|
||||
if(!emote)
|
||||
return 0
|
||||
|
||||
if(!commands[command] && !(command == "me"))
|
||||
to_chat(owner, "<span class='notice'>Unknown emote, please check *help for emotes available to your character</span>")
|
||||
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, message, audible)
|
||||
|
||||
var/prevented = emote.prevented(owner)
|
||||
if(prevented)
|
||||
to_chat(owner, "<span class='notice'>You can't do that because [prevented]!</span>")
|
||||
return 0
|
||||
return emote.doEmote(owner, command)
|
||||
|
||||
/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
|
||||
if(em.allowParent)
|
||||
continue
|
||||
found = searchTree(em)
|
||||
if(found)
|
||||
return (found)
|
||||
if(emote.available(owner))
|
||||
return emote
|
||||
|
||||
/datum/emoteHandler/proc/customEmote(var/custom, var/audible)
|
||||
if(isobserver(owner))
|
||||
return new /datum/emote/custom/ghost(owner, custom, audible)
|
||||
return new /datum/emote/custom(owner, custom, audible)
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
@@ -62,10 +62,10 @@
|
||||
|
||||
|
||||
/proc/preloadTemplates(path = "_maps/map_files/templates/") //see master controller setup
|
||||
var/list/filelist = flist(path)
|
||||
for(var/map in filelist)
|
||||
var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
|
||||
map_templates[T.name] = T
|
||||
for(var/map in flist(path))
|
||||
if(cmptext(copytext(map, length(map) - 3), ".dmm"))
|
||||
var/datum/map_template/T = new(path = "[path][map]", rename = "[map]")
|
||||
map_templates[T.name] = T
|
||||
|
||||
if(!config.disable_space_ruins) // so we don't unnecessarily clutter start-up
|
||||
preloadRuinTemplates()
|
||||
|
||||
@@ -79,8 +79,11 @@
|
||||
qdel(trail)
|
||||
|
||||
current_loc = projectile.loc
|
||||
var/matrix/M = new
|
||||
M.Turn(dir2angle(projectile.dir))
|
||||
projectile.transform = M
|
||||
|
||||
sleep(proj_step_delay)
|
||||
|
||||
if(projectile)
|
||||
qdel(projectile)
|
||||
qdel(projectile)
|
||||
|
||||
@@ -234,9 +234,9 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
|
||||
|
||||
/datum/supply_packs/security/taser
|
||||
name = "Stun Guns Crate"
|
||||
contains = list(/obj/item/weapon/gun/energy/advtaser,
|
||||
/obj/item/weapon/gun/energy/advtaser,
|
||||
/obj/item/weapon/gun/energy/advtaser)
|
||||
contains = list(/obj/item/weapon/gun/energy/gun/advtaser,
|
||||
/obj/item/weapon/gun/energy/gun/advtaser,
|
||||
/obj/item/weapon/gun/energy/gun/advtaser)
|
||||
cost = 15
|
||||
containername = "stun gun crate"
|
||||
|
||||
|
||||
+17
-10
@@ -101,9 +101,9 @@ var/list/uplink_items = list()
|
||||
|
||||
if(istype(I,/obj/item/weapon/storage/box/) && I.contents.len>0)
|
||||
for(var/atom/o in I)
|
||||
U.purchase_log += "<BIG>\icon[o]</BIG>"
|
||||
U.purchase_log += "<BIG>[bicon(o)]</BIG>"
|
||||
else
|
||||
U.purchase_log += "<BIG>\icon[I]</BIG>"
|
||||
U.purchase_log += "<BIG>[bicon(I)]</BIG>"
|
||||
|
||||
//U.interact(user)
|
||||
return 1
|
||||
@@ -341,7 +341,7 @@ var/list/uplink_items = list()
|
||||
reference = "SPI"
|
||||
desc = "A small, easily concealable handgun that uses 10mm auto rounds in 8-round magazines and is compatible with suppressors."
|
||||
item = /obj/item/weapon/gun/projectile/automatic/pistol
|
||||
cost = 9
|
||||
cost = 4
|
||||
|
||||
/datum/uplink_item/dangerous/revolver
|
||||
name = "Syndicate .357 Revolver"
|
||||
@@ -410,6 +410,13 @@ var/list/uplink_items = list()
|
||||
item = /obj/item/weapon/twohanded/chainsaw
|
||||
cost = 13
|
||||
|
||||
/datum/uplink_item/dangerous/batterer
|
||||
name = "Mind Batterer"
|
||||
desc = "A device that has a chance of knocking down people around you for a long amount of time. 50% chance per person. The user is unaffected. Has 5 charges."
|
||||
reference = "BTR"
|
||||
item = /obj/item/device/batterer
|
||||
cost = 5
|
||||
|
||||
/datum/uplink_item/dangerous/manhacks
|
||||
name = "Viscerator Delivery Grenade"
|
||||
desc = "A unique grenade that deploys a swarm of viscerators upon activation, which will chase down and shred any non-operatives in the area."
|
||||
@@ -605,10 +612,10 @@ var/list/uplink_items = list()
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/machinegun
|
||||
name = "Box Magazine - 7.62x51mm"
|
||||
desc = "A 50-round magazine of 7.62x51mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses."
|
||||
name = "Box Magazine - 5.56x45mm"
|
||||
desc = "A 50-round magazine of 5.56x45mm ammunition for use in the L6 SAW machine gun. By the time you need to use this, you'll already be on a pile of corpses."
|
||||
reference = "762"
|
||||
item = /obj/item/ammo_box/magazine/m762
|
||||
item = /obj/item/ammo_box/magazine/mm556x45
|
||||
cost = 12
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
surplus = 0
|
||||
@@ -686,7 +693,7 @@ var/list/uplink_items = list()
|
||||
desc = "Fitted for use on any small caliber weapon with a threaded barrel, this suppressor will silence the shots of the weapon for increased stealth and superior ambushing capability."
|
||||
reference = "US"
|
||||
item = /obj/item/weapon/suppressor
|
||||
cost = 3
|
||||
cost = 1
|
||||
surplus = 10
|
||||
|
||||
/datum/uplink_item/stealthy_weapons/pizza_bomb
|
||||
@@ -1016,7 +1023,7 @@ var/list/uplink_items = list()
|
||||
|
||||
/datum/uplink_item/implants/uplink
|
||||
name = "Uplink Implant"
|
||||
desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 5 telecrystals. The ability for an agent to open an uplink after their possessions have been stripped from them makes this implant excellent for escaping confinement."
|
||||
desc = "An implant injected into the body, and later activated using a bodily gesture to open an uplink with 10 telecrystals. The ability for an agent to open an uplink after their possessions have been stripped from them makes this implant excellent for escaping confinement."
|
||||
reference = "UI"
|
||||
item = /obj/item/weapon/implanter/uplink
|
||||
cost = 14
|
||||
@@ -1213,7 +1220,7 @@ var/list/uplink_items = list()
|
||||
bought_items += I.item
|
||||
remaining_TC -= I.cost
|
||||
|
||||
U.purchase_log += "<BIG>\icon[C]</BIG>"
|
||||
U.purchase_log += "<BIG>[bicon(C)]</BIG>"
|
||||
for(var/item in bought_items)
|
||||
new item(C)
|
||||
U.purchase_log += "<BIG>\icon[item]</BIG>"
|
||||
U.purchase_log += "<BIG>[bicon(item)]</BIG>"
|
||||
|
||||
@@ -66,7 +66,7 @@ var/const/CAMERA_WIRE_NOTHING2 = 32
|
||||
C.light_disabled = !C.light_disabled
|
||||
|
||||
if(CAMERA_WIRE_ALARM)
|
||||
C.visible_message("\icon[C] *beep*", "\icon[C] *beep*")
|
||||
C.visible_message("[bicon(C)] *beep*", "[bicon(C)] *beep*")
|
||||
return
|
||||
|
||||
/datum/wires/camera/proc/CanDeconstruct()
|
||||
|
||||
@@ -28,15 +28,15 @@ var/const/WIRE_BEACON_RX = 256 // beacon ping recv
|
||||
/datum/wires/mulebot/UpdatePulsed(var/index)
|
||||
switch(index)
|
||||
if(WIRE_POWER1, WIRE_POWER2)
|
||||
holder.visible_message("\blue \icon[holder] The charge light flickers.")
|
||||
holder.visible_message("\blue [bicon(holder)] The charge light flickers.")
|
||||
if(WIRE_AVOIDANCE)
|
||||
holder.visible_message("\blue \icon[holder] The external warning lights flash briefly.")
|
||||
holder.visible_message("\blue [bicon(holder)] The external warning lights flash briefly.")
|
||||
if(WIRE_LOADCHECK)
|
||||
holder.visible_message("\blue \icon[holder] The load platform clunks.")
|
||||
holder.visible_message("\blue [bicon(holder)] The load platform clunks.")
|
||||
if(WIRE_MOTOR1, WIRE_MOTOR2)
|
||||
holder.visible_message("\blue \icon[holder] The drive motor whines briefly.")
|
||||
holder.visible_message("\blue [bicon(holder)] The drive motor whines briefly.")
|
||||
else
|
||||
holder.visible_message("\blue \icon[holder] You hear a radio crackle.")
|
||||
holder.visible_message("\blue [bicon(holder)] You hear a radio crackle.")
|
||||
|
||||
// HELPER PROCS
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ var/const/PARTICLE_LIMIT_POWER_WIRE = 8 // Determines how strong the PA can be.
|
||||
C.interface_control = !C.interface_control
|
||||
|
||||
if(PARTICLE_LIMIT_POWER_WIRE)
|
||||
C.visible_message("\icon[C]<b>[C]</b> makes a large whirring noise.")
|
||||
C.visible_message("[bicon(C)]<b>[C]</b> makes a large whirring noise.")
|
||||
|
||||
/datum/wires/particle_acc/control_box/UpdateCut(var/index, var/mended)
|
||||
var/obj/machinery/particle_accelerator/control_box/C = holder
|
||||
|
||||
@@ -21,17 +21,17 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if
|
||||
switch(index)
|
||||
if(WIRE_BOOM)
|
||||
if (P.active)
|
||||
P.loc.visible_message("<span class='danger'>\icon[holder] An alarm sounds! It's go-</span>")
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
if(WIRE_UNBOLT)
|
||||
P.loc.visible_message("<span class='notice'>\icon[holder] The bolts spin in place for a moment.</span>")
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bolts spin in place for a moment.</span>")
|
||||
if(WIRE_DELAY)
|
||||
playsound(P.loc, 'sound/machines/chime.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='notice'>\icon[holder] The bomb chirps.</span>")
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bomb chirps.</span>")
|
||||
P.timer += 10
|
||||
if(WIRE_PROCEED)
|
||||
playsound(P.loc, 'sound/machines/buzz-sigh.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='danger'>\icon[holder] The bomb buzzes ominously!</span>")
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] The bomb buzzes ominously!</span>")
|
||||
if (P.timer >= 61) //Long fuse bombs can suddenly become more dangerous if you tinker with them
|
||||
P.timer = 60
|
||||
if (P.timer >= 21)
|
||||
@@ -41,11 +41,11 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if
|
||||
if(WIRE_ACTIVATE)
|
||||
if(!P.active && !P.defused)
|
||||
playsound(P.loc, 'sound/machines/click.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='danger'>\icon[holder] You hear the bomb start ticking!</span>")
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] You hear the bomb start ticking!</span>")
|
||||
P.active = 1
|
||||
P.icon_state = "[initial(P.icon_state)]-active[P.open_panel ? "-wires" : ""]"
|
||||
else
|
||||
P.loc.visible_message("<span class='notice'>\icon[holder] The bomb seems to hesitate for a moment.</span>")
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bomb seems to hesitate for a moment.</span>")
|
||||
P.timer += 5
|
||||
|
||||
/datum/wires/syndicatebomb/UpdateCut(var/index, var/mended)
|
||||
@@ -54,7 +54,7 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if
|
||||
if(WIRE_EXPLODE)
|
||||
if(!mended)
|
||||
if(P.active)
|
||||
P.loc.visible_message("<span class='danger'>\icon[holder] An alarm sounds! It's go-</span>")
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
else
|
||||
P.defused = 1
|
||||
@@ -63,15 +63,15 @@ var/const/WIRE_ACTIVATE = 16 // Will start a bombs timer if pulsed, will hint if
|
||||
if(WIRE_UNBOLT)
|
||||
if (!mended && P.anchored)
|
||||
playsound(P.loc, 'sound/effects/stealthoff.ogg', 30, 1)
|
||||
P.loc.visible_message("<span class='notice'>\icon[holder] The bolts lift out of the ground!</span>")
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The bolts lift out of the ground!</span>")
|
||||
P.anchored = 0
|
||||
if(WIRE_PROCEED)
|
||||
if(!mended && P.active)
|
||||
P.loc.visible_message("<span class='danger'>\icon[holder] An alarm sounds! It's go-</span>")
|
||||
P.loc.visible_message("<span class='danger'>[bicon(holder)] An alarm sounds! It's go-</span>")
|
||||
P.timer = 0
|
||||
if(WIRE_ACTIVATE)
|
||||
if (!mended && P.active)
|
||||
P.loc.visible_message("<span class='notice'>\icon[holder] The timer stops! The bomb has been defused!</span>")
|
||||
P.loc.visible_message("<span class='notice'>[bicon(holder)] The timer stops! The bomb has been defused!</span>")
|
||||
P.icon_state = "[initial(P.icon_state)]-inactive[P.open_panel ? "-wires" : ""]"
|
||||
P.active = 0
|
||||
P.defused = 1
|
||||
Reference in New Issue
Block a user