782 lines
22 KiB
Plaintext
782 lines
22 KiB
Plaintext
/* tws_t5_common.gsc — shared config, HUD helpers, connect/spawn/help registries. */
|
|
|
|
#include maps\_utility;
|
|
#include common_scripts\utility;
|
|
|
|
main()
|
|
{
|
|
precacheShader("white");
|
|
}
|
|
|
|
init()
|
|
{
|
|
if (GetDvar(#"zombiemode") != "1")
|
|
return;
|
|
|
|
common_config();
|
|
|
|
register_help_command(".help", "List available commands");
|
|
level thread service_game_over_via("end_game");
|
|
level thread service_game_over_via("game_ended");
|
|
level thread service_game_over_via("intermission");
|
|
level thread help_chat_listener();
|
|
level thread on_player_connect_dispatch();
|
|
}
|
|
|
|
common_config()
|
|
{
|
|
if (isDefined(level.hud_x))
|
|
return;
|
|
|
|
// Retain legacy panel coordinates for existing helper consumers.
|
|
level.hud_x = 10;
|
|
level.hud_y = 30;
|
|
// Retain the legacy fields for consumers of the original common config.
|
|
// The panel renderers below use dedicated row/column offsets instead.
|
|
level.hud_row_match = level.hud_y;
|
|
level.hud_row_round = level.hud_y + 15;
|
|
level.hud_row_name = level.hud_y + 32;
|
|
level.hud_row_count = level.hud_y + 54;
|
|
level.hud_col_count = level.hud_x + 90;
|
|
level.hud_col_name = level.hud_x + 60;
|
|
level.hud_col_health = level.hud_x + 120 + 12;
|
|
level.hud_health_threshold = 1.0;
|
|
level.hud_panel_right = 10;
|
|
level.hud_panel_top = 20;
|
|
// Fullscreen uses a 640x480 frame. Convert the panel's 480-height units
|
|
// to that frame at the 16:9 reference aspect (640 / (480 * 16 / 9)).
|
|
level.hud_panel_x_scale = 0.75;
|
|
level.hud_panel_width = 220;
|
|
level.hud_core_height = 100;
|
|
level.hud_service_y = 108;
|
|
level.hud_service_height = 124;
|
|
level.hud_pad = 10;
|
|
level.hud_row_header = 10;
|
|
level.hud_row_timers = 34;
|
|
level.hud_row_stats = 59;
|
|
level.hud_row_bar = 80;
|
|
level.hud_row_afk = 86;
|
|
|
|
level.hud_font_small = 1.1;
|
|
level.hud_font_large = 1.6;
|
|
level.hud_font_mid = 1.25;
|
|
level.hud_font_afk = 1.0;
|
|
level.hud_bar_width = 200;
|
|
level.hud_bar_height = 4;
|
|
level.hud_rate = 0.1;
|
|
level.hud_c_panel = (0.07, 0.10, 0.08);
|
|
level.hud_panel_alpha = 0.72;
|
|
level.hud_c_label = (0.72, 0.77, 0.74);
|
|
level.hud_c_dim = (0.65, 0.70, 0.67);
|
|
level.hud_c_count = (0.93, 0.96, 0.94);
|
|
level.hud_c_name = (0.65, 0.85, 0.70);
|
|
level.hud_c_high = (0.65, 0.85, 0.70);
|
|
level.hud_c_mid = (1, 0.8, 0);
|
|
level.hud_c_low = (1, 0.2, 0.2);
|
|
level.hud_c_afk = (1, 0.8, 0.2);
|
|
|
|
// Minimal overlays use absolute coordinates in the fullscreen 640x480 frame.
|
|
level.hud_overlay_timer_x = 6;
|
|
level.hud_overlay_match_y = 8;
|
|
level.hud_overlay_round_y = 30;
|
|
level.hud_overlay_brand_x = 320;
|
|
level.hud_overlay_brand_y = 8;
|
|
level.hud_overlay_count_x = 300;
|
|
level.hud_overlay_count_y = 440;
|
|
level.hud_overlay_count_label_x = 306;
|
|
level.hud_overlay_count_label_y = 446;
|
|
level.hud_overlay_bar_x = 242;
|
|
level.hud_overlay_bar_y = 466;
|
|
level.hud_overlay_bar_width = 156;
|
|
level.hud_overlay_bar_height = 4;
|
|
level.hud_overlay_health_y = 460;
|
|
level.hud_overlay_health_x = 414;
|
|
level.hud_overlay_slash_x = 418;
|
|
level.hud_overlay_maxhealth_x = 445;
|
|
level.hud_overlay_hp_x = 449;
|
|
level.hud_overlay_afk_x = 320;
|
|
level.hud_overlay_afk_y = 421;
|
|
level.hud_service_left = 432;
|
|
level.hud_service_right = 633;
|
|
level.hud_service_description_x = 538;
|
|
level.hud_service_title_y = 54;
|
|
level.hud_service_help_y = 80;
|
|
level.hud_service_help_pitch = 24;
|
|
level.hud_service_help_rows = 9;
|
|
level.hud_service_record_y = 36;
|
|
level.hud_service_holders_y = 60;
|
|
level.hud_service_holders_pitch = 18;
|
|
|
|
if (!isDefined(level.tws_spawn_handlers))
|
|
level.tws_spawn_handlers = [];
|
|
}
|
|
|
|
ensure_config()
|
|
{
|
|
if (!isDefined(level.hud_x))
|
|
common_config();
|
|
}
|
|
|
|
register_spawn_handler(fn)
|
|
{
|
|
if (!isDefined(level.tws_spawn_handlers))
|
|
level.tws_spawn_handlers = [];
|
|
|
|
level.tws_spawn_handlers[level.tws_spawn_handlers.size] = fn;
|
|
}
|
|
|
|
// Connection handlers also serve newcomers still waiting in spectator mode.
|
|
register_connect_handler(fn)
|
|
{
|
|
if (!isDefined(level.tws_connect_handlers))
|
|
level.tws_connect_handlers = [];
|
|
|
|
level.tws_connect_handlers[level.tws_connect_handlers.size] = fn;
|
|
}
|
|
|
|
// Modules register their own entries so help only lists installed commands.
|
|
register_help_command(command, description)
|
|
{
|
|
if (!isDefined(level.tws_help_commands))
|
|
level.tws_help_commands = [];
|
|
|
|
entry = spawnStruct();
|
|
entry.command = command;
|
|
entry.description = description;
|
|
level.tws_help_commands[level.tws_help_commands.size] = entry;
|
|
}
|
|
|
|
// Listen at level scope so newcomers can ask for help before their first spawn.
|
|
help_chat_listener()
|
|
{
|
|
for (;;)
|
|
{
|
|
level waittill("say", message, player);
|
|
|
|
if (!isDefined(player) || !isDefined(message))
|
|
continue;
|
|
|
|
command = toLower(message);
|
|
if (command == ".help" || command == ".commands")
|
|
player show_help();
|
|
}
|
|
}
|
|
|
|
// A single per-player controller owns service priority, pages and expiry.
|
|
show_help()
|
|
{
|
|
if (isDefined(level.tws_service_ended))
|
|
return;
|
|
self service_ensure();
|
|
state = self.tws_service;
|
|
service_advance(state, getTime());
|
|
state.generation++;
|
|
state.help = service_request("help", service_page_count(state.commands.size, level.hud_service_help_rows), state.generation);
|
|
service_render(state);
|
|
}
|
|
|
|
// An undefined snapshot is the explicit unavailable view for manual requests.
|
|
show_record(snapshot)
|
|
{
|
|
if (isDefined(level.tws_service_ended))
|
|
return;
|
|
self service_ensure();
|
|
state = self.tws_service;
|
|
service_advance(state, getTime());
|
|
count = 0;
|
|
if (isDefined(snapshot))
|
|
count = snapshot.lines.size;
|
|
state.generation++;
|
|
state.record = service_request("record", service_page_count(count, 3), state.generation);
|
|
state.record.snapshot = snapshot;
|
|
service_render(state);
|
|
}
|
|
|
|
service_page_count(count, rows)
|
|
{
|
|
return int((max(count, 1) + rows - 1) / rows);
|
|
}
|
|
|
|
service_request(kind, pages, generation)
|
|
{
|
|
request = spawnStruct();
|
|
request.kind = kind;
|
|
request.generation = generation;
|
|
request.page = 0;
|
|
request.pages = pages;
|
|
request.remaining = 12000;
|
|
return request;
|
|
}
|
|
|
|
service_current(state)
|
|
{
|
|
if (isDefined(state.help))
|
|
return state.help;
|
|
return state.record;
|
|
}
|
|
|
|
service_advance(state, now)
|
|
{
|
|
elapsed = max(0, now - state.updated_at);
|
|
state.updated_at = now;
|
|
request = service_current(state);
|
|
if (!isDefined(request) || state.closed)
|
|
return;
|
|
|
|
// Only the visible request consumes time. Help leaves the record untouched.
|
|
request.remaining -= elapsed;
|
|
if (request.remaining > 0)
|
|
return;
|
|
request.page++;
|
|
request.remaining = 12000;
|
|
if (request.page >= request.pages)
|
|
{
|
|
if (request.kind == "help")
|
|
state.help = undefined;
|
|
else
|
|
state.record = undefined;
|
|
}
|
|
}
|
|
|
|
// Stable order is independent of module initialization order; absent commands
|
|
// stay absent. Unknown future commands follow the built-in ones in registry order.
|
|
help_rank(command)
|
|
{
|
|
if (command == ".help") return 0;
|
|
if (command == ".hud") return 1;
|
|
if (command == ".afk") return 2;
|
|
if (command == ".back") return 3;
|
|
if (command == ".join") return 4;
|
|
if (command == ".leaders") return 5;
|
|
if (command == ".b") return 6;
|
|
if (command.size >= 3 && getSubStr(command, 0, 3) == ".d ") return 7;
|
|
if (command.size >= 3 && getSubStr(command, 0, 3) == ".w ") return 8;
|
|
return 9;
|
|
}
|
|
|
|
help_entries()
|
|
{
|
|
entries = [];
|
|
if (!isDefined(level.tws_help_commands))
|
|
return entries;
|
|
for (rank = 0; rank <= 9; rank++)
|
|
{
|
|
for (i = 0; i < level.tws_help_commands.size; i++)
|
|
{
|
|
entry = level.tws_help_commands[i];
|
|
if (help_rank(entry.command) == rank)
|
|
entries[entries.size] = entry;
|
|
}
|
|
}
|
|
return entries;
|
|
}
|
|
|
|
help_command_label(command)
|
|
{
|
|
return command;
|
|
}
|
|
|
|
help_description(entry)
|
|
{
|
|
rank = help_rank(entry.command);
|
|
if (rank == 0) return "Show commands";
|
|
if (rank == 1) return "Toggle core HUD";
|
|
if (rank == 2) return "Protect & freeze";
|
|
if (rank == 3) return "Return to play";
|
|
if (rank == 4) return "Join as newcomer";
|
|
if (rank == 5) return "View records";
|
|
if (rank == 6) return "Bank balance";
|
|
if (rank == 7) return "Deposit";
|
|
if (rank == 8) return "Withdraw";
|
|
return entry.description;
|
|
}
|
|
|
|
service_ensure()
|
|
{
|
|
if (isDefined(self.tws_service))
|
|
return;
|
|
ensure_config();
|
|
state = spawnStruct();
|
|
state.elems = [];
|
|
state.commands = help_entries();
|
|
state.help = undefined;
|
|
state.record = undefined;
|
|
state.closed = false;
|
|
state.updated_at = getTime();
|
|
state.rendered = false;
|
|
state.generation = 0;
|
|
state.last_generation = 0;
|
|
state.last_page = -1;
|
|
state.record_text = [];
|
|
state.help_page = -1;
|
|
state.rows = [];
|
|
state.command_rows = [];
|
|
state.description_rows = [];
|
|
state.view_kind = undefined;
|
|
self.tws_service = state;
|
|
|
|
self thread service_loop(state);
|
|
self thread service_disconnect(state);
|
|
self thread service_end_game(state);
|
|
}
|
|
|
|
// Allocate only the active view. Alpha-zero elements still occupy HUD slots.
|
|
service_view_create(state, request)
|
|
{
|
|
service_view_destroy(state);
|
|
state.view_kind = request.kind;
|
|
state.view_paged = request.pages > 1;
|
|
if (state.view_paged)
|
|
state.page_counter = service_text(self, state, level.hud_service_right,
|
|
level.hud_service_title_y, "right", 1.0, "", level.hud_c_dim);
|
|
|
|
if (request.kind == "help")
|
|
{
|
|
state.help_title = service_text(self, state, level.hud_service_left,
|
|
level.hud_service_title_y, "left", 1.1, "COMMANDS", level.hud_c_label);
|
|
rows = state.commands.size;
|
|
if (rows > level.hud_service_help_rows)
|
|
rows = level.hud_service_help_rows;
|
|
// Explicit lines also work on T5, which can collapse multiline strings.
|
|
for (i = 0; i < rows; i++)
|
|
{
|
|
y = level.hud_service_help_y + i * level.hud_service_help_pitch;
|
|
state.command_rows[i] = service_text(self, state, level.hud_service_left,
|
|
y, "left", 1.0, "", level.hud_c_count);
|
|
state.description_rows[i] = service_text(self, state, level.hud_service_description_x,
|
|
y, "left", 1.0, "", level.hud_c_label);
|
|
}
|
|
return;
|
|
}
|
|
|
|
state.record_title = service_text(self, state, level.hud_service_right,
|
|
level.hud_service_record_y, "right", 1.1, "", level.hud_c_count);
|
|
for (i = 0; i < 3; i++)
|
|
state.rows[i] = service_text(self, state, level.hud_service_right,
|
|
level.hud_service_holders_y + i * level.hud_service_holders_pitch,
|
|
"right", 1.05, "", level.hud_c_label);
|
|
if (isDefined(state.page_counter))
|
|
state.page_counter.y = level.hud_service_holders_y + 3 * level.hud_service_holders_pitch;
|
|
}
|
|
|
|
service_view_destroy(state)
|
|
{
|
|
for (i = 0; i < state.elems.size; i++)
|
|
{
|
|
if (isDefined(state.elems[i]))
|
|
state.elems[i] Destroy();
|
|
}
|
|
state.elems = [];
|
|
state.view_kind = undefined;
|
|
state.view_paged = undefined;
|
|
state.page_counter = undefined;
|
|
state.help_title = undefined;
|
|
state.command_rows = [];
|
|
state.description_rows = [];
|
|
state.record_title = undefined;
|
|
state.rows = [];
|
|
state.page_text = undefined;
|
|
state.record_header_text = undefined;
|
|
state.record_text = [];
|
|
state.help_page = -1;
|
|
}
|
|
|
|
service_text(player, state, x, y, align, scale, text, colour)
|
|
{
|
|
elem = make_overlay_text(player, x, y, align, scale, colour);
|
|
elem.alpha = 0;
|
|
elem.archived = false;
|
|
if (text != "")
|
|
elem SetText(text);
|
|
state.elems[state.elems.size] = elem;
|
|
return elem;
|
|
}
|
|
|
|
service_render(state)
|
|
{
|
|
if (state.closed)
|
|
return;
|
|
request = service_current(state);
|
|
page = -1;
|
|
generation = 0;
|
|
if (isDefined(request))
|
|
{
|
|
page = request.page;
|
|
generation = request.generation;
|
|
}
|
|
if (state.rendered && state.last_generation == generation && state.last_page == page)
|
|
return;
|
|
state.rendered = true;
|
|
state.last_generation = generation;
|
|
state.last_page = page;
|
|
if (!isDefined(request))
|
|
{
|
|
service_view_destroy(state);
|
|
return;
|
|
}
|
|
paged = request.pages > 1;
|
|
if (!isDefined(state.view_kind) || state.view_kind != request.kind || state.view_paged != paged)
|
|
service_view_create(state, request);
|
|
for (i = 0; i < state.elems.size; i++)
|
|
state.elems[i].alpha = 0;
|
|
|
|
if (paged)
|
|
{
|
|
page_text = "" + (page + 1) + " / " + request.pages;
|
|
if (!isDefined(state.page_text) || state.page_text != page_text)
|
|
{
|
|
state.page_counter SetText(page_text);
|
|
state.page_text = page_text;
|
|
}
|
|
state.page_counter.alpha = 1;
|
|
}
|
|
if (request.kind == "help")
|
|
{
|
|
state.help_title.alpha = 1;
|
|
for (i = 0; i < state.command_rows.size; i++)
|
|
{
|
|
index = page * level.hud_service_help_rows + i;
|
|
if (index >= state.commands.size)
|
|
continue;
|
|
if (state.help_page != page)
|
|
{
|
|
entry = state.commands[index];
|
|
state.command_rows[i] SetText(help_command_label(entry.command));
|
|
state.description_rows[i] SetText(help_description(entry));
|
|
}
|
|
state.command_rows[i].alpha = 1;
|
|
state.description_rows[i].alpha = 1;
|
|
}
|
|
state.help_page = page;
|
|
return;
|
|
}
|
|
|
|
header = "Map record unavailable";
|
|
snapshot = request.snapshot;
|
|
if (isDefined(snapshot))
|
|
{
|
|
header = "No recorded high round yet";
|
|
if (snapshot.round > 0)
|
|
header = "Map record | Round " + snapshot.round;
|
|
}
|
|
if (!isDefined(state.record_header_text) || state.record_header_text != header)
|
|
{
|
|
state.record_title SetText(header);
|
|
state.record_header_text = header;
|
|
}
|
|
state.record_title.alpha = 1;
|
|
if (!isDefined(snapshot) || snapshot.round == 0)
|
|
return;
|
|
for (i = 0; i < 3; i++)
|
|
{
|
|
index = page * 3 + i;
|
|
if (index < snapshot.lines.size)
|
|
{
|
|
text = snapshot.lines[index];
|
|
if (!isDefined(state.record_text[i]) || state.record_text[i] != text)
|
|
{
|
|
state.rows[i] SetText(text);
|
|
state.record_text[i] = text;
|
|
}
|
|
state.rows[i].alpha = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
service_loop(state)
|
|
{
|
|
self endon("disconnect");
|
|
level endon("tws_service_game_over");
|
|
for (;;)
|
|
{
|
|
service_advance(state, getTime());
|
|
service_render(state);
|
|
wait 0.1;
|
|
}
|
|
}
|
|
|
|
service_disconnect(state)
|
|
{
|
|
self waittill("disconnect");
|
|
service_destroy(state);
|
|
}
|
|
|
|
service_end_game(state)
|
|
{
|
|
self endon("disconnect");
|
|
level waittill("tws_service_game_over");
|
|
service_destroy(state);
|
|
}
|
|
|
|
service_destroy(state)
|
|
{
|
|
if (state.closed)
|
|
return;
|
|
state.closed = true;
|
|
state.help = undefined;
|
|
state.record = undefined;
|
|
service_view_destroy(state);
|
|
}
|
|
|
|
service_game_over_via(event)
|
|
{
|
|
level endon("tws_service_game_over");
|
|
level waittill(event);
|
|
level.tws_service_ended = true;
|
|
level notify("tws_service_game_over");
|
|
}
|
|
|
|
// The only connected listener; modules use the shared registries.
|
|
on_player_connect_dispatch()
|
|
{
|
|
for (;;)
|
|
{
|
|
level waittill("connected", player);
|
|
player thread on_player_spawned_dispatch();
|
|
player thread on_player_connected_dispatch();
|
|
}
|
|
}
|
|
|
|
on_player_connected_dispatch()
|
|
{
|
|
self endon("disconnect");
|
|
// Leave the connection handshake before invoking optional modules.
|
|
wait 0.05;
|
|
|
|
if (!isDefined(level.tws_connect_handlers))
|
|
return;
|
|
|
|
for (i = 0; i < level.tws_connect_handlers.size; i++)
|
|
self thread [[ level.tws_connect_handlers[i] ]]();
|
|
}
|
|
|
|
// handlers own their own self endon("disconnect")
|
|
on_player_spawned_dispatch()
|
|
{
|
|
self endon("disconnect");
|
|
|
|
self waittill("spawned_player");
|
|
|
|
if (!isDefined(level.tws_spawn_handlers))
|
|
return;
|
|
|
|
for (i = 0; i < level.tws_spawn_handlers.size; i++)
|
|
self thread [[ level.tws_spawn_handlers[i] ]]();
|
|
}
|
|
|
|
make_text_elem(player, x, y, align_x, scale, colour)
|
|
{
|
|
elem = NewClientHudElem(player);
|
|
|
|
elem.horzAlign = "left";
|
|
elem.vertAlign = "top";
|
|
elem.alignX = align_x;
|
|
elem.alignY = "top";
|
|
elem.x = x;
|
|
elem.y = y;
|
|
elem.foreground = 1;
|
|
// Sub-1.0 text can render oversized on clients; keep a safe minimum.
|
|
elem.fontScale = max(1.0, scale);
|
|
elem.alpha = 1;
|
|
elem.color = colour;
|
|
|
|
// black glow reads as an outline against bright geometry
|
|
elem.glowColor = (0, 0, 0);
|
|
elem.glowAlpha = 0.6;
|
|
|
|
return elem;
|
|
}
|
|
|
|
make_shader_elem(player, x, y)
|
|
{
|
|
elem = NewClientHudElem(player);
|
|
|
|
elem.horzAlign = "left";
|
|
elem.vertAlign = "top";
|
|
elem.alignX = "left";
|
|
elem.alignY = "top";
|
|
elem.x = x;
|
|
elem.y = y;
|
|
elem.foreground = 1;
|
|
elem.alpha = 1;
|
|
|
|
return elem;
|
|
}
|
|
|
|
// Absolute fullscreen overlays leave stock HUD areas and the center clear.
|
|
make_overlay_text(player, x, y, align_x, scale, colour)
|
|
{
|
|
elem = make_text_elem(player, x, y, align_x, scale, colour);
|
|
elem.horzAlign = "fullscreen";
|
|
elem.vertAlign = "fullscreen";
|
|
elem.sort = 20;
|
|
elem.archived = true;
|
|
return elem;
|
|
}
|
|
|
|
make_overlay_shader(player, x, y, width, height, colour, alpha, sort)
|
|
{
|
|
elem = make_shader_elem(player, x, y);
|
|
elem.horzAlign = "fullscreen";
|
|
elem.vertAlign = "fullscreen";
|
|
elem.color = colour;
|
|
elem.alpha = alpha;
|
|
elem.sort = sort;
|
|
elem.archived = true;
|
|
elem SetShader("white", make_overlay_width(width), int(max(1, height)));
|
|
return elem;
|
|
}
|
|
|
|
make_overlay_width(width)
|
|
{
|
|
// Native max() returns a float; shader dimensions must be integers.
|
|
return int(max(1, width));
|
|
}
|
|
|
|
make_core_overlay_text(player, x, y, align_x, scale, colour)
|
|
{
|
|
elem = make_overlay_text(player, x, y, align_x, scale, colour);
|
|
register_core_elem(player, elem);
|
|
return elem;
|
|
}
|
|
|
|
make_core_overlay_shader(player, x, y, width, height, colour, alpha, sort)
|
|
{
|
|
elem = make_overlay_shader(player, x, y, width, height, colour, alpha, sort);
|
|
register_core_elem(player, elem);
|
|
return elem;
|
|
}
|
|
|
|
// Panel x/y are local to the upper-right core origin. Fullscreen bypasses the
|
|
// engine safe area. Horizontal conversion preserves the original size at 16:9;
|
|
// other aspects retain the right-edge anchor with proportional horizontal size.
|
|
make_panel_text(player, x, y, align_x, scale, colour)
|
|
{
|
|
elem = make_text_elem(player, 640 + (x - level.hud_panel_width - level.hud_panel_right) * level.hud_panel_x_scale,
|
|
level.hud_panel_top + y, align_x, scale, colour);
|
|
elem.horzAlign = "fullscreen";
|
|
elem.vertAlign = "fullscreen";
|
|
elem.sort = 20;
|
|
elem.archived = true;
|
|
return elem;
|
|
}
|
|
|
|
make_panel_shader(player, x, y, width, height, colour, alpha, sort)
|
|
{
|
|
elem = make_shader_elem(player, 640 + (x - level.hud_panel_width - level.hud_panel_right) * level.hud_panel_x_scale,
|
|
level.hud_panel_top + y);
|
|
elem.horzAlign = "fullscreen";
|
|
elem.vertAlign = "fullscreen";
|
|
elem.color = colour;
|
|
elem.alpha = alpha;
|
|
elem.sort = sort;
|
|
elem.archived = true;
|
|
elem SetShader("white", make_panel_width(width), height);
|
|
return elem;
|
|
}
|
|
|
|
// Native shader widths are integers; dynamic fills use the same conversion.
|
|
make_panel_width(width)
|
|
{
|
|
// max() returns a float even for integer inputs; cast its final result.
|
|
return int(max(1, width * level.hud_panel_x_scale));
|
|
}
|
|
|
|
// Core elements share a visibility mask; services keep their independent alpha.
|
|
make_core_text(player, x, y, align_x, scale, colour)
|
|
{
|
|
elem = make_panel_text(player, x, y, align_x, scale, colour);
|
|
register_core_elem(player, elem);
|
|
return elem;
|
|
}
|
|
|
|
make_core_shader(player, x, y, width, height, colour, alpha, sort)
|
|
{
|
|
elem = make_panel_shader(player, x, y, width, height, colour, alpha, sort);
|
|
register_core_elem(player, elem);
|
|
return elem;
|
|
}
|
|
|
|
register_core_elem(player, elem)
|
|
{
|
|
live = [];
|
|
if (isDefined(player.tws_core_hud_elems))
|
|
{
|
|
for (i = 0; i < player.tws_core_hud_elems.size; i++)
|
|
{
|
|
old = player.tws_core_hud_elems[i];
|
|
if (isDefined(old))
|
|
live[live.size] = old;
|
|
}
|
|
}
|
|
live[live.size] = elem;
|
|
player.tws_core_hud_elems = live;
|
|
set_core_alpha(player, elem, elem.alpha);
|
|
}
|
|
|
|
set_core_alpha(player, elem, alpha)
|
|
{
|
|
if (!isDefined(elem))
|
|
return;
|
|
elem.tws_core_alpha = alpha;
|
|
elem.alpha = alpha;
|
|
if (isDefined(player.tws_hud_hidden) && player.tws_hud_hidden)
|
|
elem.alpha = 0;
|
|
}
|
|
|
|
toggle_core_hud()
|
|
{
|
|
hidden = false;
|
|
if (isDefined(self.tws_hud_hidden))
|
|
hidden = self.tws_hud_hidden;
|
|
self.tws_hud_hidden = !hidden;
|
|
if (!isDefined(self.tws_core_hud_elems))
|
|
return;
|
|
live = [];
|
|
for (i = 0; i < self.tws_core_hud_elems.size; i++)
|
|
{
|
|
elem = self.tws_core_hud_elems[i];
|
|
if (!isDefined(elem))
|
|
continue;
|
|
set_core_alpha(self, elem, elem.tws_core_alpha);
|
|
live[live.size] = elem;
|
|
}
|
|
self.tws_core_hud_elems = live;
|
|
}
|
|
|
|
destroy_on_disconnect(elems)
|
|
{
|
|
self waittill("disconnect");
|
|
|
|
for (i = 0; i < elems.size; i++)
|
|
{
|
|
if (isDefined(elems[i]))
|
|
elems[i] Destroy();
|
|
}
|
|
}
|
|
|
|
int_dvar_or(name, fallback)
|
|
{
|
|
raw = GetDvar(name);
|
|
if (raw == "")
|
|
return fallback;
|
|
return int(raw);
|
|
}
|
|
|
|
format_mmss(elapsed_ms)
|
|
{
|
|
total_secs = int(elapsed_ms / 1000);
|
|
|
|
if (total_secs < 0)
|
|
total_secs = 0;
|
|
|
|
mins = int(total_secs / 60);
|
|
secs = total_secs - (mins * 60);
|
|
|
|
sec_str = "" + secs;
|
|
if (secs < 10)
|
|
sec_str = "0" + secs;
|
|
|
|
return "" + mins + ":" + sec_str;
|
|
}
|