Skip to content

Commit

Permalink
TGS Test Merge (#15961)
Browse files Browse the repository at this point in the history
  • Loading branch information
comfyorange committed Sep 14, 2024
2 parents 936eb84 + f718eaf commit 8af999e
Show file tree
Hide file tree
Showing 10 changed files with 159 additions and 19 deletions.
7 changes: 7 additions & 0 deletions code/__DEFINES/tts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
#define TTS_SOUND_BLIPS "Blips Only"
GLOBAL_LIST_INIT(all_tts_options, list(TTS_SOUND_OFF, TTS_SOUND_ENABLED, TTS_SOUND_BLIPS))

#define RADIO_TTS_SL (1<<0)
#define RADIO_TTS_SQUAD (1<<1)
#define RADIO_TTS_COMMAND (1<<2)
#define RADIO_TTS_ALL (1<<3)

GLOBAL_LIST_INIT(all_radio_tts_options, list(RADIO_TTS_SL, RADIO_TTS_SQUAD, RADIO_TTS_COMMAND, RADIO_TTS_ALL))

///TTS filter to activate start/stop radio clicks on speech.
#define TTS_FILTER_RADIO "radio"
///TTS filter to activate a silicon effect on speech.
Expand Down
8 changes: 8 additions & 0 deletions code/__HELPERS/sanitize_values.dm
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,14 @@
if(length(L))
return L[1]

/proc/sanitize_bitfield(value, list/L, default)
for(var/flag in bitfield2list(value))
if(flag in L)
continue
if(default)
return default
return value

///a wrapper with snowflake handling for tts
/proc/sanitize_inlist_tts(value, gender)
var/list/to_check
Expand Down
48 changes: 33 additions & 15 deletions code/controllers/subsystem/tts.dm
Original file line number Diff line number Diff line change
Expand Up @@ -104,32 +104,47 @@ SUBSYSTEM_DEF(tts)
return SS_INIT_FAILURE
return SS_INIT_SUCCESS

/datum/controller/subsystem/tts/proc/play_tts(target, list/listeners, sound/audio, sound/audio_blips, datum/language/language, range = 7, volume_offset = 0, pitch = 0, silicon = "")
/datum/controller/subsystem/tts/proc/play_tts(target, list/listeners, sound/audio, sound/audio_blips, datum/language/language, range = 7, volume_offset = 0, pitch = 0, silicon = "", directionality = TRUE)
var/turf/turf_source = get_turf(target)
if(!turf_source)
return

var/channel = SSsounds.random_available_channel()
for(var/mob/listening_mob in listeners | SSmobs.dead_players_by_zlevel[turf_source.z])//observers always hear through walls
if(directionality)
for(var/mob/listening_mob in listeners | SSmobs.dead_players_by_zlevel[turf_source.z])//observers always hear through walls
var/volume_to_play_at = listening_mob.client?.prefs.volume_tts
var/tts_pref = listening_mob.client?.prefs.sound_tts
if(volume_to_play_at == 0 || tts_pref == TTS_SOUND_OFF)
continue

var/sound_volume = ((listening_mob == target)? 60 : 85) + volume_offset
sound_volume = sound_volume * (volume_to_play_at / 100)
var/datum/language_holder/holder = listening_mob.get_language_holder()
var/audio_to_use = (tts_pref == TTS_SOUND_BLIPS) ? audio_blips : audio
if(!holder.has_language(language))
continue
if(get_dist(listening_mob, turf_source) <= range)
listening_mob.playsound_local(
turf_source,
soundin = audio_to_use,
vol = sound_volume,
channel = channel,
distance_multiplier = 1,
)
return

//If the TTS is not directional, we don't have to worry about falloff
for(var/mob/listening_mob in listeners)
var/volume_to_play_at = listening_mob.client?.prefs.volume_tts
var/tts_pref = listening_mob.client?.prefs.sound_tts
if(volume_to_play_at == 0 || tts_pref == TTS_SOUND_OFF)
continue

var/sound_volume = ((listening_mob == target)? 60 : 85) + volume_offset
sound_volume = sound_volume * (volume_to_play_at / 100)
var/datum/language_holder/holder = listening_mob.get_language_holder()
var/audio_to_use = (tts_pref == TTS_SOUND_BLIPS) ? audio_blips : audio
if(!holder.has_language(language))
continue
if(get_dist(listening_mob, turf_source) <= range)
listening_mob.playsound_local(
turf_source,
soundin = audio_to_use,
vol = sound_volume,
channel = channel,
distance_multiplier = 1,
)
listening_mob.playsound_local(get_turf(listening_mob), soundin = audio_to_use, vol = volume_to_play_at, channel = channel)

// Need to wait for all HTTP requests to complete here because of a rustg crash bug that causes crashes when dd restarts whilst HTTP requests are ongoing.
/datum/controller/subsystem/tts/Shutdown()
Expand Down Expand Up @@ -241,7 +256,7 @@ SUBSYSTEM_DEF(tts)
else if(current_target.when_to_play < world.time)
audio_file = new(current_target.audio_file)
audio_file_blips = new(current_target.audio_file_blips)
play_tts(tts_target, current_target.listeners, audio_file, audio_file_blips, current_target.language, current_target.message_range, current_target.volume_offset)
play_tts(tts_target, current_target.listeners, audio_file, audio_file_blips, current_target.language, current_target.message_range, current_target.volume_offset, current_target.directionality)
if(length(data) != 1)
var/datum/tts_request/next_target = data[2]
next_target.when_to_play = world.time + current_target.audio_length
Expand All @@ -257,7 +272,7 @@ SUBSYSTEM_DEF(tts)

#undef TTS_ARBRITRARY_DELAY

/datum/controller/subsystem/tts/proc/queue_tts_message(datum/target, message, datum/language/language, speaker, filter, list/listeners, local = FALSE, message_range = 7, volume_offset = 0, pitch = 0, special_filters = "")
/datum/controller/subsystem/tts/proc/queue_tts_message(datum/target, message, datum/language/language, speaker, filter, list/listeners, local = FALSE, message_range = 7, volume_offset = 0, pitch = 0, special_filters = "", directionality = TRUE)
if(!tts_enabled)
return

Expand Down Expand Up @@ -286,7 +301,7 @@ SUBSYSTEM_DEF(tts)
var/file_name_blips = "tmp/tts/[identifier]_blips.ogg"
request.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name)
request_blips.prepare(RUSTG_HTTP_METHOD_GET, "[CONFIG_GET(string/tts_http_url)]/tts-blips?voice=[speaker]&identifier=[identifier]&filter=[url_encode(filter)]&pitch=[pitch]&special_filters=[url_encode(special_filters)]", json_encode(list("text" = shell_scrubbed_input)), headers, file_name_blips)
var/datum/tts_request/current_request = new /datum/tts_request(identifier, request, request_blips, shell_scrubbed_input, target, local, language, message_range, volume_offset, listeners, pitch)
var/datum/tts_request/current_request = new /datum/tts_request(identifier, request, request_blips, shell_scrubbed_input, target, local, language, message_range, volume_offset, listeners, pitch, directionality)
var/list/player_queued_tts_messages = queued_tts_messages[target]
if(!player_queued_tts_messages)
player_queued_tts_messages = list()
Expand Down Expand Up @@ -338,6 +353,8 @@ SUBSYSTEM_DEF(tts)
var/use_blips = FALSE
/// What's the pitch adjustment?
var/pitch = 0
/// If false, play at full volume to each listener, regardless of distance
var/directionality = TRUE

/datum/tts_request/New(identifier, datum/http_request/request, datum/http_request/request_blips, message, target, local, datum/language/language, message_range, volume_offset, list/listeners, pitch)
. = ..()
Expand All @@ -352,6 +369,7 @@ SUBSYSTEM_DEF(tts)
src.volume_offset = volume_offset
src.listeners = listeners
src.pitch = pitch
src.directionality = directionality
start_time = world.time

/datum/tts_request/proc/start_requests()
Expand Down
2 changes: 1 addition & 1 deletion code/game/objects/items/radio/headset.dm
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Defines for TTS modes.
// Used for translating channels to tokens on examination
GLOBAL_LIST_INIT(channel_tokens, list(
RADIO_CHANNEL_REQUISITIONS = RADIO_TOKEN_REQUISITIONS,
Expand Down Expand Up @@ -27,7 +28,6 @@ GLOBAL_LIST_INIT(channel_tokens, list(
equip_slot_flags = ITEM_SLOT_EARS
var/obj/item/encryptionkey/keyslot2 = null


/obj/item/radio/headset/Initialize(mapload)
if(keyslot)
keyslot = new keyslot(src)
Expand Down
6 changes: 3 additions & 3 deletions code/game/objects/machinery/overwatch.dm
Original file line number Diff line number Diff line change
Expand Up @@ -986,17 +986,17 @@ GLOBAL_LIST_EMPTY(active_cas_targets)
switch(command_aura)
if("move")
var/image/move = image('icons/mob/talk.dmi', src, icon_state = "order_move")
message = pick(";GET MOVING!", ";GO, GO, GO!", ";WE ARE ON THE MOVE!", ";MOVE IT!", ";DOUBLE TIME!", ";ONWARDS!", ";MOVE MOVE MOVE!", ";ON YOUR FEET!", ";GET A MOVE ON!", ";ON THE DOUBLE!", ";ROLL OUT!", ";LET'S GO, LET'S GO!", ";MOVE OUT!", ";LEAD THE WAY!", ";FORWARD!", ";COME ON, MOVE!", ";HURRY, GO!")
message = pick("GET MOVING!", "GO, GO, GO!", "WE ARE ON THE MOVE!", "MOVE IT!", "DOUBLE TIME!", "ONWARDS!", "MOVE MOVE MOVE!", "ON YOUR FEET!", "GET A MOVE ON!", "ON THE DOUBLE!", "ROLL OUT!", "LET'S GO, LET'S GO!", "MOVE OUT!", "LEAD THE WAY!", "FORWARD!", "COME ON, MOVE!", "HURRY, GO!")
say(message)
add_emote_overlay(move)
if("hold")
var/image/hold = image('icons/mob/talk.dmi', src, icon_state = "order_hold")
message = pick(";DUCK AND COVER!", ";HOLD THE LINE!", ";HOLD POSITION!", ";STAND YOUR GROUND!", ";STAND AND FIGHT!", ";TAKE COVER!", ";COVER THE AREA!", ";BRACE FOR COVER!", ";BRACE!", ";INCOMING!")
message = pick("DUCK AND COVER!", "HOLD THE LINE!", "HOLD POSITION!", "STAND YOUR GROUND!", "STAND AND FIGHT!", "TAKE COVER!", "COVER THE AREA!", "BRACE FOR COVER!", "BRACE!", "INCOMING!")
say(message)
add_emote_overlay(hold)
if("focus")
var/image/focus = image('icons/mob/talk.dmi', src, icon_state = "order_focus")
message = pick(";FOCUS FIRE!", ";PICK YOUR TARGETS!", ";CENTER MASS!", ";CONTROLLED BURSTS!", ";AIM YOUR SHOTS!", ";READY WEAPONS!", ";TAKE AIM!", ";LINE YOUR SIGHTS!", ";LOCK AND LOAD!", ";GET READY TO FIRE!")
message = pick("FOCUS FIRE!", "PICK YOUR TARGETS!", "CENTER MASS!", "CONTROLLED BURSTS!", "AIM YOUR SHOTS!", "READY WEAPONS!", "TAKE AIM!", "LINE YOUR SIGHTS!", "LOCK AND LOAD!", "GET READY TO FIRE!")
say(message)
add_emote_overlay(focus)

Expand Down
42 changes: 42 additions & 0 deletions code/game/objects/machinery/telecomms/broadcasting.dm
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,48 @@
continue
hearer.Hear(rendered, virt, language, message, frequency, spans)


//Check that speaker isn't banned from TTS
var/atom/movable/speaker = virt?.source
var/banned = FALSE
if(ismob(speaker))
var/mob/potential_user = speaker
if(is_banned_from(potential_user.ckey, "TTS") || potential_user.client?.prefs.muted & MUTE_TTS)
banned = TRUE

//If they aren't, handle radio TTS
if(speaker && speaker.voice && !banned)
var/is_speaker_squad_lead = FALSE
if(ishuman(speaker))
var/mob/living/carbon/human/human_speaker = speaker
if(human_speaker.assigned_squad?.squad_leader == speaker)
is_speaker_squad_lead = TRUE

var/is_speaker_command_freq = FALSE
if(frequency == FREQ_COMMAND || frequency == FREQ_COMMAND_SOM)
is_speaker_command_freq = TRUE

if(speaker in receive)
receive -= speaker //This list isn't used again, so we can just cut out the original speaker from it so TTS doesn't play twice

var/list/list_of_listeners
for(var/mob/living/carbon/human/potential_hearer in receive)
if(potential_hearer.stat >= UNCONSCIOUS || potential_hearer.disabilities & DEAF || !(potential_hearer.client?.prefs.sound_tts != TTS_SOUND_OFF))
continue

var/radio_flags = potential_hearer.client.prefs.radio_tts_flags
if(CHECK_BITFIELD(radio_flags, RADIO_TTS_ALL))
list_of_listeners += potential_hearer
continue
if(potential_hearer.assigned_squad?.radio_freq == frequency && (CHECK_BITFIELD(radio_flags, RADIO_TTS_SQUAD) || (CHECK_BITFIELD(radio_flags, RADIO_TTS_SL) && is_speaker_squad_lead)))
list_of_listeners += potential_hearer
continue
if(CHECK_BITFIELD(radio_flags, RADIO_TTS_COMMAND) && is_speaker_command_freq)
list_of_listeners += potential_hearer
continue

INVOKE_ASYNC(SStts, TYPE_PROC_REF(/datum/controller/subsystem/tts, queue_tts_message), list_of_listeners, html_decode(message), language, speaker.voice, speaker.voice_filter, local = TRUE, pitch = speaker.pitch, special_filters = TTS_FILTER_RADIO, directionality = FALSE)

var/spans_part = ""
if(length(spans))
spans_part = "(spans:"
Expand Down
2 changes: 2 additions & 0 deletions code/modules/client/preferences.dm
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
var/tts_pitch = 0
///Volume to use for tts
var/volume_tts = 100
///Which types of comms the user wants to hear TTS from
var/radio_tts_flags = RADIO_TTS_SL | RADIO_TTS_SQUAD | RADIO_TTS_COMMAND

/// Preference for letting people make TGUI windows use more accessible (basically, default) themes, where needed/possible.
/// Example application: health analyzers using this to choose between default themes or the NtOS themes.
Expand Down
4 changes: 4 additions & 0 deletions code/modules/client/preferences_savefile.dm
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@
READ_FILE(S["tooltips"], tooltips)
READ_FILE(S["sound_tts"], sound_tts)
READ_FILE(S["volume_tts"], volume_tts)
READ_FILE(S["radio_tts_flags"], radio_tts_flags)
READ_FILE(S["fast_mc_refresh"], fast_mc_refresh)
READ_FILE(S["split_admin_tabs"], split_admin_tabs)

Expand Down Expand Up @@ -228,6 +229,7 @@
tooltips = sanitize_integer(tooltips, FALSE, TRUE, initial(tooltips))
sound_tts = sanitize_inlist(sound_tts, GLOB.all_tts_options, initial(sound_tts))
volume_tts = sanitize_integer(volume_tts, 1, 100, initial(volume_tts))
radio_tts_flags = sanitize_bitfield(radio_tts_flags, GLOB.all_radio_tts_options, (RADIO_TTS_SL | RADIO_TTS_SQUAD | RADIO_TTS_COMMAND))

key_bindings = sanitize_islist(key_bindings, list())
if (!length(key_bindings))
Expand Down Expand Up @@ -304,6 +306,7 @@
tooltips = sanitize_integer(tooltips, FALSE, TRUE, initial(tooltips))
sound_tts = sanitize_inlist(sound_tts, GLOB.all_tts_options, initial(sound_tts))
volume_tts = sanitize_integer(volume_tts, 1, 100, initial(volume_tts))
radio_tts_flags = sanitize_bitfield(radio_tts_flags, GLOB.all_radio_tts_options, (RADIO_TTS_SL | RADIO_TTS_SQUAD | RADIO_TTS_COMMAND))

mute_self_combat_messages = sanitize_integer(mute_self_combat_messages, FALSE, TRUE, initial(mute_self_combat_messages))
mute_others_combat_messages = sanitize_integer(mute_others_combat_messages, FALSE, TRUE, initial(mute_others_combat_messages))
Expand Down Expand Up @@ -356,6 +359,7 @@
WRITE_FILE(S["tooltips"], tooltips)
WRITE_FILE(S["sound_tts"], sound_tts)
WRITE_FILE(S["volume_tts"], volume_tts)
WRITE_FILE(S["radio_tts_flags"], radio_tts_flags)
WRITE_FILE(S["slot_draw_order"], slot_draw_order_pref)

WRITE_FILE(S["mute_self_combat_messages"], mute_self_combat_messages)
Expand Down
25 changes: 25 additions & 0 deletions code/modules/client/preferences_ui.dm
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
data["mute_xeno_health_alert_messages"] = mute_xeno_health_alert_messages
data["sound_tts"] = sound_tts
data["volume_tts"] = volume_tts
data["radio_tts_flags"] = radio_tts_flags
data["accessible_tgui_themes"] = accessible_tgui_themes
data["tgui_fancy"] = tgui_fancy
data["tgui_lock"] = tgui_lock
Expand Down Expand Up @@ -637,6 +638,30 @@
new_vol = round(new_vol)
volume_tts = clamp(new_vol, 0, 100)

if("toggle_radio_tts_setting")
switch(params["newsetting"])
if("sl")
TOGGLE_BITFIELD(radio_tts_flags, RADIO_TTS_SL)
if(!CHECK_BITFIELD(radio_tts_flags, RADIO_TTS_SL)) //When SL radio is being disabled, disable squad radio too
DISABLE_BITFIELD(radio_tts_flags, RADIO_TTS_SQUAD)

if("squad")
TOGGLE_BITFIELD(radio_tts_flags, RADIO_TTS_SQUAD)
if(CHECK_BITFIELD(radio_tts_flags, RADIO_TTS_SQUAD))
ENABLE_BITFIELD(radio_tts_flags, RADIO_TTS_SL) //Enable SL TTS if not already enabled

if("command")
TOGGLE_BITFIELD(radio_tts_flags, RADIO_TTS_COMMAND)

if("all")
TOGGLE_BITFIELD(radio_tts_flags, RADIO_TTS_ALL)
if(CHECK_BITFIELD(radio_tts_flags, RADIO_TTS_ALL)) //Enable all other channels when 'ALL' is enabled
for(var/flag in GLOB.all_radio_tts_options)
ENABLE_BITFIELD(radio_tts_flags, flag)

if(!CHECK_MULTIPLE_BITFIELDS(radio_tts_flags, RADIO_TTS_SL|RADIO_TTS_SQUAD|RADIO_TTS_COMMAND))
DISABLE_BITFIELD(radio_tts_flags, RADIO_TTS_ALL)

if("accessible_tgui_themes")
accessible_tgui_themes = !accessible_tgui_themes

Expand Down
34 changes: 34 additions & 0 deletions tgui/packages/tgui/interfaces/PlayerPreferences/GameSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,22 @@ export const GameSettings = (props) => {
const { act, data } = useBackend<GameSettingData>();
const { ui_style_color, scaling_method, pixel_size, parallax, is_admin } =
data;

// Remember to update this alongside defines
const TTSRadioSetting = ['sl', 'squad', 'command', 'all'];
const TTSRadioSettingToBitfield = {
sl: 1 << 0,
squad: 1 << 1,
command: 1 << 2,
all: 1 << 3,
};
const TTSRadioSettingToName = {
sl: 'Squad Leader',
squad: 'Squad',
command: 'Command',
all: 'All Channels',
};

return (
<Section title="Game Settings">
<Stack fill>
Expand Down Expand Up @@ -78,6 +94,24 @@ export const GameSettings = (props) => {
label="Text to speech volume"
value="volume_tts"
/>
<LabeledList.Item label={'Text to Speech radio configuration'}>
{TTSRadioSetting.map((setting) => (
<Button.Checkbox
inline
key={setting}
content={TTSRadioSettingToName[setting]}
checked={
TTSRadioSettingToBitfield[setting] &
data['radio_tts_flags']
}
onClick={() =>
act('toggle_radio_tts_setting', {
newsetting: setting,
})
}
/>
))}
</LabeledList.Item>
<Tooltip content="Use more accessible TGUI themes/layouts wherever possible.">
<ToggleFieldPreference
label="Accessible TGUI themes"
Expand Down

0 comments on commit 8af999e

Please sign in to comment.