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:
@@ -1,587 +0,0 @@
|
||||
/*******************************************************************************************************
|
||||
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)
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
/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
+24
-11
@@ -150,9 +150,9 @@
|
||||
if (istype(current, /mob/living/carbon/human))
|
||||
/** Impanted**/
|
||||
if(isloyal(H))
|
||||
text = "Loyalty Implant:<a href='?src=\ref[src];implant=remove'>Remove</a>|<b>Implanted</b></br>"
|
||||
text = "Mindshield Implant:<a href='?src=\ref[src];implant=remove'>Remove</a>|<b>Implanted</b></br>"
|
||||
else
|
||||
text = "Loyalty Implant:<b>No Implant</b>|<a href='?src=\ref[src];implant=add'>Implant him!</a></br>"
|
||||
text = "Mindshield Implant:<b>No Implant</b>|<a href='?src=\ref[src];implant=add'>Implant him!</a></br>"
|
||||
sections["implant"] = text
|
||||
/** REVOLUTION ***/
|
||||
text = "revolution"
|
||||
@@ -653,27 +653,27 @@
|
||||
if(I && I.implanted)
|
||||
I.removed(H)
|
||||
qdel(I)
|
||||
to_chat(H, "\blue <Font size =3><B>Your loyalty implant has been deactivated.</B></FONT>")
|
||||
log_admin("[key_name(usr)] has deactivated [key_name(current)]'s loyalty implant")
|
||||
message_admins("[key_name_admin(usr)] has deactivated [key_name_admin(current)]'s loyalty implant")
|
||||
to_chat(H, "\blue <Font size =3><B>Your mindshield implant has been deactivated.</B></FONT>")
|
||||
log_admin("[key_name(usr)] has deactivated [key_name(current)]'s mindshield implant")
|
||||
message_admins("[key_name_admin(usr)] has deactivated [key_name_admin(current)]'s mindshield implant")
|
||||
if("add")
|
||||
var/obj/item/weapon/implant/loyalty/L = new/obj/item/weapon/implant/loyalty(H)
|
||||
L.imp_in = H
|
||||
L.implanted = 1
|
||||
H.sec_hud_set_implants()
|
||||
|
||||
log_admin("[key_name(usr)] has given [key_name(current)] a loyalty implant")
|
||||
message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] a loyalty implant")
|
||||
log_admin("[key_name(usr)] has given [key_name(current)] a mindshield implant")
|
||||
message_admins("[key_name_admin(usr)] has given [key_name_admin(current)] a mindshield implant")
|
||||
|
||||
to_chat(H, "\red <Font size =3><B>You somehow have become the recepient of a loyalty transplant, and it just activated!</B></FONT>")
|
||||
to_chat(H, "\red <Font size =3><B>You somehow have become the recepient of a mindshield transplant, and it just activated!</B></FONT>")
|
||||
if(src in ticker.mode.revolutionaries)
|
||||
special_role = null
|
||||
ticker.mode.revolutionaries -= src
|
||||
to_chat(src, "\red <Font size = 3><B>The nanobots in the loyalty implant remove all thoughts about being a revolutionary. Get back to work!</B></Font>")
|
||||
to_chat(src, "\red <Font size = 3><B>The nanobots in the mindshield implant remove all thoughts about being a revolutionary. Get back to work!</B></Font>")
|
||||
if(src in ticker.mode.head_revolutionaries)
|
||||
special_role = null
|
||||
ticker.mode.head_revolutionaries -=src
|
||||
to_chat(src, "\red <Font size = 3><B>The nanobots in the loyalty implant remove all thoughts about being a revolutionary. Get back to work!</B></Font>")
|
||||
to_chat(src, "\red <Font size = 3><B>The nanobots in the mindshield implant remove all thoughts about being a revolutionary. Get back to work!</B></Font>")
|
||||
if(src in ticker.mode.cult)
|
||||
ticker.mode.cult -= src
|
||||
ticker.mode.update_cult_icons_removed(src)
|
||||
@@ -681,7 +681,7 @@
|
||||
var/datum/game_mode/cult/cult = ticker.mode
|
||||
if (istype(cult))
|
||||
cult.memorize_cult_objectives(src)
|
||||
to_chat(current, "\red <FONT size = 3><B>The nanobots in the loyalty implant remove all thoughts about being in a cult. Have a productive day!</B></FONT>")
|
||||
to_chat(current, "\red <FONT size = 3><B>The nanobots in the mindshield implant remove all thoughts about being in a cult. Have a productive day!</B></FONT>")
|
||||
memory = ""
|
||||
|
||||
else if (href_list["revolution"])
|
||||
@@ -1516,6 +1516,19 @@
|
||||
spell.action.Grant(new_character)
|
||||
return
|
||||
|
||||
/datum/mind/proc/get_ghost(even_if_they_cant_reenter)
|
||||
for(var/mob/dead/observer/G in dead_mob_list)
|
||||
if(G.mind == src)
|
||||
if(G.can_reenter_corpse || even_if_they_cant_reenter)
|
||||
return G
|
||||
break
|
||||
|
||||
/datum/mind/proc/grab_ghost(force)
|
||||
var/mob/dead/observer/G = get_ghost(even_if_they_cant_reenter = force)
|
||||
. = G
|
||||
if(G)
|
||||
G.reenter_corpse()
|
||||
|
||||
//Initialisation procs
|
||||
/mob/proc/mind_initialize()
|
||||
if(mind)
|
||||
|
||||
@@ -24,9 +24,14 @@
|
||||
target:hulk_time=world.time + duration */
|
||||
target.sdisabilities |= sdisabilities
|
||||
target.update_mutations() //update target's mutation overlays
|
||||
var/mob/living/carbon/human/H = target
|
||||
if(ishuman(target))
|
||||
H.update_body()
|
||||
spawn(duration)
|
||||
target.mutations.Remove(mutations)
|
||||
target.sdisabilities &= ~sdisabilities
|
||||
target.update_mutations()
|
||||
if(ishuman(target))
|
||||
H.update_body()
|
||||
|
||||
return
|
||||
@@ -53,6 +53,15 @@
|
||||
|
||||
action_icon_state = "mutate"
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/genetic/mutate/cast(list/targets)
|
||||
for(var/mob/living/target in targets)
|
||||
target.dna.SetSEState(HULKBLOCK, 1)
|
||||
genemutcheck(target, HULKBLOCK, null, MUTCHK_FORCED)
|
||||
spawn(duration)
|
||||
target.dna.SetSEState(HULKBLOCK, 0)
|
||||
genemutcheck(target, HULKBLOCK, null, MUTCHK_FORCED)
|
||||
..()
|
||||
|
||||
/obj/effect/proc_holder/spell/targeted/smoke
|
||||
name = "Smoke"
|
||||
desc = "This spell spawns a cloud of choking smoke at your location and does not require wizard garb."
|
||||
|
||||
@@ -375,10 +375,10 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
|
||||
/////// Implants & etc
|
||||
|
||||
/datum/supply_packs/security/armory/loyalty
|
||||
name = "Loyalty Implants Crate"
|
||||
name = "Mindshield Implants Crate"
|
||||
contains = list (/obj/item/weapon/storage/lockbox/loyalty)
|
||||
cost = 40
|
||||
containername = "loyalty implant crate"
|
||||
containername = "mindshield implant crate"
|
||||
|
||||
/datum/supply_packs/security/armory/trackingimp
|
||||
name = "Tracking Implants Crate"
|
||||
|
||||
@@ -378,6 +378,15 @@ var/list/uplink_items = list()
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
surplus = 0
|
||||
|
||||
/datum/uplink_item/dangerous/sniper
|
||||
name = "Sniper Rifle"
|
||||
desc = "Ranged fury, Syndicate style. guaranteed to cause shock and awe or your TC back!"
|
||||
reference = "SSR"
|
||||
item = /obj/item/weapon/gun/projectile/automatic/sniper_rifle/syndicate
|
||||
cost = 16
|
||||
surplus = 25
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/dangerous/crossbow
|
||||
name = "Energy Crossbow"
|
||||
desc = "A miniature energy crossbow that is small enough both to fit into a pocket and to slip into a backpack unnoticed by observers. Fires bolts tipped with toxin, a poisonous substance that is the product of a living organism. Stuns enemies for a short period of time. Recharges automatically."
|
||||
@@ -620,6 +629,38 @@ var/list/uplink_items = list()
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
surplus = 0
|
||||
|
||||
/datum/uplink_item/ammo/sniper
|
||||
cost = 4
|
||||
gamemodes = list(/datum/game_mode/nuclear)
|
||||
|
||||
/datum/uplink_item/ammo/sniper/basic
|
||||
name = ".50 Magazine"
|
||||
desc = "An additional standard 6-round magazine for use with .50 sniper rifles."
|
||||
reference = "50M"
|
||||
item = /obj/item/ammo_box/magazine/sniper_rounds
|
||||
|
||||
/datum/uplink_item/ammo/sniper/soporific
|
||||
name = ".50 Soporific Magazine"
|
||||
desc = "A 3-round magazine of soporific ammo designed for use with .50 sniper rifles. Put your enemies to sleep today!"
|
||||
reference = "50S"
|
||||
item = /obj/item/ammo_box/magazine/sniper_rounds/soporific
|
||||
cost = 6
|
||||
|
||||
/datum/uplink_item/ammo/sniper/haemorrhage
|
||||
name = ".50 Haemorrhage Magazine"
|
||||
desc = "A 5-round magazine of haemorrhage ammo designed for use with .50 sniper rifles; causes heavy bleeding \
|
||||
in the target."
|
||||
reference = "50B"
|
||||
item = /obj/item/ammo_box/magazine/sniper_rounds/haemorrhage
|
||||
|
||||
/datum/uplink_item/ammo/sniper/penetrator
|
||||
name = ".50 Penetrator Magazine"
|
||||
desc = "A 5-round magazine of penetrator ammo designed for use with .50 sniper rifles. \
|
||||
Can pierce walls and multiple enemies."
|
||||
reference = "50P"
|
||||
item = /obj/item/ammo_box/magazine/sniper_rounds/penetrator
|
||||
cost = 5
|
||||
|
||||
// STEALTHY WEAPONS
|
||||
|
||||
/datum/uplink_item/stealthy_weapons
|
||||
|
||||
@@ -107,7 +107,8 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
|
||||
A.autoclose = mended
|
||||
if(mended)
|
||||
if(!A.density)
|
||||
A.close()
|
||||
spawn(0)
|
||||
A.close()
|
||||
|
||||
if(AIRLOCK_WIRE_LIGHT)
|
||||
A.lights = mended
|
||||
@@ -159,12 +160,16 @@ var/const/AIRLOCK_WIRE_LIGHT = 2048
|
||||
//will succeed only if the ID wire is cut or the door requires no access and it's not emagged
|
||||
if(A.emagged) return
|
||||
if(!A.requiresID() || A.check_access(null))
|
||||
if(A.density) A.open()
|
||||
else A.close()
|
||||
spawn(0)
|
||||
if(A.density)
|
||||
A.open()
|
||||
else
|
||||
A.close()
|
||||
if(AIRLOCK_WIRE_SAFETY)
|
||||
A.safe = !A.safe
|
||||
if(!A.density)
|
||||
A.close()
|
||||
spawn(0)
|
||||
A.close()
|
||||
|
||||
if(AIRLOCK_WIRE_SPEED)
|
||||
A.normalspeed = !A.normalspeed
|
||||
|
||||
Reference in New Issue
Block a user