]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into terencehill/ca_arena_freezetag_bugfixes
authorterencehill <piuntn@gmail.com>
Tue, 5 Feb 2013 21:41:41 +0000 (22:41 +0100)
committerterencehill <piuntn@gmail.com>
Tue, 5 Feb 2013 21:41:41 +0000 (22:41 +0100)
18 files changed:
qcsrc/common/constants.qh
qcsrc/server/arena.qc
qcsrc/server/autocvars.qh
qcsrc/server/bot/aim.qc
qcsrc/server/cl_client.qc
qcsrc/server/cl_player.qc
qcsrc/server/cl_weapons.qc
qcsrc/server/defs.qh
qcsrc/server/g_world.qc
qcsrc/server/miscfunctions.qc
qcsrc/server/mutators/base.qh
qcsrc/server/mutators/gamemode_freezetag.qc
qcsrc/server/progs.src
qcsrc/server/round_handler.qc [new file with mode: 0644]
qcsrc/server/round_handler.qh [new file with mode: 0644]
qcsrc/server/sv_main.qc
qcsrc/server/teamplay.qc
qcsrc/server/w_minstanex.qc

index 75f5a0bde762037387dbeb344989a47b1409bc01..83063cf6975bf45412e4b3cb77468f46be79c306 100644 (file)
@@ -469,6 +469,7 @@ float CPID_TIMEOUT_COUNTDOWN = 8;
 float CPID_MOTD = 9;
 float CPID_KH_MSG = 10;
 float CPID_PREVENT_JOIN = 11;
+float CPID_WAITING_PLAYERS = 12;
 
 // CSQC centerprint/notify message types
 float MSG_SUICIDE = 0;
index ef81fd92bad7db138edb2fa1e1067d252bae875b..14caab85b81cdb98b6b5231380efc2dcd1aaa5b7 100644 (file)
@@ -16,7 +16,6 @@ void PutClientInServer();
 
 float next_round;
 float redalive, bluealive, yellowalive, pinkalive;
-float totalalive;
 .float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
 float red_players, blue_players, yellow_players, pink_players;
 float total_players;
@@ -30,22 +29,29 @@ void reset_map(float dorespawn)
        entity oldself;
        oldself = self;
 
-       if(g_arena && autocvar_g_arena_warmup)
-               warmup = time + autocvar_g_arena_warmup;
-       else if(g_ca) {
-               warmup = time + autocvar_g_ca_warmup;
-               allowed_to_spawn = 1;
+       if(time <= game_starttime && round_handler_IsActive())
+               round_handler_Reset(game_starttime + 1);
+
+       if(g_arena)
+       {
+               warmup = max(time, game_starttime);
+               if(autocvar_g_arena_warmup > 0)
+                       warmup += autocvar_g_arena_warmup;
        }
-       else if(g_freezetag)
+       else if(g_ca)
        {
-               warmup = time + autocvar_g_freezetag_warmup;
+               warmup = max(time, game_starttime);
+               if(autocvar_g_ca_warmup > 0)
+                       warmup += autocvar_g_ca_warmup;
+               allowed_to_spawn = 1;
        }
+       else if(g_race || g_cts)
+               race_ReadyRestart();
+       else MUTATOR_CALLHOOK(reset_map_global);
 
        lms_lowest_lives = 999;
        lms_next_place = player_count;
 
-       race_ReadyRestart();
-
        for(self = world; (self = nextent(self)); )
        if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
        {
@@ -76,6 +82,7 @@ void reset_map(float dorespawn)
        // Moving the player reset code here since the player-reset depends
        // on spawnpoint entities which have to be reset first --blub
        if(dorespawn)
+       if(!MUTATOR_CALLHOOK(reset_map_players))
        FOR_EACH_CLIENT(self) {
                if(self.flags & FL_CLIENT)                              // reset all players
                {
@@ -90,11 +97,6 @@ void reset_map(float dorespawn)
                                self.classname = "player";
                                PutClientInServer();
                        }
-                       else if(g_freezetag)
-                       {
-                               if(self.classname == "player")
-                                       PutClientInServer();
-                       }
                        else
                        {
                                /*
@@ -211,21 +213,36 @@ void Arena_Warmup()
                }
                return;
        }
-       if((!g_arena && !g_ca && !g_freezetag) || (g_arena && !arena_roundbased) || (time < game_starttime))
+       if(time < game_starttime)
                return;
 
        f = ceil(warmup - time);
 
-       if(inWarmupStage)
-               allowed_to_spawn = 1;
-       else if(!g_ca)
-               allowed_to_spawn = 0;
+       if(g_ca)
+       {
+               if(inWarmupStage)
+                       allowed_to_spawn = 1;
+               else if (warmup == 0) //first warmup or warmup cleared
+               {
+                       if (red_players && blue_players)
+                               reset_map(TRUE);
+                       else if(f != roundStartTime_prev)
+                       {
+                               if(roundStartTime_prev & 1) // msg every 2 seconds
+                               if(roundStartTime_prev - f == 1) // block sudden msg
+                               FOR_EACH_REALCLIENT(self)
+                                       Send_CSQC_Centerprint_Generic(self, CPID_ROUND_STARTING, "^1Need at least 1 player in each team to play CA", 2, 0);
+                               roundStartTime_prev = f;
+                       }
+                       return;
+               }
+       }
 
        if(time < warmup && !inWarmupStage)
        {
                if (g_ca)
                        allowed_to_spawn = 1;
-               if(champion && g_arena)
+               else if(champion && g_arena)
                {
                        FOR_EACH_REALCLIENT(e)
                                centerprint(e, strcat("The Champion is ", champion.netname));
@@ -233,23 +250,23 @@ void Arena_Warmup()
 
                if(f != roundStartTime_prev) {
                        roundStartTime_prev = f;
+
                        if(g_ca && !(red_players && blue_players)) {
-                               FOR_EACH_REALCLIENT(self)
-                                       Send_CSQC_Centerprint_Generic(self, CPID_ROUND_STARTING, "^1Need at least 1 player in each team to play CA", 2, 0);
-                               warmup = time + autocvar_g_ca_warmup;
-                       } else {
-                               if(f == 5)
-                                       Announce("prepareforbattle");
-                               else if(f == 3)
-                                       Announce("3");
-                               else if(f == 2)
-                                       Announce("2");
-                               else if(f == 1)
-                                       Announce("1");
-
-                               FOR_EACH_REALCLIENT(e)
-                                       Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
+                               warmup = 0;
+                               return;
                        }
+
+                       if(f == 5)
+                               Announce("prepareforbattle");
+                       else if(f == 3)
+                               Announce("3");
+                       else if(f == 2)
+                               Announce("2");
+                       else if(f == 1)
+                               Announce("1");
+
+                       FOR_EACH_REALCLIENT(e)
+                               Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
                }
 
                if (g_arena) {
@@ -260,19 +277,21 @@ void Arena_Warmup()
                        }
                }
        }
-       else if(f > -1 && f != roundStartTime_prev)
+       else if(f > -1 && f != roundStartTime_prev && !inWarmupStage)
        {
                roundStartTime_prev = f;
                if(g_ca) {
                        if(red_players && blue_players)
                                allowed_to_spawn = 0;
                        else
-                               reset_map(TRUE);
-               } else {
-                       Announce("begin");
-                       FOR_EACH_REALCLIENT(e)
-                               Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
+                       {
+                               warmup = 0;
+                               return;
+                       }
                }
+               Announce("begin");
+               FOR_EACH_REALCLIENT(e)
+                       Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
 
                if(g_arena) {
                        FOR_EACH_CLIENT(e)
@@ -318,59 +337,17 @@ void count_players()
 
 void count_alive_players()
 {
-       totalalive = redalive = bluealive = yellowalive = pinkalive = 0;
-       if(g_ca)
-       {
-               FOR_EACH_PLAYER(self) {
-                       if (self.team == COLOR_TEAM1 && self.health >= 1)
-                       {
-                               redalive += 1;
-                               totalalive += 1;
-                       }
-                       else if (self.team == COLOR_TEAM2 && self.health >= 1)
-                       {
-                               bluealive += 1;
-                               totalalive += 1;
-                       }
-               }
-               FOR_EACH_REALCLIENT(self) {
-                       self.redalive_stat = redalive;
-                       self.bluealive_stat = bluealive;
-               }
+       redalive = bluealive = yellowalive = pinkalive = 0;
+       FOR_EACH_PLAYER(self) {
+               if (self.team == COLOR_TEAM1 && self.health >= 1)
+                       redalive += 1;
+               else if (self.team == COLOR_TEAM2 && self.health >= 1)
+                       bluealive += 1;
        }
-       else if(g_freezetag)
-       {
-               // count amount of alive players in each team
-               FOR_EACH_PLAYER(self) {
-                       if (self.team == COLOR_TEAM1 && self.freezetag_frozen == 0 && self.health >= 1)
-                       {
-                               redalive += 1;
-                               totalalive += 1;
-                       }
-                       else if (self.team == COLOR_TEAM2 && self.freezetag_frozen == 0 && self.health >= 1)
-                       {
-                               bluealive += 1;
-                               totalalive += 1;
-                       }
-                       else if (self.team == COLOR_TEAM3 && self.freezetag_frozen == 0 && self.health >= 1)
-                       {
-                               yellowalive += 1;
-                               totalalive += 1;
-                       }
-                       else if (self.team == COLOR_TEAM4 && self.freezetag_frozen == 0 && self.health >= 1)
-                       {
-                               pinkalive += 1;
-                               totalalive += 1;
-                       }
-               }
-               FOR_EACH_REALCLIENT(self) {
-                       self.redalive_stat = redalive;
-                       self.bluealive_stat = bluealive;
-                       self.yellowalive_stat = yellowalive;
-                       self.pinkalive_stat = pinkalive;
-               }
+       FOR_EACH_REALCLIENT(self) {
+               self.redalive_stat = redalive;
+               self.bluealive_stat = bluealive;
        }
-
 }
 
 /**
@@ -382,12 +359,6 @@ void count_alive_players()
  */
 void Spawnqueue_Check()
 {
-       if(warmup == 0 && g_ca && !inWarmupStage)
-       {
-               if(red_players || blue_players)
-                       reset_map(TRUE);
-               return;
-       }
        if(time < warmup + 1 || inWarmupStage || intermission_running)
                return;
 
@@ -426,12 +397,6 @@ void Spawnqueue_Check()
                        next_round = 0;
                        reset_map(TRUE);
                }
-       } else if(g_freezetag) {
-               if((next_round && next_round < time))
-               {
-                       next_round = 0;
-                       reset_map(TRUE);
-               }
        } else { // arena
                //extend next_round if it isn't set yet and only 1 player is spawned
                if(!next_round)
@@ -465,3 +430,19 @@ void Spawnqueue_Check()
                }
        }
 }
+
+void Arena_Main()
+{
+       if(!(g_ca || g_arena))
+               return;
+
+       if(g_ca)
+       {
+               count_players();
+               count_alive_players();
+       }
+       if(!g_arena || arena_roundbased)
+               Arena_Warmup();
+       Spawnqueue_Check();
+}
+
index c8db3db8a409c5749a6b1c4fef7e086cdb5d22dd..cc0e48cc5512fb6ff96d7233e511d84a9fedf2a1 100644 (file)
@@ -1018,7 +1018,6 @@ float autocvar_g_spawn_useallspawns;
 float autocvar_g_spawnpoints_auto_move_out_of_solid;
 #define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
 float autocvar_g_spawnsound;
-float autocvar_g_start_delay;
 #define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser")
 float autocvar_g_tdm_team_spawns;
 float autocvar_g_tdm_teams;
index 3bff21ecf00a4801bd083ba12315087312f28931..cb42aa5c2c4b0b158697b4122a51c27e88543d7d 100644 (file)
@@ -111,9 +111,8 @@ float bot_shouldattack(entity e)
                        return FALSE;
        }
 
-       if(g_freezetag)
-               if(e.freezetag_frozen)
-                       return FALSE;
+       if(e.freezetag_frozen)
+               return FALSE;
 
        // If neither player has ball then don't attack unless the ball is on the
        // ground.
index 691f8621c6f8b35b14c5f80b0057a248fb720aff..ae40c4e1ef2025139a9714db695065858dc89430 100644 (file)
@@ -2043,7 +2043,7 @@ void player_regen (void)
        limita = limita * limit_mod;
        //limitf = limitf * limit_mod;
 
-       if(g_lms && g_ca)
+       if(g_ca)
                rot_mod = 0;
 
        if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
index 6945fe7221463fd6dd638ec5688d1ee7f5532b30..be700c87a4545650bb6a08a6df67e0173e401de4 100644 (file)
@@ -431,7 +431,6 @@ void PlayerCorpseDamage (entity inflictor, entity attacker, float damage, float
 }
 
 void ClientKill_Now_TeamChange();
-void freezetag_CheckWinner();
 
 void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
 {
@@ -672,14 +671,6 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
                        }
                }
 
-               if(!g_freezetag)
-               {
-                       // become fully visible
-                       self.alpha = default_player_alpha;
-                       // throw a weapon
-                       SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
-               }
-
                // print an obituary message
                Obituary (attacker, inflictor, self, deathtype);
                race_PreDie();
@@ -692,18 +683,12 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
        if(accuracy_isgooddamage(attacker, self))
         attacker.accuracy.(accuracy_frags[w-1]) += 1;
 
-               if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
-               {
-                       PutClientInServer();
-                       count_alive_players(); // re-count players
-                       freezetag_CheckWinner();
-                       return;
-               }
-
                frag_attacker = attacker;
                frag_inflictor = inflictor;
                frag_target = self;
+               frag_deathtype = deathtype;
                MUTATOR_CALLHOOK(PlayerDies);
+
                weapon_action(self.weapon, WR_PLAYERDEATH);
 
                RemoveGrapplingHook(self);
@@ -721,19 +706,26 @@ void PlayerDamage (entity inflictor, entity attacker, float damage, float deatht
                        //WriteAngle (MSG_ONE, 80);
                }
 
-               if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
-                       ClientKill_Now_TeamChange();
+               if(defer_ClientKill_Now_TeamChange)
+                       ClientKill_Now_TeamChange(); // can turn player into spectator
 
                if(g_arena)
                        Spawnqueue_Unmark(self);
 
-               if(g_freezetag)
+               // player could have been miraculously resuscitated ;)
+               // e.g. players in freezetag get frozen, they don't really die
+               if(self.health >= 1 || self.classname != "player")
                        return;
 
                // when we get here, player actually dies
-               // clear waypoints (do this AFTER FreezeTag)
+
+               // clear waypoints
                WaypointSprite_PlayerDead();
+               // throw a weapon
+               SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
 
+               // become fully visible
+               self.alpha = default_player_alpha;
                // make the corpse upright (not tilted)
                self.angles_x = 0;
                self.angles_z = 0;
index 4df59a09afde775e7e73cca9fb0be6e248ad1205..b78d22cec213532745cc66c66803e4c243c6fcc2 100644 (file)
@@ -375,7 +375,10 @@ void W_WeaponFrame()
        if (frametime)
                self.weapon_frametime = frametime;
 
-       if(((arena_roundbased || g_ca || g_freezetag) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
+       if(((arena_roundbased || g_ca) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
+               return;
+
+       if(round_handler_IsActive() && !round_handler_IsRoundStarted())
                return;
 
        if(self.freezetag_frozen == 1)
index f777254138e0c0dc4facdb4259567ac397d11cba..401cc786661b0835d5f6c3686f9837218e472ce0 100644 (file)
@@ -642,6 +642,7 @@ float serverflags;
 .float player_blocked;
 
 .float freezetag_frozen;
+.float freezetag_frozen_timeout;
 .float freezetag_revive_progress;
 
 .entity muzzle_flash;
index 8d8c0328ec6abed9d4e4e7c7d516fb4249faf260..c70f7b84c569b7cbbb1a5cdc18890eb68509cf58 100644 (file)
@@ -585,8 +585,6 @@ void spawnfunc_worldspawn (void)
 
        compressShortVector_init();
 
-       allowed_to_spawn = TRUE;
-
        entity head;
        head = nextent(world);
        maxclients = 0;
@@ -808,17 +806,10 @@ void spawnfunc_worldspawn (void)
 
        addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
 
-       if(g_ca || g_freezetag)
+       if(g_ca)
        {
                addstat(STAT_REDALIVE, AS_INT, redalive_stat);
                addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
-               addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
-               addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
-       }
-       if(g_freezetag)
-       {
-               addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
-               addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
        }
 
        // g_movementspeed hack
index 7f8931bffe648c90d3bd4a7b3eada671725f66e6..53719e075f9099273be8a139820681786c3194ff 100644 (file)
@@ -1264,7 +1264,7 @@ void readlevelcvars(void)
     if(!g_weapon_stay)
         g_weapon_stay = cvar("g_weapon_stay");
 
-       if not(inWarmupStage && !g_ca)
+       if not(inWarmupStage)
                game_starttime = cvar("g_start_delay");
 
        sv_pitch_min = cvar("sv_pitch_min");
index d90d564b501447acb3e3ef1def71530be1a521ee..a9e180c5968008da2b5a713c1e001bc2c06f5539 100644 (file)
@@ -50,6 +50,12 @@ MUTATOR_HOOKABLE(PlayerSpawn);
        entity spawn_spot; // spot that was used, or world
        // called when a player spawns as player, after shared setup, before his weapon is chosen (so items may be changed in here)
 
+MUTATOR_HOOKABLE(reset_map_global);
+       // called in reset_map
+
+MUTATOR_HOOKABLE(reset_map_players);
+       // called in reset_map
+
 MUTATOR_HOOKABLE(ClientDisconnect);
        // called when a player disconnects
 
@@ -59,6 +65,7 @@ MUTATOR_HOOKABLE(PlayerDies);
                entity frag_inflictor;
                entity frag_attacker;
                entity frag_target; // same as self
+               float frag_deathtype;
 
 MUTATOR_HOOKABLE(GiveFragsForKill);
        // called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
index 116eecbbf6b773613f7b299568df3ee31a5817d6..7e068e954687e855d3b54fea4c3d0869feb8de32 100644 (file)
@@ -1,25 +1,98 @@
+float freezetag_CheckTeams();
+float freezetag_CheckWinner();
 void freezetag_Initialize()
 {
        precache_model("models/ice/ice.md3");
-       warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
        ScoreRules_freezetag();
+
+       round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, 5, autocvar_g_freezetag_warmup);
+
+       addstat(STAT_REDALIVE, AS_INT, redalive_stat);
+       addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
+       addstat(STAT_YELLOWALIVE, AS_INT, yellowalive_stat);
+       addstat(STAT_PINKALIVE, AS_INT, pinkalive_stat);
+
+       addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
+       addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
 }
 
-void freezetag_CheckWinner()
+void freezetag_count_alive_players()
 {
-       if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
-               return;
-
-       if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
-               return; // already waiting for next round to start
+       entity e;
+       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+       FOR_EACH_PLAYER(e) {
+               if(e.team == COLOR_TEAM1 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++redalive;
+               }
+               else if(e.team == COLOR_TEAM2 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++bluealive;
+               }
+               else if(e.team == COLOR_TEAM3 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++yellowalive;
+               }
+               else if(e.team == COLOR_TEAM4 && e.health >= 1)
+               {
+                       ++total_players;
+                       if (!e.freezetag_frozen) ++pinkalive;
+               }
+       }
+       FOR_EACH_REALCLIENT(e) {
+               e.redalive_stat = redalive;
+               e.bluealive_stat = bluealive;
+               e.yellowalive_stat = yellowalive;
+               e.pinkalive_stat = pinkalive;
+       }
+}
 
+float freezetag_TeamsCanPlay()
+{
        if((redalive >= 1 && bluealive >= 1)
                || (redalive >= 1 && yellowalive >= 1)
                || (redalive >= 1 && pinkalive >= 1)
                || (bluealive >= 1 && yellowalive >= 1)
                || (bluealive >= 1 && pinkalive >= 1)
                || (yellowalive >= 1 && pinkalive >= 1))
-               return; // we still have active players on two or more teams, nobody won yet
+               return 1; // we still have active players on two or more teams, nobody won yet
+       return 0;
+}
+
+float prev_total_players;
+float freezetag_CheckTeams()
+{
+       entity e;
+       if(freezetag_TeamsCanPlay())
+       {
+               if(prev_total_players != -1)
+               {
+                       FOR_EACH_REALCLIENT(e)
+                               Send_CSQC_Centerprint_Generic_Expire(e, CPID_WAITING_PLAYERS);
+               }
+               prev_total_players = -1;
+               return 1;
+       }
+       if(prev_total_players != total_players)
+       {
+               string teams_missing;
+               if(!redalive)   teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM1), ", ");
+               if(!bluealive)  teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM2), ", ");
+               teams_missing = substring(teams_missing, 0, strlen(teams_missing)-2);
+
+               FOR_EACH_REALCLIENT(e)
+                       Send_CSQC_Centerprint_Generic(e, CPID_WAITING_PLAYERS, strcat("Waiting for players to join...\n\nNeed active players for: ", teams_missing), -1, 0);
+               prev_total_players = total_players;
+       }
+       return 0;
+}
+float freezetag_CheckWinner()
+{
+       if(freezetag_TeamsCanPlay())
+               return 0;
 
        entity e, winner;
        string teamname;
@@ -36,22 +109,14 @@ void freezetag_CheckWinner()
 
        if(winner != world) // just in case a winner wasn't found
        {
-               if(winner.team == COLOR_TEAM1)
-                       teamname = "^1Red Team";
-               else if(winner.team == COLOR_TEAM2)
-                       teamname = "^4Blue Team";
-               else if(winner.team == COLOR_TEAM3)
-                       teamname = "^3Yellow Team";
-               else
-                       teamname = "^6Pink Team";
-               FOR_EACH_PLAYER(e) {
-                       centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.\n"));
-               }
+               teamname = ColoredTeamName(winner.team);
+               FOR_EACH_REALCLIENT(e)
+                       centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen."));
                bprint(teamname, "^5 wins the round since all the other teams were frozen.\n");
                TeamScore_AddToTeam(winner.team, ST_SCORE, +1);
        }
 
-       next_round = time + 5;
+       return 1;
 }
 
 // this is needed to allow the player to turn his view around (fixangle can't
@@ -63,6 +128,24 @@ void freezetag_Ice_Think()
        self.nextthink = time;
 }
 
+void freezetag_Add_Score(entity attacker)
+{
+       if(attacker == self)
+       {
+               // you froze your own dumb self
+               // counted as "suicide" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+       }
+       else if(attacker.classname == "player")
+       {
+               // got frozen by an enemy
+               // counted as "kill" and "death" already
+               PlayerScore_Add(self, SP_SCORE, -1);
+               PlayerScore_Add(attacker, SP_SCORE, +1);
+       }
+       // else nothing - got frozen by the game type rules themselves
+}
+
 void freezetag_Freeze(entity attacker)
 {
        if(self.freezetag_frozen)
@@ -70,6 +153,10 @@ void freezetag_Freeze(entity attacker)
        self.freezetag_frozen = 1;
        self.freezetag_revive_progress = 0;
        self.health = 1;
+       // if(inWarmupStage)
+               // self.freezetag_frozen_timeout = time + 5;
+
+       freezetag_count_alive_players();
 
        entity ice;
        ice = spawn();
@@ -91,30 +178,14 @@ void freezetag_Freeze(entity attacker)
        // add waypoint
        WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
 
-       if(attacker == self)
-       {
-               // you froze your own dumb self
-               // counted as "suicide" already
-               PlayerScore_Add(self, SP_SCORE, -1);
-       }
-       else if(attacker.classname == "player")
-       {
-               // got frozen by an enemy
-               // counted as "kill" and "death" already
-               PlayerScore_Add(self, SP_SCORE, -1);
-               PlayerScore_Add(attacker, SP_SCORE, +1);
-       }
-       else
-       {
-               // nothing - got frozen by the game type rules themselves
-       }
+       freezetag_Add_Score(attacker);
 }
 
 void freezetag_Unfreeze(entity attacker)
 {
        self.freezetag_frozen = 0;
+       self.freezetag_frozen_timeout = 0;
        self.freezetag_revive_progress = 0;
-       self.health = autocvar_g_balance_health_start;
 
        // remove the ice block
        entity ice;
@@ -240,44 +311,45 @@ void havocbot_role_ft_freeing()
 
 MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer)
 {
-       if(self.freezetag_frozen == 0 && self.health >= 1)
-       {
-               if(self.team == COLOR_TEAM1)
-                       --redalive;
-               else if(self.team == COLOR_TEAM2)
-                       --bluealive;
-               else if(self.team == COLOR_TEAM3)
-                       --yellowalive;
-               else if(self.team == COLOR_TEAM4)
-                       --pinkalive;
-               --totalalive;
-       }
-
-       if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that)
-               freezetag_CheckWinner();
-
+       self.health = 0; // neccessary to update correctly alive stats
        freezetag_Unfreeze(world);
-
+       freezetag_count_alive_players();
        return 1;
 }
 
 MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
 {
-       if(self.freezetag_frozen == 0)
+       if(round_handler_IsActive())
+       if(round_handler_CountdownRunning())
        {
-               if(self.team == COLOR_TEAM1)
-                       --redalive;
-               else if(self.team == COLOR_TEAM2)
-                       --bluealive;
-               else if(self.team == COLOR_TEAM3)
-                       --yellowalive;
-               else if(self.team == COLOR_TEAM4)
-                       --pinkalive;
-               --totalalive;
+               if(self.freezetag_frozen)
+                       freezetag_Unfreeze(world);
+               freezetag_count_alive_players();
+               return 1; // let the player die so that he can respawn whenever he wants
+       }
 
-               freezetag_Freeze(frag_attacker);
+       // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+       // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+       if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+               || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
+       {
+               // let the player die, he will be automatically frozen when he respawns
+               if(!self.freezetag_frozen)
+               {
+                       freezetag_Add_Score(frag_attacker);
+                       freezetag_count_alive_players();
+               }
+               else
+                       freezetag_Unfreeze(world); // remove ice
+               self.freezetag_frozen_timeout = -2; // freeze on respawn
+               return 1;
        }
 
+       if(self.freezetag_frozen)
+               return 1;
+
+       freezetag_Freeze(frag_attacker);
+
        if(frag_attacker == frag_target || frag_attacker == world)
        {
                if(frag_target.classname == STR_PLAYER)
@@ -295,30 +367,46 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
 
        frag_target.health = 1; // "respawn" the player :P
 
-       freezetag_CheckWinner();
-
        return 1;
 }
 
 MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
 {
-       freezetag_Unfreeze(world); // start by making sure that all ice blocks are removed
+       if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+               return 1; // do nothing, round is starting right now
 
-       if(total_players == 1 && time > game_starttime) // only one player active on server, start a new match immediately
-       if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
+       if(self.freezetag_frozen_timeout == -2) // player was dead
        {
-               next_round = time;
+               freezetag_Freeze(world);
                return 1;
        }
-       if(warmup && time > warmup) // spawn too late, freeze player
+
+       freezetag_count_alive_players();
+
+       if(round_handler_IsActive())
+       if(round_handler_IsRoundStarted())
        {
-               centerprint(self, "^1You spawned after the round started, you'll spawn as frozen.\n");
+               centerprint(self, "^1Round already started, you spawn as frozen.");
                freezetag_Freeze(world);
        }
 
        return 1;
 }
 
+MUTATOR_HOOKFUNCTION(freezetag_reset_map_players)
+{
+       FOR_EACH_PLAYER(self)
+       {
+               if (self.freezetag_frozen)
+                       freezetag_Unfreeze(world);
+               self.freezetag_frozen_timeout = -1;
+               PutClientInServer();
+               self.freezetag_frozen_timeout = 0;
+       }
+       freezetag_count_alive_players();
+       return 1;
+}
+
 MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
 {
        frag_score = 0; // no frags counted in Freeze Tag
@@ -330,6 +418,27 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
        float n;
        vector revive_extra_size;
 
+       if(gameover)
+               return 1;
+
+       if(self.freezetag_frozen)
+       {
+               // keep health = 1
+               self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+
+               if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+               {
+                       self.health = autocvar_g_balance_health_start;
+                       freezetag_Unfreeze(world);
+                       freezetag_count_alive_players();
+                       return 1;
+               }
+       }
+
+       if(round_handler_IsActive())
+       if(!round_handler_IsRoundStarted())
+               return 1;
+
        revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
 
        entity o;
@@ -359,6 +468,7 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPreThink)
                if(self.freezetag_revive_progress >= 1)
                {
                        freezetag_Unfreeze(self);
+                       freezetag_count_alive_players();
 
                        // EVERY team mate nearby gets a point (even if multiple!)
                        FOR_EACH_PLAYER(other) if(self != other)
@@ -425,15 +535,12 @@ MUTATOR_HOOKFUNCTION(freezetag_PlayerPhysics)
 
 MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
 {
-    if(g_freezetag)
-    {
-        if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
-        {
-            frag_damage = 0;
-            frag_force = frag_force * autocvar_g_freezetag_frozen_force;
-        }
-    }
-    return 1;
+       if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
+       {
+               frag_damage = 0;
+               frag_force = frag_force * autocvar_g_freezetag_frozen_force;
+       }
+       return 1;
 }
 
 MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
@@ -452,22 +559,31 @@ MUTATOR_HOOKFUNCTION(freezetag_BotRoles)
                else
                        self.havocbot_role = havocbot_role_ft_offense;
        }
-       
+
        return TRUE;
 }
 
+MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
+{
+       self.freezetag_frozen = other.freezetag_frozen;
+       self.freezetag_revive_progress = other.freezetag_revive_progress;
+       return 0;
+}
+
 MUTATOR_DEFINITION(gamemode_freezetag)
 {
        MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY);
        MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY);
+       MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
        MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
        MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
-       MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno.
+       MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_ANY);
        MUTATOR_HOOK(HavocBot_ChooseRule, freezetag_BotRoles, CBC_ORDER_ANY);
+       MUTATOR_HOOK(SpectateCopy, freezetag_SpectateCopy, CBC_ORDER_ANY);
 
        MUTATOR_ONADD
        {
index 36936e38642e597bad39ca5b3d56621450a9dbe1..0a27d68b90eaacb701f998d6b460033ab6cf149c 100644 (file)
@@ -78,6 +78,8 @@ antilag.qh
 
 playerdemo.qh
 
+round_handler.qh
+
 // singleplayer stuff
 item_key.qh
 secret.qh
@@ -204,6 +206,8 @@ anticheat.qc
 cheats.qc
 playerstats.qc
 
+round_handler.qc
+
 ../common/explosion_equation.qc
 
 mutators/base.qc
diff --git a/qcsrc/server/round_handler.qc b/qcsrc/server/round_handler.qc
new file mode 100644 (file)
index 0000000..2bac357
--- /dev/null
@@ -0,0 +1,129 @@
+void round_handler_Think()
+{
+       entity e;
+       float f;
+
+       if(time <= game_starttime)
+       {
+               round_handler_Reset(game_starttime + 1);
+               return;
+       }
+
+       if(gameover)
+       {
+               round_handler_Reset(0);
+               round_handler_Remove();
+               return;
+       }
+
+       if(self.wait)
+       {
+               reset_map(TRUE);
+               self.wait = FALSE;
+               self.cnt = self.count + 1; // init countdown
+       }
+
+       if(self.cnt > 0) // countdown running
+       {
+               if(self.canRoundStart())
+               {
+                       f = self.cnt - 1;
+                       if(f == 5) Announce("prepareforbattle");
+                       else if(f == 3) Announce("3");
+                       else if(f == 2) Announce("2");
+                       else if(f == 1) Announce("1");
+                       else if(f == 0)
+                       {
+                               Announce("begin");
+                               FOR_EACH_REALCLIENT(e)
+                                       Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
+                               self.cnt = 0;
+                               self.nextthink = time;
+                               return;
+                       }
+
+                       FOR_EACH_REALCLIENT(e)
+                               Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
+                       self.cnt = self.cnt - 1;
+               }
+               else
+               {
+                       round_handler_Reset(0);
+               }
+               self.nextthink = time + 1; // canRoundStart every second
+       }
+       else
+       {
+               if(self.canRoundEnd())
+               {
+                       // schedule a new round
+                       self.wait = TRUE;
+                       self.nextthink = time + self.delay;
+               }
+               else
+               {
+                       self.nextthink = time; // canRoundEnd every frame
+               }
+       }
+}
+
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, float the_delay, float the_count)
+{
+       if(round_handler)
+       {
+               backtrace("Can't spawn round_handler again!");
+               return;
+       }
+       round_handler = spawn();
+       round_handler.classname = "round_handler";
+
+       round_handler.think = round_handler_Think;
+       round_handler.canRoundStart = canRoundStart_func;
+       round_handler.canRoundEnd = canRoundEnd_func;
+       round_handler.delay = (the_delay > 0) ? the_delay : 0;
+       round_handler.count = fabs(floor(the_count));
+       round_handler.wait = FALSE;
+       round_handler.cnt = round_handler.count + 1;
+       round_handler.nextthink = max(time, game_starttime + 1);
+}
+
+float round_handler_IsActive()
+{
+       return (round_handler != world);
+}
+
+float round_handler_AwaitingNextRound()
+{
+       return (round_handler.wait);
+}
+
+float round_handler_CountdownRunning()
+{
+       return (!round_handler.wait && round_handler.cnt);
+}
+
+float round_handler_IsRoundStarted()
+{
+       return (!round_handler.wait && !round_handler.cnt);
+}
+
+void round_handler_Reset(float next_think)
+{
+       entity e;
+       round_handler.wait = FALSE;
+       if(round_handler.count)
+       if(round_handler.cnt < round_handler.count + 1)
+       {
+               FOR_EACH_REALCLIENT(e)
+                       Send_CSQC_Centerprint_Generic_Expire(e, CPID_ROUND_STARTING);
+               round_handler.cnt = round_handler.count + 1;
+       }
+       round_handler.nextthink = next_think;
+}
+
+void round_handler_Remove()
+{
+       remove(round_handler);
+       round_handler = world;
+}
+
diff --git a/qcsrc/server/round_handler.qh b/qcsrc/server/round_handler.qh
new file mode 100644 (file)
index 0000000..55026fa
--- /dev/null
@@ -0,0 +1,17 @@
+entity round_handler;
+.float delay; // stores delay from round end to countdown start
+.float count; // stores initial number of the countdown
+.float wait; // it's set to TRUE when round ends, to FALSE when countdown starts
+.float cnt;    // its initial value is .count + 1, then decreased while counting down
+                       // reaches 0 when the round starts
+.float() canRoundStart;
+.float() canRoundEnd;
+
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, float the_delay, float the_count);
+float round_handler_IsActive();
+float round_handler_AwaitingNextRound();
+float round_handler_CountdownRunning();
+float round_handler_IsRoundStarted();
+void round_handler_Reset(float next_think);
+void round_handler_Remove();
+
index c91c1ac1895ecae9d49667175258f3b91b9f9486..171a4ae9b7d9505e52f6faf3a77a880638a77663 100644 (file)
@@ -153,6 +153,7 @@ Called before each frame by the server
 float game_delay;
 float game_delay_last;
 
+void Arena_Main();
 void RuneMatchGivePoints();
 float RedirectionThink();
 entity SelectSpawnPoint (float anypoint);
@@ -210,19 +211,13 @@ void StartFrame (void)
 
        skill = autocvar_skill;
 
-       count_players();
-       if(g_ca || g_freezetag)
-               count_alive_players();
-       Arena_Warmup();
-       Spawnqueue_Check();
-
        // detect when the pre-game countdown (if any) has ended and the game has started
        game_delay = (time < game_starttime) ? TRUE : FALSE;
 
        if(game_delay_last == TRUE)
        if(game_delay == FALSE)
        if(autocvar_sv_eventlog)
-                       GameLogEcho(":startdelay_ended");
+               GameLogEcho(":startdelay_ended");
 
        game_delay_last = game_delay;
 
@@ -235,6 +230,8 @@ void StartFrame (void)
                return;
        }
 
+       Arena_Main();
+
        CreatureFrame ();
        CheckRules_World ();
 
index b8f2f3ac8746ea4e02daae0936833d2086954699..61b9f06fdc5064127c14e19d5c408ac3adcaad6b 100644 (file)
@@ -181,6 +181,7 @@ void InitGameplayMode()
                ActivateTeamplay();
                fraglimit_override = autocvar_g_ca_point_limit;
                leadlimit_override = autocvar_g_ca_point_leadlimit;
+               allowed_to_spawn = TRUE;
                precache_sound("ctf/red_capture.wav");
                precache_sound("ctf/blue_capture.wav");
        }
index a2d3b988734a6d75e9ff2c3fd3db737573821e30..0a76265d7a2847c54e6eca6ea031751255112abc 100644 (file)
@@ -104,8 +104,9 @@ void minstagib_ammocheck(void)
                minstagib_stop_countdown(self);
        else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
        {
+               if (self.minstagib_needammo)
+                       self.health = 100;
                minstagib_stop_countdown(self);
-               self.health = 100;
        }
        else
        {