Import T5-AIO and T6 into combined repo

This commit is contained in:
2026-09-23 23:33:09 -04:00
commit f77cc7bdee
22 changed files with 3256 additions and 0 deletions
+345
View File
@@ -0,0 +1,345 @@
/* tws_t6_hud.gsc - configurable HUD stack: timers, zombie count, health bar. */
#include maps\mp\_utility;
#include common_scripts\utility;
// Plutonium probes both entry points; runtime setup belongs in init.
main()
{
}
init()
{
scripts\zm\tws_t6_common::ensure_config();
level thread round_watcher();
level thread game_over_watcher();
scripts\zm\tws_t6_common::register_spawn_handler(::hud_start);
}
hud_start()
{
self endon("disconnect");
if (isDefined(level.tws_ended) && level.tws_ended)
return;
self thread hud_timer_row();
self thread hud_zombie_counter();
self thread hud_health_display();
}
// Same game-over notification fan-out as T5.
game_over_watcher()
{
level thread game_over_via("end_game");
level thread game_over_via("game_ended");
level thread game_over_via("intermission");
}
game_over_via(notify_name)
{
level endon("hud_game_over");
level waittill(notify_name);
level.tws_ended = true;
level notify("hud_game_over");
}
// Poll stock round state; the first player spawn seeds pre-set round 1.
round_watcher()
{
level endon("hud_game_over");
last = 0;
if (isDefined(level.round_number))
last = level.round_number;
for (;;)
{
if (isDefined(level.round_number) && level.round_number != last)
{
last = level.round_number;
level.round_start_time = getTime();
if (!isDefined(level.match_start_time) && level.round_number >= 1)
{
level.match_start_time = getTime();
level notify("hud_match_started");
}
level notify("hud_round_changed");
}
wait (0.5);
}
}
hud_timer_row()
{
self endon("disconnect");
// fallback seed for the round-1-already-active case (round_watcher misses it)
if (!isDefined(level.match_start_time) &&
isDefined(level.round_number) &&
level.round_number >= 1)
{
level.match_start_time = getTime();
level.round_start_time = getTime();
level notify("hud_match_started");
}
match = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_x, level.hud_row_match,
"left", level.hud_font_small, level.hud_c_dim);
match.alpha = 0; // revealed by match_timer_bind when round 1 opens
round = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_x, level.hud_row_round,
"left", level.hud_font_small, level.hud_c_dim);
round SetTimerUp(0);
if (isDefined(level.round_start_time))
round SetTimerUp(max(0, (getTime() - level.round_start_time) / 1000.0));
// name only shows in co-op — your own name is noise in solo
name = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_x, level.hud_row_name,
"left", level.hud_font_small, level.hud_c_name);
if (isDefined(self.name))
name SetText(self.name);
else
name SetText(self.playername);
name.alpha = 0;
elems = [];
elems[elems.size] = match;
elems[elems.size] = round;
elems[elems.size] = name;
self thread scripts\zm\tws_t6_common::destroy_on_disconnect(elems);
self thread reset_timer_each_round(round);
self thread match_timer_bind(match);
self thread freeze_timers_on_game_over(match, round);
coop = -1;
for (;;)
{
is_coop = 0;
players = getPlayers();
if (players.size > 1)
is_coop = 1;
if (is_coop != coop)
{
name.alpha = is_coop;
coop = is_coop;
}
wait (1);
}
}
reset_timer_each_round(timer)
{
level endon("hud_game_over");
self endon("disconnect");
for (;;)
{
level waittill("hud_round_changed");
if (isDefined(timer))
timer SetTimerUp(0);
}
}
// T6 timer seed includes elapsed time for late joiners.
match_timer_bind(elem)
{
self endon("disconnect");
if (!isDefined(level.match_start_time))
level waittill("hud_match_started");
if (isDefined(elem))
{
elem SetTimerUp(max(0, (getTime() - level.match_start_time) / 1000.0));
elem.alpha = 1;
}
}
/*
Level-scope trigger only — per-player death/health polling is intercepted
by the zombiemode scripts. Freeze value math relies on the timers being
anchored at first spawn / first round transition, not level init.
*/
freeze_timers_on_game_over(match_elem, round_elem)
{
self endon("disconnect");
level waittill("hud_game_over");
if (isDefined(match_elem) && isDefined(level.match_start_time))
match_elem SetText(scripts\zm\tws_t6_common::format_mmss(getTime() - level.match_start_time));
if (isDefined(round_elem) && isDefined(level.round_start_time))
round_elem SetText(scripts\zm\tws_t6_common::format_mmss(getTime() - level.round_start_time));
}
hud_zombie_counter()
{
self endon("disconnect");
label = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_x, level.hud_row_count,
"left", level.hud_font_large, level.hud_c_label);
label SetText("Zombies");
count = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_col_count, level.hud_row_count,
"left", level.hud_font_large, level.hud_c_count);
count SetValue(0);
elems = [];
elems[elems.size] = label;
elems[elems.size] = count;
self thread scripts\zm\tws_t6_common::destroy_on_disconnect(elems);
last = -1;
for (;;)
{
remaining = 0;
if (isDefined(level.zombie_team))
remaining = maps\mp\zombies\_zm_utility::get_current_zombie_count();
if (isDefined(level.zombie_total))
remaining += max(0, level.zombie_total);
if (remaining != last)
{
count SetValue(remaining);
last = remaining;
}
wait (level.hud_rate);
}
}
hud_health_display()
{
self endon("disconnect");
bar_width = level.hud_bar_width;
// -2 on both axes so the back frames the bar with 2px padding
back = scripts\zm\tws_t6_common::make_shader_elem(self, level.hud_x - 2, level.hud_row_bar - 2);
back.alpha = 0.5;
back.color = (0, 0, 0);
back SetShader("white", bar_width + 4, level.hud_bar_height + 4);
bar = scripts\zm\tws_t6_common::make_shader_elem(self, level.hud_x, level.hud_row_bar);
bar.color = level.hud_c_high;
bar SetShader("white", bar_width, level.hud_bar_height);
/*
"87/160" is three elements, not a rebuilt string. SetText allocates
a config string per call; per-tick rebuilds crash the server.
cur is right-aligned so digits grow leftward and the slash + max
never shift.
*/
cur = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_col_health + 26, level.hud_row_bar + 3,
"right", level.hud_font_mid, level.hud_c_high);
cur SetValue(self.health);
slash = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_col_health + 30, level.hud_row_bar + 3,
"center", level.hud_font_mid, level.hud_c_high);
slash SetText("/");
max_hp = scripts\zm\tws_t6_common::make_text_elem(
self, level.hud_col_health + 34, level.hud_row_bar + 3,
"left", level.hud_font_mid, level.hud_c_high);
max_hp SetValue(100);
cur.alpha = 0;
slash.alpha = 0;
max_hp.alpha = 0;
elems = [];
elems[elems.size] = back;
elems[elems.size] = bar;
elems[elems.size] = cur;
elems[elems.size] = slash;
elems[elems.size] = max_hp;
self thread scripts\zm\tws_t6_common::destroy_on_disconnect(elems);
last_width = bar_width;
last_health = -1;
last_max = -1;
last_shown = -1;
for (;;)
{
maximum = 100;
if (isDefined(self.maxhealth) && self.maxhealth > 0)
maximum = self.maxhealth;
frac = self.health / (maximum * 1.0);
if (frac > 1)
frac = 1;
if (frac < 0)
frac = 0;
width = int(max(frac * bar_width, 1));
if (width != last_width)
{
bar SetShader("white", width, level.hud_bar_height);
last_width = width;
}
colour = level.hud_c_high;
if (frac <= 0.25)
colour = level.hud_c_low;
else if (frac <= 0.5)
colour = level.hud_c_mid;
bar.color = colour;
cur.color = colour;
slash.color = colour;
max_hp.color = colour;
// numbers only show once you're hurt
show = 0;
if (frac < level.hud_health_threshold)
show = 1;
if (show != last_shown)
{
cur.alpha = show;
slash.alpha = show;
max_hp.alpha = show;
last_shown = show;
}
if (self.health != last_health)
{
cur SetValue(self.health);
last_health = self.health;
}
if (maximum != last_max)
{
max_hp SetValue(maximum);
last_max = maximum;
}
wait (level.hud_rate);
}
}