Saycode Overhaul -- Multilingualism

This commit is contained in:
ShadowLarkens
2020-04-20 04:12:53 -04:00
committed by VirgoBot
parent 583472d42e
commit 139d5cd3c3
70 changed files with 1742 additions and 2641 deletions
+27 -48
View File
@@ -1,63 +1,42 @@
/mob/observer/dead/say(var/message)
/mob/observer/dead/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
if (!message)
return
log_ghostsay(message, src)
if (src.client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(src.client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<font color='red'>You cannot talk in deadchat (muted).</font>")
return
. = src.say_dead(message)
/mob/observer/dead/emote(var/act, var/type, var/message)
//message = sanitize(message) - already sanitized in verb/me_verb()
if(!message)
return
if(act != "me")
log_ghostsay(message, src)
if (client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<font color='red'>You cannot talk in deadchat (muted).</font>")
return
. = say_dead(message)
/mob/observer/dead/me_verb(message as text)
if(!message)
return
log_ghostemote(message, src)
if(src.client)
if(client)
if(message)
client.handle_spam_prevention(MUTE_DEADCHAT)
if(src.client.prefs.muted & MUTE_DEADCHAT)
if(client.prefs.muted & MUTE_DEADCHAT)
to_chat(src, "<font color='red'>You cannot emote in deadchat (muted).</font>")
return
. = src.emote_dead(message)
. = emote_dead(message)
/*
for (var/mob/M in hearers(null, null))
if (!M.stat)
if(M.job == "Chaplain")
if (prob (49))
M.show_message("<span class='game'><i>You hear muffled speech... but nothing is there...</i></span>", 2)
if(prob(20))
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
else
M.show_message("<span class='game'><i>You hear muffled speech... you can almost make out some words...</i></span>", 2)
// M.show_message("<span class='game'><i>[stutter(message)]</i></span>", 2)
if(prob(30))
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
else
if (prob(50))
return
else if (prob (95))
M.show_message("<span class='game'><i>You hear muffled speech... but nothing is there...</i></span>", 2)
if(prob(20))
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
else
M.show_message("<span class='game'><i>You hear muffled speech... you can almost make out some words...</i></span>", 2)
// M.show_message("<span class='game'><i>[stutter(message)]</i></span>", 2)
playsound(src.loc, pick('sound/effects/ghost.ogg','sound/effects/ghost2.ogg'), 10, 1)
*/
/mob/observer/dead/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear)
return "[speaker_name] ([ghost_follow_link(speaker, src)])"
/mob/observer/dead/handle_speaker_name(mob/speaker = null, vname, hard_to_hear)
var/speaker_name = ..()
//Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
if(speaker && (speaker_name != speaker.real_name) && !isAI(speaker))
speaker_name = "[speaker.real_name] ([speaker_name])"
return speaker_name
+119 -139
View File
@@ -1,54 +1,96 @@
// At minimum every mob has a hear_say proc.
/mob/proc/combine_message(var/list/message_pieces, var/verb, var/mob/speaker, always_stars = FALSE, var/radio = FALSE)
var/iteration_count = 0
var/msg = "" // This is to make sure that the pieces have actually added something
. = "[verb], \""
for(var/datum/multilingual_say_piece/SP in message_pieces)
iteration_count++
var/piece = SP.message
if(piece == "")
continue
/mob/proc/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
if(SP.speaking && SP.speaking.flags & INNATE) // Snowflake for noise lang
if(radio)
return SP.speaking.format_message_radio(piece)
else
return SP.speaking.format_message(piece)
if(iteration_count == 1)
piece = capitalize(piece)
if(always_stars)
piece = stars(piece)
else if(!say_understands(speaker, SP.speaking))
piece = saypiece_scramble(SP)
if(isliving(speaker))
var/mob/living/S = speaker
if(istype(S.say_list) && length(S.say_list.speak))
piece = pick(S.say_list.speak)
if(!SP.speaking) // Catch the most generic case first
piece = "<span class='message body'>[piece]</span>"
else if(radio) // SP.speaking == TRUE enforced by previous !SP.speaking
piece = SP.speaking.format_message_radio(piece)
else // SP.speaking == TRUE && radio == FALSE
piece = SP.speaking.format_message(piece)
msg += (piece + " ")
if(msg == "")
// There is literally no content left in this message, we need to shut this shit down
. = "" // hear_say will suppress it
else
. = trim(. + trim(msg))
. += "\""
/mob/proc/saypiece_scramble(datum/multilingual_say_piece/SP)
if(SP.speaking)
return SP.speaking.scramble(SP.message)
else
return stars(SP.message)
/mob/proc/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
if(!client && !teleop)
return
return FALSE
if(speaker && !speaker.client && istype(src,/mob/observer/dead) && is_preference_enabled(/datum/client_preference/ghost_ears) && !(speaker in view(src)))
if(isobserver(src) && is_preference_enabled(/datum/client_preference/ghost_ears))
if(speaker && !speaker.client && !(speaker in view(src)))
//Does the speaker have a client? It's either random stuff that observers won't care about (Experiment 97B says, 'EHEHEHEHEHEHEHE')
//Or someone snoring. So we make it where they won't hear it.
return
return FALSE
//make sure the air can transmit speech - hearer's side
var/turf/T = get_turf(src)
if ((T) && (!(istype(src, /mob/observer/dead)))) //Ghosts can hear even in vacuum.
if(T && !isobserver(src)) //Ghosts can hear even in vacuum.
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE && get_dist(speaker, src) > 1)
return
return FALSE
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
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 = 1
sound_vol *= 0.5 //muffle the sound a bit, so it's like we're actually talking through contact
if(sleeping || stat == 1)
hear_sleep(message)
return
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if (language && (language.flags & NONVERBAL))
if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src)))
message = stars(message)
if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages
if(!say_understands(speaker,language))
if(language)
message = language.scramble(message, languages)
else
message = stars(message)
var/speaker_name = speaker.name
if(istype(speaker, /mob/living/carbon/human))
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
speaker_name = H.GetVoice()
var/message = combine_message(message_pieces, verb, speaker)
if(message == "")
return
if(sleeping || stat == UNCONSCIOUS)
hear_sleep(message)
return FALSE
if(italics)
message = "<i>[message]</i>"
message = encode_html_emphasis(message)
var/track = null
if(istype(src, /mob/observer/dead))
if(isobserver(src))
if(italics && is_preference_enabled(/datum/client_preference/ghost_radio))
return
if(speaker_name != speaker.real_name && speaker.real_name)
@@ -58,31 +100,27 @@
message = "<b>[message]</b>"
if(is_deaf())
if(!language || !(language.flags & INNATE)) // INNATE is the flag for audible-emote-language, so we don't want to show an "x talks but you cannot hear them" message if it's set
if(speaker == src)
to_chat(src, "<span class='warning'>You cannot hear yourself speak!</span>")
else
to_chat(src, "<span class='name'>[speaker_name]</span>[alt_name] talks but you cannot hear.")
if(speaker == src)
to_chat(src, "<span class='filter_say'><span class='warning'>You cannot hear yourself speak!</span></span>")
else
to_chat(src, "<span class='filter_say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] makes a noise, possibly speech, but you cannot hear them.</span>")
else
var/message_to_send = null
if(language)
message_to_send = "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][language.format_message(message, verb)]</span>"
else
message_to_send = "<span class='game say'><span class='name'>[speaker_name]</span>[alt_name] [track][verb], <span class='message'><span class='body'>\"[message]\"</span></span></span>"
if(check_mentioned(message) && is_preference_enabled(/datum/client_preference/check_mention))
message_to_send = "<span class='game say'><span class='name'>[speaker_name]</span>[speaker.GetAltName()] [track][message]</span>"
if(check_mentioned(multilingual_to_message(message_pieces)) && is_preference_enabled(/datum/client_preference/check_mention))
message_to_send = "<font size='3'><b>[message_to_send]</b></font>"
on_hear_say(message_to_send)
if (speech_sound && (get_dist(speaker, src) <= world.view && src.z == speaker.z))
var/turf/source = speaker? get_turf(speaker) : get_turf(src)
src.playsound_local(source, speech_sound, sound_vol, 1)
if(speech_sound && (get_dist(speaker, src) <= world.view && z == speaker.z))
var/turf/source = speaker ? get_turf(speaker) : get_turf(src)
playsound_local(source, speech_sound, sound_vol, 1)
// Done here instead of on_hear_say() since that is NOT called if the mob is clientless (which includes most AI mobs).
/mob/living/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
/mob/living/hear_say(var/list/message_pieces, var/verb = "says", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
..()
if(has_AI()) // Won't happen if no ai_holder exists or there's a player inside w/o autopilot active.
ai_holder.on_hear_say(speaker, message)
ai_holder.on_hear_say(speaker, multilingual_to_message(message_pieces))
/mob/proc/on_hear_say(var/message)
to_chat(src, message)
@@ -124,114 +162,25 @@
return tagged_message
/mob/proc/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
/mob/proc/hear_radio(var/list/message_pieces, var/verb = "says", var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname = "")
if(!client)
return
if(sleeping || stat==1) //If unconscious or sleeping
var/message = combine_message(message_pieces, verb, speaker, always_stars = hard_to_hear, radio = TRUE)
if(sleeping || stat == UNCONSCIOUS) //If unconscious or sleeping
hear_sleep(message)
return
var/track = null
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if (language && (language.flags & NONVERBAL))
if (!speaker || (src.sdisabilities & BLIND || src.blinded) || !(speaker in view(src)))
message = stars(message)
if(!(language && (language.flags & INNATE))) // skip understanding checks for INNATE languages
if(!say_understands(speaker,language))
if(language)
message = language.scramble(message, languages)
else
message = stars(message)
if(hard_to_hear)
message = stars(message)
var/speaker_name = speaker.name
if(vname)
speaker_name = vname
if(istype(speaker, /mob/living/carbon/human))
var/mob/living/carbon/human/H = speaker
if(H.voice)
speaker_name = H.voice
if(hard_to_hear)
speaker_name = "unknown"
var/changed_voice
if(istype(src, /mob/living/silicon/ai) && !hard_to_hear)
var/jobname // the mob's "job"
var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any.
if (ishuman(speaker))
var/mob/living/carbon/human/H = speaker
if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))
changed_voice = 1
var/list/impersonated = new()
var/mob/living/carbon/human/I = impersonated[speaker_name]
if(!I)
for(var/mob/living/carbon/human/M in mob_list)
if(M.real_name == speaker_name)
I = M
impersonated[speaker_name] = I
break
// If I's display name is currently different from the voice name and using an agent ID then don't impersonate
// as this would allow the AI to track I and realize the mismatch.
if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate)))
impersonating = I
jobname = impersonating.get_assignment()
else
jobname = "Unknown"
else
jobname = H.get_assignment()
else if (iscarbon(speaker)) // Nonhuman carbon mob
jobname = "No id"
else if (isAI(speaker))
jobname = "AI"
else if (isrobot(speaker))
jobname = "Cyborg"
else if (istype(speaker, /mob/living/silicon/pai))
jobname = "Personal AI"
else
jobname = "Unknown"
if(changed_voice)
if(impersonating)
track = "<a href='byond://?src=\ref[src];trackname=[html_encode(speaker_name)];track=\ref[impersonating]'>[speaker_name] ([jobname])</a>"
else
track = "[speaker_name] ([jobname])"
else
track = "<a href='byond://?src=\ref[src];trackname=[html_encode(speaker_name)];track=\ref[speaker]'>[speaker_name] ([jobname])</a>"
if(istype(src, /mob/observer/dead))
if(speaker_name != speaker.real_name && !isAI(speaker)) //Announce computer and various stuff that broadcasts doesn't use it's real name but AI's can't pretend to be other mobs.
speaker_name = "[speaker.real_name] ([speaker_name])"
track = "[speaker_name] ([ghost_follow_link(speaker, src)])"
var/speaker_name = handle_speaker_name(speaker, vname, hard_to_hear)
var/track = handle_track(message, verb, speaker, speaker_name, hard_to_hear)
message = encode_html_emphasis(message)
var/formatted
if(language)
formatted = "[language.format_message_radio(message, verb)][part_c]"
else
formatted = "[verb], <span class=\"body\">\"[message]\"</span>[part_c]"
if((sdisabilities & DEAF) || ear_deaf)
if(prob(20))
to_chat(src, "<span class='warning'>You feel your headset vibrate but can hear nothing from it!</span>")
else
on_hear_radio(part_a, speaker_name, track, part_b, formatted)
on_hear_radio(part_a, speaker_name, track, part_b, message)
/proc/say_timestamp()
return "<span class='say_quote'>\[[stationtime2text()]\]</span>"
@@ -296,9 +245,40 @@
heardword = copytext(heardword,2)
if(copytext(heardword,-1) in punctuation)
heardword = copytext(heardword,1,length(heardword))
heard = "<span class = 'game_say'>...You hear something about...[heardword]</span>"
heard = "<span class='game say'>...You hear something about...[heardword]</span>"
else
heard = "<span class = 'game_say'>...<i>You almost hear someone talking</i>...</span>"
heard = "<span class='game say'>...<i>You almost hear someone talking</i>...</span>"
to_chat(src,heard)
to_chat(src, heard)
/mob/proc/handle_speaker_name(mob/speaker, vname, hard_to_hear)
var/speaker_name = "unknown"
if(speaker)
speaker_name = speaker.name
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
if(H.voice)
speaker_name = H.voice
if(vname)
speaker_name = vname
if(hard_to_hear)
speaker_name = "unknown"
return speaker_name
/mob/proc/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear)
return
/mob/proc/hear_holopad_talk(list/message_pieces, var/verb = "says", var/mob/speaker = null)
var/message = combine_message(message_pieces, verb, speaker)
var/name = speaker.name
if(!say_understands(speaker))
name = speaker.voice_name
var/rendered = "<span class='game say'><span class='name'>[name]</span> [message]</span>"
to_chat(src, rendered)
+11 -6
View File
@@ -5,12 +5,6 @@
key = ""
flags = RESTRICTED|NONGLOBAL|INNATE|NO_TALK_MSG|NO_STUTTER
/datum/language/noise/format_message(message, verb)
return "<span class='message'><span class='[colour]'>[message]</span></span>"
/datum/language/noise/format_message_plain(message, verb)
return message
/datum/language/noise/format_message_radio(message, verb)
return "<span class='[colour]'>[message]</span>"
@@ -143,6 +137,17 @@
var/obj/item/organ/external/hand/hands = locate() in speaker //you can't sign without hands
return (hands || !iscarbon(speaker))
/datum/language/sign/scramble(var/input, var/list/known_languages)
return stars(input)
// This is a little weird because broadcast is traditionally for hivemind languages
// But in practice, it's just a way for a language to override all other languages and bypass hear_say
// which is exactly what sign language does.
/datum/language/sign/broadcast(var/mob/living/speaker, var/message, var/speaker_mask)
log_say("(SIGN) [message]", speaker)
speaker.say_signlang(message, pick(signlang_verb), src)
// Silly language for those times when you try to talk a languague you normally can't
/datum/language/gibberish
name = LANGUAGE_GIBBERISH
+29 -29
View File
@@ -113,13 +113,13 @@
return scrambled_text
/datum/language/proc/format_message(message, verb)
return "[verb], <span class='message'><span class='[colour]'>\"[capitalize(message)]\"</span></span>"
return "<span class='message'><span class='[colour]'>[message]</span></span>"
/datum/language/proc/format_message_plain(message, verb)
return "[verb], \"[capitalize(message)]\""
return "[capitalize(message)]"
/datum/language/proc/format_message_radio(message, verb)
return "[verb], <span class='[colour]'>\"[capitalize(message)]\"</span>"
return "<span class='[colour]'>[capitalize(message)]</span>"
/datum/language/proc/get_talkinto_msg_range(message)
// if you yell, you'll be heard from two tiles over instead of one
@@ -129,7 +129,7 @@
log_say("(HIVE) [message]", speaker)
if(!speaker_mask) speaker_mask = speaker.name
message = format_message(message, get_spoken_verb(message))
message = "[get_spoken_verb(message)], \"[format_message(message, get_spoken_verb(message))]\""
for(var/mob/player in player_list)
player.hear_broadcast(src, speaker, speaker_mask, message)
@@ -233,36 +233,36 @@
return prefix in config.language_prefixes
//TBD
/mob/proc/check_lang_data()
. = ""
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
. += "<b>[L.name] ([get_language_prefix()][L.key])</b><br/>[L.desc]<br/><br/>"
/mob/living/check_lang_data()
. = ""
if(default_language)
. += "Current default language: [default_language] - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br/><br/>"
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
if(L == default_language)
. += "<b>[L.name] ([get_language_prefix()][L.key])</b> - default - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br/>[L.desc]<br/><br/>"
else if (can_speak(L))
. += "<b>[L.name] ([get_language_prefix()][L.key])</b> - <a href='byond://?src=\ref[src];default_lang=\ref[L]'>set default</a><br/>[L.desc]<br/><br/>"
else
. += "<b>[L.name] ([get_language_prefix()][L.key])</b> - cannot speak!<br/>[L.desc]<br/><br/>"
/mob/verb/check_languages()
set name = "Check Known Languages"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Languages</font></b><br/><br/>"
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
dat += "<b>[L.name] ([get_language_prefix()][L.key])</b><br/>[L.desc]<br/><br/>"
src << browse(dat, "window=checklanguage")
return
/mob/living/check_languages()
var/dat = "<b><font size = 5>Known Languages</font></b><br/><br/>"
if(default_language)
dat += "Current default language: [default_language] - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br/><br/>"
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
if(L == default_language)
dat += "<b>[L.name] ([get_language_prefix()][L.key])</b> - default - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br/>[L.desc]<br/><br/>"
else if (can_speak(L))
dat += "<b>[L.name] ([get_language_prefix()][L.key])</b> - <a href='byond://?src=\ref[src];default_lang=\ref[L]'>set default</a><br/>[L.desc]<br/><br/>"
else
dat += "<b>[L.name] ([get_language_prefix()][L.key])</b> - cannot speak!<br/>[L.desc]<br/><br/>"
src << browse(dat, "window=checklanguage")
var/datum/browser/popup = new(src, "checklanguage", "Known Languages", 420, 470)
popup.set_content(check_lang_data())
popup.open()
/mob/living/Topic(href, href_list)
if(href_list["default_lang"])
+4
View File
@@ -94,6 +94,10 @@
key = "l"
flags = WHITELISTED | SIGNLANG | NO_STUTTER | NONVERBAL
/datum/language/tajsign/broadcast(var/mob/living/speaker, var/message, var/speaker_mask)
log_say("(SIGN) [message]", speaker)
speaker.say_signlang(message, pick(signlang_verb), src)
/datum/language/tajsign/can_speak_special(var/mob/speaker) // TODO: If ever we make external organs assist languages, convert this over to the new format
var/list/allowed_species = list(SPECIES_TAJ, SPECIES_TESHARI) // Need a tail and ears and such to use this.
if(iscarbon(speaker))
+1 -1
View File
@@ -6,7 +6,7 @@
#define AUTOHISS_NUM 3
/mob/living/proc/handle_autohiss(message, datum/language/L)
/mob/proc/handle_autohiss(message, datum/language/L)
return message // no autohiss at this level
/mob/living/carbon/human/handle_autohiss(message, datum/language/L)
+2 -6
View File
@@ -144,12 +144,8 @@
/mob/living/bot/attack_ai(var/mob/user)
return attack_hand(user)
/mob/living/bot/say(var/message)
var/verb = "beeps"
message = sanitize(message)
..(message, null, verb)
/mob/living/bot/say_quote(var/message, var/datum/language/speaking = null)
return "beeps"
/mob/living/bot/speech_bubble_appearance()
return "machine"
+20 -2
View File
@@ -1,5 +1,4 @@
/mob/living/carbon/alien
name = "alien"
desc = "What IS that?"
icon = 'icons/mob/alien.dmi'
@@ -52,4 +51,23 @@
return //Consider adding cuffs and hats to this, for the sake of fun.
/mob/living/carbon/alien/cannot_use_vents()
return
return
/mob/living/carbon/alien/get_default_language()
if(default_language)
return default_language
return GLOB.all_languages["Xenomorph"]
/mob/living/carbon/alien/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "hisses"
var/ending = copytext(message, length(message))
if(speaking && (speaking.name != "Galactic Common")) //this is so adminbooze xenos speaking common have their custom verbs,
verb = speaking.get_spoken_verb(ending) //and use normal verbs for their own languages and non-common languages
else
if(ending == "!")
verb = "roars"
else if(ending == "?")
verb = "hisses curiously"
return verb
@@ -1,6 +1,5 @@
/mob/living/carbon/alien/diona/say_understands(var/mob/other,var/datum/language/speaking = null)
if (istype(other, /mob/living/carbon/human) && !speaking)
/mob/living/carbon/alien/diona/say_understands(var/mob/other, var/datum/language/speaking = null)
if(ishuman(other) && !speaking)
if(languages.len >= 2) // They have sucked down some blood.
return 1
return TRUE
return ..()
+46 -70
View File
@@ -1,131 +1,107 @@
/mob/living/carbon/alien/emote(var/act,var/m_type=1,var/message = null)
/mob/living/carbon/alien/emote(var/act, var/m_type=1, var/message = null)
var/param = null
if (findtext(act, "-", 1, null))
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
switch(act)
if ("me")
if(silent)
return
if (src.client)
if (client.prefs.muted & MUTE_IC)
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
return
if (stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if ("custom")
return custom_emote(m_type, message)
if("sign")
if (!src.restrained())
message = text("<B>The alien</B> signs[].", (text2num(param) ? text(" the number []", text2num(param)) : null))
m_type = 1
if ("burp")
if (!muzzled)
if(!restrained())
var/num = null
if(text2num(param))
num = "the number [text2num(param)]"
if(num)
message = "<B>[src]</B> signs [num]."
m_type = 1
if("burp")
if(!muzzled)
message = "<B>[src]</B> burps."
m_type = 2
if("deathgasp")
message = "<B>The [src.name]</B> lets out a waning guttural screech, green blood bubbling from its maw."
message = "<B>[src]</B> lets out a waning guttural screech, green blood bubbling from its maw."
m_type = 2
if("scratch")
if (!src.restrained())
message = "<B>The [src.name]</B> scratches."
if(!restrained())
message = "<B>[src]</B> scratches."
m_type = 1
if("whimper")
if (!muzzled)
message = "<B>The [src.name]</B> whimpers."
if(!muzzled)
message = "<B>[src]</B> whimpers."
m_type = 2
if("tail")
message = "<B>The [src.name]</B> waves its tail."
message = "<B>[src]</B> waves its tail."
m_type = 1
if("gasp")
message = "<B>The [src.name]</B> gasps."
message = "<B>[src]</B> gasps."
m_type = 2
if("shiver")
message = "<B>The [src.name]</B> shivers."
message = "<B>[src]</B> shivers."
m_type = 2
if("drool")
message = "<B>The [src.name]</B> drools."
message = "<B>[src]</B> drools."
m_type = 1
if("scretch")
if (!muzzled)
message = "<B>The [src.name]</B> scretches."
if(!muzzled)
message = "<B>[src]</B> scretches."
m_type = 2
if("choke")
message = "<B>The [src.name]</B> chokes."
message = "<B>[src]</B> chokes."
m_type = 2
if("moan")
message = "<B>The [src.name]</B> moans!"
message = "<B>[src]</B> moans!"
m_type = 2
if("nod")
message = "<B>The [src.name]</B> nods its head."
message = "<B>[src]</B> nods its head."
m_type = 1
// if("sit")
// message = "<B>The [src.name]</B> sits down." //Larvan can't sit down, /N
// message = "<B>[src]</B> sits down." //Larvan can't sit down, /N
// m_type = 1
if("sway")
message = "<B>The [src.name]</B> sways around dizzily."
message = "<B>[src]</B> sways around dizzily."
m_type = 1
if("sulk")
message = "<B>The [src.name]</B> sulks down sadly."
message = "<B>[src]</B> sulks down sadly."
m_type = 1
if("twitch")
message = "<B>The [src.name]</B> twitches."
message = "<B>[src]</B> twitches."
m_type = 1
if("twitch_v")
message = "<B>The [src.name]</B> twitches violently."
message = "<B>[src]</B> twitches violently."
m_type = 1
if("dance")
if (!src.restrained())
message = "<B>The [src.name]</B> dances around happily."
if(!restrained())
message = "<B>[src]</B> dances around happily."
m_type = 1
if("roll")
if (!src.restrained())
message = "<B>The [src.name]</B> rolls."
if(!restrained())
message = "<B>[src]</B> rolls."
m_type = 1
if("shake")
message = "<B>The [src.name]</B> shakes its head."
message = "<B>[src]</B> shakes its head."
m_type = 1
if("gnarl")
if (!muzzled)
message = "<B>The [src.name]</B> gnarls and shows its teeth.."
if(!muzzled)
message = "<B>[src]</B> gnarls and shows its teeth.."
m_type = 2
if("jump")
message = "<B>The [src.name]</B> jumps!"
message = "<B>[src]</B> jumps!"
m_type = 1
if("hiss_")
message = "<B>The [src.name]</B> hisses softly."
message = "<B>[src]</B> hisses softly."
m_type = 1
if("collapse")
Paralyse(2)
message = text("<B>[]</B> collapses!", src)
message = "<B>[src]</B> collapses!"
m_type = 2
if("chirp")
message = "<B>The [src.name]</B> chirps!"
playsound(src.loc, 'sound/misc/nymphchirp.ogg', 50, 0)
message = "<B>[src]</B> chirps!"
playsound(loc, 'sound/misc/nymphchirp.ogg', 50, 0)
m_type = 2
if("help")
to_chat(src, "burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper")
else
to_chat(src, "Invalid Emote: [act]")
if ((message && src.stat == 0))
log_emote(message, src)
if (m_type & 1)
for(var/mob/O in viewers(src, null))
O.show_message(message, m_type)
//Foreach goto(703)
else
for(var/mob/O in hearers(src, null))
O.show_message(message, m_type)
//Foreach goto(746)
return
to_chat(src, "<span class='filter_say'>burp, chirp, choke, collapse, dance, drool, gasp, shiver, gnarl, jump, moan, nod, roll, scratch,\nscretch, shake, sign-#, sulk, sway, tail, twitch, whimper</span>")
if(!stat)
..(act, m_type, message)
@@ -1,25 +0,0 @@
/mob/living/carbon/alien/say(var/message)
var/verb = "says"
var/message_range = world.view
if(client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<font color='red'>You cannot speak in IC (Muted).</font>")
return
message = sanitize(message)
if(stat == 2)
return say_dead(message)
if(copytext(message,1,2) == "*")
return emote(copytext(message,2))
var/datum/language/speaking = parse_language(message)
message = trim(message)
if(!message || stat)
return
..(message, speaking, verb, null, null, message_range, null)
+8 -25
View File
@@ -18,36 +18,19 @@
/mob/living/carbon/brain/Destroy()
if(key) //If there is a mob connected to this thing. Have to check key twice to avoid false death reporting.
if(stat!=DEAD) //If not dead.
if(stat != DEAD) //If not dead.
death(1) //Brains can die again. AND THEY SHOULD AHA HA HA HA HA HA
ghostize() //Ghostize checks for key so nothing else is necessary.
return ..()
/mob/living/carbon/brain/say_understands(var/other)//Goddamn is this hackish, but this say code is so odd
if (istype(other, /mob/living/silicon/ai))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
if (istype(other, /mob/living/silicon/decoy))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
if (istype(other, /mob/living/silicon/pai))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
if (istype(other, /mob/living/silicon/robot))
if(!(container && istype(container, /obj/item/device/mmi)))
return 0
else
return 1
if (istype(other, /mob/living/carbon/human))
return 1
if (istype(other, /mob/living/simple_mob/slime))
return 1
if(istype(container, /obj/item/device/mmi))
if(issilicon(other))
return TRUE
if(ishuman(other))
return TRUE
if(isslime(other))
return TRUE
return ..()
/mob/living/carbon/brain/update_canmove()
+15 -48
View File
@@ -2,79 +2,46 @@
if(!(container && istype(container, /obj/item/device/mmi)))//No MMI, no emotes
return
if (findtext(act, "-", 1, null))
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
if(src.stat == DEAD)
if(stat == DEAD)
return
switch(act)
if ("me")
if(silent)
return
if (src.client)
if (client.prefs.muted & MUTE_IC)
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
return
if (stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if ("custom")
return custom_emote(m_type, message)
if ("alarm")
if("alarm")
to_chat(src, "You sound an alarm.")
message = "<B>[src]</B> sounds an alarm."
m_type = 2
if ("alert")
if("alert")
to_chat(src, "You let out a distressed noise.")
message = "<B>[src]</B> lets out a distressed noise."
m_type = 2
if ("notice")
if("notice")
to_chat(src, "You play a loud tone.")
message = "<B>[src]</B> plays a loud tone."
m_type = 2
if ("flash")
if("flash")
message = "The lights on <B>[src]</B> flash quickly."
m_type = 1
if ("blink")
if("blink")
message = "<B>[src]</B> blinks."
m_type = 1
if ("whistle")
if("whistle")
to_chat(src, "You whistle.")
message = "<B>[src]</B> whistles."
m_type = 2
if ("beep")
if("beep")
to_chat(src, "You beep.")
message = "<B>[src]</B> beeps."
m_type = 2
if ("boop")
if("boop")
to_chat(src, "You boop.")
message = "<B>[src]</B> boops."
m_type = 2
if ("help")
to_chat(src, "alarm,alert,notice,flash,blink,whistle,beep,boop")
else
to_chat(src, "<font color='blue'>Unusable emote '[act]'. Say *help for a list.</font>")
if("help")
to_chat(src, "<span class='filter_say'>alarm, alert, notice, flash, blink, whistle, beep, boop</span>")
if (message)
log_emote(message, src)
for(var/mob/M in dead_mob_list)
if (!M.client || istype(M, /mob/new_player))
continue //skip monkeys, leavers, and new_players
if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_sight) && !(M in viewers(src,null)))
M.show_message(message)
if (m_type & 1)
for (var/mob/O in viewers(src, null))
O.show_message(message, m_type)
else if (m_type & 2)
for (var/mob/O in hearers(src.loc, null))
O.show_message(message, m_type)
if(!stat)
..(act, m_type, message)
+7 -24
View File
@@ -1,6 +1,6 @@
//TODO: Convert this over for languages.
/mob/living/carbon/brain/say(var/message)
if (silent)
/mob/living/carbon/brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silent)
return
message = sanitize(message)
@@ -8,39 +8,22 @@
if(!(container && container.can_speak))
return //Certain objects can speak, like MMIs. Most others cannot. -Q
else
var/datum/language/speaking = parse_language(message)
if(speaking)
message = copytext(message, 2+length(speaking.key))
var/verb = "says"
var/ending = copytext(message, length(message))
if (speaking)
verb = speaking.get_spoken_verb(ending)
else
if(ending=="!")
verb=pick("exclaims","shouts","yells")
if(ending=="?")
verb="asks"
if(prob(emp_damage*4))
if(prob(emp_damage * 4))
if(prob(10))//10% chance to drop the message entirely
return
else
message = Gibberish(message, (emp_damage*6))//scrambles the message, gets worse when emp_damage is higher
if(speaking && speaking.flags & HIVEMIND)
speaking.broadcast(src,trim(message))
return
..()
..(trim(message), speaking, verb)
/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/carbon/brain/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
var/obj/item/device/mmi/R = container
if (R.radio && R.radio.radio_enabled)
if(R.radio && R.radio.radio_enabled)
if(message_mode == "general")
message_mode = null
return R.radio.talk_into(src,message,message_mode,verb,speaking)
return R.radio.talk_into(src, message, message_mode, verb, speaking)
else
to_chat(src, "<span class='danger'>Your radio is disabled.</span>")
return 0
+139 -138
View File
@@ -3,29 +3,26 @@
var/datum/gender/T = gender_datums[get_visible_gender()]
if (findtext(act, "-", 1, null))
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/muzzled = is_muzzled()
//var/m_type = 1
for(var/obj/item/organ/O in src.organs)
for (var/obj/item/weapon/implant/I in O)
if (I.implanted)
if(I.implanted)
I.trigger(act, src)
if(src.stat == 2.0 && (act != "deathgasp"))
if(stat == DEAD && (act != "deathgasp"))
return
if(attempt_vr(src,"handle_emote_vr",list(act,m_type,message))) return //VOREStation Add - Custom Emote Handler
switch(act)
if ("airguitar")
if (!src.restrained())
if("airguitar")
if(!src.restrained())
message = "is strumming the air and headbanging like a safari chimp."
m_type = 1
@@ -39,7 +36,7 @@
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if(!M)
@@ -75,7 +72,7 @@
else
use_sound = 'sound/effects/mob_effects/f_machine_sneeze.ogg'
if (param)
if(param)
message = "[display_msg] at [param]."
else
message = "[display_msg]."
@@ -103,142 +100,142 @@
message = "warbles."
m_type = 2
if ("blink")
if("blink")
message = "blinks."
m_type = 1
if ("blink_r")
if("blink_r")
message = "blinks rapidly."
m_type = 1
if ("bow")
if (!src.buckled)
if("bow")
if(!src.buckled)
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
if(param)
message = "bows to [param]."
else
message = "bows."
m_type = 1
if ("custom")
if("custom")
var/input = sanitize(input("Choose an emote to display.") as text|null)
if (!input)
if(!input)
return
var/input2 = input("Is this a visible or hearable emote?") in list("Visible","Hearable")
if (input2 == "Visible")
if(input2 == "Visible")
m_type = 1
else if (input2 == "Hearable")
if (src.miming)
else if(input2 == "Hearable")
if(src.miming)
return
m_type = 2
else
alert("Unable to use this emote, must be either hearable or visible.")
return
return custom_emote(m_type, message)
return custom_emote(m_type, input)
if ("me")
if("me")
//if(silent && silent > 0 && findtext(message,"\"",1, null) > 0)
// return //This check does not work and I have no idea why, I'm leaving it in for reference.
if (src.client)
if (client.prefs.muted & MUTE_IC)
if(src.client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
return
if (stat)
if(stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if ("salute")
if (!src.buckled)
if("salute")
if(!src.buckled)
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
if(param)
message = "salutes to [param]."
else
message = "salutes."
m_type = 1
if ("choke")
if("choke")
if(miming)
message = "clutches [T.his] throat desperately!"
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "chokes!"
m_type = 2
else
message = "makes a strong noise."
m_type = 2
if ("clap")
if (!src.restrained())
if("clap")
if(!src.restrained())
message = "claps."
playsound(src.loc, 'sound/misc/clapping.ogg')
m_type = 2
if(miming)
m_type = 1
if ("flap")
if (!src.restrained())
if("flap")
if(!src.restrained())
message = "flaps [T.his] wings."
m_type = 2
if(miming)
m_type = 1
if ("aflap")
if (!src.restrained())
if("aflap")
if(!src.restrained())
message = "flaps [T.his] wings ANGRILY!"
m_type = 2
if(miming)
m_type = 1
if ("drool")
if("drool")
message = "drools."
m_type = 1
if ("eyebrow")
if("eyebrow")
message = "raises an eyebrow."
m_type = 1
if ("chuckle")
if("chuckle")
if(miming)
message = "appears to chuckle."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "chuckles."
m_type = 2
else
message = "makes a noise."
m_type = 2
if ("twitch")
if("twitch")
message = "twitches."
m_type = 1
if ("twitch_v")
if("twitch_v")
message = "twitches violently."
m_type = 1
if ("faint")
if("faint")
message = "faints."
if(src.sleeping)
return //Can't faint while asleep
@@ -277,167 +274,167 @@
message = "makes a strong noise."
m_type = 2
if ("frown")
if("frown")
message = "frowns."
m_type = 1
if ("nod")
if("nod")
message = "nods."
m_type = 1
if ("blush")
if("blush")
message = "blushes."
m_type = 1
if ("wave")
if("wave")
message = "waves."
m_type = 1
if ("gasp")
if("gasp")
if(miming)
message = "appears to be gasping!"
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "gasps!"
m_type = 2
else
message = "makes a weak noise."
m_type = 2
if ("deathgasp")
if("deathgasp")
message = "[species.get_death_message()]"
m_type = 1
if ("giggle")
if("giggle")
if(miming)
message = "giggles silently!"
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "giggles."
m_type = 2
else
message = "makes a noise."
m_type = 2
if ("glare")
if("glare")
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
if(param)
message = "glares at [param]."
else
message = "glares."
if ("stare")
if("stare")
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
if(param)
message = "stares at [param]."
else
message = "stares."
if ("look")
if("look")
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
if(param)
message = "looks at [param]."
else
message = "looks."
m_type = 1
if ("grin")
if("grin")
message = "grins."
m_type = 1
if ("cry")
if("cry")
if(miming)
message = "cries."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "cries."
m_type = 2
else
message = "makes a weak noise. [T.he] [get_visible_gender() == NEUTER ? "frown" : "frowns"]." // no good, non-unwieldy alternative to this ternary at the moment
m_type = 2
if ("sigh")
if("sigh")
if(miming)
message = "sighs."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "sighs."
m_type = 2
else
message = "makes a weak noise."
m_type = 2
if ("laugh")
if("laugh")
if(miming)
message = "acts out a laugh."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "laughs."
m_type = 2
else
message = "makes a noise."
m_type = 2
if ("mumble")
if("mumble")
message = "mumbles!"
m_type = 2
if(miming)
m_type = 1
if ("grumble")
if("grumble")
if(miming)
message = "grumbles!"
m_type = 1
if (!muzzled)
if(!muzzled)
message = "grumbles!"
m_type = 2
else
message = "makes a noise."
m_type = 2
if ("groan")
if("groan")
if(miming)
message = "appears to groan!"
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "groans!"
m_type = 2
else
message = "makes a loud noise."
m_type = 2
if ("moan")
if("moan")
if(miming)
message = "appears to moan!"
m_type = 1
@@ -445,11 +442,11 @@
message = "moans!"
m_type = 2
if ("johnny")
if("johnny")
var/M
if (param)
if(param)
M = param
if (!M)
if(!M)
param = null
else
if(miming)
@@ -459,27 +456,27 @@
message = "says, \"[M], please. He had a family.\" [src.name] takes a drag from a cigarette and blows his name out in smoke."
m_type = 2
if ("point")
if (!src.restrained())
if("point")
if(!src.restrained())
var/mob/M = null
if (param)
if(param)
for (var/atom/A as mob|obj|turf|area in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
message = "points."
else
pointed(M)
if (M)
if(M)
message = "points to [M]."
else
m_type = 1
if ("raise")
if (!src.restrained())
if("raise")
if(!src.restrained())
message = "raises a hand."
m_type = 1
@@ -487,35 +484,35 @@
message = "shakes [T.his] head."
m_type = 1
if ("shrug")
if("shrug")
message = "shrugs."
m_type = 1
if ("signal")
if (!src.restrained())
if("signal")
if(!src.restrained())
var/t1 = round(text2num(param))
if (isnum(t1))
if (t1 <= 5 && (!src.r_hand || !src.l_hand))
if(isnum(t1))
if(t1 <= 5 && (!src.r_hand || !src.l_hand))
message = "raises [t1] finger\s."
else if (t1 <= 10 && (!src.r_hand && !src.l_hand))
else if(t1 <= 10 && (!src.r_hand && !src.l_hand))
message = "raises [t1] finger\s."
m_type = 1
if ("smile")
if("smile")
message = "smiles."
m_type = 1
if ("shiver")
if("shiver")
message = "shivers."
m_type = 2
if(miming)
m_type = 1
if ("pale")
if("pale")
message = "goes pale for a second."
m_type = 1
if ("tremble")
if("tremble")
message = "trembles in fear!"
m_type = 1
@@ -550,48 +547,48 @@
message = "makes a strange noise."
m_type = 2
if ("sniff")
if("sniff")
message = "sniffs."
m_type = 2
if(miming)
m_type = 1
if ("snore")
if (miming)
if("snore")
if(miming)
message = "sleeps soundly."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "snores."
m_type = 2
else
message = "makes a noise."
m_type = 2
if ("whimper")
if (miming)
if("whimper")
if(miming)
message = "appears hurt."
m_type = 1
else
if (!muzzled)
if(!muzzled)
message = "whimpers."
m_type = 2
else
message = "makes a weak noise."
m_type = 2
if ("wink")
if("wink")
message = "winks."
m_type = 1
if ("yawn")
if (!muzzled)
if("yawn")
if(!muzzled)
message = "yawns."
m_type = 2
if(miming)
m_type = 1
if ("collapse")
if("collapse")
Paralyse(2)
message = "collapses!"
m_type = 2
@@ -600,49 +597,49 @@
if("hug")
m_type = 1
if (!src.restrained())
if(!src.restrained())
var/M = null
if (param)
if(param)
for (var/mob/A in view(1, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (M == src)
if(M == src)
M = null
if (M)
if(M)
message = "hugs [M]."
else
message = "hugs [T.himself]."
if ("handshake")
if("handshake")
m_type = 1
if (!src.restrained() && !src.r_hand)
if(!src.restrained() && !src.r_hand)
var/mob/living/M = null
if (param)
if(param)
for (var/mob/living/A in view(1, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (M == src)
if(M == src)
M = null
if (M)
if (M.canmove && !M.r_hand && !M.restrained())
if(M)
if(M.canmove && !M.r_hand && !M.restrained())
message = "shakes hands with [M]."
else
message = "holds out [T.his] hand to [M]."
if("dap")
m_type = 1
if (!src.restrained())
if(!src.restrained())
var/M = null
if (param)
if(param)
for (var/mob/A in view(1, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (M)
if(M)
message = "gives daps to [M]."
else
message = "sadly can't find anybody to give daps to, and daps [T.himself]. Shameful."
@@ -737,16 +734,20 @@
else
message = "makes a light spitting noise, a poor attempt at a whistle."
if ("help")
to_chat(src, "blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
if("help")
to_chat(src, "<span class='filter_say'>blink, blink_r, blush, bow-(none)/mob, burp, choke, chuckle, clap, collapse, cough, cry, custom, deathgasp, drool, eyebrow, fastsway/qwag, \
frown, gasp, giggle, glare-(none)/mob, grin, groan, grumble, handshake, hug-(none)/mob, laugh, look-(none)/mob, moan, mumble, nod, pale, point-atom, \
raise, salute, scream, sneeze, shake, shiver, shrug, sigh, signal-#1-10, slap-(none)/mob, smile, sneeze, sniff, snore, stare-(none)/mob, stopsway/swag, sway/wag, swish, tremble, twitch, \
twitch_v, vomit, whimper, wink, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble")
twitch_v, vomit, whimper, wink, yawn. Prometheans: squish Synthetics: beep, buzz, dwoop, yes, no, rcough, rsneeze, ping. Skrell: warble</span>")
else
<<<<<<< HEAD
to_chat(src, "<font color='blue'>Unusable emote '[act]'. Say *help or *vhelp for a list.</font>") //VOREStation Edit, mention *vhelp for Virgo-specific emotes located in emote_vr.dm.
=======
to_chat(src, "<span class='filter_say'><font color='blue'>Unusable emote '[act]'. Say *help for a list.</font></span>")
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
if (message)
if(message)
custom_emote(m_type,message)
/mob/living/carbon/human/verb/pose()
+75 -75
View File
@@ -1,10 +1,13 @@
/mob/living/carbon/human/say(var/message,var/whispering=0)
var/alt_name = ""
/mob/living/carbon/human/GetAltName()
if(name != GetVoice())
alt_name = "(as [get_id_name("Unknown")])"
return " (as [get_id_name("Unknown")])"
<<<<<<< HEAD
message = sanitize_or_reflect(message,src) //VOREStation Edit - Reflect too-long messages, within reason
..(message, alt_name = alt_name, whispering = whispering)
=======
return ..()
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
/mob/living/carbon/human/proc/forcesay(list/append)
if(stat == CONSCIOUS)
@@ -47,18 +50,18 @@
return species.speech_bubble_appearance
return "normal"
/mob/living/carbon/human/say_understands(var/mob/other,var/datum/language/speaking = null)
/mob/living/carbon/human/say_understands(var/mob/other, var/datum/language/speaking = null)
if(has_brain_worms()) //Brain worms translate everything. Even mice and alien speak.
return 1
return TRUE
if(species.can_understand(other))
return 1
return TRUE
//These only pertain to common. Languages are handled by mob/say_understands()
if (!speaking)
if (istype(other, /mob/living/carbon/alien/diona))
if(!speaking)
if(istype(other, /mob/living/carbon/alien/diona))
if(other.languages.len >= 2) //They've sucked down some blood and can speak common now.
<<<<<<< HEAD
return 1
if (istype(other, /mob/living/silicon))
return 1
@@ -72,11 +75,19 @@
// if((other.universal_speak && !speaking) || src.universal_speak || src.universal_understand)
// return 1
// return 0
=======
return TRUE
if(issilicon(other))
return TRUE
if(isbrain(other))
return TRUE
if(isslime(other))
return TRUE
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
return ..()
/mob/living/carbon/human/GetVoice()
var/voice_sub
if(istype(get_rig(),/obj/item/weapon/rig))
var/obj/item/weapon/rig/rig = get_rig()
@@ -113,30 +124,6 @@
/mob/living/carbon/human/proc/GetSpecialVoice()
return special_voice
/*
***Deprecated***
let this be handled at the hear_say or hear_radio proc
This is left in for robot speaking when humans gain binary channel access until I get around to rewriting
robot_talk() proc.
There is no language handling build into it however there is at the /mob level so we accept the call
for it but just ignore it.
*/
/mob/living/carbon/human/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "says"
var/ending = copytext(message, length(message))
if(speaking)
verb = speaking.get_spoken_verb(ending)
else
if(ending == "!")
verb=pick("exclaims","shouts","yells")
else if(ending == "?")
verb="asks"
return verb
/mob/living/carbon/human/handle_speech_problems(var/list/message_data)
if(silent || (sdisabilities & MUTE))
message_data[1] = ""
@@ -152,59 +139,72 @@
else
. = ..(message_data)
/mob/living/carbon/human/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/carbon/human/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
switch(message_mode)
if("intercom")
if(!src.restrained())
if(!restrained())
for(var/obj/item/device/radio/intercom/I in view(1))
I.talk_into(src, message, null, verb, speaking)
I.talk_into(src, message_pieces, null, verb)
I.add_fingerprint(src)
used_radios += I
if("headset")
if(l_ear && istype(l_ear,/obj/item/device/radio))
var/obj/item/device/radio/R = l_ear
R.talk_into(src,message,null,verb,speaking)
used_radios += l_ear
else if(r_ear && istype(r_ear,/obj/item/device/radio))
var/obj/item/device/radio/R = r_ear
R.talk_into(src,message,null,verb,speaking)
used_radios += r_ear
if("right ear")
var/obj/item/device/radio/R
var/has_radio = 0
if(r_ear && istype(r_ear,/obj/item/device/radio))
R = r_ear
has_radio = 1
if(r_hand && istype(r_hand, /obj/item/device/radio))
R = r_hand
has_radio = 1
if(has_radio)
R.talk_into(src,message,null,verb,speaking)
used_radios += R
if("left ear")
var/obj/item/device/radio/R
var/has_radio = 0
if(l_ear && istype(l_ear,/obj/item/device/radio))
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
has_radio = 1
if(l_hand && istype(l_hand,/obj/item/device/radio))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if(isradio(r_ear))
R = r_ear
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
return
if("right ear")
var/obj/item/device/radio/R = null
if(isradio(r_ear))
R = r_ear
if(isradio(r_hand))
R = r_hand
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
if("left ear")
var/obj/item/device/radio/R = null
if(isradio(l_ear))
R = l_ear
if(isradio(l_hand))
R = l_hand
has_radio = 1
if(has_radio)
R.talk_into(src,message,null,verb,speaking)
used_radios += R
if(istype(R))
if(R.talk_into(src, message_pieces, null, verb))
used_radios += R
else
if(message_mode)
if(l_ear && istype(l_ear,/obj/item/device/radio))
l_ear.talk_into(src,message, message_mode, verb, speaking)
used_radios += l_ear
else if(r_ear && istype(r_ear,/obj/item/device/radio))
r_ear.talk_into(src,message, message_mode, verb, speaking)
used_radios += r_ear
if(isradio(l_ear))
if(l_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += l_ear
return
if(isradio(r_ear))
if(r_ear.talk_into(src, message_pieces, message_mode, verb))
used_radios += r_ear
/mob/living/carbon/human/handle_speech_sound()
var/list/returns[2]
if(species.speech_sounds && prob(species.speech_chance))
var/list/returns[2]
returns[1] = sound(pick(species.speech_sounds))
returns[2] = 50
return ..()
return returns
/mob/living/carbon/human/binarycheck()
. = FALSE
var/obj/item/device/radio/headset/R = null
if(istype(l_ear, /obj/item/device/radio/headset))
R = l_ear
if(R.translate_binary)
. = TRUE
if(istype(r_ear, /obj/item/device/radio/headset))
R = r_ear
if(R.translate_binary)
. = TRUE
@@ -532,10 +532,9 @@
genders = list(PLURAL)
/datum/species/diona/can_understand(var/mob/other)
var/mob/living/carbon/alien/diona/D = other
if(istype(D))
return 1
return 0
if(istype(other, /mob/living/carbon/alien/diona))
return TRUE
return FALSE
/datum/species/diona/equip_survival_gear(var/mob/living/carbon/human/H)
if(H.backbag == 1)
@@ -86,11 +86,9 @@
return "alien [caste_name] ([alien_number])"
/datum/species/xenos/can_understand(var/mob/other)
if(istype(other,/mob/living/carbon/alien/larva))
return 1
return 0
if(istype(other, /mob/living/carbon/alien/larva))
return TRUE
return FALSE
/datum/species/xenos/hug(var/mob/living/carbon/human/H,var/mob/living/target)
H.visible_message("<span class='notice'>[H] caresses [target] with its scythe-like arm.</span>", \
@@ -1,22 +0,0 @@
/mob/living/carbon/slime/death(gibbed)
if(stat == DEAD) return
if(!gibbed && is_adult)
var/mob/living/carbon/slime/M = new /mob/living/carbon/slime(loc, colour)
M.rabid = 1
M.Friends = Friends.Copy()
step_away(M, src)
is_adult = 0
maxHealth = 150
revive()
if (!client) rabid = 1
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
return
. = ..(gibbed, "seizes up and falls limp...")
mood = null
regenerate_icons()
return
@@ -1,99 +0,0 @@
/mob/living/carbon/slime/emote(var/act, var/m_type=1, var/message = null)
if (findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
//param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act,"s",-1) && !findtext(act,"_",-2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act,1,length(act))
var/updateicon = 0
switch(act) //Alphabetical please
if ("me")
if(silent)
return
if (src.client)
if (client.prefs.muted & MUTE_IC)
to_chat(src, "<font color='red'>You cannot send IC messages (muted).</font>")
return
if (stat)
return
if(!(message))
return
return custom_emote(m_type, message)
if("bounce")
message = "<B>The [src.name]</B> bounces in place."
m_type = 1
if ("custom")
return custom_emote(m_type, message)
if("jiggle")
message = "<B>The [src.name]</B> jiggles!"
m_type = 1
if("light")
message = "<B>The [src.name]</B> lights up for a bit, then stops."
m_type = 1
if("moan")
message = "<B>The [src.name]</B> moans."
m_type = 2
if("shiver")
message = "<B>The [src.name]</B> shivers."
m_type = 2
if("sway")
message = "<B>The [src.name]</B> sways around dizzily."
m_type = 1
if("twitch")
message = "<B>The [src.name]</B> twitches."
m_type = 1
if("vibrate")
message = "<B>The [src.name]</B> vibrates!"
m_type = 1
if("nomood")
mood = null
updateicon = 1
if("pout")
mood = "pout"
updateicon = 1
if("sad")
mood = "sad"
updateicon = 1
if("angry")
mood = "angry"
updateicon = 1
if("frown")
mood = "mischevous"
updateicon = 1
if("smile")
mood = ":3"
updateicon = 1
if ("help") //This is an exception
to_chat(src, "Help for slime emotes. You can use these emotes with say \"*emote\":\n\nbounce, custom, jiggle, light, moan, shiver, sway, twitch, vibrate. You can also set your face with: \n\nnomood, pout, sad, angry, frown, smile")
else
to_chat(src, "<font color='blue'>Unusable emote '[act]'. Say *help for a list.</font>")
if ((message && src.stat == 0))
if (m_type & 1)
for(var/mob/O in viewers(src, null))
O.show_message(message, m_type)
else
for(var/mob/O in hearers(src, null))
O.show_message(message, m_type)
if(updateicon)
regenerate_icons()
return
@@ -1,31 +0,0 @@
/mob/living/carbon/slime/examine(mob/user)
..(user)
var/msg = ""
if (src.stat == DEAD)
msg += "<span class='deadsay'>It is limp and unresponsive.</span>\n"
else
if (src.getBruteLoss())
msg += "<span class='warning'>"
if (src.getBruteLoss() < 40)
msg += "It has some punctures in its flesh!"
else
msg += "<B>It has severe punctures and tears in its flesh!</B>"
msg += "</span>\n"
switch(powerlevel)
if(2 to 3)
msg += "It is flickering gently with a little electrical activity.\n"
if(4 to 5)
msg += "It is glowing gently with moderate levels of electrical activity.\n"
if(6 to 9)
msg += "<span class='warning'>It is glowing brightly with high levels of electrical activity.</span>\n"
if(10)
msg += "<span class='warning'><B>It is radiating with massive levels of electrical activity!</B></span>\n"
msg += "*---------*"
to_chat(user,msg)
return
@@ -1,2 +0,0 @@
/mob/living/carbon/slime/handle_regular_hud_updates()
return
@@ -1,527 +0,0 @@
/mob/living/carbon/slime/Life()
set invisibility = 0
set background = 1
if (src.transforming)
return
..()
if(stat != DEAD)
handle_nutrition()
if (!client)
handle_targets()
if (!AIproc)
spawn()
handle_AI()
handle_speech_and_mood()
/mob/living/carbon/slime/handle_environment(datum/gas_mixture/environment)
if(!environment)
adjustToxLoss(rand(10,20))
return
//var/environment_heat_capacity = environment.heat_capacity()
var/loc_temp = T0C
if(istype(get_turf(src), /turf/space))
//environment_heat_capacity = loc:heat_capacity
var/turf/heat_turf = get_turf(src)
loc_temp = heat_turf.temperature
else if(istype(loc, /obj/machinery/atmospherics/unary/cryo_cell))
loc_temp = loc:air_contents.temperature
else
loc_temp = environment.temperature
bodytemperature += adjust_body_temperature(bodytemperature, loc_temp, 1)
if(bodytemperature < (T0C + 5)) // start calculating temperature damage etc
if(bodytemperature <= hurt_temperature)
if(bodytemperature <= die_temperature)
adjustToxLoss(200)
else
// could be more fancy, but doesn't worth the complexity: when the slimes goes into a cold area
// the damage is mostly determined by how fast its body cools
adjustToxLoss(30)
updatehealth()
return //TODO: DEFERRED
/mob/living/carbon/slime/proc/adjust_body_temperature(current, loc_temp, boost)
var/temperature = current
var/difference = abs(current-loc_temp) //get difference
var/increments// = difference/10 //find how many increments apart they are
if(difference > 50)
increments = difference/5
else
increments = difference/10
var/change = increments*boost // Get the amount to change by (x per increment)
var/temp_change
if(current < loc_temp)
temperature = min(loc_temp, temperature+change)
else if(current > loc_temp)
temperature = max(loc_temp, temperature-change)
temp_change = (temperature - current)
return temp_change
/mob/living/carbon/slime/handle_chemicals_in_body()
chem_effects.Cut()
if(touching) touching.metabolize()
if(ingested) ingested.metabolize()
if(bloodstr) bloodstr.metabolize()
src.updatehealth()
return //TODO: DEFERRED
/mob/living/carbon/slime/handle_regular_status_updates()
src.blinded = null
health = getMaxHealth() - (getOxyLoss() + getToxLoss() + getFireLoss() + getBruteLoss() + getCloneLoss())
if(health < 0 && stat != DEAD)
death()
return
if (halloss)
halloss = 0
if(prob(30))
adjustOxyLoss(-1)
adjustToxLoss(-1)
adjustFireLoss(-1)
adjustCloneLoss(-1)
adjustBruteLoss(-1)
if (src.stat == DEAD)
src.lying = 1
src.blinded = 1
else
if (src.paralysis || src.stunned || src.weakened || (status_flags & FAKEDEATH)) //Stunned etc.
if (src.stunned > 0)
src.set_stat(CONSCIOUS)
if (src.weakened > 0)
src.lying = 0
src.set_stat(CONSCIOUS)
if (src.paralysis > 0)
src.blinded = 0
src.lying = 0
src.set_stat(CONSCIOUS)
else
src.lying = 0
src.set_stat(CONSCIOUS)
if (src.stuttering) src.stuttering = 0
if (src.eye_blind)
SetBlinded(0)
src.blinded = 1
if (src.ear_deaf > 0) src.ear_deaf = 0
if (src.ear_damage < 25)
src.ear_damage = 0
src.density = !( src.lying )
if (src.sdisabilities & BLIND)
src.blinded = 1
if (src.sdisabilities & DEAF)
src.ear_deaf = 1
if (src.eye_blurry > 0)
src.eye_blurry = 0
if (src.druggy > 0)
src.druggy = 0
return 1
/mob/living/carbon/slime/proc/handle_nutrition()
if (prob(15))
nutrition -= 1 + is_adult
if(nutrition <= 0)
nutrition = 0
adjustToxLoss(rand(1,3))
if (client && prob(5))
to_chat(src, "<span class='danger'>You are starving!</span>")
else if (nutrition >= get_grow_nutrition() && amount_grown < 10)
nutrition -= 20
amount_grown++
/mob/living/carbon/slime/proc/handle_targets()
if(attacked > 50) attacked = 50 // Let's not get into absurdly long periods of rage
if(attacked > 0)
attacked--
if(Discipline > 0)
if(Discipline >= 5 && rabid)
if(prob(60)) rabid = 0
if(prob(10))
Discipline--
if(!canmove) return
if(Victim) return // if it's eating someone already, continue eating!
if(Target)
--target_patience
if (target_patience <= 0 || SStun || Discipline || attacked) // Tired of chasing or something draws out attention
target_patience = 0
Target = null
var/hungry = 0 // determines if the slime is hungry
if (nutrition < get_starve_nutrition())
hungry = 2
else if (nutrition < get_grow_nutrition() && prob(25) || nutrition < get_hunger_nutrition())
hungry = 1
if(hungry == 2 && !client) // if a slime is starving, it starts losing its friends
if(Friends.len > 0 && prob(1))
var/mob/nofriend = pick(Friends)
if(nofriend && Friends[nofriend])
Friends[nofriend] -= 1
if (Friends[nofriend] <= 0)
Friends[nofriend] = null
Friends -= nofriend
Friends -= null
if(!Target)
if(will_hunt(hungry) || attacked || rabid) // Only add to the list if we need to
var/list/targets = list()
for(var/mob/living/L in view(7,src))
if(isslime(L) || L.stat == DEAD) // Ignore other slimes and dead mobs
continue
if(L in Friends) // No eating friends!
continue
if(issilicon(L) && (rabid || attacked)) // They can't eat silicons, but they can glomp them in defence
targets += L // Possible target found!
if(istype(L, /mob/living/carbon/human) && dna) //Ignore slime(wo)men
var/mob/living/carbon/human/H = L
if(H.species.name == "Promethean")
continue
if(!L.canmove) // Only one slime can latch on at a time.
var/notarget = 0
for(var/mob/living/carbon/slime/M in view(1,L))
if(M.Victim == L)
notarget = 1
if(notarget)
continue
targets += L // Possible target found!
if(targets.len > 0)
if(attacked || rabid || hungry == 2)
Target = targets[1] // I am attacked and am fighting back or so hungry I don't even care
else
for(var/mob/living/carbon/C in targets)
if(ishuman(C) && !Discipline && prob(5))
Target = C
break
if(isalien(C) || issmall(C) || isanimal(C))
Target = C
break
if (Target)
target_patience = rand(5,7)
if (is_adult)
target_patience += 3
if(!Target) // If we have no target, we are wandering or following orders
if (Leader)
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc))
step_to(src, Leader)
else if(hungry)
if (holding_still)
holding_still = max(holding_still - 1 - hungry, 0)
else if(canmove && isturf(loc) && prob(50))
step(src, pick(cardinal))
else
if (holding_still)
holding_still = max(holding_still - 1, 0)
else if(canmove && isturf(loc) && prob(33))
step(src, pick(cardinal))
/mob/living/carbon/slime/proc/handle_AI() // the master AI process
if(stat == DEAD || client || Victim) return // If we're dead or have a client, we don't need AI, if we're feeding, we continue feeding
AIproc = 1
if(amount_grown >= 10 && !Target)
if(is_adult)
Reproduce()
else
Evolve()
AIproc = 0
return
if(Target) // We're chasing the target
if(Target.stat == DEAD)
Target = null
AIproc = 0
return
for(var/mob/living/carbon/slime/M in view(1, Target))
if(M.Victim == Target)
Target = null
AIproc = 0
return
if(Target.Adjacent(src))
if(istype(Target, /mob/living/silicon)) // Glomp the silicons
if(!Atkcool)
a_intent = I_HURT
UnarmedAttack(Target)
Atkcool = 1
spawn(45)
Atkcool = 0
AIproc = 0
return
if(Target.client && !Target.lying && prob(60 + powerlevel * 4)) // Try to take down the target first
if(!Atkcool)
Atkcool = 1
spawn(45)
Atkcool = 0
a_intent = I_DISARM
UnarmedAttack(Target)
else
if(!Atkcool)
a_intent = I_GRAB
UnarmedAttack(Target)
else if(Target in view(7, src))
step_to(src, Target)
else
Target = null
AIproc = 0
return
else
var/mob/living/carbon/slime/frenemy
for (var/mob/living/carbon/slime/S in view(1, src))
if (S != src)
frenemy = S
if (frenemy && prob(1))
if (frenemy.colour == colour)
a_intent = I_HELP
else
a_intent = I_HURT
UnarmedAttack(frenemy)
var/sleeptime = movement_delay()
if(sleeptime <= 5) sleeptime = 5 // Maximum one action per half a second
spawn (sleeptime)
handle_AI()
return
/mob/living/carbon/slime/proc/handle_speech_and_mood()
//Mood starts here
var/newmood = ""
a_intent = I_HELP
if (rabid || attacked)
newmood = "angry"
a_intent = I_HURT
else if (Target) newmood = "mischevous"
if (!newmood)
if (Discipline && prob(25))
newmood = "pout"
else if (prob(1))
newmood = pick("sad", ":3", "pout")
if ((mood == "sad" || mood == ":3" || mood == "pout") && !newmood)
if (prob(75)) newmood = mood
if (newmood != mood) // This is so we don't redraw them every time
mood = newmood
regenerate_icons()
//Speech understanding starts here
var/to_say
if (speech_buffer.len > 0)
var/who = speech_buffer[1] // Who said it?
var/phrase = speech_buffer[2] // What did they say?
if ((findtext(phrase, num2text(number)) || findtext(phrase, "slimes"))) // Talking to us
if (findtext(phrase, "hello") || findtext(phrase, "hi"))
to_say = pick("Hello...", "Hi...")
else if (findtext(phrase, "follow"))
if (Leader)
if (Leader == who) // Already following him
to_say = pick("Yes...", "Lead...", "Following...")
else if (Friends[who] > Friends[Leader]) // VIVA
Leader = who
to_say = "Yes... I follow [who]..."
else
to_say = "No... I follow [Leader]..."
else
if (Friends[who] > 2)
Leader = who
to_say = "I follow..."
else // Not friendly enough
to_say = pick("No...", "I won't follow...")
else if (findtext(phrase, "stop"))
if (Victim) // We are asked to stop feeding
if (Friends[who] > 4)
Victim = null
Target = null
if (Friends[who] < 7)
--Friends[who]
to_say = "Grrr..." // I'm angry but I do it
else
to_say = "Fine..."
else if (Target) // We are asked to stop chasing
if (Friends[who] > 3)
Target = null
if (Friends[who] < 6)
--Friends[who]
to_say = "Grrr..." // I'm angry but I do it
else
to_say = "Fine..."
else if (Leader) // We are asked to stop following
if (Leader == who)
to_say = "Yes... I'll stay..."
Leader = null
else
if (Friends[who] > Friends[Leader])
Leader = null
to_say = "Yes... I'll stop..."
else
to_say = "No... I'll keep following..."
else if (findtext(phrase, "stay"))
if (Leader)
if (Leader == who)
holding_still = Friends[who] * 10
to_say = "Yes... Staying..."
else if (Friends[who] > Friends[Leader])
holding_still = (Friends[who] - Friends[Leader]) * 10
to_say = "Yes... Staying..."
else
to_say = "No... I'll keep following..."
else
if (Friends[who] > 2)
holding_still = Friends[who] * 10
to_say = "Yes... Staying..."
else
to_say = "No... I won't stay..."
speech_buffer = list()
//Speech starts here
if (to_say)
say (to_say)
else if(prob(1))
emote(pick("bounce","sway","light","vibrate","jiggle"))
else
var/t = 10
var/slimes_near = -1 // Don't count myself
var/dead_slimes = 0
var/friends_near = list()
for (var/mob/living/carbon/M in view(7,src))
if (isslime(M))
++slimes_near
if (M.stat == DEAD)
++dead_slimes
if (M in Friends)
t += 20
friends_near += M
if (nutrition < get_hunger_nutrition()) t += 10
if (nutrition < get_starve_nutrition()) t += 10
if (prob(2) && prob(t))
var/phrases = list()
if (Target) phrases += "[Target]... looks tasty..."
if (nutrition < get_starve_nutrition())
phrases += "So... hungry..."
phrases += "Very... hungry..."
phrases += "Need... food..."
phrases += "Must... eat..."
else if (nutrition < get_hunger_nutrition())
phrases += "Hungry..."
phrases += "Where is the food?"
phrases += "I want to eat..."
phrases += "Rawr..."
phrases += "Blop..."
phrases += "Blorble..."
if (rabid || attacked)
phrases += "Hrr..."
phrases += "Nhuu..."
phrases += "Unn..."
if (mood == ":3")
phrases += "Purr..."
if (attacked)
phrases += "Grrr..."
if (getToxLoss() > 30)
phrases += "Cold..."
if (getToxLoss() > 60)
phrases += "So... cold..."
phrases += "Very... cold..."
if (getToxLoss() > 90)
phrases += "..."
phrases += "C... c..."
if (Victim)
phrases += "Nom..."
phrases += "Tasty..."
if (powerlevel > 3) phrases += "Bzzz..."
if (powerlevel > 5) phrases += "Zap..."
if (powerlevel > 8) phrases += "Zap... Bzz..."
if (mood == "sad") phrases += "Bored..."
if (slimes_near) phrases += "Brother..."
if (slimes_near > 1) phrases += "Brothers..."
if (dead_slimes) phrases += "What happened?"
if (!slimes_near)
phrases += "Lonely..."
for (var/M in friends_near)
phrases += "[M]... friend..."
if (nutrition < get_hunger_nutrition())
phrases += "[M]... feed me..."
say (pick(phrases))
/mob/living/carbon/slime/proc/get_max_nutrition() // Can't go above it
if (is_adult) return 1200
else return 1000
/mob/living/carbon/slime/proc/get_grow_nutrition() // Above it we grow, below it we can eat
if (is_adult) return 1000
else return 800
/mob/living/carbon/slime/proc/get_hunger_nutrition() // Below it we will always eat
if (is_adult) return 600
else return 500
/mob/living/carbon/slime/proc/get_starve_nutrition() // Below it we will eat before everything else
if (is_adult) return 300
else return 200
/mob/living/carbon/slime/proc/will_hunt(var/hunger) // Check for being stopped from feeding and chasing
if (hunger == 2 || rabid || attacked) return 1
if (Leader) return 0
if (holding_still) return 0
if (hunger == 1 || prob(25))
return 1
return 0
/mob/living/carbon/slime/slip() //Can't slip something without legs.
return 0
@@ -1,4 +0,0 @@
/mob/living/carbon/slime/Login()
..()
update_hud()
return
@@ -1,384 +0,0 @@
/mob/living/carbon/slime
name = "baby slime"
icon = 'icons/mob/slimes.dmi'
icon_state = "grey baby slime"
pass_flags = PASSTABLE
var/is_adult = 0
speak_emote = list("chirps")
plane = MOB_PLANE
layer = ABOVE_MOB_LAYER
maxHealth = 150
health = 150
gender = NEUTER
update_icon = 0
nutrition = 700
see_in_dark = 8
update_slimes = 0
// canstun and canweaken don't affect slimes because they ignore stun and weakened variables
// for the sake of cleanliness, though, here they are.
status_flags = CANPARALYSE|CANPUSH
var/cores = 1 // the number of /obj/item/slime_extract's the slime has left inside
var/mutation_chance = 30 // Chance of mutating, should be between 25 and 35
var/powerlevel = 0 // 0-10 controls how much electricity they are generating
var/amount_grown = 0 // controls how long the slime has been overfed, if 10, grows or reproduces
var/number = 0 // Used to understand when someone is talking to it
var/mob/living/Victim = null // the person the slime is currently feeding on
var/mob/living/Target = null // AI variable - tells the slime to hunt this down
var/mob/living/Leader = null // AI variable - tells the slime to follow this person
var/attacked = 0 // Determines if it's been attacked recently. Can be any number, is a cooloff-ish variable
var/rabid = 0 // If set to 1, the slime will attack and eat anything it comes in contact with
var/holding_still = 0 // AI variable, cooloff-ish for how long it's going to stay in one place
var/target_patience = 0 // AI variable, cooloff-ish for how long it's going to follow its target
var/list/Friends = list() // A list of friends; they are not considered targets for feeding; passed down after splitting
var/list/speech_buffer = list() // Last phrase said near it and person who said it
var/mood = "" // To show its face
var/AIproc = 0 // If it's 0, we need to launch an AI proc
var/Atkcool = 0 // attack cooldown
var/SStun = 0 // NPC stun variable. Used to calm them down when they are attacked while feeding, or they will immediately re-attach
var/Discipline = 0 // if a slime has been hit with a freeze gun, or wrestled/attacked off a human, they become disciplined and don't attack anymore for a while. The part about freeze gun is a lie
var/hurt_temperature = T0C-50 // slime keeps taking damage when its bodytemperature is below this
var/die_temperature = 50 // slime dies instantly when its bodytemperature is below this
///////////TIME FOR SUBSPECIES
var/colour = "grey"
var/coretype = /obj/item/slime_extract/grey
var/list/slime_mutation[4]
var/core_removal_stage = 0 //For removing cores.
/mob/living/carbon/slime/New(var/location, var/colour="grey")
verbs += /mob/living/proc/ventcrawl
src.colour = colour
number = rand(1, 1000)
name = "[colour] [is_adult ? "adult" : "baby"] slime ([number])"
real_name = name
slime_mutation = mutation_table(colour)
mutation_chance = rand(25, 35)
var/sanitizedcolour = replacetext(colour, " ", "")
coretype = text2path("/obj/item/slime_extract/[sanitizedcolour]")
regenerate_icons()
..(location)
/mob/living/carbon/slime/movement_delay()
if (bodytemperature >= 330.23) // 135 F
return -1 // slimes become supercharged at high temperatures
var/tally = 0
var/health_deficiency = (getMaxHealth() - health)
if(health_deficiency >= 30) tally += (health_deficiency / 25)
if (bodytemperature < 183.222)
tally += (283.222 - bodytemperature) / 10 * 1.75
if(reagents)
if(reagents.has_reagent("hyperzine")) // Hyperzine slows slimes down
tally *= 2
if(reagents.has_reagent("frostoil")) // Frostoil also makes them move VEEERRYYYYY slow
tally *= 5
if(health <= 0) // if damaged, the slime moves twice as slow
tally *= 2
return tally + config.slime_delay
/mob/living/carbon/slime/Bump(atom/movable/AM as mob|obj, yes)
if ((!(yes) || now_pushing))
return
now_pushing = 1
if(isobj(AM) && !client && powerlevel > 0)
var/probab = 10
switch(powerlevel)
if(1 to 2) probab = 20
if(3 to 4) probab = 30
if(5 to 6) probab = 40
if(7 to 8) probab = 60
if(9) probab = 70
if(10) probab = 95
if(prob(probab))
if(istype(AM, /obj/structure/window) || istype(AM, /obj/structure/grille))
if(nutrition <= get_hunger_nutrition() && !Atkcool)
if (is_adult || prob(5))
UnarmedAttack(AM)
Atkcool = 1
spawn(45)
Atkcool = 0
if(ismob(AM))
var/mob/tmob = AM
if(is_adult)
if(istype(tmob, /mob/living/carbon/human))
if(prob(90))
now_pushing = 0
return
else
if(istype(tmob, /mob/living/carbon/human))
now_pushing = 0
return
now_pushing = 0
..()
/mob/living/carbon/slime/Process_Spacemove()
return 2
/mob/living/carbon/slime/Stat()
..()
statpanel("Status")
stat(null, "Health: [round((health / getMaxHealth()) * 100)]%")
stat(null, "Intent: [a_intent]")
if (client.statpanel == "Status")
stat(null, "Nutrition: [nutrition]/[get_max_nutrition()]")
if(amount_grown >= 10)
if(is_adult)
stat(null, "You can reproduce!")
else
stat(null, "You can evolve!")
stat(null,"Power Level: [powerlevel]")
/mob/living/carbon/slime/adjustFireLoss(amount)
..(-abs(amount)) // Heals them
return
/mob/living/carbon/slime/bullet_act(var/obj/item/projectile/Proj)
attacked += 10
..(Proj)
return 0
/mob/living/carbon/slime/emp_act(severity)
powerlevel = 0 // oh no, the power!
..()
/mob/living/carbon/slime/ex_act(severity)
..()
var/b_loss = null
var/f_loss = null
switch (severity)
if (1.0)
qdel(src)
return
if (2.0)
b_loss += 60
f_loss += 60
if(3.0)
b_loss += 30
adjustBruteLoss(b_loss)
adjustFireLoss(f_loss)
updatehealth()
/mob/living/carbon/slime/u_equip(obj/item/W as obj)
return
/mob/living/carbon/slime/attack_ui(slot)
return
/mob/living/carbon/slime/attack_hand(mob/living/carbon/human/M as mob)
..()
if(Victim)
if(Victim == M)
if(prob(60))
visible_message("<span class='warning'>[M] attempts to wrestle \the [name] off!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message("<span class='warning'> [M] manages to wrestle \the [name] off!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(prob(90) && !client)
Discipline++
SStun = 1
spawn(rand(45,60))
SStun = 0
Victim = null
anchored = 0
step_away(src,M)
return
else
if(prob(30))
visible_message("<span class='warning'>[M] attempts to wrestle \the [name] off of [Victim]!</span>")
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
else
visible_message("<span class='warning'> [M] manages to wrestle \the [name] off of [Victim]!</span>")
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
if(prob(80) && !client)
Discipline++
if(!is_adult)
if(Discipline == 1)
attacked = 0
SStun = 1
spawn(rand(55,65))
SStun = 0
Victim = null
anchored = 0
step_away(src,M)
return
switch(M.a_intent)
if (I_HELP)
help_shake_act(M)
if (I_GRAB)
if (M == src || anchored)
return
var/obj/item/weapon/grab/G = new /obj/item/weapon/grab(M, src)
M.put_in_active_hand(G)
G.synch()
LAssailant = M
playsound(loc, 'sound/weapons/thudswoosh.ogg', 50, 1, -1)
visible_message("<span class='warning'>[M] has grabbed [src] passively!</span>")
else
var/damage = rand(1, 9)
attacked += 10
if (prob(90))
if (HULK in M.mutations)
damage += 5
if(Victim || Target)
Victim = null
Target = null
anchored = 0
if(prob(80) && !client)
Discipline++
spawn(0)
step_away(src,M,15)
sleep(3)
step_away(src,M,15)
playsound(loc, "punch", 25, 1, -1)
visible_message("<span class='danger'>[M] has punched [src]!</span>", \
"<span class='danger'>[M] has punched [src]!</span>")
adjustBruteLoss(damage)
updatehealth()
else
playsound(loc, 'sound/weapons/punchmiss.ogg', 25, 1, -1)
visible_message("<span class='danger'>[M] has attempted to punch [src]!</span>")
return
/mob/living/carbon/slime/attackby(obj/item/W, mob/user)
if(W.force > 0)
attacked += 10
if(prob(25))
to_chat(user, "<span class='danger'>[W] passes right through [src]!</span>")
return
if(Discipline && prob(50)) // wow, buddy, why am I getting attacked??
Discipline = 0
if(W.force >= 3)
if(is_adult)
if(prob(5 + round(W.force/2)))
if(Victim || Target)
if(prob(80) && !client)
Discipline++
Victim = null
Target = null
anchored = 0
SStun = 1
spawn(rand(5,20))
SStun = 0
spawn(0)
if(user)
canmove = 0
step_away(src, user)
if(prob(25 + W.force))
sleep(2)
if(user)
step_away(src, user)
canmove = 1
else
if(prob(10 + W.force*2))
if(Victim || Target)
if(prob(80) && !client)
Discipline++
if(Discipline == 1)
attacked = 0
SStun = 1
spawn(rand(5,20))
SStun = 0
Victim = null
Target = null
anchored = 0
spawn(0)
if(user)
canmove = 0
step_away(src, user)
if(prob(25 + W.force*4))
sleep(2)
if(user)
step_away(src, user)
canmove = 1
..()
/mob/living/carbon/slime/restrained()
return 0
/mob/living/carbon/slime/var/co2overloadtime = null
/mob/living/carbon/slime/var/temperature_resistance = T0C+75
/mob/living/carbon/slime/toggle_throw_mode()
return
/mob/living/carbon/slime/proc/gain_nutrition(var/amount)
nutrition += amount
if(prob(amount * 2)) // Gain around one level per 50 nutrition
powerlevel++
if(powerlevel > 10)
powerlevel = 10
adjustToxLoss(-10)
nutrition = max(nutrition, get_max_nutrition())
@@ -1,39 +0,0 @@
/mob/living/carbon/slime/say(var/message)
message = sanitize(message)
var/verb = say_quote(message)
if(copytext(message,1,2) == "*")
return emote(copytext(message,2))
return ..(message, null, verb)
/mob/living/carbon/slime/say_quote(var/text)
var/ending = copytext(text, length(text))
if (ending == "?")
return "asks";
else if (ending == "!")
return "cries";
return "chirps";
/mob/living/carbon/slime/say_understands(var/other)
if (istype(other, /mob/living/carbon/slime))
return 1
return ..()
/mob/living/carbon/slime/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "", var/italics = 0, var/mob/speaker = null, var/sound/speech_sound, var/sound_vol)
if (speaker in Friends)
speech_buffer = list()
speech_buffer.Add(speaker)
speech_buffer.Add(lowertext(html_decode(message)))
..()
/mob/living/carbon/slime/hear_radio(var/message, var/verb="says", var/datum/language/language=null, var/part_a, var/part_b, var/part_c, var/mob/speaker = null, var/hard_to_hear = 0, var/vname ="")
if (speaker in Friends)
speech_buffer = list()
speech_buffer.Add(speaker)
speech_buffer.Add(lowertext(html_decode(message)))
..()
@@ -1,79 +0,0 @@
/mob/living/carbon/slime/proc/mutation_table(var/colour)
var/list/slime_mutation[4]
switch(colour)
//Tier 1
if("grey")
slime_mutation[1] = "orange"
slime_mutation[2] = "metal"
slime_mutation[3] = "blue"
slime_mutation[4] = "purple"
//Tier 2
if("purple")
slime_mutation[1] = "dark purple"
slime_mutation[2] = "dark blue"
slime_mutation[3] = "green"
slime_mutation[4] = "green"
if("metal")
slime_mutation[1] = "silver"
slime_mutation[2] = "yellow"
slime_mutation[3] = "gold"
slime_mutation[4] = "gold"
if("orange")
slime_mutation[1] = "dark purple"
slime_mutation[2] = "yellow"
slime_mutation[3] = "red"
slime_mutation[4] = "red"
if("blue")
slime_mutation[1] = "dark blue"
slime_mutation[2] = "silver"
slime_mutation[3] = "pink"
slime_mutation[4] = "pink"
//Tier 3
if("dark blue")
slime_mutation[1] = "purple"
slime_mutation[2] = "purple"
slime_mutation[3] = "blue"
slime_mutation[4] = "blue"
if("dark purple")
slime_mutation[1] = "purple"
slime_mutation[2] = "purple"
slime_mutation[3] = "orange"
slime_mutation[4] = "orange"
if("yellow")
slime_mutation[1] = "metal"
slime_mutation[2] = "metal"
slime_mutation[3] = "orange"
slime_mutation[4] = "orange"
if("silver")
slime_mutation[1] = "metal"
slime_mutation[2] = "metal"
slime_mutation[3] = "blue"
slime_mutation[4] = "blue"
//Tier 4
if("pink")
slime_mutation[1] = "pink"
slime_mutation[2] = "pink"
slime_mutation[3] = "light pink"
slime_mutation[4] = "light pink"
if("red")
slime_mutation[1] = "red"
slime_mutation[2] = "red"
slime_mutation[3] = "oil"
slime_mutation[4] = "oil"
if("gold")
slime_mutation[1] = "gold"
slime_mutation[2] = "gold"
slime_mutation[3] = "adamantine"
slime_mutation[4] = "adamantine"
if("green")
slime_mutation[1] = "green"
slime_mutation[2] = "green"
slime_mutation[3] = "black"
slime_mutation[4] = "black"
// Tier 5
else
slime_mutation[1] = colour
slime_mutation[2] = colour
slime_mutation[3] = colour
slime_mutation[4] = colour
return(slime_mutation)
@@ -1,9 +0,0 @@
/mob/living/carbon/slime/regenerate_icons()
if (stat == DEAD)
icon_state = "[colour] baby slime dead"
else
icon_state = "[colour] [is_adult ? "adult" : "baby"] slime[Victim ? "" : " eat"]"
overlays.len = 0
if (mood)
overlays += image('icons/mob/slimes.dmi', icon_state = "aslime-[mood]")
..()
+1 -1
View File
@@ -10,7 +10,7 @@
return 0
if(language == GLOB.all_languages[src.species_language])
to_chat(src, "<span class='notice'>You will now speak your standard default language, [language], if you do not specify a language when speaking.</span>")
to_chat(src, "<span class='notice'>You will now speak your standard default language, [language ? language : "common"], if you do not specify a language when speaking.</span>")
else if (language)
if(language && !can_speak(language))
+133 -95
View File
@@ -70,34 +70,23 @@ proc/get_radio_key_from_channel(var/channel)
return key
/mob/living/proc/binarycheck()
return FALSE
if (istype(src, /mob/living/silicon/pai))
return
/mob/proc/get_default_language()
return null
if (!ishuman(src))
return
var/mob/living/carbon/human/H = src
if (H.l_ear || H.r_ear)
var/obj/item/device/radio/headset/dongle
if(istype(H.l_ear,/obj/item/device/radio/headset))
dongle = H.l_ear
else
dongle = H.r_ear
if(!istype(dongle)) return
if(dongle.translate_binary) return 1
/mob/living/proc/get_default_language()
/mob/living/get_default_language()
return default_language
//Takes a list of the form list(message, verb, whispering) and modifies it as needed
//Returns 1 if a speech problem was applied, 0 otherwise
/mob/living/proc/handle_speech_problems(var/list/message_data)
var/message = message_data[1]
var/list/message_pieces = message_data[1]
var/verb = message_data[2]
var/whispering = message_data[3]
. = 0
<<<<<<< HEAD
if((HULK in mutations) && health >= 25 && length(message))
message = "[uppertext(message)]!!!"
verb = pick("yells","roars","hollers")
@@ -119,13 +108,35 @@ proc/get_radio_key_from_channel(var/channel)
//VOREStation Edit End
message_data[1] = message
=======
// Technically this rerolls the verb for as many say pieces as there are. _shrug_
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && (S.speaking.flags & NO_STUTTER || S.speaking.flags & SIGNLANG))
continue
if((HULK in mutations) && health >= 25 && length(S.message))
S.message = "[uppertext(S.message)]!!!"
verb = pick("yells","roars","hollers")
whispering = 0
. = 1
if(slurring)
S.message = slur(S.message)
verb = pick("slobbers","slurs")
. = 1
if(stuttering)
S.message = stutter(S.message)
verb = pick("stammers","stutters")
. = 1
message_data[1] = message_pieces
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
message_data[2] = verb
message_data[3] = whispering
/mob/living/proc/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/proc/handle_message_mode(message_mode, list/message_pieces, verb, used_radios)
if(message_mode == "intercom")
for(var/obj/item/device/radio/intercom/I in view(1, null))
I.talk_into(src, message, verb, speaking)
I.talk_into(src, message_pieces, verb)
used_radios += I
return 0
@@ -136,13 +147,13 @@ proc/get_radio_key_from_channel(var/channel)
return returns
/mob/living/proc/get_speech_ending(verb, var/ending)
if(ending=="!")
if(ending == "!")
return pick("exclaims","shouts","yells")
if(ending=="?")
if(ending == "?")
return "asks"
return verb
/mob/living/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering = 0)
/mob/living/say(var/message, var/whispering = 0)
//If you're muted for IC chat
if(client)
if(message)
@@ -161,98 +172,81 @@ proc/get_radio_key_from_channel(var/channel)
var/message_mode = parse_message_mode(message, "headset")
//Maybe they are using say/whisper to do a quick emote, so do those
switch(copytext(message,1,2))
if("*") return emote(copytext(message,2))
if("^") return custom_emote(1, copytext(message,2))
switch(copytext(message, 1, 2))
if("*") return emote(copytext(message, 2))
if("^") return custom_emote(1, copytext(message, 2))
//Parse the radio code and consume it
if (message_mode)
if (message_mode == "headset")
message = copytext(message,2) //it would be really nice if the parse procs could do this for us.
else if (message_mode == "whisper")
if(message_mode)
if(message_mode == "headset")
message = copytext(message, 2) //it would be really nice if the parse procs could do this for us.
else if(message_mode == "whisper")
whispering = 1
message_mode = null
message = copytext(message,3)
message = copytext(message, 3)
else
message = copytext(message,3)
message = copytext(message, 3)
//Clean up any remaining space on the left
message = trim_left(message)
//Parse the language code and consume it
if(!speaking)
speaking = parse_language(message)
if(!speaking)
speaking = get_default_language()
if(!can_speak(speaking))
speaking = GLOB.all_languages[LANGUAGE_GIBBERISH]
var/babble_key = ",r"
message = babble_key + message
if(speaking == get_default_language())
var/new_message = ",[speaking.key]"
new_message += message
message = new_message
if(speaking)
message = copytext(message,2+length(speaking.key))
//HIVEMIND languages always send to all people with that language
if(speaking && (speaking.flags & HIVEMIND))
speaking.broadcast(src,trim(message))
var/list/message_pieces = parse_languages(message)
if(istype(message_pieces, /datum/multilingual_say_piece)) // Little quark for dealing with hivemind/signlang languages.
var/datum/multilingual_say_piece/S = message_pieces // Yay for BYOND's hilariously broken typecasting for allowing us to do this.
S.speaking.broadcast(src, S.message)
return 1
//Self explanatory.
if(is_muzzled() && !(speaking && (speaking.flags & SIGNLANG)))
if(!LAZYLEN(message_pieces))
log_runtime(EXCEPTION("Message failed to generate pieces. [message] - [json_encode(message_pieces)]"))
return 0
// If you're muzzled, you can only speak sign language
// However, sign language is handled above.
if(is_muzzled())
to_chat(src, "<span class='danger'>You're muzzled and cannot speak!</span>")
return
//Clean up any remaining junk on the left like spaces.
message = trim_left(message)
//Autohiss handles auto-rolling tajaran R's and unathi S's/Z's
message = handle_autohiss(message, speaking)
//Whisper vars
var/w_scramble_range = 5 //The range at which you get ***as*th**wi****
var/w_adverb //An adverb prepended to the verb in whispers
var/w_not_heard //The message for people in watching range
var/datum/multilingual_say_piece/first_piece = message_pieces[1]
var/verb = ""
//Handle language-specific verbs and adverb setup if necessary
if(!whispering) //Just doing normal 'say' (for now, may change below)
verb = say_quote(message, speaking)
else if(whispering && speaking.whisper_verb) //Language has defined whisper verb
verb = speaking.whisper_verb
verb = say_quote(message, first_piece.speaking)
else if(whispering && first_piece.speaking.whisper_verb) //Language has defined whisper verb
verb = first_piece.speaking.whisper_verb
w_not_heard = "[verb] something"
else //Whispering but language has no whisper verb, use say verb
w_adverb = pick("quietly", "softly")
verb = speaking.speech_verb
w_not_heard = "[speaking.speech_verb] something [w_adverb]"
verb = first_piece.speaking.speech_verb
w_not_heard = "[first_piece.speaking.speech_verb] something [w_adverb]"
//For speech disorders (hulk, slurring, stuttering)
if(!(speaking && (speaking.flags & NO_STUTTER || speaking.flags & SIGNLANG)))
var/list/message_data = list(message, verb, whispering)
if(handle_speech_problems(message_data))
message = message_data[1]
whispering = message_data[3]
var/list/message_data = list(message_pieces, verb, whispering)
if(handle_speech_problems(message_data))
message_pieces = message_data[1]
whispering = message_data[3]
if(verb != message_data[2]) //They changed our verb
if(whispering)
w_adverb = pick("quietly", "softly")
verb = message_data[2]
if(verb != message_data[2]) //They changed our verb
if(whispering)
w_adverb = pick("quietly", "softly")
verb = message_data[2]
//Whisper may have adverbs, add those if one was set
if(w_adverb) verb = "[verb] [w_adverb]"
if(w_adverb)
verb = "[verb] [w_adverb]"
//If something nulled or emptied the message, forget it
if(!message || message == "")
if(!LAZYLEN(message_pieces))
return 0
//Radio message handling
var/list/obj/item/used_radios = new
if(handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name, whispering))
var/list/used_radios = list()
if(handle_message_mode(message_mode, message_pieces, verb, used_radios, whispering))
return 1
//For languages with actual speech sounds
@@ -268,16 +262,19 @@ proc/get_radio_key_from_channel(var/channel)
if(used_radios.len)
italics = 1
message_range = 1
if(speaking)
message_range = speaking.get_talkinto_msg_range(message)
if(first_piece.speaking)
message_range = first_piece.speaking.get_talkinto_msg_range(message)
var/msg
if(!speaking || !(speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>\The [src] talks into \the [used_radios[1]]</span>"
for(var/mob/living/M in hearers(5, src))
if((M != src) && msg)
if(!first_piece.speaking || !(first_piece.speaking.flags & NO_TALK_MSG))
msg = "<span class='notice'>[src] talks into [used_radios[1]]</span>"
if(msg)
for(var/mob/living/M in hearers(5, src) - src)
M.show_message(msg)
if (speech_sound)
sound_vol *= 0.5
if(speech_sound)
sound_vol *= 0.5
//Set vars if we're still whispering by this point
if(whispering)
@@ -285,6 +282,7 @@ proc/get_radio_key_from_channel(var/channel)
message_range = 1
sound_vol *= 0.5
<<<<<<< HEAD
//VOREStation edit - allows for custom say verbs, overriding all other say-verb types- e.g. "says loudly" instead of "shouts"
//You'll still stammer if injured or slur if drunk, but it won't have those specific words
var/ending = copytext(message, length(message))
@@ -308,6 +306,13 @@ proc/get_radio_key_from_channel(var/channel)
if (speaking.flags & NONVERBAL)
if (prob(30))
src.custom_emote(1, "[pick(speaking.signlang_verb)].")
=======
//Handle nonverbal languages here
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking.flags & NONVERBAL)
if(prob(30))
custom_emote(1, "[pick(S.speaking.signlang_verb)].")
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
//These will contain the main receivers of the message
var/list/listening = list()
@@ -318,12 +323,12 @@ proc/get_radio_key_from_channel(var/channel)
if(T)
//Air is too thin to carry sound at all, contact speech only
var/datum/gas_mixture/environment = T.return_air()
var/pressure = (environment)? environment.return_pressure() : 0
var/pressure = environment ? environment.return_pressure() : 0
if(pressure < SOUND_MINIMUM_PRESSURE)
message_range = 1
//Air is nearing minimum levels, make text italics as a hint, and muffle sound
if (pressure < ONE_ATMOSPHERE*0.4)
if(pressure < ONE_ATMOSPHERE * 0.4)
italics = 1
sound_vol *= 0.5
@@ -376,16 +381,16 @@ proc/get_radio_key_from_channel(var/channel)
var/image/I1 = listening[M] || speech_bubble
images_to_clients[I1] |= M.client
M << I1
M.hear_say(message, verb, speaking, alt_name, italics, src, speech_sound, sound_vol)
M.hear_say(message_pieces, verb, italics, src, speech_sound, sound_vol)
if(whispering) //Don't even bother with these unless whispering
if(dst > message_range && dst <= w_scramble_range) //Inside whisper scramble range
if(M.client)
var/image/I2 = listening[M] || speech_bubble
images_to_clients[I2] |= M.client
M << I2
M.hear_say(stars(message), verb, speaking, alt_name, italics, src, speech_sound, sound_vol*0.2)
M.hear_say(stars_all(message_pieces), verb, italics, src, speech_sound, sound_vol*0.2)
if(dst > w_scramble_range && dst <= world.view) //Inside whisper 'visible' range
M.show_message("<span class='game say'><span class='name'>[src.name]</span> [w_not_heard].</span>", 2)
M.show_message("<span class='game say'><span class='name'>[name]</span> [w_not_heard].</span>", 2)
//Object message delivery
for(var/obj/O in listening_obj)
@@ -393,7 +398,7 @@ proc/get_radio_key_from_channel(var/channel)
if(O && src) //If we still exist, when the spawn processes
var/dst = get_dist(get_turf(O),get_turf(src))
if(dst <= message_range)
O.hear_talk(src, message, verb, speaking)
O.hear_talk(src, message_pieces, verb)
//Remove all those images. At least it's just ONE spawn this time.
spawn(30)
@@ -410,7 +415,7 @@ proc/get_radio_key_from_channel(var/channel)
if(message_mode)
message = "([message_mode == "headset" ? "Common" : capitalize(message_mode)]) [message]" //Adds radio keys used if available
if(whispering)
log_whisper(message,src)
log_whisper(message, src)
else
log_say(message, src)
return 1
@@ -438,8 +443,41 @@ proc/get_radio_key_from_channel(var/channel)
/obj/effect/speech_bubble
var/mob/parent
/mob/living/proc/GetVoice()
/mob/proc/GetVoice()
return name
/mob/living/emote(var/act, var/type, var/message) //emote code is terrible, this is so that anything that isn't
if(stat) //already snowflaked to shit can call the parent and handle emoting sanely
return FALSE
if(..(act, type, message))
return TRUE
if(act && type && message)
log_emote(message, src)
for(var/mob/M in dead_mob_list)
if(!M.client)
continue
if(isnewplayer(M))
continue
if(isobserver(M) && M.is_preference_enabled(/datum/client_preference/ghost_sight))
M.show_message(message)
switch(type)
if(1) // Visible
visible_message(message)
return TRUE
if(2) // Audible
audible_message(message)
return TRUE
else
if(act == "help")
return // Mobs handle this individually
to_chat(src, "<span class='warning'>Unusable emote '[act]'. Say *help for a list.</span>")
/mob/proc/speech_bubble_appearance()
return "normal"
+63
View File
@@ -837,6 +837,69 @@ var/list/ai_verbs_default = list(
// If that is ever fixed please update this proc.
return TRUE
/mob/living/silicon/ai/handle_track(message, verb = "says", mob/speaker = null, speaker_name, hard_to_hear)
if(hard_to_hear)
return
var/jobname // the mob's "job"
var/mob/living/carbon/human/impersonating //The crew member being impersonated, if any.
var/changed_voice
if(ishuman(speaker))
var/mob/living/carbon/human/H = speaker
if(H.wear_mask && istype(H.wear_mask,/obj/item/clothing/mask/gas/voice))
changed_voice = 1
var/list/impersonated = new()
var/mob/living/carbon/human/I = impersonated[speaker_name]
if(!I)
for(var/mob/living/carbon/human/M in mob_list)
if(M.real_name == speaker_name)
I = M
impersonated[speaker_name] = I
break
// If I's display name is currently different from the voice name and using an agent ID then don't impersonate
// as this would allow the AI to track I and realize the mismatch.
if(I && !(I.name != speaker_name && I.wear_id && istype(I.wear_id,/obj/item/weapon/card/id/syndicate)))
impersonating = I
jobname = impersonating.get_assignment()
else
jobname = "Unknown"
else
jobname = H.get_assignment()
else if(iscarbon(speaker)) // Nonhuman carbon mob
jobname = "No id"
else if(isAI(speaker))
jobname = "AI"
else if(isrobot(speaker))
jobname = "Cyborg"
else if(istype(speaker, /mob/living/silicon/pai))
jobname = "Personal AI"
else
jobname = "Unknown"
var/track = ""
if(changed_voice)
if(impersonating)
track = "<a href='byond://?src=\ref[src];trackname=[html_encode(speaker_name)];track=\ref[impersonating]'>[speaker_name] ([jobname])</a>"
else
track = "[speaker_name] ([jobname])"
else
track = "<a href='byond://?src=\ref[src];trackname=[html_encode(speaker_name)];track=\ref[speaker]'>[speaker_name] ([jobname])</a>"
return track
/mob/living/silicon/ai/proc/relay_speech(mob/living/M, list/message_pieces, verb)
var/message = combine_message(message_pieces, verb, M)
var/name_used = M.GetVoice()
//This communication is imperfect because the holopad "filters" voices and is only designed to connect to the master only.
var/rendered = "<i><span class='game say'>Relayed Speech: <span class='name'>[name_used]</span> [message]</span></i>"
show_message(rendered, 2)
//Special subtype kept around for global announcements
/mob/living/silicon/ai/announcer/
is_dummy = 1
+113
View File
@@ -0,0 +1,113 @@
/mob/living/silicon/emote(var/act, var/m_type = 1,var/message = null)
var/param = null
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
if(findtext(act, "s", -1) && !findtext(act, "_", -2))//Removes ending s's unless they are prefixed with a '_'
act = copytext(act, 1, length(act))
switch(act)
if("beep")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> beeps at [param]."
else
message = "<b>[src]</b> beeps."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 1
if("ping")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> pings at [param]."
else
message = "<b>[src]</b> pings."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 1
if("buzz")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> buzzes at [param]."
else
message = "<b>[src]</b> buzzes."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 1
if("yes", "ye")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> emits an affirmative blip at [param]."
else
message = "<b>[src]</b> emits an affirmative blip."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 1
if("dwoop")
var/M = null
if(param)
for (var/mob/A in view(null, null))
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> chirps happily at [param]"
else
message = "<b>[src]</b> chirps happily."
playsound(src.loc, 'sound/machines/dwoop.ogg', 50, 0)
m_type = 1
if("no")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "<b>[src]</b> emits a negative blip at [param]."
else
message = "<b>[src]</b> emits a negative blip."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
m_type = 1
..(act, m_type, message)
+2 -2
View File
@@ -1,5 +1,5 @@
/mob/living/silicon/pai/say(var/msg)
/mob/living/silicon/pai/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(silence_time)
to_chat(src, "<font color=green>Communication circuits remain uninitialized.</font>")
else
..(msg)
..()
@@ -1,4 +1,4 @@
/mob/living/silicon/robot/drone/say(var/message)
/mob/living/silicon/robot/drone/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if(local_transmit)
if (src.client)
if(client.prefs.muted & MUTE_IC)
@@ -36,4 +36,4 @@
if(M.client)
to_chat(M, "<b>[src]</b> transmits, \"[message]\"")
return 1
return ..(message, 0)
return ..()
+61 -173
View File
@@ -1,6 +1,6 @@
/mob/living/silicon/robot/emote(var/act,var/m_type=1,var/message = null)
var/param = null
if (findtext(act, "-", 1, null))
if(findtext(act, "-", 1, null))
var/t1 = findtext(act, "-", 1, null)
param = copytext(act, t1 + 1, length(act) + 1)
act = copytext(act, 1, t1)
@@ -9,236 +9,124 @@
act = copytext(act,1,length(act))
switch(act)
if ("me")
if (src.client)
if(client.prefs.muted & MUTE_IC)
to_chat(src, "You cannot send IC messages (muted).")
return
if (stat)
return
if(!(message))
return
else
return custom_emote(m_type, message)
if ("custom")
return custom_emote(m_type, message)
if ("salute")
if (!src.buckled)
if("salute")
if(!src.buckled)
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
message = "salutes to [param]."
if(param)
message = "<b>[src]</b> salutes to [param]."
else
message = "salutes."
message = "<b>[src]</b> salutes."
m_type = 1
if ("bow")
if (!src.buckled)
if("bow")
if(!src.buckled)
var/M = null
if (param)
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if (!M)
if(!M)
param = null
if (param)
message = "bows to [param]."
if(param)
message = "<b>[src]</b> bows to [param]."
else
message = "bows."
message = "<b>[src]</b> bows."
m_type = 1
if ("clap")
if (!src.restrained())
message = "claps."
if("clap")
if(!src.restrained())
message = "<b>[src]</b> claps."
m_type = 2
if ("flap")
if (!src.restrained())
message = "flaps its wings."
if("flap")
if(!src.restrained())
message = "<b>[src]</b> flaps its wings."
m_type = 2
if ("aflap")
if (!src.restrained())
message = "flaps its wings ANGRILY!"
if("aflap")
if(!src.restrained())
message = "<b>[src]</b> flaps its wings ANGRILY!"
m_type = 2
if ("twitch")
message = "twitches."
if("twitch")
message = "<b>[src]</b> twitches."
m_type = 1
if ("twitch_v")
message = "twitches violently."
if("twitch_v")
message = "<b>[src]</b> twitches violently."
m_type = 1
if ("nod")
message = "nods."
if("nod")
message = "<b>[src]</b> nods."
m_type = 1
if ("deathgasp")
message = "shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
if("deathgasp")
message = "<b>[src]</b> shudders violently for a moment, then becomes motionless, its eyes slowly darkening."
m_type = 1
if ("glare")
var/M = null
if (param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "glares at [param]."
else
message = "glares."
if ("stare")
var/M = null
if (param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "stares at [param]."
else
message = "stares."
if ("look")
var/M = null
if (param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if (!M)
param = null
if (param)
message = "looks at [param]."
else
message = "looks."
m_type = 1
if("beep")
if("glare")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "beeps at [param]."
if(param)
message = "<b>[src]</b> glares at [param]."
else
message = "beeps."
playsound(src.loc, 'sound/machines/twobeep.ogg', 50, 0)
m_type = 1
message = "<b>[src]</b> glares."
if("ping")
if("stare")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "pings at [param]."
if(param)
message = "<b>[src]</b> stares at [param]."
else
message = "pings."
playsound(src.loc, 'sound/machines/ping.ogg', 50, 0)
m_type = 1
message = "<b>[src]</b> stares."
if("buzz")
if("look")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
if(param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "buzzes at [param]."
else
message = "buzzes."
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
m_type = 1
if("yes", "ye")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "emits an affirmative blip at [param]."
message = "<b>[src]</b> looks at [param]."
else
message = "emits an affirmative blip."
playsound(src.loc, 'sound/machines/synth_yes.ogg', 50, 0)
m_type = 1
if("dwoop")
var/M = null
if(param)
for (var/mob/A in view(null, null))
M = A
break
if(!M)
param = null
if (param)
message = "chirps happily at [param]"
else
message = "chirps happily."
playsound(src.loc, 'sound/machines/dwoop.ogg', 50, 0)
m_type = 1
if("no")
var/M = null
if(param)
for (var/mob/A in view(null, null))
if (param == A.name)
M = A
break
if(!M)
param = null
if (param)
message = "emits a negative blip at [param]."
else
message = "emits a negative blip."
playsound(src.loc, 'sound/machines/synth_no.ogg', 50, 0)
message = "<b>[src]</b> looks."
m_type = 1
if("law")
<<<<<<< HEAD
if (istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
message = "shows its legal authorization barcode."
=======
if(istype(module,/obj/item/weapon/robot_module/robot/security))
message = "<b>[src]</b> shows its legal authorization barcode."
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
playsound(src.loc, 'sound/voice/biamthelaw.ogg', 50, 0)
m_type = 2
@@ -246,20 +134,20 @@
to_chat(src, "You are not THE LAW, pal.")
if("halt")
<<<<<<< HEAD
if (istype(module,/obj/item/weapon/robot_module/robot/security) || istype(module,/obj/item/weapon/robot_module/robot/knine)) //VOREStation Add - K9
message = "<B>'s</B> speakers skreech, \"Halt! Security!\"."
=======
if(istype(module,/obj/item/weapon/robot_module/robot/security))
message = "<b>[src]</b> <B>'s</B> speakers skreech, \"Halt! Security!\"."
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
playsound(src.loc, 'sound/voice/halt.ogg', 50, 0)
m_type = 2
else
to_chat(src, "You are not security.")
if ("help")
if("help")
to_chat(src, "salute, bow-(none)/mob, clap, flap, aflap, twitch, twitch_s, nod, deathgasp, glare-(none)/mob, stare-(none)/mob, look, beep, ping, \nbuzz, law, halt, yes, dwoop, no")
else
to_chat(src, "<font color='blue'>Unusable emote '[act]'. Say *help for a list.</font>")
if ((message && src.stat == 0))
custom_emote(m_type,message)
return
..(act, m_type, message)
+23 -38
View File
@@ -1,10 +1,4 @@
/mob/living/silicon/say(var/message, var/sanitize = 1, var/whispering = 0)
return ..((sanitize ? sanitize(message) : message), whispering = whispering)
/mob/living/silicon/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
log_say(message, src)
/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/silicon/robot/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
if(!is_component_functioning("radio"))
@@ -17,7 +11,7 @@
/mob/living/silicon/speech_bubble_appearance()
return "synthetic"
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/silicon/ai/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode == "department")
return holopad_talk(message, verb, speaking)
@@ -29,7 +23,7 @@
message_mode = null
return aiRadio.talk_into(src,message,message_mode,verb,speaking)
/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios, alt_name)
/mob/living/silicon/pai/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
if(message_mode == "general")
@@ -50,29 +44,24 @@
#define IS_ROBOT 2
#define IS_PAI 3
/mob/living/silicon/say_understands(var/other,var/datum/language/speaking = null)
/mob/living/silicon/say_understands(var/other, var/datum/language/speaking = null)
//These only pertain to common. Languages are handled by mob/say_understands()
if (!speaking)
if (istype(other, /mob/living/carbon))
return 1
if (istype(other, /mob/living/silicon))
return 1
if (istype(other, /mob/living/carbon/brain))
return 1
if(!speaking)
if(iscarbon(other))
return TRUE
if(issilicon(other))
return TRUE
if(isbrain(other))
return TRUE
return ..()
//For holopads only. Usable by AI.
/mob/living/silicon/ai/proc/holopad_talk(var/message, verb, datum/language/speaking)
log_say("(HPAD) [message]",src)
message = trim(message)
if (!message)
return
/mob/living/silicon/ai/proc/holopad_talk(list/message_pieces, verb)
log_say("(HPAD) [multilingual_to_message(message_pieces)]",src)
var/obj/machinery/hologram/holopad/T = src.holo
if(T && T.masters[src])//If there is a hologram and its master is the user.
<<<<<<< HEAD
//Human-like, sorta, heard by those who understand humans.
var/rendered_a
//Speech distorted, heard by those who do not understand AIs.
@@ -87,33 +76,29 @@
rendered_a = "<span class='game say'><span class='name'>[name]</span> [verb], <span class='message'>\"[message]\"</span></span>"
rendered_b = "<span class='game say'><span class='name'>[voice_name]</span> [verb], <span class='message'>\"[message_stars]\"</span></span>"
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [verb], <span class='message'><span class='body'>\"[message]\"</span></span></span></i>") //The AI can "hear" its own message.
=======
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
var/list/listeners = get_mobs_and_objs_in_view_fast(get_turf(T), world.view)
var/list/listening = listeners["mobs"]
var/list/listening_obj = listeners["objs"]
for(var/mob/M in listening)
spawn(0)
if(M.say_understands(src))//If they understand AI speak. Humans and the like will be able to.
M.show_message(rendered_a, 2)
else//If they do not.
M.show_message(rendered_b, 2)
M.hear_holopad_talk(message_pieces, verb, src)
for(var/obj/O in listening_obj)
if(O == T) //Don't recieve your own speech
continue
spawn(0)
if(O && src) //If we still exist, when the spawn processes
O.hear_talk(src, message, verb, speaking)
O.hear_talk(src, message_pieces, verb)
/*Radios "filter out" this conversation channel so we don't need to account for them.
This is another way of saying that we won't bother dealing with them.*/
to_chat(src, "<i><span class='game say'>Holopad transmitted, <span class='name'>[real_name]</span> [combine_message(message_pieces, verb, src)]</span></i>")
else
to_chat(src, "No holopad connected.")
return 0
return 1
/mob/living/silicon/ai/proc/holopad_emote(var/message) //This is called when the AI uses the 'me' verb while using a holopad.
message = trim(message)
if (!message)
if(!message)
return
var/obj/machinery/hologram/holopad/T = src.holo
@@ -147,11 +132,11 @@
return 1
/mob/living/silicon/ai/emote(var/act, var/type, var/message)
var/obj/machinery/hologram/holopad/T = src.holo
var/obj/machinery/hologram/holopad/T = holo
if(T && T.masters[src]) //Is the AI using a holopad?
src.holopad_emote(message)
. = holopad_emote(message)
else //Emote normally, then.
..()
. = ..()
#undef IS_AI
#undef IS_ROBOT
+12 -12
View File
@@ -193,7 +193,14 @@
//Silicon mob language procs
/mob/living/silicon/can_speak(datum/language/speaking)
return universal_speak || (speaking in src.speech_synthesizer_langs) || (speaking.name == "Noise") //need speech synthesizer support to vocalize a language
if(universal_speak)
return TRUE
//need speech synthesizer support to vocalize a language
if(speaking in speech_synthesizer_langs)
return TRUE
if(speaking && speaking.flags & INNATE)
return TRUE
return FALSE
/mob/living/silicon/add_language(var/language, var/can_speak=1)
var/var/datum/language/added_language = GLOB.all_languages[language]
@@ -213,15 +220,11 @@
..(rem_language)
speech_synthesizer_langs -= removed_language
/mob/living/silicon/check_languages()
set name = "Check Known Languages"
set category = "IC"
set src = usr
var/dat = "<b><font size = 5>Known Languages</font></b><br/><br/>"
/mob/living/silicon/check_lang_data()
. = ""
if(default_language)
dat += "Current default language: [default_language] - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br/><br/>"
. += "Current default language: [default_language] - <a href='byond://?src=\ref[src];default_lang=reset'>reset</a><br><br>"
for(var/datum/language/L in languages)
if(!(L.flags & NONGLOBAL))
@@ -232,10 +235,7 @@
default_str = " - <a href='byond://?src=\ref[src];default_lang=\ref[L]'>set default</a>"
var/synth = (L in speech_synthesizer_langs)
dat += "<b>[L.name] ([get_language_prefix()][L.key])</b>[synth ? default_str : null]<br/>Speech Synthesizer: <i>[synth ? "YES" : "NOT SUPPORTED"]</i><br/>[L.desc]<br/><br/>"
src << browse(dat, "window=checklanguage")
return
. += "<b>[L.name] ([get_language_prefix()][L.key])</b>[synth ? default_str : null]<br>Speech Synthesizer: <i>[synth ? "YES" : "NOT SUPPORTED"]</i><br>[L.desc]<br><br>"
/mob/living/silicon/proc/toggle_sensor_mode()
var/sensor_type = input("Please select sensor type.", "Sensor Integration", null) in list("Security","Medical","Disable")
@@ -194,12 +194,6 @@
. = ..()
to_chat(src,"<b>You are \the [src].</b> [player_msg]")
/mob/living/simple_mob/emote(var/act, var/type, var/desc)
if(act)
..(act, type, desc)
/mob/living/simple_mob/SelfMove(turf/n, direct)
var/turf/old_turf = get_turf(src)
var/old_dir = dir
@@ -264,14 +258,11 @@
update_icon()
/mob/living/simple_mob/say(var/message,var/datum/language/language)
var/verb = "says"
/mob/living/simple_mob/say_quote(var/message, var/datum/language/speaking = null)
if(speak_emote.len)
verb = pick(speak_emote)
message = sanitize(message)
..(message, null, verb)
. = pick(speak_emote)
else if(speaking)
. = ..()
/mob/living/simple_mob/get_speech_ending(verb, var/ending)
return verb
@@ -205,7 +205,7 @@
return
// This is awful but its literally say code.
/mob/living/simple_mob/animal/borer/say(message)
/mob/living/simple_mob/animal/borer/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
message = sanitize(message)
message = capitalize(message)
@@ -224,10 +224,11 @@
if(copytext(message, 1, 2) == "*")
return emote(copytext(message, 2))
var/datum/language/L = parse_language(message)
if(L && L.flags & HIVEMIND)
L.broadcast(src,trim(copytext(message,3)), src.true_name)
return
var/list/message_pieces = parse_languages(message)
for(var/datum/multilingual_say_piece/S in message_pieces)
if(S.speaking && S.speaking.flags & HIVEMIND)
S.speaking.broadcast(src, trim(copytext(message, 3)), src.true_name)
return
if(!host)
if(chemicals >= 30)
@@ -5,7 +5,7 @@
real_name = "host brain"
universal_understand = 1
/mob/living/captive_brain/say(var/message)
/mob/living/captive_brain/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
if (src.client)
if(client.prefs.muted & MUTE_IC)
@@ -31,7 +31,12 @@
else if(M.stat == DEAD && M.is_preference_enabled(/datum/client_preference/ghost_ears))
to_chat(M, "The captive mind of [src] whispers, \"[message]\"")
/mob/living/captive_brain/me_verb(message as text)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/emote(var/message)
to_chat(src, "<span class='danger'>You cannot emote as a captive mind.</span>")
return
/mob/living/captive_brain/process_resist()
@@ -1,3 +1,4 @@
<<<<<<< HEAD
// Parrots can talk, and may repeat things it hears.
/mob/living/simple_mob/animal/passive/bird/parrot
name = "parrot"
@@ -249,4 +250,257 @@
if(holder.stat || !holder.say_list || !message || speaker == holder)
return
var/datum/say_list/S = holder.say_list
=======
// Parrots can talk, and may repeat things it hears.
/mob/living/simple_mob/animal/passive/bird/parrot
name = "parrot"
description_info = "You can give it a headset by clicking on it with a headset. \
To remove it, click the bird while on grab intent."
has_langs = list("Galactic Common", "Bird")
ai_holder_type = /datum/ai_holder/simple_mob/passive/parrot
// A headset, so that talking parrots can yell at the crew over comms.
// If set to a type, on initialize it will be instantiated into that type.
var/obj/item/device/radio/headset/my_headset = null
// Say list
/datum/say_list/bird/poly
speak = list(
"Poly wanna cracker!",
"Check the singulo, you chucklefucks!",
"Wire the solars, you lazy bums!",
"WHO TOOK THE DAMN HARDSUITS?",
"OH GOD ITS FREE CALL THE SHUTTLE",
"Danger! Crystal hyperstructure instability!",
"CRYSTAL DELAMINATION IMMINENT.",
"Tweet tweet, I'm a Teshari.",
"Chitters.",
"Meteors have been detected on a collision course with the station!"
)
// Lets the AI use headsets.
// Player-controlled parrots will need to do it manually.
/mob/living/simple_mob/animal/passive/bird/parrot/ISay(message)
if(my_headset && prob(50))
var/list/keys = list()
for(var/channel in my_headset.channels)
var/key = get_radio_key_from_channel(channel)
if(key)
keys += key
if(keys.len)
var/key_used = pick(keys)
return say("[key_used] [message]")
return say(message)
// Ugly saycode so parrots can use their headsets.
/mob/living/simple_mob/animal/passive/bird/parrot/handle_message_mode(message_mode, message, verb, speaking, used_radios)
..()
if(message_mode)
if(my_headset && istype(my_headset, /obj/item/device/radio))
my_headset.talk_into(src, message, message_mode, verb, speaking)
used_radios += my_headset
// Clicked on while holding an object.
/mob/living/simple_mob/animal/passive/bird/parrot/attackby(obj/item/I, mob/user)
if(istype(I, /obj/item/device/radio/headset))
give_headset(I, user)
return
return ..()
// Clicked on by empty hand.
/mob/living/simple_mob/animal/passive/bird/parrot/attack_hand(mob/living/L)
if(L.a_intent == I_GRAB && my_headset)
remove_headset(L)
else
..()
/mob/living/simple_mob/animal/passive/bird/parrot/proc/give_headset(obj/item/device/radio/headset/new_headset, mob/living/user)
if(!istype(new_headset))
to_chat(user, span("warning", "\The [new_headset] isn't a headset."))
return
if(my_headset)
to_chat(user, span("warning", "\The [src] is already wearing \a [my_headset]."))
return
else
user.drop_item(new_headset)
my_headset = new_headset
new_headset.forceMove(src)
to_chat(user, span("warning", "You place \a [new_headset] on \the [src]. You monster."))
to_chat(src, span("notice", "\The [user] gives you \a [new_headset]. You should put it to good use immediately."))
return
/mob/living/simple_mob/animal/passive/bird/parrot/proc/remove_headset(mob/living/user)
if(!my_headset)
to_chat(user, "<span class='warning'>\The [src] doesn't have a headset to remove, thankfully.</span>")
else
ISay("BAWWWWWK LEAVE THE HEADSET BAWKKKKK!")
my_headset.forceMove(get_turf(src))
user.put_in_hands(my_headset)
to_chat(user, span("notice", "You take away \the [src]'s [my_headset.name]. Finally."))
to_chat(src, span("warning", "\The [user] takes your [my_headset.name] away! How cruel!"))
my_headset = null
/mob/living/simple_mob/animal/passive/bird/parrot/examine(mob/user)
..()
if(my_headset)
to_chat(user, "It is wearing \a [my_headset].")
/mob/living/simple_mob/animal/passive/bird/parrot/Initialize()
if(my_headset)
my_headset = new my_headset(src)
return ..()
// Subtypes.
// Best Bird
/mob/living/simple_mob/animal/passive/bird/parrot/poly
name = "Poly"
desc = "It's a parrot. An expert on quantum cracker theory."
icon_state = "poly"
icon_rest = "poly-held"
icon_dead = "poly-dead"
tt_desc = "E Ara macao"
my_headset = /obj/item/device/radio/headset/headset_eng
say_list_type = /datum/say_list/bird/poly
// Best Bird with best headset.
/mob/living/simple_mob/animal/passive/bird/parrot/poly/ultimate
my_headset = /obj/item/device/radio/headset/omni
/mob/living/simple_mob/animal/passive/bird/parrot/kea
name = "kea"
desc = "A species of parrot. On Earth, they are unique among other parrots for residing in alpine climates. \
They are known to be intelligent and curious, which has made some consider them a pest."
icon_state = "kea"
icon_rest = "kea-held"
icon_dead = "kea-dead"
tt_desc = "E Nestor notabilis"
/mob/living/simple_mob/animal/passive/bird/parrot/eclectus
name = "eclectus"
desc = "A species of parrot, this species features extreme sexual dimorphism in their plumage's colors. \
A male eclectus has emerald green plumage, where as a female eclectus has red and purple plumage."
icon_state = "eclectus"
icon_rest = "eclectus-held"
icon_dead = "eclectus-dead"
tt_desc = "E Eclectus roratus"
/mob/living/simple_mob/animal/passive/bird/parrot/eclectus/Initialize()
gender = pick(MALE, FEMALE)
if(gender == FEMALE)
icon_state = "eclectusf"
icon_rest = "eclectusf-held"
icon_dead = "eclectusf-dead"
return ..()
/mob/living/simple_mob/animal/passive/bird/parrot/grey_parrot
name = "grey parrot"
desc = "A species of parrot. This one is predominantly grey, but has red tail feathers."
icon_state = "agrey"
icon_rest = "agrey-held"
icon_dead = "agrey-dead"
tt_desc = "E Psittacus erithacus"
/mob/living/simple_mob/animal/passive/bird/parrot/black_headed_caique
name = "black-headed caique"
desc = "A species of parrot, these birds have a distinct black color on their heads, distinguishing them from their relative Caiques."
icon_state = "bcaique"
icon_rest = "bcaique-held"
icon_dead = "bcaique-dead"
tt_desc = "E Pionites melanocephalus"
/mob/living/simple_mob/animal/passive/bird/parrot/white_caique
name = "white-bellied caique"
desc = "A species of parrot, they are also known as the Green-Thighed Parrot."
icon_state = "wcaique"
icon_rest = "wcaique-held"
icon_dead = "wcaique-dead"
tt_desc = "E Pionites leucogaster"
/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar
name = "budgerigar"
desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
This one is has its natural colors of green and yellow."
icon_state = "gbudge"
icon_rest = "gbudge-held"
icon_dead = "gbudge-dead"
tt_desc = "E Melopsittacus undulatus"
/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/blue
icon_state = "bbudge"
icon_rest = "bbudge-held"
icon_dead = "bbudge-dead"
desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
This one has a mutation which altered its color to be blue instead of green and yellow."
/mob/living/simple_mob/animal/passive/bird/parrot/budgerigar/bluegreen
icon_state = "bgbudge"
icon_rest = "bgbudge-held"
icon_dead = "bgbudge-dead"
desc = "A species of parrot, they are also known as the common parakeet, or in some circles, the budgie. \
This one has a mutation which altered its color to be a mix of blue and green."
/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel
name = "cockatiel"
desc = "A species of parrot. This one has a highly visible crest."
icon_state = "tiel"
icon_rest = "tiel-held"
icon_dead = "tiel-dead"
tt_desc = "E Nymphicus hollandicus"
/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/white
icon_state = "wtiel"
icon_rest = "wtiel-held"
icon_dead = "wtiel-dead"
/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/yellowish
icon_state = "luttiel"
icon_rest = "luttiel-held"
icon_dead = "luttiel-dead"
/mob/living/simple_mob/animal/passive/bird/parrot/cockatiel/grey
icon_state = "blutiel" // idk why this is blu.
icon_rest = "blutiel-held"
icon_dead = "blutiel-dead"
// This actually might be the yellow-crested cockatoo but idk.
/mob/living/simple_mob/animal/passive/bird/parrot/sulphur_cockatoo
name = "sulphur-crested cockatoo"
desc = "A species of parrot. This one has an expressive yellow crest. Their underwing and tail feathers are also yellow."
icon_state = "too"
icon_rest = "too-held"
icon_dead = "too-dead"
tt_desc = "E Cacatua galerita"
// This was originally called 'hooded_too', which might not mean the unbrella cockatoo but idk.
/mob/living/simple_mob/animal/passive/bird/parrot/white_cockatoo
name = "white cockatoo"
desc = "A species of parrot. This one is also known as the Umbrella Cockatoo, due to the semicircular shape of its crest."
icon_state = "utoo"
icon_rest = "utoo-held"
icon_dead = "utoo-dead"
tt_desc = "E Cacatua alba"
/mob/living/simple_mob/animal/passive/bird/parrot/pink_cockatoo
name = "pink cockatoo"
desc = "A species of parrot. This one is also known as Major Mitchell's cockatoo, \
in honor of a human surveyor and explorer who existed before humans fully explored their home planet."
icon_state = "mtoo"
icon_rest = "mtoo-held"
icon_dead = "mtoo-dead"
tt_desc = "E Lophochroa leadbeateri"
// AI
/datum/ai_holder/simple_mob/passive/parrot
speak_chance = 2
base_wander_delay = 8
/datum/ai_holder/simple_mob/passive/parrot/on_hear_say(mob/living/speaker, message)
if(holder.stat || !holder.say_list || !message || speaker == holder)
return
var/datum/say_list/S = holder.say_list
>>>>>>> 54a8a58... Saycode Overhaul -- Multilingualism (#6956)
S.speak |= message
+10 -10
View File
@@ -104,7 +104,7 @@
// Proc: say()
// Parameters: 4 (generic say() arguments)
// Description: Adds a speech bubble to the communicator device, then calls ..() to do the real work.
/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/verb="says", var/alt_name="", var/whispering=0)
/mob/living/voice/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
//Speech bubbles.
if(comm)
var/speech_bubble_test = say_test(message)
@@ -118,7 +118,7 @@
M << speech_bubble
src << speech_bubble
..(message, speaking, verb, alt_name, whispering) //mob/living/say() can do the actual talking.
..() //mob/living/say() can do the actual talking.
// Proc: speech_bubble_appearance()
// Parameters: 0
@@ -126,15 +126,15 @@
/mob/living/voice/speech_bubble_appearance()
return "comm"
/mob/living/voice/say_understands(var/other,var/datum/language/speaking = null)
/mob/living/voice/say_understands(var/other, var/datum/language/speaking = null)
//These only pertain to common. Languages are handled by mob/say_understands()
if (!speaking)
if (istype(other, /mob/living/carbon))
return 1
if (istype(other, /mob/living/silicon))
return 1
if (istype(other, /mob/living/carbon/brain))
return 1
if(!speaking)
if(iscarbon(other))
return TRUE
if(issilicon(other))
return TRUE
if(isbrain(other))
return TRUE
return ..()
/mob/living/voice/custom_emote(var/m_type=1,var/message = null,var/range=world.view)
+3
View File
@@ -1224,3 +1224,6 @@ mob/proc/yank_out_object()
selfimage.loc = src
return selfimage
/mob/proc/GetAltName()
return ""
+6
View File
@@ -184,6 +184,12 @@ proc/getsensorlevel(A)
p++
return t
/proc/stars_all(list/message_pieces, pr)
// eugh, we have to clone the list to avoid collateral damage due to the nature of these messages
. = list()
for(var/datum/multilingual_say_piece/S in message_pieces)
. += new /datum/multilingual_say_piece(S.speaking, stars(S.message))
proc/slur(phrase)
phrase = html_decode(phrase)
var/leng=length(phrase)
+1 -1
View File
@@ -605,7 +605,7 @@
return ready && ..()
// Prevents lobby players from seeing say, even with ghostears
/mob/new_player/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/alt_name = "",var/italics = 0, var/mob/speaker = null)
/mob/new_player/hear_say(var/message, var/verb = "says", var/datum/language/language = null, var/italics = 0, var/mob/speaker = null)
return
// Prevents lobby players from seeing emotes, even with ghosteyes
+140 -55
View File
@@ -1,4 +1,4 @@
/mob/proc/say()
/mob/proc/say(var/message, var/datum/language/speaking = null, var/whispering = 0)
return
/mob/verb/whisper(message as text)
@@ -30,7 +30,7 @@
set_typing_indicator(FALSE)
if(use_me)
usr.emote("me",usr.emote_type,message)
custom_emote(usr.emote_type, message)
else
usr.emote(message)
@@ -42,7 +42,7 @@
if(!client)
return // Clientless mobs shouldn't be trying to talk in deadchat.
if(!src.client.holder)
if(!client.holder)
if(!config.dsay_allowed)
to_chat(src, "<span class='danger'>Deadchat is globally muted.</span>")
return
@@ -55,55 +55,55 @@
say_dead_direct("[pick("complains","moans","whines","laments","blubbers")], <span class='message'>\"[message]\"</span>", src)
/mob/proc/say_understands(var/mob/other,var/datum/language/speaking = null)
if (src.stat == DEAD)
return 1
/mob/proc/say_understands(var/mob/other, var/datum/language/speaking = null)
if(stat == DEAD)
return TRUE
//Universal speak makes everything understandable, for obvious reasons.
else if(src.universal_speak || src.universal_understand)
return 1
else if(universal_speak || universal_understand)
return TRUE
//Languages are handled after.
if (!speaking)
if(!speaking)
if(!other)
return 1
return TRUE
if(other.universal_speak)
return 1
return TRUE
if(isAI(src) && ispAI(other))
return 1
if (istype(other, src.type) || istype(src, other.type))
return 1
return 0
return TRUE
if(istype(other, type) || istype(src, other.type))
return TRUE
return FALSE
if(speaking.flags & INNATE)
return 1
return TRUE
//non-verbal languages are garbled if you can't see the speaker. Yes, this includes if they are inside a closet.
if(speaking.flags & NONVERBAL)
if(sdisabilities & BLIND || blinded)
return FALSE
if(!other || !(other in view(src)))
return FALSE
//Language check.
for(var/datum/language/L in src.languages)
for(var/datum/language/L in languages)
if(speaking.name == L.name)
return 1
return TRUE
return 0
/*
***Deprecated***
let this be handled at the hear_say or hear_radio proc
This is left in for robot speaking when humans gain binary channel access until I get around to rewriting
robot_talk() proc.
There is no language handling build into it however there is at the /mob level so we accept the call
for it but just ignore it.
*/
return FALSE
/mob/proc/say_quote(var/message, var/datum/language/speaking = null)
var/verb = "says"
var/ending = copytext(message, length(message))
if(ending=="!")
verb=pick("exclaims","shouts","yells")
else if(ending=="?")
verb="asks"
var/verb = "says"
var/ending = copytext(message, length(message))
return verb
if(speaking)
verb = speaking.get_spoken_verb(ending)
else
if(ending == "!")
verb = pick("exclaims", "shouts", "yells")
else if(ending == "?")
verb = "asks"
return verb
/mob/proc/emote(var/act, var/type, var/message)
@@ -120,38 +120,123 @@
/mob/proc/say_test(var/text)
var/ending = copytext(text, length(text))
if (ending == "?")
if(ending == "?")
return "1"
else if (ending == "!")
else if(ending == "!")
return "2"
return "0"
//parses the message mode code (e.g. :h, :w) from text, such as that supplied to say.
//returns the message mode string or null for no message mode.
//standard mode is the mode returned for the special ';' radio code.
/mob/proc/parse_message_mode(var/message, var/standard_mode="headset")
if(length(message) >= 1 && copytext(message,1,2) == ";")
/mob/proc/parse_message_mode(var/message, var/standard_mode = "headset")
if(length(message) >= 1 && copytext(message, 1, 2) == ";")
return standard_mode
if(length(message) >= 2)
var/channel_prefix = copytext(message, 1 ,3)
var/channel_prefix = copytext(message, 1, 3)
return department_radio_keys[channel_prefix]
return null
//parses the language code (e.g. :j) from text, such as that supplied to say.
//returns the language object only if the code corresponds to a language that src can speak, otherwise null.
/mob/proc/parse_language(var/message)
var/prefix = copytext(message,1,2)
// This is for audible emotes
if(length(message) >= 1 && prefix == "!")
return GLOB.all_languages["Noise"]
/datum/multilingual_say_piece
var/datum/language/speaking = null
var/message = ""
if(length(message) >= 2 && is_language_prefix(prefix))
var/language_prefix = copytext(message, 2 ,3)
var/datum/language/L = GLOB.language_keys[language_prefix]
if (can_speak(L))
return L
/datum/multilingual_say_piece/New(datum/language/new_speaking, new_message)
. = ..()
speaking = new_speaking
if(new_message)
message = new_message
/mob/proc/find_valid_prefixes(message)
var/list/prefixes = list() // [["Common", start, end], ["Gutter", start, end]]
for(var/i in 1 to length(message))
// This grabs trimmed 3 character substrings, to allow for up to 1 prefix and 1 letter language keys
var/selection = trim_right(lowertext(copytext(message, i, i + 2)))
// The first character in the selection will always be the prefix (if this is a valid language invocation)
var/prefix = copytext(selection, 1, 2)
var/language_key = copytext(selection, 2, 3)
if(is_language_prefix(prefix))
// Okay, we're definitely now trying to invoke a language (probably)
// This "[]" is probably unnecessary but BYOND will runtime if a number is used
var/datum/language/L = GLOB.language_keys["[language_key]"]
// It's kinda silly that we have to check L != null and this isn't done for us by can_speak (it runtimes instead), but w/e
if(L && can_speak(L))
// So we have a valid language invocation, and we can speak that language, let's make a piece for it
// This language will be the language until the next prefixes[] index, or the end of the message if there are none.
prefixes[++prefixes.len] = list(L, i, i + length(selection))
else if(L)
// We found a valid language, but they can't speak it. Let's make them speak gibberish instead.
prefixes[++prefixes.len] = list(GLOB.all_languages[LANGUAGE_GIBBERISH], i, i + length(selection))
continue
if(i == 1)
// This covers the case of "no prefixes in use."
prefixes[++prefixes.len] = list(get_default_language(), i, i)
return prefixes
/mob/proc/strip_prefixes(message, mob/prefixer = null)
. = ""
var/last_index = 1
for(var/i in 1 to length(message))
var/selection = trim_right(lowertext(copytext(message, i, i + 2)))
// The first character in the selection will always be the prefix (if this is a valid language invocation)
var/prefix = copytext(selection, 1, 2)
var/language_key = copytext(selection, 2, 3)
if(is_language_prefix(prefix))
var/datum/language/L = GLOB.language_keys["[language_key]"]
if(L)
. += copytext(message, last_index, i)
last_index = i + 2
if(i + 1 > length(message))
. += copytext(message, last_index)
// this returns a structured message with language sections
// list(/datum/multilingual_say_piece(common, "hi"), /datum/multilingual_say_piece(farwa, "squik"), /datum/multilingual_say_piece(common, "meow!"))
/mob/proc/parse_languages(message)
. = list()
// Noise language is a snowflake.
if(copytext(message, 1, 2) == "!" && length(message) > 1)
// Note that list() here is intended
// Returning a raw /datum/multilingual_say_piece is supported, but only for hivemind languages
// What we actually want is a normal say piece that's all noise lang
return list(new /datum/multilingual_say_piece(GLOB.all_languages["Noise"], trim(strip_prefixes(copytext(message, 2)))))
// Scan the message for prefixes
var/list/prefix_locations = find_valid_prefixes(message)
if(!LAZYLEN(prefix_locations)) // There are no prefixes... or at least, no _valid_ prefixes.
. += new /datum/multilingual_say_piece(get_default_language(), trim(strip_prefixes(message))) // So we'll just strip those pesky things and still make the message.
for(var/i in 1 to length(prefix_locations))
var/current = prefix_locations[i] // ["Common", start, end]
// There are a few things that will make us want to ignore all other languages in - namely, HIVEMIND languages.
var/datum/language/L = current[1]
if(L && (L.flags & HIVEMIND || L.flags & SIGNLANG))
return new /datum/multilingual_say_piece(L, trim(strip_prefixes(message)))
if(i + 1 > length(prefix_locations)) // We are out of lookaheads, that means the rest of the message is in cur lang
var/spoke_message = handle_autohiss(trim(copytext(message, current[3])), L)
. += new /datum/multilingual_say_piece(current[1], spoke_message)
else
return GLOB.all_languages[LANGUAGE_GIBBERISH]
return null
var/next = prefix_locations[i + 1] // We look ahead at the next message to see where we need to stop.
var/spoke_message = handle_autohiss(trim(copytext(message, current[3], next[2])), L)
. += new /datum/multilingual_say_piece(current[1], spoke_message)
/* These are here purely because it would be hell to try to convert everything over to using the multi-lingual system at once */
/proc/message_to_multilingual(message, datum/language/speaking = null)
. = list(new /datum/multilingual_say_piece(speaking, message))
/proc/multilingual_to_message(list/message_pieces, var/requires_machine_understands = FALSE, var/with_capitalization = FALSE)
. = ""
for(var/datum/multilingual_say_piece/S in message_pieces)
var/message_to_append = S.message
if(S.speaking)
if(with_capitalization)
message_to_append = S.speaking.format_message_plain(S.message)
if(requires_machine_understands && !S.speaking.machine_understands)
message_to_append = S.speaking.scramble(S.message)
. += message_to_append + " "
. = trim_right(.)