mirror of
https://github.com/yogstation13/Yogstation.git
synced 2025-02-26 09:04:50 +00:00
Voice Announcement System for AIs and Captains (#11548)
* Voice Announcement System * Fixes shit the linter complained about * Uses topic instead of JSON files * fixes alex's problems * use /dev/urandom on linux * GenerateToken * update the config in theory * Allow downloading sounds via Get Server Logs
This commit is contained in:
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
@@ -7,12 +7,9 @@
|
|||||||
"tgui/.yarn": true,
|
"tgui/.yarn": true,
|
||||||
"tgui/.pnp.*": true
|
"tgui/.pnp.*": true
|
||||||
},
|
},
|
||||||
"workbench.editorAssociations": [
|
"workbench.editorAssociations": {
|
||||||
{
|
"*.dmi": "imagePreview.previewEditor"
|
||||||
"filenamePattern": "*.dmi",
|
},
|
||||||
"viewType": "imagePreview.previewEditor"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"files.eol": "\n",
|
"files.eol": "\n",
|
||||||
"gitlens.advanced.blame.customArguments": ["-w"]
|
"gitlens.advanced.blame.customArguments": ["-w"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,12 @@
|
|||||||
#define CHANNEL_AMBIENCE 1018
|
#define CHANNEL_AMBIENCE 1018
|
||||||
#define CHANNEL_BUZZ 1017
|
#define CHANNEL_BUZZ 1017
|
||||||
#define CHANNEL_BICYCLE 1016
|
#define CHANNEL_BICYCLE 1016
|
||||||
|
#define CHANNEL_VOICE_ANNOUNCE 1015
|
||||||
|
|
||||||
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
|
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
|
||||||
//KEEP IT UPDATED
|
//KEEP IT UPDATED
|
||||||
|
|
||||||
#define CHANNEL_HIGHEST_AVAILABLE 1015
|
#define CHANNEL_HIGHEST_AVAILABLE 1014
|
||||||
|
|
||||||
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
|
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "json"))
|
/client/proc/browse_files(root="data/logs/", max_iterations=10, list/valid_extensions=list("txt","log","htm", "html", "json", "aac", "mp3", "ogg", "opus", "wav", "weba"))
|
||||||
if(IsAdminAdvancedProcCall())
|
if(IsAdminAdvancedProcCall())
|
||||||
log_admin_private("BROWSEFILES: Admin proc call blocked")
|
log_admin_private("BROWSEFILES: Admin proc call blocked")
|
||||||
message_admins("BROWSEFILES: Admin proc call blocked")
|
message_admins("BROWSEFILES: Admin proc call blocked")
|
||||||
|
|||||||
@@ -274,6 +274,10 @@
|
|||||||
/datum/config_entry/string/invoke_youtubedl
|
/datum/config_entry/string/invoke_youtubedl
|
||||||
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
|
protection = CONFIG_ENTRY_LOCKED | CONFIG_ENTRY_HIDDEN
|
||||||
|
|
||||||
|
/datum/config_entry/string/voice_announce_url_base
|
||||||
|
|
||||||
|
/datum/config_entry/string/voice_announce_dir
|
||||||
|
|
||||||
/datum/config_entry/flag/show_irc_name
|
/datum/config_entry/flag/show_irc_name
|
||||||
|
|
||||||
/datum/config_entry/flag/see_own_notes //Can players see their own admin notes
|
/datum/config_entry/flag/see_own_notes //Can players see their own admin notes
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ SUBSYSTEM_DEF(communications)
|
|||||||
|
|
||||||
var/silicon_message_cooldown
|
var/silicon_message_cooldown
|
||||||
var/nonsilicon_message_cooldown
|
var/nonsilicon_message_cooldown
|
||||||
|
var/last_voice_announce_open = 0
|
||||||
|
|
||||||
/datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon)
|
/datum/controller/subsystem/communications/proc/can_announce(mob/living/user, is_silicon)
|
||||||
if(is_silicon && silicon_message_cooldown > world.time)
|
if(is_silicon && silicon_message_cooldown > world.time)
|
||||||
|
|||||||
173
code/datums/voice_announcements.dm
Normal file
173
code/datums/voice_announcements.dm
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
GLOBAL_LIST_EMPTY(voice_announce_list)
|
||||||
|
|
||||||
|
/datum/voice_announce
|
||||||
|
var/id
|
||||||
|
var/client/client
|
||||||
|
var/is_ai = FALSE
|
||||||
|
var/started_playing = FALSE
|
||||||
|
var/duration = 300
|
||||||
|
var/canceled = FALSE
|
||||||
|
var/was_queried = FALSE
|
||||||
|
|
||||||
|
/datum/voice_announce/New(client/client)
|
||||||
|
. = ..()
|
||||||
|
src.client = client
|
||||||
|
id = "[client.ckey]_[GenerateToken()]"
|
||||||
|
|
||||||
|
/datum/voice_announce/Destroy()
|
||||||
|
GLOB.voice_announce_list -= id
|
||||||
|
. = ..()
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/open()
|
||||||
|
if(SScommunications.last_voice_announce_open + 30 > world.time)
|
||||||
|
// Keep cheeky fucks from trying to waste resources by spamming the button
|
||||||
|
return
|
||||||
|
var/url_base = CONFIG_GET(string/voice_announce_url_base)
|
||||||
|
var/dir = CONFIG_GET(string/voice_announce_dir)
|
||||||
|
if(!url_base || !dir)
|
||||||
|
return
|
||||||
|
|
||||||
|
if(is_banned_from(client.ckey, "Voice Announcements"))
|
||||||
|
to_chat(client, "<span class='warning>You are banned from making voice announcements.</span>")
|
||||||
|
return
|
||||||
|
|
||||||
|
SScommunications.last_voice_announce_open = world.time
|
||||||
|
|
||||||
|
GLOB.voice_announce_list[id] = src
|
||||||
|
usr << link(url_base + "[CONFIG_GET(string/serversqlname)]/[id]")
|
||||||
|
addtimer(CALLBACK(src, .proc/timeout1), 15 SECONDS)
|
||||||
|
addtimer(CALLBACK(src, .proc/timeout2), 5 MINUTES)
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/timeout1()
|
||||||
|
if(!was_queried && !started_playing)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/timeout2()
|
||||||
|
if(!started_playing)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/voice_announce/Topic(href, href_list)
|
||||||
|
. = ..()
|
||||||
|
if(href_list["stop_announce"] && started_playing && !canceled && check_rights(NONE))
|
||||||
|
SEND_SOUND(world, sound(null, channel = CHANNEL_VOICE_ANNOUNCE))
|
||||||
|
canceled = TRUE
|
||||||
|
log_admin("[key_name(usr)] has canceled the voice announcement")
|
||||||
|
message_admins("[key_name_admin(usr)] has canceled the voice announcement")
|
||||||
|
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/do_announce_sound(sound/sound1, sound/sound2, sounds_delay, z_level)
|
||||||
|
started_playing = TRUE
|
||||||
|
// Play for admins
|
||||||
|
for(var/mob/M in GLOB.player_list)
|
||||||
|
if(M.client && M.client.holder && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
|
||||||
|
var/turf/T = get_turf(M)
|
||||||
|
if(T.z == z_level)
|
||||||
|
SEND_SOUND(M, sound1)
|
||||||
|
sleep(sounds_delay)
|
||||||
|
for(var/mob/M in GLOB.player_list)
|
||||||
|
if(M.client && M.client.holder && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
|
||||||
|
var/turf/T = get_turf(M)
|
||||||
|
if(T.z == z_level)
|
||||||
|
SEND_SOUND(M, sound2)
|
||||||
|
sleep(30)
|
||||||
|
if(canceled)
|
||||||
|
return
|
||||||
|
// Play for everyone else
|
||||||
|
for(var/mob/M in GLOB.player_list)
|
||||||
|
if(M.client && !M.client.holder && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
|
||||||
|
var/turf/T = get_turf(M)
|
||||||
|
if(T.z == z_level)
|
||||||
|
SEND_SOUND(M, sound1)
|
||||||
|
sleep(sounds_delay)
|
||||||
|
if(canceled)
|
||||||
|
return
|
||||||
|
for(var/mob/M in GLOB.player_list)
|
||||||
|
if(M.client && !M.client.holder && M.can_hear() && (M.client.prefs.toggles & SOUND_ANNOUNCEMENTS))
|
||||||
|
var/turf/T = get_turf(M)
|
||||||
|
if(T.z == z_level)
|
||||||
|
SEND_SOUND(M, sound2)
|
||||||
|
sleep(duration)
|
||||||
|
qdel(src)
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/check_valid()
|
||||||
|
if(client == null)
|
||||||
|
return FALSE
|
||||||
|
if(is_banned_from(client.ckey, "Voice Announcements"))
|
||||||
|
to_chat(client, "<span class='warning>You are banned from making voice announcements.</span>")
|
||||||
|
return FALSE
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/announce(snd)
|
||||||
|
stack_trace("announce() is unimplemented")
|
||||||
|
|
||||||
|
/datum/voice_announce/proc/handle_announce(ogg_filename, base_filename, ip, duration)
|
||||||
|
src.duration = duration
|
||||||
|
GLOB.voice_announce_list -= id
|
||||||
|
var/ogg_file = file("[CONFIG_GET(string/voice_announce_dir)]/[ogg_filename]")
|
||||||
|
var/base_file = file("[CONFIG_GET(string/voice_announce_dir)]/[base_filename]")
|
||||||
|
if(check_valid())
|
||||||
|
var/snd = fcopy_rsc(ogg_file)
|
||||||
|
fdel(ogg_file)
|
||||||
|
fcopy(base_file, "[GLOB.log_directory]/[base_filename]")
|
||||||
|
fdel(base_file)
|
||||||
|
|
||||||
|
log_admin("[key_name(client)] has made a voice announcement via [ip], saved to [base_filename]")
|
||||||
|
message_admins("[key_name_admin(client)] has made a voice announcement. ((<a href='?src=[REF(src)]&stop_announce=1'>CANCEL</a>))")
|
||||||
|
|
||||||
|
announce(snd)
|
||||||
|
else
|
||||||
|
fdel(ogg_file)
|
||||||
|
fdel(base_file)
|
||||||
|
|
||||||
|
/datum/voice_announce/ai
|
||||||
|
is_ai = TRUE
|
||||||
|
|
||||||
|
/datum/voice_announce/ai/check_valid()
|
||||||
|
if(!..())
|
||||||
|
return FALSE
|
||||||
|
var/mob/living/silicon/ai/M = client.mob
|
||||||
|
if(!istype(M))
|
||||||
|
return FALSE
|
||||||
|
if(GLOB.announcing_vox > world.time || M.control_disabled || M.incapacitated())
|
||||||
|
return FALSE
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/datum/voice_announce/ai/announce(snd)
|
||||||
|
set waitfor = 0
|
||||||
|
|
||||||
|
GLOB.announcing_vox = world.time + 600
|
||||||
|
|
||||||
|
var/turf/mob_turf = get_turf(client.mob)
|
||||||
|
var/z_level = mob_turf.z
|
||||||
|
|
||||||
|
var/sound/sound1 = sound('sound/vox/doop.ogg')
|
||||||
|
var/sound/sound2 = sound(snd, channel = CHANNEL_VOICE_ANNOUNCE, volume = 70)
|
||||||
|
do_announce_sound(sound1, sound2, 5, z_level)
|
||||||
|
|
||||||
|
/datum/voice_announce/command
|
||||||
|
var/obj/machinery/computer/communications/comms_console
|
||||||
|
|
||||||
|
/datum/voice_announce/command/New(client/client, obj/machinery/computer/communications/console)
|
||||||
|
. = ..()
|
||||||
|
comms_console = console
|
||||||
|
|
||||||
|
/datum/voice_announce/command/check_valid()
|
||||||
|
if(!..())
|
||||||
|
return FALSE
|
||||||
|
var/mob/living/user = client.mob
|
||||||
|
if(!SScommunications.can_announce(user, issilicon(user)))
|
||||||
|
return FALSE
|
||||||
|
if(!istype(user) || !user.canUseTopic(comms_console, !issilicon(user)))
|
||||||
|
return FALSE
|
||||||
|
return TRUE
|
||||||
|
|
||||||
|
/datum/voice_announce/command/announce(snd)
|
||||||
|
set waitfor = 0
|
||||||
|
var/turf/console_turf = get_turf(comms_console)
|
||||||
|
var/z_level = console_turf.z
|
||||||
|
SScommunications.nonsilicon_message_cooldown = world.time + 300
|
||||||
|
var/mob/living/user = client.mob
|
||||||
|
deadchat_broadcast(" made a priority announcement from <span class='name'>[get_area_name(user, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
|
||||||
|
var/sound/sound1 = sound('sound/misc/announce.ogg')
|
||||||
|
var/sound/sound2 = sound(snd, channel = CHANNEL_VOICE_ANNOUNCE, volume = 70)
|
||||||
|
do_announce_sound(sound1, sound2, 15, z_level)
|
||||||
@@ -174,6 +174,41 @@
|
|||||||
|
|
||||||
return jointext(message, "")
|
return jointext(message, "")
|
||||||
|
|
||||||
|
// Plays a voice announcement, given the ID of a voice annoucnement datum and a filename of a file in the shared folder, among other things
|
||||||
|
/datum/world_topic/voice_announce
|
||||||
|
keyword = "voice_announce"
|
||||||
|
require_comms_key = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic/voice_announce/Run(list/input)
|
||||||
|
var/datum/voice_announce/A = GLOB.voice_announce_list[input["voice_announce"]]
|
||||||
|
if(istype(A))
|
||||||
|
A.handle_announce(input["ogg_file"], input["uploaded_file"], input["ip"], text2num(input["duration"]))
|
||||||
|
|
||||||
|
// Cancels a voice announcement, given the ID of voice announcement datum, used if the user closes their browser window instead of uploading
|
||||||
|
/datum/world_topic/voice_announce_cancel
|
||||||
|
keyword = "voice_announce_cancel"
|
||||||
|
require_comms_key = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic/voice_announce_cancel/Run(list/input)
|
||||||
|
var/datum/voice_announce/A = GLOB.voice_announce_list[input["voice_announce_cancel"]]
|
||||||
|
if(istype(A))
|
||||||
|
qdel(A)
|
||||||
|
|
||||||
|
// Queries information about a voice announcement.
|
||||||
|
/datum/world_topic/voice_announce_query
|
||||||
|
keyword = "voice_announce_query"
|
||||||
|
require_comms_key = TRUE
|
||||||
|
|
||||||
|
/datum/world_topic/voice_announce_query/Run(list/input)
|
||||||
|
. = list()
|
||||||
|
var/datum/voice_announce/A = GLOB.voice_announce_list[input["voice_announce_query"]]
|
||||||
|
if(istype(A))
|
||||||
|
A.was_queried = TRUE
|
||||||
|
.["exists"] = TRUE
|
||||||
|
.["is_ai"] = A.is_ai
|
||||||
|
else
|
||||||
|
.["exists"] = FALSE
|
||||||
|
|
||||||
/datum/world_topic/status
|
/datum/world_topic/status
|
||||||
keyword = "status"
|
keyword = "status"
|
||||||
|
|
||||||
|
|||||||
@@ -161,6 +161,10 @@
|
|||||||
if (!authenticated_as_silicon_or_captain(usr))
|
if (!authenticated_as_silicon_or_captain(usr))
|
||||||
return
|
return
|
||||||
make_announcement(usr)
|
make_announcement(usr)
|
||||||
|
if ("makeVoiceAnnouncement")
|
||||||
|
if (!authenticated_as_non_silicon_captain(usr))
|
||||||
|
return
|
||||||
|
make_voice_announcement(usr)
|
||||||
if ("messageAssociates")
|
if ("messageAssociates")
|
||||||
if (!authenticated_as_non_silicon_captain(usr))
|
if (!authenticated_as_non_silicon_captain(usr))
|
||||||
return
|
return
|
||||||
@@ -343,6 +347,7 @@
|
|||||||
if (STATE_MAIN)
|
if (STATE_MAIN)
|
||||||
data["canBuyShuttles"] = can_buy_shuttles(user)
|
data["canBuyShuttles"] = can_buy_shuttles(user)
|
||||||
data["canMakeAnnouncement"] = FALSE
|
data["canMakeAnnouncement"] = FALSE
|
||||||
|
data["canMakeVoiceAnnouncement"] = FALSE
|
||||||
data["canMessageAssociates"] = FALSE
|
data["canMessageAssociates"] = FALSE
|
||||||
data["canRecallShuttles"] = !issilicon(user)
|
data["canRecallShuttles"] = !issilicon(user)
|
||||||
data["canRequestNuke"] = FALSE
|
data["canRequestNuke"] = FALSE
|
||||||
@@ -381,6 +386,7 @@
|
|||||||
|
|
||||||
data["alertLevelTick"] = alert_level_tick
|
data["alertLevelTick"] = alert_level_tick
|
||||||
data["canMakeAnnouncement"] = TRUE
|
data["canMakeAnnouncement"] = TRUE
|
||||||
|
data["canMakeVoiceAnnouncement"] = ishuman(user)
|
||||||
data["canSetAlertLevel"] = issilicon(user) ? "NO_SWIPE_NEEDED" : "SWIPE_NEEDED"
|
data["canSetAlertLevel"] = issilicon(user) ? "NO_SWIPE_NEEDED" : "SWIPE_NEEDED"
|
||||||
|
|
||||||
if (SSshuttle.emergency.mode != SHUTTLE_IDLE && SSshuttle.emergency.mode != SHUTTLE_RECALL)
|
if (SSshuttle.emergency.mode != SHUTTLE_IDLE && SSshuttle.emergency.mode != SHUTTLE_RECALL)
|
||||||
@@ -481,6 +487,14 @@
|
|||||||
SScommunications.make_announcement(user, is_ai, input)
|
SScommunications.make_announcement(user, is_ai, input)
|
||||||
deadchat_broadcast(" made a priority announcement from <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
|
deadchat_broadcast(" made a priority announcement from <span class='name'>[get_area_name(usr, TRUE)]</span>.", "<span class='name'>[user.real_name]</span>", user)
|
||||||
|
|
||||||
|
/obj/machinery/computer/communications/proc/make_voice_announcement(mob/living/user)
|
||||||
|
if(!SScommunications.can_announce(user, FALSE))
|
||||||
|
to_chat(user, "<span class='alert'>Intercomms recharging. Please stand by.</span>")
|
||||||
|
return
|
||||||
|
var/datum/voice_announce/command/announce_datum = new(user.client, src)
|
||||||
|
announce_datum.open()
|
||||||
|
|
||||||
|
|
||||||
/obj/machinery/computer/communications/proc/post_status(command, data1, data2)
|
/obj/machinery/computer/communications/proc/post_status(command, data1, data2)
|
||||||
|
|
||||||
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
|
var/datum/radio_frequency/frequency = SSradio.return_frequency(FREQ_STATUS_DISPLAYS)
|
||||||
|
|||||||
@@ -252,7 +252,7 @@
|
|||||||
output += "</div></div>"
|
output += "</div></div>"
|
||||||
//departments/groups that don't have command staff would throw a javascript error since there's no corresponding reference for toggle_head()
|
//departments/groups that don't have command staff would throw a javascript error since there's no corresponding reference for toggle_head()
|
||||||
var/list/headless_job_lists = list("Silicon" = GLOB.nonhuman_positions,
|
var/list/headless_job_lists = list("Silicon" = GLOB.nonhuman_positions,
|
||||||
"Abstract" = list("Appearance", "Emote", "OOC"))
|
"Abstract" = list("Appearance", "Emote", "OOC", "Voice Announcements"))
|
||||||
for(var/department in headless_job_lists)
|
for(var/department in headless_job_lists)
|
||||||
output += "<div class='column'><label class='rolegroup [ckey(department)]'><input type='checkbox' name='[department]' class='hidden' [usr.client.prefs.tgui_fancy ? " onClick='toggle_checkboxes(this, \"_com\")'" : ""]>[department]</label><div class='content'>"
|
output += "<div class='column'><label class='rolegroup [ckey(department)]'><input type='checkbox' name='[department]' class='hidden' [usr.client.prefs.tgui_fancy ? " onClick='toggle_checkboxes(this, \"_com\")'" : ""]>[department]</label><div class='content'>"
|
||||||
break_counter = 0
|
break_counter = 0
|
||||||
|
|||||||
@@ -85,20 +85,40 @@
|
|||||||
popup.set_content(dat)
|
popup.set_content(dat)
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
|
/mob/living/silicon/ai/proc/voice_announce()
|
||||||
|
if(GLOB.announcing_vox > world.time)
|
||||||
|
to_chat(src, "<span class='notice'>Please wait [DisplayTimeText(GLOB.announcing_vox - world.time)].</span>")
|
||||||
|
return
|
||||||
|
if(incapacitated())
|
||||||
|
return
|
||||||
|
if(control_disabled)
|
||||||
|
to_chat(src, "<span class='warning'>Wireless interface disabled, unable to interact with announcement PA.</span>")
|
||||||
|
return
|
||||||
|
|
||||||
|
var/datum/voice_announce/ai/announce_datum = new(client)
|
||||||
|
announce_datum.open()
|
||||||
|
|
||||||
|
GLOBAL_VAR_INIT(announcing_vox, 0)
|
||||||
|
|
||||||
/mob/living/silicon/ai/proc/announcement()
|
/mob/living/silicon/ai/proc/announcement()
|
||||||
var/static/announcing_vox = 0 // Stores the time of the last announcement
|
if(GLOB.announcing_vox > world.time)
|
||||||
if(announcing_vox > world.time)
|
to_chat(src, "<span class='notice'>Please wait [DisplayTimeText(GLOB.announcing_vox - world.time)].</span>")
|
||||||
to_chat(src, "<span class='notice'>Please wait [DisplayTimeText(announcing_vox - world.time)].</span>")
|
return
|
||||||
|
|
||||||
|
var/list/types_list = list("Victor (male)", "Verity (female)", "Oscar (military)") //Victor is vox_sounds_male, Verity is vox_sounds, Oscar is vox_sounds_military
|
||||||
|
if(!is_banned_from(ckey, "Voice Announcements"))
|
||||||
|
types_list += "Use Microphone"
|
||||||
|
var/voxType = input(src, "Which voice?", "VOX") in types_list
|
||||||
|
|
||||||
|
if(voxType == "Use Microphone")
|
||||||
|
voice_announce()
|
||||||
return
|
return
|
||||||
|
|
||||||
var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text
|
var/message = input(src, "WARNING: Misuse of this verb can result in you being job banned. More help is available in 'Announcement Help'", "Announcement", src.last_announcement) as text
|
||||||
|
|
||||||
last_announcement = message
|
last_announcement = message
|
||||||
|
|
||||||
var/voxType = input(src, "Which voice?", "VOX") in list("Victor (male)", "Verity (female)", "Oscar (military)") //Victor is vox_sounds_male, Verity is vox_sounds, Oscar is vox_sounds_military
|
if(!message || GLOB.announcing_vox > world.time)
|
||||||
|
|
||||||
if(!message || announcing_vox > world.time)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
if(incapacitated())
|
if(incapacitated())
|
||||||
@@ -130,7 +150,7 @@
|
|||||||
to_chat(src, "<span class='notice'>These words are not available on the announcement system: [english_list(incorrect_words)].</span>")
|
to_chat(src, "<span class='notice'>These words are not available on the announcement system: [english_list(incorrect_words)].</span>")
|
||||||
return
|
return
|
||||||
|
|
||||||
announcing_vox = world.time + VOX_DELAY
|
GLOB.announcing_vox = world.time + VOX_DELAY
|
||||||
|
|
||||||
log_game("[key_name(src)] made a vocal announcement with the following message: [message].")
|
log_game("[key_name(src)] made a vocal announcement with the following message: [message].")
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ $include resources.txt
|
|||||||
SERVERNAME Space station 13
|
SERVERNAME Space station 13
|
||||||
|
|
||||||
## Server SQL name: This is the name used to identify the server to the SQL DB, distinct from SERVERNAME as it must be at most 32 characters.
|
## Server SQL name: This is the name used to identify the server to the SQL DB, distinct from SERVERNAME as it must be at most 32 characters.
|
||||||
#SERVERSQLNAME
|
SERVERSQLNAME yogstation
|
||||||
|
|
||||||
## Put on byond hub: Uncomment this to put your server on the byond hub.
|
## Put on byond hub: Uncomment this to put your server on the byond hub.
|
||||||
#HUB
|
#HUB
|
||||||
@@ -79,3 +79,6 @@ TICK_LIMIT_MC_INIT 500
|
|||||||
## FEEDBACK_TABLEPREFIX SS13_
|
## FEEDBACK_TABLEPREFIX SS13_
|
||||||
## Remove "SS13_" if you are using the standard schema file.
|
## Remove "SS13_" if you are using the standard schema file.
|
||||||
FEEDBACK_TABLEPREFIX SS13_
|
FEEDBACK_TABLEPREFIX SS13_
|
||||||
|
|
||||||
|
VOICE_ANNOUNCE_URL_BASE http://localhost/voice_announce/
|
||||||
|
VOICE_ANNOUNCE_DIR ../Yogstation.net/voice_announce_tmp
|
||||||
|
|||||||
@@ -86,3 +86,6 @@ SQL_ENABLED
|
|||||||
## FEEDBACK_TABLEPREFIX SS13_
|
## FEEDBACK_TABLEPREFIX SS13_
|
||||||
## Remove "SS13_" if you are using the standard schema file.
|
## Remove "SS13_" if you are using the standard schema file.
|
||||||
FEEDBACK_TABLEPREFIX erro_
|
FEEDBACK_TABLEPREFIX erro_
|
||||||
|
|
||||||
|
VOICE_ANNOUNCE_URL_BASE https://www.yogstation.net/voice_announce/
|
||||||
|
VOICE_ANNOUNCE_DIR data/voice_announcements
|
||||||
|
|||||||
@@ -268,6 +268,7 @@ const PageMain = (props, context) => {
|
|||||||
callShuttleReasonMinLength,
|
callShuttleReasonMinLength,
|
||||||
canBuyShuttles,
|
canBuyShuttles,
|
||||||
canMakeAnnouncement,
|
canMakeAnnouncement,
|
||||||
|
canMakeVoiceAnnouncement,
|
||||||
canMessageAssociates,
|
canMessageAssociates,
|
||||||
canRecallShuttles,
|
canRecallShuttles,
|
||||||
canRequestNuke,
|
canRequestNuke,
|
||||||
@@ -380,6 +381,12 @@ const PageMain = (props, context) => {
|
|||||||
onClick={() => act("makePriorityAnnouncement")}
|
onClick={() => act("makePriorityAnnouncement")}
|
||||||
/>}
|
/>}
|
||||||
|
|
||||||
|
{!!canMakeVoiceAnnouncement && <Button
|
||||||
|
icon="bullhorn"
|
||||||
|
content="Make Voice Announcement"
|
||||||
|
onClick={() => act("makeVoiceAnnouncement")}
|
||||||
|
/>}
|
||||||
|
|
||||||
{!!canToggleEmergencyAccess && <Button.Confirm
|
{!!canToggleEmergencyAccess && <Button.Confirm
|
||||||
icon="id-card-o"
|
icon="id-card-o"
|
||||||
content={`${emergencyAccess ? "Disable" : "Enable"} Emergency Maintenance Access`}
|
content={`${emergencyAccess ? "Disable" : "Enable"} Emergency Maintenance Access`}
|
||||||
|
|||||||
@@ -368,6 +368,7 @@
|
|||||||
#include "code\datums\spawners_menu.dm"
|
#include "code\datums\spawners_menu.dm"
|
||||||
#include "code\datums\verbs.dm"
|
#include "code\datums\verbs.dm"
|
||||||
#include "code\datums\view.dm"
|
#include "code\datums\view.dm"
|
||||||
|
#include "code\datums\voice_announcements.dm"
|
||||||
#include "code\datums\weakrefs.dm"
|
#include "code\datums\weakrefs.dm"
|
||||||
#include "code\datums\world_topic.dm"
|
#include "code\datums\world_topic.dm"
|
||||||
#include "code\datums\achievements\achievements.dm"
|
#include "code\datums\achievements\achievements.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user