]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/gamemodes/gamemode/freezetag/freezetag.qc
Merge branch 'master' into Lyberta/TeamplayOverhaul
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / freezetag / freezetag.qc
index cceff4806c5618c079809312d61bc583f3cd1304..15726ada31d03b5442b12e15e175d34533af9768 100644 (file)
@@ -2,6 +2,9 @@
 
 // TODO: sv_freezetag
 #ifdef SVQC
+
+#include <server/resources.qh>
+
 float autocvar_g_freezetag_frozen_maxtime;
 float autocvar_g_freezetag_revive_clearspeed;
 float autocvar_g_freezetag_round_timelimit;
@@ -11,27 +14,40 @@ float autocvar_g_freezetag_warmup;
 
 void freezetag_count_alive_players()
 {
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), {
-               switch(it.team)
+       total_players = 0;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
+       }
+       FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
+       {
+               ++total_players;
+               if ((GetResourceAmount(it, RESOURCE_HEALTH) < 1) ||
+                       (STAT(FROZEN, it) == 1))
                {
-                       case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
+                       continue;
                }
+               entity team_ = Entity_GetTeam(it);
+               int num_alive = Team_GetNumberOfAlivePlayers(team_);
+               ++num_alive;
+               Team_SetNumberOfAlivePlayers(team_, num_alive);
        });
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), {
-               STAT(REDALIVE, it) = redalive;
-               STAT(BLUEALIVE, it) = bluealive;
-               STAT(YELLOWALIVE, it) = yellowalive;
-               STAT(PINKALIVE, it) = pinkalive;
+       FOREACH_CLIENT(IS_REAL_CLIENT(it),
+       {
+               STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(
+                       1));
+               STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(2));
+               STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(3));
+               STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(
+                       Team_GetTeamFromIndex(4));
        });
 
        eliminatedPlayers.SendFlags |= 1;
 }
-#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == NumTeams(freezetag_teams))
+
+#define FREEZETAG_ALIVE_TEAMS_OK() (Team_GetNumberOfAliveTeams() == NumTeams(freezetag_teams))
 
 float freezetag_CheckTeams()
 {
@@ -51,14 +67,14 @@ float freezetag_CheckTeams()
                return 0;
        }
        int missing_teams_mask = 0;
-       if(freezetag_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(freezetag_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(freezetag_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(freezetag_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if ((freezetag_teams & Team_IndexToBit(i)) &&
+                       (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) == 0))
+               {
+                       missing_teams_mask |= Team_IndexToBit(i);
+               }
+       }
        if(prev_missing_teams_mask != missing_teams_mask)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
@@ -67,28 +83,28 @@ float freezetag_CheckTeams()
        return 0;
 }
 
-float freezetag_getWinnerTeam()
+int freezetag_getWinnerTeam()
 {
-       float winner_team = 0;
-       if(redalive >= 1)
-               winner_team = NUM_TEAM_1;
-       if(bluealive >= 1)
+       int winner_team = 0;
+       if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1)) >= 1)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_2;
+               winner_team = NUM_TEAM_1;
        }
-       if(yellowalive >= 1)
+       for (int i = 2; i <= NUM_TEAMS; ++i)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_3;
+               if (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) >= 1)
+               {
+                       if (winner_team != 0)
+                       {
+                               return 0;
+                       }
+                       winner_team = Team_IndexToTeam(i);
+               }
        }
-       if(pinkalive >= 1)
+       if (winner_team)
        {
-               if(winner_team) return 0;
-               winner_team = NUM_TEAM_4;
-       }
-       if(winner_team)
                return winner_team;
+       }
        return -1; // no player left
 }
 
@@ -110,8 +126,10 @@ float freezetag_CheckWinner()
                return 1;
        }
 
-       if(FREEZETAG_ALIVE_TEAMS() > 1)
+       if (Team_GetNumberOfAliveTeams() > 1)
+       {
                return 0;
+       }
 
        int winner_team = freezetag_getWinnerTeam();
        if(winner_team > 0)
@@ -139,14 +157,14 @@ float freezetag_CheckWinner()
 entity freezetag_LastPlayerForTeam(entity this)
 {
        entity last_pl = NULL;
-       FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
-               if(it.health >= 1)
-               if(!STAT(FROZEN, it))
-               if(SAME_TEAM(it, this))
-               if(!last_pl)
-                       last_pl = it;
-               else
-                       return NULL;
+       FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
+               if (!STAT(FROZEN, it) && GetResourceAmount(it, RESOURCE_HEALTH) >= 1)
+               {
+                       if (!last_pl)
+                               last_pl = it;
+                       else
+                               return NULL;
+               }
        });
        return last_pl;
 }
@@ -180,6 +198,7 @@ void freezetag_Add_Score(entity targ, entity attacker)
        // else nothing - got frozen by the game type rules themselves
 }
 
+// to be called when the player is frozen by freezetag (on death, spectator join etc), gives the score
 void freezetag_Freeze(entity targ, entity attacker)
 {
        if(STAT(FROZEN, targ))
@@ -195,14 +214,6 @@ void freezetag_Freeze(entity targ, entity attacker)
        freezetag_Add_Score(targ, attacker);
 }
 
-void freezetag_Unfreeze(entity this)
-{
-       this.freezetag_frozen_time = 0;
-       this.freezetag_frozen_timeout = 0;
-
-       Unfreeze(this);
-}
-
 float freezetag_isEliminated(entity e)
 {
        if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
@@ -232,7 +243,7 @@ void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org,
                {
                        // If teamate is not frozen still seek them out as fight better
                        // in a group.
-                       t = 0.2 * 150 / (this.health + this.armorvalue);
+                       t = 0.2 * 150 / (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR));
                        navigation_routerating(this, it, t * ratingscale, 2000);
                }
        });
@@ -308,10 +319,10 @@ void havocbot_role_ft_freeing(entity this)
 
 void ft_RemovePlayer(entity this)
 {
-       this.health = 0; // neccessary to update correctly alive stats
+       SetResourceAmountExplicit(this, RESOURCE_HEALTH, 0); // neccessary to update correctly alive stats
        if(!STAT(FROZEN, this))
                freezetag_LastPlayerForTeam_Notify(this);
-       freezetag_Unfreeze(this);
+       Unfreeze(this);
        freezetag_count_alive_players();
 }
 
@@ -340,7 +351,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
        if(round_handler_CountdownRunning())
        {
                if(STAT(FROZEN, frag_target))
-                       freezetag_Unfreeze(frag_target);
+                       Unfreeze(frag_target);
                freezetag_count_alive_players();
                return true; // let the player die so that he can respawn whenever he wants
        }
@@ -358,8 +369,8 @@ MUTATOR_HOOKFUNCTION(ft, PlayerDies)
                        freezetag_LastPlayerForTeam_Notify(frag_target);
                }
                else
-                       freezetag_Unfreeze(frag_target); // remove ice
-               frag_target.health = 0; // Unfreeze resets health
+                       Unfreeze(frag_target); // remove ice
+               SetResourceAmountExplicit(frag_target, RESOURCE_HEALTH, 0); // Unfreeze resets health
                frag_target.freezetag_frozen_timeout = -2; // freeze on respawn
                return true;
        }
@@ -427,6 +438,15 @@ MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
        return true;
 }
 
+MUTATOR_HOOKFUNCTION(ft, Unfreeze)
+{
+       entity targ = M_ARGV(0, entity);
+       targ.freezetag_frozen_time = 0;
+       targ.freezetag_frozen_timeout = 0;
+
+       freezetag_count_alive_players();
+}
+
 MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
 {
        if(game_stopped)
@@ -468,11 +488,11 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        if(n && STAT(FROZEN, player) == 1) // OK, there is at least one teammate reviving us
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
 
                if(STAT(REVIVE_PROGRESS, player) >= 1)
                {
-                       freezetag_Unfreeze(player);
+                       Unfreeze(player);
                        freezetag_count_alive_players();
 
                        if(n == -1)
@@ -502,7 +522,7 @@ MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
        else if(!n && STAT(FROZEN, player) == 1) // only if no teammate is nearby will we reset
        {
                STAT(REVIVE_PROGRESS, player) = bound(0, STAT(REVIVE_PROGRESS, player) - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
-               player.health = max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health));
+               SetResourceAmountExplicit(player, RESOURCE_HEALTH, max(1, STAT(REVIVE_PROGRESS, player) * ((warmup_stage) ? warmup_start_health : start_health)));
        }
        else if(!n && !STAT(FROZEN, player))
        {
@@ -540,9 +560,10 @@ MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ft, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ft, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = freezetag_teams;
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
@@ -564,7 +585,8 @@ MUTATOR_HOOKFUNCTION(ft, FragCenterMessage)
                return; // target was already frozen, so this is just pushing them off the cliff
 
        Send_Notification(NOTIF_ONE, frag_attacker, MSG_CHOICE, CHOICE_FRAG_FREEZE, frag_target.netname, kill_count_to_attacker, (IS_BOT_CLIENT(frag_target) ? -1 : CS(frag_target).ping));
-       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target, frag_attacker.health, frag_attacker.armorvalue, (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
+       Send_Notification(NOTIF_ONE, frag_target, MSG_CHOICE, CHOICE_FRAGGED_FREEZE, frag_attacker.netname, kill_count_to_target,
+               GetResourceAmount(frag_attacker, RESOURCE_HEALTH), GetResourceAmount(frag_attacker, RESOURCE_ARMOR), (IS_BOT_CLIENT(frag_attacker) ? -1 : CS(frag_attacker).ping));
 
        return true;
 }
@@ -577,7 +599,7 @@ void freezetag_Initialize()
 
        freezetag_teams = BITS(bound(2, freezetag_teams, 4));
        GameRules_scoring(freezetag_teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, {
-           field(SP_FREEZETAG_REVIVALS, "revivals", 0);
+               field(SP_FREEZETAG_REVIVALS, "revivals", 0);
        });
 
        round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);