Merge branch 'bones_was_here/matchid_eventlog' into 'master'
authorterencehill <piuntn@gmail.com>
Tue, 31 May 2022 11:24:43 +0000 (11:24 +0000)
committerterencehill <piuntn@gmail.com>
Tue, 31 May 2022 11:24:43 +0000 (11:24 +0000)
Always use a monotonic matchid to prevent random rejections by xonstat

See merge request xonotic/xonotic-data.pk3dir!1019

48 files changed:
.gitlab-ci.yml
.tx/merge-base
common.cs.po
common.es.po
common.es_MX.po
common.fr.po
common.it.po
common.kw.po
common.pt.po
common.pt_BR.po
common.tr.po
qcsrc/client/announcer.qc
qcsrc/client/hud/crosshair.qc
qcsrc/client/hud/panel/centerprint.qc
qcsrc/client/hud/panel/scoreboard.qc
qcsrc/client/main.qc
qcsrc/client/view.qc
qcsrc/common/gamemodes/gamemode/assault/sv_assault.qc
qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
qcsrc/common/playerstats.qc
qcsrc/common/weapons/weapon/minelayer.qc
qcsrc/menu/xonotic/dialog_multiplayer_create.qh
qcsrc/menu/xonotic/dialog_multiplayer_join.qh
qcsrc/menu/xonotic/dialog_multiplayer_join_serverinfotab.qh
qcsrc/menu/xonotic/dialog_multiplayer_join_termsofservice.qh
qcsrc/menu/xonotic/dialog_multiplayer_media.qh
qcsrc/menu/xonotic/dialog_multiplayer_media_demo.qh
qcsrc/menu/xonotic/dialog_multiplayer_media_musicplayer.qh
qcsrc/menu/xonotic/dialog_multiplayer_media_screenshot.qh
qcsrc/menu/xonotic/dialog_multiplayer_profile.qh
qcsrc/menu/xonotic/dialog_settings_audio.qh
qcsrc/menu/xonotic/dialog_settings_effects.qh
qcsrc/menu/xonotic/dialog_settings_game.qh
qcsrc/menu/xonotic/dialog_settings_game_crosshair.qh
qcsrc/menu/xonotic/dialog_settings_game_hud.qh
qcsrc/menu/xonotic/dialog_settings_game_messages.qh
qcsrc/menu/xonotic/dialog_settings_game_model.qh
qcsrc/menu/xonotic/dialog_settings_game_view.qh
qcsrc/menu/xonotic/dialog_settings_game_weapons.qh
qcsrc/menu/xonotic/dialog_settings_input.qh
qcsrc/menu/xonotic/dialog_settings_misc.qh
qcsrc/menu/xonotic/dialog_settings_user.qh
qcsrc/menu/xonotic/dialog_settings_video.qh
qcsrc/menu/xonotic/dialog_welcome.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/client.qc
qcsrc/server/command/vote.qc
qcsrc/server/mutators/events.qh

index caf20d12527ad3a08a93669ec63e052c9f305392..87bb7bb07c412caf7368bec7950418fa7f2eb4b2 100644 (file)
@@ -55,7 +55,7 @@ test_sv_game:
     - wget -O data/maps/stormkeep.waypoints https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints\r
     - wget -O data/maps/stormkeep.waypoints.cache https://gitlab.com/xonotic/xonotic-maps.pk3dir/raw/master/maps/stormkeep.waypoints.cache\r
 \r
-    - EXPECT=a728d38448ae86459582804aa10320c0\r
+    - EXPECT=458e9e611a757c745da05c85a37e576d\r
     - HASH=$(${ENGINE} +timestamps 1 +exec serverbench.cfg\r
       | tee /dev/stderr\r
       | sed -e 's,^\[[^]]*\] ,,'\r
index 4d7d48d7f8904c54792c24031b9521c120f15f29..41063ec71c4bb5c14c311f3b208ad893afd82c0d 100644 (file)
@@ -1 +1 @@
-Tue May  3 07:23:14 CEST 2022
+Sat May 28 07:23:08 CEST 2022
index f3b1672ff39ef3fc6dd0fd3e7e219aad83800480..ad3aef2178c0d5b10921796186cffec537237f09 100644 (file)
@@ -7,8 +7,8 @@
 # Adam Říha, 2021
 # Adam Říha, 2021
 # fasdasd sdasd <transifexalternativeaccount@yopmail.com>, 2021
-# gamingforyou875 <gamingforyou875@gmail.com>, 2019
-# gamingforyou875 <gamingforyou875@gmail.com>, 2019
+# GamingasCZ <gamingforyou875@gmail.com>, 2019
+# GamingasCZ <gamingforyou875@gmail.com>, 2019
 # Jan Kocka <kockahonza@gmail.com>, 2019
 # Jiří Vrána <jirkacz199@gmail.com>, 2020-2021
 # Martin Taibr <taibr.martin@gmail.com>, 2017
index 37c0666223f456e6bbd21fe076db243911935134..bc5b944904c7c25a0ed49b23ede8feb298818398 100644 (file)
@@ -40,7 +40,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
+"1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index 5254cde9ec127bbe27dd7fed7f3ba0494ad20049..1b96f5e140545af42efbac54df47b4ff204b3e69 100644 (file)
@@ -16,7 +16,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
+"1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index dfb67da7c8d983588dda57dc557c3d506f9aa88f..a291ce9c8dc13c19cdb1d0f42a15b051403b44b7 100644 (file)
@@ -30,7 +30,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
+"1000000 == 0 ? 1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index e9cb1afa4ae3e32a36df52c3a24bbc28c42e5fcc..962f1a75b55d7c41323de632a3ac7b9eaa3c6509 100644 (file)
@@ -23,7 +23,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? "
+"1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index dc32fd24b65e5592c98f4834492176656a8d4138..679a6c1db416b452510b5124a0becfef92c89bfe 100644 (file)
@@ -19,7 +19,13 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=3; plural=(n == 1 ? 0 : n == 2 ? 1 : 2);\n"
+"Plural-Forms: nplurals=6; plural=n == 0 ? 0 : n == 1 ? 1 : (n % 100 == 2 || "
+"n % 100 == 22 || n % 100 == 42 || n % 100 == 62 || n % 100 == 82) || n % "
+"1000 == 0 && (n % 100000 >= 1000 && n % 100000 <= 20000 || n % 100000 == "
+"40000 || n % 100000 == 60000 || n % 100000 == 80000) || n != 0 && n % "
+"1000000 == 100000 ? 2 : (n % 100 == 3 || n % 100 == 23 || n % 100 == 43 || n "
+"% 100 == 63 || n % 100 == 83) ? 3 : n != 1 && (n % 100 == 1 || n % 100 == 21 "
+"|| n % 100 == 41 || n % 100 == 61 || n % 100 == 81) ? 4 : 5;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index e3c8ef10646b9906c91d72451e98ef3d7bdc8fe0..83aaff5e8466b9e92ee9cb3d18a7ed0eb4b31d26 100644 (file)
@@ -24,7 +24,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
+"1000000 == 0 ? 1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
index f99dbd8b78e8050722eb205de262b872c5ba85a7..65f14f8d39bd5eeccab10d5b2db96f67e4301a47 100644 (file)
@@ -25,7 +25,8 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+"Plural-Forms: nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % "
+"1000000 == 0 ? 1 : 2;\n"
 
 #: qcsrc/client/announcer.qc:45
 msgid "vs"
@@ -4356,7 +4357,7 @@ msgid ""
 "^F2^COUNT^BG until weapon change...\n"
 "Next weapon: ^F1%s"
 msgstr ""
-"^F2^CONTAGEM^BG até a mudança de arma...\n"
+"^F2^COUNT^BG até a mudança de arma...\n"
 "Próxima arma: ^F1%s"
 
 #: qcsrc/common/notifications/all.inc:719
index 187b3ea3de698d635eef120d07ddadcff3ace0e9..2f8e2c97b4e8cb8451b461d616c46f94ee95dcd8 100644 (file)
@@ -6,21 +6,21 @@
 # Abdurrahman AKKUŞ <a.rahmanakkus@hotmail.com>, 2019
 # Ahmet, 2022
 # Ahmet, 2022
-# Big Brother <tanakinci2002@gmail.com>, 2021
+# Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021
 # Çağlar Turalı <caglarturali@gmail.com>, 2018
 # Demiray Muhterem <mdemiray@msn.com>, 2018
-# Big Brother <tanakinci2002@gmail.com>, 2021
+# Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021
 # Gokdeniz.Kucukali, 2021
 # Gokdeniz.Kucukali, 2021
 # ibra kap <ibrakap@gmail.com>, 2019
-# Big Brother <tanakinci2002@gmail.com>, 2021
+# Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021
 msgid ""
 msgstr ""
 "Project-Id-Version: Xonotic\n"
 "Report-Msgid-Bugs-To: \n"
 "POT-Creation-Date: 2022-04-17 07:22+0200\n"
 "PO-Revision-Date: 2013-09-12 16:53+0000\n"
-"Last-Translator: Big Brother <tanakinci2002@gmail.com>, 2021\n"
+"Last-Translator: Tan Siret Akıncı <tanakinci2002@gmail.com>, 2021\n"
 "Language-Team: Turkish (http://www.transifex.com/team-xonotic/xonotic/"
 "language/tr/)\n"
 "Language: tr\n"
index e86702afa086a8314ee12ba92540f605929a6b7d..d46595e8718bde0a2007fb276a6e54ab6b49d7ca 100644 (file)
@@ -53,6 +53,8 @@ void Announcer_ClearTitle()
 }
 
 bool prev_inround;
+float prev_starttime;
+float prev_roundstarttime;
 void Announcer_Countdown(entity this)
 {
        float starttime = STAT(GAMESTARTTIME);
@@ -70,6 +72,9 @@ void Announcer_Countdown(entity this)
        float countdown = (inround ? roundstarttime - time : starttime - time);
        float countdown_rounded = floor(0.5 + countdown);
 
+       if (starttime != prev_starttime || roundstarttime != prev_roundstarttime || prev_inround != inround)
+               this.skin = 0; // restart centerprint countdown
+
        if(countdown <= 0) // countdown has finished, starttime is now
        {
                Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_BEGIN);
@@ -84,7 +89,8 @@ void Announcer_Countdown(entity this)
                if(inround)
                {
                        if(!prev_inround) Announcer_ClearTitle(); // clear title if we just started the match
-                       Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTART, STAT(ROUNDS_PLAYED) + 1, countdown_rounded);
+                       if (!this.skin) // first tic
+                               Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_ROUNDSTART, STAT(ROUNDS_PLAYED) + 1, countdown_rounded);
                        Notification annce_num = Announcer_PickNumber(CNT_ROUNDSTART, countdown_rounded);
                        if(annce_num != NULL)
                                Local_Notification(MSG_ANNCE, annce_num);
@@ -92,15 +98,22 @@ void Announcer_Countdown(entity this)
                }
                else
                {
-                       Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
+                       if (!this.skin) // first tic
+                               Local_Notification(MSG_CENTER, CENTER_COUNTDOWN_GAMESTART, countdown_rounded);
                        Notification annce_num = Announcer_PickNumber(CNT_GAMESTART, countdown_rounded);
                        if(!roundstarttime && annce_num != NULL) // Don't announce game start in round based modes
                                Local_Notification(MSG_ANNCE, annce_num);
                        this.nextthink = (starttime - (countdown - 1));
                }
+               // Don't call centerprint countdown in the remaining tics, it will continue automatically.
+               // It's an optimization but also fixes ^COUNT shown in the last tic because of high slowmo values (15+).
+               // Hopefully it fixes ^COUNT occasionally shown in online servers, probably due to lags.
+               this.skin = 1; // recycled field
        }
 
        prev_inround = inround;
+       prev_starttime = starttime;
+       prev_roundstarttime = roundstarttime;
 }
 
 /**
@@ -119,6 +132,7 @@ void Announcer_Gamestart()
                startTime = roundstarttime;
        if(intermission)
        {
+               Announcer_ClearTitle();
                if(announcer_countdown)
                {
                        centerprint_Kill(ORDINAL(CPID_ROUND));
@@ -216,6 +230,9 @@ void Announcer_Time()
 
 void Announcer()
 {
+       // announcer code sets gametype name as centerprint title
+       if(!gametype)
+               return;
        Announcer_Gamestart();
        Announcer_Time();
 }
index cf2c01d971f134ec41ca51d1e04e175c83c9cf00..229a6024084df01cbabefa97a02de385a558a86a 100644 (file)
@@ -63,9 +63,8 @@ float EnemyHitCheck()
        if(n > maxclients)
                return SHOTTYPE_HITWORLD;
        t = entcs_GetTeam(n - 1);
-       if(teamplay)
-               if(t == myteam)
-                       return SHOTTYPE_HITTEAM;
+       if(teamplay && t == myteam)
+               return SHOTTYPE_HITTEAM;
        if(t == NUM_SPECTATOR)
                return SHOTTYPE_HITWORLD;
        return SHOTTYPE_HITENEMY;
index 1436f2ef6a9d48e8675976e190ee76c542847329..1af0e330147c68176e7a4af911c2037fd18e5adb 100644 (file)
@@ -278,14 +278,14 @@ void HUD_CenterPrint()
                if (centerprint_title_left != "" && align == 0.5) // Center line at the main word (for duels)
                        pos.x += (stringwidth(centerprint_title_right, true, fontsize) - stringwidth(centerprint_title_left, true, fontsize)) / 2;
 
-               drawcolorcodedstring(pos, centerprint_title, fontsize, 1, DRAWFLAG_NORMAL);
+               drawcolorcodedstring(pos, centerprint_title, fontsize, panel_fg_alpha, DRAWFLAG_NORMAL);
 
                if (autocvar_hud_panel_centerprint_flip)
                        pos.y -= cp_fontsize.y * CENTERPRINT_TITLE_SPACING;
                else
                        pos.y += fontsize.y + (hud_fontsize.y * CENTERPRINT_TITLE_SPACING);
 
-               drawfill(pos, vec2(width, 1), '1 1 1', 1, DRAWFLAG_NORMAL);
+               drawfill(pos, vec2(width, 1), '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
 
                if (autocvar_hud_panel_centerprint_flip)
                        pos.y -= cp_fontsize.y * CENTERPRINT_TITLE_SPACING;
index ed8715e022909cd1545784a29c222d3d1d130c92..0d0a44b6a295f839a7516ac210f96a685edee8bc 100644 (file)
@@ -2110,8 +2110,7 @@ void Scoreboard_Draw()
 
        // print information about respawn status
        float respawn_time = STAT(RESPAWN_TIME);
-       if(!intermission)
-       if(respawn_time)
+       if(!intermission && respawn_time)
        {
                if(respawn_time < 0)
                {
index 8bd5d78638c1fc607fd379d7d1b20d82d0b52ca9..091cc466183efecd96bda5291383c2aab720acda 100644 (file)
@@ -1438,6 +1438,8 @@ void Welcome_Message_Show_Try()
                        string msg = MakeConsoleSafe(strreplace("\n", "\\n", welcome_msg));
                        welcomedialog_args = strcat(welcomedialog_args, " WELCOME \"", msg, "\"");
                        localcmd("\nmenu_cmd directmenu Welcome ", welcomedialog_args, "\n");
+                       if (intermission) // close it after it's been initialized so it can still be opened manually
+                               localcmd("\ntogglemenu 0\n");
                }
                else
                        centerprint_Add(ORDINAL(CPID_MOTD), strcat(hostname, "\n\n\n", welcome_msg), -1, 0);
index 855d20f818fbf7d04028cd255ec5067f42ab25f8..a183c82d0ad04e2482cf522e73b94399d596cffd 100644 (file)
@@ -868,41 +868,46 @@ void HUD_Draw(entity this)
        Hud_Dynamic_Frame();
 
        if(!intermission)
-       if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
        {
-               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), M_ARGV(0, vector), autocvar_hud_colorflash_alpha * M_ARGV(1, float), DRAWFLAG_ADDITIVE);
-       }
-       else if(STAT(FROZEN))
-       {
-               vector col = '0.25 0.90 1';
-               float col_fade = max(0, STAT(REVIVE_PROGRESS) * 2 - 1);
-               float alpha_fade = 0.3 + 0.7 * (1 - max(0, STAT(REVIVE_PROGRESS) * 4 - 3));
-               if(col_fade)
-                       col += vec3(col_fade, -col_fade, -col_fade);
-               drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha * alpha_fade, DRAWFLAG_ADDITIVE);
+               if (MUTATOR_CALLHOOK(HUD_Draw_overlay))
+               {
+                       drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), M_ARGV(0, vector), autocvar_hud_colorflash_alpha * M_ARGV(1, float), DRAWFLAG_ADDITIVE);
+               }
+               else if(STAT(FROZEN))
+               {
+                       vector col = '0.25 0.90 1';
+                       float col_fade = max(0, STAT(REVIVE_PROGRESS) * 2 - 1);
+                       float alpha_fade = 0.3 + 0.7 * (1 - max(0, STAT(REVIVE_PROGRESS) * 4 - 3));
+                       if(col_fade)
+                               col += vec3(col_fade, -col_fade, -col_fade);
+                       drawfill('0 0 0', vec2(vid_conwidth, vid_conheight), col, autocvar_hud_colorflash_alpha * alpha_fade, DRAWFLAG_ADDITIVE);
+               }
        }
 
        HUD_Scale_Enable();
        if(!intermission)
-       if(STAT(NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
-       {
-               vector col = '0.25 0.90 1' + vec3(STAT(NADE_TIMER), -STAT(NADE_TIMER), -STAT(NADE_TIMER));
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(NADE_TIMER), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-               drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
-       }
-       else if(STAT(CAPTURE_PROGRESS))
-       {
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(CAPTURE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-               drawstring_aspect(eY * 0.64 * vid_conheight, _("Capture progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
-       }
-       else if(STAT(REVIVE_PROGRESS))
        {
-               DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
-               drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
+               if(STAT(NADE_TIMER) && autocvar_cl_nade_timer) // give nade top priority, as it's a matter of life and death
+               {
+                       vector col = '0.25 0.90 1' + vec3(STAT(NADE_TIMER), -STAT(NADE_TIMER), -STAT(NADE_TIMER));
+                       DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(NADE_TIMER), col, autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+                       drawstring_aspect(eY * 0.64 * vid_conheight, ((autocvar_cl_nade_timer == 2) ? _("Nade timer") : ""), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
+               }
+               else if(STAT(CAPTURE_PROGRESS))
+               {
+                       DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(CAPTURE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+                       drawstring_aspect(eY * 0.64 * vid_conheight, _("Capture progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
+               }
+               else if(STAT(REVIVE_PROGRESS))
+               {
+                       DrawCircleClippedPic(vec2(0.5 * vid_conwidth, 0.6 * vid_conheight), 0.1 * vid_conheight, "gfx/crosshair_ring", STAT(REVIVE_PROGRESS), '0.25 0.90 1', autocvar_hud_colorflash_alpha, DRAWFLAG_ADDITIVE);
+                       drawstring_aspect(eY * 0.64 * vid_conheight, _("Revival progress"), vec2(vid_conwidth, 0.025 * vid_conheight), '1 1 1', 1, DRAWFLAG_NORMAL);
+               }
        }
        HUD_Scale_Disable();
 
        if(autocvar_r_letterbox == 0)
+       {
                if(autocvar_viewsize < 120)
                {
                        if(!MUTATOR_CALLHOOK(DrawScoreboardAccuracy))
@@ -911,6 +916,7 @@ void HUD_Draw(entity this)
                        HUD_Main();
                        HUD_Scale_Disable();
                }
+       }
 
        // crosshair goes VERY LAST
        UpdateDamage();
index 5edfd5ff1863362ecaf53354431793598c11e228..e9fb0a48dea9b2988e4bf22135d457b143a65d22 100644 (file)
@@ -255,7 +255,7 @@ int WinningCondition_Assault()
 
                        TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
 
-                       if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round
+                       if(ent.cnt == 1 || autocvar_g_campaign) // this was the second round or the only round in campaign
                        {
                                status = WINNING_YES;
                        }
@@ -630,5 +630,8 @@ MUTATOR_HOOKFUNCTION(as, OnEntityPreSpawn)
 MUTATOR_HOOKFUNCTION(as, ReadyRestart_Deny)
 {
        // readyrestart not supported (yet)
+       // it's supported only in campaign mode (single round mode), since campaign requires it
+       if (autocvar_g_campaign)
+               return false;
        return true;
 }
index 3b823dfdf14c8142fb041c16b27f40cd6cc481fe..7803108c6c00010cb896fce7fde81da0fbfebc00 100644 (file)
@@ -194,12 +194,7 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_players)
 {
        FOREACH_CLIENT(true, {
                CS(it).killcount = 0;
-               if (!INGAME(it) && IS_BOT_CLIENT(it))
-               {
-                       it.team = -1;
-                       INGAME_STATUS_SET(it, INGAME_STATUS_JOINED);
-               }
-               if (INGAME(it))
+               if (INGAME(it) || IS_BOT_CLIENT(it))
                {
                        TRANSMUTE(Player, it);
                        INGAME_STATUS_SET(it, INGAME_STATUS_JOINED);
index f8aa2b514059884b5ed43020a06740ece5a6fc37..e83305886cee1522ddbb5b8db4c11388ee59e0e7 100644 (file)
@@ -207,7 +207,13 @@ void PlayerStats_GameReport_FinalizePlayer(entity p)
                {
                        float latency = max(0, CS(p).latency_sum / CS(p).latency_cnt);
                        if(latency)
-                               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, latency);
+                       {
+                               // if previous average latency exists (player disconnected and reconnected)
+                               // make the average of previous and current average latency
+                               float prev_latency = PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, 0);
+                               float new_latency = !prev_latency ? latency : (prev_latency + latency) / 2;
+                               PlayerStats_GameReport_Event_Player(p, PLAYERSTATS_AVGLATENCY, -prev_latency + new_latency);
+                       }
                }
 
                db_put(PS_GR_OUT_DB, sprintf("%s:_ranked", p.playerstats_id), ftos(CS_CVAR(p).cvar_cl_allow_uidranking));
index f25859e0532983b1b1fbf7c9605f8f902fcde27d..8a8d4839cd4c307a6f62a418884abf551569fc92 100644 (file)
@@ -192,7 +192,7 @@ void W_MineLayer_Think(entity this)
        head = findradius(this.origin, WEP_CVAR(minelayer, proximityradius));
        while(head)
        {
-               if(IS_PLAYER(head) && !IS_DEAD(head) && !STAT(FROZEN, head))
+               if(IS_PLAYER(head) && !IS_DEAD(head) && !STAT(FROZEN, head) && !IS_INDEPENDENT_PLAYER(head))
                if(head != this.realowner && DIFF_TEAM(head, this.realowner)) // don't trigger for team mates
                if(!this.mine_time)
                {
index b6aee3a43f8259774915525877659fba631ff168..e275522864a84ee9af820e0cb6f55f7323df9efb 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticServerCreateTab, XonoticTab)
        METHOD(XonoticServerCreateTab, fill, void(entity));
        METHOD(XonoticServerCreateTab, gameTypeChangeNotify, void(entity));
        METHOD(XonoticServerCreateTab, gameTypeSelectNotify, void(entity));
+       ATTRIB(XonoticServerCreateTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticServerCreateTab, rows, float, 23);
        ATTRIB(XonoticServerCreateTab, columns, float, 6.2);  // added extra .2 for center space
 
index 1769597e03a8b4134d1328eff2d3e77a1e0656fe..38744f366de85800ac7693ebd6bf4b4afba93006 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticServerListTab, XonoticTab)
        METHOD(XonoticServerListTab, fill, void(entity));
+       ATTRIB(XonoticServerListTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticServerListTab, rows, float, 23);
        ATTRIB(XonoticServerListTab, columns, float, 6.5);
 
index 0cd2ec6371da84e236ad362c7fe134a410dc0876..ed3515f99d81566c64d5952576a4aa830833ddb6 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticServerInfoTab, XonoticTab)
        METHOD(XonoticServerInfoTab, fill, void(entity));
        ATTRIB(XonoticServerInfoTab, title, string, _("Server Information"));
        ATTRIB(XonoticServerInfoTab, color, vector, SKINCOLOR_DIALOG_SERVERINFO);
+       ATTRIB(XonoticServerInfoTab, intendedWidth, float, 0.8);
        ATTRIB(XonoticServerInfoTab, rows, float, 17);
        ATTRIB(XonoticServerInfoTab, columns, float, 6.2);
 
index 0cbdcb1f53363887e2eac3d2937107cbf04c7b17..ebc2d867e0d1740201354b716b8ea8daf9069620 100644 (file)
@@ -6,6 +6,7 @@ CLASS(XonoticServerToSTab, XonoticTab)
        METHOD(XonoticServerToSTab, loadToS, void(entity, string));
        ATTRIB(XonoticServerToSTab, title, string, _("Terms of Service"));
        ATTRIB(XonoticServerToSTab, color, vector, SKINCOLOR_DIALOG_SERVERINFO);
+       ATTRIB(XonoticServerToSTab, intendedWidth, float, 0.8);
        ATTRIB(XonoticServerToSTab, rows, float, 17);
        ATTRIB(XonoticServerToSTab, columns, float, 6.2);
 
index c6ecfb518899ab3e6143df8b83bfa62d658c54b1..9713e82c2da595fc6833dc287021a00cae5f7f00 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticMediaTab, XonoticTab)
        METHOD(XonoticMediaTab, fill, void(entity));
+       ATTRIB(XonoticMediaTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticMediaTab, rows, float, 23);
        ATTRIB(XonoticMediaTab, columns, float, 3);
        ATTRIB(XonoticMediaTab, name, string, "Media");
index b90f4b8703317f9ba7bf589a9b61ceb75c96e10c..cf3548d77409e791fecf40d9bf1caec2cab8371d 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticDemoBrowserTab, XonoticTab)
        METHOD(XonoticDemoBrowserTab, fill, void(entity));
+       ATTRIB(XonoticDemoBrowserTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticDemoBrowserTab, rows, float, 21);
        ATTRIB(XonoticDemoBrowserTab, columns, float, 6.5);
        ATTRIB(XonoticDemoBrowserTab, name, string, "DemoBrowser");
index e13e239920459d1b5c60e353bf735d7e9e2c1a08..6172dae03cbff4bffadab55e694ab68fd9859c72 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticMusicPlayerTab, XonoticTab)
        METHOD(XonoticMusicPlayerTab, fill, void(entity));
+       ATTRIB(XonoticMusicPlayerTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticMusicPlayerTab, rows, float, 21);
        ATTRIB(XonoticMusicPlayerTab, columns, float, 6.5);
        ATTRIB(XonoticMusicPlayerTab, name, string, "MusicPlayer");
index 3bc3dcfeb855a3e8dd3abe86979316b86c1ab352..66dc3cf077fac5591b20881fcb52d70cf53b8575 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticScreenshotBrowserTab, XonoticTab)
        METHOD(XonoticScreenshotBrowserTab, fill, void(entity));
+       ATTRIB(XonoticScreenshotBrowserTab, intendedWidth, float, 1);
        ATTRIB(XonoticScreenshotBrowserTab, rows, float, 21);
        ATTRIB(XonoticScreenshotBrowserTab, columns, float, 6.5);
        ATTRIB(XonoticScreenshotBrowserTab, name, string, "ScreenshotBrowser");
index e0ff5a3503452fd67382e388d4a132b1ab791b63..f346aaf66672c0e26de8537a47dee05be6a63bf7 100644 (file)
@@ -4,6 +4,7 @@
 CLASS(XonoticProfileTab, XonoticTab)
        METHOD(XonoticProfileTab, fill, void(entity));
        METHOD(XonoticProfileTab, draw, void(entity));
+       ATTRIB(XonoticProfileTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticProfileTab, rows, float, 23);
        ATTRIB(XonoticProfileTab, columns, float, 6.1);  // added extra .2 for center space
        ATTRIB(XonoticProfileTab, playerNameLabel, entity);
index 0eaff98588517a69114635afef1a6c2c72404d99..5794a70ccfb8e1852b59dc15b226d24fbdf846e0 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticAudioSettingsTab, XonoticTab)
        METHOD(XonoticAudioSettingsTab, fill, void(entity));
+       ATTRIB(XonoticAudioSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticAudioSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticAudioSettingsTab, columns, float, 6.2);  // added extra .2 for center space
        ATTRIB(XonoticAudioSettingsTab, hiddenMenuSoundsSlider, entity);
index 7a99a140663e2cd98b531b9a48836c4df24e7f4a..369c68d9132932d434315e3b630098b57807fbfb 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticEffectsSettingsTab, XonoticTab)
        METHOD(XonoticEffectsSettingsTab, fill, void(entity));
+       ATTRIB(XonoticEffectsSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticEffectsSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticEffectsSettingsTab, columns, float, 6.2);  // added extra .2 for center space
 ENDCLASS(XonoticEffectsSettingsTab)
index 0f3ae81489ea643196e20feb68249c5d6df72a39..c0965c23249470b0e686ddbcb68822abecc1b2b1 100644 (file)
@@ -34,6 +34,7 @@ ENDCLASS(XonoticRegisteredSettingsList)
 #include "tab.qh"
 #include "scrollpanel.qh"
 CLASS(XonoticGameSettingsTab, XonoticTab)
+       ATTRIB(XonoticGameSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameSettingsTab, columns, float, 6.5);
        ATTRIB(XonoticGameSettingsTab, source, DataSource, NEW(SettingSource));
index ed15b1e0bc106f737dc69afbb8f9bcd4825f08f2..33576a3ec0a3ffdd0a5bd5ce7f59f4b07afb51fa 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticGameCrosshairSettingsTab, XonoticTab)
        METHOD(XonoticGameCrosshairSettingsTab, fill, void(entity));
        METHOD(XonoticGameCrosshairSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameCrosshairSettingsTab, title, string, _("Crosshair"));
+       ATTRIB(XonoticGameCrosshairSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameCrosshairSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameCrosshairSettingsTab, columns, float, 6.2);
 ENDCLASS(XonoticGameCrosshairSettingsTab)
index 108b09d4a21420c01f0b3d691f35b26020e20b56..a9851dc63414255e95a64b301797ee9c8d9c0462 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticGameHUDSettingsTab, XonoticTab)
        METHOD(XonoticGameHUDSettingsTab, fill, void(entity));
        METHOD(XonoticGameHUDSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameHUDSettingsTab, title, string, _("HUD"));
+       ATTRIB(XonoticGameHUDSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameHUDSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameHUDSettingsTab, columns, float, 6.2);
 ENDCLASS(XonoticGameHUDSettingsTab)
index c5230aeddb3419ad64fcff1f941642b05e3c9d1f..28a7698626368175b407ae3b2e2accc7c26084e8 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticGameMessageSettingsTab, XonoticTab)
        METHOD(XonoticGameMessageSettingsTab, fill, void(entity));
        METHOD(XonoticGameMessageSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameMessageSettingsTab, title, string, _("Messages"));
+       ATTRIB(XonoticGameMessageSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameMessageSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameMessageSettingsTab, columns, float, 6);
        ATTRIB(XonoticGameMessageSettingsTab, weaponsList, entity);
index 04240353a899047e42aa2eacc98a8d986b335bb4..c3caabee724b3f4a4c7bc620a0e09f1e7f55d93b 100644 (file)
@@ -6,6 +6,7 @@ CLASS(XonoticGameModelSettingsTab, XonoticTab)
        METHOD(XonoticGameModelSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameModelSettingsTab, title, string, _("Models"));
        ATTRIB(XonoticGameModelSettingsTab, titleTooltip, string, _("Customize how players and items are displayed in game"));
+       ATTRIB(XonoticGameModelSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameModelSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameModelSettingsTab, columns, float, 5);
 ENDCLASS(XonoticGameModelSettingsTab)
index c7d1f23b1633c1f066a27b00e7e72ceb608d60ce..f9d6001199b740f6555230112c19fd616fc22971 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticGameViewSettingsTab, XonoticTab)
        METHOD(XonoticGameViewSettingsTab, fill, void(entity));
        METHOD(XonoticGameViewSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameViewSettingsTab, title, string, _("View"));
+       ATTRIB(XonoticGameViewSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameViewSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameViewSettingsTab, columns, float, 6.2);
 ENDCLASS(XonoticGameViewSettingsTab)
index b61d442b1784f5ecf09e90c3e7743262810caefe..ded41a5abdeb25963cccdef129ba591642df879a 100644 (file)
@@ -5,6 +5,7 @@ CLASS(XonoticGameWeaponsSettingsTab, XonoticTab)
        METHOD(XonoticGameWeaponsSettingsTab, fill, void(entity));
        METHOD(XonoticGameWeaponsSettingsTab, showNotify, void(entity));
        ATTRIB(XonoticGameWeaponsSettingsTab, title, string, _("Weapons"));
+       ATTRIB(XonoticGameWeaponsSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticGameWeaponsSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticGameWeaponsSettingsTab, columns, float, 6);
        ATTRIB(XonoticGameWeaponsSettingsTab, weaponsList, entity);
index 5064de9ebbe7bbb9c37a70878d0e7a54f41353c9..13e56afbb5bf751ce2436e4241d903c4ba0248c3 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticInputSettingsTab, XonoticTab)
        METHOD(XonoticInputSettingsTab, fill, void(entity));
+       ATTRIB(XonoticInputSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticInputSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticInputSettingsTab, columns, float, 6.2);  // added extra .2 for center space
        ATTRIB(XonoticInputSettingsTab, name, string, "inputsettings");
index 2146bebd74c0411036cc66b58b1f670070a7698f..a2a86b7e1fb956adbbb750f090168cbe8df3650d 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticMiscSettingsTab, XonoticTab)
        METHOD(XonoticMiscSettingsTab, fill, void(entity));
+       ATTRIB(XonoticMiscSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticMiscSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticMiscSettingsTab, columns, float, 6.2);
 ENDCLASS(XonoticMiscSettingsTab)
index f1ba31a148f7a0b86b7421ff00105ff1b55fd63f..22f84d0f0b7c024b5247f17a28c46efa9848bfab 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticUserSettingsTab, XonoticTab)
        METHOD(XonoticUserSettingsTab, fill, void(entity));
+       ATTRIB(XonoticUserSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticUserSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticUserSettingsTab, columns, float, 6);
 ENDCLASS(XonoticUserSettingsTab)
index 2c6fe0a88e91a82fe15dc649723ebedd44730d64..61d8a368e0e67edd06003e6b6966fb9525f298fa 100644 (file)
@@ -3,6 +3,7 @@
 #include "tab.qh"
 CLASS(XonoticVideoSettingsTab, XonoticTab)
        METHOD(XonoticVideoSettingsTab, fill, void(entity));
+       ATTRIB(XonoticVideoSettingsTab, intendedWidth, float, 0.9);
        ATTRIB(XonoticVideoSettingsTab, rows, float, 15.5);
        ATTRIB(XonoticVideoSettingsTab, columns, float, 6.2);  // added extra .2 for center space
        ATTRIB(XonoticVideoSettingsTab, name, string, "videosettings");
index ca80ef4dd780241e2c971810972628fd7a60a979..5da6f8b1ea9a0bb30aba0786c0bba645f59f2d3b 100644 (file)
@@ -71,6 +71,10 @@ void XonoticWelcomeDialog_readInputArgs(entity me, int argsbuf)
 void XonoticWelcomeDialog_draw(entity me)
 {
        SUPER(XonoticWelcomeDialog).draw(me);
+
+       if (!(gamestatus & (GAME_ISSERVER | GAME_CONNECTED)))
+               me.close(me);
+
        if(me.serverinfo_MOTD == "" && gamestatus & (GAME_CONNECTED | GAME_ISSERVER))
        {
                // if serverinfo_MOTD is empty while connected it means we are connected to an old server
index d9585768d9fc2f7a606582d4566f67e642d119ce..79b3a96924754bf066ef762b7d602c03faa9ca8b 100644 (file)
@@ -243,7 +243,11 @@ void bot_setnameandstuff(entity this)
        else bot_pants = ftos(floor(random() * 15));
 
        if (teamplay && !(autocvar_bot_vs_human && AvailableTeams() == 2))
+       {
                this.bot_forced_team = stof(argv(5));
+               if (!Team_IsValidIndex(this.bot_forced_team))
+                       this.bot_forced_team = 0;
+       }
        else
                this.bot_forced_team = 0;
 
@@ -448,16 +452,6 @@ void bot_clientconnect(entity this)
                bot_setclientfields(this);
        }
 
-       if (teamplay && Team_IsValidIndex(this.bot_forced_team))
-       {
-               SetPlayerTeam(this, this.bot_forced_team, TEAM_CHANGE_MANUAL);
-       }
-       else
-       {
-               this.bot_forced_team = 0;
-               TeamBalance_JoinBestTeam(this);
-       }
-
        havocbot_setupbot(this);
 }
 
@@ -687,6 +681,7 @@ void bot_serverframe()
        // spectators in the scoreboard and never go away. This issue happens at time 2 if map is changed
        // with the gotomap command, minplayers is > 1 and human clients join as players very soon
        // either intentionally or automatically (sv_spectate 0)
+       // A working workaround for this bug was implemented in commit fbd145044, see entcs_attach
        if (time < 2.5)
        {
                currentbots = -1;
index cab642e67fd9b0f8e65a3eafedb54800e8cc3927..2e6e9e6b852c84a6b6ffe5bec87524fb59e6a260 100644 (file)
@@ -540,6 +540,9 @@ void PutPlayerInServer(entity this)
        PlayerState_attach(this);
        accuracy_resend(this);
 
+       if (teamplay && this.bot_forced_team)
+               SetPlayerTeam(this, this.bot_forced_team, TEAM_CHANGE_MANUAL);
+
        if (this.team < 0)
                TeamBalance_JoinBestTeam(this);
 
@@ -810,9 +813,7 @@ void PutPlayerInServer(entity this)
 /** Called when a client spawns in the server */
 void PutClientInServer(entity this)
 {
-       if (IS_BOT_CLIENT(this)) {
-               TRANSMUTE(Player, this);
-       } else if (IS_REAL_CLIENT(this)) {
+       if (IS_REAL_CLIENT(this)) {
                msg_entity = this;
                WriteByte(MSG_ONE, SVC_SETVIEW);
                WriteEntity(MSG_ONE, this);
@@ -2269,6 +2270,14 @@ void ObserverOrSpectatorThink(entity this)
                }
        }
 
+       if (IS_BOT_CLIENT(this) && !CS(this).autojoin_checked)
+       {
+               CS(this).autojoin_checked = true;
+               TRANSMUTE(Player, this);
+               PutClientInServer(this);
+               return;
+       }
+
        if (this.flags & FL_JUMPRELEASED) {
                if (PHYS_INPUT_BUTTON_JUMP(this) && (joinAllowed(this) || time < CS(this).jointime + MIN_SPEC_TIME)) {
                        this.flags &= ~FL_JUMPRELEASED;
index 01758efe5e4630e357962b9e9b65b330cb740480..12e130c9e80ddf25aa17ba4da4583762ddcb95bd 100644 (file)
@@ -486,7 +486,13 @@ void ReadyRestart_force(bool is_fake_round_start)
 
 void ReadyRestart(bool forceWarmupEnd)
 {
-       if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || intermission_running || race_completing) localcmd("restart\n");
+       if (MUTATOR_CALLHOOK(ReadyRestart_Deny) || intermission_running || race_completing)
+       {
+               // NOTE: ReadyRestart support is mandatory in campaign
+               if (autocvar_g_campaign)
+                       error("ReadyRestart must be supported in campaign mode!");
+               localcmd("restart\n"); // if ReadyRestart is denied, restart the server
+       }
        else localcmd("\nsv_hook_readyrestart\n");
 
        if(forceWarmupEnd || autocvar_g_campaign)
index 6feb8113233dd0280b964a3b7f7e0687a324b89a..e7f9f897b0fdce206ccae04312aad6bbe17092b1 100644 (file)
@@ -1153,7 +1153,10 @@ MUTATOR_HOOKABLE(ChatMessage, EV_ChatMessage);
     /**/
 MUTATOR_HOOKABLE(ChatMessageTo, EV_ChatMessageTo);
 
-/** return true to just restart the match, for modes that don't support readyrestart */
+/**
+ * return true to restart the server instead of restarting the match, for modes that don't support readyrestart.
+ * NOTE: ReadyRestart support is mandatory in campaign
+ */
 MUTATOR_HOOKABLE(ReadyRestart_Deny, EV_NO_ARGS);
 
 /** called when a fusion reactor is validating its target */