]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'terencehill/gameover_stuff' into 'master'
authorMario <zacjardine@y7mail.com>
Sat, 10 Dec 2016 06:13:34 +0000 (06:13 +0000)
committerMario <zacjardine@y7mail.com>
Sat, 10 Dec 2016 06:13:34 +0000 (06:13 +0000)
gameover stuff

* Assault: when the first round ends show the message "Objective destroyed in X minutes" and block the game for 5 seconds before starting the other round in order to show objective destruction
* When a round ends block players and switch to 3rd person view (affected game types: Clan Arena, Domination, Freeze Tag, Invasion, Onslaught)

Implementation details:
* intermission_running and gameover are now 2 different conditions
* if set gameover has the effect of blocking players and triggering 3rd person view (eventchase); server must reset (respawn) players and vehicles (round_handler takes care of it) when resetting gameover to false.

See merge request !368

24 files changed:
notifications.cfg
qcsrc/client/defs.qh
qcsrc/client/hud/panel/timer.qc
qcsrc/client/view.qc
qcsrc/common/mutators/mutator/nix/sv_nix.qc
qcsrc/common/mutators/mutator/overkill/sv_overkill.qc
qcsrc/common/notifications/all.inc
qcsrc/common/stats.qh
qcsrc/common/vehicles/vehicle/bumblebee.qc
qcsrc/common/vehicles/vehicle/racer.qc
qcsrc/common/vehicles/vehicle/raptor.qc
qcsrc/common/vehicles/vehicle/spiderbot.qc
qcsrc/server/bot/default/bot.qc
qcsrc/server/client.qc
qcsrc/server/command/vote.qc
qcsrc/server/defs.qh
qcsrc/server/g_hook.qc
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/mutator/gamemode_assault.qc
qcsrc/server/mutators/mutator/gamemode_keyhunt.qc
qcsrc/server/player.qc
qcsrc/server/round_handler.qc
qcsrc/server/weapons/weaponsystem.qc

index 8583592b9acb74d11d24b8125b9b9caac23f0177..8ca401bb423f43be3e960a9b23cd2215f889ed9a 100644 (file)
@@ -424,10 +424,11 @@ seta notification_INFO_WEAPON_TUBA_SUICIDE "1" "0 = off, 1 = print to console, 2
 seta notification_INFO_WEAPON_VAPORIZER_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 seta notification_INFO_WEAPON_VORTEX_MURDER "1" "0 = off, 1 = print to console, 2 = print to console and chatbox (if notification_allow_chatboxprint is enabled)"
 
-// MSG_CENTER notifications (count = 230):
+// MSG_CENTER notifications (count = 231):
 seta notification_CENTER_ALONE "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ASSAULT_ATTACKING "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_ASSAULT_DEFENDING "1" "0 = off, 1 = centerprint"
+seta notification_CENTER_ASSAULT_OBJ_DESTROYED "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_CAMPCHECK "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_COINTOSS "1" "0 = off, 1 = centerprint"
 seta notification_CENTER_COUNTDOWN_BEGIN "1" "0 = off, 1 = centerprint"
@@ -886,4 +887,4 @@ seta notification_show_sprees_info "3" "Show spree information in MSG_INFO messa
 seta notification_show_sprees_info_newline "1" "Show attacker spree information for MSG_INFO messages on a separate line than the death notification itself"
 seta notification_show_sprees_info_specialonly "1" "Don't show attacker spree information in MSG_INFO messages if it isn't an achievement"
 
-// Notification counts (total = 820): MSG_ANNCE = 89, MSG_INFO = 320, MSG_CENTER = 230, MSG_MULTI = 153, MSG_CHOICE = 28
+// Notification counts (total = 821): MSG_ANNCE = 89, MSG_INFO = 320, MSG_CENTER = 231, MSG_MULTI = 153, MSG_CHOICE = 28
index 437e1dd75bab5538dc80c311102adcb7719a8ebd..309ed1d81572998098dcc40fdaad24ae72df6ba1 100644 (file)
@@ -120,7 +120,7 @@ int serverflags;
 
 float uid2name_dialog;
 
-float gameover_time;
+float intermission_time;
 
 .bool csqcmodel_isdead; // used by shownames and miscfunctions (entcs_IsDead) to know when a player is dead
 
index fab0392dc08938d19dd27046faf608e9f1241931..45f46b4087ad35da1c4cff70aabe9799a40463f6 100644 (file)
@@ -50,15 +50,15 @@ void HUD_Timer()
        }
 
        vector timer_color;
-       if(gameover_time || minutesLeft >= 5 || warmup_stage || timelimit == 0)
+       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
        else
                timer_color = '1 0 0'; //red
 
-       if (gameover_time) {
-               timer = seconds_tostring(max(0, floor(gameover_time - STAT(GAMESTARTTIME))));
+       if (intermission_time) {
+               timer = seconds_tostring(max(0, floor(intermission_time - STAT(GAMESTARTTIME))));
        } else if (autocvar_hud_panel_timer_increment || (!warmup_stage && timelimit == 0) || (warmup_stage && warmup_timeleft <= 0)) {
                if (time < STAT(GAMESTARTTIME))
                        timer = seconds_tostring(0); //while restart is still active, show 00:00
index 2ca531166a936555ce61bde93b471579ed3a9a10..5f88e78edf4b13bcc8702fc030edb6f22cc1d8ac 100644 (file)
@@ -747,7 +747,7 @@ bool WantEventchase(entity this)
 {
        if(autocvar_cl_orthoview)
                return false;
-       if(intermission)
+       if(STAT(GAMEOVER) || intermission)
                return true;
        if(this.viewloc)
                return true;
@@ -940,7 +940,7 @@ void HUD_Crosshair(entity this)
 {
        float f, i, j;
        vector v;
-       if(!scoreboard_active && !camera_active && intermission != 2 &&
+       if(!scoreboard_active && !camera_active && intermission != 2 && !STAT(GAMEOVER) &&
                spectatee_status != -1 && !csqcplayer.viewloc && !MUTATOR_CALLHOOK(DrawCrosshair) &&
                !HUD_MinigameMenu_IsOpened() )
        {
@@ -1748,8 +1748,8 @@ void CSQC_UpdateView(entity this, float w, float h)
        if(!postinit)
                PostInit();
 
-       if(intermission && !gameover_time)
-               gameover_time = time;
+       if(intermission && !intermission_time)
+               intermission_time = time;
 
        if(intermission && !isdemo() && !(calledhooks & HOOK_END))
        {
index 143b3c6edf63200089fd825c41508f636a18905a..76e735e5505b482a34df8cd32d09847a6a21b58b 100644 (file)
@@ -256,7 +256,7 @@ MUTATOR_HOOKFUNCTION(nix, PlayerPreThink)
 {
        entity player = M_ARGV(0, entity);
 
-       if(!intermission_running)
+       if(!gameover)
        if(!IS_DEAD(player))
        if(IS_PLAYER(player))
                NIX_GiveCurrentWeapon(player);
index 21a191a0e67c82b080d962ec034fa668fa997324..9b00c44cfcd1d1b4cf72e067657b4cbbba44ee04 100644 (file)
@@ -164,7 +164,7 @@ MUTATOR_HOOKFUNCTION(ok, ForbidThrowCurrentWeapon)
 
 MUTATOR_HOOKFUNCTION(ok, PlayerPreThink)
 {
-       if(intermission_running || gameover)
+       if(gameover)
                return;
 
        entity player = M_ARGV(0, entity);
index a6431cf673810c1625552fc2418c644738c3e8ad..92fd5df1ac37330b1479044e7ef1cb61280d3930 100644 (file)
 
     MSG_CENTER_NOTIF(ASSAULT_ATTACKING,                 1,      0, 0, "",               CPID_ASSAULT_ROLE,      "0 0",  _("^BGYou are attacking!"), "")
     MSG_CENTER_NOTIF(ASSAULT_DEFENDING,                 1,      0, 0, "",               CPID_ASSAULT_ROLE,      "0 0",  _("^BGYou are defending!"), "")
+    MSG_CENTER_NOTIF(ASSAULT_OBJ_DESTROYED,             1,      0, 1, "f1time",         CPID_ASSAULT_ROLE,      "0 0",  _("^BGObjective destroyed in ^F4%s^BG!"), "")
 
     MSG_CENTER_NOTIF(COUNTDOWN_BEGIN,                   1,      0, 0, "",               CPID_ROUND,             "2 0",  _("^F4Begin!"), "")
     MSG_CENTER_NOTIF(COUNTDOWN_GAMESTART,               1,      0, 1, "",               CPID_ROUND,             "1 f1", _("^F4Game starts in ^COUNT"), "")
index 82398aa56b1c7d40513bdfb5e735115a0e4087ee..b3459a67b9e5dcacfc4a33c0ce03b6a0fd47f1fb 100644 (file)
@@ -63,9 +63,10 @@ REGISTER_STAT(WEAPON_NEXTTHINK, float)
 #ifdef SVQC
 SPECTATE_COPYFIELD(_STAT(WEAPON_NEXTTHINK))
 float W_WeaponRateFactor(entity this);
+float gameover;
 #endif
 REGISTER_STAT(WEAPONRATEFACTOR, float, W_WeaponRateFactor(this))
-
+REGISTER_STAT(GAMEOVER, int, gameover)
 REGISTER_STAT(GAMESTARTTIME, float)
 REGISTER_STAT(STRENGTH_FINISHED, float)
 REGISTER_STAT(INVINCIBLE_FINISHED, float)
index 3f5f40435819d6de9b7f748eeb7724af411623c6..95cc74802ceab386bc8611a277e9c9f3bd4eec04 100644 (file)
@@ -391,7 +391,7 @@ bool bumblebee_pilot_frame(entity this, float dt)
        entity vehic = this.vehicle;
        return = true;
 
-       if(intermission_running)
+       if(gameover)
        {
                vehic.solid = SOLID_NOT;
                vehic.takedamage = DAMAGE_NO;
index 0cdfc8cb870b52960254e754c07f38c5c0dfaa0a..80c28a8ab9ac7eab11f3f0fbd29053ad072864c3 100644 (file)
@@ -151,7 +151,7 @@ bool racer_frame(entity this, float dt)
        entity vehic = this.vehicle;
        return = true;
 
-       if(intermission_running)
+       if(gameover)
        {
                vehic.solid = SOLID_NOT;
                vehic.takedamage = DAMAGE_NO;
index 1068e7430dd47a8cc36b008575f2077b98071d9e..7c433f9c76f69dce59cbdba280418880c8210fe1 100644 (file)
@@ -133,7 +133,7 @@ bool raptor_frame(entity this, float dt)
        entity vehic = this.vehicle;
        return = true;
 
-       if(intermission_running)
+       if(gameover)
        {
                vehic.solid = SOLID_NOT;
                vehic.takedamage = DAMAGE_NO;
index d99335a51c3bcdde3497a9f6cd2866fdfa87d4da..6ad46946d70927728dd7447d96d8314a907cc5f9 100644 (file)
@@ -48,7 +48,7 @@ bool spiderbot_frame(entity this, float dt)
        entity vehic = this.vehicle;
        return = true;
 
-       if(intermission_running)
+       if(gameover)
        {
                vehic.solid = SOLID_NOT;
                vehic.takedamage = DAMAGE_NO;
index 9d612ea2edb2ba19b34d7368e53b5af044ff6b1b..9c84a6b67d3b74f2e3a1a2ae9aec07559b8c4742 100644 (file)
@@ -634,7 +634,7 @@ float bot_fixcount()
 
 void bot_serverframe()
 {
-       if (intermission_running)
+       if (gameover)
                return;
 
        if (time < 2)
index 04c35a11761ffbb05b04cec53c55919c53b4a55c..9583118ceacae67335fc8ff8612e17d3b4bd97e5 100644 (file)
@@ -284,8 +284,8 @@ void PutObserverInServer(entity this)
        if (this.killcount != FRAGS_SPECTATOR)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_QUIT_SPECTATE, this.netname);
-               if(!intermission_running)
-               if(autocvar_g_chat_nospectators == 1 || (!(warmup_stage || gameover) && autocvar_g_chat_nospectators == 2))
+               if(!gameover)
+               if(autocvar_g_chat_nospectators == 1 || (!warmup_stage && autocvar_g_chat_nospectators == 2))
                        Send_Notification(NOTIF_ONE_ONLY, this, MSG_INFO, INFO_CHAT_NOSPECTATORS);
 
                if(this.just_joined == false) {
@@ -2320,8 +2320,9 @@ void PlayerPreThink (entity this)
        if (IS_PLAYER(this)) {
                CheckRules_Player(this);
 
-               if (intermission_running) {
-                       IntermissionThink(this);
+               if (gameover || intermission_running) {
+                       if(intermission_running)
+                               IntermissionThink(this);
                        return;
                }
 
@@ -2472,8 +2473,9 @@ void PlayerPreThink (entity this)
 
                this.dmg_team = max(0, this.dmg_team - autocvar_g_teamdamage_resetspeed * frametime);
        }
-       else if (gameover) {
-               if (intermission_running) IntermissionThink(this);
+       else if (gameover || intermission_running) {
+               if(intermission_running)
+                       IntermissionThink(this);
                return;
        }
        else if (IS_OBSERVER(this)) {
@@ -2615,13 +2617,23 @@ void PlayerPostThink (entity this)
        CheatFrame(this);
 
        //CheckPlayerJump();
+       if (gameover)
+       {
+               this.solid = SOLID_NOT;
+               this.takedamage = DAMAGE_NO;
+               set_movetype(this, MOVETYPE_NONE);
+       }
 
        if (IS_PLAYER(this)) {
                DrownPlayer(this);
                CheckRules_Player(this);
                UpdateChatBubble(this);
                if (this.impulse) ImpulseCommands(this);
-               if (intermission_running) return; // intermission or finale
+               if (gameover)
+               {
+                       CSQCMODEL_AUTOUPDATE(this);
+                       return;
+               }
                GetPressedKeys(this);
        }
 
index 85c5d18472f82b08f94ff695c220ae2181761662..44b8acb8e7a8ff5fb9ea7e18688e269b3bd66be9 100644 (file)
@@ -465,7 +465,7 @@ void ReadyRestart_force()
 void ReadyRestart()
 {
        // no assault support yet...
-       if (g_assault | gameover | intermission_running | race_completing) localcmd("restart\n");
+       if (g_assault || gameover || race_completing) localcmd("restart\n");
        else localcmd("\nsv_hook_gamerestart\n");
 
        // Reset ALL scores, but only do that at the beginning of the countdown if sv_ready_restart_after_countdown is off!
index 52153fcd7edeedaf2b7c3aec557103786fcca343..fedd5eb1ab346354f6121da51fa247627a5de039 100644 (file)
@@ -129,7 +129,6 @@ const int W_TICSPERFRAME = 2;
 
 void weapon_defaultspawnfunc(entity this, Weapon e);
 
-float gameover;
 float intermission_running;
 float intermission_exittime;
 float alreadychangedlevel;
index fd725ad35e8b128a3e78521e0d46913e64f6134e..cccba42bb42128fff96050498f317875c050c360 100644 (file)
@@ -144,7 +144,7 @@ void GrapplingHookThink(entity this)
                error("Owner lost the hook!\n");
                return;
        }
-       if(LostMovetypeFollow(this) || intermission_running || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade"))
+       if(LostMovetypeFollow(this) || gameover || (round_handler_IsActive() && !round_handler_IsRoundStarted()) || ((this.aiment.flags & FL_PROJECTILE) && this.aiment.classname != "nade"))
        {
                RemoveGrapplingHook(this.realowner);
                return;
index 8edcf3b8f58f7b0010efffabd1279ab4c6d9ab9f..4ca9ef77c8afb16b1b5fab0190bc1cbd1770e8f5 100644 (file)
@@ -1308,7 +1308,6 @@ When the player presses attack or jump, change to the next level
 void IntermissionThink(entity this)
 {
        FixIntermissionClient(this);
-       CSQCMODEL_AUTOUPDATE(this); // PlayerPostThink returns before calling this during intermission, so run it here
 
        float server_screenshot = (autocvar_sv_autoscreenshot && this.cvar_cl_autoscreenshot);
        float client_screenshot = (this.cvar_cl_autoscreenshot == 2);
@@ -1496,9 +1495,6 @@ void FixIntermissionClient(entity e)
                e.autoscreenshot = time + 0.8;  // used for autoscreenshot
                e.health = -2342;
                // first intermission phase; voting phase has positive health (used to decide whether to send SVC_FINALE or not)
-               e.solid = SOLID_NOT;
-               set_movetype(e, MOVETYPE_NONE);
-               e.takedamage = DAMAGE_NO;
                for (int slot = 0; slot < MAX_WEAPONSLOTS; ++slot)
                {
                    .entity weaponentity = weaponentities[slot];
@@ -1536,7 +1532,7 @@ void NextLevel()
 
        intermission_running = 1;
 
-// enforce a wait time before allowing changelevel
+       // enforce a wait time before allowing changelevel
        if(player_count > 0)
                intermission_exittime = time + autocvar_sv_mapchange_delay;
        else
@@ -1843,7 +1839,7 @@ void CheckRules_World()
 
        SetDefaultAlpha();
 
-       if (gameover)   // someone else quit the game already
+       if (intermission_running) // someone else quit the game already
        {
                if(player_count == 0) // Nobody there? Then let's go to the next map
                        MapVote_Start();
index 7f4899f127faed3c1d53e77e9ad15a4d236f197b..d2aff2ae7bbc53d7378372b3aac05033ecb826a7 100644 (file)
@@ -461,7 +461,7 @@ void GetCvars(entity this, int f)
 string playername(entity p)
 {
     string t;
-    if (teamplay && !intermission_running && IS_PLAYER(p))
+    if (teamplay && !gameover && IS_PLAYER(p))
     {
         t = Team_ColorCode(p.team);
         return strcat(t, strdecolorize(p.netname));
index 1a1d7959fd2799b4e3908d3e13736b314106aced..d92e77158c3f8b18e011f9347c97df0e3c9edac7 100644 (file)
@@ -1,6 +1,7 @@
 #include "gamemode_assault.qh"
 
 .entity sprite;
+#define AS_ROUND_DELAY 5
 
 // random functions
 void assault_objective_use(entity this, entity actor, entity trigger)
@@ -202,14 +203,27 @@ void assault_new_round(entity this)
        });
 
        // reset the level with a countdown
-       cvar_set("timelimit", ftos(ceil(time - game_starttime) / 60));
+       cvar_set("timelimit", ftos(ceil(time - AS_ROUND_DELAY - game_starttime) / 60));
        ReadyRestart_force(); // sets game_starttime
 }
 
+entity as_round;
+.entity ent_winning;
+void as_round_think()
+{
+       gameover = false;
+       assault_new_round(as_round.ent_winning);
+       delete(as_round);
+       as_round = NULL;
+}
+
 // Assault winning condition: If the attackers triggered a round end (by fulfilling all objectives)
 // they win. Otherwise the defending team wins once the timelimit passes.
 int WinningCondition_Assault()
 {
+       if(as_round)
+               return WINNING_NO;
+
        WinningConditionHelper(NULL); // set worldstatus
 
        int status = WINNING_NO;
@@ -229,7 +243,7 @@ int WinningCondition_Assault()
        {
                if(ent.winning) // round end has been triggered by attacking team
                {
-                       bprint("ASSAULT: round completed...\n");
+                       bprint("Assault: round completed.\n");
                        SetWinners(team, assault_attacker_team);
 
                        TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 666 - TeamScore_AddToTeam(assault_attacker_team, ST_ASSAULT_OBJECTIVES, 0));
@@ -240,7 +254,17 @@ int WinningCondition_Assault()
                        }
                        else
                        {
-                               assault_new_round(ent);
+                               Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ASSAULT_OBJ_DESTROYED, ceil(time - game_starttime));
+                               as_round = new(as_round);
+                               as_round.think = as_round_think;
+                               as_round.ent_winning = ent;
+                               as_round.nextthink = time + AS_ROUND_DELAY;
+                               gameover = true;
+
+                               // make sure timelimit isn't hit while the game is blocked
+                               if(autocvar_timelimit > 0)
+                               if(time + AS_ROUND_DELAY >= game_starttime + autocvar_timelimit * 60)
+                                       cvar_set("timelimit", ftos(autocvar_timelimit + AS_ROUND_DELAY / 60));
                        }
                }
        }
index 2954fd1d33a2507f0809bc8838e416f2b0299f3a..2aede9204052148d1dee08243f137e5379be642f 100644 (file)
@@ -155,7 +155,7 @@ void kh_Controller_SetThink(float t, kh_Think_t func)  // runs occasionaly
 void kh_WaitForPlayers();
 void kh_Controller_Think(entity this)  // called a lot
 {
-       if(intermission_running)
+       if(gameover)
                return;
        if(this.cnt > 0)
        {
@@ -175,7 +175,7 @@ void kh_Controller_Think(entity this)  // called a lot
 void kh_Scores_Event(entity player, entity key, string what, float frags_player, float frags_owner)  // update the score when a key is captured
 {
        string s;
-       if(intermission_running)
+       if(gameover)
                return;
 
        if(frags_player)
@@ -448,7 +448,7 @@ void kh_Key_Collect(entity key, entity player)  //a player picks up a dropped ke
 
 void kh_Key_Touch(entity this, entity toucher)  // runs many, many times when a key has been dropped and can be picked up
 {
-       if(intermission_running)
+       if(gameover)
                return;
 
        if(this.owner) // already carried
@@ -659,7 +659,7 @@ void kh_LoserTeam(int loser_team, entity lostkey)  // runs when a player pushes
 
 void kh_Key_Think(entity this)  // runs all the time
 {
-       if(intermission_running)
+       if(gameover)
                return;
 
        if(this.owner)
index fea4b125abb0a6604fde98e6380efe6a32dcc2b3..9cccbe887a87790aa49ce0b8ac1b9a32e8304483 100644 (file)
@@ -699,7 +699,7 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
                teamsay = false;
        }
 
-       if(intermission_running)
+       if(gameover)
                teamsay = false;
 
     if (!source) {
@@ -876,9 +876,9 @@ int Say(entity source, int teamsay, entity privatesay, string msgin, bool floodc
 
        if (!privatesay && source && !IS_PLAYER(source))
        {
-               if (!intermission_running)
-                       if(teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !(warmup_stage || gameover)))
-                               teamsay = -1; // spectators
+               if (!gameover)
+               if (teamsay || (autocvar_g_chat_nospectators == 1) || (autocvar_g_chat_nospectators == 2 && !warmup_stage))
+                       teamsay = -1; // spectators
        }
 
        if(flood)
index 8cc3295b9a5d4acfe8d59a7f77585e115a30ccf3..063c12abb0aa8f67dd25c600ab70512251194589 100644 (file)
@@ -13,6 +13,9 @@ void round_handler_Think(entity this)
        }
 
        if (gameover)
+               gameover = false;
+
+       if (intermission_running)
        {
                round_handler_Reset(0);
                round_handler_Remove();
@@ -56,6 +59,7 @@ void round_handler_Think(entity this)
                        // schedule a new round
                        this.wait = true;
                        this.nextthink = time + this.delay;
+                       gameover = true;
                }
                else
                {
index c0d302e2232123e9e3c049eed1965f27d750cf7b..7dbdae6838cb2d5adcd632b9f67404b1f9359021 100644 (file)
@@ -67,7 +67,7 @@ vector CL_Weapon_GetShotOrg(int wpn)
 void CL_Weaponentity_Think(entity this)
 {
        this.nextthink = time;
-       if (intermission_running) this.frame = this.anim_idle.x;
+       if (gameover) this.frame = this.anim_idle.x;
        .entity weaponentity = this.weaponentity_fld;
        if (this.owner.(weaponentity) != this)
        {