]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blob - qcsrc/common/gamemodes/gamemode/clanarena/sv_clanarena.qc
Merge branch 'LegendaryGuard/fix_playban_notif' into 'master'
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / gamemodes / gamemode / clanarena / sv_clanarena.qc
1 #include "sv_clanarena.qh"
2
3 float autocvar_g_ca_damage2score = 100;
4 bool autocvar_g_ca_prevent_stalemate;
5
6 float autocvar_g_ca_start_health = 200;
7 float autocvar_g_ca_start_armor = 200;
8 float autocvar_g_ca_start_ammo_shells = 60;
9 float autocvar_g_ca_start_ammo_nails = 320;
10 float autocvar_g_ca_start_ammo_rockets = 160;
11 float autocvar_g_ca_start_ammo_cells = 180;
12 float autocvar_g_ca_start_ammo_plasma = 180;
13 float autocvar_g_ca_start_ammo_fuel = 0;
14
15 .float ca_damage_counter;
16
17 void CA_count_alive_players()
18 {
19         total_players = 0;
20         for (int i = 1; i <= NUM_TEAMS; ++i)
21         {
22                 Team_SetNumberOfAlivePlayers(Team_GetTeamFromIndex(i), 0);
23         }
24         FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it),
25         {
26                 ++total_players;
27                 if (IS_DEAD(it))
28                 {
29                         continue;
30                 }
31                 entity team_ = Entity_GetTeam(it);
32                 int num_alive = Team_GetNumberOfAlivePlayers(team_);
33                 ++num_alive;
34                 Team_SetNumberOfAlivePlayers(team_, num_alive);
35         });
36         FOREACH_CLIENT(IS_REAL_CLIENT(it),
37         {
38                 STAT(REDALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(1));
39                 STAT(BLUEALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(2));
40                 STAT(YELLOWALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(3));
41                 STAT(PINKALIVE, it) = Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(4));
42         });
43 }
44
45 void nades_Clear(entity player);
46
47 int CA_PreventStalemate()
48 {
49         //LOG_INFO("PreventStalemate running");
50         int winnerTeam = 0;
51         int secondTeam = 0;
52
53         for(int i = 1; i <= AVAILABLE_TEAMS; i++)
54         {
55                 if(!winnerTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)))
56                 {
57                         secondTeam = winnerTeam;
58                         winnerTeam = Team_IndexToTeam(i);
59                 }
60                 else
61                 {
62                         if(!secondTeam || Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) > Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
63                                 secondTeam = Team_IndexToTeam(i);
64                 }
65         }
66
67         if(Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)) != Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)))
68         {
69                 LOG_INFOF("Stalemate broken by alive players. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)",
70                         Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(winnerTeam)),
71                         Team_ColorCode(secondTeam), Team_ColorName(secondTeam), Team_GetNumberOfAlivePlayers(Team_GetTeam(secondTeam)));
72                 return winnerTeam;
73         }
74
75         // Equality. Let's check which team has more health now
76         //LOG_INFO("Equality. Checking health now.");
77         winnerTeam = 0;
78         secondTeam = 0;
79         int winnerTeamHealth = 0;
80         int secondTeamHealth = 0;
81         int teamIndex, teamHealth;
82
83         for(int i = 1; i <= AVAILABLE_TEAMS; i++)
84         {
85                 teamIndex = i;
86                 teamHealth = 0;
87
88                 // Add up health for the players in this team
89                 FOREACH_CLIENT(IS_PLAYER(it) && Entity_HasValidTeam(it) && it.team == Team_IndexToTeam(teamIndex),
90                 {
91                         if (IS_DEAD(it))
92                                 continue;
93                         teamHealth += GetResource(it, RES_HEALTH) + GetResource(it, RES_ARMOR);
94                 });
95
96                 // Set the winner teams
97                 if(!winnerTeam || teamHealth > winnerTeamHealth)
98                 {
99                         secondTeam = winnerTeam;
100                         secondTeamHealth = winnerTeamHealth;
101                         winnerTeam = Team_IndexToTeam(i);
102                         winnerTeamHealth = teamHealth;
103                 }
104                 else
105                 {
106                         if(!secondTeam || teamHealth > secondTeamHealth)
107                         {
108                                 secondTeam = Team_IndexToTeam(i);
109                                 secondTeamHealth = teamHealth;
110                         }
111                 }
112         }
113
114         if(winnerTeamHealth != secondTeamHealth)
115         {
116                 LOG_INFOF("Stalemate broken by team health. Best team: %s%s (%d)^7 - Trailing team: %s%s (%d)",
117                         Team_ColorCode(winnerTeam), Team_ColorName(winnerTeam), winnerTeamHealth,
118                         Team_ColorCode(secondTeam), Team_ColorName(secondTeam), secondTeamHealth);
119                 return winnerTeam;
120         }
121         else
122                 return -2; // Equality. Can't avoid the stalemate.
123 }
124
125 float CA_CheckWinner()
126 {
127         int winner_team = 0;
128
129         if(round_handler_GetEndTime() > 0 && round_handler_GetEndTime() - time <= 0)
130         {
131                 if(autocvar_g_ca_prevent_stalemate)
132                         winner_team = CA_PreventStalemate();
133                 else
134                         winner_team = -2;
135         }
136
137         CA_count_alive_players();
138         if (!winner_team)
139                 winner_team = Team_GetWinnerAliveTeam();
140         if (!winner_team)
141                 return 0;
142
143         if(winner_team > 0)
144         {
145                 Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, APP_TEAM_NUM(winner_team, CENTER_ROUND_TEAM_WIN));
146                 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, APP_TEAM_NUM(winner_team, INFO_ROUND_TEAM_WIN));
147                 TeamScore_AddToTeam(winner_team, ST_CA_ROUNDS, +1);
148         }
149         else if(winner_team == -1)
150         {
151                 Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_TIED);
152                 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_TIED);
153         }
154         else if(winner_team == -2)
155         {
156                 Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_ROUND_OVER);
157                 Send_Notification(NOTIF_ALL, NULL, MSG_INFO, INFO_ROUND_OVER);
158         }
159
160         allowed_to_spawn = false;
161         game_stopped = true;
162         round_handler_Init(5, autocvar_g_ca_warmup, autocvar_g_ca_round_timelimit);
163
164         FOREACH_CLIENT(IS_PLAYER(it), { nades_Clear(it); });
165
166         return 1;
167 }
168
169 void CA_RoundStart()
170 {
171         allowed_to_spawn = boolean(warmup_stage);
172 }
173
174 bool CA_CheckTeams()
175 {
176         static int prev_missing_teams_mask;
177         allowed_to_spawn = true;
178         CA_count_alive_players();
179         if (Team_GetNumberOfAliveTeams() == NumTeams(ca_teams))
180         {
181                 if(prev_missing_teams_mask > 0)
182                         Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
183                 prev_missing_teams_mask = -1;
184                 return true;
185         }
186         if(total_players == 0)
187         {
188                 if(prev_missing_teams_mask > 0)
189                         Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_MISSING_TEAMS);
190                 prev_missing_teams_mask = -1;
191                 return false;
192         }
193         int missing_teams_mask = 0;
194         for (int i = 1; i <= NUM_TEAMS; ++i)
195         {
196                 if ((ca_teams & Team_IndexToBit(i)) &&
197                         (Team_GetNumberOfAlivePlayers(Team_GetTeamFromIndex(i)) == 0))
198                 {
199                         missing_teams_mask |= Team_IndexToBit(i);
200                 }
201         }
202         if(prev_missing_teams_mask != missing_teams_mask)
203         {
204                 Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_MISSING_TEAMS, missing_teams_mask);
205                 prev_missing_teams_mask = missing_teams_mask;
206         }
207         return false;
208 }
209
210 bool ca_isEliminated(entity e)
211 {
212         if(INGAME_JOINED(e) && (IS_DEAD(e) || e.frags == FRAGS_PLAYER_OUT_OF_GAME))
213                 return true;
214         if(INGAME_JOINING(e))
215                 return true;
216         return false;
217 }
218
219 /** Returns next available player to spectate if g_ca_spectate_enemies == 0 */
220 entity CA_SpectateNext(entity player, entity start)
221 {
222         if (SAME_TEAM(start, player)) return start;
223         // continue from current player
224         for (entity e = start; (e = find(e, classname, STR_PLAYER)); )
225         {
226                 if (SAME_TEAM(player, e)) return e;
227         }
228         // restart from the beginning
229         for (entity e = NULL; (e = find(e, classname, STR_PLAYER)); )
230         {
231                 if (SAME_TEAM(player, e)) return e;
232         }
233         return start;
234 }
235
236
237 MUTATOR_HOOKFUNCTION(ca, PlayerSpawn)
238 {
239         entity player = M_ARGV(0, entity);
240
241         INGAME_STATUS_SET(player, INGAME_STATUS_JOINED);
242         if (time <= game_starttime) // reset on game restart, not on round start
243                 player.ca_damage_counter = 0;
244         if (!warmup_stage)
245                 eliminatedPlayers.SendFlags |= 1;
246 }
247
248 MUTATOR_HOOKFUNCTION(ca, ForbidSpawn)
249 {
250         entity player = M_ARGV(0, entity);
251
252         // spectators / observers that weren't playing can join; they are
253         // immediately forced to observe in the PutClientInServer hook
254         // this way they are put in a team and can play in the next round
255         if (!allowed_to_spawn && INGAME(player))
256                 return true;
257         return false;
258 }
259
260 MUTATOR_HOOKFUNCTION(ca, PutClientInServer)
261 {
262         entity player = M_ARGV(0, entity);
263
264         if (!allowed_to_spawn && IS_PLAYER(player)) // this is true even when player is trying to join
265         {
266                 TRANSMUTE(Observer, player);
267                 if (CS(player).jointime != time && !INGAME(player)) // not when connecting
268                 {
269                         INGAME_STATUS_SET(player, INGAME_STATUS_JOINING);
270                         Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_JOIN_LATE);
271                 }
272         }
273
274         if (!warmup_stage)
275                 eliminatedPlayers.SendFlags |= 1;
276 }
277
278 MUTATOR_HOOKFUNCTION(ca, reset_map_players)
279 {
280         g_ca_spectate_enemies = autocvar_g_ca_spectate_enemies;
281         observe_blocked_if_eliminated = (g_ca_spectate_enemies == -1);
282         // we can avoid sending observe_blocked_if_eliminated to all clients here (with ClientData_Touch)
283         // since it will get sent whenever the client spectates someone anyway
284
285         FOREACH_CLIENT(true, {
286                 CS(it).killcount = 0;
287                 if (INGAME(it) || IS_BOT_CLIENT(it))
288                 {
289                         TRANSMUTE(Player, it);
290                         INGAME_STATUS_SET(it, INGAME_STATUS_JOINED);
291                         PutClientInServer(it);
292                 }
293         });
294         return true;
295 }
296
297 MUTATOR_HOOKFUNCTION(ca, reset_map_global)
298 {
299         allowed_to_spawn = true;
300         return true;
301 }
302
303 MUTATOR_HOOKFUNCTION(ca, TeamBalance_CheckAllowedTeams, CBC_ORDER_EXCLUSIVE)
304 {
305         M_ARGV(0, float) = ca_teams;
306         return true;
307 }
308
309 entity ca_LastPlayerForTeam(entity this)
310 {
311         entity last_pl = NULL;
312         FOREACH_CLIENT(IS_PLAYER(it) && it != this, {
313                 if (!IS_DEAD(it) && SAME_TEAM(this, it))
314                 {
315                         if (!last_pl)
316                                 last_pl = it;
317                         else
318                                 return NULL;
319                 }
320         });
321         return last_pl;
322 }
323
324 void ca_LastPlayerForTeam_Notify(entity this)
325 {
326         if (!warmup_stage && round_handler_IsActive() && round_handler_IsRoundStarted())
327         {
328                 entity pl = ca_LastPlayerForTeam(this);
329                 if (pl)
330                         Send_Notification(NOTIF_ONE, pl, MSG_CENTER, CENTER_ALONE);
331         }
332 }
333
334 MUTATOR_HOOKFUNCTION(ca, PlayerDies)
335 {
336         entity frag_target = M_ARGV(2, entity);
337
338         ca_LastPlayerForTeam_Notify(frag_target);
339         if (!allowed_to_spawn)
340         {
341                 frag_target.respawn_flags = RESPAWN_SILENT;
342                 // prevent unwanted sudden rejoin as spectator and movement of spectator camera
343                 frag_target.respawn_time = time + 2;
344         }
345         frag_target.respawn_flags |= RESPAWN_FORCE;
346         if (!warmup_stage)
347                 eliminatedPlayers.SendFlags |= 1;
348         return true;
349 }
350
351
352 MUTATOR_HOOKFUNCTION(ca, ClientDisconnect)
353 {
354         entity player = M_ARGV(0, entity);
355
356         if (IS_PLAYER(player) && !IS_DEAD(player))
357                 ca_LastPlayerForTeam_Notify(player);
358         return true;
359 }
360
361 MUTATOR_HOOKFUNCTION(ca, MakePlayerObserver)
362 {
363         entity player = M_ARGV(0, entity);
364
365         bool is_forced = M_ARGV(1, bool);
366         if (is_forced && INGAME(player))
367                 INGAME_STATUS_CLEAR(player);
368
369         if (IS_PLAYER(player) && !IS_DEAD(player))
370                 ca_LastPlayerForTeam_Notify(player);
371         if (player.killindicator_teamchange == -2) // player wants to spectate
372         {
373                 entcs_update_players(player);
374                 INGAME_STATUS_CLEAR(player);
375         }
376         if (INGAME(player))
377         {
378                 player.frags = FRAGS_PLAYER_OUT_OF_GAME;
379                 player.would_spectate = observe_blocked_if_eliminated; // if blocked from observing force to spectate now
380         }
381         if (!warmup_stage)
382                 eliminatedPlayers.SendFlags |= 1;
383         if (!INGAME(player))
384                 return false;  // allow team reset
385         return true;  // prevent team reset
386 }
387
388 MUTATOR_HOOKFUNCTION(ca, ForbidThrowCurrentWeapon)
389 {
390         return true;
391 }
392
393 MUTATOR_HOOKFUNCTION(ca, GiveFragsForKill, CBC_ORDER_FIRST)
394 {
395         M_ARGV(2, float) = 0; // score will be given to the winner team when the round ends
396         return true;
397 }
398
399 MUTATOR_HOOKFUNCTION(ca, SetStartItems)
400 {
401         start_items       &= ~(IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS);
402         if(!cvar("g_use_ammunition"))
403                 start_items |= IT_UNLIMITED_AMMO;
404
405         start_health       = warmup_start_health       = autocvar_g_ca_start_health;
406         start_armorvalue   = warmup_start_armorvalue   = autocvar_g_ca_start_armor;
407         start_ammo_shells  = warmup_start_ammo_shells  = autocvar_g_ca_start_ammo_shells;
408         start_ammo_nails   = warmup_start_ammo_nails   = autocvar_g_ca_start_ammo_nails;
409         start_ammo_rockets = warmup_start_ammo_rockets = autocvar_g_ca_start_ammo_rockets;
410         start_ammo_cells   = warmup_start_ammo_cells   = autocvar_g_ca_start_ammo_cells;
411         start_ammo_plasma  = warmup_start_ammo_plasma  = autocvar_g_ca_start_ammo_plasma;
412         start_ammo_fuel    = warmup_start_ammo_fuel    = autocvar_g_ca_start_ammo_fuel;
413 }
414
415 MUTATOR_HOOKFUNCTION(ca, Damage_Calculate)
416 {
417         entity frag_attacker = M_ARGV(1, entity);
418         entity frag_target = M_ARGV(2, entity);
419         float frag_deathtype = M_ARGV(3, float);
420         float frag_damage = M_ARGV(4, float);
421         float frag_mirrordamage = M_ARGV(5, float);
422
423         if (IS_PLAYER(frag_target))
424         if (!IS_DEAD(frag_target))
425         if (frag_target == frag_attacker || SAME_TEAM(frag_target, frag_attacker) || frag_deathtype == DEATH_FALL.m_id)
426                 frag_damage = 0;
427
428         frag_mirrordamage = 0;
429
430         M_ARGV(4, float) = frag_damage;
431         M_ARGV(5, float) = frag_mirrordamage;
432 }
433
434 MUTATOR_HOOKFUNCTION(ca, FilterItem)
435 {
436         entity item = M_ARGV(0, entity);
437
438         if (autocvar_g_powerups <= 0)
439         if (item.itemdef.instanceOfPowerup)
440                 return true;
441
442         if (autocvar_g_pickup_items <= 0)
443                 return true;
444 }
445
446 MUTATOR_HOOKFUNCTION(ca, PlayerDamage_SplitHealthArmor)
447 {
448         if (time < game_starttime || (round_handler_IsActive() && !round_handler_IsRoundStarted()))
449                 return;
450
451         entity frag_attacker = M_ARGV(1, entity);
452         entity frag_target = M_ARGV(2, entity);
453         float frag_deathtype = M_ARGV(6, float);
454         float frag_damage = M_ARGV(7, float);
455         float damage_take = bound(0, M_ARGV(4, float), GetResource(frag_target, RES_HEALTH));
456         float damage_save = bound(0, M_ARGV(5, float), GetResource(frag_target, RES_ARMOR));
457
458         float excess = max(0, frag_damage - damage_take - damage_save);
459
460         if (autocvar_g_ca_damage2score <= 0 || frag_damage - excess == 0) return;
461
462         entity scorer = NULL;
463         float scorer_damage = 0;
464
465         if (IS_PLAYER(frag_attacker))
466         {
467                 if (DIFF_TEAM(frag_target, frag_attacker))
468                         scorer_damage = frag_damage - excess;
469                 else // friendly fire
470                         scorer_damage = -(frag_damage - excess);
471
472                 scorer = frag_attacker;
473         }
474         else
475         {
476                 //handle (environmental hazard) suiciding, check first if player has a registered attacker who most likely pushed them there to avoid punishing pushed players as pushers are already rewarded
477                 //deathtypes:
478                 //kill = suicide, drown = drown in water/liquid, hurttrigger = out of the map void or hurt triggers inside maps like electric sparks
479                 //camp = campcheck, lava = lava, slime = slime
480                 //team change / rebalance suicides are currently not included
481                 if (frag_deathtype == DEATH_KILL.m_id ||
482                         frag_deathtype == DEATH_DROWN.m_id ||
483                         frag_deathtype == DEATH_HURTTRIGGER.m_id ||
484                         frag_deathtype == DEATH_CAMP.m_id ||
485                         frag_deathtype == DEATH_LAVA.m_id ||
486                         frag_deathtype == DEATH_SLIME.m_id ||
487                         frag_deathtype == DEATH_SWAMP.m_id)
488                 {
489                         scorer_damage = -(frag_damage - excess);
490                         scorer = frag_target;
491                 }
492         }
493
494         if (scorer)
495                 GameRules_scoring_add_float2int(scorer, SCORE, scorer_damage, ca_damage_counter, autocvar_g_ca_damage2score);
496 }
497
498 MUTATOR_HOOKFUNCTION(ca, CalculateRespawnTime)
499 {
500         // no respawn calculations needed, player is forced to spectate anyway
501         return true;
502 }
503
504 MUTATOR_HOOKFUNCTION(ca, PlayerRegen)
505 {
506         // no regeneration in CA
507         return true;
508 }
509
510 MUTATOR_HOOKFUNCTION(ca, Scores_CountFragsRemaining)
511 {
512         // announce remaining frags
513         return true;
514 }
515
516 MUTATOR_HOOKFUNCTION(ca, SpectateSet)
517 {
518         entity client = M_ARGV(0, entity);
519         entity targ = M_ARGV(1, entity);
520
521         if (g_ca_spectate_enemies != 1 && INGAME(client))
522         if (DIFF_TEAM(targ, client))
523                 return true;
524 }
525
526 MUTATOR_HOOKFUNCTION(ca, SpectateNext)
527 {
528         entity client = M_ARGV(0, entity);
529
530         if (g_ca_spectate_enemies != 1 && INGAME(client)
531                 && Team_GetNumberOfAlivePlayers(Entity_GetTeam(client)))
532         {
533                 entity targ = M_ARGV(1, entity);
534                 M_ARGV(1, entity) = CA_SpectateNext(client, targ);
535                 return true;
536         }
537 }
538
539 MUTATOR_HOOKFUNCTION(ca, SpectatePrev)
540 {
541         entity client = M_ARGV(0, entity);
542         entity targ = M_ARGV(1, entity);
543         entity first = M_ARGV(2, entity);
544
545         if (g_ca_spectate_enemies != 1 && INGAME(client)
546                 && Team_GetNumberOfAlivePlayers(Entity_GetTeam(client)))
547         {
548                 do { targ = targ.chain; }
549                 while(targ && DIFF_TEAM(targ, client));
550
551                 if (!targ)
552                 {
553                         for (targ = first; targ && DIFF_TEAM(targ, client); targ = targ.chain);
554
555                         if (targ == client.enemy)
556                                 return MUT_SPECPREV_RETURN;
557                 }
558         }
559         else
560                 return MUT_SPECPREV_CONTINUE;
561
562         M_ARGV(1, entity) = targ;
563
564         return MUT_SPECPREV_FOUND;
565 }
566
567 MUTATOR_HOOKFUNCTION(ca, Bot_FixCount, CBC_ORDER_EXCLUSIVE)
568 {
569         FOREACH_CLIENT(IS_REAL_CLIENT(it), {
570                 if (IS_PLAYER(it) || INGAME_JOINED(it))
571                         ++M_ARGV(0, int);
572                 ++M_ARGV(1, int);
573         });
574         return true;
575 }
576
577 MUTATOR_HOOKFUNCTION(ca, ClientCommand_Spectate)
578 {
579         entity player = M_ARGV(0, entity);
580
581         if (INGAME(player))
582         {
583                 // they're going to spec, we can do other checks
584                 if (autocvar_sv_spectate && (IS_SPEC(player) || IS_OBSERVER(player)))
585                         Send_Notification(NOTIF_ONE_ONLY, player, MSG_INFO, INFO_CA_LEAVE);
586                 return MUT_SPECCMD_FORCE;
587         }
588
589         return MUT_SPECCMD_CONTINUE;
590 }
591
592 MUTATOR_HOOKFUNCTION(ca, HideTeamNagger)
593 {
594         return true; // doesn't work well with the whole spectator as player thing
595 }
596
597 MUTATOR_HOOKFUNCTION(ca, SetWeaponArena)
598 {
599         if (M_ARGV(0, string) == "0" || M_ARGV(0, string) == "")
600                 M_ARGV(0, string) = autocvar_g_ca_weaponarena;
601 }
602
603 MUTATOR_HOOKFUNCTION(ca, SV_ParseServerCommand)
604 {
605         string cmd_name = M_ARGV(0, string);
606         if (cmd_name == "shuffleteams")
607                 shuffleteams_on_reset_map = !allowed_to_spawn;
608         return false;
609 }