-.float spawned;
-float maxspawned;
-float numspawned;
-.entity spawnqueue_next;
-.entity spawnqueue_prev;
-.float spawnqueue_in;
-entity spawnqueue_first;
-entity spawnqueue_last;
-
-void Spawnqueue_Insert(entity e)
-{
- if(e.spawnqueue_in)
- return;
- dprint(strcat("Into queue: ", e.netname, "\n"));
- e.spawnqueue_in = TRUE;
- e.spawnqueue_prev = spawnqueue_last;
- e.spawnqueue_next = world;
- if(spawnqueue_last)
- spawnqueue_last.spawnqueue_next = e;
- spawnqueue_last = e;
- if(!spawnqueue_first)
- spawnqueue_first = e;
-}
-
-void Spawnqueue_Remove(entity e)
-{
- if(!e.spawnqueue_in)
- return;
- dprint(strcat("Out of queue: ", e.netname, "\n"));
- e.spawnqueue_in = FALSE;
- if(e == spawnqueue_first)
- spawnqueue_first = e.spawnqueue_next;
- if(e == spawnqueue_last)
- spawnqueue_last = e.spawnqueue_prev;
- if(e.spawnqueue_prev)
- e.spawnqueue_prev.spawnqueue_next = e.spawnqueue_next;
- if(e.spawnqueue_next)
- e.spawnqueue_next.spawnqueue_prev = e.spawnqueue_prev;
- e.spawnqueue_next = world;
- e.spawnqueue_prev = world;
-}
-
-void Spawnqueue_Unmark(entity e)
-{
- if(!e.spawned)
- return;
- e.spawned = FALSE;
- numspawned = numspawned - 1;
-}
-
-void Spawnqueue_Mark(entity e)
-{
- if(e.spawned)
- return;
- e.spawned = TRUE;
- numspawned = numspawned + 1;
-}
-
-float Arena_CheckWinner()
-{
- entity e;
-
- if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
- round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
- return 1;
- }
-
- if(numspawned > 1)
- return 0;
-
- entity champion;
- champion = world;
- FOR_EACH_CLIENT(e)
- {
- if(e.spawned && IS_PLAYER(e))
- champion = e;
- }
-
- if(champion)
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_PLAYER_WIN, champion.netname);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_PLAYER_WIN, champion.netname);
- UpdateFrags(champion, +1);
- }
- else
- {
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
- Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
- }
- round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
- return 1;
-}
-
-void Arena_AddChallengers()
-{
- entity e;
- if(time < 2) // don't force players to spawn so early
- return;
- e = self;
- while(numspawned < maxspawned && spawnqueue_first)
- {
- self = spawnqueue_first;
-
- bprint ("^4", self.netname, "^4 is the next challenger\n");
-
- Spawnqueue_Remove(self);
- Spawnqueue_Mark(self);
-
- self.classname = "player";
- PutClientInServer();
- }
- self = e;
-}
-
-float prev_numspawned;
-float Arena_CheckPlayers()
-{
- Arena_AddChallengers();
-
- if(numspawned >= 2)
- {
- if(prev_numspawned > 0)
- Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_PLAYERS);
- prev_numspawned = -1;
- return 1;
- }
-
- if(prev_numspawned != numspawned && numspawned == 1)
- {
- if(maxspawned - numspawned > 0)
- Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_PLAYERS, maxspawned - numspawned);
- prev_numspawned = numspawned;
- }
-
- return 0;
-}
-
-void Arena_RoundStart()
-{
- entity e;
- FOR_EACH_PLAYER(e)
- e.player_blocked = 0;
-}
-
-MUTATOR_HOOKFUNCTION(arena_ClientDisconnect)
-{
- Spawnqueue_Unmark(self);
- Spawnqueue_Remove(self);
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_reset_map_players)
-{
- FOR_EACH_CLIENT(self)
- {
- if(self.spawned)
- {
- PutClientInServer();
- self.player_blocked = 1;
- }
- else
- PutObserverInServer();
- }
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_MakePlayerObserver)
-{
- if(self.version_mismatch)
- {
- self.frags = FRAGS_SPECTATOR;
- Spawnqueue_Unmark(self);
- Spawnqueue_Remove(self);
- }
- else
- {
- self.frags = FRAGS_LMS_LOSER;
- Spawnqueue_Insert(self);
- }
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_PutClientInServer)
-{
- if(!self.spawned)
- self.classname = "observer";
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_ClientConnect)
-{
- self.classname = "observer";
- Spawnqueue_Insert(self);
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_PlayerSpawn)
-{
- Spawnqueue_Remove(self);
- Spawnqueue_Mark(self);
- if(arena_roundbased)
- self.player_blocked = 1;
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_ForbidPlayerScore_Clear)
-{
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_GiveFragsForKill)
-{
- if(arena_roundbased)
- frag_score = 0; // score will be given to the champion when the round ends
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_PlayerDies)
-{
- // put dead players in the spawn queue
- if(arena_roundbased)
- self.respawn_flags = (RESPAWN_FORCE | RESPAWN_SILENT);
- else
- self.respawn_flags = RESPAWN_SILENT;
- Spawnqueue_Unmark(self);
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_SV_StartFrame)
-{
- if(gameover) return 1;
- if(time <= game_starttime || !arena_roundbased)
- Arena_AddChallengers();
- return 1;
-}
-
-MUTATOR_HOOKFUNCTION(arena_FilterItem)
-{
- if(autocvar_g_powerups <= 0)
- if(self.flags & FL_POWERUP)
- return TRUE;
-
- return FALSE;
-}
-
-void arena_Initialize()
-{
- maxspawned = max(2, autocvar_g_arena_maxspawned);
- arena_roundbased = autocvar_g_arena_roundbased;
- if(arena_roundbased)
- {
- round_handler_Spawn(Arena_CheckPlayers, Arena_CheckWinner, Arena_RoundStart);
- round_handler_Init(5, autocvar_g_arena_warmup, autocvar_g_arena_round_timelimit);
- }
-}
-
-MUTATOR_DEFINITION(gamemode_arena)
-{
- MUTATOR_HOOK(ClientDisconnect, arena_ClientDisconnect, CBC_ORDER_ANY);
- MUTATOR_HOOK(reset_map_players, arena_reset_map_players, CBC_ORDER_ANY);
- MUTATOR_HOOK(MakePlayerObserver, arena_MakePlayerObserver, CBC_ORDER_ANY);
- MUTATOR_HOOK(PutClientInServer, arena_PutClientInServer, CBC_ORDER_ANY);
- MUTATOR_HOOK(ClientConnect, arena_ClientConnect, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerSpawn, arena_PlayerSpawn, CBC_ORDER_ANY);
- MUTATOR_HOOK(ForbidPlayerScore_Clear, arena_ForbidPlayerScore_Clear, CBC_ORDER_ANY);
- MUTATOR_HOOK(GiveFragsForKill, arena_GiveFragsForKill, CBC_ORDER_ANY);
- MUTATOR_HOOK(PlayerDies, arena_PlayerDies, CBC_ORDER_ANY);
- MUTATOR_HOOK(SV_StartFrame, arena_SV_StartFrame, CBC_ORDER_ANY);
- MUTATOR_HOOK(FilterItem, arena_FilterItem, 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.");
- arena_Initialize();
- }
-
- MUTATOR_ONREMOVE
- {
- print("This is a game type and it cannot be removed at runtime.");
- return -1;
- }
-
- return 0;
-}