]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/server/mutators/mutator/gamemode_freezetag.qc
Merge branch 'terencehill/menu_optimization' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / server / mutators / mutator / gamemode_freezetag.qc
1 #ifndef GAMEMODE_FREEZETAG_H
2 #define GAMEMODE_FREEZETAG_H
3
4 int autocvar_g_freezetag_point_limit;
5 int autocvar_g_freezetag_point_leadlimit;
6 bool autocvar_g_freezetag_team_spawns;
7 void freezetag_Initialize();
8
9 REGISTER_MUTATOR(ft, false)
10 {
11         MUTATOR_ONADD
12         {
13                 if (time > 1) // game loads at time 1
14                         error("This is a game type and it cannot be added at runtime.");
15                 freezetag_Initialize();
16
17                 ActivateTeamplay();
18                 SetLimits(autocvar_g_freezetag_point_limit, autocvar_g_freezetag_point_leadlimit, -1, -1);
19
20                 if (autocvar_g_freezetag_team_spawns)
21                         have_team_spawns = -1; // request team spawns
22         }
23
24         MUTATOR_ONROLLBACK_OR_REMOVE
25         {
26                 // we actually cannot roll back freezetag_Initialize here
27                 // BUT: we don't need to! If this gets called, adding always
28                 // succeeds.
29         }
30
31         MUTATOR_ONREMOVE
32         {
33                 LOG_INFO("This is a game type and it cannot be removed at runtime.");
34                 return -1;
35         }
36
37         return 0;
38 }
39
40 .float freezetag_frozen_time;
41 .float freezetag_frozen_timeout;
42 const float ICE_MAX_ALPHA = 1;
43 const float ICE_MIN_ALPHA = 0.1;
44 float freezetag_teams;
45
46 .float reviving; // temp var
47
48 float autocvar_g_freezetag_revive_extra_size;
49 float autocvar_g_freezetag_revive_speed;
50 bool autocvar_g_freezetag_revive_nade;
51 float autocvar_g_freezetag_revive_nade_health;
52
53 #endif
54 #ifdef IMPLEMENTATION
55
56 float autocvar_g_freezetag_frozen_maxtime;
57 float autocvar_g_freezetag_revive_clearspeed;
58 float autocvar_g_freezetag_round_timelimit;
59 int autocvar_g_freezetag_teams;
60 int autocvar_g_freezetag_teams_override;
61 float autocvar_g_freezetag_warmup;
62
63 const float SP_FREEZETAG_REVIVALS = 4;
64 void freezetag_ScoreRules(float teams)
65 {
66         ScoreRules_basics(teams, SFL_SORT_PRIO_PRIMARY, SFL_SORT_PRIO_PRIMARY, true); // SFL_SORT_PRIO_PRIMARY
67         ScoreInfo_SetLabel_PlayerScore(SP_FREEZETAG_REVIVALS, "revivals", 0);
68         ScoreRules_basics_end();
69 }
70
71 void freezetag_count_alive_players()
72 {
73         total_players = redalive = bluealive = yellowalive = pinkalive = 0;
74         FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
75                 switch(it.team)
76                 {
77                         case NUM_TEAM_1: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++redalive; break;
78                         case NUM_TEAM_2: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++bluealive; break;
79                         case NUM_TEAM_3: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++yellowalive; break;
80                         case NUM_TEAM_4: ++total_players; if(it.health >= 1 && STAT(FROZEN, it) != 1) ++pinkalive; break;
81                 }
82         ));
83         FOREACH_CLIENT(IS_REAL_CLIENT(it), LAMBDA(
84                 it.redalive_stat = redalive;
85                 it.bluealive_stat = bluealive;
86                 it.yellowalive_stat = yellowalive;
87                 it.pinkalive_stat = pinkalive;
88         ));
89
90         eliminatedPlayers.SendFlags |= 1;
91 }
92 #define FREEZETAG_ALIVE_TEAMS() ((redalive > 0) + (bluealive > 0) + (yellowalive > 0) + (pinkalive > 0))
93 #define FREEZETAG_ALIVE_TEAMS_OK() (FREEZETAG_ALIVE_TEAMS() == freezetag_teams)
94
95 float freezetag_CheckTeams()
96 {
97         static float prev_missing_teams_mask;
98         if(FREEZETAG_ALIVE_TEAMS_OK())
99         {
100                 if(prev_missing_teams_mask > 0)
101                         Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS);
102                 prev_missing_teams_mask = -1;
103                 return 1;
104         }
105         if(total_players == 0)
106         {
107                 if(prev_missing_teams_mask > 0)
108                         Kill_Notification(NOTIF_ALL, world, MSG_CENTER_CPID, CPID_MISSING_TEAMS);
109                 prev_missing_teams_mask = -1;
110                 return 0;
111         }
112         float missing_teams_mask = (!redalive) + (!bluealive) * 2;
113         if(freezetag_teams >= 3) missing_teams_mask += (!yellowalive) * 4;
114         if(freezetag_teams >= 4) missing_teams_mask += (!pinkalive) * 8;
115         if(prev_missing_teams_mask != missing_teams_mask)
116         {
117                 Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
118                 prev_missing_teams_mask = missing_teams_mask;
119         }
120         return 0;
121 }
122
123 float freezetag_getWinnerTeam()
124 {
125         float winner_team = 0;
126         if(redalive >= 1)
127                 winner_team = NUM_TEAM_1;
128         if(bluealive >= 1)
129         {
130                 if(winner_team) return 0;
131                 winner_team = NUM_TEAM_2;
132         }
133         if(yellowalive >= 1)
134         {
135                 if(winner_team) return 0;
136                 winner_team = NUM_TEAM_3;
137         }
138         if(pinkalive >= 1)
139         {
140                 if(winner_team) return 0;
141                 winner_team = NUM_TEAM_4;
142         }
143         if(winner_team)
144                 return winner_team;
145         return -1; // no player left
146 }
147
148 float freezetag_CheckWinner()
149 {
150         if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
151         {
152                 Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_OVER);
153                 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_OVER);
154                 FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
155                         it.freezetag_frozen_timeout = 0;
156                         nades_Clear(it);
157                 ));
158                 round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
159                 return 1;
160         }
161
162         if(FREEZETAG_ALIVE_TEAMS() > 1)
163                 return 0;
164
165         int winner_team = freezetag_getWinnerTeam();
166         if(winner_team > 0)
167         {
168                 Send_Notification(NOTIF_ALL, world, MSG_CENTER, APP_TEAM_NUM_4(winner_team, CENTER_ROUND_TEAM_WIN_));
169                 Send_Notification(NOTIF_ALL, world, MSG_INFO, APP_TEAM_NUM_4(winner_team, INFO_ROUND_TEAM_WIN_));
170                 TeamScore_AddToTeam(winner_team, ST_SCORE, +1);
171         }
172         else if(winner_team == -1)
173         {
174                 Send_Notification(NOTIF_ALL, world, MSG_CENTER, CENTER_ROUND_TIED);
175                 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_ROUND_TIED);
176         }
177
178         FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
179                 it.freezetag_frozen_timeout = 0;
180                 nades_Clear(it);
181         ));
182         round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
183         return 1;
184 }
185
186 entity freezetag_LastPlayerForTeam()
187 {SELFPARAM();
188         entity last_pl = world;
189         FOREACH_CLIENT(IS_PLAYER(it) && it != self, LAMBDA(
190                 if(it.health >= 1)
191                 if(!STAT(FROZEN, it))
192                 if(SAME_TEAM(it, self))
193                 if(!last_pl)
194                         last_pl = it;
195                 else
196                         return world;
197         ));
198         return last_pl;
199 }
200
201 void freezetag_LastPlayerForTeam_Notify()
202 {
203         if(round_handler_IsActive())
204         if(round_handler_IsRoundStarted())
205         {
206                 entity pl = freezetag_LastPlayerForTeam();
207                 if(pl)
208                         Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
209         }
210 }
211
212 void freezetag_Add_Score(entity attacker)
213 {SELFPARAM();
214         if(attacker == self)
215         {
216                 // you froze your own dumb self
217                 // counted as "suicide" already
218                 PlayerScore_Add(self, SP_SCORE, -1);
219         }
220         else if(IS_PLAYER(attacker))
221         {
222                 // got frozen by an enemy
223                 // counted as "kill" and "death" already
224                 PlayerScore_Add(self, SP_SCORE, -1);
225                 PlayerScore_Add(attacker, SP_SCORE, +1);
226         }
227         // else nothing - got frozen by the game type rules themselves
228 }
229
230 void freezetag_Freeze(entity attacker)
231 {SELFPARAM();
232         if(STAT(FROZEN, self))
233                 return;
234
235         if(autocvar_g_freezetag_frozen_maxtime > 0)
236                 self.freezetag_frozen_timeout = time + autocvar_g_freezetag_frozen_maxtime;
237
238         Freeze(self, 0, 1, true);
239
240         freezetag_count_alive_players();
241
242         freezetag_Add_Score(attacker);
243 }
244
245 void freezetag_Unfreeze(entity attacker)
246 {SELFPARAM();
247         self.freezetag_frozen_time = 0;
248         self.freezetag_frozen_timeout = 0;
249
250         Unfreeze(self);
251 }
252
253 float freezetag_isEliminated(entity e)
254 {
255         if(IS_PLAYER(e) && (STAT(FROZEN, e) == 1 || IS_DEAD(e)))
256                 return true;
257         return false;
258 }
259
260
261 // ================
262 // Bot player logic
263 // ================
264
265 void() havocbot_role_ft_freeing;
266 void() havocbot_role_ft_offense;
267
268 void havocbot_goalrating_freeplayers(float ratingscale, vector org, float sradius)
269 {SELFPARAM();
270         float distance;
271
272         FOREACH_CLIENT(IS_PLAYER(it) && it != self && SAME_TEAM(it, self), LAMBDA(
273                 if (STAT(FROZEN, it) == 1)
274                 {
275                         distance = vlen(it.origin - org);
276                         if (distance > sradius)
277                                 continue;
278                         navigation_routerating(it, ratingscale, 2000);
279                 }
280                 else
281                 {
282                         // If teamate is not frozen still seek them out as fight better
283                         // in a group.
284                         navigation_routerating(it, ratingscale/3, 2000);
285                 }
286         ));
287 }
288
289 void havocbot_role_ft_offense()
290 {SELFPARAM();
291         if(IS_DEAD(self))
292                 return;
293
294         if (!self.havocbot_role_timeout)
295                 self.havocbot_role_timeout = time + random() * 10 + 20;
296
297         // Count how many players on team are unfrozen.
298         int unfrozen = 0;
299         FOREACH_CLIENT(IS_PLAYER(it) && SAME_TEAM(it, self) && !(STAT(FROZEN, it) != 1), LAMBDA(unfrozen++));
300
301         // If only one left on team or if role has timed out then start trying to free players.
302         if (((unfrozen == 0) && (!STAT(FROZEN, self))) || (time > self.havocbot_role_timeout))
303         {
304                 LOG_TRACE("changing role to freeing\n");
305                 self.havocbot_role = havocbot_role_ft_freeing;
306                 self.havocbot_role_timeout = 0;
307                 return;
308         }
309
310         if (time > self.bot_strategytime)
311         {
312                 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
313
314                 navigation_goalrating_start();
315                 havocbot_goalrating_items(10000, self.origin, 10000);
316                 havocbot_goalrating_enemyplayers(20000, self.origin, 10000);
317                 havocbot_goalrating_freeplayers(9000, self.origin, 10000);
318                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
319                 navigation_goalrating_end();
320         }
321 }
322
323 void havocbot_role_ft_freeing()
324 {SELFPARAM();
325         if(IS_DEAD(self))
326                 return;
327
328         if (!self.havocbot_role_timeout)
329                 self.havocbot_role_timeout = time + random() * 10 + 20;
330
331         if (time > self.havocbot_role_timeout)
332         {
333                 LOG_TRACE("changing role to offense\n");
334                 self.havocbot_role = havocbot_role_ft_offense;
335                 self.havocbot_role_timeout = 0;
336                 return;
337         }
338
339         if (time > self.bot_strategytime)
340         {
341                 self.bot_strategytime = time + autocvar_bot_ai_strategyinterval;
342
343                 navigation_goalrating_start();
344                 havocbot_goalrating_items(8000, self.origin, 10000);
345                 havocbot_goalrating_enemyplayers(10000, self.origin, 10000);
346                 havocbot_goalrating_freeplayers(20000, self.origin, 10000);
347                 //havocbot_goalrating_waypoints(1, self.origin, 1000);
348                 navigation_goalrating_end();
349         }
350 }
351
352
353 // ==============
354 // Hook Functions
355 // ==============
356
357 void ft_RemovePlayer()
358 {SELFPARAM();
359         self.health = 0; // neccessary to update correctly alive stats
360         if(!STAT(FROZEN, self))
361                 freezetag_LastPlayerForTeam_Notify();
362         freezetag_Unfreeze(world);
363         freezetag_count_alive_players();
364 }
365
366 MUTATOR_HOOKFUNCTION(ft, ClientDisconnect)
367 {SELFPARAM();
368         ft_RemovePlayer();
369         return 1;
370 }
371
372 MUTATOR_HOOKFUNCTION(ft, MakePlayerObserver)
373 {SELFPARAM();
374         ft_RemovePlayer();
375         return false;
376 }
377
378 MUTATOR_HOOKFUNCTION(ft, PlayerDies)
379 {SELFPARAM();
380         if(round_handler_IsActive())
381         if(round_handler_CountdownRunning())
382         {
383                 if(STAT(FROZEN, self))
384                         freezetag_Unfreeze(world);
385                 freezetag_count_alive_players();
386                 return 1; // let the player die so that he can respawn whenever he wants
387         }
388
389         // Cases DEATH_TEAMCHANGE and DEATH_AUTOTEAMCHANGE are needed to fix a bug whe
390         // you succeed changing team through the menu: you both really die (gibbing) and get frozen
391         if(ITEM_DAMAGE_NEEDKILL(frag_deathtype)
392                 || frag_deathtype == DEATH_TEAMCHANGE.m_id || frag_deathtype == DEATH_AUTOTEAMCHANGE.m_id)
393         {
394                 // let the player die, he will be automatically frozen when he respawns
395                 if(STAT(FROZEN, self) != 1)
396                 {
397                         freezetag_Add_Score(frag_attacker);
398                         freezetag_count_alive_players();
399                         freezetag_LastPlayerForTeam_Notify();
400                 }
401                 else
402                         freezetag_Unfreeze(world); // remove ice
403                 self.health = 0; // Unfreeze resets health
404                 self.freezetag_frozen_timeout = -2; // freeze on respawn
405                 return 1;
406         }
407
408         if(STAT(FROZEN, self))
409                 return 1;
410
411         freezetag_Freeze(frag_attacker);
412         freezetag_LastPlayerForTeam_Notify();
413
414         if(frag_attacker == frag_target || frag_attacker == world)
415         {
416                 if(IS_PLAYER(frag_target))
417                         Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_SELF);
418                 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_SELF, frag_target.netname);
419         }
420         else
421         {
422                 if(IS_PLAYER(frag_target))
423                         Send_Notification(NOTIF_ONE, frag_target, MSG_CENTER, CENTER_FREEZETAG_FROZEN, frag_attacker.netname);
424                 if(IS_PLAYER(frag_attacker))
425                         Send_Notification(NOTIF_ONE, frag_attacker, MSG_CENTER, CENTER_FREEZETAG_FREEZE, frag_target.netname);
426                 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_FREEZE, frag_target.netname, frag_attacker.netname);
427         }
428
429         return 1;
430 }
431
432 MUTATOR_HOOKFUNCTION(ft, PlayerSpawn)
433 {SELFPARAM();
434         if(self.freezetag_frozen_timeout == -1) // if PlayerSpawn is called by reset_map_players
435                 return 1; // do nothing, round is starting right now
436
437         if(self.freezetag_frozen_timeout == -2) // player was dead
438         {
439                 freezetag_Freeze(world);
440                 return 1;
441         }
442
443         freezetag_count_alive_players();
444
445         if(round_handler_IsActive())
446         if(round_handler_IsRoundStarted())
447         {
448                 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_SPAWN_LATE);
449                 freezetag_Freeze(world);
450         }
451
452         return 1;
453 }
454
455 MUTATOR_HOOKFUNCTION(ft, reset_map_players)
456 {SELFPARAM();
457         FOREACH_CLIENT(IS_PLAYER(it), LAMBDA(
458                 it.killcount = 0;
459                 it.freezetag_frozen_timeout = -1;
460                 setself(it);
461                 PutClientInServer();
462                 it.freezetag_frozen_timeout = 0;
463         ));
464         freezetag_count_alive_players();
465         return 1;
466 }
467
468 MUTATOR_HOOKFUNCTION(ft, GiveFragsForKill, CBC_ORDER_FIRST)
469 {
470         frag_score = 0; // no frags counted in Freeze Tag
471         return 1;
472 }
473
474 MUTATOR_HOOKFUNCTION(ft, PlayerPreThink, CBC_ORDER_FIRST)
475 {SELFPARAM();
476         if(gameover)
477                 return 1;
478
479         if(STAT(FROZEN, self) == 1)
480         {
481                 // keep health = 1
482                 self.pauseregen_finished = time + autocvar_g_balance_pause_health_regen;
483         }
484
485         if(round_handler_IsActive())
486         if(!round_handler_IsRoundStarted())
487                 return 1;
488
489         int n;
490
491         entity o;
492         o = world;
493         //if(STAT(FROZEN, self))
494         //if(self.freezetag_frozen_timeout > 0 && time < self.freezetag_frozen_timeout)
495                 //self.iceblock.alpha = ICE_MIN_ALPHA + (ICE_MAX_ALPHA - ICE_MIN_ALPHA) * (self.freezetag_frozen_timeout - time) / (self.freezetag_frozen_timeout - self.freezetag_frozen_time);
496
497         if(self.freezetag_frozen_timeout > 0 && time >= self.freezetag_frozen_timeout)
498                 n = -1;
499         else
500         {
501                 vector revive_extra_size = '1 1 1' * autocvar_g_freezetag_revive_extra_size;
502                 n = 0;
503                 FOREACH_CLIENT(IS_PLAYER(it) && it != self, LAMBDA(
504                         if(STAT(FROZEN, it) == 0)
505                         if(!IS_DEAD(it))
506                         if(SAME_TEAM(it, self))
507                         if(boxesoverlap(self.absmin - revive_extra_size, self.absmax + revive_extra_size, it.absmin, it.absmax))
508                         {
509                                 if(!o)
510                                         o = it;
511                                 if(STAT(FROZEN, self) == 1)
512                                         it.reviving = true;
513                                 ++n;
514                         }
515                 ));
516
517         }
518
519         if(n && STAT(FROZEN, self) == 1) // OK, there is at least one teammate reviving us
520         {
521                 self.revive_progress = bound(0, self.revive_progress + frametime * max(1/60, autocvar_g_freezetag_revive_speed), 1);
522                 self.health = max(1, self.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
523
524                 if(self.revive_progress >= 1)
525                 {
526                         freezetag_Unfreeze(self);
527                         freezetag_count_alive_players();
528
529                         if(n == -1)
530                         {
531                                 Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_AUTO_REVIVED, autocvar_g_freezetag_frozen_maxtime);
532                                 Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_AUTO_REVIVED, self.netname, autocvar_g_freezetag_frozen_maxtime);
533                                 return 1;
534                         }
535
536                         // EVERY team mate nearby gets a point (even if multiple!)
537                         FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, LAMBDA(
538                                 PlayerScore_Add(it, SP_FREEZETAG_REVIVALS, +1);
539                                 PlayerScore_Add(it, SP_SCORE, +1);
540                                 nades_GiveBonus(it,autocvar_g_nades_bonus_score_low);
541                         ));
542
543                         Send_Notification(NOTIF_ONE, self, MSG_CENTER, CENTER_FREEZETAG_REVIVED, o.netname);
544                         Send_Notification(NOTIF_ONE, o, MSG_CENTER, CENTER_FREEZETAG_REVIVE, self.netname);
545                         Send_Notification(NOTIF_ALL, world, MSG_INFO, INFO_FREEZETAG_REVIVED, self.netname, o.netname);
546                 }
547
548                 FOREACH_CLIENT(IS_PLAYER(it) && it.reviving, LAMBDA(
549                         it.revive_progress = self.revive_progress;
550                         it.reviving = false;
551                 ));
552         }
553         else if(!n && STAT(FROZEN, self) == 1) // only if no teammate is nearby will we reset
554         {
555                 self.revive_progress = bound(0, self.revive_progress - frametime * autocvar_g_freezetag_revive_clearspeed, 1);
556                 self.health = max(1, self.revive_progress * ((warmup_stage) ? warmup_start_health : start_health));
557         }
558         else if(!n && !STAT(FROZEN, self))
559         {
560                 self.revive_progress = 0; // thawing nobody
561         }
562
563         return 1;
564 }
565
566 MUTATOR_HOOKFUNCTION(ft, SetStartItems)
567 {
568         start_items &= ~IT_UNLIMITED_AMMO;
569         //start_health       = warmup_start_health       = cvar("g_lms_start_health");
570         //start_armorvalue   = warmup_start_armorvalue   = cvar("g_lms_start_armor");
571         start_ammo_shells  = warmup_start_ammo_shells  = cvar("g_lms_start_ammo_shells");
572         start_ammo_nails   = warmup_start_ammo_nails   = cvar("g_lms_start_ammo_nails");
573         start_ammo_rockets = warmup_start_ammo_rockets = cvar("g_lms_start_ammo_rockets");
574         start_ammo_cells   = warmup_start_ammo_cells   = cvar("g_lms_start_ammo_cells");
575         start_ammo_plasma  = warmup_start_ammo_plasma  = cvar("g_lms_start_ammo_plasma");
576         start_ammo_fuel    = warmup_start_ammo_fuel    = cvar("g_lms_start_ammo_fuel");
577
578         return 0;
579 }
580
581 MUTATOR_HOOKFUNCTION(ft, HavocBot_ChooseRole)
582 {SELFPARAM();
583         if (!IS_DEAD(self))
584         {
585                 if (random() < 0.5)
586                         self.havocbot_role = havocbot_role_ft_freeing;
587                 else
588                         self.havocbot_role = havocbot_role_ft_offense;
589         }
590
591         return true;
592 }
593
594 MUTATOR_HOOKFUNCTION(ft, GetTeamCount, CBC_ORDER_EXCLUSIVE)
595 {
596         ret_float = freezetag_teams;
597         return false;
598 }
599
600 MUTATOR_HOOKFUNCTION(ft, SetWeaponArena)
601 {
602         // most weapons arena
603         if(ret_string == "0" || ret_string == "")
604                 ret_string = "most";
605         return false;
606 }
607
608 void freezetag_Initialize()
609 {
610         freezetag_teams = autocvar_g_freezetag_teams_override;
611         if(freezetag_teams < 2)
612                 freezetag_teams = autocvar_g_freezetag_teams;
613         freezetag_teams = bound(2, freezetag_teams, 4);
614         freezetag_ScoreRules(freezetag_teams);
615
616         round_handler_Spawn(freezetag_CheckTeams, freezetag_CheckWinner, func_null);
617         round_handler_Init(5, autocvar_g_freezetag_warmup, autocvar_g_freezetag_round_timelimit);
618
619         EliminatedPlayers_Init(freezetag_isEliminated);
620 }
621
622 #endif