// TODO: sv_freezetag
#ifdef SVQC
+
#include <server/resources.qh>
float autocvar_g_freezetag_frozen_maxtime;
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(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++redalive; break;
- case NUM_TEAM_2: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++bluealive; break;
- case NUM_TEAM_3: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 1) ++yellowalive; break;
- case NUM_TEAM_4: ++total_players; if(STAT(FROZEN, it) != 1 && GetResourceAmount(it, RESOURCE_HEALTH) >= 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()
{
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);
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
}
return 1;
}
- if(FREEZETAG_ALIVE_TEAMS() > 1)
+ if (Team_GetNumberOfAliveTeams() > 1)
+ {
return 0;
+ }
int winner_team = freezetag_getWinnerTeam();
if(winner_team > 0)
void(entity this) havocbot_role_ft_freeing;
void(entity this) havocbot_role_ft_offense;
-void havocbot_goalrating_freeplayers(entity this, float ratingscale, vector org, float sradius)
+void havocbot_goalrating_ft_freeplayers(entity this, float ratingscale, vector org, float sradius)
{
- float t;
+ entity best_pl = NULL;
+ float best_dist2 = FLOAT_MAX;
FOREACH_CLIENT(IS_PLAYER(it) && it != this && SAME_TEAM(it, this), {
if (STAT(FROZEN, it) == 1)
{
continue;
navigation_routerating(this, it, ratingscale, 2000);
}
- else if(vdist(it.origin - org, >, 400)) // avoid gathering all teammates in one place
+ else if (best_dist2
+ && GetResourceAmount(it, RESOURCE_HEALTH) < GetResourceAmount(this, RESOURCE_HEALTH) + 30
+ && vlen2(it.origin - org) < best_dist2)
{
// If teamate is not frozen still seek them out as fight better
// in a group.
- t = 0.2 * 150 / (GetResourceAmount(this, RESOURCE_HEALTH) + GetResourceAmount(this, RESOURCE_ARMOR));
- navigation_routerating(this, it, t * ratingscale, 2000);
+ best_dist2 = vlen2(it.origin - org);
+ if (best_dist2 < 700 ** 2)
+ {
+ best_pl = NULL;
+ best_dist2 = 0; // already close to a teammate
+ }
+ else
+ best_pl = it;
}
});
+ if (best_pl)
+ navigation_routerating(this, best_pl, ratingscale / 2, 2000);
}
void havocbot_role_ft_offense(entity this)
// Count how many players on team are unfrozen.
int unfrozen = 0;
- FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !(STAT(FROZEN, it) != 1), { unfrozen++; });
+ FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, this) && !STAT(FROZEN, it), { unfrozen++; });
// If only one left on team or if role has timed out then start trying to free players.
- if (((unfrozen == 0) && (!STAT(FROZEN, this))) || (time > this.havocbot_role_timeout))
+ if ((unfrozen == 0 && !STAT(FROZEN, this)) || time > this.havocbot_role_timeout)
{
LOG_TRACE("changing role to freeing");
this.havocbot_role = havocbot_role_ft_freeing;
if (navigation_goalrating_timeout(this))
{
navigation_goalrating_start(this);
- havocbot_goalrating_items(this, 10000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 20000, this.origin, 10000);
- havocbot_goalrating_freeplayers(this, 9000, this.origin, 10000);
+ havocbot_goalrating_items(this, 12000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
+ havocbot_goalrating_ft_freeplayers(this, 9000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
if (navigation_goalrating_timeout(this))
{
navigation_goalrating_start(this);
- havocbot_goalrating_items(this, 8000, this.origin, 10000);
- havocbot_goalrating_enemyplayers(this, 10000, this.origin, 10000);
- havocbot_goalrating_freeplayers(this, 20000, this.origin, 10000);
+ havocbot_goalrating_items(this, 10000, this.origin, 10000);
+ havocbot_goalrating_enemyplayers(this, 5000, this.origin, 10000);
+ havocbot_goalrating_ft_freeplayers(this, 20000, this.origin, 10000);
havocbot_goalrating_waypoints(this, 1, this.origin, 3000);
navigation_goalrating_end(this);
bot.havocbot_role = havocbot_role_ft_offense;
}
+ // if bots spawn all at once assign them a more appropriated role after a while
+ if (time < CS(bot).jointime + 1)
+ bot.havocbot_role_timeout = time + 10 + random() * 10;
+
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)