float CPID_MOTD = 9;
float CPID_KH_MSG = 10;
float CPID_PREVENT_JOIN = 11;
+float CPID_WAITING_PLAYERS = 12;
// CSQC centerprint/notify message types
float MSG_SUICIDE = 0;
float next_round;
float redalive, bluealive, yellowalive, pinkalive;
-float totalalive;
.float redalive_stat, bluealive_stat, yellowalive_stat, pinkalive_stat;
float red_players, blue_players, yellow_players, pink_players;
float total_players;
entity oldself;
oldself = self;
- if(g_arena && autocvar_g_arena_warmup)
- warmup = time + autocvar_g_arena_warmup;
- else if(g_ca) {
- warmup = time + autocvar_g_ca_warmup;
- allowed_to_spawn = 1;
+ if(time <= game_starttime && round_handler_IsActive())
+ round_handler_Reset(game_starttime + 1);
+
+ if(g_arena)
+ {
+ warmup = max(time, game_starttime);
+ if(autocvar_g_arena_warmup > 0)
+ warmup += autocvar_g_arena_warmup;
}
- else if(g_freezetag)
+ else if(g_ca)
{
- warmup = time + autocvar_g_freezetag_warmup;
+ 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);
lms_lowest_lives = 999;
lms_next_place = player_count;
- race_ReadyRestart();
-
for(self = world; (self = nextent(self)); )
if(clienttype(self) == CLIENTTYPE_NOTACLIENT)
{
// Moving the player reset code here since the player-reset depends
// on spawnpoint entities which have to be reset first --blub
if(dorespawn)
+ if(!MUTATOR_CALLHOOK(reset_map_players))
FOR_EACH_CLIENT(self) {
if(self.flags & FL_CLIENT) // reset all players
{
self.classname = "player";
PutClientInServer();
}
- else if(g_freezetag)
- {
- if(self.classname == "player")
- PutClientInServer();
- }
else
{
/*
}
return;
}
- if((!g_arena && !g_ca && !g_freezetag) || (g_arena && !arena_roundbased) || (time < game_starttime))
+ if(time < game_starttime)
return;
f = ceil(warmup - time);
- if(inWarmupStage)
- allowed_to_spawn = 1;
- else if(!g_ca)
- allowed_to_spawn = 0;
+ if(g_ca)
+ {
+ if(inWarmupStage)
+ allowed_to_spawn = 1;
+ else if (warmup == 0) //first warmup or warmup cleared
+ {
+ if (red_players && blue_players)
+ 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;
- if(champion && g_arena)
+ else if(champion && g_arena)
{
FOR_EACH_REALCLIENT(e)
centerprint(e, strcat("The Champion is ", champion.netname));
if(f != roundStartTime_prev) {
roundStartTime_prev = f;
+
if(g_ca && !(red_players && blue_players)) {
- 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);
- warmup = time + autocvar_g_ca_warmup;
- } else {
- if(f == 5)
- Announce("prepareforbattle");
- else if(f == 3)
- Announce("3");
- else if(f == 2)
- Announce("2");
- else if(f == 1)
- Announce("1");
-
- FOR_EACH_REALCLIENT(e)
- Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
+ warmup = 0;
+ return;
}
+
+ if(f == 5)
+ Announce("prepareforbattle");
+ else if(f == 3)
+ Announce("3");
+ else if(f == 2)
+ Announce("2");
+ else if(f == 1)
+ Announce("1");
+
+ FOR_EACH_REALCLIENT(e)
+ Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
}
if (g_arena) {
}
}
}
- else if(f > -1 && f != roundStartTime_prev)
+ else if(f > -1 && f != roundStartTime_prev && !inWarmupStage)
{
roundStartTime_prev = f;
if(g_ca) {
if(red_players && blue_players)
allowed_to_spawn = 0;
else
- reset_map(TRUE);
- } else {
- Announce("begin");
- FOR_EACH_REALCLIENT(e)
- Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
+ {
+ 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)
void count_alive_players()
{
- totalalive = redalive = bluealive = yellowalive = pinkalive = 0;
- if(g_ca)
- {
- FOR_EACH_PLAYER(self) {
- if (self.team == COLOR_TEAM1 && self.health >= 1)
- {
- redalive += 1;
- totalalive += 1;
- }
- else if (self.team == COLOR_TEAM2 && self.health >= 1)
- {
- bluealive += 1;
- totalalive += 1;
- }
- }
- FOR_EACH_REALCLIENT(self) {
- self.redalive_stat = redalive;
- self.bluealive_stat = bluealive;
- }
+ 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(g_freezetag)
- {
- // count amount of alive players in each team
- FOR_EACH_PLAYER(self) {
- if (self.team == COLOR_TEAM1 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- redalive += 1;
- totalalive += 1;
- }
- else if (self.team == COLOR_TEAM2 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- bluealive += 1;
- totalalive += 1;
- }
- else if (self.team == COLOR_TEAM3 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- yellowalive += 1;
- totalalive += 1;
- }
- else if (self.team == COLOR_TEAM4 && self.freezetag_frozen == 0 && self.health >= 1)
- {
- pinkalive += 1;
- totalalive += 1;
- }
- }
- FOR_EACH_REALCLIENT(self) {
- self.redalive_stat = redalive;
- self.bluealive_stat = bluealive;
- self.yellowalive_stat = yellowalive;
- self.pinkalive_stat = pinkalive;
- }
+ FOR_EACH_REALCLIENT(self) {
+ self.redalive_stat = redalive;
+ self.bluealive_stat = bluealive;
}
-
}
/**
*/
void Spawnqueue_Check()
{
- if(warmup == 0 && g_ca && !inWarmupStage)
- {
- if(red_players || blue_players)
- reset_map(TRUE);
- return;
- }
if(time < warmup + 1 || inWarmupStage || intermission_running)
return;
next_round = 0;
reset_map(TRUE);
}
- } else if(g_freezetag) {
- if((next_round && next_round < time))
- {
- next_round = 0;
- reset_map(TRUE);
- }
} else { // arena
//extend next_round if it isn't set yet and only 1 player is spawned
if(!next_round)
}
}
}
+
+void Arena_Main()
+{
+ if(!(g_ca || g_arena))
+ return;
+
+ if(g_ca)
+ {
+ count_players();
+ count_alive_players();
+ }
+ if(!g_arena || arena_roundbased)
+ Arena_Warmup();
+ Spawnqueue_Check();
+}
+
float autocvar_g_spawnpoints_auto_move_out_of_solid;
#define autocvar_g_spawnshieldtime cvar("g_spawnshieldtime")
float autocvar_g_spawnsound;
-float autocvar_g_start_delay;
#define autocvar_g_start_weapon_laser cvar("g_start_weapon_laser")
float autocvar_g_tdm_team_spawns;
float autocvar_g_tdm_teams;
return FALSE;
}
- if(g_freezetag)
- if(e.freezetag_frozen)
- return FALSE;
+ if(e.freezetag_frozen)
+ return FALSE;
// If neither player has ball then don't attack unless the ball is on the
// ground.
limita = limita * limit_mod;
//limitf = limitf * limit_mod;
- if(g_lms && g_ca)
+ if(g_ca)
rot_mod = 0;
if (!g_minstagib && !g_ca && (!g_lms || autocvar_g_lms_regenerate))
}
void ClientKill_Now_TeamChange();
-void freezetag_CheckWinner();
void PlayerDamage (entity inflictor, entity attacker, float damage, float deathtype, vector hitloc, vector force)
{
}
}
- if(!g_freezetag)
- {
- // become fully visible
- self.alpha = default_player_alpha;
- // throw a weapon
- SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
- }
-
// print an obituary message
Obituary (attacker, inflictor, self, deathtype);
race_PreDie();
if(accuracy_isgooddamage(attacker, self))
attacker.accuracy.(accuracy_frags[w-1]) += 1;
- if(deathtype == DEATH_HURTTRIGGER && g_freezetag)
- {
- PutClientInServer();
- count_alive_players(); // re-count players
- freezetag_CheckWinner();
- return;
- }
-
frag_attacker = attacker;
frag_inflictor = inflictor;
frag_target = self;
+ frag_deathtype = deathtype;
MUTATOR_CALLHOOK(PlayerDies);
+
weapon_action(self.weapon, WR_PLAYERDEATH);
RemoveGrapplingHook(self);
//WriteAngle (MSG_ONE, 80);
}
- if(defer_ClientKill_Now_TeamChange) // TODO does this work with FreezeTag?
- ClientKill_Now_TeamChange();
+ if(defer_ClientKill_Now_TeamChange)
+ ClientKill_Now_TeamChange(); // can turn player into spectator
if(g_arena)
Spawnqueue_Unmark(self);
- if(g_freezetag)
+ // player could have been miraculously resuscitated ;)
+ // e.g. players in freezetag get frozen, they don't really die
+ if(self.health >= 1 || self.classname != "player")
return;
// when we get here, player actually dies
- // clear waypoints (do this AFTER FreezeTag)
+
+ // clear waypoints
WaypointSprite_PlayerDead();
+ // throw a weapon
+ SpawnThrownWeapon (self.origin + (self.mins + self.maxs) * 0.5, self.switchweapon);
+ // become fully visible
+ self.alpha = default_player_alpha;
// make the corpse upright (not tilted)
self.angles_x = 0;
self.angles_z = 0;
if (frametime)
self.weapon_frametime = frametime;
- if(((arena_roundbased || g_ca || g_freezetag) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
+ if(((arena_roundbased || g_ca) && time < warmup) || ((time < game_starttime) && !autocvar_sv_ready_restart_after_countdown))
+ return;
+
+ if(round_handler_IsActive() && !round_handler_IsRoundStarted())
return;
if(self.freezetag_frozen == 1)
.float player_blocked;
.float freezetag_frozen;
+.float freezetag_frozen_timeout;
.float freezetag_revive_progress;
.entity muzzle_flash;
compressShortVector_init();
- allowed_to_spawn = TRUE;
-
entity head;
head = nextent(world);
maxclients = 0;
addstat(STAT_HAGAR_LOAD, AS_INT, hagar_load);
- if(g_ca || g_freezetag)
+ if(g_ca)
{
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_freezetag)
- {
- addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
- addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
}
// g_movementspeed hack
if(!g_weapon_stay)
g_weapon_stay = cvar("g_weapon_stay");
- if not(inWarmupStage && !g_ca)
+ if not(inWarmupStage)
game_starttime = cvar("g_start_delay");
sv_pitch_min = cvar("sv_pitch_min");
entity spawn_spot; // spot that was used, or world
// called when a player spawns as player, after shared setup, before his weapon is chosen (so items may be changed in here)
+MUTATOR_HOOKABLE(reset_map_global);
+ // called in reset_map
+
+MUTATOR_HOOKABLE(reset_map_players);
+ // called in reset_map
+
MUTATOR_HOOKABLE(ClientDisconnect);
// called when a player disconnects
entity frag_inflictor;
entity frag_attacker;
entity frag_target; // same as self
+ float frag_deathtype;
MUTATOR_HOOKABLE(GiveFragsForKill);
// called when someone was fragged by "self", and is expected to change frag_score to adjust scoring for the kill
+float freezetag_CheckTeams();
+float freezetag_CheckWinner();
void freezetag_Initialize()
{
precache_model("models/ice/ice.md3");
- warmup = time + autocvar_g_start_delay + autocvar_g_freezetag_warmup;
ScoreRules_freezetag();
+
+ round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, 5, autocvar_g_freezetag_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);
+
+ addstat(STAT_FROZEN, AS_INT, freezetag_frozen);
+ addstat(STAT_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
}
-void freezetag_CheckWinner()
+void freezetag_count_alive_players()
{
- if(time <= game_starttime) // game didn't even start yet! nobody can win in that case.
- return;
-
- if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
- return; // already waiting for next round to start
+ entity e;
+ total_players = redalive = bluealive = yellowalive = pinkalive = 0;
+ FOR_EACH_PLAYER(e) {
+ if(e.team == COLOR_TEAM1 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++redalive;
+ }
+ else if(e.team == COLOR_TEAM2 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++bluealive;
+ }
+ else if(e.team == COLOR_TEAM3 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++yellowalive;
+ }
+ else if(e.team == COLOR_TEAM4 && e.health >= 1)
+ {
+ ++total_players;
+ if (!e.freezetag_frozen) ++pinkalive;
+ }
+ }
+ FOR_EACH_REALCLIENT(e) {
+ e.redalive_stat = redalive;
+ e.bluealive_stat = bluealive;
+ e.yellowalive_stat = yellowalive;
+ 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; // we still have active players on two or more teams, nobody won yet
+ return 1; // we still have active players on two or more teams, nobody won yet
+ return 0;
+}
+
+float prev_total_players;
+float freezetag_CheckTeams()
+{
+ entity e;
+ if(freezetag_TeamsCanPlay())
+ {
+ 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), ", ");
+ 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;
+}
+float freezetag_CheckWinner()
+{
+ if(freezetag_TeamsCanPlay())
+ return 0;
entity e, winner;
string teamname;
if(winner != world) // just in case a winner wasn't found
{
- if(winner.team == COLOR_TEAM1)
- teamname = "^1Red Team";
- else if(winner.team == COLOR_TEAM2)
- teamname = "^4Blue Team";
- else if(winner.team == COLOR_TEAM3)
- teamname = "^3Yellow Team";
- else
- teamname = "^6Pink Team";
- FOR_EACH_PLAYER(e) {
- centerprint(e, strcat(teamname, "^5 wins the round, all other teams were frozen.\n"));
- }
+ 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);
}
- next_round = time + 5;
+ return 1;
}
// this is needed to allow the player to turn his view around (fixangle can't
self.nextthink = time;
}
+void freezetag_Add_Score(entity attacker)
+{
+ if(attacker == self)
+ {
+ // you froze your own dumb self
+ // counted as "suicide" already
+ PlayerScore_Add(self, SP_SCORE, -1);
+ }
+ else if(attacker.classname == "player")
+ {
+ // got frozen by an enemy
+ // counted as "kill" and "death" already
+ PlayerScore_Add(self, SP_SCORE, -1);
+ PlayerScore_Add(attacker, SP_SCORE, +1);
+ }
+ // else nothing - got frozen by the game type rules themselves
+}
+
void freezetag_Freeze(entity attacker)
{
if(self.freezetag_frozen)
self.freezetag_frozen = 1;
self.freezetag_revive_progress = 0;
self.health = 1;
+ // if(inWarmupStage)
+ // self.freezetag_frozen_timeout = time + 5;
+
+ freezetag_count_alive_players();
entity ice;
ice = spawn();
// add waypoint
WaypointSprite_Spawn("freezetag_frozen", 0, 0, self, '0 0 64', world, self.team, self, waypointsprite_attached, TRUE, RADARICON_WAYPOINT, '0.25 0.90 1');
- if(attacker == self)
- {
- // you froze your own dumb self
- // counted as "suicide" already
- PlayerScore_Add(self, SP_SCORE, -1);
- }
- else if(attacker.classname == "player")
- {
- // got frozen by an enemy
- // counted as "kill" and "death" already
- PlayerScore_Add(self, SP_SCORE, -1);
- PlayerScore_Add(attacker, SP_SCORE, +1);
- }
- else
- {
- // nothing - got frozen by the game type rules themselves
- }
+ freezetag_Add_Score(attacker);
}
void freezetag_Unfreeze(entity attacker)
{
self.freezetag_frozen = 0;
+ self.freezetag_frozen_timeout = 0;
self.freezetag_revive_progress = 0;
- self.health = autocvar_g_balance_health_start;
// remove the ice block
entity ice;
MUTATOR_HOOKFUNCTION(freezetag_RemovePlayer)
{
- if(self.freezetag_frozen == 0 && self.health >= 1)
- {
- if(self.team == COLOR_TEAM1)
- --redalive;
- else if(self.team == COLOR_TEAM2)
- --bluealive;
- else if(self.team == COLOR_TEAM3)
- --yellowalive;
- else if(self.team == COLOR_TEAM4)
- --pinkalive;
- --totalalive;
- }
-
- if(total_players > 2) // only check for winners if we had more than two players (one of them left, don't let the other player win just because of that)
- freezetag_CheckWinner();
-
+ self.health = 0; // neccessary to update correctly alive stats
freezetag_Unfreeze(world);
-
+ freezetag_count_alive_players();
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
{
- if(self.freezetag_frozen == 0)
+ if(round_handler_IsActive())
+ if(round_handler_CountdownRunning())
{
- if(self.team == COLOR_TEAM1)
- --redalive;
- else if(self.team == COLOR_TEAM2)
- --bluealive;
- else if(self.team == COLOR_TEAM3)
- --yellowalive;
- else if(self.team == COLOR_TEAM4)
- --pinkalive;
- --totalalive;
+ if(self.freezetag_frozen)
+ freezetag_Unfreeze(world);
+ freezetag_count_alive_players();
+ return 1; // let the player die so that he can respawn whenever he wants
+ }
- freezetag_Freeze(frag_attacker);
+ // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
+ // you succeed changing team through the menu: you both really die (gibbing) and get frozen
+ if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
+ || frag_deathtype == DEATH_TEAMCHANGE || frag_deathtype == DEATH_AUTOTEAMCHANGE)
+ {
+ // let the player die, he will be automatically frozen when he respawns
+ if(!self.freezetag_frozen)
+ {
+ freezetag_Add_Score(frag_attacker);
+ freezetag_count_alive_players();
+ }
+ else
+ freezetag_Unfreeze(world); // remove ice
+ self.freezetag_frozen_timeout = -2; // freeze on respawn
+ return 1;
}
+ if(self.freezetag_frozen)
+ return 1;
+
+ freezetag_Freeze(frag_attacker);
+
if(frag_attacker == frag_target || frag_attacker == world)
{
if(frag_target.classname == STR_PLAYER)
frag_target.health = 1; // "respawn" the player :P
- freezetag_CheckWinner();
-
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
{
- freezetag_Unfreeze(world); // start by making sure that all ice blocks are removed
+ if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+ return 1; // do nothing, round is starting right now
- if(total_players == 1 && time > game_starttime) // only one player active on server, start a new match immediately
- if(!next_round && warmup && (time < warmup - autocvar_g_freezetag_warmup || time > warmup)) // not awaiting next round
+ if(self.freezetag_frozen_timeout == -2) // player was dead
{
- next_round = time;
+ freezetag_Freeze(world);
return 1;
}
- if(warmup && time > warmup) // spawn too late, freeze player
+
+ freezetag_count_alive_players();
+
+ if(round_handler_IsActive())
+ if(round_handler_IsRoundStarted())
{
- centerprint(self, "^1You spawned after the round started, you'll spawn as frozen.\n");
+ centerprint(self, "^1Round already started, you spawn as frozen.");
freezetag_Freeze(world);
}
return 1;
}
+MUTATOR_HOOKFUNCTION(freezetag_reset_map_players)
+{
+ FOR_EACH_PLAYER(self)
+ {
+ if (self.freezetag_frozen)
+ freezetag_Unfreeze(world);
+ self.freezetag_frozen_timeout = -1;
+ PutClientInServer();
+ self.freezetag_frozen_timeout = 0;
+ }
+ freezetag_count_alive_players();
+ return 1;
+}
+
MUTATOR_HOOKFUNCTION(freezetag_GiveFragsForKill)
{
frag_score = 0; // no frags counted in Freeze Tag
float n;
vector revive_extra_size;
+ if(gameover)
+ return 1;
+
+ if(self.freezetag_frozen)
+ {
+ // keep health = 1
+ self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
+
+ if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
+ {
+ self.health = autocvar_g_balance_health_start;
+ freezetag_Unfreeze(world);
+ freezetag_count_alive_players();
+ return 1;
+ }
+ }
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ return 1;
+
revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
entity o;
if(self.freezetag_revive_progress >= 1)
{
freezetag_Unfreeze(self);
+ freezetag_count_alive_players();
// EVERY team mate nearby gets a point (even if multiple!)
FOR_EACH_PLAYER(other) if(self != other)
MUTATOR_HOOKFUNCTION(freezetag_PlayerDamage_Calculate)
{
- if(g_freezetag)
- {
- if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
- {
- frag_damage = 0;
- frag_force = frag_force * autocvar_g_freezetag_frozen_force;
- }
- }
- return 1;
+ if(frag_target.freezetag_frozen == 1 && frag_deathtype != DEATH_HURTTRIGGER)
+ {
+ frag_damage = 0;
+ frag_force = frag_force * autocvar_g_freezetag_frozen_force;
+ }
+ return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_ForbidThrowCurrentWeapon)
else
self.havocbot_role = havocbot_role_ft_offense;
}
-
+
return TRUE;
}
+MUTATOR_HOOKFUNCTION(freezetag_SpectateCopy)
+{
+ self.freezetag_frozen = other.freezetag_frozen;
+ self.freezetag_revive_progress = other.freezetag_revive_progress;
+ return 0;
+}
+
MUTATOR_DEFINITION(gamemode_freezetag)
{
MUTATOR_HOOK(MakePlayerObserver, freezetag_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(ClientDisconnect, freezetag_RemovePlayer, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerDies, freezetag_PlayerDies, CBC_ORDER_ANY);
MUTATOR_HOOK(PlayerSpawn, freezetag_PlayerSpawn, CBC_ORDER_ANY);
+ MUTATOR_HOOK(reset_map_players, freezetag_reset_map_players, CBC_ORDER_ANY);
MUTATOR_HOOK(GiveFragsForKill, freezetag_GiveFragsForKill, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerPreThink, freezetag_PlayerPreThink, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerPhysics, freezetag_PlayerPhysics, CBC_ORDER_FIRST);
MUTATOR_HOOK(PlayerDamage_Calculate, freezetag_PlayerDamage_Calculate, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidThrowCurrentWeapon, freezetag_ForbidThrowCurrentWeapon, CBC_ORDER_FIRST); //first, last or any? dunno.
+ 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_ONADD
{
playerdemo.qh
+round_handler.qh
+
// singleplayer stuff
item_key.qh
secret.qh
cheats.qc
playerstats.qc
+round_handler.qc
+
../common/explosion_equation.qc
mutators/base.qc
--- /dev/null
+void round_handler_Think()
+{
+ entity e;
+ float f;
+
+ if(time <= game_starttime)
+ {
+ round_handler_Reset(game_starttime + 1);
+ return;
+ }
+
+ if(gameover)
+ {
+ round_handler_Reset(0);
+ round_handler_Remove();
+ return;
+ }
+
+ if(self.wait)
+ {
+ reset_map(TRUE);
+ self.wait = FALSE;
+ self.cnt = self.count + 1; // init countdown
+ }
+
+ if(self.cnt > 0) // countdown running
+ {
+ if(self.canRoundStart())
+ {
+ f = self.cnt - 1;
+ if(f == 5) Announce("prepareforbattle");
+ else if(f == 3) Announce("3");
+ else if(f == 2) Announce("2");
+ else if(f == 1) Announce("1");
+ else if(f == 0)
+ {
+ Announce("begin");
+ FOR_EACH_REALCLIENT(e)
+ Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "^1Begin!", 1, 0);
+ self.cnt = 0;
+ self.nextthink = time;
+ return;
+ }
+
+ FOR_EACH_REALCLIENT(e)
+ Send_CSQC_Centerprint_Generic(e, CPID_ROUND_STARTING, "Round will start in %d", 1, f);
+ self.cnt = self.cnt - 1;
+ }
+ else
+ {
+ round_handler_Reset(0);
+ }
+ self.nextthink = time + 1; // canRoundStart every second
+ }
+ else
+ {
+ if(self.canRoundEnd())
+ {
+ // schedule a new round
+ self.wait = TRUE;
+ self.nextthink = time + self.delay;
+ }
+ else
+ {
+ self.nextthink = time; // canRoundEnd every frame
+ }
+ }
+}
+
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, float the_delay, float the_count)
+{
+ if(round_handler)
+ {
+ backtrace("Can't spawn round_handler again!");
+ return;
+ }
+ round_handler = spawn();
+ round_handler.classname = "round_handler";
+
+ round_handler.think = round_handler_Think;
+ round_handler.canRoundStart = canRoundStart_func;
+ round_handler.canRoundEnd = canRoundEnd_func;
+ round_handler.delay = (the_delay > 0) ? the_delay : 0;
+ round_handler.count = fabs(floor(the_count));
+ round_handler.wait = FALSE;
+ round_handler.cnt = round_handler.count + 1;
+ round_handler.nextthink = max(time, game_starttime + 1);
+}
+
+float round_handler_IsActive()
+{
+ return (round_handler != world);
+}
+
+float round_handler_AwaitingNextRound()
+{
+ return (round_handler.wait);
+}
+
+float round_handler_CountdownRunning()
+{
+ return (!round_handler.wait && round_handler.cnt);
+}
+
+float round_handler_IsRoundStarted()
+{
+ return (!round_handler.wait && !round_handler.cnt);
+}
+
+void round_handler_Reset(float next_think)
+{
+ entity e;
+ round_handler.wait = FALSE;
+ if(round_handler.count)
+ if(round_handler.cnt < round_handler.count + 1)
+ {
+ FOR_EACH_REALCLIENT(e)
+ Send_CSQC_Centerprint_Generic_Expire(e, CPID_ROUND_STARTING);
+ round_handler.cnt = round_handler.count + 1;
+ }
+ round_handler.nextthink = next_think;
+}
+
+void round_handler_Remove()
+{
+ remove(round_handler);
+ round_handler = world;
+}
+
--- /dev/null
+entity round_handler;
+.float delay; // stores delay from round end to countdown start
+.float count; // stores initial number of the countdown
+.float wait; // it's set to TRUE when round ends, to FALSE when countdown starts
+.float cnt; // its initial value is .count + 1, then decreased while counting down
+ // reaches 0 when the round starts
+.float() canRoundStart;
+.float() canRoundEnd;
+
+void round_handler_Spawn(float() canRoundStart_func, float() canRoundEnd_func, float the_delay, float the_count);
+float round_handler_IsActive();
+float round_handler_AwaitingNextRound();
+float round_handler_CountdownRunning();
+float round_handler_IsRoundStarted();
+void round_handler_Reset(float next_think);
+void round_handler_Remove();
+
float game_delay;
float game_delay_last;
+void Arena_Main();
void RuneMatchGivePoints();
float RedirectionThink();
entity SelectSpawnPoint (float anypoint);
skill = autocvar_skill;
- count_players();
- if(g_ca || g_freezetag)
- count_alive_players();
- Arena_Warmup();
- Spawnqueue_Check();
-
// detect when the pre-game countdown (if any) has ended and the game has started
game_delay = (time < game_starttime) ? TRUE : FALSE;
if(game_delay_last == TRUE)
if(game_delay == FALSE)
if(autocvar_sv_eventlog)
- GameLogEcho(":startdelay_ended");
+ GameLogEcho(":startdelay_ended");
game_delay_last = game_delay;
return;
}
+ Arena_Main();
+
CreatureFrame ();
CheckRules_World ();
ActivateTeamplay();
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");
}
minstagib_stop_countdown(self);
else if (self.ammo_cells > 0 || (self.items & IT_UNLIMITED_WEAPON_AMMO))
{
+ if (self.minstagib_needammo)
+ self.health = 100;
minstagib_stop_countdown(self);
- self.health = 100;
}
else
{