Bundle mission speech with an admin mute option and fix live audio downloads

This commit is contained in:
2026-10-15 16:53:39 +02:00
parent 07c4d70de5
commit 009b2fb591
181 changed files with 19248 additions and 103 deletions
+327
View File
@@ -0,0 +1,327 @@
{
"voice": "en-US-Chirp3-HD-Algenib",
"clips": [
{
"id": "welcome",
"text": "Welcome to Escape Reintroduced. Work together, stay alert, and find your way off the island. Good luck.",
"category": "welcome",
"sha256": "01de068469bd6746dba7634fb6b5b85b150621d3359c17fd01bcb916b34b1720",
"bytes": 318764,
"graph": "{3B55F836F9B6D20C}Sounds/ERR/Speech/welcome.acp"
},
{
"id": "soldier_1001",
"text": "I can see one of them.",
"category": "soldier",
"kind": "1001",
"sha256": "a8935a5aded028f2fb03734f4423e731ea4f5b17394526df47c0407a3deddfe7",
"bytes": 76844,
"graph": "{3DF753B659A184FB}Sounds/ERR/Speech/soldier_1001.acp"
},
{
"id": "soldier_1002",
"text": "I've got eyes on two of them.",
"category": "soldier",
"kind": "1002",
"sha256": "8535643e93757dd916f4158b5b03671cefc599489dbccf6bb0f7abf294fbae88",
"bytes": 78764,
"graph": "{B1B78A9E50D41FD5}Sounds/ERR/Speech/soldier_1002.acp"
},
{
"id": "soldier_1003",
"text": "Hey, I can see three of them.",
"category": "soldier",
"kind": "1003",
"sha256": "5910896661ad67333d2374a16ca44ce831a5820feb337655df99c02df2915d5a",
"bytes": 115244,
"graph": "{FEE47650B627484E}Sounds/ERR/Speech/soldier_1003.acp"
},
{
"id": "soldier_1004",
"text": "There's at least four of them.",
"category": "soldier",
"kind": "1004",
"sha256": "76375e462ba518c76f752d4b194c9370dffcebd8ce0037865133b37af3ff9a9e",
"bytes": 78764,
"graph": "{2FA4DC16F80F04FE}Sounds/ERR/Speech/soldier_1004.acp"
},
{
"id": "soldier_1005",
"text": "They're getting closer. Keep your eyes open.",
"category": "soldier",
"kind": "1005",
"sha256": "3e20728fb61863278738f5366343cddd6fac1b8b114a14867f91ebb5cac547d8",
"bytes": 145964,
"graph": "{5F3C22AA392DAE36}Sounds/ERR/Speech/soldier_1005.acp"
},
{
"id": "soldier_1100",
"text": "I could use a hot coffee. How about you?",
"category": "soldier",
"kind": "1100",
"sha256": "eaf1deb5381f6bac165e364a652920fcf78438c351c564ebe50a216f3f3ba5a0",
"bytes": 153644,
"graph": "{AD2DC2C52E226AA7}Sounds/ERR/Speech/soldier_1100.acp"
},
{
"id": "soldier_1101",
"text": "Yeah. And something decent to eat for once.",
"category": "soldier",
"kind": "1101",
"sha256": "4bca012ec25d8456cd38d26606312f54b480b674365b76a9c9f54e408314570b",
"bytes": 140204,
"graph": "{AE2E3AA19209018D}Sounds/ERR/Speech/soldier_1101.acp"
},
{
"id": "soldier_1102",
"text": "My feet are killing me.",
"category": "soldier",
"kind": "1102",
"sha256": "1432bb3c9d99910314a84d9773d2afafe4f5fbb143afb291b0deed55d25ee6d0",
"bytes": 92204,
"graph": "{74617A1D01426F95}Sounds/ERR/Speech/soldier_1102.acp"
},
{
"id": "soldier_1103",
"text": "Same here. Can't wait to sit down.",
"category": "soldier",
"kind": "1103",
"sha256": "c294454907a229d521c2285eec26dbb82f9782f2a7eca764e11713ff63f0e004",
"bytes": 119084,
"graph": "{6B5037B1DEEB3FCB}Sounds/ERR/Speech/soldier_1103.acp"
},
{
"id": "soldier_1104",
"text": "Feels like this shift will never end.",
"category": "soldier",
"kind": "1104",
"sha256": "952b3d71366c26fc12bdbb9014665bfc0402f30944c22b1b2369d26a93db7104",
"bytes": 149804,
"graph": "{0C8AE411366B20EB}Sounds/ERR/Speech/soldier_1104.acp"
},
{
"id": "soldier_1105",
"text": "Tell me about it.",
"category": "soldier",
"kind": "1105",
"sha256": "20e9e82d9897b598497da4722432f83ae03a5e6bf9a1f7a77caab712e3fc3130",
"bytes": 78764,
"graph": "{3E1B0B6406E16734}Sounds/ERR/Speech/soldier_1105.acp"
},
{
"id": "soldier_1200",
"text": "Covering. Keep low.",
"category": "soldier",
"kind": "1200",
"sha256": "5a1561e821ef33a574c1f9ef95ccf76e69b832bf0a20bcbbf914760345921859",
"bytes": 115244,
"graph": "{86FD331E3D1EB134}Sounds/ERR/Speech/soldier_1200.acp"
},
{
"id": "soldier_1201",
"text": "Move up. Stay low.",
"category": "soldier",
"kind": "1201",
"sha256": "f058f0482cfe4034fdf37d9b596f7ba8172fae1c57aeb387ce153f8041895e45",
"bytes": 99884,
"graph": "{A840837CC23E4A32}Sounds/ERR/Speech/soldier_1201.acp"
},
{
"id": "soldier_1202",
"text": "Fall back. Stay together.",
"category": "soldier",
"kind": "1202",
"sha256": "c875f4e798ff5e24c3eb3b48bdfa1b8af03de9326a19c671eca86660297ad737",
"bytes": 96044,
"graph": "{3AF9ED4087FE442C}Sounds/ERR/Speech/soldier_1202.acp"
},
{
"id": "soldier_1203",
"text": "Hold here. Keep together.",
"category": "soldier",
"kind": "1203",
"sha256": "6e7857dc96dfb556f011ba89f2f4ea659cfd7b605b88790c69e754d5cc51398a",
"bytes": 101804,
"graph": "{97397F4FD27C4371}Sounds/ERR/Speech/soldier_1203.acp"
},
{
"id": "soldier_1204",
"text": "No sign here. Keep looking.",
"category": "soldier",
"kind": "1204",
"sha256": "bd170ca015b017114e42078dcc5c49d5626aef17d22e4a12b8282e9ee4908ae6",
"bytes": 71084,
"graph": "{EB394FAC323A0CA0}Sounds/ERR/Speech/soldier_1204.acp"
},
{
"id": "soldier_1205",
"text": "Watch this approach.",
"category": "soldier",
"kind": "1205",
"sha256": "769c457805376e9c0172ddb525ead5f1d8774e15bd1f3f3b218a19f9d77b6883",
"bytes": 101804,
"graph": "{69750949590AECF1}Sounds/ERR/Speech/soldier_1205.acp"
},
{
"id": "soldier_clear",
"text": "Clear.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_CLEAR",
"sha256": "d6527b8136aa720b721463210420f47de0dbc45acc4e4c390b6a44968c5f0acd",
"bytes": 23084,
"graph": "{ECF3257A4BFF2F53}Sounds/ERR/Speech/soldier_clear.acp"
},
{
"id": "soldier_moving",
"text": "Moving. Cover me.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_MOVING",
"sha256": "a61dda64e6fc2a11eac3e6008ee14b89f360bd67e258dce1191a71d9e2e26fad",
"bytes": 71084,
"graph": "{BAB1942B5DE85A52}Sounds/ERR/Speech/soldier_moving.acp"
},
{
"id": "soldier_covering",
"text": "I've got you covered.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_COVERING",
"sha256": "f51e0086eaf0eece8b4061711088a413a2dbeae263deab7ea30fb1852dafda69",
"bytes": 76844,
"graph": "{78DCA194DA126513}Sounds/ERR/Speech/soldier_covering.acp"
},
{
"id": "soldier_reloading",
"text": "Reloading!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_RELOADING",
"sha256": "15b2749f79bc73fd0784bcd6e6076e1bc50da835e0c434cd43bd185d0735c732",
"bytes": 34604,
"graph": "{C51337F1692C21A7}Sounds/ERR/Speech/soldier_reloading.acp"
},
{
"id": "soldier_under_fire",
"text": "Taking fire!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_UNDER_FIRE",
"sha256": "e4bd5e69fda289593fc6e6b8c2fae9a271a10d0a9bae877f18ba02dbbf75d1fc",
"bytes": 48044,
"graph": "{8A05B1A08D5F23CC}Sounds/ERR/Speech/soldier_under_fire.acp"
},
{
"id": "soldier_no_ammo",
"text": "I'm out of ammo!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_NO_AMMO",
"sha256": "ffe6ef5fdf30411749e0cb73186e3005b1ce6a52fcb7c836caeb1bca422ed3ed",
"bytes": 38444,
"graph": "{D363E6B37331E416}Sounds/ERR/Speech/soldier_no_ammo.acp"
},
{
"id": "soldier_engaging",
"text": "Engaging!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_ENGAGING",
"sha256": "ac0f2d7d698732e3d7c270186e7aa2ab7e6bd4c908f36b07fb6f66a3cbe75ccf",
"bytes": 63404,
"graph": "{A700E14970CCA3E2}Sounds/ERR/Speech/soldier_engaging.acp"
},
{
"id": "soldier_target_down",
"text": "Target down.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_TARGET_DOWN",
"sha256": "e2e60e8b83a24a548c90b84c5e1137adb7e792cf1d4ba6232ddfb1012fa78892",
"bytes": 55724,
"graph": "{388F2800E5683289}Sounds/ERR/Speech/soldier_target_down.acp"
},
{
"id": "soldier_target_lost",
"text": "Lost visual. Keep your eyes open.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_TARGET_LOST",
"sha256": "bbcf454d48adea47478d410b1baf14df3a5d018237272e70ae33ee62823f822f",
"bytes": 121004,
"graph": "{DA42EA7B286B20BD}Sounds/ERR/Speech/soldier_target_lost.acp"
},
{
"id": "radio_01",
"text": "Escapists, this is rescue command. We are preparing your escape route and assembling transports with armed escort helicopters. Hold the radio position until preparations are complete. Keep your smoke grenades ready and stand by for pickup coordinates.",
"category": "radio",
"sha256": "cfe4a00000bc9b629a9e8e282ed64e7177673f829c5657b1ae2b2cb9e661d2ae",
"bytes": 720044,
"graph": "{29F6A1A8A691488D}Sounds/ERR/Speech/radio_01.acp"
},
{
"id": "radio_02",
"text": "Your escape route is ready. The exact pickup point is marked on your map. Gather your team there and throw a smoke grenade within 25 metres of the mark. We will send the transport and armed escorts when we see your smoke.",
"category": "radio",
"sha256": "6f0c94ae0e501afe6cc1aba804ba6a0403ba4de931debc28bf22970f591d0798",
"bytes": 554924,
"graph": "{0B1147F331AC4EDA}Sounds/ERR/Speech/radio_02.acp"
},
{
"id": "radio_03",
"text": "Rescue command cannot establish a safe approach. Extraction has failed.",
"category": "radio",
"sha256": "415a206bd1de167342cf1b82d59c708441b8d802395f941d15097c064133802a",
"bytes": 184364,
"graph": "{BC0C902F48008D93}Sounds/ERR/Speech/radio_03.acp"
},
{
"id": "radio_04",
"text": "Rescue command could not assemble the required transport capacity. Extraction has failed.",
"category": "radio",
"sha256": "a225810c7fba048517248fd9f7e9f7ab8aad5bac35e59f22e11e69166551f7f3",
"bytes": 224684,
"graph": "{E9EB0183C1ED1906}Sounds/ERR/Speech/radio_04.acp"
},
{
"id": "radio_05",
"text": "Signal received. Launching the rescue flight. Keep the landing point clear.",
"category": "radio",
"sha256": "90f5abe221165ac5cd7d88c9b3e01cf6fd4d00b594c84d09c6baf101fdb776ad",
"bytes": 236204,
"graph": "{4995CB641455140B}Sounds/ERR/Speech/radio_05.acp"
},
{
"id": "radio_06",
"text": "A rescue transport is down or unable to continue. Extraction has failed.",
"category": "radio",
"sha256": "b3f86b8dde535bc1a63301376c8d42775446d1b6117168557841565391fe0a14",
"bytes": 291884,
"graph": "{E4473DD1140515F9}Sounds/ERR/Speech/radio_06.acp"
},
{
"id": "radio_07",
"text": "Rescue transports are on the ground. Everyone aboard, including your wounded. Use either rescue transport if there are two. Escorts are covering the pickup. We leave when all surviving prisoners are inside.",
"category": "radio",
"sha256": "f3fd18ddaebe9eb3d0db9ac73c89a7b7a7f18b76e4b66d404d544be660a6825e",
"bytes": 625964,
"graph": "{3D3AA49576443D5D}Sounds/ERR/Speech/radio_07.acp"
},
{
"id": "radio_08",
"text": "All survivors aboard. Lifting now. Stay inside the transport; escorts are taking you to safety.",
"category": "radio",
"sha256": "ce3c2aff20dbea83aa6545a383c454969c5caeb53d5a88155ec182f789047d4a",
"bytes": 349484,
"graph": "{207C5D973D7EBE55}Sounds/ERR/Speech/radio_08.acp"
},
{
"id": "radio_09",
"text": "Smoke confirmed. Rescue transport and armed cover are inbound. Clear the marked landing point. Bring your wounded; we wait for all surviving prisoners to board.",
"category": "radio",
"sha256": "3eb0be6393c431b526dbddc723cb608a7681a2dcd8af6910d9f2234aa98c923c",
"bytes": 497324,
"graph": "{DCAF67D5B901D45F}Sounds/ERR/Speech/radio_09.acp"
},
{
"id": "radio_10",
"text": "Smoke confirmed. Two rescue transports and armed cover are inbound. The helicopters will land separately near the marker. Use either transport and bring your wounded; both wait until everyone is aboard.",
"category": "radio",
"sha256": "2b2dac499a45a7779e79465d628a67b87078c0951db7db3e051feeb4342f2816",
"bytes": 593324,
"graph": "{8CC6CCBA6BDF1568}Sounds/ERR/Speech/radio_10.acp"
}
]
}
+217
View File
@@ -0,0 +1,217 @@
{
"voice": "en-US-Chirp3-HD-Algenib",
"language": "en-US",
"clips": [
{
"id": "welcome",
"text": "Welcome to Escape Reintroduced. Work together, stay alert, and find your way off the island. Good luck.",
"category": "welcome"
},
{
"id": "soldier_1001",
"text": "I can see one of them.",
"category": "soldier",
"kind": "1001"
},
{
"id": "soldier_1002",
"text": "I've got eyes on two of them.",
"category": "soldier",
"kind": "1002"
},
{
"id": "soldier_1003",
"text": "Hey, I can see three of them.",
"category": "soldier",
"kind": "1003"
},
{
"id": "soldier_1004",
"text": "There's at least four of them.",
"category": "soldier",
"kind": "1004"
},
{
"id": "soldier_1005",
"text": "They're getting closer. Keep your eyes open.",
"category": "soldier",
"kind": "1005"
},
{
"id": "soldier_1100",
"text": "I could use a hot coffee. How about you?",
"category": "soldier",
"kind": "1100"
},
{
"id": "soldier_1101",
"text": "Yeah. And something decent to eat for once.",
"category": "soldier",
"kind": "1101"
},
{
"id": "soldier_1102",
"text": "My feet are killing me.",
"category": "soldier",
"kind": "1102"
},
{
"id": "soldier_1103",
"text": "Same here. Can't wait to sit down.",
"category": "soldier",
"kind": "1103"
},
{
"id": "soldier_1104",
"text": "Feels like this shift will never end.",
"category": "soldier",
"kind": "1104"
},
{
"id": "soldier_1105",
"text": "Tell me about it.",
"category": "soldier",
"kind": "1105"
},
{
"id": "soldier_1200",
"text": "Covering. Keep low.",
"category": "soldier",
"kind": "1200"
},
{
"id": "soldier_1201",
"text": "Move up. Stay low.",
"category": "soldier",
"kind": "1201"
},
{
"id": "soldier_1202",
"text": "Fall back. Stay together.",
"category": "soldier",
"kind": "1202"
},
{
"id": "soldier_1203",
"text": "Hold here. Keep together.",
"category": "soldier",
"kind": "1203"
},
{
"id": "soldier_1204",
"text": "No sign here. Keep looking.",
"category": "soldier",
"kind": "1204"
},
{
"id": "soldier_1205",
"text": "Watch this approach.",
"category": "soldier",
"kind": "1205"
},
{
"id": "soldier_clear",
"text": "Clear.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_CLEAR"
},
{
"id": "soldier_moving",
"text": "Moving. Cover me.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_MOVING"
},
{
"id": "soldier_covering",
"text": "I've got you covered.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_COVERING"
},
{
"id": "soldier_reloading",
"text": "Reloading!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_RELOADING"
},
{
"id": "soldier_under_fire",
"text": "Taking fire!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_UNDER_FIRE"
},
{
"id": "soldier_no_ammo",
"text": "I'm out of ammo!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_NO_AMMO"
},
{
"id": "soldier_engaging",
"text": "Engaging!",
"category": "soldier",
"kind": "ECommunicationType.REPORT_ENGAGING"
},
{
"id": "soldier_target_down",
"text": "Target down.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_TARGET_DOWN"
},
{
"id": "soldier_target_lost",
"text": "Lost visual. Keep your eyes open.",
"category": "soldier",
"kind": "ECommunicationType.REPORT_TARGET_LOST"
},
{
"id": "radio_01",
"text": "Escapists, this is rescue command. We are preparing your escape route and assembling transports with armed escort helicopters. Hold the radio position until preparations are complete. Keep your smoke grenades ready and stand by for pickup coordinates.",
"category": "radio"
},
{
"id": "radio_02",
"text": "Your escape route is ready. The exact pickup point is marked on your map. Gather your team there and throw a smoke grenade within 25 metres of the mark. We will send the transport and armed escorts when we see your smoke.",
"category": "radio"
},
{
"id": "radio_03",
"text": "Rescue command cannot establish a safe approach. Extraction has failed.",
"category": "radio"
},
{
"id": "radio_04",
"text": "Rescue command could not assemble the required transport capacity. Extraction has failed.",
"category": "radio"
},
{
"id": "radio_05",
"text": "Signal received. Launching the rescue flight. Keep the landing point clear.",
"category": "radio"
},
{
"id": "radio_06",
"text": "A rescue transport is down or unable to continue. Extraction has failed.",
"category": "radio"
},
{
"id": "radio_07",
"text": "Rescue transports are on the ground. Everyone aboard, including your wounded. Use either rescue transport if there are two. Escorts are covering the pickup. We leave when all surviving prisoners are inside.",
"category": "radio"
},
{
"id": "radio_08",
"text": "All survivors aboard. Lifting now. Stay inside the transport; escorts are taking you to safety.",
"category": "radio"
},
{
"id": "radio_09",
"text": "Smoke confirmed. Rescue transport and armed cover are inbound. Clear the marked landing point. Bring your wounded; we wait for all surviving prisoners to board.",
"category": "radio"
},
{
"id": "radio_10",
"text": "Smoke confirmed. Two rescue transports and armed cover are inbound. The helicopters will land separately near the marker. Use either transport and bring your wounded; both wait until everyone is aboard.",
"category": "radio"
}
]
}
+1 -1
View File
@@ -93,7 +93,7 @@ Edit the file while the mission is stopped, then restart to load manual changes.
| `factions` | Player, enemy and independent role choices | `EscapistsFactions.json` |
| `terrain` | Selected next-start scenario | `EscapistsTerrain.json` |
| `items` | Item rules and named presets, including dormant rules for absent mods | `EscapistsItems.json` |
| `voice` | Original welcome clip (`welcomeUrl`), speech bridge URL/token (`briefingUrl`, `briefingToken`), optional `ttsEnabled` | `EscapistsWelcomeVoice.json` |
| `voice` | Original welcome clip (`welcomeUrl`), speech bridge URL/token (`briefingUrl`, `briefingToken`), optional `ttsEnabled`, `bundledSpeech` (default true), `recordingsEnabled` (default true; TTS menu prerecorded speech On / Off) | `EscapistsWelcomeVoice.json` |
The admin mission menu's **TTS** page can test and save the speech bridge settings
without a restart. Only a successful test enables the new settings; an empty or
+1
View File
@@ -177,6 +177,7 @@
"UI/Textures/Icons/icons_mapMarkersUI.imageset": "E23427CAC80DA8B7",
"UI/Textures/Icons/icons_wrapperUI-glow.imageset": "00FE3DBDFD15227B",
"UI/Textures/Icons/icons_wrapperUI.imageset": "3262679C50EF4F01",
"UI/layouts/HUD/Chat/ChatPanel.layout": "28C54D576A8997CF",
"UI/layouts/HUD/GameOver/EndScreen/EndScreenContent_NoImage.layout": "C4507D07F3C54831",
"UI/layouts/Menus/PauseMenu/PauseMenuButton.layout": "9ECCD201BCF07E95",
"UI/layouts/Sights/Optic_Default.layout": "4CE66FA8219D33D7",
+67 -37
View File
@@ -1,6 +1,6 @@
# Welcome briefing
The optional welcome plays once per authenticated account in the running server
The bundled welcome plays once per authenticated account in the running server
game session, after a controlled character exists, loading releases audio and
the player closes the menus. The server records permission before the client
downloads the greeting, so a crash, reconnect or return through the main menu
@@ -16,7 +16,27 @@ Requests are skipped while the engine HTTP service is disabled (including native
`-noBackend` diagnostics).
An empty URL disables downloading instead of requesting an empty address.
The dynamic briefing names the **loaded terrain**, not a saved next-round choice,
The default welcome is a bundled generic recording and contains no terrain or
weather claims. The addon includes 37 prerecorded messages: the welcome, ten
extraction-radio lines, and 26 soldier lines. They need no speech service,
credentials, HTTP downloads, or PCM reconstruction during play. Recordings use
the existing Algenib voice, with their scripts and hashes in
[`bundled-speech.json`](bundled-speech.json) and
[`bundled-speech-assets.json`](bundled-speech-assets.json). Their combined PCM
source size is about 6.9 MB. Event-specific wording still requires the appropriate
gameplay event; the bank does not manufacture contact, rescue, or weather facts.
An administrator can explicitly opt into a live welcome using **TTS → Test &
enable**. **Disable live TTS** restores the bundled welcome source.
**TTS → Prerecorded speech → On / Off** controls all bundled welcome, soldier,
and extraction recordings for everyone. It defaults to On, saves immediately as
`voice.recordingsEnabled`, survives restarts, and stops bundled audio already
playing when switched Off. Text announcements remain visible. The optional live
welcome has its own setting. The `voice.bundledSpeech`
preference defaults to true, including for existing configurations without that
field. Live bridge credentials alone do not disable the bundled default.
The optional dynamic briefing names the **loaded terrain**, not a saved next-round choice,
and says the escape was generated for it. It reports the game's current weather
and its next known weather state when different. It gives no invented time or
forecast for an unknown custom weather state. The server checks for changes once
@@ -83,6 +103,26 @@ The existing `/welcome.b64` and `/welcome.wav` endpoints remain supported.
recording to the new voice, regenerate it once. Dynamic cache entries include
the text, voice, model, prompt and endpoint in their identity.
Speech downloads use sequential `?part=N` requests on the `.b64` URL. Each
response contains at most 256 KiB of encoded audio plus a small JSON envelope
(`offset`, `total`, `data`), below the engine's REST response limit. The client
checks part order, exact sizes and a consistent total, then runs the existing
bounded WAV preparation. Audio bytes, quality and duration are unchanged; old
cached clips need no regeneration. At most eleven parts can form a 2 MiB WAV.
An invalid part or failed request cancels the transfer without playing partial
audio. The original full-download URLs remain available for older clients.
Deploy the updated helper before the addon containing the chunked downloader.
Restart only the speech helper to activate its new endpoint. The addon update
is still required on the mission and clients; updating the helper alone does not
fix an older client's oversized downloads. Existing external speech helpers must
implement the same part response protocol.
The opt-in native `speech-download` fixture uses an explicit loopback
`--speech-probe-url`, real REST callbacks, queued decoding and a native playback
handle. Compare its `speech-downloaded.wav` with the served clip for exact byte
integrity. It does not prove audible multiplayer playback.
## Enable the dynamic briefing
Log in as administrator, open the mission menu from Escape, and select **TTS**.
@@ -127,20 +167,16 @@ Alternatively, edit only the `voice` section of the dedicated server's
}
```
The saved service is verified at mission startup before replacing `welcomeUrl`.
Restart after installing the
updated mod and speech helper. Merely republishing the mod does not upgrade an
already-running external helper or give it Google credentials. If the bridge
fails, the game keeps the original `welcomeUrl` recording, if configured, and
shows the failure in the TTS page. With no original recording it remains silent.
An unavailable service does not block gameplay. Startup verification may delay
the optional welcome while the request is pending (up to 100 seconds).
Bundled playback starts immediately once the normal welcome readiness checks
pass. A saved explicit live preference (`bundledSpeech: false`) verifies its
service at startup; unavailable live speech falls back to the generic bundled
welcome. The admin test saves the live preference only after verification.
Disable keeps the bridge address/token but saves the bundled preference.
For the old fixed recording, leave the bridge fields absent/empty and keep
`welcomeUrl` pointing at a public `.b64` clip. It gains the connection-scoped
playback fix, but its spoken terrain/weather cannot change. Unconfigured TTS makes
no requests and leaves this behavior unchanged. For compatibility, existing
complete bridge settings without `ttsEnabled` are treated as enabled.
Installing the addon supplies the recordings to every player. The external
helper is needed only for optional live speech and its admin preview. Legacy
`welcomeUrl` settings are preserved in the profile; the generic bundled welcome
is now the default and failure fallback.
Mission code can use the server-only `mode.ERR_Speech().Request(text, receiver)`
entry point after verification. It returns false when unavailable, busy, or
@@ -269,31 +305,25 @@ contact/engaging events with a confirmed visible count or observed approach.
Other detailed orders and radio transmissions stay native. There are no generic
HQ announcements. Calm groups can now have the short exchanges described below.
A supported callout near a living player prepares its TTS line if the verified
bridge is idle. New preparations are spaced at least 65 seconds apart to respect
the bridge's synthesis limit. The first occurrences therefore remain native;
the generated vocabulary fills gradually as those events occur. Server and
bridge caches reuse repeated text. Subsequent calls advertise the prepared
clip to nearby clients, which download, validate and prepare a spatial graph.
A supported callout near a living player selects its bundled recording. Nearby
clients initialize its native spatial graph without synthesis or downloading.
The server replaces a call only after **every nearby living player** has
acknowledged readiness for that exact clip in the current mission. Otherwise
the entire allowed native call uses normal native audio. Covert calls are silent
including their stock fallback; added conversations wait for prepared clips.
No player request can start synthesis.
the allowed call uses native audio. Covert calls remain silent, including their
stock fallback; conversations still require both sides to be ready. Unknown
callout types and radio transmissions remain native.
Generated direct speech uses `AudioSystem.PlayEvent` with a runtime audio graph
and the soldier's transform. Playback follows the soldier near head height,
stops on death or loss of a nearby living listener, and has an 80 metre delivery
limit and twelve second lifetime. Up to eight actors can speak concurrently.
Generated clips are not transmitted as native VoN audio, and this version does
not reproduce native radio filtering or all environmental occlusion. It must
not be described as full native voice replacement. TTS credentials remain on
the server; clients receive only public clip URLs and speaker replication IDs.
Unconfigured/disabled TTS leaves native soldier speech and the welcome unchanged.
Direct speech uses `AudioSystem.PlayEvent` at the soldier's transform. Playback
follows the soldier near head height, stops on death or loss of a nearby living
listener, and keeps the existing 80 metre delivery limit, twelve second lifetime
and eight simultaneous actor limit. These are local audio graphs, not native
VoN transmission, and are not a full replacement for native radio filtering or
all environmental occlusion. Disabling the optional live TTS service does not
disable bundled speech.
Verification: production policy tests cover all-client readiness, fallback,
actual-event mapping, radio exclusion, range, unavailable service, changed URL
and preparation failure. A hidden client using a null audio sink prepared the
and preparation failure. Earlier live-download validation: a hidden client using a null audio sink prepared the
production runtime graph and recorded the existing Google WAV with strong left
and right separation at five metres. Playback at 500 metres returned an invalid
handle and the recording was silent after the preceding clip finished. The
@@ -307,14 +337,14 @@ historical. It proves radio recipient routing, not native soldier voice playback
## Context and conversations (5 October follow-up)
When optional TTS is verified and enabled, the comms handler suppresses direct
The comms handler suppresses direct
and radio callouts while an alerted group has not opened fire or come under
fire. This is a conservative proxy for being discovered, not a claim to know
what a player has noticed. Own projectile events and incoming bullet impacts
or flybys permit combat calls for 20 seconds; mere sightings, aiming and distant
gunshots do not. Recent perceived enemies keep casual chatter suppressed for
at least 60 seconds after the last threat observation. Disabling/unconfiguring
TTS preserves native speech; this feature does not change combat decisions.
Missing bundled clips preserve allowed native speech; this feature does not change combat decisions.
Reports count distinct currently visible, living enemy characters in the
speaker's own native perception, without enumerating players or inspecting
@@ -336,7 +366,7 @@ can take several eligible encounters to become audible. This is contextual
scripted dialogue voiced by Google TTS, not an LLM generating conversations.
Validation for this follow-up: production-method regression harnesses cover
stealth fallback, disabled settings, count/motion sampling, two-clip readiness,
stealth fallback, offline bundled playback, count/motion sampling, two-clip readiness,
reply cancellation and cooldowns. The complete mod compiled and loaded in the
isolated Nogova dedicated fixture without script errors. No live server restart,
Workshop publication or end-to-end multiplayer conversation test was performed.