Vendor pinned T5 and T6 plugin sources under the new plugins layout. Add native HTTP deadlines, status and timing diagnostics, telemetry integration, and build/test tooling.
118 lines
3.6 KiB
Plaintext
118 lines
3.6 KiB
Plaintext
/* tws_t6_join.gsc - .join lets a newcomer leave spectator mode before round end. */
|
|
|
|
#include maps\mp\_utility;
|
|
#include common_scripts\utility;
|
|
|
|
// Plutonium probes both entry points; runtime setup belongs in init.
|
|
main()
|
|
{
|
|
println("[tws_t6_join] main reached");
|
|
}
|
|
|
|
init()
|
|
{
|
|
println("[tws_t6_join] init reached");
|
|
|
|
scripts\zm\tws_t6_common::ensure_config();
|
|
scripts\zm\tws_t6_common::register_help_command(".join", "Join mid-round (newcomers only)");
|
|
scripts\zm\tws_t6_common::register_spawn_handler(::join_spawn);
|
|
|
|
level thread join_chat_listener();
|
|
}
|
|
|
|
// Never reset this on death or round change. Spectator spawns do not count.
|
|
join_spawn()
|
|
{
|
|
self.tws_join_has_played = true;
|
|
}
|
|
|
|
join_chat_listener()
|
|
{
|
|
level endon("end_game");
|
|
level endon("game_ended");
|
|
level endon("intermission");
|
|
|
|
for (;;)
|
|
{
|
|
level waittill("say", message, player);
|
|
|
|
if (!isDefined(player) || !isDefined(message))
|
|
continue;
|
|
|
|
if (toLower(message) == ".join")
|
|
player thread join_request();
|
|
}
|
|
}
|
|
|
|
join_request()
|
|
{
|
|
self endon("disconnect");
|
|
level endon("end_game");
|
|
level endon("game_ended");
|
|
level endon("intermission");
|
|
|
|
// The spawn handler flag is set on first playable spawn only; spectator
|
|
// spawns do not trigger it. Belt-and-suspenders against re-triggering.
|
|
if (is_true(self.tws_join_has_played) || is_true(self.tws_join_used))
|
|
{
|
|
self iPrintLnBold("^3.join is only for newcomers who have not played yet");
|
|
return;
|
|
}
|
|
|
|
// Fail closed while the stock connection setup is still in progress.
|
|
// T6 stock does not populate self.initialized the way T5 SP zombiemode
|
|
// does; use sessionstate as the readiness signal.
|
|
if (!isDefined(self.sessionstate) || self.sessionstate != "spectator")
|
|
{
|
|
self iPrintLnBold("^3.join is only available while waiting to enter the game");
|
|
return;
|
|
}
|
|
|
|
if (is_true(level.intermission) || is_true(level.gameended) ||
|
|
!isDefined(level.round_number) || level.round_number < 1 ||
|
|
!isDefined(level.spawnplayer) || !join_has_active_player())
|
|
{
|
|
self iPrintLnBold("^3The game is not ready for .join");
|
|
return;
|
|
}
|
|
|
|
// Late connections can miss the stock seeding of self.spectator_respawn
|
|
// (stock asserts it in spectator_respawn); pick a random map spawn point
|
|
// as a fallback so the stock callback can proceed.
|
|
if (!isDefined(self.spectator_respawn))
|
|
{
|
|
points = getstructarray("initial_spawn_points", "targetname");
|
|
if (!isDefined(points) || points.size == 0)
|
|
{
|
|
self iPrintLnBold("^3No spawn point available; wait for the next round");
|
|
return;
|
|
}
|
|
|
|
self.spectator_respawn = points[randomInt(points.size)];
|
|
}
|
|
|
|
// Match stock spectators_respawn setup. Preserve any map-specific
|
|
// spawn callback if another mod already installed one.
|
|
if (!isDefined(level.custom_spawnplayer))
|
|
level.custom_spawnplayer = maps\mp\zombies\_zm::spectator_respawn;
|
|
|
|
// Consume BEFORE entering stock code, which may yield. Repeated chat
|
|
// commands cannot start overlapping spawns or grant another life.
|
|
self.tws_join_used = true;
|
|
self [[level.spawnplayer]]();
|
|
}
|
|
|
|
join_has_active_player()
|
|
{
|
|
players = getPlayers();
|
|
for (i = 0; i < players.size; i++)
|
|
{
|
|
player = players[i];
|
|
if (isDefined(player.sessionstate) && player.sessionstate == "playing" &&
|
|
isAlive(player) && !(player maps\mp\zombies\_zm_laststand::player_is_in_laststand()))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|