entity spawnqueue_last;
entity champion;
float warmup;
-.float caplayer;
void PutObserverInServer();
void PutClientInServer();
float next_round;
-float redalive, bluealive, yellowalive, pinkalive;
-.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
-float red_players, blue_players, yellow_players, pink_players;
-float total_players;
-#define CA_TEAMS() ((red_players > 0) + (blue_players > 0) + (yellow_players > 0) + (pink_players > 0))
-#define CA_TEAMS_OK() (CA_TEAMS() == ca_teams)
/**
* Resets the state of all clients, items, flags, runes, keys, weapons, waypoints, ... of the map.
if(autocvar_g_arena_warmup > 0)
warmup += autocvar_g_arena_warmup;
}
- else if(g_ca)
- {
- 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);
else
PutObserverInServer();
}
- else if(g_ca && self.caplayer) {
- self.classname = "player";
- PutClientInServer();
- }
else
{
/*
if(gameover)
{
- if(warmup && time < warmup)
- {
- FOR_EACH_REALCLIENT(e)
- Send_CSQC_Centerprint_Generic_Expire(e, CPID_ROUND_STARTING);
- warmup = 0;
- }
- if(champion && g_arena)
+ if(champion)
{
FOR_EACH_REALCLIENT(e)
centerprint(e, strcat("The Champion is ", champion.netname));
f = ceil(warmup - time);
- if(g_ca)
- {
- if(inWarmupStage)
- allowed_to_spawn = 1;
- else if (warmup == 0) //first warmup or warmup cleared
- {
- if(CA_TEAMS_OK())
- 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;
- else if(champion && g_arena)
+ if(champion)
{
FOR_EACH_REALCLIENT(e)
centerprint(e, strcat("The Champion is ", champion.netname));
if(f != roundStartTime_prev) {
roundStartTime_prev = f;
- if(g_ca && !CA_TEAMS_OK()) {
- warmup = 0;
- return;
- }
-
if(f == 5)
Announce("prepareforbattle");
else if(f == 3)
Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
}
- if (g_arena) {
- FOR_EACH_CLIENT(e)
- {
- if(e.spawned && e.classname == "player")
- e.player_blocked = 1;
- }
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.spawned && e.classname == "player")
+ e.player_blocked = 1;
}
}
else if(f > -1 && f != roundStartTime_prev && !inWarmupStage)
{
roundStartTime_prev = f;
- if(g_ca) {
- if(CA_TEAMS_OK())
- allowed_to_spawn = 0;
- else
- {
- 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)
- {
- if(e.player_blocked)
- e.player_blocked = 0;
- }
+ FOR_EACH_CLIENT(e)
+ {
+ if(e.player_blocked)
+ e.player_blocked = 0;
}
}
champion = world;
}
-void count_players()
-{
- // count amount of players in each team
- total_players = red_players = blue_players = yellow_players = pink_players = 0;
- FOR_EACH_PLAYER(self) {
- if (self.team == COLOR_TEAM1)
- {
- red_players += 1;
- total_players += 1;
- }
- else if (self.team == COLOR_TEAM2)
- {
- blue_players += 1;
- total_players += 1;
- }
- else if (self.team == COLOR_TEAM3)
- {
- yellow_players += 1;
- total_players += 1;
- }
- else if (self.team == COLOR_TEAM4)
- {
- pink_players += 1;
- total_players += 1;
- }
- }
-}
-
-void count_alive_players()
-{
- 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 (self.team == COLOR_TEAM3 && self.health >= 1)
- yellowalive += 1;
- else if (self.team == COLOR_TEAM4 && self.health >= 1)
- pinkalive += 1;
- }
- FOR_EACH_REALCLIENT(self) {
- self.redalive_stat = redalive;
- self.bluealive_stat = bluealive;
- self.yellowalive_stat = yellowalive;
- self.pinkalive_stat = pinkalive;
- }
-}
-
-float CA_GetWinnerTeam()
-{
- float winner_team;
- if(redalive >= 1)
- winner_team = COLOR_TEAM1;
- if(bluealive >= 1)
- {
- if(winner_team) return 0;
- winner_team = COLOR_TEAM2;
- }
- if(yellowalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = COLOR_TEAM3;
- }
- if(pinkalive >= 1)
- {
- if(winner_team) return 0;
- winner_team = COLOR_TEAM4;
- }
- if(winner_team)
- return winner_team;
- return -1; // no player left
-}
-
/**
* This function finds out whether an arena round is over 1 player is left.
* It determines the last player who's still alive and saves it's entity reference
if(time < warmup + 1 || inWarmupStage || intermission_running)
return;
- if(g_ca) {
- float winner_team;
- if(allowed_to_spawn) // round is not started yet
- return;
- if(!next_round) {
- winner_team = CA_GetWinnerTeam();
- if(winner_team) {
- if(winner_team > 0) {
- FOR_EACH_CLIENT(self)
- centerprint(self, strcat(ColoredTeamName(winner_team), " wins the round"));
- TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
- }
- else //if(winner_team == -1) // no player left
- FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
- next_round = -1;
- }
- else if(time - warmup > autocvar_g_ca_round_timelimit) {
- FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
- next_round = time + 5;
- }
- }
- else if(next_round == -1) {
- // wait for killed players to be put as spectators
- if(!CA_TEAMS_OK())
- next_round = time + 5;
- }
- else if((next_round > 0 && next_round < time))
+ //extend next_round if it isn't set yet and only 1 player is spawned
+ if(!next_round)
+ if(numspawned < 2)
+ next_round = time + 3;
+
+ if(!arena_roundbased || (next_round && next_round < time && player_count > 1))
+ {
+ next_round = 0;
+
+ if(arena_roundbased)
{
- next_round = 0;
+ champion = find(world, classname, "player");
+ while(champion && champion.deadflag)
+ champion = find(champion, classname, "player");
reset_map(TRUE);
}
- } else { // arena
- //extend next_round if it isn't set yet and only 1 player is spawned
- if(!next_round)
- if(numspawned < 2)
- next_round = time + 3;
- if(!arena_roundbased || (next_round && next_round < time && player_count > 1))
+ while(numspawned < maxspawned && spawnqueue_first)
{
- next_round = 0;
+ self = spawnqueue_first;
- if(arena_roundbased)
- {
- champion = find(world, classname, "player");
- while(champion && champion.deadflag)
- champion = find(champion, classname, "player");
- reset_map(TRUE);
- }
-
- while(numspawned < maxspawned && spawnqueue_first)
- {
- self = spawnqueue_first;
-
- bprint ("^4", self.netname, "^4 is the next challenger\n");
+ bprint ("^4", self.netname, "^4 is the next challenger\n");
- Spawnqueue_Remove(self);
- Spawnqueue_Mark(self);
+ Spawnqueue_Remove(self);
+ Spawnqueue_Mark(self);
- self.classname = "player";
- PutClientInServer();
- }
+ self.classname = "player";
+ PutClientInServer();
}
}
}
void Arena_Main()
{
- if(!(g_ca || g_arena))
+ if(!g_arena)
return;
-
- if(g_ca)
- {
- count_players();
- count_alive_players();
- }
- if(!g_arena || arena_roundbased)
+ if(arena_roundbased)
Arena_Warmup();
Spawnqueue_Check();
}
Spawnqueue_Remove(self);
Spawnqueue_Mark(self);
}
- else if(g_ca)
- self.caplayer = 1;
self.event_damage = PlayerDamage;
self.stat_allow_oldnexbeam = autocvar_g_allow_oldnexbeam;
self.stat_leadlimit = autocvar_leadlimit;
- if(g_arena || (g_ca && !allowed_to_spawn))
+ if(g_arena)
self.stat_respawn_time = 0;
else
self.stat_respawn_time = self.respawn_time;
float valid_damage_for_weaponstats;
float excess;
- if((g_arena && numspawned < 2) || (g_ca && allowed_to_spawn) && !inWarmupStage)
+ if((g_arena && numspawned < 2) && !inWarmupStage)
return;
dh = max(self.health, 0);
if (frametime)
self.weapon_frametime = frametime;
- if(((arena_roundbased || g_ca) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
+ if(((g_arena && arena_roundbased) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
return;
if(round_handler_IsActive() && !round_handler_IsRoundStarted())
{
if(nJoinAllowed(self))
{
- if(g_ca) { self.caplayer = 1; }
if(autocvar_g_campaign) { campaign_bots_may_start = 1; }
-
+
self.classname = "player";
PlayerScore_Clear(self);
bprint ("^4", self.netname, "^4 is playing now\n");
float maxclients;
-float ca_teams;
-
// Fields
.void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
.float hagar_load;
-float allowed_to_spawn; // boolean variable used by the clan arena code to determine if a player can spawn (after the round has ended)
-
float serverflags;
.float team_forced; // can be a team number to force a team, or 0 for default action, or -1 for forced spectator
MUTATOR_HOOKABLE(reset_map_players);
// called in reset_map
+MUTATOR_HOOKABLE(ForbidPlayerScore_Clear);
+ // returns 1 if clearing player score shall not be allowed
+
MUTATOR_HOOKABLE(ClientDisconnect);
// called when a player disconnects
--- /dev/null
+void CA_count_alive_players()
+{
+ entity e;
+ total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+ FOR_EACH_PLAYER(e) {
+ if(e.team == COLOR_TEAM1)
+ {
+ ++total_players;
+ if (e.health >= 1) ++redalive;
+ }
+ else if(e.team == COLOR_TEAM2)
+ {
+ ++total_players;
+ if (e.health >= 1) ++bluealive;
+ }
+ else if(e.team == COLOR_TEAM3)
+ {
+ ++total_players;
+ if (e.health >= 1) ++yellowalive;
+ }
+ else if(e.team == COLOR_TEAM4)
+ {
+ ++total_players;
+ if (e.health >= 1) ++pinkalive;
+ }
+ }
+ FOR_EACH_REALCLIENT(e) {
+ e.redalive_stat = redalive;
+ e.bluealive_stat = bluealive;
+ e.yellowalive_stat = yellowalive;
+ e.pinkalive_stat = pinkalive;
+ }
+}
+
+float CA_GetWinnerTeam()
+{
+ float winner_team;
+ if(redalive >= 1)
+ winner_team = COLOR_TEAM1;
+ if(bluealive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = COLOR_TEAM2;
+ }
+ if(yellowalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = COLOR_TEAM3;
+ }
+ if(pinkalive >= 1)
+ {
+ if(winner_team) return 0;
+ winner_team = COLOR_TEAM4;
+ }
+ if(winner_team)
+ return winner_team;
+ return -1; // no player left
+}
+
+float CA_CheckWinner()
+{
+ // TODO round tied if(time - warmup > autocvar_g_ca_round_timelimit
+
+ if(inWarmupStage)
+ allowed_to_spawn = TRUE;
+ else
+ allowed_to_spawn = FALSE;
+
+ CA_count_alive_players();
+ if(CA_ALIVE_TEAMS() > 1)
+ return 0;
+
+ entity e;
+ float winner_team;
+ string teamname;
+ winner_team = CA_GetWinnerTeam();
+ if(winner_team > 0)
+ {
+ teamname = ColoredTeamName(winner_team);
+ FOR_EACH_REALCLIENT(e)
+ centerprint(e, strcat(teamname, " wins the round"));
+ bprint(teamname, " wins the round.\n");
+ TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
+ }
+ else if(winner_team == -1)
+ {
+ FOR_EACH_REALCLIENT(e)
+ centerprint(e, "Round tied");
+ bprint("Round tied.\n");
+ }
+
+ allowed_to_spawn = TRUE;
+ return 1;
+}
+
+float prev_total_players;
+float CA_CheckTeams()
+{
+ entity e;
+ allowed_to_spawn = TRUE;
+ CA_count_alive_players();
+ if(CA_ALIVE_TEAMS_OK())
+ {
+ 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), ", ");
+ if(ca_teams >= 3)
+ if(!yellowalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM3), ", ");
+ if(ca_teams == 4)
+ if(!pinkalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM4), ", ");
+ 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;
+}
+
+MUTATOR_HOOKFUNCTION(ca_PlayerSpawn)
+{
+ self.caplayer = TRUE;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_reset_map_players)
+{
+ FOR_EACH_CLIENT(self)
+ {
+ if(self.caplayer)
+ {
+ self.classname = "player";
+ PutClientInServer();
+ }
+ }
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_reset_map_global)
+{
+ allowed_to_spawn = TRUE;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_GetTeamCount)
+{
+ ca_teams = autocvar_g_ca_teams_override;
+ if(ca_teams < 2)
+ ca_teams = autocvar_g_ca_teams;
+ ca_teams = bound(2, ca_teams, 4);
+ ret_float = ca_teams;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_PlayerPreThink)
+{
+ if(!allowed_to_spawn)
+ self.stat_respawn_time = 0;
+ return 1;
+}
+
+MUTATOR_HOOKFUNCTION(ca_ForbidPlayerScore_Clear)
+{
+ return 1;
+}
+
+void ca_Initialize()
+{
+ allowed_to_spawn = TRUE;
+
+ round_handler_Spawn(CA_CheckTeams, CA_CheckWinner, 5, autocvar_g_ca_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);
+}
+
+MUTATOR_DEFINITION(gamemode_ca)
+{
+ MUTATOR_HOOK(PlayerSpawn, ca_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_global, ca_reset_map_global, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, ca_reset_map_players, CBC_ORDER_ANY);
+ MUTATOR_HOOK(GetTeamCount, ca_GetTeamCount, CBC_ORDER_EXCLUSIVE);
+ MUTATOR_HOOK(PlayerPreThink, ca_PlayerPreThink, CBC_ORDER_ANY);
+ MUTATOR_HOOK(ForbidPlayerScore_Clear, ca_ForbidPlayerScore_Clear, CBC_ORDER_ANY);
+
+ MUTATOR_ONADD
+ {
+ if(time > 1) // game loads at time 1
+ error("This is a game type and it cannot be added at runtime.");
+ ca_Initialize();
+ }
+
+ MUTATOR_ONREMOVE
+ {
+ error("This is a game type and it cannot be removed at runtime.");
+ }
+
+ return 0;
+}
--- /dev/null
+.float caplayer;
+float total_players;
+float redalive, bluealive, yellowalive, pinkalive;
+.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
+#define CA_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define CA_ALIVE_TEAMS_OK() (CA_ALIVE_TEAMS() == ca_teams)
+float ca_teams;
+
+float allowed_to_spawn;
+
+MUTATOR_DECLARATION(gamemode_ca);
MUTATOR_DECLARATION(gamemode_keyhunt);
MUTATOR_DECLARATION(gamemode_freezetag);
MUTATOR_DECLARATION(gamemode_keepaway);
mutators/base.qh
mutators/mutators.qh
+mutators/gamemode_ca.qh
mutators/gamemode_ctf.qh
mutators/gamemode_keyhunt.qh // TODO fix this
mutators/gamemode_keepaway.qh
../common/explosion_equation.qc
mutators/base.qc
+mutators/gamemode_ca.qc
mutators/gamemode_ctf.qc
mutators/gamemode_freezetag.qc
mutators/gamemode_keyhunt.qc
if(teamscores_entities_count)
return;
+ if(MUTATOR_CALLHOOK(ForbidPlayerScore_Clear)) return;
if(g_lms) return;
- if(g_arena || g_ca) return;
+ if(g_arena) return;
if(g_cts) return; // in CTS, you don't lose score by observing
if(g_race && g_race_qualifying) return; // in qualifying, you don't lose score by observing
ActivateTeamplay();
fraglimit_override = autocvar_g_ca_point_limit;
leadlimit_override = autocvar_g_ca_point_leadlimit;
- allowed_to_spawn = TRUE;
- ca_teams = autocvar_g_ca_teams_override;
- if(ca_teams < 2)
- ca_teams = autocvar_g_ca_teams;
- ca_teams = bound(2, ca_teams, 4);
- 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);
+ MUTATOR_ADD(gamemode_ca);
}
if(g_keyhunt)
{
// cover anything else by treating it like tdm with no teams spawned
if(g_race)
dm = race_teams;
- else if(g_ca)
- dm = ca_teams;
else
dm = 2;