]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into develop
authorbones_was_here <bones_was_here@xa.org.au>
Thu, 2 Jun 2022 02:25:34 +0000 (12:25 +1000)
committerbones_was_here <bones_was_here@xa.org.au>
Thu, 2 Jun 2022 02:25:34 +0000 (12:25 +1000)
35 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
gamemodes-server.cfg
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_welcome.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/client.qc
qcsrc/server/command/vote.qc
qcsrc/server/gamelog.qc
qcsrc/server/gamelog.qh
qcsrc/server/items/items.qc
qcsrc/server/mutators/events.qh
qcsrc/server/race.qc
qcsrc/server/scores.qh
qcsrc/server/weapons/spawning.qc
qcsrc/server/weapons/throwing.qc
qcsrc/server/world.qc

index 57b7d581d86c32518742ea381f0ac2e44fcff184..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=0f809ceef84073f0926b08b6d4831f05\r
+    - EXPECT=458e9e611a757c745da05c85a37e576d\r
     - HASH=$(${ENGINE} +timestamps 1 +exec serverbench.cfg\r
       | tee /dev/stderr\r
       | sed -e 's,^\[[^]]*\] ,,'\r
index 5ef01d8a33ff2852c379b282a9adb5baf37317d9..41063ec71c4bb5c14c311f3b208ad893afd82c0d 100644 (file)
@@ -1 +1 @@
-Tue Apr 26 07:23:12 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 5c1fce96b5bd1a5f305892e2cc1a647b77497343..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"
@@ -1227,7 +1228,7 @@ msgstr "Ceci est %s"
 
 #: qcsrc/client/main.qc:1358
 msgid "Your client version is outdated."
-msgstr "Votre version de client est obsolète."
+msgstr "La version de votre client est obsolète."
 
 #: qcsrc/client/main.qc:1359
 msgid "### YOU WON'T BE ABLE TO PLAY ON THIS SERVER ###"
@@ -9674,7 +9675,7 @@ msgid ""
 "help slow GPUs"
 msgstr ""
 "Multiplicateur de taille d'écran ou de fenêtre, permet l'anticrénelage au-"
-"dessus de 1x, peut aider à ralentir les GPUs en-dessous de 1x"
+"dessus de 1x, en-dessous de 1x cela peut aider les petits GPUs"
 
 #: qcsrc/menu/xonotic/dialog_settings_video.qc:90
 msgid "Anisotropy:"
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 ba4812b57afd8bdc4c5da48d31320788f122acb2..483b6ea3fb35ab435171bfaee61e012cfa416011 100644 (file)
@@ -322,7 +322,7 @@ exec ctfscoring-samual.cfg
 // ====================
 set g_cts 0 "CTS: complete the stage"
 set g_cts_selfdamage 1 "0 = disable all selfdamage and falldamage in cts"
-set g_cts_finish_kill_delay 10 "prevent cheating by running back to the start line, and starting out with more speed than otherwise possible"
+set g_cts_finish_kill_delay 2 "kill player this many seconds after stage completion to prevent cheating by starting out with more speed than otherwise possible; set it to 0 to not kill or to -1 to kill instantly"
 set g_cts_send_rankings_cnt 15 "send this number of map records to clients"
 set g_cts_removeprojectiles 0 "remove projectiles when the player dies, to prevent using weapons earlier in the stage than intended"
 
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 4bb2ff9f1c41363749e7cca475bb5ab732c6fe57..40d6cbbc2b6c2d4a93727927645993e04ed7b524 100644 (file)
@@ -1445,6 +1445,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 7183d80c8be432be81153e230e98e58c0f110cdf..530324656373d1346762879984b5473795df5af5 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 3e1444a35f9f28fcc98a16ed8553e042a1777d82..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));
@@ -366,6 +372,7 @@ void PlayerStats_GameReport_Handler(entity fh, entity pass, float status)
                 * i: player index
                 * n: nickname of the player (optional)
                 * t: team ID
+                * r: player ranking enabled / disabled
                 * e: followed by an event name, a space, and the event count/score
                 *  event names can be:
                 *   alivetime: total playing time of the player
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 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 f89cf18a0335c284f531de6a385e0bc5ca346a59..1b308d0940de2bcbcfb0ab9a79bcd4c76d06f5e6 100644 (file)
@@ -1,5 +1,7 @@
 #include "gamelog.qh"
-
+#include <server/intermission.qh>    // GetGametype(), GetMapname()
+#include <server/weapons/tracing.qh> // autocvar_g_norecoil
+#include <server/world.qh>           // matchid
 #include <server/main.qh>
 
 string GameLog_ProcessIP(string s)
@@ -41,8 +43,32 @@ void GameLogEcho(string s)
 
 void GameLogInit()
 {
-       logfile_open = false;
-       // will be opened later
+       GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", matchid));
+       string s = ":gameinfo:mutators:LIST";
+
+       MUTATOR_CALLHOOK(BuildMutatorsString, s);
+       s = M_ARGV(0, string);
+
+       // initialiation stuff, not good in the mutator system
+       if(!autocvar_g_use_ammunition)
+               s = strcat(s, ":no_use_ammunition");
+
+       // initialiation stuff, not good in the mutator system
+       if(autocvar_g_pickup_items == 0)
+               s = strcat(s, ":no_pickup_items");
+       if(autocvar_g_pickup_items > 0)
+               s = strcat(s, ":pickup_items");
+
+       // initialiation stuff, not good in the mutator system
+       if(autocvar_g_weaponarena != "0")
+               s = strcat(s, ":", autocvar_g_weaponarena, " arena");
+
+       // TODO to mutator system
+       if(autocvar_g_norecoil)
+               s = strcat(s, ":norecoil");
+
+       GameLogEcho(s);
+       GameLogEcho(":gameinfo:end");
 }
 
 void GameLogClose()
index f96679b819d62eb36629bbaf9e4f9916320205cc..99ac37c3c762e8803b32634363f321db5da7af69 100644 (file)
@@ -9,7 +9,7 @@ string autocvar_sv_eventlog_files_namesuffix;
 bool autocvar_sv_eventlog_files_timestamps;
 bool autocvar_sv_eventlog_ipv6_delimiter = false;
 
-bool logfile_open;
+bool logfile_open = false;
 float logfile;
 
 string GameLog_ProcessIP(string s);
index ed39c7bca91e11fcb3d11d32f590c737379e0355..99c0165fd3a1b51061979bf4ff3fb384ab3bcdd2 100644 (file)
@@ -1094,7 +1094,6 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
        // support skinned models for powerups
        this.skin = def.m_skin;
-       this.glowmod = def.m_color;
 
        setsize (this, this.pos1 =  def.m_mins, this.pos2 = def.m_maxs);
 
@@ -1110,6 +1109,8 @@ void _StartItem(entity this, entity def, float defaultrespawntime, float default
 
        if(Item_IsLoot(this))
                this.gravity = 1;
+       else
+               this.glowmod = def.m_color;
 
        if(def.instanceOfWeaponPickup)
        {
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 */
index 4ecda0a9a09732b0411f164b1d4e3c175a729005..545bdad27be16a5595e74692fd9fa750cc3fad26 100644 (file)
@@ -502,6 +502,9 @@ void race_SendTime(entity e, float cp, float t, float tvalid)
                        {
                                CS(e).race_completed = 1;
                                MAKE_INDEPENDENT_PLAYER(e);
+                               if(e.bot_attack)
+                                       IL_REMOVE(g_bot_targets, e);
+                               e.bot_attack = false;
                                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_RACE_FINISHED, e.netname);
                                ClientData_Touch(e);
                        }
index 178181cbada248a0ee7e55f5da55b8583d09d6ea..2b6ea4881045808340260607aaabd596032a6a5f 100644 (file)
@@ -88,7 +88,7 @@ void ScoreInfo_SetLabel_PlayerScore(PlayerScoreField i, string label, float scor
  * Initialize the scores info for the given number of teams.
  * Set all labels right before this call.
  */
-void ScoreInfo_Init(float teams);
+void ScoreInfo_Init(int teams);
 
 /**
  * Clear ALL scores (for ready-restart).
index 30a2869f399f42b1887a4d7e626364a3f7b81b4e..6a2d65db2075b19a02a74cbba26adf4f47c8d17b 100644 (file)
@@ -152,6 +152,8 @@ void weapon_defaultspawnfunc(entity this, Weapon wpn)
 
        if(!this.owner)
                this.glowmod = wpn.wpcolor;
+       else
+               this.glowmod = colormapPaletteColor(this.owner.clientcolors & 0x0F, true) * 2;
 
        GameItem def = wpn.m_pickup;
        _StartItem(
index 719b5993590891173a572c25584398b7882de4f5..01c6ac0d200634347c27d88ba2631322b8fb7c66 100644 (file)
@@ -49,7 +49,7 @@ float W_ThrowNewWeapon(entity own, float wpn, float doreduce, vector org, vector
        wep.owner = wep.enemy = own;
        wep.flags |= FL_TOSSED;
        wep.colormap = own.colormap;
-       wep.glowmod = weaponentity_glowmod(info, own, own.clientcolors, own.(weaponentity));
+       // wep.glowmod will be set in weapon_defaultspawnfunc
        navigation_dynamicgoal_init(wep, false);
 
        W_DropEvent(wr_drop,own,wpn,wep,weaponentity);
index fca7c1741497e7a092245ad376744a1b3e4b630a..6c2e4a3f71b906f18242bf69ac8220aab0b6d2ab 100644 (file)
@@ -35,7 +35,6 @@
 #include <server/damage.qh>
 #include <server/gamelog.qh>
 #include <server/hook.qh>
-#include <server/intermission.qh>
 #include <server/ipban.qh>
 #include <server/items/items.qh>
 #include <server/main.qh>
@@ -46,7 +45,6 @@
 #include <server/scores_rules.qh>
 #include <server/spawnpoints.qh>
 #include <server/teamplay.qh>
-#include <server/weapons/common.qh>
 #include <server/weapons/weaponstats.qh>
 
 const float LATENCY_THINKRATE = 10;
@@ -844,46 +842,15 @@ spawnfunc(worldspawn)
 
        WaypointSprite_Init();
 
-       GameLogInit(); // prepare everything
        // NOTE for matchid:
        // changing the logic generating it is okay. But:
        // it HAS to stay <= 64 chars
        // character set: ASCII 33-126 without the following characters: : ; ' " \ $
-       if(autocvar_sv_eventlog)
-       {
-               string num = strftime_s(); // strftime(false, "%s") isn't reliable, see strftime_s description
-               string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), num, floor(random() * 1000000));
-               matchid = strzone(s);
-
-               GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
-               s = ":gameinfo:mutators:LIST";
-
-               MUTATOR_CALLHOOK(BuildMutatorsString, s);
-               s = M_ARGV(0, string);
-
-               // initialiation stuff, not good in the mutator system
-               if(!autocvar_g_use_ammunition)
-                       s = strcat(s, ":no_use_ammunition");
-
-               // initialiation stuff, not good in the mutator system
-               if(autocvar_g_pickup_items == 0)
-                       s = strcat(s, ":no_pickup_items");
-               if(autocvar_g_pickup_items > 0)
-                       s = strcat(s, ":pickup_items");
+       // strftime(false, "%s") isn't reliable, see strftime_s description
+       matchid = strzone(sprintf("%d.%s.%06d", autocvar_sv_eventlog_files_counter, strftime_s(), random() * 1000000));
 
-               // initialiation stuff, not good in the mutator system
-               if(autocvar_g_weaponarena != "0")
-                       s = strcat(s, ":", autocvar_g_weaponarena, " arena");
-
-               // TODO to mutator system
-               if(autocvar_g_norecoil)
-                       s = strcat(s, ":norecoil");
-
-               GameLogEcho(s);
-               GameLogEcho(":gameinfo:end");
-       }
-       else
-               matchid = strzone(ftos(random()));
+       if(autocvar_sv_eventlog)
+               GameLogInit(); // requires matchid to be set
 
        cvar_set("nextmap", "");