seta hud_panel_healtharmor_hide_ondeath 0 "hide this panel when dead"
seta hud_panel_timer_increment "0" "show elapsed time instead of remaining time"
+seta hud_panel_timer_secondary "1" "secondary timer (0 = hide, 1 = show, 2 = show swapped)"
seta hud_panel_timer_unbound "0" "show seconds leading up to the start of the match"
seta hud_panel_engineinfo_framecounter_exponentialmovingaverage 1 "use an averaging method for calculating fps instead of counting frametime like engine does"
alias warp "qc_cmd_sv warp ${* ?}" // Choose different level in campaign
// other aliases for server commands
-alias endmatch "timelimit -1"
+set _endmatch 0 "if set to 1 ends the match immediately; use it instead of timelimit -1 (deprecated)"
+alias endmatch "_endmatch 1"
alias bots "minplayers 4; minplayers_per_team 2"
alias nobots "minplayers 0; minplayers_per_team 0"
seta hud_panel_notify_fadetime "3"
seta hud_panel_notify_icon_aspect "1"
-seta hud_panel_timer_pos "0.456000 0"
-seta hud_panel_timer_size "0.088000 0.030000"
+seta hud_panel_timer_pos "0.455000 0"
+seta hud_panel_timer_size "0.090000 0.050000"
seta hud_panel_timer_bg "border_plain_north"
seta hud_panel_timer_bg_color ""
seta hud_panel_timer_bg_color_team ""
seta hud_panel_notify_fadetime "3"
seta hud_panel_notify_icon_aspect "2"
-seta hud_panel_timer_pos "0.800000 0.040000"
-seta hud_panel_timer_size "0.070000 0.040000"
+seta hud_panel_timer_pos "0.790000 0.040000"
+seta hud_panel_timer_size "0.090000 0.050000"
seta hud_panel_timer_bg "border_small_timer"
seta hud_panel_timer_bg_color ""
seta hud_panel_timer_bg_color_team ""
seta hud_panel_notify_fadetime "3"
seta hud_panel_notify_icon_aspect "2"
-seta hud_panel_timer_pos "0.435000 0"
-seta hud_panel_timer_size "0.135000 0.060000"
+seta hud_panel_timer_pos "0.430000 0"
+seta hud_panel_timer_size "0.140000 0.060000"
seta hud_panel_timer_bg "0"
seta hud_panel_timer_bg_color ""
seta hud_panel_timer_bg_color_team ""
seta hud_panel_radar_maximized_rotation "1"
seta hud_panel_radar_maximized_zoommode "3"
-seta hud_panel_score_pos "0.465000 0.045000"
+seta hud_panel_score_pos "0.465000 0.060000"
seta hud_panel_score_size "0.090000 0.060000"
seta hud_panel_score_bg ""
seta hud_panel_score_bg_color ""
seta hud_panel_score_bg_padding ""
seta hud_panel_score_rankings "1"
-seta hud_panel_racetimer_pos "0.360000 0.090000"
+seta hud_panel_racetimer_pos "0.360000 0.130000"
seta hud_panel_racetimer_size "0.280000 0.090000"
seta hud_panel_racetimer_bg "0"
seta hud_panel_racetimer_bg_color ""
seta hud_panel_vote_bg_padding ""
seta hud_panel_vote_alreadyvoted_alpha "0.8"
-seta hud_panel_modicons_pos "0.560000 0"
+seta hud_panel_modicons_pos "0.580000 0"
seta hud_panel_modicons_size "0.050000 0.100000"
seta hud_panel_modicons_bg ""
seta hud_panel_modicons_bg_color ""
seta hud_panel_notify_fadetime "3"
seta hud_panel_notify_icon_aspect "2"
-seta hud_panel_timer_pos "0.435000 0"
-seta hud_panel_timer_size "0.135000 0.060000"
+seta hud_panel_timer_pos "0.430000 0"
+seta hud_panel_timer_size "0.140000 0.060000"
seta hud_panel_timer_bg "0"
seta hud_panel_timer_bg_color ""
seta hud_panel_timer_bg_color_team ""
seta hud_panel_radar_maximized_rotation "1"
seta hud_panel_radar_maximized_zoommode "3"
-seta hud_panel_score_pos "0.465000 0.045000"
+seta hud_panel_score_pos "0.465000 0.060000"
seta hud_panel_score_size "0.090000 0.060000"
seta hud_panel_score_bg ""
seta hud_panel_score_bg_color ""
seta hud_panel_score_bg_padding ""
seta hud_panel_score_rankings "1"
-seta hud_panel_racetimer_pos "0.360000 0.090000"
+seta hud_panel_racetimer_pos "0.360000 0.130000"
seta hud_panel_racetimer_size "0.280000 0.090000"
seta hud_panel_racetimer_bg "0"
seta hud_panel_racetimer_bg_color ""
seta hud_panel_vote_bg_padding ""
seta hud_panel_vote_alreadyvoted_alpha "0.8"
-seta hud_panel_modicons_pos "0.560000 0"
+seta hud_panel_modicons_pos "0.580000 0"
seta hud_panel_modicons_size "0.050000 0.100000"
seta hud_panel_modicons_bg ""
seta hud_panel_modicons_bg_color ""
seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer_pos "0.870000 0"
-seta hud_panel_timer_size "0.130000 0.060000"
+seta hud_panel_timer_size "0.130000 0.090000"
seta hud_panel_timer_bg "0"
seta hud_panel_timer_bg_color ""
seta hud_panel_timer_bg_color_team ""
seta hud_panel_notify_icon_aspect "2"
seta hud_panel_timer_pos "0.850000 0"
-seta hud_panel_timer_size "0.150000 0.060000"
+seta hud_panel_timer_size "0.150000 0.080000"
seta hud_panel_timer_bg ""
seta hud_panel_timer_bg_color "0 0.5 0.35"
seta hud_panel_timer_bg_color_team ""
// allow saving cvars that aesthetically change the panel into hud skin files
}
+vector HUD_Timer_Color(float timeleft)
+{
+ if(timeleft >= 300)
+ return '1 1 1'; //white
+ else if(timeleft >= 60)
+ return '1 1 0'; //yellow
+ else
+ return '1 0 0'; //red
+}
+
+float HUD_Timer_TimeElapsed(float curtime, float starttime)
+{
+ float time_elapsed = curtime - starttime;
+ if (!autocvar_hud_panel_timer_unbound)
+ time_elapsed = max(0, time_elapsed);
+ return floor(time_elapsed);
+}
+
+float HUD_Timer_TimeLeft(float curtime, float starttime, float timelimit)
+{
+ float timeleft = timelimit + starttime - curtime;
+ if (!autocvar_hud_panel_timer_unbound)
+ timeleft = bound(0, timeleft, timelimit);
+ return ceil(timeleft);
+}
+
void HUD_Timer()
{
if(!autocvar__hud_configure)
HUD_Scale_Enable();
else
HUD_Scale_Disable();
- HUD_Panel_DrawBg();
if(panel_bg_padding)
{
pos += '1 1 0' * panel_bg_padding;
}
string timer;
- float timelimit, timeleft, minutesLeft;
-
- timelimit = STAT(TIMELIMIT);
-
- if (autocvar_hud_panel_timer_unbound){
- timeleft = max(0, timelimit * 60 + STAT(GAMESTARTTIME) - time);
- } else {
- timeleft = bound(0, timelimit * 60 + STAT(GAMESTARTTIME) - time, timelimit * 60);
- }
- timeleft = ceil(timeleft);
-
- minutesLeft = floor(timeleft / 60);
-
- float warmup_timeleft = 0;
+ string subtimer = string_null;
+ string subtext = string_null;
+ float curtime, timelimit, timeleft;
+ vector timer_size, subtext_size, subtimer_size;
+ vector timer_color = '1 1 1';
+ vector subtimer_color = '1 1 1';
+ bool swap = (autocvar_hud_panel_timer_secondary == 2 && STAT(ROUNDSTARTTIME));
+
+ // Use real or frozen time and get the time limit
+ curtime = (intermission_time ? intermission_time : time);
if(warmup_stage)
{
- float warmup_timelimit = STAT(WARMUP_TIMELIMIT);
- if(warmup_timelimit > 0)
- warmup_timeleft = max(0, warmup_timelimit - time + STAT(GAMESTARTTIME));
- else if(warmup_timelimit == 0)
- warmup_timeleft = timeleft;
- warmup_timeleft = ceil(warmup_timeleft);
+ timelimit = STAT(WARMUP_TIMELIMIT);
+ if(timelimit == 0)
+ timelimit = STAT(TIMELIMIT) * 60;
+ }
+ else
+ {
+ timelimit = STAT(TIMELIMIT) * 60;
}
- vector timer_color;
- if(intermission_time || minutesLeft >= 5 || warmup_stage || timelimit == 0)
- timer_color = '1 1 1'; //white
- else if(minutesLeft >= 1)
- timer_color = '1 1 0'; //yellow
+ // Calculate time left
+ timeleft = HUD_Timer_TimeLeft(curtime, STAT(GAMESTARTTIME), timelimit);
+
+ // Timer color
+ if(!intermission_time && !warmup_stage && timelimit > 0)
+ timer_color = HUD_Timer_Color(timeleft);
+
+ // Timer text
+ if (autocvar_hud_panel_timer_increment || timelimit == 0)
+ timer = seconds_tostring(HUD_Timer_TimeElapsed(curtime, STAT(GAMESTARTTIME)));
else
- timer_color = '1 0 0'; //red
-
- if (intermission_time) {
- timer = seconds_tostring(max(0, floor(intermission_time - STAT(GAMESTARTTIME))));
- } else if (warmup_stage && warmup_timeleft >= 60) {
- timer = _("WARMUP");
- } else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
- if (time < STAT(GAMESTARTTIME))
- if (autocvar_hud_panel_timer_unbound){
- timer = seconds_tostring(-(STAT(GAMESTARTTIME) - time));
- } else {
- timer = seconds_tostring(0); //while restart is still active, show 00:00
- }
- else
- timer = seconds_tostring(floor(time - STAT(GAMESTARTTIME)));
- } else {
- if(warmup_stage)
- timer = seconds_tostring(warmup_timeleft);
- else
- timer = seconds_tostring(timeleft);
+ timer = seconds_tostring(timeleft);
+
+ // Secondary timer for round-based game modes
+ if(STAT(ROUNDSTARTTIME) && autocvar_hud_panel_timer_secondary)
+ {
+ if(STAT(ROUNDSTARTTIME) == -1) {
+ // Round can't start
+ subtimer = "--:--";
+ subtimer_color = '1 0 0';
+ } else {
+ float round_curtime, round_timelimit, round_timeleft;
+
+ // Use real or frozen time and get the time limit
+ round_curtime = (game_stopped_time ? game_stopped_time : time);
+ round_timelimit = STAT(ROUND_TIMELIMIT);
+
+ // Calculate time left
+ round_timeleft = HUD_Timer_TimeLeft(round_curtime, STAT(ROUNDSTARTTIME), round_timelimit);
+
+ // Subtimer color
+ if(!intermission_time && round_timelimit > 0)
+ subtimer_color = HUD_Timer_Color(round_timeleft);
+
+ // Subtimer text
+ if (autocvar_hud_panel_timer_increment || round_timelimit <= 0)
+ subtimer = seconds_tostring(HUD_Timer_TimeElapsed(round_curtime, STAT(ROUNDSTARTTIME)));
+ else
+ subtimer = seconds_tostring(round_timeleft);
+ }
}
- drawstring_aspect(pos, timer, mySize, timer_color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ // Subtext
+ int overtimes = STAT(OVERTIMES);
+
+ if(warmup_stage || autocvar__hud_configure)
+ subtext = _("Warmup");
+ else if(STAT(TIMEOUT_STATUS))
+ subtext = _("Timeout");
+ else if (overtimes == -1)
+ subtext = _("Sudden Death");
+ else if(overtimes == 1)
+ subtext = _("Overtime");
+ else if (overtimes >= 2)
+ subtext = sprintf(_("Overtime #%d"), overtimes);
+
+ subtext_size = vec2(mySize.x, mySize.y / 3);
+ timer_size = vec2(mySize.x, mySize.y - subtext_size.y);
+ subtimer_size = vec2(mySize.x / 3, mySize.y - subtext_size.y);
+
+ panel_size.y -= subtext_size.y;
+ HUD_Panel_DrawBg();
+
+ if(subtimer) {
+ float subtimer_padding = subtimer_size.y / 5;
+ timer_size.x -= subtimer_size.x;
+ drawstring_aspect(pos + eX * timer_size.x + eY * subtimer_padding, (swap ? timer : subtimer), subtimer_size - eY * subtimer_padding * 2, (swap ? timer_color : subtimer_color), panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+
+ drawstring_aspect(pos, (swap ? subtimer : timer), timer_size, (swap ? subtimer_color : timer_color), panel_fg_alpha, DRAWFLAG_NORMAL);
+
+ if(subtext)
+ drawstring_aspect(pos + eY * timer_size.y, subtext, subtext_size, '0 1 0', panel_fg_alpha, DRAWFLAG_NORMAL);
draw_endBoldFont();
}
bool autocvar_hud_panel_timer;
bool autocvar_hud_panel_timer_dynamichud = true;
bool autocvar_hud_panel_timer_increment;
+int autocvar_hud_panel_timer_secondary = 1;
bool autocvar_hud_panel_timer_unbound;
+
+vector HUD_Timer_Color(float timeleft);
+float HUD_Timer_TimeElapsed(float curtime, float starttime);
+float HUD_Timer_TimeLeft(float curtime, float starttime, float timelimit);
if(intermission && !intermission_time)
intermission_time = time;
+ if(STAT(GAME_STOPPED) && !game_stopped_time)
+ game_stopped_time = time;
+ else if(game_stopped_time && !STAT(GAME_STOPPED))
+ game_stopped_time = 0;
+
if(intermission && !isdemo() && !(calledhooks & HOOK_END))
{
if(calledhooks & HOOK_START)
#endif
float intermission_time;
+float game_stopped_time;
float game_starttime; //point in time when the countdown to game start is over
float round_starttime; //point in time when the countdown to round start is over
int autocvar_leadlimit;
+int overtimes; // overtimes added (-1 = sudden death)
+int timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
+
// TODO: world.qh can't be included here due to circular includes!
#define autocvar_fraglimit cvar("fraglimit")
#define autocvar_fraglimit_override cvar("fraglimit_override")
REGISTER_STAT(SECRETS_FOUND, int, secrets_found)
REGISTER_STAT(RESPAWN_TIME, float)
REGISTER_STAT(ROUNDSTARTTIME, float, round_starttime)
+REGISTER_STAT(OVERTIMES, int, overtimes)
+REGISTER_STAT(TIMEOUT_STATUS, int, timeout_status)
REGISTER_STAT(MONSTERS_TOTAL, int)
REGISTER_STAT(MONSTERS_KILLED, int)
REGISTER_STAT(NADE_BONUS, float)
#ifdef SVQC
#include "physics/movetypes/movetypes.qh"
float warmup_limit;
+float round_limit;
#endif
#ifdef SVQC
REGISTER_STAT(FRAGLIMIT, float, autocvar_fraglimit)
REGISTER_STAT(TIMELIMIT, float, autocvar_timelimit)
REGISTER_STAT(WARMUP_TIMELIMIT, float, warmup_limit)
+REGISTER_STAT(ROUND_TIMELIMIT, float, round_limit)
#ifdef SVQC
float autocvar_sv_wallfriction;
#define autocvar_sv_gravity cvar("sv_gravity")
#include "dialog_hudpanel_timer.qh"
+#include "textslider.qh"
#include "checkbox.qh"
#include "textlabel.qh"
me.TR(me);
me.TDempty(me, 0.2);
me.TD(me, 1, 3.8, e = makeXonoticCheckBox(0, "hud_panel_timer_increment", _("Show elapsed time")));
+ me.TR(me);
+ me.TDempty(me, 0.2);
+ me.TD(me, 1, 1.2, e = makeXonoticTextLabel(0, _("Secondary timer:")));
+ me.TD(me, 1, 2.6, e = makeXonoticTextSlider("hud_panel_timer_secondary"));
+ e.addValue(e, _("Disable"), "0");
+ e.addValue(e, _("Enable"), "1");
+ e.addValue(e, _("Swapped"), "2");
+ e.configureXonoticTextSliderValues(e);
}
float orig_slowmo; // contains the value of autocvar_slowmo so that, after timeout finished, it isn't set to slowmo 1 necessarily
float timeout_time; // contains the time in seconds that the active timeout has left
float timeout_leadtime; // contains the number of seconds left of the leadtime (before the timeout starts)
-float timeout_status; // (values: 0, 1, 2) contains whether a timeout is not active (0), was called but still at leadtime (1) or is active (2)
.float allowed_timeouts; // contains the number of allowed timeouts for each player
.vector lastV_angle; // used when pausing the game in order to force the player to keep his old view angle fixed
// clear overtime, we have to decrease timelimit to its original value again.
if (checkrules_overtimesadded > 0 && g_race_qualifying != 2)
cvar_set("timelimit", ftos(autocvar_timelimit - (checkrules_overtimesadded * autocvar_timelimit_overtime)));
- checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;
+ checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = overtimes = 0;
if(warmup_stage)
game_starttime = time; // Warmup: No countdown in warmup
if(!MapInfo_CheckMap(m))
return "The map you suggested does not support the current game mode.";
cvar_set("nextmap", m);
- cvar_set("timelimit", "-1");
+ cvar_set("_endmatch", "1");
if(mapvote_initialized || alreadychangedlevel)
{
if(DoNextMapOverride(0))
else
{
round_handler_Reset(0);
+ round_starttime = -1; // can't start
}
this.nextthink = time + 1; // canRoundStart every second
}
this.count = fabs(floor(the_count));
this.cnt = this.count + 1;
this.round_timelimit = (the_round_timelimit > 0) ? the_round_timelimit : 0;
+ round_limit = the_round_timelimit;
}
// NOTE: this is only needed because if round_handler spawns at time 1
if (this.count)
if (this.cnt < this.count + 1) this.cnt = this.count + 1;
this.nextthink = next_think;
- round_starttime = (next_think) ? (next_think + this.count) : -1;
+ if (next_think)
+ round_starttime = next_think + this.count;
}
void round_handler_Remove()
*/
void NextLevel()
{
+ cvar_set("_endmatch", "0");
game_stopped = true;
intermission_running = true; // game over
if(!checkrules_suddendeathend)
{
if(autocvar_g_campaign)
+ {
checkrules_suddendeathend = time; // no suddendeath in campaign
+ }
else
+ {
checkrules_suddendeathend = time + 60 * autocvar_timelimit_suddendeath;
+ overtimes = -1;
+ }
if(g_race && !g_race_qualifying)
race_StartCompleting();
}
void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true
{
++checkrules_overtimesadded;
+ overtimes = checkrules_overtimesadded;
//add one more overtime by simply extending the timelimit
cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
leadlimit = 0; // no leadlimit for now
}
- if(timelimit > 0)
- {
- timelimit += game_starttime;
- }
- else if (timelimit < 0)
+ if (autocvar__endmatch || timelimit < 0)
{
// endmatch
NextLevel();
return;
}
+ if(timelimit > 0)
+ timelimit += game_starttime;
+
float wantovertime;
wantovertime = 0;
#include <common/weapons/_all.qh>
bool autocvar__sv_init;
+bool autocvar__endmatch;
bool autocvar_g_use_ammunition;
bool autocvar_g_jetpack;
bool autocvar_g_warmup_allguns;
float checkrules_equality;
float checkrules_suddendeathwarning;
float checkrules_suddendeathend;
-float checkrules_overtimesadded; //how many overtimes have been already added
+int checkrules_overtimesadded; //how many overtimes have been already added
// flag set on worldspawn so that the code knows if it is dedicated or not
bool server_is_dedicated;