]> de.git.xonotic.org Git - voretournament/voretournament.git/blob - data/qcsrc/server/clientcommands.qc
Enable falling sounds
[voretournament/voretournament.git] / data / qcsrc / server / clientcommands.qc
1 entity nagger;\r
2 float readycount;\r
3 float Nagger_SendEntity(entity to, float sendflags)\r
4 {\r
5         float nags, i, f, b;\r
6         entity e;\r
7         WriteByte(MSG_ENTITY, ENT_CLIENT_NAGGER);\r
8 \r
9         nags = 0;\r
10         if(readycount)\r
11         {\r
12                 nags |= 1;\r
13                 if(to.ready == 0)\r
14                         nags |= 2;\r
15         }\r
16         if(votecalled)\r
17         {\r
18                 nags |= 4;\r
19                 if(to.vote_vote == 0)\r
20                         nags |= 8;\r
21         }\r
22         if(inWarmupStage)\r
23                 nags |= 16;\r
24 \r
25         if(sendflags & 128)\r
26                 nags |= 128;\r
27 \r
28         WriteByte(MSG_ENTITY, nags);\r
29 \r
30         if(nags & 128)\r
31         {\r
32                 WriteString(MSG_ENTITY, votecalledvote_display);\r
33         }\r
34 \r
35         if(nags & 1)\r
36         {\r
37                 for(i = 1; i <= maxclients; i += 8)\r
38                 {\r
39                         for(f = 0, e = edict_num(i), b = 1; b < 256; b *= 2, e = nextent(e))\r
40                                 if(clienttype(e) != CLIENTTYPE_REAL || e.ready)\r
41                                         f |= b;\r
42                         WriteByte(MSG_ENTITY, f);\r
43                 }\r
44         }\r
45 \r
46         return TRUE;\r
47 }\r
48 void Nagger_Init()\r
49 {\r
50         Net_LinkEntity(nagger = spawn(), FALSE, 0, Nagger_SendEntity);\r
51 }\r
52 void Nagger_VoteChanged()\r
53 {\r
54         if(nagger)\r
55                 nagger.SendFlags |= 128;\r
56 }\r
57 void Nagger_VoteCountChanged()\r
58 {\r
59         if(nagger)\r
60                 nagger.SendFlags |= 1;\r
61 }\r
62 void Nagger_ReadyCounted()\r
63 {\r
64         if(nagger)\r
65                 nagger.SendFlags |= 1;\r
66 }\r
67 \r
68 void ReadyCount();\r
69 string MapVote_Suggest(string m);\r
70 \r
71 entity GetPlayer(string name)\r
72 {\r
73         float num;\r
74         entity e;\r
75         string ns;\r
76 \r
77         if(substring(name, 0, 1) == "#") {\r
78                 num = stof(substring(name, 1, 999));\r
79                 if(num >= 1 && num <= maxclients) {\r
80                         for((e = world); num > 0; --num, (e = nextent(e)))\r
81                                 ;\r
82                         //if(clienttype(e) == CLIENTTYPE_REAL)\r
83                         if(e.classname == "player")\r
84                                 return e;\r
85                 }\r
86         } else {\r
87                 ns = strdecolorize(name);\r
88                 FOR_EACH_REALPLAYER(e) {\r
89                         if(!strcasecmp(strdecolorize(e.netname), ns)) {\r
90                                 return e;\r
91                         }\r
92                 }\r
93         }\r
94         return world;\r
95 }\r
96 \r
97 //float ctf_clientcommand();\r
98 float readyrestart_happened;\r
99 .float lms_spectate_warning;\r
100 void spawnfunc_func_breakable();\r
101 \r
102 .float cmd_floodtime;\r
103 .float cmd_floodcount;\r
104 float cmd_floodcheck()\r
105 {\r
106         if (timeoutStatus != 2)\r
107         {\r
108                 if(time == self.cmd_floodtime)\r
109                 {\r
110                         self.cmd_floodcount += 1;\r
111                         if(self.cmd_floodcount > 8)\r
112                                 return TRUE;\r
113                 }\r
114                 else\r
115                 {\r
116                         self.cmd_floodtime = time;\r
117                         self.cmd_floodcount = 1;\r
118                 }\r
119         }\r
120         return FALSE;\r
121 }\r
122 \r
123 void SV_ParseClientCommand(string s) {\r
124         string cmd;\r
125         float tokens;\r
126         float i;\r
127         entity e;\r
128 \r
129         tokens = tokenize_console(s);\r
130 \r
131         cmd = argv(0);\r
132         if(cmd != "reportcvar")\r
133         if(cmd != "sentcvar")\r
134         if(cmd != "pause")\r
135         if(cmd != "prespawn")\r
136         if(cmd != "spawn")\r
137         if(cmd != "begin")\r
138         {\r
139                 if(cmd_floodcheck())\r
140                         return;\r
141         }\r
142 \r
143         if(GameCommand_Vote(s, self)) {\r
144                 return;\r
145         } else if(GameCommand_MapVote(argv(0))) {\r
146                 return;\r
147         } else if(cmd == "autoswitch") {\r
148                 // be backwards compatible with older clients (enabled)\r
149                 self.autoswitch = ("0" != argv(1));\r
150                 local string autoswitchmsg;\r
151                 if (self.autoswitch) {\r
152                         autoswitchmsg = "on";\r
153                 } else {\r
154                         autoswitchmsg = "off";\r
155                 }\r
156                 sprint(self, strcat("^1autoswitch turned ", autoswitchmsg, "\n"));\r
157         } else if(cmd == "clientversion") {\r
158                 if not(self.flags & FL_CLIENT)\r
159                         return;\r
160                 if (argv(1) == "$gameversion") {\r
161                         //versionmsg = "^1client is too old to get versioninfo.\nUPDATE!!! (http://www.alientrap.org/voretournament/)^8";\r
162                         // either that or someone wants to be funny\r
163                         self.version = 1;\r
164                 } else {\r
165                         self.version = stof(argv(1));\r
166                 }\r
167                 if(self.version != cvar("gameversion"))\r
168                 {\r
169                         self.classname = "observer";\r
170                         self.version_mismatch = 1;\r
171                         PutClientInServer();\r
172                 } else if(cvar("g_campaign") || cvar("g_balance_teams") || cvar("g_balance_teams_force")) {\r
173                         //JoinBestTeam(self, FALSE, TRUE);\r
174                 } else if(teams_matter && !cvar("sv_spectate")) {\r
175                         self.classname = "observer";\r
176                         stuffcmd(self,"menu_showteamselect\n");\r
177                 }\r
178         } else if(cmd == "reportcvar") { // old system\r
179                 if(substring(argv(2), 0, 1) == "$") // undefined cvar: use the default value on the server then\r
180                 {\r
181                         s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");\r
182                         tokens = tokenize_console(s);\r
183                 }\r
184                 GetCvars(1);\r
185 #ifdef UID\r
186         } else if(cmd == "uid") {\r
187                 if not(self.uid)\r
188                 {\r
189                         self.uid = strzone(argv(1));\r
190                         self.uid_kicktime = 0;\r
191                         print("Client ", etos(self), " has UID ", self.uid, "\n");\r
192                         Ban_MaybeEnforceBan(self);\r
193                 }\r
194 #endif\r
195         } else if(cmd == "sentcvar") { // new system\r
196                 if(tokens == 2) // undefined cvar: use the default value on the server then\r
197                 {\r
198                         s = strcat(substring(s, argv_start_index(0), argv_end_index(1) - argv_start_index(0)), " \"", cvar_defstring(argv(1)), "\"");\r
199                         tokens = tokenize_console(s);\r
200                 }\r
201                 GetCvars(1);\r
202         } else if(cmd == "spectate") {\r
203                 if(cmd_floodcheck())\r
204                         return;\r
205                 if not(self.flags & FL_CLIENT)\r
206                         return;\r
207                 if(g_arena)\r
208                         return;\r
209                 if(g_lms)\r
210                 {\r
211                         if(self.lms_spectate_warning)\r
212                         {\r
213                                 // mark player as spectator\r
214                                 PlayerScore_Add(self, SP_LMS_RANK, 666 - PlayerScore_Add(self, SP_LMS_RANK, 0));\r
215                         }\r
216                         else\r
217                         {\r
218                                 self.lms_spectate_warning = 1;\r
219                                 sprint(self, "WARNING: you won't be able to enter the game again after spectating in LMS. Use the same command again to spectate anyway.\n");\r
220                                 return;\r
221                         }\r
222                 }\r
223                 if(self.classname == "player" && cvar("sv_spectate") == 1) {\r
224                         if(self.flagcarried)\r
225                                 DropFlag(self.flagcarried, world, world);\r
226                         kh_Key_DropAll(self, TRUE);\r
227                         WaypointSprite_PlayerDead();\r
228                         self.classname = "observer";\r
229                         if(g_ca)\r
230                                 self.caplayer = 0;\r
231                         if(blockSpectators)\r
232                                 sprint(self, strcat("^7You have to become a player within the next ", ftos(cvar("g_maxplayers_spectator_blocktime")), " seconds, otherwise you will be kicked, because spectators aren't allowed at this time!\n"));\r
233                         PutClientInServer();\r
234                 }\r
235         } else if(cmd == "join") {\r
236                 if not(self.flags & FL_CLIENT)\r
237                         return;\r
238                 if(!g_arena)\r
239                 if (self.classname != "player" && !lockteams)\r
240                 {\r
241                         if(isJoinAllowed()) {\r
242                                 self.classname = "player";\r
243                                 if(g_ca)\r
244                                         self.caplayer = 1;\r
245                                 PlayerScore_Clear(self);\r
246                                 bprint ("^4", self.netname, "^4 is playing now\n");\r
247                                 self.stat_count = WEP_LAST;\r
248                                 PutClientInServer();\r
249                                 if(cvar("g_campaign"))\r
250                                         campaign_bots_may_start = 1;\r
251                         }\r
252                         else {\r
253                                 //player may not join because of g_maxplayers is set\r
254                                 centerprint_atprio(self, CENTERPRIO_MAPVOTE, PREVENT_JOIN_TEXT);\r
255                         }\r
256                 }\r
257         } else if( cmd == "selectteam" ) {\r
258                 if not(self.flags & FL_CLIENT)\r
259                         return;\r
260                 if( !teams_matter ) {\r
261                         sprint( self, "selecteam can only be used in teamgames\n");\r
262                 } else if(cvar("g_campaign")) {\r
263                         //JoinBestTeam(self, 0);\r
264                 } else if(lockteams) {\r
265                         sprint( self, "^7The game has already begun, you must wait until the next map to be able to join a team.\n");\r
266                 } else if( argv(1) == "red" ) {\r
267                         DoTeamChange(COLOR_TEAM1);\r
268                 } else if( argv(1) == "blue" ) {\r
269                         DoTeamChange(COLOR_TEAM2);\r
270                 } else if( argv(1) == "yellow" ) {\r
271                         DoTeamChange(COLOR_TEAM3);\r
272                 } else if( argv(1) == "pink" ) {\r
273                         DoTeamChange(COLOR_TEAM4);\r
274                 } else if( argv(1) == "auto" ) {\r
275                         DoTeamChange(-1);\r
276                 } else {\r
277                         sprint( self, strcat( "selectteam none/red/blue/yellow/pink/auto - \"", argv(1), "\" not recognised\n" ) );\r
278                 }\r
279         } else if(cmd == "ready") {\r
280                 if not(self.flags & FL_CLIENT)\r
281                         return;\r
282 \r
283                 if((inWarmupStage && 0 >= g_warmup_limit) // with unlimited warmup players have to be able to restart\r
284                    || cvar("sv_ready_restart") || g_race_qualifying == 2)\r
285                 {\r
286                         if(!readyrestart_happened || cvar("sv_ready_restart_repeatable"))\r
287                         {\r
288                                 if (self.ready) // toggle\r
289                                 {\r
290                                         self.ready = FALSE;\r
291                                         bprint(self.netname, "^2 is ^1NOT^2 ready\n");\r
292                                 }\r
293                                 else\r
294                                 {\r
295                                         self.ready = TRUE;\r
296                                         bprint(self.netname, "^2 is ready\n");\r
297                                 }\r
298 \r
299                                 // cannot reset the game while a timeout is active!\r
300                                 if(!timeoutStatus)\r
301                                         ReadyCount();\r
302                         } else {\r
303                                 sprint(self, "^1Game has already been restarted\n");\r
304                         }\r
305                 }\r
306         } else if(cmd == "maplist") {\r
307                 sprint(self, maplist_reply);\r
308         } else if(cmd == "lsmaps") {\r
309                 sprint(self, lsmaps_reply);\r
310         } else if(cmd == "lsnewmaps") {\r
311                 sprint(self, lsnewmaps_reply);\r
312         } else if(cmd == "records") {\r
313                 for(i = 0; i < 10; ++i)\r
314                         sprint(self, records_reply[i]);\r
315         } else if(cmd == "rankings") {\r
316                 sprint(self, rankings_reply);\r
317         } else if(cmd == "voice") {\r
318                 if(tokens >= 3)\r
319                         VoiceMessage(argv(1), substring(s, argv_start_index(2), argv_end_index(-1) - argv_start_index(2)));\r
320                 else\r
321                         VoiceMessage(argv(1), "");\r
322         } else if(cmd == "say") {\r
323                 if(tokens >= 2)\r
324                         Say(self, FALSE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);\r
325                 //clientcommand(self, formatmessage(s));\r
326         } else if(cmd == "say_team") {\r
327                 if(tokens >= 2)\r
328                         Say(self, TRUE, world, substring(s, argv_start_index(1), argv_end_index(-1) - argv_start_index(1)), 1);\r
329                 //clientcommand(self, formatmessage(s));\r
330         } else if(cmd == "tell") {\r
331                 e = GetCommandPlayerSlotTargetFromTokenizedCommand(tokens, 1);\r
332                 if(e && tokens > ParseCommandPlayerSlotTarget_firsttoken)\r
333                 {\r
334                         Say(self, FALSE, e, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)), TRUE);\r
335                 }\r
336                 else\r
337                 {\r
338                         if(tokens > ParseCommandPlayerSlotTarget_firsttoken)\r
339                                 trigger_magicear_processmessage_forallears(self, -1, world, substring(s, argv_start_index(ParseCommandPlayerSlotTarget_firsttoken), argv_end_index(-1) - argv_start_index(ParseCommandPlayerSlotTarget_firsttoken)));\r
340                         sprint(self, "ERROR: usage: tell # playerid text...\n");\r
341                 }\r
342                 //clientcommand(self, formatmessage(s));\r
343         } else if(cmd == "info") {\r
344                 cmd = cvar_string_builtin(strcat("sv_info_", argv(1))); // This needed fixed for the cvar check\r
345                 if(cmd == "")\r
346                         sprint(self, "ERROR: unsupported info command\n");\r
347                 else\r
348                         wordwrap_sprint(cmd, 1111);\r
349         } else if(cmd == "suggestmap") {\r
350                 sprint(self, strcat(MapVote_Suggest(argv(1)), "\n"));\r
351         } else if(cmd == "timeout") {\r
352                 if not(self.flags & FL_CLIENT)\r
353                         return;\r
354                 if(cvar("sv_timeout")) {\r
355                         if(self.classname == "player") {\r
356                                 if(votecalled)\r
357                                         sprint(self, "^7Error: you can not call a timeout while a vote is active!\n");\r
358                                 else\r
359                                         evaluateTimeout();\r
360                         }\r
361                         else\r
362                                 sprint(self, "^7Error: only players can call a timeout!\n");\r
363                 }\r
364         } else if(cmd == "timein") {\r
365                 if not(self.flags & FL_CLIENT)\r
366                         return;\r
367                 if(cvar("sv_timeout")) {\r
368                         evaluateTimein();\r
369                 }\r
370         } else if(cmd == "teamstatus") {\r
371                 Score_NicePrint(self);\r
372         } else if(cmd == "cvar_changes") {\r
373                 sprint(self, cvar_changes);\r
374         } else if(CheatCommand(tokens)) {\r
375         } else {\r
376                 //if(ctf_clientcommand())\r
377                 //      return;\r
378                 // grep for Cmd_AddCommand_WithClientCommand to find them all\r
379                 if(cmd != "status")\r
380                 //if(cmd != "say") // handled above\r
381                 //if(cmd != "say_team") // handled above\r
382                 if(cmd != "kill")\r
383                 if(cmd != "pause")\r
384                 if(cmd != "ping")\r
385                 if(cmd != "name")\r
386                 if(cmd != "color")\r
387                 if(cmd != "rate")\r
388                 if(cmd != "pmodel")\r
389                 if(cmd != "playermodel")\r
390                 if(cmd != "playerskin")\r
391                 if(cmd != "prespawn")\r
392                 if(cmd != "spawn")\r
393                 if(cmd != "begin")\r
394                 if(cmd != "pings")\r
395                 if(cmd != "sv_startdownload")\r
396                 if(cmd != "download")\r
397                 {\r
398                         print("WARNING: Invalid clientcommand by ", self.netname, ": ", s, "\n");\r
399                         return;\r
400                 }\r
401 \r
402                 if(self.jointime > 0 && time > self.jointime + 10 && time > self.nickspamtime) // allow any changes in the first 10 seconds since joining\r
403                 if(cmd == "name" || cmd == "playermodel") // TODO also playerskin and color?\r
404                 {\r
405                         if(self.nickspamtime == 0 || time > self.nickspamtime + cvar("g_nick_flood_timeout"))\r
406                                 // good, no serious flood\r
407                                 self.nickspamcount = 1;\r
408                         else\r
409                                 self.nickspamcount += 1;\r
410                         self.nickspamtime = time + cvar("g_nick_flood_penalty");\r
411 \r
412                         if (timeoutStatus == 2) //when game is paused, no flood protection\r
413                                 self.nickspamcount = self.nickspamtime = 0;\r
414                 }\r
415 \r
416                 clientcommand(self,s);\r
417         }\r
418 }\r
419 \r
420 void ReadyRestartForce()\r
421 {\r
422         local entity e;\r
423 \r
424         bprint("^1Server is restarting...\n");\r
425 \r
426         VoteReset();\r
427 \r
428         // clear overtime\r
429         if (checkrules_overtimesadded > 0 && g_race_qualifying != 2) {\r
430                 //we have to decrease timelimit to its original value again!!\r
431                 float newTL;\r
432                 newTL = cvar("timelimit");\r
433                 newTL -= checkrules_overtimesadded * cvar("timelimit_overtime");\r
434                 cvar_set("timelimit", ftos(newTL));\r
435         }\r
436 \r
437         checkrules_suddendeathend = checkrules_overtimesadded = checkrules_suddendeathwarning = 0;\r
438 \r
439 \r
440         readyrestart_happened = 1;\r
441         game_starttime = time;\r
442         if(!g_ca)\r
443                 game_starttime += RESTART_COUNTDOWN;\r
444         restart_mapalreadyrestarted = 0; //reset this var, needed when cvar sv_ready_restart_repeatable is in use\r
445 \r
446         inWarmupStage = 0; //once the game is restarted the game is in match stage\r
447 \r
448         //reset the .ready status of all players (also spectators)\r
449         FOR_EACH_CLIENTSLOT(e)\r
450                 e.ready = 0;\r
451         readycount = 0;\r
452         Nagger_ReadyCounted(); // NOTE: this causes a resend of that entity, and will also turn off warmup state on the client\r
453 \r
454         if(cvar("teamplay_lockonrestart") && teams_matter) {\r
455                 lockteams = 1;\r
456                 bprint("^1The teams are now locked.\n");\r
457         }\r
458 \r
459         //initiate the restart-countdown-announcer entity\r
460         if(cvar("sv_ready_restart_after_countdown"))\r
461         {\r
462                 restartTimer = spawn();\r
463                 restartTimer.think = restartTimer_Think;\r
464                 restartTimer.nextthink = game_starttime;\r
465         }\r
466 \r
467         //after a restart every players number of allowed timeouts gets reset, too\r
468         if(cvar("sv_timeout"))\r
469         {\r
470                 FOR_EACH_REALPLAYER(e)\r
471                         e.allowedTimeouts = cvar("sv_timeout_number");\r
472         }\r
473 \r
474         //reset map immediately if this cvar is not set\r
475         if (!cvar("sv_ready_restart_after_countdown"))\r
476                 reset_map(TRUE);\r
477 \r
478         if(cvar("sv_eventlog"))\r
479                 GameLogEcho(":restart");\r
480 }\r
481 \r
482 void ReadyRestart()\r
483 {\r
484         // no arena, assault support yet...\r
485         if(g_arena | g_assault | gameover | intermission_running | race_completing)\r
486                 localcmd("restart\n");\r
487         else\r
488                 localcmd("\nsv_grabber_gamerestart;");\r
489 \r
490         ReadyRestartForce();\r
491 \r
492         // reset ALL scores, but only do that at the beginning\r
493         //of the countdown if sv_ready_restart_after_countdown is off!\r
494         //Otherwise scores could be manipulated during the countdown!\r
495         if (!cvar("sv_ready_restart_after_countdown"))\r
496                 Score_ClearAll();\r
497 }\r
498 \r
499 /**\r
500  * Counts how many players are ready. If not enough players are ready, the function\r
501  * does nothing. If all players are ready, the timelimit will be extended and the\r
502  * restart_countdown variable is set to allow other functions like PlayerPostThink\r
503  * to detect that the countdown is now active. If the cvar sv_ready_restart_after_countdown\r
504  * is not set the map will be resetted.\r
505  *\r
506  * Function is called after the server receives a 'ready' sign from a player.\r
507  */\r
508 void ReadyCount()\r
509 {\r
510         local entity e;\r
511         local float r, p;\r
512 \r
513         r = p = 0;\r
514 \r
515         FOR_EACH_REALPLAYER(e)\r
516         {\r
517                 p += 1;\r
518                 if(e.ready)\r
519                         r += 1;\r
520         }\r
521 \r
522         readycount = r;\r
523 \r
524         Nagger_ReadyCounted();\r
525 \r
526         if(r) // at least one is ready\r
527         if(r == p) // and, everyone is ready\r
528                 ReadyRestart();\r
529 }\r
530 \r
531 /**\r
532  * Restarts the map after the countdown is over (and cvar sv_ready_restart_after_countdown\r
533  * is set)\r
534  */\r
535 void restartTimer_Think() {\r
536         restart_mapalreadyrestarted = 1;\r
537         reset_map(TRUE);\r
538         Score_ClearAll();\r
539         remove(self);\r
540         return;\r
541 }\r
542 \r
543 /**\r
544  * Checks whether the player who calls the timeout is allowed to do so.\r
545  * If so, it initializes the timeout countdown. It also checks whether another\r
546  * timeout was already running at this time and reacts correspondingly.\r
547  *\r
548  * affected globals/fields: .allowedTimeouts, remainingTimeoutTime, remainingLeadTime,\r
549  *                          timeoutInitiator, timeoutStatus, timeoutHandler\r
550  *\r
551  * This function is called when a player issues the calltimeout command.\r
552  */\r
553 void evaluateTimeout() {\r
554         if (inWarmupStage && !g_warmup_allow_timeout)\r
555                 return sprint(self, "^7Error: You can not call a timeout in warmup-stage!\n");\r
556         if (time < game_starttime )\r
557                 return sprint(self, "^7Error: You can not call a timeout while the map is being restarted!\n");\r
558         if (timeoutStatus != 2) {\r
559                 //if the map uses a timelimit make sure that timeout cannot be called right before the map ends\r
560                 if (cvar("timelimit")) {\r
561                         //a timelimit was used\r
562                         local float myTl;\r
563                         myTl = cvar("timelimit");\r
564 \r
565                         local float lastPossibleTimeout;\r
566                         lastPossibleTimeout = (myTl*60) - cvar("sv_timeout_leadtime") - 1;\r
567 \r
568                         if (lastPossibleTimeout < time - game_starttime)\r
569                                 return sprint(self, "^7Error: It is too late to call a timeout now!\n");\r
570                 }\r
571         }\r
572         //player may not call a timeout if he has no calls left\r
573         if (self.allowedTimeouts < 1)\r
574                 return sprint(self, "^7Error: You already used all your timeout calls for this map!\n");\r
575         //now all required checks are passed\r
576         self.allowedTimeouts -= 1;\r
577         bprint(self.netname, " ^7called a timeout (", ftos(self.allowedTimeouts), " timeouts left)!\n"); //write a bprint who started the timeout (and how many he has left)\r
578         remainingTimeoutTime = cvar("sv_timeout_length");\r
579         remainingLeadTime = cvar("sv_timeout_leadtime");\r
580         timeoutInitiator = self;\r
581         if (timeoutStatus == 0) { //if another timeout was already active, don't change its status (which was 1 or 2) to 1, only change it to 1 if no timeout was active yet\r
582                 timeoutStatus = 1;\r
583                 //create the timeout indicator which centerprints the information to all players and takes care of pausing/unpausing\r
584                 timeoutHandler = spawn();\r
585                 timeoutHandler.think = timeoutHandler_Think;\r
586         }\r
587         timeoutHandler.nextthink = time; //always let the entity think asap\r
588 \r
589         //inform all connected clients about the timeout call\r
590         Announce("timeoutcalled");\r
591 }\r
592 \r
593 /**\r
594  * Checks whether a player is allowed to resume the game. If he is allowed to do it,\r
595  * and the lead time for the timeout is still active, this countdown just will be aborted (the\r
596  * game will never be paused). Otherwise the remainingTimeoutTime will be set to the corresponding\r
597  * value of the cvar sv_timeout_resumetime.\r
598  *\r
599  * This function is called when a player issues the resumegame command.\r
600  */\r
601 void evaluateTimein() {\r
602         if (!timeoutStatus)\r
603                 return sprint(self, "^7Error: There is no active timeout which could be aborted!\n");\r
604         if (self != timeoutInitiator)\r
605                 return sprint(self, "^7Error: You may not abort the active timeout. Only the player who called it can do that!\n");\r
606         if (timeoutStatus == 1) {\r
607                 remainingTimeoutTime = timeoutStatus = 0;\r
608                 timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately\r
609                 bprint(strcat("^7The timeout was aborted by ", self.netname, " !\n"));\r
610         }\r
611         else if (timeoutStatus == 2) {\r
612                 //only shorten the remainingTimeoutTime if it makes sense\r
613                 if( remainingTimeoutTime > (cvar("sv_timeout_resumetime") + 1) ) {\r
614                         bprint(strcat("^1Attention: ^7", self.netname, " resumed the game! Prepare for battle!\n"));\r
615                         remainingTimeoutTime = cvar("sv_timeout_resumetime");\r
616                         timeoutHandler.nextthink = time; //timeoutHandler has to take care of it immediately\r
617                 }\r
618                 else\r
619                         sprint(self, "^7Error: Your resumegame call was discarded!\n");\r
620 \r
621         }\r
622 }\r