+float freezetag_TeamsCanPlay();
+float freezetag_CheckWinner();
void freezetag_Initialize()
{
precache_model("models/ice/ice.md3");
- warmup = max(time, game_starttime) + autocvar_g_freezetag_warmup;
ScoreRules_freezetag();
+ round_handler_Spawn(freezetag_TeamsCanPlay, 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_REVIVE_PROGRESS, AS_FLOAT, freezetag_revive_progress);
}
-void freezetag_CheckWinner()
+void freezetag_count_alive_players()
{
- if(time <= game_starttime || inWarmupStage)
- 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 freezetag_CheckWinner()
+{
+ if(freezetag_TeamsCanPlay())
+ return 0;
entity e, winner;
string teamname;
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_count_alive_players()
-{
- 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;
- }
-}
-
void freezetag_Freeze(entity attacker)
{
if(self.freezetag_frozen)
{
self.health = 0; // neccessary to update correctly alive stats
freezetag_Unfreeze(world);
-
freezetag_count_alive_players();
-
- if(total_players > 1) // 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();
-
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerDies)
{
- // let the player die in these cases
- if(time <= game_starttime)
- return 1;
- if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
- return 1;
+ if(round_handler_IsActive())
+ if(round_handler_CountdownRunning())
+ {
+ 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
+ }
if(frag_deathtype == DEATH_HURTTRIGGER)
{
if(!self.freezetag_frozen)
- {
freezetag_Freeze(world);
- freezetag_CheckWinner();
- }
PutClientInServer(); // respawn the player
self.health = 1;
self.armorvalue = 0;
frag_target.health = 1; // "respawn" the player :P
- freezetag_CheckWinner();
-
return 1;
}
MUTATOR_HOOKFUNCTION(freezetag_PlayerSpawn)
{
+ if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
+ return 1; // do nothing, round is starting right now
+
freezetag_count_alive_players();
if(self.freezetag_frozen) // stay frozen if respawning after death (DEATH_HURTTRIGGER)
return 1;
- if(time <= game_starttime || inWarmupStage || total_players == 1)
- return 1;
-
- if(total_players == 2) // 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
- {
- next_round = time;
- return 1;
- }
-
- if(warmup && time > warmup) // spawn too late, freeze player
+ if(round_handler_IsActive())
+ if(round_handler_IsRoundStarted())
{
centerprint(self, "^1Round already started, you spawn as frozen.");
freezetag_Freeze(world);
return 1;
}
-MUTATOR_HOOKFUNCTION(freezetag_reset_map_global)
-{
- redalive = bluealive = yellowalive = pinkalive = 0;
- warmup = max(time, game_starttime);
- if(autocvar_g_freezetag_warmup > 0)
- warmup += autocvar_g_freezetag_warmup;
- 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;
}
float n;
vector revive_extra_size;
- if(gameover)
- return 1;
-
if(self.freezetag_frozen)
{
// keep health = 1
return 1;
}
}
- if(next_round || (time > warmup - autocvar_g_freezetag_warmup && time < warmup))
- return 1; // already waiting for next round to start
+
+ if(round_handler_IsActive())
+ if(!round_handler_IsRoundStarted())
+ return 1;
revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
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_global, freezetag_reset_map_global, 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);
--- /dev/null
+void round_handler_Think()
+{
+ entity e;
+ float f;
+
+ if(inWarmupStage || time < game_starttime)
+ {
+ self.nextthink = time + 1;
+ return;
+ }
+
+ if(gameover)
+ {
+ round_handler_Stop();
+ 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_Stop();
+ }
+ 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 = time;
+}
+
+float round_handler_IsActive()
+{
+ return (round_handler && !inWarmupStage && time > game_starttime);
+}
+
+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_Stop()
+{
+ entity e;
+ 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 = 0;
+}
+
+void round_handler_Remove()
+{
+ remove(round_handler);
+}
+