seta hud_panel_modicons_bg_alpha "" "if set to something else than \"\" = override default panel background alpha"
seta hud_panel_modicons_bg_border "" "if set to something else than \"\" = override default size of border around the background"
seta hud_panel_modicons_bg_padding "" "if set to something else than \"\" = override default padding of contents from border"
+seta hud_panel_modicons_ca_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
seta hud_panel_modicons_dom_layout "" "3 possible layouts: 0) only icons; 1) icons and percentage of average pps (points per second); 2) icons and average pps"
+seta hud_panel_modicons_freezetag_layout "" "2 possible layouts: 0) number of alive players; 1) icons and number of alive players"
seta hud_panel_pressedkeys "" "enable/disable this panel, 1 = show only when spectating other players, 2 = show always"
seta hud_panel_pressedkeys_pos "" "position of this base of the panel"
set g_ca_warmup 10 "how long the players will have time to run around the map before the round starts"
set g_ca_damage2score_multiplier 0.01
set g_ca_round_timelimit 180
+seta g_ca_teams_override 0
+set g_ca_teams 0
+
// ==================
seta g_freezetag_revive_clearspeed 1.6 "Speed at which reviving progress gets lost when out of range"
seta g_freezetag_revive_extra_size 100 "Distance in qu that you can stand from a frozen teammate to keep reviving him"
seta g_freezetag_frozen_force 0.6 "How much to multiply the force on a frozen player with"
+seta g_freezetag_teams_override 0
+set g_freezetag_teams 0
// ==========
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding "0"
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.720000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.650000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.450000 0.690000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.410000 0.710000"
seta hud_panel_modicons_bg_alpha ""
seta hud_panel_modicons_bg_border ""
seta hud_panel_modicons_bg_padding ""
+seta hud_panel_modicons_ca_layout "1"
seta hud_panel_modicons_dom_layout "1"
+seta hud_panel_modicons_freezetag_layout "1"
seta hud_panel_pressedkeys 1
seta hud_panel_pressedkeys_pos "0.440000 0.760000"
float autocvar_hud_panel_infomessages;
float autocvar_hud_panel_infomessages_flip;
float autocvar_hud_panel_modicons;
+float autocvar_hud_panel_modicons_ca_layout;
float autocvar_hud_panel_modicons_dom_layout;
+float autocvar_hud_panel_modicons_freezetag_layout;
float autocvar_hud_panel_notify;
float autocvar_hud_panel_notify_fadetime;
float autocvar_hud_panel_notify_flip;
float mod_active; // is there any active mod icon?
-// Clan Arena HUD modicons
-void HUD_Mod_CA(vector pos, vector mySize)
+void DrawCAItem(vector myPos, vector mySize, float aspect_ratio, float layout, float i)
{
- mod_active = 1; // CA should never hide the mod icons panel
- float redalive, bluealive;
- redalive = getstati(STAT_REDALIVE);
- bluealive = getstati(STAT_BLUEALIVE);
+ float stat;
+ string pic;
+ vector color;
+ switch(i)
+ {
+ case 0:
+ stat = getstati(STAT_REDALIVE);
+ pic = "player_red.tga";
+ color = '1 0 0';
+ break;
+ case 1:
+ stat = getstati(STAT_BLUEALIVE);
+ pic = "player_blue.tga";
+ color = '0 0 1';
+ break;
+ case 2:
+ stat = getstati(STAT_YELLOWALIVE);
+ pic = "player_yellow.tga";
+ color = '1 1 0';
+ break;
+ case 3:
+ stat = getstati(STAT_PINKALIVE);
+ pic = "player_pink.tga";
+ color = '1 0 1';
+ }
- vector redpos, bluepos;
- if(mySize_x > mySize_y)
+ if(mySize_x/mySize_y > aspect_ratio)
{
- redpos = pos;
- bluepos = pos + eY * 0.5 * mySize_y;
- drawpic_aspect_skin(redpos, "player_red.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(redpos + eX * 0.5 * mySize_x, ftos(redalive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(bluepos, "player_blue.tga", 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(bluepos + eX * 0.5 * mySize_x, ftos(bluealive), 0.5 * mySize, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ i = aspect_ratio * mySize_y;
+ myPos_x = myPos_x + (mySize_x - i) / 2;
+ mySize_x = i;
}
else
{
- redpos = pos;
- bluepos = pos + eY * 0.5 * mySize_y;
- drawpic_aspect_skin(redpos, "player_red.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(redpos + eY * 0.3 * mySize_y, ftos(redalive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawpic_aspect_skin(bluepos, "player_blue.tga", eX * mySize_x + eY * 0.3 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
- drawstring_aspect(bluepos + eY * 0.3 * mySize_y, ftos(bluealive), eX * mySize_x + eY * 0.2 * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ i = 1/aspect_ratio * mySize_x;
+ myPos_y = myPos_y + (mySize_y - i) / 2;
+ mySize_y = i;
+ }
+
+ if(layout)
+ {
+ drawpic_aspect_skin(myPos, pic, eX * 0.7 * mySize_x + eY * mySize_y, '1 1 1', panel_fg_alpha, DRAWFLAG_NORMAL);
+ drawstring_aspect(myPos + eX * 0.7 * mySize_x, ftos(stat), eX * 0.3 * mySize_x + eY * mySize_y, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+ }
+ else
+ drawstring_aspect(myPos, ftos(stat), mySize, color, panel_fg_alpha, DRAWFLAG_NORMAL);
+}
+
+// Clan Arena and Freeze Tag HUD modicons
+void HUD_Mod_CA(vector myPos, vector mySize)
+{
+ mod_active = 1; // required in each mod function that always shows something
+ entity tm;
+ float teams_count;
+ for(tm = teams.sort_next; tm; tm = tm.sort_next)
+ if(tm.team != COLOR_SPECTATOR)
+ ++teams_count;
+
+ float layout;
+ if(gametype == MAPINFO_TYPE_CA)
+ layout = autocvar_hud_panel_modicons_ca_layout;
+ else //if(gametype == MAPINFO_TYPE_FREEZETAG)
+ layout = autocvar_hud_panel_modicons_freezetag_layout;
+ float rows, columns, aspect_ratio;
+ rows = mySize_y/mySize_x;
+ aspect_ratio = (layout) ? 2 : 1;
+ rows = bound(1, floor((sqrt((4 * aspect_ratio * teams_count + rows) * rows) + rows + 0.5) / 2), teams_count);
+ columns = ceil(teams_count/rows);
+
+ int i;
+ float row, column;
+ for(i=0; i<teams_count; ++i)
+ {
+ vector pos, itemSize;
+ pos = myPos + eX * column * mySize_x*(1/columns) + eY * row * mySize_y*(1/rows);
+ itemSize = eX * mySize_x*(1/columns) + eY * mySize_y*(1/rows);
+
+ DrawCAItem(pos, itemSize, aspect_ratio, layout, i);
+
+ ++row;
+ if(row >= rows)
+ {
+ row = 0;
+ ++column;
+ }
}
}
HUD_Write_PanelCvar_q("_alreadyvoted_alpha");
break;
case HUD_PANEL_MODICONS:
+ HUD_Write_PanelCvar_q("_ca_layout");
HUD_Write_PanelCvar_q("_dom_layout");
+ HUD_Write_PanelCvar_q("_freezetag_layout");
break;
case HUD_PANEL_PRESSEDKEYS:
HUD_Write_PanelCvar_q("_attack");
.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.
allowed_to_spawn = 1;
else if (warmup == 0) //first warmup or warmup cleared
{
- if (red_players && blue_players)
+ if(CA_TEAMS_OK())
reset_map(TRUE);
else if(f != roundStartTime_prev)
{
if(f != roundStartTime_prev) {
roundStartTime_prev = f;
- if(g_ca && !(red_players && blue_players)) {
+ if(g_ca && !CA_TEAMS_OK()) {
warmup = 0;
return;
}
{
roundStartTime_prev = f;
if(g_ca) {
- if(red_players && blue_players)
+ if(CA_TEAMS_OK())
allowed_to_spawn = 0;
else
{
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
return;
if(g_ca) {
+ float winner_team;
if(allowed_to_spawn) // round is not started yet
return;
if(!next_round) {
- if(!(redalive && bluealive)) {
- // every player of (at least) one team is dead, round ends here
- if(redalive) {
- play2all("ctf/red_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^1RED ^7team wins the round");
- TeamScore_AddToTeam(COLOR_TEAM1, ST_SCORE, +1);
+ 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(bluealive) {
- play2all("ctf/blue_capture.wav");
- FOR_EACH_CLIENT(self) centerprint(self, "^4BLUE ^7team wins the round");
- TeamScore_AddToTeam(COLOR_TEAM2, ST_SCORE, +1);
- }
- else
+ else //if(winner_team == -1) // no player left
FOR_EACH_CLIENT(self) centerprint(self, "^7Round tied");
next_round = -1;
}
}
else if(next_round == -1) {
// wait for killed players to be put as spectators
- if(!(red_players && blue_players))
+ if(!CA_TEAMS_OK())
next_round = time + 5;
}
else if((next_round > 0 && next_round < time))
float autocvar_g_ca_point_limit;
float autocvar_g_ca_round_timelimit;
float autocvar_g_ca_spectate_enemies;
+float autocvar_g_ca_teams;
+float autocvar_g_ca_teams_override;
float autocvar_g_ca_warmup;
float autocvar_g_campaign;
#define autocvar_g_campaign_forceteam cvar("g_campaign_forceteam")
float autocvar_g_freezetag_revive_extra_size;
float autocvar_g_freezetag_revive_speed;
float autocvar_g_freezetag_revive_clearspeed;
+float autocvar_g_freezetag_teams;
+float autocvar_g_freezetag_teams_override;
float autocvar_g_freezetag_warmup;
#define autocvar_g_friendlyfire cvar("g_friendlyfire")
#define autocvar_g_friendlyfire_virtual cvar("g_friendlyfire_virtual")
float maxclients;
+float ca_teams;
+
// Fields
.void(entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force) event_damage;
addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
- if(g_ca)
- {
- addstat(STAT_REDALIVE, AS_INT, redalive_stat);
- addstat(STAT_BLUEALIVE, AS_INT, bluealive_stat);
- }
-
// g_movementspeed hack
addstat(STAT_MOVEVARS_AIRSPEEDLIMIT_NONQW, AS_FLOAT, stat_sv_airspeedlimit_nonqw);
addstat(STAT_MOVEVARS_MAXSPEED, AS_FLOAT, stat_sv_maxspeed);
+float freezetag_teams;
float freezetag_CheckTeams();
float freezetag_CheckWinner();
void freezetag_Initialize()
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 1; // we still have active players on two or more teams, nobody won yet
- return 0;
-}
+#define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
+#define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
float prev_total_players;
float freezetag_CheckTeams()
{
entity e;
- if(freezetag_TeamsCanPlay())
+ if(FREEZETAG_ALIVE_TEAMS_OK())
{
if(prev_total_players != -1)
{
string teams_missing;
if(!redalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM1), ", ");
if(!bluealive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM2), ", ");
+ if(freezetag_teams >= 3)
+ if(!yellowalive) teams_missing = strcat(teams_missing, ColoredTeamName(COLOR_TEAM3), ", ");
+ if(freezetag_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)
}
return 0;
}
+
+float freezetag_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 freezetag_CheckWinner()
{
- if(freezetag_TeamsCanPlay())
+ if(FREEZETAG_ALIVE_TEAMS() > 1)
return 0;
- entity e, winner;
+ entity e;
+ float winner_team;
string teamname;
- winner = world;
-
- FOR_EACH_PLAYER(e)
- {
- if(e.freezetag_frozen == 0 && e.health >= 1) // here's one player from the winning team... good
- {
- winner = e;
- break; // break, we found the winner
- }
- }
-
- if(winner != world) // just in case a winner wasn't found
+ winner_team = freezetag_getWinnerTeam();
+ if(winner_team > 0)
{
- teamname = ColoredTeamName(winner.team);
+ 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);
+ TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
+ }
+ else if(winner_team == -1)
+ {
+ FOR_EACH_REALCLIENT(e)
+ centerprint(e, "^5Round tied! All teams were frozen.");
+ bprint("^5Round tied! All teams were frozen.\n");
}
return 1;
return 0;
}
+MUTATOR_HOOKFUNCTION(freezetag_GetTeamCount)
+{
+ freezetag_teams = autocvar_g_freezetag_teams_override;
+ if(freezetag_teams < 2)
+ freezetag_teams = autocvar_g_freezetag_teams;
+ freezetag_teams = bound(2, freezetag_teams, 4);
+ ret_float = freezetag_teams;
+ return 0;
+}
+
MUTATOR_DEFINITION(gamemode_freezetag)
{
MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
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_HOOK(GetTeamCount, freezetag_GetTeamCount, CBC_ORDER_EXCLUSIVE);
MUTATOR_ONADD
{
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");
+ 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);
}
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;