mirror of
https://github.com/goonstation/goonstation-2020.git
synced 2026-07-11 07:02:20 +01:00
868 lines
30 KiB
Plaintext
868 lines
30 KiB
Plaintext
/mob/proc/say()
|
|
return
|
|
|
|
/mob/verb/whisper()
|
|
return
|
|
|
|
/mob/verb/say_verb(message as text)
|
|
set name = "say"
|
|
//&& !src.client.holder
|
|
if (!message)
|
|
return
|
|
if (src.client && url_regex && url_regex.Find(message) && !client.holder)
|
|
boutput(src, "<span style=\"color:blue\"><b>Web/BYOND links are not allowed in ingame chat.</b></span>")
|
|
boutput(src, "<span style=\"color:red\"> <b>\"[message]</b>\"</span>")
|
|
return
|
|
src.say(message)
|
|
if (!dd_hasprefix(message, "*")) // if this is an emote it is logged in emote
|
|
logTheThing("say", src, null, "SAY: [html_encode(message)] [log_loc(src)]")
|
|
logit("say", 0, src, " said ", message)
|
|
|
|
/mob/verb/say_radio()
|
|
set name = "say_radio"
|
|
set hidden = 1
|
|
|
|
/mob/living/say_radio()
|
|
set name = "say_radio"
|
|
set hidden = 1
|
|
|
|
if (isAI(src))
|
|
var/mob/living/silicon/ai/A = src
|
|
var/list/choices = list()
|
|
var/list/channels = list()
|
|
var/list/radios = list(A.radio1, A.radio2, A.radio3)
|
|
for (var/i = 1, i <= radios.len, i++)
|
|
var/obj/item/device/radio/R = radios[i]
|
|
var/channel_name
|
|
|
|
if (!istype(R, /obj/item/device/radio/headset/command/ai))
|
|
// Skip the AI headset (radio 3) because it reads the first char as a channel.
|
|
// Honestly this should probably be fixed in some other way, but, effort.
|
|
channel_name = "[format_frequency(R.frequency)] - " + (headset_channel_lookup["[R.frequency]"] ? headset_channel_lookup["[R.frequency]"] : "(Unknown)")
|
|
choices += channel_name
|
|
channels[channel_name] = ":[i]"
|
|
|
|
if (istype(R.secure_frequencies) && R.secure_frequencies.len)
|
|
for (var/sayToken in R.secure_frequencies)
|
|
channel_name = "[format_frequency(R.secure_frequencies[sayToken])] - " + (headset_channel_lookup["[R.secure_frequencies[sayToken]]"] ? headset_channel_lookup["[R.secure_frequencies[sayToken]]"] : "(Unknown)")
|
|
|
|
choices += channel_name
|
|
channels[channel_name] = ":[i][sayToken]"
|
|
|
|
if (A.robot_talk_understand)
|
|
var/channel_name = "* - Robot Talk"
|
|
channels[channel_name] = ":s"
|
|
choices += channel_name
|
|
|
|
var/choice = 0
|
|
if (choices.len == 1)
|
|
choice = choices[1]
|
|
else
|
|
choice = input("", "Select Radio and Channel", null) as null|anything in choices
|
|
if (!choice)
|
|
return
|
|
|
|
var/token = channels[choice]
|
|
if (!token)
|
|
boutput(src, "Somehow '[choice]' didn't match anything. Welp. Probably busted.")
|
|
var/text = input("", "Speaking over [choice] ([token])")
|
|
if (text)
|
|
src.say_verb(token + text)
|
|
|
|
|
|
else if (src.ears && istype(src.ears, /obj/item/device/radio))
|
|
var/obj/item/device/radio/R = src.ears
|
|
var/token = ""
|
|
var/list/choices = list()
|
|
choices += "[ headset_channel_lookup["[R.frequency]"] ? headset_channel_lookup["[R.frequency]"] : "???" ]: \[[format_frequency(R.frequency)]]"
|
|
|
|
if (istype(R.secure_frequencies) && R.secure_frequencies.len)
|
|
for (var/sayToken in R.secure_frequencies)
|
|
choices += "[ headset_channel_lookup["[R.secure_frequencies["[sayToken]"]]"] ? headset_channel_lookup["[R.secure_frequencies["[sayToken]"]]"] : "???" ]: \[[format_frequency(R.secure_frequencies["[sayToken]"])]]"
|
|
|
|
if (src.robot_talk_understand)
|
|
choices += "Robot Talk: \[***]"
|
|
|
|
|
|
var/choice = 0
|
|
if (choices.len == 1)
|
|
choice = choices[1]
|
|
else
|
|
choice = input("", "Select Radio Channel", null) as null|anything in choices
|
|
if (!choice)
|
|
return
|
|
|
|
var/choice_index = choices.Find(choice)
|
|
if (choice_index == 1)
|
|
token = ";"
|
|
else if (choice == "Robot Talk: \[***]")
|
|
token = ":s"
|
|
else
|
|
token = ":" + R.secure_frequencies[choice_index - 1]
|
|
|
|
var/text = input("", "Speaking to [choice] frequency")
|
|
src.say_verb(token+text)
|
|
else
|
|
boutput(src, "<span style=\"color:blue\">You must put a headset on your ear slot to speak on the radio.</span>")
|
|
|
|
// ghosts now can emote now too so vOv
|
|
/* if (isliving(src))
|
|
if (copytext(message, 1, 2) != "*") // if this is an emote it is logged in emote
|
|
logTheThing("say", src, null, "SAY: [message]")
|
|
else logTheThing("say", src, null, "SAY: [message]")
|
|
*/
|
|
/mob/verb/me_verb(message as text)
|
|
set name = "me"
|
|
|
|
if (src.client && !src.client.holder && url_regex && url_regex.Find(message))
|
|
boutput(src, "<span style=\"color:blue\"><b>Web/BYOND links are not allowed in ingame chat.</b></span>")
|
|
boutput(src, "<span style=\"color:red\"> <b>\"[message]</b>\"</span>")
|
|
return
|
|
|
|
src.emote(message, 1)
|
|
/* ghost emotes wooo also the logging is already taken care of in the emote() procs vOv
|
|
if (isliving(src) && isalive(src))
|
|
src.emote(message, 1)
|
|
logTheThing("say", src, null, "EMOTE: [message]")
|
|
else
|
|
boutput(src, "<span style=\"color:blue\">You can't emote when you're dead! How would that even work!?</span>")
|
|
*/
|
|
/mob/proc/say_dead(var/message, wraith = 0)
|
|
var/name = src.real_name
|
|
var/alt_name = ""
|
|
|
|
if (!deadchat_allowed)
|
|
boutput(usr, "<b>Deadchat is currently disabled.</b>")
|
|
return
|
|
|
|
message = trim(copytext(html_encode(sanitize(message)), 1, MAX_MESSAGE_LEN))
|
|
if (!message)
|
|
return
|
|
|
|
if (ishuman(src) && src.name != src.real_name)
|
|
if (src:wear_id && src:wear_id:registered && src:wear_id:registered != src.real_name)
|
|
alt_name = " (as [src:wear_id:registered])"
|
|
else if (!src:wear_id)
|
|
alt_name = " (as Unknown)"
|
|
|
|
else if (isobserver(src))
|
|
name = "Ghost"
|
|
alt_name = " ([src.real_name])"
|
|
else if (iswraith(src))
|
|
name = "Wraith"
|
|
alt_name = " ([src.real_name])"
|
|
|
|
else if (!ishuman(src))
|
|
name = src.name
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(message)
|
|
#endif
|
|
|
|
message = src.say_quote(message)
|
|
//logTheThing("say", src, null, "SAY: [message]")
|
|
|
|
var/rendered = "<span class='game deadsay'><span class='prefix'>DEAD:</span> <span class='name' data-ctx='\ref[src.mind]'>[name]<span class='text-normal'>[alt_name]</span></span> <span class='message'>[message]</span></span>"
|
|
//logit( "chat", 0, "([name])", src, message )
|
|
for (var/mob/M in mobs)
|
|
if (istype(M, /mob/new_player))
|
|
continue
|
|
if (M.client && M.client.deadchatoff)
|
|
continue
|
|
if (istype(M,/mob/dead/target_observer/hivemind_observer))
|
|
continue
|
|
|
|
//admins can toggle deadchat on and off. This is a proc in admin.dm and is only give to Administrators and above
|
|
if (isdead(M) || iswraith(M) || (M.client && M.client.holder && M.client.deadchat && !M.client.player_mode) || isghostdrone(M) || isVRghost(M) || inafterlifebar(M))
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
|
|
//changeling hivemind say
|
|
/mob/proc/say_hive(var/message, var/datum/abilityHolder/changeling/hivemind_owner)
|
|
var/name = src.real_name
|
|
var/alt_name = ""
|
|
|
|
if (!hivemind_owner)
|
|
return
|
|
|
|
//i guess this caused some real ugly text huh
|
|
//message = trim(copytext(html_encode(sanitize(message)), 1, MAX_MESSAGE_LEN))
|
|
if (!message)
|
|
return
|
|
|
|
if (istype(src, /mob/living/critter/changeling/handspider))
|
|
name = src.real_name
|
|
alt_name = " (HANDSPIDER)"
|
|
else if (istype(src, /mob/living/critter/changeling/eyespider))
|
|
name = src.real_name
|
|
alt_name = " (EYESPIDER)"
|
|
else if (istype(src, /mob/living/critter/changeling/legworm))
|
|
name = src.real_name
|
|
alt_name = " (LEGWORM)"
|
|
else if(!hivemind_owner.master)
|
|
//Standard behaviour
|
|
if (src == hivemind_owner.owner)
|
|
name = src.name
|
|
alt_name = " (MASTER)"
|
|
else
|
|
//Someone else is controlling stuff
|
|
if (src == hivemind_owner.owner)
|
|
name = hivemind_owner.original_controller_real_name
|
|
alt_name = " (CONTROLLER)"
|
|
else if (src == hivemind_owner.master)
|
|
name = src.name
|
|
alt_name = " (MASTER)"
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(message)
|
|
#endif
|
|
|
|
message = src.say_quote(message)
|
|
//logTheThing("say", src, null, "SAY: [message]")
|
|
|
|
var/rendered = "<span class='game hivesay'><span class='prefix'>HIVEMIND:</span> <span class='name' data-ctx='\ref[src.mind]'>[name]<span class='text-normal'>[alt_name]</span></span> <span class='message'>[message]</span></span>"
|
|
|
|
|
|
//show message to admins (Follow rules of their deadchat toggle)
|
|
for (var/mob/M in mobs)
|
|
if (M.client && M.client.holder && M.client.deadchat && !M.client.player_mode)
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//show to hivemind
|
|
for (var/mob/M in hivemind_owner.hivemind)
|
|
if ((isdead(M) || istype(M,/mob/living/critter/changeling)) && !(M.client && M.client.holder && M.client.deadchat && !M.client.player_mode))
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//show to hivemind owner
|
|
if (!(hivemind_owner.owner.client && hivemind_owner.owner.client.holder && hivemind_owner.owner.client.deadchat && !hivemind_owner.owner.client.player_mode))
|
|
var/thisR = rendered
|
|
if (hivemind_owner.owner.client && hivemind_owner.owner.client.holder && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[hivemind_owner.owner.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(hivemind_owner.owner, thisR)
|
|
|
|
|
|
//changeling hivemind say
|
|
/mob/proc/say_ghoul(var/message, var/datum/abilityHolder/vampire/owner)
|
|
var/name = src.real_name
|
|
var/alt_name = ""
|
|
|
|
if (!owner)
|
|
return
|
|
|
|
if (!message)
|
|
return
|
|
|
|
if (istype(src, /mob/living/critter/changeling/handspider))
|
|
name = src.real_name
|
|
alt_name = " (VAMPIRE)"
|
|
else if (istype(src, /mob/living/critter/changeling/eyespider))
|
|
name = src.real_name
|
|
alt_name = " (GHOUL)"
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(message)
|
|
#endif
|
|
|
|
message = src.say_quote(message)
|
|
//logTheThing("say", src, null, "SAY: [message]")
|
|
|
|
var/rendered = "<span class='game ghoulsay'><span class='prefix'>GHOULSPEAK:</span> <span class='name' data-ctx='\ref[src.mind]'>[name]<span class='text-normal'>[alt_name]</span></span> <span class='message'>[message]</span></span>"
|
|
|
|
|
|
//show message to admins (Follow rules of their deadchat toggle)
|
|
for (var/mob/M in mobs)
|
|
if (M.client && M.client.holder && M.client.deadchat && !M.client.player_mode)
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//show to ghouls
|
|
for (var/mob/M in owner.ghouls)
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//show to ghoul owner
|
|
if (!(owner.owner.client && owner.owner.client.holder && owner.owner.client.deadchat && !owner.owner.client.player_mode))
|
|
var/thisR = rendered
|
|
if (owner.owner.client && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[owner.owner.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(owner.owner, thisR)
|
|
|
|
//kudzu hivemind say
|
|
/mob/proc/say_kudzu(var/message, var/datum/abilityHolder/kudzu/owner)
|
|
var/name = src.real_name
|
|
var/alt_name = ""
|
|
|
|
if (!owner)
|
|
return
|
|
|
|
if (!message)
|
|
return
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(message)
|
|
#endif
|
|
logTheThing("diary", src, null, "(KUDZU): [message]", "hivesay")
|
|
|
|
message = src.say_quote(message)
|
|
//logTheThing("say", src, null, "SAY: [message]")
|
|
|
|
var/rendered = "<span class='game kudzusay'><span class='prefix'><small>KUDZUSPEAK:</small></span> <span class='name' data-ctx='\ref[src.mind]'>[name]<span class='text-normal'>[alt_name]</span></span> <span class='message'>[message]</span></span>"
|
|
|
|
|
|
//show message to admins (Follow rules of their deadchat toggle)
|
|
for (var/mob/M in mobs)
|
|
if (M.client && M.client.holder && M.client.deadchat && !M.client.player_mode)
|
|
var/thisR = rendered
|
|
if (M.client && (istype(M, /mob/dead/observer)||M.client.holder) && src.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//show to kudzu
|
|
for (var/mob/M in mobs)
|
|
var/thisR = rendered
|
|
if (M.client && src.mind && istype(M.abilityHolder, /datum/abilityHolder/kudzu))
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
boutput(M, thisR)
|
|
//////////////////////////////////
|
|
|
|
/mob/proc/say_understands(var/mob/other, var/forced_language)
|
|
if (isdead(src))
|
|
return 1
|
|
// else if (istype(other, src.type) || istype(src, other.type))
|
|
// return 1
|
|
var/L = other.say_language
|
|
if (forced_language)
|
|
L = forced_language
|
|
if (understands_language(L))
|
|
return 1
|
|
return 0
|
|
/*if (isrobot(other) || isAI(other) || (ismonkey(other) && src.bioHolder.HasEffect("monkey_speak")))
|
|
return 1
|
|
else
|
|
. = 0
|
|
. += ismonkey(src) ? 1 : 0
|
|
. += ismonkey(other) ? 1 : 0
|
|
if (. == 1)
|
|
return monkeysspeakhuman
|
|
else
|
|
return 1
|
|
return 0*/
|
|
|
|
/mob/proc/say_quote(var/text, var/special = 0)
|
|
var/ending = copytext(text, length(text))
|
|
var/speechverb = speechverb_say
|
|
var/loudness = 0
|
|
var/font_accent = null
|
|
|
|
if (ending == "?")
|
|
speechverb = speechverb_ask
|
|
else if (ending == "!")
|
|
speechverb = speechverb_exclaim
|
|
if (src.stuttering)
|
|
speechverb = speechverb_stammer
|
|
for (var/datum/ailment_data/A in src.ailments)
|
|
if (istype(A.master, /datum/ailment/disease/berserker))
|
|
if (A.stage > 1)
|
|
speechverb = "roars"
|
|
if ((src.reagents && src.reagents.get_reagent_amount("ethanol") > 30))
|
|
speechverb = "slurs"
|
|
if (src.bioHolder)
|
|
if (src.bioHolder.HasEffect("loud_voice"))
|
|
speechverb = "bellows"
|
|
loudness += 1
|
|
if (src.bioHolder.HasEffect("quiet_voice"))
|
|
speechverb = "murmurs"
|
|
loudness -= 1
|
|
if (src.bioHolder.HasEffect("unintelligable"))
|
|
speechverb = "splutters"
|
|
if (src.bioHolder.HasEffect("accent_comic"))
|
|
font_accent = "Comic Sans MS"
|
|
|
|
if (src.bioHolder && src.bioHolder.genetic_stability < 50)
|
|
speechverb = "gurgles"
|
|
|
|
if (src.get_brain_damage() >= 60)
|
|
speechverb = pick("says","stutters","mumbles","slurs")
|
|
|
|
if (special)
|
|
if (special == "gasp_whisper")
|
|
speechverb = speechverb_gasp
|
|
loudness -= 1
|
|
|
|
// hi cirr here i feel this should be relative for weak mobs
|
|
var/health_percentage = (src.health/(max(1, src.max_health))) * 100 // prevent div/0 errors from stopping people talking
|
|
// better to inaccurately not gasp than be silenced by runtimes
|
|
if (health_percentage <= 20)
|
|
speechverb = speechverb_gasp
|
|
if (isdead(src) || isobserver(src))
|
|
speechverb = pick("moans","wails","laments")
|
|
if (prob(5))
|
|
speechverb = "grumps"
|
|
|
|
if (text == "" || !text)
|
|
return speechverb
|
|
|
|
if (src.speech_void)
|
|
text = voidSpeak(text)
|
|
|
|
if (loudness > 0)
|
|
return "[speechverb], \"[font_accent ? "<font face='[font_accent]'>" : null]<big><strong><b>[text]</b></strong></big>[font_accent ? "</font>" : null]\""
|
|
else if (loudness < 0)
|
|
return "[speechverb], \"[font_accent ? "<font face='[font_accent]'>" : null]<small>[text]</small>[font_accent ? "</font>" : null]\""
|
|
else
|
|
return "[speechverb], \"[font_accent ? "<font face='[font_accent]'>" : null][text][font_accent ? "</font>" : null]\""
|
|
|
|
/mob/proc/emote(var/act, var/voluntary = 0)
|
|
return
|
|
|
|
/mob/proc/emote_check(var/voluntary = 1, var/time = 10, var/admin_bypass = 1, var/dead_check = 1)
|
|
if (src.emote_allowed)
|
|
if (dead_check && isdead(src))
|
|
src.emote_allowed = 0
|
|
return 0
|
|
if (world.time >= (src.last_emote_time + src.last_emote_wait))
|
|
if (!(src.client && (src.client.holder && admin_bypass)) && voluntary)
|
|
src.emote_allowed = 0
|
|
src.last_emote_time = world.time
|
|
src.last_emote_wait = time
|
|
SPAWN_DBG(time)
|
|
src.emote_allowed = 1
|
|
return 1
|
|
else
|
|
return 0
|
|
else
|
|
return 0
|
|
|
|
/mob/verb/listen_ooc()
|
|
set name = "(Un)Mute OOC"
|
|
set desc = "Mute or Unmute Out Of Character chat."
|
|
|
|
if (src.client)
|
|
src.client.preferences.listen_ooc = !src.client.preferences.listen_ooc
|
|
if (src.client.preferences.listen_ooc)
|
|
boutput(src, "<span style=\"color:blue\">You are now listening to messages on the OOC channel.</span>")
|
|
else
|
|
boutput(src, "<span style=\"color:blue\">You are no longer listening to messages on the OOC channel.</span>")
|
|
|
|
/mob/verb/ooc(msg as text)
|
|
if (IsGuestKey(src.key))
|
|
boutput(src, "You are not authorized to communicate over these channels.")
|
|
return
|
|
if (oocban_isbanned(src))
|
|
boutput(src, "You are currently banned from using OOC and LOOC, you may appeal at https://forum.ss13.co/index.php")
|
|
return
|
|
|
|
msg = trim(copytext(html_encode(msg), 1, MAX_MESSAGE_LEN))
|
|
if (!msg)
|
|
return
|
|
else if (!src.client.preferences.listen_ooc)
|
|
return
|
|
else if (!ooc_allowed && !src.client.holder)
|
|
boutput(usr, "OOC is currently disabled.")
|
|
return
|
|
else if (!dooc_allowed && !src.client.holder && (src.client.deadchat != 0))
|
|
boutput(usr, "OOC for dead mobs has been turned off.")
|
|
return
|
|
else if (src.client && src.client.ismuted())
|
|
boutput(usr, "You are currently muted and cannot talk in OOC.")
|
|
return
|
|
else if (findtext(msg, "byond://") && !src.client.holder)
|
|
boutput(src, "<B>Advertising other servers is not allowed.</B>")
|
|
logTheThing("admin", src, null, "has attempted to advertise in OOC.")
|
|
logTheThing("diary", src, null, "has attempted to advertise in OOC.", "admin")
|
|
message_admins("[key_name(src)] has attempted to advertise in OOC.")
|
|
return
|
|
|
|
logTheThing("diary", src, null, ": [msg]", "ooc")
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(msg)
|
|
#endif
|
|
|
|
for (var/client/C in clients)
|
|
// DEBUGGING
|
|
if (!C.preferences)
|
|
logTheThing("debug", null, null, "[C] (\ref[C]): client.preferences is null")
|
|
|
|
if (C.preferences && !C.preferences.listen_ooc)
|
|
continue
|
|
|
|
var ooc_class = ""
|
|
var display_name = src.key
|
|
|
|
if (src.client.stealth || src.client.alt_key)
|
|
if (!C.holder)
|
|
display_name = src.client.fakekey
|
|
else
|
|
display_name += " (as [src.client.fakekey])"
|
|
|
|
if (src.client.holder && (!src.client.stealth || C.holder))
|
|
if (src.client.holder.level == LEVEL_BABBY)
|
|
ooc_class = "gfartooc"
|
|
else
|
|
ooc_class = "adminooc"
|
|
else if (src.client.is_mentor() && !src.client.stealth)
|
|
ooc_class = "mentorooc"
|
|
|
|
if( src.client.cloud_available() && src.client.cloud_get("donor") )
|
|
msg = replacetext(msg, ":shelterfrog:", "<img src='http://stuff.goonhub.com/shelterfrog.png' width=32>")
|
|
|
|
var/rendered = "<span class=\"ooc [ooc_class]\"><span class=\"prefix\">OOC:</span> <span class=\"name\" data-ctx='\ref[src.mind]'>[display_name]:</span> <span class=\"message\">[msg]</span></span>"
|
|
|
|
if (C.holder)
|
|
rendered = "<span class='adminHearing' data-ctx='[C.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
|
|
boutput(C, rendered)
|
|
|
|
logTheThing("ooc", src, null, "OOC: [msg]")
|
|
|
|
/mob/verb/listen_looc()
|
|
set name = "(Un)Mute LOOC"
|
|
set desc = "Mute or Unmute Local Out Of Character chat."
|
|
|
|
if (src.client)
|
|
src.client.preferences.listen_looc = !src.client.preferences.listen_looc
|
|
if (src.client.preferences.listen_looc)
|
|
boutput(src, "<span style=\"color:blue\">You are now listening to messages on the LOOC channel.</span>")
|
|
else
|
|
boutput(src, "<span style=\"color:blue\">You are no longer listening to messages on the LOOC channel.</span>")
|
|
|
|
/mob/verb/looc(msg as text)
|
|
if (IsGuestKey(src.key))
|
|
boutput(src, "You are not authorized to communicate over these channels.")
|
|
return
|
|
if (oocban_isbanned(src))
|
|
boutput(src, "You are currently banned from using OOC and LOOC, you may appeal at https://forum.ss13.co/index.php")
|
|
return
|
|
|
|
msg = trim(copytext(html_encode(sanitize(msg)), 1, MAX_MESSAGE_LEN))
|
|
if (!msg)
|
|
return
|
|
else if (!src.client.preferences.listen_looc)
|
|
return
|
|
else if (!looc_allowed && !src.client.holder)
|
|
boutput(usr, "LOOC is currently disabled.")
|
|
return
|
|
else if (!dooc_allowed && !src.client.holder && (src.client.deadchat != 0))
|
|
boutput(usr, "LOOC for dead mobs has been turned off.")
|
|
return
|
|
else if (src.client && src.client.ismuted())
|
|
boutput(usr, "You are currently muted and cannot talk in LOOC.")
|
|
return
|
|
else if (findtext(msg, "byond://") && !src.client.holder)
|
|
boutput(src, "<B>Advertising other servers is not allowed.</B>")
|
|
logTheThing("admin", src, null, "has attempted to advertise in LOOC.")
|
|
logTheThing("diary", src, null, "has attempted to advertise in LOOC.", "admin")
|
|
message_admins("[key_name(src)] has attempted to advertise in LOOC.")
|
|
return
|
|
|
|
logTheThing("diary", src, null, ": [msg]", "ooc")
|
|
|
|
#ifdef DATALOGGER
|
|
game_stats.ScanText(msg)
|
|
#endif
|
|
|
|
var/list/recipients = list()
|
|
|
|
for (var/mob/M in range(LOOC_RANGE))
|
|
if (!M.client)
|
|
continue
|
|
if (M.client.preferences && !M.client.preferences.listen_looc)
|
|
continue
|
|
recipients += M.client
|
|
|
|
for (var/mob/M in mobs)
|
|
if (!M.client)
|
|
continue
|
|
if (recipients.Find(M.client))
|
|
continue
|
|
if (M.client.holder && !M.client.only_local_looc && !M.client.player_mode)
|
|
recipients += M.client
|
|
|
|
for (var/client/C in recipients)
|
|
// DEBUGGING
|
|
if (!C.preferences)
|
|
logTheThing("debug", null, null, "[C] (\ref[C]): client.preferences is null")
|
|
|
|
if (C.preferences && !C.preferences.listen_ooc)
|
|
continue
|
|
|
|
var looc_class = ""
|
|
var display_name = src.key
|
|
|
|
if (src.client.stealth || src.client.alt_key)
|
|
if (!C.holder)
|
|
display_name = src.client.fakekey
|
|
else
|
|
display_name += " (as [src.client.fakekey])"
|
|
|
|
if (src.client.holder && (!src.client.stealth || C.holder))
|
|
if (src.client.holder.level == LEVEL_BABBY)
|
|
looc_class = "gfartlooc"
|
|
else
|
|
looc_class = "adminlooc"
|
|
else if (src.client.is_mentor() && !src.client.stealth)
|
|
looc_class = "mentorlooc"
|
|
|
|
var/rendered = "<span class=\"looc [looc_class]\"><span class=\"prefix\">LOOC:</span> <span class=\"name\" data-ctx='\ref[src.mind]'>[display_name]:</span> <span class=\"message\">[msg]</span></span>"
|
|
|
|
if (C.holder)
|
|
rendered = "<span class='adminHearing' data-ctx='[C.chatOutput.getContextFlags()]'>[rendered]</span>"
|
|
|
|
boutput(C, rendered)
|
|
|
|
logTheThing("ooc", src, null, "LOOC: [msg]")
|
|
|
|
/mob/proc/heard_say(var/mob/other)
|
|
return
|
|
|
|
/mob/proc/lastgasp()
|
|
return
|
|
|
|
/mob/proc/item_attack_message(var/mob/T, var/obj/item/S, var/d_zone, var/devastating = 0)
|
|
if (d_zone)
|
|
return "<span style=\"color:red\"><B>[src] attacks [T] in the [d_zone] with [S][devastating ? " and lands a devastating hit!" : "!"]</B></span>"
|
|
else
|
|
return "<span style=\"color:red\"><B>[src] attacks [T] with [S] [devastating ? "and lands a devastating hit!" : "!"]</B></span>"
|
|
|
|
/mob/proc/get_age_pitch_for_talk()
|
|
if (!src.bioHolder || !src.bioHolder.age) return
|
|
var/modifier = 30
|
|
if (src.reagents && src.reagents.has_reagent("helium"))
|
|
modifier += 30
|
|
if (deep_farting)
|
|
modifier -= 120
|
|
if (modifier == 0)
|
|
modifier = 1
|
|
return 1.0 + (0.5*(modifier - src.bioHolder.age)/80) + ((src.gender == MALE) ? 0.1 : 0.3)
|
|
|
|
/mob/proc/get_age_pitch()
|
|
if (!src.bioHolder || !src.bioHolder.age) return
|
|
var/modifier = 30
|
|
if (src.reagents && src.reagents.has_reagent("helium"))
|
|
modifier += 30
|
|
if (deep_farting)
|
|
modifier -= 120
|
|
if (modifier == 0)
|
|
modifier = 1
|
|
return 1.0 + 0.5*(modifier - src.bioHolder.age)/80
|
|
|
|
/mob/proc/understands_language(var/langname)
|
|
if (langname == say_language)
|
|
return 1
|
|
if (langname == "english" || !langname)
|
|
return 1
|
|
if (langname == "monkey" && (monkeysspeakhuman || (bioHolder && bioHolder.HasEffect("monkey_speak"))))
|
|
return 1
|
|
return 0
|
|
|
|
/mob/proc/get_language_id(var/forced_language = null)
|
|
var/language = say_language
|
|
if (forced_language)
|
|
language = forced_language
|
|
return language
|
|
|
|
/mob/proc/process_language(var/message, var/forced_language = null)
|
|
var/datum/language/L = languages.language_cache[get_language_id(forced_language)]
|
|
if (!L)
|
|
L = languages.language_cache["english"]
|
|
return L.get_messages(message)
|
|
|
|
/mob/proc/get_special_language(var/secure_mode)
|
|
return null
|
|
|
|
/mob/proc/see(message)
|
|
if (!src.is_active())
|
|
return 0
|
|
boutput(src, message)
|
|
return 1
|
|
|
|
/mob/proc/show_viewers(message)
|
|
for(var/mob/M in AIviewers())
|
|
M.see(message)
|
|
|
|
/mob/verb/togglelocaldeadchat()
|
|
set desc = "Toggle whether you can hear all chat while dead or just local chat"
|
|
set name = "Toggle Deadchat Range"
|
|
|
|
if (!usr.client) //How could this even happen?
|
|
return
|
|
|
|
usr.client.local_deadchat = !usr.client.local_deadchat
|
|
boutput(usr, "<span style=\"color:blue\">[usr.client.local_deadchat ? "Now" : "No longer"] hearing local chat only.</span>")
|
|
|
|
/mob/proc/show_message(msg, type, alt, alt_type, group = "")
|
|
if (!src.client)
|
|
return
|
|
|
|
// We have procs to check for this stuff, you know. Ripped out a bunch of duplicate code, which also fixed earmuffs (Convair880).
|
|
if (type)
|
|
if ((type & 1) && !src.sight_check(1))
|
|
if (!alt)
|
|
return
|
|
else
|
|
msg = alt
|
|
type = alt_type
|
|
if ((type & 2) && !src.hearing_check(1))
|
|
if (!alt)
|
|
return
|
|
else
|
|
msg = alt
|
|
type = alt_type
|
|
if ((type & 1) && !src.sight_check(1))
|
|
return
|
|
|
|
if (isunconscious(src) || src.sleeping || src.getStatusDuration("paralysis"))
|
|
if (prob(20))
|
|
boutput(src, "<I>... You can almost hear something ...</I>")
|
|
if (isliving(src))
|
|
for (var/mob/dead/target_observer/observer in src:observers)
|
|
boutput(observer, "<I>... You can almost hear something ...</I>")
|
|
else
|
|
boutput(src, msg, group)
|
|
|
|
var/psychic_link = src.get_psychic_link()
|
|
if (ismob(psychic_link))
|
|
boutput(psychic_link, msg, group)
|
|
|
|
if (isliving(src))
|
|
for (var/mob/dead/target_observer/observer in src:observers)
|
|
boutput(observer, msg, group)
|
|
|
|
// Show a message to all mobs in sight of this one
|
|
// This would be for visible actions by the src mob
|
|
// message is the message output to anyone who can see e.g. "[src] does something!"
|
|
// self_message (optional) is what the src mob sees e.g. "You do something!"
|
|
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
|
|
|
/mob/visible_message(var/message, var/self_message, var/blind_message, var/group = "")
|
|
for (var/mob/M in AIviewers(src))
|
|
if (!M.client)
|
|
continue
|
|
var/msg = message
|
|
if (self_message && M==src)
|
|
msg = self_message
|
|
M.show_message(msg, 1, blind_message, 2, group)
|
|
|
|
// Show a message to all mobs in sight of this atom
|
|
// Use for objects performing visible actions
|
|
// message is output to anyone who can see, e.g. "The [src] does something!"
|
|
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
|
/atom/proc/visible_message(var/message, var/blind_message, var/group = "")
|
|
for (var/mob/M in AIviewers(src))
|
|
if (!M.client)
|
|
continue
|
|
M.show_message(message, 1, blind_message, 2, group)
|
|
|
|
// for things where there are three parties that should recieve different messages (specifically made for surgery):
|
|
// viewer_message, the thing visible to everyone except specified targets
|
|
// first_message, the thing visible to first_target
|
|
// second_message, the thing visible to second_target
|
|
// blind_message (optional) is what blind people will hear e.g. "You hear something!"
|
|
/mob/proc/tri_message(var/viewer_message, var/first_target, var/first_message, var/second_target, var/second_message, var/blind_message)
|
|
for (var/mob/M in AIviewers(src))
|
|
if (!M.client)
|
|
continue
|
|
var/msg = viewer_message
|
|
if (first_message && M == first_target)
|
|
msg = first_message
|
|
if (second_message && M == second_target && M != first_target)
|
|
msg = second_message
|
|
M.show_message(msg, 1, blind_message, 2)
|
|
//DEBUG_MESSAGE("<b>[M] recieves message: "[msg]"</b>")
|
|
|
|
// it was about time we had this instead of just visible_message()
|
|
/atom/proc/audible_message(var/message)
|
|
for (var/mob/M in all_hearers(null, src))
|
|
if (!M.client)
|
|
continue
|
|
M.show_message(message, 2)
|
|
|
|
/mob/audible_message(var/message, var/self_message)
|
|
for (var/mob/M in all_hearers(null, src))
|
|
if (!M.client)
|
|
continue
|
|
var/msg = message
|
|
if (self_message && M==src)
|
|
msg = self_message
|
|
M.show_message(msg, 2)
|
|
|
|
|
|
// FLOCKSAY
|
|
//#define FLOCK_SPEAKER_SYSTEM 1
|
|
//#define FLOCK_SPEAKER_ADMIN 2
|
|
//#define FLOCK_SPEAKER_FLOCKMIND 3
|
|
//#define FLOCK_SPEAKER_FLOCKTRACE 4
|
|
//#define FLOCK_SPEAKER_NPC 5
|
|
|
|
/proc/flock_speak(var/mob/speaker, var/message as text, var/datum/flock/flock, var/speak_as_admin=0)
|
|
|
|
var/client/C = null
|
|
if(speaker)
|
|
C = speaker.client
|
|
|
|
var/name = ""
|
|
var/is_npc = 0
|
|
var/is_flockmind = istype(speaker, /mob/living/intangible/flock/flockmind)
|
|
if(!speak_as_admin)
|
|
if(speaker)
|
|
message = speaker.say_quote(message)
|
|
else // system message
|
|
message = gradientText("#3cb5a3", "#124e43", "\"[message]\"")
|
|
message = "alerts, [message]"
|
|
if(istype(speaker, /mob/living/critter/flock/drone))
|
|
var/mob/living/critter/flock/drone/F = speaker
|
|
if(F.is_npc)
|
|
name = "Drone [F.real_name]"
|
|
is_npc = 1
|
|
else if(F.controller)
|
|
name = "[F.controller.real_name]"
|
|
if(istype(F.controller, /mob/living/intangible/flock/flockmind))
|
|
is_flockmind = 1
|
|
else if(speaker) // not set yet
|
|
name = speaker.real_name // final catch
|
|
|
|
var/rendered = ""
|
|
var/flockmindRendered = ""
|
|
var/class = "flocksay"
|
|
if(is_flockmind)
|
|
class = "flocksay flockmindsay"
|
|
if(is_npc)
|
|
class = "flocksay flocknpc"
|
|
if(isnull(speaker))
|
|
class = "flocksay bold italics"
|
|
name = "\[SYSTEM\]"
|
|
|
|
if(C && C.holder && speak_as_admin) // for admin verb flocksay
|
|
// admin mode go
|
|
var/show_other_key = 0
|
|
if (C.stealth || C.alt_key)
|
|
show_other_key = 1
|
|
rendered = "<span class='game [class]'><span class='bold'></span><span class='name'>ADMIN([show_other_key ? C.fakekey : C.key])</span> informs, <span class='message'>\"[message]\"</span></span>"
|
|
flockmindRendered = rendered // no need for URLs
|
|
else
|
|
rendered = "<span class='game [class]'><span class='bold'>\[[flock ? flock.name : "--.--"]\] </span><span class='name' [speaker ? "data-ctx='\ref[speaker.mind]'" : ""]>[name]</span> <span class='message'>[message]</span></span>"
|
|
flockmindRendered = "<span class='game [class]'><span class='bold'>\[[flock ? flock.name : "--.--"]\] </span><span class='name'>[flock ? "<a href='?src=\ref[flock.flockmind];origin=\ref[speaker]'>[name]</a>" : "[name]"]</span> <span class='message'>[message]</span></span>"
|
|
|
|
for (var/mob/M in mobs)
|
|
if(istype(M, /mob/new_player))
|
|
continue
|
|
|
|
var/thisR = ""
|
|
if (M.client)
|
|
if((isflock(M)) || (M.client.holder && !M.client.player_mode) || (isobserver(M) && !(istype(M, /mob/dead/target_observer/hivemind_observer))))
|
|
thisR = rendered
|
|
if(istype(M, /mob/living/intangible/flock/flockmind) && !(istype(speaker, /mob/living/intangible/flock/flockmind)) && M:flock == flock)
|
|
thisR = flockmindRendered
|
|
if ((istype(M, /mob/dead/observer)||M.client.holder) && speaker && speaker.mind)
|
|
thisR = "<span class='adminHearing' data-ctx='[M.client.chatOutput.getContextFlags()]'>[thisR]</span>"
|
|
if(thisR != "")
|
|
M.show_message(thisR, 2)
|