]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/server/mutators/mutator/gamemode_ca.qc
Merge branch 'master' into Lyberta/TeamplayOverhaul
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator / gamemode_ca.qc
index 44c9d1592a4da0e78230d3d0c0993045341294fe..52fc272dcb46182ac457c43706d230eeb57af031 100644 (file)
@@ -5,68 +5,83 @@ bool autocvar_g_ca_spectate_enemies;
 
 void CA_count_alive_players()
 {
-       total_players = redalive = bluealive = yellowalive = pinkalive = 0;
-       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
-               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 (IS_DEAD(it))
                {
-                       case NUM_TEAM_1: ++total_players; if(!IS_DEAD(it)) ++redalive; break;
-                       case NUM_TEAM_2: ++total_players; if(!IS_DEAD(it)) ++bluealive; break;
-                       case NUM_TEAM_3: ++total_players; if(!IS_DEAD(it)) ++yellowalive; break;
-                       case NUM_TEAM_4: ++total_players; if(!IS_DEAD(it)) ++pinkalive; break;
+                       continue;
                }
-       ));
-       FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
-               it.redalive_stat = redalive;
-               it.bluealive_stat = bluealive;
-               it.yellowalive_stat = yellowalive;
-               it.pinkalive_stat = pinkalive;
-       ));
+               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) = 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));
+       });
 }
 
-float CA_GetWinnerTeam()
+int CA_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
 }
 
 void nades_Clear(entity player);
 
-#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
-#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == NumTeams(ca_teams))
+#define CA_ALIVE_TEAMS_OK() (Team_GetNumberOfAliveTeams() == NumTeams(ca_teams))
 float CA_CheckWinner()
 {
        if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
        {
                Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
                Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
+               FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
+
                allowed_to_spawn = false;
+               game_stopped = true;
                round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
-               FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(nades_Clear(it)));
                return 1;
        }
 
        CA_count_alive_players();
-       if(CA_ALIVE_TEAMS() > 1)
+       if (Team_GetNumberOfAliveTeams() > 1)
+       {
                return 0;
+       }
 
        int winner_team = CA_GetWinnerTeam();
        if(winner_team > 0)
@@ -82,9 +97,10 @@ float CA_CheckWinner()
        }
 
        allowed_to_spawn = false;
+       game_stopped = true;
        round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
 
-       FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(nades_Clear(it)));
+       FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
 
        return 1;
 }
@@ -114,14 +130,14 @@ bool CA_CheckTeams()
                return false;
        }
        int missing_teams_mask = 0;
-       if(ca_teams & BIT(0))
-               missing_teams_mask += (!redalive) * 1;
-       if(ca_teams & BIT(1))
-               missing_teams_mask += (!bluealive) * 2;
-       if(ca_teams & BIT(2))
-               missing_teams_mask += (!yellowalive) * 4;
-       if(ca_teams & BIT(3))
-               missing_teams_mask += (!pinkalive) * 8;
+       for (int i = 1; i <= NUM_TEAMS; ++i)
+       {
+               if ((ca_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);
@@ -185,7 +201,7 @@ MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
        if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
        {
                TRANSMUTE(Observer, player);
-               if (player.jointime != time && !player.caplayer) // not when connecting
+               if (CS(player).jointime != time && !player.caplayer) // not when connecting
                {
                        player.caplayer = 0.5;
                        Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
@@ -196,7 +212,7 @@ MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
 MUTATOR_HOOKFUNCTION(ca, reset_map_players)
 {
        FOREACH_CLIENT(true, {
-               it.killcount = 0;
+               CS(it).killcount = 0;
                if (!it.caplayer && IS_BOT_CLIENT(it))
                {
                        it.team = -1;
@@ -227,9 +243,10 @@ MUTATOR_HOOKFUNCTION(ca, reset_map_global)
        return true;
 }
 
-MUTATOR_HOOKFUNCTION(ca, CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
+MUTATOR_HOOKFUNCTION(ca, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
 {
        M_ARGV(0, float) = ca_teams;
+       return true;
 }
 
 entity ca_LastPlayerForTeam(entity this)
@@ -263,7 +280,12 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDies)
 
        ca_LastPlayerForTeam_Notify(frag_target);
        if (!allowed_to_spawn)
-               frag_target.respawn_flags =  RESPAWN_SILENT;
+       {
+               frag_target.respawn_flags = RESPAWN_SILENT;
+               // prevent unwanted sudden rejoin as spectator and movement of spectator camera
+               frag_target.respawn_time = time + 2;
+       }
+       frag_target.respawn_flags |= RESPAWN_FORCE;
        if (!warmup_stage)
                eliminatedPlayers.SendFlags |= 1;
        if(IS_BOT_CLIENT(frag_target))
@@ -363,7 +385,13 @@ MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
        float excess = max(0, frag_damage - damage_take - damage_save);
 
        if (frag_target != frag_attacker && IS_PLAYER(frag_attacker))
-               PlayerTeamScore_Add(frag_attacker, SP_SCORE, ST_SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
+               GameRules_scoring_add_team(frag_attacker, SCORE, (frag_damage - excess) * autocvar_g_ca_damage2score_multiplier);
+}
+
+MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
+{
+       // no respawn calculations needed, player is forced to spectate anyway
+       return true;
 }
 
 MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
@@ -455,6 +483,11 @@ MUTATOR_HOOKFUNCTION(ca, WantWeapon)
        M_ARGV(2, bool) = true; // all weapons
 }
 
+MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
+{
+       return true; // doesn't work well with the whole spectator as player thing
+}
+
 MUTATOR_HOOKFUNCTION(ca, GetPlayerStatus)
 {
        entity player = M_ARGV(0, entity);