5.8 KiB
tws-zombies-scripts
Combined working repo for the TWS Plutonium Zombies GSC scripts across two games.
Layout
- t5/ — Plutonium T5 (Call of Duty: Black Ops 1) Zombies scripts. Most-developed baseline. See t5/README.md and t5/NOTES.md.
- t6/ — Plutonium T6 (Call of Duty: Black Ops 2) Zombies scripts. Ported from T5; at parity on common, HUD, AFK, lock, telemetry, join and leaderboard. Only
dbandbankremain T5-only. See t6/README.md, t6/NOTES.md, and t6/tools/check.ps1.
Parity
T5 and T6 are separate source trees, not a shared library — GSC namespaces, includes, and stock APIs differ enough between the two engines that a shared file is not practical. Feature parity is enforced pairwise: a change landed in t5/ should be considered for a companion change in t6/, adapted to T6 conventions.
Modules currently in each tree:
| Module | T5 | T6 |
|---|---|---|
| common | t5/tws_common.gsc |
t6/tws_t6_common.gsc |
| hud | t5/tws_hud.gsc |
t6/tws_t6_hud.gsc |
| afk | t5/tws_afk.gsc |
t6/tws_t6_afk.gsc |
| lock | t5/tws_lock.gsc |
t6/tws_t6_lock.gsc |
| telemetry | t5/tws_telemetry.gsc |
t6/tws_t6_telemetry.gsc — queued game_start / heartbeat / round_change / game_end matching T5 |
| join | t5/tws_join.gsc |
t6/tws_t6_join.gsc |
| leaderboard | t5/tws_leaderboard.gsc |
t6/tws_t6_leaderboard.gsc |
| db | t5/tws_db.gsc |
(not ported) |
| bank | t5/tws_bank.gsc |
(not ported) |
db and bank are T5-only for now.
Map record announcements
Install tws_leaderboard.gsc for T5 or tws_t6_leaderboard.gsc for T6,
along with the updated common module for that game.
The new module privately announces the current map's fleet-wide highest recorded
round and every tied holder once per connection, including spectator newcomers.
It reads Electric Cherry's public /api/leaderboard endpoint without a token;
only completed matches contribute. Ties may come from the same run or separate
runs. Names are the API's latest player names, with players identified by GUID.
Both versions default to https://ec.thewrightserver.net/api/leaderboard.
T5 discovers the map by engine identifier. T6 selects the exact variant using
the active mode/location, so Town Survival, TranZit and Town Grief stay separate.
See the game READMEs for plugin requirements and installation paths.
| Dvar | Default | Purpose |
|---|---|---|
tws_leaderboard_enabled |
enabled | 0 disables announcements and requests |
tws_leaderboard_url |
endpoint above | Full HTTPS API endpoint, without query parameters |
tws_leaderboard_map_key |
automatic | Exact, decoded API map key when automatic selection is unavailable |
For example, set tws_leaderboard_map_key "t6:zm_transit:town" explicitly
selects Town Survival. Normally this setting is unnecessary. An override must
exist in the API's map list and match the current game and engine map. Clear it
when changing variants; restart the map after changing these settings.
The announcement starts five seconds after player readiness and waits for the
initial record fetch if necessary. It appears in the same HUD area as .help,
below the health bar, with a heading such as Record: Round 23 and holder names
underneath. Each page shows up to three holder lines for 12 seconds. Opening
.help hides the record and pauses its display time until help closes.
All holders are included; colour/control codes are removed, and unusually long
names are shortened to keep messages readable. HUD elements are removed when
the announcement finishes, the player disconnects, or the game ends.
One level worker fetches the map list and pages of three players, stopping when the highest-round tie ends. Successful snapshots refresh every five minutes. Failures retry after 30 seconds and retain the last complete snapshot for up to 15 minutes. An empty selection says “No recorded high round yet”; unavailable, malformed or ambiguous results are logged and skipped when no usable cache exists. Partial page results never replace the cache. The API has no pagination snapshot token: changed totals/record rounds reject the refresh, but concurrent renames can still move entries between pages. Refreshes deduplicate GUIDs.
Requests have a 15-second GSC wait limit. The plugins cannot cancel a native request, so a stalled request prevents new leaderboard requests until it finishes; player threads never wait directly on HTTP. Responses at the plugins' 20 KiB truncation boundary are rejected. The complete JSON grammar, UTF-8, string escapes and response shape are checked before consuming data. These guards also reject HTML/error bodies; the plugins do not expose HTTP status or response headers.
Run the portable data/structure checks with node tools/check_leaderboard.mjs.
They execute the scripts' data helpers with engine-value shims, not a game VM.
Live checks: join while playing and spectating; die/respawn (no repeat); reconnect
(one new announcement); compare Town/TranZit/Grief; check one holder, ties across
pages, no records, and a slow/unavailable/malformed API. Disconnect or end the game
mid-announcement and confirm messages stop. Verify existing HUD, .help, .join
and telemetry still work. Open .help during a record page and check that the
record resumes afterwards without overlapping it. Runtime linking and client
readiness require Plutonium.
Validating T6
powershell -File t6/tools/check.ps1
Requires gsc-tool 1.4.10 (T6 PC) on PATH.