mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-22 19:47:22 +01:00
* adds antaghud icon * TGUI bundle build dont push changes i didnt stage challenge 2025 (IMPOSSIBLE) * Adds organ repair passive * Description fix * Runs prettier * Fixes desc 2 * Fix revert * Remove vamp text * Fix some CI + Partial refactor * Fixes CI * Fixes gamemodes I messed with * Moves these procs over * Description fix again * Add back limit requiring drainees to have ckeys * Adds terminator icon * Update code/datums/status_effects/buffs.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Update code/modules/surgery/organs/augments_internal.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/powers/flayer_stealth_powers.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * More lewv review * Clamps the EMP severity * Fixes "surveilance" typos * The TODO is gone and can't hurt me anymore * Update code/modules/antagonists/mind_flayer/flayer_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/game/objects/items/weapons/pneumaticCannon.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/game/objects/items/weapons/stunbaton.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * More lewc reviews * Update code/modules/antagonists/_common/antag_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/_common/antag_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_datum.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_power.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Fixes some camera bug issues + lewc reviews * Update code/modules/antagonists/mind_flayer/powers/flayer_passives.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/flayer_power.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Updates a comment and fixes whitespace * Autodocs flayerprod * Update code/modules/antagonists/mind_flayer/powers/flayer_mobility_powers.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * qdel things we dont need anymore + typing an argument of add_abillity * Remove debug log * Update code/modules/antagonists/mind_flayer/flayer_power.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * Slightly buffs, and fixes GC issues of tether * I no longer feel i am a mindflayer * Fixes formatting of greeting * Better greeting * Worlds shittiest sprite * Don't need this TODO anymore * Fixes double description * Changes the wording on the borg laws * and bundle too * The cannon uses shrapnel now * Initial style changes * Ratios for brain damage * Adds a chemical to test for flayerism * Fixes the brain damage ratios * Abilities are purchasable again * Updates TGUI properly * im sorry linter * Steam smoke * Hi bundle * Re-abstracts this proc post syndi orgs * Fixes gamemode logic post cling round removal * I WONT FORGET IT THIS TIME * Fix name of steam ability * I'm a fool * Fixes processed passives + removes debug message * Fixes updating abilities inside UI * Better description for quicksilver form * First part lewc review * Remove debug thingy * Apply suggestions from code review Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Fixes defines + GCs weapon spells * We don't need this * Eyes GC properly * Update code/modules/antagonists/mind_flayer/powers/flayer_mobility_powers.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * adds better logging to the assimilate * Adds parenthesis Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> * TGUI Bundle Rebuild * Fixes and Reworks TGUI * Cleaner JS and Fixes * adds anti-snitching clause to borg laws * changes the span for the borg messages * No holoparasites * Puts baton silence in line with glare * Fixes total_swarms_gathered * Nuke old trait * Gun no longer not stuck * Rejuv clears delayed knockdown * Some weapon ability fixes * Makes radio enable timers not counterintuitive * Fixes beepsky runtimes * Makes naming more consistent * Adds one-click-antag * Adds the mind flayer toggle (doesn't technically work) * Adds flayers to check_antagonist * Gives IDs to the status effects * Also this one * Makes retracting work again if it's in your offhand * Fixes pacification tech levels * Grapple is a weapon ability now, nullifcation retracts implants * Fixed descriptions * Adds some pizzaz to torque enhancer * This actually needs to be like this * Moves a helper proc over to a helper proc file * Extra admin visibility * Nukes the wacky flayer mob * Makes silicon administrative access more sane * Terminator form better description * Makes rejuv set stamina to 0 * Various price increases * AAAAAAAAAAAAA * Better feedback + logging on cyborg subversion * Swarm purchase display (temp fix) * Makes mindflayer sounds more silent * UI improvements * Various mindflayer fixes * Typo * More fixes * Fixes innates from being stupid * Forgot to add this check earlier * Oh this is how you add things to the protolathe * Changes some description and upgrade messages * Allows you to drain people beyond your limit * Fixes some weapon upgrade issues * Fix CI * Fixes some draining issues * More UI Tweaks and QoL * Fixes most of the issues * text * Fixes * Adds a radio jamming option to intruder * Gives obfusciation to jammer ability * Small passive cleanup * Fixes Search and Adds Ability Stages to UI * Adds freebie abilities * Restructuring chain and adding blackbox * Tgui polish * Small fix for traceroute * Fixes one click antag * Increases EMP resistance cost * Changes the pneumatic cannon into a shotgun * Slightly lower static * Fixed innate building rendering in upgrades * Fixes icon and description * Consistency * Punctuation fix. * Quick reboot + terminator form synergy * Adds safety deleting * Fix level for torque * Fixes a bad bug * Update code/game/gamemodes/objective.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Aaaaaaaaaaa * Makes torque a martial art and some martial arts safeties * Replaces vortex arm with barrier * Fix paths * Adds torque knockdown * Part 1 lewc review * HIIIII SQUIDWARD I'M IN YOUR BRANCH NOW * Removes flak cannon * Flayer respects mindshielding now on vamp+cling * Fixes EMP resist * More fixes * DGL review * Contra review * Clean up weapon powers * Various tweaks * Borg hand slight improvements * Parent call needs to be after this * Fixes stuff * Adds a new proc that is called when a spell is purchased * NEW SPRITES WOOOO * Traceroute update * Slightly lower traceroute cost * Formatting * Oops * Wow this could've been bad * Overclock small buff * Reduces cost of 1st level EMP immunity * Lewc review * TGUI Bundle Rebuild * Fix barricades * Lewc review * Okay FINE qwerty I'll change this * Traceroute thingy * I am an idiot * First part * Lewc review * Forgor this one * Last bits * Update code/game/objects/items/control_wand.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Update code/modules/antagonists/mind_flayer/powers/flayer_mobility_powers.dm Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Null * Static-ness * Update code/game/gamemodes/changeling/traitor_chan.dm Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Update code/__DEFINES/mindflayer_defines.dm Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> * Last bits --------- Signed-off-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Signed-off-by: BiancaWilkson <42818125+BiancaWilkson@users.noreply.github.com> Co-authored-by: DGamerL <daan.lyklema@gmail.com> Co-authored-by: DGamerL <108773801+DGamerL@users.noreply.github.com> Co-authored-by: Luc <89928798+lewcc@users.noreply.github.com> Co-authored-by: Burzah <116982774+Burzah@users.noreply.github.com> Co-authored-by: Qwertytoforty <52090703+Qwertytoforty@users.noreply.github.com>
465 lines
15 KiB
Plaintext
465 lines
15 KiB
Plaintext
GLOBAL_LIST_INIT(department_radio_keys, list(
|
|
":r" = "right ear", "#r" = "right ear", ".r" = "right ear",
|
|
":l" = "left ear", "#l" = "left ear", ".l" = "left ear",
|
|
":i" = "intercom", "#i" = "intercom", ".i" = "intercom",
|
|
":h" = "department", "#h" = "department", ".h" = "department",
|
|
":+" = "special", "#+" = "special", ".+" = "special", //activate radio-specific special functions
|
|
":c" = "Command", "#c" = "Command", ".c" = "Command",
|
|
":n" = "Science", "#n" = "Science", ".n" = "Science",
|
|
":m" = "Medical", "#m" = "Medical", ".m" = "Medical",
|
|
":x" = "Procedure", "#x" = "Procedure", ".x" = "Procedure",
|
|
":e" = "Engineering", "#e" = "Engineering", ".e" = "Engineering",
|
|
":s" = "Security", "#s" = "Security", ".s" = "Security",
|
|
":w" = "whisper", "#w" = "whisper", ".w" = "whisper",
|
|
":t" = "Syndicate", "#t" = "Syndicate", ".t" = "Syndicate",
|
|
":u" = "Supply", "#u" = "Supply", ".u" = "Supply",
|
|
":z" = "Service", "#z" = "Service", ".z" = "Service",
|
|
":p" = "AI Private", "#p" = "AI Private", ".p" = "AI Private",
|
|
|
|
":R" = "right ear", "#R" = "right ear", ".R" = "right ear",
|
|
":L" = "left ear", "#L" = "left ear", ".L" = "left ear",
|
|
":I" = "intercom", "#I" = "intercom", ".I" = "intercom",
|
|
":H" = "department", "#H" = "department", ".H" = "department",
|
|
":C" = "Command", "#C" = "Command", ".C" = "Command",
|
|
":N" = "Science", "#N" = "Science", ".N" = "Science",
|
|
":M" = "Medical", "#M" = "Medical", ".M" = "Medical",
|
|
":X" = "Procedure", "#X" = "Procedure", ".X" = "Procedure",
|
|
":E" = "Engineering", "#E" = "Engineering", ".E" = "Engineering",
|
|
":S" = "Security", "#S" = "Security", ".S" = "Security",
|
|
":W" = "whisper", "#W" = "whisper", ".W" = "whisper",
|
|
":T" = "Syndicate", "#T" = "Syndicate", ".T" = "Syndicate",
|
|
":U" = "Supply", "#U" = "Supply", ".U" = "Supply",
|
|
":Z" = "Service", "#Z" = "Service", ".Z" = "Service",
|
|
":P" = "AI Private", "#P" = "AI Private", ".P" = "AI Private",
|
|
":$" = "Response Team", "#$" = "Response Team", ".$" = "Response Team",
|
|
":-" = "Special Ops", "#-" = "Special Ops", ".-" = "Special Ops",
|
|
":_" = "SyndTeam", "#_" = "SyndTeam", "._" = "SyndTeam",
|
|
":~" = "cords", "#~" = "cords", ".~" = "cords"
|
|
))
|
|
|
|
GLOBAL_LIST_EMPTY(channel_to_radio_key)
|
|
|
|
/proc/get_radio_key_from_channel(channel)
|
|
var/key = GLOB.channel_to_radio_key[channel]
|
|
if(!key)
|
|
for(var/radio_key in GLOB.department_radio_keys)
|
|
if(GLOB.department_radio_keys[radio_key] == channel)
|
|
key = radio_key
|
|
break
|
|
if(!key)
|
|
key = ""
|
|
GLOB.channel_to_radio_key[channel] = key
|
|
|
|
return key
|
|
|
|
/mob/living/proc/binarycheck()
|
|
return FALSE
|
|
|
|
/mob/proc/get_default_language()
|
|
return null
|
|
|
|
/mob/living/get_default_language()
|
|
return default_language
|
|
|
|
/mob/living/proc/handle_speech_problems(list/message_pieces, verb)
|
|
var/robot = ismachineperson(src)
|
|
for(var/datum/multilingual_say_piece/S in message_pieces)
|
|
if(S.speaking && S.speaking.flags & NO_STUTTER)
|
|
continue
|
|
|
|
if(HAS_TRAIT(src, TRAIT_HULK) && health >= 25)
|
|
S.message = "[uppertext(S.message)]!!!"
|
|
verb = pick("yells", "roars", "hollers")
|
|
|
|
if(AmountSluring())
|
|
if(robot)
|
|
S.message = slur(S.message, list("@", "!", "#", "$", "%", "&", "?"))
|
|
else
|
|
S.message = slur(S.message)
|
|
verb = "slurs"
|
|
|
|
if(AmountStuttering())
|
|
S.message = stutter(S.message, getStaminaLoss(), robot)
|
|
verb = "stammers"
|
|
|
|
if(AmountCultSlurring())
|
|
S.message = cultslur(S.message)
|
|
verb = "slurs"
|
|
|
|
if(!IsVocal() || HAS_TRAIT(src, TRAIT_MUTE))
|
|
S.message = ""
|
|
return list("verb" = verb)
|
|
|
|
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
|
|
switch(message_mode)
|
|
if("whisper") //all mobs can whisper by default
|
|
whisper_say(message_pieces)
|
|
return 1
|
|
return 0
|
|
|
|
/mob/living/proc/handle_speech_sound()
|
|
var/list/returns[3]
|
|
returns[1] = null
|
|
returns[2] = null
|
|
returns[3] = null
|
|
return returns
|
|
|
|
|
|
/mob/living/say(message, verb = "says", sanitize = TRUE, ignore_speech_problems = FALSE, ignore_atmospherics = FALSE, ignore_languages = FALSE)
|
|
if(client)
|
|
if(check_mute(client.ckey, MUTE_IC))
|
|
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
|
return FALSE
|
|
|
|
if(sanitize)
|
|
if(speaks_ooc)
|
|
if(GLOB.configuration.general.enable_ooc_emoji)
|
|
message = emoji_parse(sanitize(message))
|
|
else
|
|
message = sanitize(message)
|
|
else
|
|
message = sanitize_for_ic(message)
|
|
|
|
if(stat)
|
|
if(stat == DEAD)
|
|
return say_dead(message)
|
|
return FALSE
|
|
|
|
var/message_mode = parse_message_mode(message, "headset")
|
|
|
|
if(copytext(message, 1, 2) == "*")
|
|
return emote(copytext(message, 2), intentional = TRUE)
|
|
|
|
//parse the radio code and consume it
|
|
if(message_mode)
|
|
if(message_mode == "headset")
|
|
message = copytext_char(message, 2) //it would be really nice if the parse procs could do this for us.
|
|
else
|
|
message = copytext_char(message, 3)
|
|
|
|
message = trim_left(message)
|
|
|
|
//parse the language code and consume it
|
|
var/list/message_pieces = list()
|
|
if(ignore_languages)
|
|
message_pieces = message_to_multilingual(message)
|
|
else
|
|
message_pieces = parse_languages(message)
|
|
|
|
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
|
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
|
S.speaking.broadcast(src, S.message)
|
|
return 1
|
|
|
|
|
|
if(!LAZYLEN(message_pieces))
|
|
. = FALSE
|
|
CRASH("Message failed to generate pieces. [message] - [json_encode(message_pieces)]")
|
|
|
|
if(message_mode == "cords")
|
|
if(iscarbon(src))
|
|
var/mob/living/carbon/C = src
|
|
var/obj/item/organ/internal/vocal_cords/V = C.get_int_organ(/obj/item/organ/internal/vocal_cords)
|
|
if(V && V.can_speak_with())
|
|
C.say(V.handle_speech(message), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
|
|
V.speak_with(message) //words come before actions
|
|
return TRUE
|
|
|
|
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
|
verb = say_quote(message, first_piece.speaking)
|
|
|
|
if(is_muzzled())
|
|
var/obj/item/clothing/mask/muzzle/G = wear_mask
|
|
if(G.mute == MUZZLE_MUTE_ALL) //if the mask is supposed to mute you completely or just muffle you
|
|
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
|
return
|
|
else if(G.mute == MUZZLE_MUTE_MUFFLE)
|
|
muffledspeech_all(message_pieces)
|
|
verb = "mumbles"
|
|
|
|
if(is_facehugged())
|
|
muffledspeech_all(message_pieces)
|
|
verb = "gurgles"
|
|
|
|
if(!ignore_speech_problems)
|
|
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
|
verb = hsp["verb"]
|
|
|
|
if(cannot_speak_loudly())
|
|
return whisper(message)
|
|
|
|
// Do this so it gets logged for all types of communication
|
|
var/log_message = "[message_mode ? "([message_mode])" : ""] '[message]'"
|
|
create_log(SAY_LOG, log_message)
|
|
|
|
var/list/used_radios = list()
|
|
if(handle_message_mode(message_mode, message_pieces, verb, used_radios))
|
|
return TRUE
|
|
|
|
// Log of what we've said, plain message, no spans or junk
|
|
// handle_message_mode should have logged this already if it handled it
|
|
say_log += log_message
|
|
log_say(log_message, src)
|
|
|
|
var/list/handle_v = handle_speech_sound()
|
|
var/sound/speech_sound = handle_v[1]
|
|
var/sound_vol = handle_v[2]
|
|
var/sound_frequency = handle_v[3]
|
|
|
|
var/italics = 0
|
|
var/message_range = world.view
|
|
|
|
//speaking into radios
|
|
if(length(used_radios))
|
|
italics = TRUE
|
|
message_range = 1
|
|
if(first_piece.speaking)
|
|
message_range = first_piece.speaking.get_talkinto_msg_range(message)
|
|
|
|
var/msg
|
|
if((!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG)) && client)
|
|
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
|
|
var/static/list/special_radio_channels = list("Syndicate", "SyndTeam", "Security", "Procedure", "Command", "Response Team", "Special Ops")
|
|
if(message_mode in special_radio_channels)
|
|
SEND_SOUND(src, sound('sound/items/radio_security.ogg', volume = rand(4, 16) * 5 * client.prefs.get_channel_volume(CHANNEL_RADIO_NOISE), channel = CHANNEL_RADIO_NOISE))
|
|
else
|
|
SEND_SOUND(src, sound('sound/items/radio_common.ogg', volume = rand(4, 16) * 5 * client.prefs.get_channel_volume(CHANNEL_RADIO_NOISE), channel = CHANNEL_RADIO_NOISE))
|
|
|
|
if(msg)
|
|
for(var/mob/living/M in hearers(5, src) - src)
|
|
M.show_message(msg)
|
|
|
|
if(speech_sound)
|
|
sound_vol *= 0.5
|
|
|
|
|
|
var/turf/T = get_turf(src)
|
|
var/list/listening = list()
|
|
var/list/listening_obj = list()
|
|
|
|
message_range += extra_message_range
|
|
|
|
if(T)
|
|
//make sure the air can transmit speech - speaker's side
|
|
var/datum/gas_mixture/environment = T.get_readonly_air()
|
|
var/pressure = environment ? environment.return_pressure() : 0
|
|
if(!ignore_atmospherics)
|
|
if(pressure < SOUND_MINIMUM_PRESSURE)
|
|
message_range = 1
|
|
|
|
if(pressure < ONE_ATMOSPHERE * 0.4) //sound distortion pressure, to help clue people in that the air is thin, even if it isn't a vacuum yet
|
|
italics = TRUE
|
|
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
|
|
|
|
var/list/hear = hear(message_range, T)
|
|
var/list/hearturfs = list()
|
|
|
|
for(var/I in hear)
|
|
if(ismob(I))
|
|
var/mob/M = I
|
|
listening += M
|
|
hearturfs += get_turf(M)
|
|
for(var/obj/O in M.contents)
|
|
listening_obj |= O
|
|
if(isobj(I))
|
|
var/obj/O = I
|
|
hearturfs += get_turf(O)
|
|
listening_obj |= O
|
|
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(!M.client)
|
|
continue
|
|
|
|
if(isnewplayer(M))
|
|
continue
|
|
|
|
if(isobserver(M))
|
|
if(M.get_preference(PREFTOGGLE_CHAT_GHOSTEARS) && client) // The client check is so that ghosts don't have to listen to mice.
|
|
listening |= M
|
|
continue
|
|
|
|
if(message_range < world.view && (get_dist(T, M) <= world.view))
|
|
listening |= M
|
|
continue
|
|
|
|
if(get_turf(M) in hearturfs)
|
|
listening |= M
|
|
|
|
var/list/speech_bubble_recipients = list()
|
|
var/speech_bubble_test = say_test(message)
|
|
|
|
for(var/mob/M in listening)
|
|
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol, sound_frequency)
|
|
if(M.client)
|
|
speech_bubble_recipients.Add(M.client)
|
|
|
|
if(loc && !isturf(loc))
|
|
var/atom/A = loc //Non-turf, let it handle the speech bubble
|
|
A.speech_bubble("[A.bubble_icon][speech_bubble_test]", A, speech_bubble_recipients)
|
|
else //Turf, leave speech bubbles to the mob
|
|
speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
|
|
|
|
for(var/obj/O in listening_obj)
|
|
spawn(0) // KILL THIS
|
|
if(O) //It's possible that it could be deleted in the meantime.
|
|
O.hear_talk(src, message_pieces, verb)
|
|
|
|
return TRUE
|
|
|
|
/obj/effect/speech_bubble
|
|
var/mob/parent
|
|
|
|
/mob/living/proc/GetVoice()
|
|
return name
|
|
|
|
/mob/living/whisper(message as text)
|
|
message = trim_strip_html_tags(message)
|
|
|
|
//parse the language code and consume it
|
|
var/list/message_pieces = parse_languages(message)
|
|
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quirk to just easily deal with HIVEMIND languages
|
|
var/datum/multilingual_say_piece/S = message_pieces // Yay BYOND's hilarious typecasting
|
|
S.speaking.broadcast(src, S.message)
|
|
return 1
|
|
// Log it here since it skips the default way say handles it
|
|
create_log(SAY_LOG, "(whisper) '[message]'")
|
|
whisper_say(message_pieces)
|
|
|
|
// for weird circumstances where you're inside an atom that is also you, like pai's
|
|
/mob/living/proc/get_whisper_loc()
|
|
return src
|
|
|
|
/mob/living/proc/whisper_say(list/message_pieces, verb = "whispers")
|
|
if(client)
|
|
if(check_mute(client.ckey, MUTE_IC))
|
|
to_chat(src, "<span class='danger'>You cannot speak in IC (Muted).</span>")
|
|
return
|
|
|
|
if(stat)
|
|
return
|
|
|
|
if(is_muzzled())
|
|
if(istype(wear_mask, /obj/item/clothing/mask/muzzle/tapegag)) //just for tape
|
|
to_chat(src, "<span class='danger'>Your mouth is taped and you cannot speak!</span>")
|
|
else
|
|
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
|
|
return
|
|
|
|
if(is_facehugged())
|
|
to_chat(src, "<span class='danger'>You can't get a word out with this horrible creature on your face!</span>")
|
|
return
|
|
|
|
var/message = multilingual_to_message(message_pieces)
|
|
|
|
say_log += "whisper: [message]"
|
|
log_whisper(message, src)
|
|
var/message_range = 1
|
|
var/eavesdropping_range = 2
|
|
var/watching_range = 5
|
|
var/italics = 1
|
|
var/adverb_added = FALSE
|
|
var/not_heard //the message displayed to people who could not hear the whispering
|
|
|
|
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
|
|
if(first_piece.speaking)
|
|
if(first_piece.speaking.whisper_verb)
|
|
verb = first_piece.speaking.whisper_verb
|
|
not_heard = "[verb] something"
|
|
else
|
|
var/adverb = pick("quietly", "softly")
|
|
adverb_added = TRUE
|
|
verb = "[first_piece.speaking.speech_verb] [adverb]"
|
|
not_heard = "[first_piece.speaking.speech_verb] something [adverb]"
|
|
else
|
|
not_heard = "[verb] something"
|
|
|
|
var/list/hsp = handle_speech_problems(message_pieces, verb)
|
|
verb = hsp["verb"]
|
|
if(verb == "yells loudly")
|
|
verb = "slurs emphatically"
|
|
else if(!adverb_added)
|
|
var/adverb = pick("quietly", "softly")
|
|
verb = "[verb] [adverb]"
|
|
|
|
var/atom/whisper_loc = get_whisper_loc()
|
|
var/list/listening = hear(message_range, whisper_loc)
|
|
listening |= src
|
|
|
|
var/list/hearturfs = list()
|
|
|
|
// Pass whispers on to anything inside the immediate listeners.
|
|
// This comes before the ghosts do so that ghosts don't act as whisper relays
|
|
for(var/atom/L in listening)
|
|
if(ismob(L))
|
|
for(var/mob/C in L.contents)
|
|
if(isliving(C))
|
|
listening += C
|
|
hearturfs += get_turf(L)
|
|
if(isobj(L))
|
|
hearturfs += get_turf(L)
|
|
|
|
// Loop through all players to see if they need to hear it.
|
|
for(var/mob/M in GLOB.player_list)
|
|
if(!M.client)
|
|
continue
|
|
|
|
if(isnewplayer(M))
|
|
continue
|
|
|
|
if(isobserver(M))
|
|
if(M.get_preference(PREFTOGGLE_CHAT_GHOSTEARS)) // The client check is so that ghosts don't have to listen to mice.
|
|
listening |= M
|
|
continue
|
|
|
|
if(message_range < world.view && (get_dist(whisper_loc, M) <= world.view))
|
|
listening |= M
|
|
continue
|
|
|
|
if(get_turf(M) in hearturfs)
|
|
listening |= M
|
|
|
|
//pass on the message to objects that can hear us.
|
|
for(var/obj/O in view(message_range, whisper_loc))
|
|
spawn(0)
|
|
if(O)
|
|
O.hear_talk(src, message_pieces, verb)
|
|
|
|
var/list/eavesdropping = hearers(eavesdropping_range, whisper_loc)
|
|
eavesdropping -= src
|
|
eavesdropping -= listening
|
|
|
|
var/list/watching = hearers(watching_range, whisper_loc)
|
|
watching -= src
|
|
watching -= listening
|
|
watching -= eavesdropping
|
|
|
|
//now mobs
|
|
var/list/speech_bubble_recipients = list()
|
|
var/speech_bubble_test = say_test(message)
|
|
|
|
for(var/mob/M in listening)
|
|
M.hear_say(message_pieces, verb, italics, src, use_voice = FALSE)
|
|
if(M.client)
|
|
speech_bubble_recipients.Add(M.client)
|
|
|
|
if(length(eavesdropping))
|
|
stars_all(message_pieces) //hopefully passing the message twice through stars() won't hurt... I guess if you already don't understand the language, when they speak it too quietly to hear normally you would be able to catch even less.
|
|
for(var/mob/M in eavesdropping)
|
|
M.hear_say(message_pieces, verb, italics, src, use_voice = FALSE)
|
|
if(M.client)
|
|
speech_bubble_recipients.Add(M.client)
|
|
|
|
speech_bubble("[bubble_icon][speech_bubble_test]", src, speech_bubble_recipients)
|
|
|
|
if(length(watching))
|
|
var/rendered = "<span class='game say'><span class='name'>[name]</span> [not_heard].</span>"
|
|
for(var/mob/M in watching)
|
|
M.show_message(rendered, 2)
|
|
|
|
return 1
|
|
|
|
/mob/living/speech_bubble(bubble_state = "", bubble_loc = src, list/bubble_recipients = list())
|
|
var/image/I = image('icons/mob/talk.dmi', bubble_loc, bubble_state, FLY_LAYER)
|
|
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
|
|
INVOKE_ASYNC(GLOBAL_PROC, GLOBAL_PROC_REF(flick_overlay), I, bubble_recipients, 30)
|