Xonotic
world.qc
Go to the documentation of this file.
1 #include "world.qh"
2 
3 #include <common/constants.qh>
7 #include <common/items/_mod.qh>
8 #include <common/mapinfo.qh>
13 #include <common/monsters/_mod.qh>
15 #include <common/net_linked.qh>
17 #include <common/physics/player.qh>
18 #include <common/playerstats.qh>
19 #include <common/state.qh>
20 #include <common/stats.qh>
21 #include <common/teams.qh>
22 #include <common/util.qh>
23 #include <common/vehicles/all.qh>
24 #include <common/weapons/_all.qh>
25 #include <server/anticheat.qh>
26 #include <server/antilag.qh>
27 #include <server/bot/api.qh>
28 #include <server/campaign.qh>
29 #include <server/cheats.qh>
30 #include <server/client.qh>
31 #include <server/command/common.qh>
33 #include <server/command/sv_cmd.qh>
34 #include <server/command/vote.qh>
35 #include <server/damage.qh>
36 #include <server/gamelog.qh>
37 #include <server/hook.qh>
38 #include <server/intermission.qh>
39 #include <server/ipban.qh>
40 #include <server/items/items.qh>
41 #include <server/main.qh>
42 #include <server/mapvoting.qh>
43 #include <server/mutators/_mod.qh>
44 #include <server/race.qh>
45 #include <server/scores.qh>
46 #include <server/scores_rules.qh>
47 #include <server/spawnpoints.qh>
48 #include <server/teamplay.qh>
49 #include <server/weapons/common.qh>
51 
52 const float LATENCY_THINKRATE = 10;
53 .float latency_sum;
54 .float latency_cnt;
55 .float latency_time;
58 {
59  float delta;
60  entity e;
61 
62  delta = 3 / maxclients;
63  if(delta < sys_frametime)
64  delta = 0;
65  this.nextthink = time + delta;
66 
67  e = edict_num(this.cnt + 1);
68  if(IS_CLIENT(e) && IS_REAL_CLIENT(e))
69  {
70  WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
72  WriteShort(MSG_BROADCAST, bound(1, rint(CS(e).ping), 32767));
75 
76  // record latency times for clients throughout the match so we can report it to playerstats
78  {
79  CS(e).latency_sum += CS(e).ping;
80  CS(e).latency_cnt += 1;
81  CS(e).latency_time = time;
82  //print("sum: ", ftos(CS(e).latency_sum), ", cnt: ", ftos(CS(e).latency_cnt), ", avg: ", ftos(CS(e).latency_sum / CS(e).latency_cnt), ".\n");
83  }
84  }
85  else
86  {
87  WriteHeader(MSG_BROADCAST, TE_CSQC_PINGPLREPORT);
92  }
93  this.cnt = (this.cnt + 1) % maxclients;
94 }
96 {
99  pingplreport.nextthink = time;
100 }
101 
103 
105 {
107  {
109  if(default_player_alpha == 0)
112  }
113 }
114 
116 {
117  float n;
119  {
120  // cvar_set("_sv_init", "0");
121  // we do NOT set this to 0 any more, so someone "accidentally" changing
122  // to this "init" map on a dedicated server will cause no permanent
123  // harm
125  ShuffleMaplist();
127  cvar_set("g_maplist_index", ftos(n - 1)); // jump to map 0 in GotoNextMap
128 
131 
132  if(!DoNextMapOverride(1))
133  GotoNextMap(1);
134 
135  return;
136  }
137 
138  if(time < 5)
139  {
140  this.nextthink = time;
141  }
142  else
143  {
144  this.nextthink = time + 1;
145  LOG_INFO("Waiting for _sv_init being set to 1 by initialization scripts...");
146  }
147 }
148 
150 {
151  float h;
152  string k, v, d;
153  float n, i, adding, pureadding;
154 
158 
159  h = buf_create();
160  buf_cvarlist(h, "", "_"); // exclude all _ cvars as they are temporary
161  n = buf_getsize(h);
162 
163  adding = true;
164  pureadding = true;
165 
166  for(i = 0; i < n; ++i)
167  {
168  k = bufstr_get(h, i);
169 
170 #define BADPREFIX(p) if(substring(k, 0, strlen(p)) == p) continue
171 #define BADPRESUFFIX(p,s) if(substring(k, 0, strlen(p)) == p && substring(k, -strlen(s), -1) == s) continue
172 #define BADCVAR(p) if(k == p) continue
173 #define BADVALUE(p, val) if (k == p && v == val) continue
174 
175  // general excludes and namespaces for server admin used cvars
176  BADPREFIX("help_"); // PN's server has this listed as changed, let's not rat him out for THAT
177 
178  // internal
179  BADPREFIX("csqc_");
180  BADPREFIX("cvar_check_");
181  BADCVAR("gamecfg");
182  BADCVAR("g_configversion");
183  BADCVAR("halflifebsp");
184  BADCVAR("sv_mapformat_is_quake2");
185  BADCVAR("sv_mapformat_is_quake3");
186  BADPREFIX("sv_world");
187 
188  // client
189  BADPREFIX("chase_");
190  BADPREFIX("cl_");
191  BADPREFIX("con_");
192  BADPREFIX("scoreboard_");
193  BADPREFIX("g_campaign");
194  BADPREFIX("g_waypointsprite_");
195  BADPREFIX("gl_");
196  BADPREFIX("joy");
197  BADPREFIX("hud_");
198  BADPREFIX("m_");
199  BADPREFIX("menu_");
200  BADPREFIX("net_slist_");
201  BADPREFIX("r_");
202  BADPREFIX("sbar_");
203  BADPREFIX("scr_");
204  BADPREFIX("snd_");
205  BADPREFIX("show");
206  BADPREFIX("sensitivity");
207  BADPREFIX("userbind");
208  BADPREFIX("v_");
209  BADPREFIX("vid_");
210  BADPREFIX("crosshair");
211  BADCVAR("mod_q3bsp_lightmapmergepower");
212  BADCVAR("mod_q3bsp_nolightmaps");
213  BADCVAR("fov");
214  BADCVAR("mastervolume");
215  BADCVAR("volume");
216  BADCVAR("bgmvolume");
217  BADCVAR("in_pitch_min");
218  BADCVAR("in_pitch_max");
219 
220  // private
221  BADCVAR("developer");
222  BADCVAR("log_dest_udp");
223  BADCVAR("net_address");
224  BADCVAR("net_address_ipv6");
225  BADCVAR("port");
226  BADCVAR("savedgamecfg");
227  BADCVAR("serverconfig");
228  BADCVAR("sv_autoscreenshot");
229  BADCVAR("sv_heartbeatperiod");
230  BADCVAR("sv_vote_master_password");
231  BADCVAR("sys_colortranslation");
232  BADCVAR("sys_specialcharactertranslation");
233  BADCVAR("timeformat");
234  BADCVAR("timestamps");
235  BADCVAR("g_require_stats");
236  BADPREFIX("developer_");
237  BADPREFIX("g_ban_");
238  BADPREFIX("g_banned_list");
239  BADPREFIX("g_require_stats_");
240  BADPREFIX("g_chat_flood_");
241  BADPREFIX("g_ghost_items");
242  BADPREFIX("g_playerstats_");
243  BADPREFIX("g_voice_flood_");
244  BADPREFIX("log_file");
245  BADPREFIX("quit_");
246  BADPREFIX("rcon_");
247  BADPREFIX("sv_allowdownloads");
248  BADPREFIX("sv_autodemo");
249  BADPREFIX("sv_curl_");
250  BADPREFIX("sv_eventlog");
251  BADPREFIX("sv_logscores_");
252  BADPREFIX("sv_master");
253  BADPREFIX("sv_weaponstats_");
254  BADPREFIX("sv_waypointsprite_");
255  BADCVAR("rescan_pending");
256 
257  // these can contain player IDs, so better hide
258  BADPREFIX("g_forced_team_");
259  BADCVAR("sv_muteban_list");
260  BADCVAR("sv_voteban_list");
261  BADCVAR("sv_allow_customplayermodels_idlist");
262  BADCVAR("sv_allow_customplayermodels_speciallist");
263 
264  // mapinfo
265  BADCVAR("fraglimit");
266  BADCVAR("g_arena");
267  BADCVAR("g_assault");
268  BADCVAR("g_ca");
269  BADCVAR("g_ca_teams");
270  BADCVAR("g_conquest");
271  BADCVAR("g_conquest_teams");
272  BADCVAR("g_ctf");
273  BADCVAR("g_cts");
274  BADCVAR("g_dotc");
275  BADCVAR("g_dm");
276  BADCVAR("g_domination");
277  BADCVAR("g_domination_default_teams");
278  BADCVAR("g_duel");
279  BADCVAR("g_duel_not_dm_maps");
280  BADCVAR("g_freezetag");
281  BADCVAR("g_freezetag_teams");
282  BADCVAR("g_invasion_teams");
283  BADCVAR("g_invasion_type");
284  BADCVAR("g_jailbreak");
285  BADCVAR("g_jailbreak_teams");
286  BADCVAR("g_keepaway");
287  BADCVAR("g_keyhunt");
288  BADCVAR("g_keyhunt_teams");
289  BADCVAR("g_lms");
290  BADCVAR("g_nexball");
291  BADCVAR("g_onslaught");
292  BADCVAR("g_race");
293  BADCVAR("g_race_laps_limit");
294  BADCVAR("g_race_qualifying_timelimit");
295  BADCVAR("g_race_qualifying_timelimit_override");
296  BADCVAR("g_runematch");
297  BADCVAR("g_shootfromeye");
298  BADCVAR("g_snafu");
299  BADCVAR("g_survival");
300  BADCVAR("g_survival_not_dm_maps");
301  BADCVAR("g_tdm");
302  BADCVAR("g_tdm_on_dm_maps");
303  BADCVAR("g_tdm_teams");
304  BADCVAR("g_vip");
305  BADCVAR("leadlimit");
306  BADCVAR("nextmap");
307  BADCVAR("teamplay");
308  BADCVAR("timelimit");
309  BADCVAR("g_mapinfo_settemp_acl");
310  BADCVAR("g_mapinfo_ignore_warnings");
311  BADCVAR("g_maplist_ignore_sizes");
312  BADCVAR("g_maplist_sizes_count_bots");
313 
314  // long
315  BADCVAR("hostname");
316  BADCVAR("g_maplist");
317  BADCVAR("g_maplist_mostrecent");
318  BADCVAR("sv_motd");
319 
320  v = cvar_string(k);
321  d = cvar_defstring(k);
322  if(v == d)
323  continue;
324 
325  if(adding)
326  {
327  cvar_changes = strcat(cvar_changes, k, " \"", v, "\" // \"", d, "\"\n");
328  if(strlen(cvar_changes) > 16384)
329  {
330  cvar_changes = "// too many settings have been changed to show them here\n";
331  adding = 0;
332  }
333  }
334 
335  // now check if the changes are actually gameplay relevant
336 
337  // does nothing gameplay relevant
338  BADCVAR("captureleadlimit_override");
339  BADCVAR("condump_stripcolors");
340  BADCVAR("gameversion");
341  BADCVAR("fs_gamedir");
342  BADCVAR("g_allow_oldvortexbeam");
343  BADCVAR("g_balance_kill_delay");
344  BADCVAR("g_buffs_pickup_anyway");
345  BADCVAR("g_buffs_randomize");
346  BADCVAR("g_buffs_randomize_teamplay");
347  BADCVAR("g_campcheck_distance");
348  BADCVAR("g_chatsounds");
349  BADCVAR("g_ca_point_leadlimit");
350  BADCVAR("g_ca_point_limit");
351  BADCVAR("g_ca_spectate_enemies");
352  BADCVAR("g_ctf_captimerecord_always");
353  BADCVAR("g_ctf_flag_glowtrails");
354  BADCVAR("g_ctf_dynamiclights");
355  BADCVAR("g_ctf_flag_pickup_verbosename");
356  BADCVAR("g_ctf_flagcarrier_auto_helpme_damage");
357  BADPRESUFFIX("g_ctf_flag_", "_model");
358  BADPRESUFFIX("g_ctf_flag_", "_skin");
359  BADCVAR("g_domination_point_leadlimit");
360  BADCVAR("g_forced_respawn");
361  BADCVAR("g_freezetag_point_leadlimit");
362  BADCVAR("g_freezetag_point_limit");
363  BADCVAR("g_glowtrails");
364  BADCVAR("g_hats");
365  BADCVAR("g_casings");
366  BADCVAR("g_invasion_point_limit");
367  BADCVAR("g_jump_grunt");
368  BADCVAR("g_keepaway_ballcarrier_effects");
369  BADCVAR("g_keepawayball_effects");
370  BADCVAR("g_keyhunt_point_leadlimit");
371  BADCVAR("g_nexball_goalleadlimit");
372  BADCVAR("g_new_toys_autoreplace");
373  BADCVAR("g_new_toys_use_pickupsound");
374  BADCVAR("g_physics_predictall");
375  BADCVAR("g_piggyback");
376  BADCVAR("g_playerclip_collisions");
377  BADCVAR("g_spawn_alloweffects");
378  BADCVAR("g_tdm_point_leadlimit");
379  BADCVAR("g_tdm_point_limit");
380  BADCVAR("leadlimit_and_fraglimit");
381  BADCVAR("leadlimit_override");
382  BADCVAR("pausable");
383  BADCVAR("sv_announcer");
384  BADCVAR("sv_checkforpacketsduringsleep");
385  BADCVAR("sv_damagetext");
386  BADCVAR("sv_db_saveasdump");
387  BADCVAR("sv_intermission_cdtrack");
388  BADCVAR("sv_mapchange_delay");
389  BADCVAR("sv_minigames");
390  BADCVAR("sv_namechangetimer");
391  BADCVAR("sv_precacheplayermodels");
392  BADCVAR("sv_qcphysics");
393  BADCVAR("sv_radio");
394  BADCVAR("sv_stepheight");
395  BADCVAR("sv_timeout");
396  BADCVAR("sv_weapons_modeloverride");
397  BADCVAR("w_prop_interval");
398  BADPREFIX("chat_");
399  BADPREFIX("crypto_");
400  BADPREFIX("gameversion_");
401  BADPREFIX("g_chat_");
402  BADPREFIX("g_ctf_captimerecord_");
403  BADPREFIX("g_hats_");
404  BADPREFIX("g_maplist_");
405  BADPREFIX("g_mod_");
406  BADPREFIX("g_respawn_");
407  BADPREFIX("net_");
408  BADPREFIX("notification_");
409  BADPREFIX("prvm_");
410  BADPREFIX("skill_");
411  BADPREFIX("sv_allow_");
412  BADPREFIX("sv_cullentities_");
413  BADPREFIX("sv_maxidle");
414  BADPREFIX("sv_minigames_");
415  BADPREFIX("sv_radio_");
416  BADPREFIX("sv_timeout_");
417  BADPREFIX("sv_vote_");
418  BADPREFIX("timelimit_");
419 
420  // allowed changes to server admins (please sync this to server.cfg)
421  // vi commands:
422  // :/"impure"/,$d
423  // :g!,^\/\/[^ /],d
424  // :%s,//\([^ ]*\).*,BADCVAR("\1");,
425  // :%!sort
426  // yes, this does contain some redundant stuff, don't really care
427  BADPREFIX("bot_ai_");
428  BADCVAR("bot_config_file");
429  BADCVAR("bot_number");
430  BADCVAR("bot_prefix");
431  BADCVAR("bot_suffix");
432  BADCVAR("capturelimit_override");
433  BADCVAR("fraglimit_override");
434  BADCVAR("gametype");
435  BADCVAR("g_antilag");
436  BADCVAR("g_balance_teams");
437  BADCVAR("g_balance_teams_prevent_imbalance");
438  BADCVAR("g_balance_teams_scorefactor");
439  BADCVAR("g_ban_sync_trusted_servers");
440  BADCVAR("g_ban_sync_uri");
441  BADCVAR("g_buffs");
442  BADCVAR("g_ca_teams_override");
443  BADCVAR("g_ctf_fullbrightflags");
444  BADCVAR("g_ctf_ignore_frags");
445  BADCVAR("g_ctf_leaderboard");
446  BADCVAR("g_domination_point_limit");
447  BADCVAR("g_domination_teams_override");
448  BADCVAR("g_freezetag_revive_spawnshield");
449  BADCVAR("g_freezetag_teams_override");
450  BADCVAR("g_friendlyfire");
451  BADCVAR("g_fullbrightitems");
452  BADCVAR("g_fullbrightplayers");
453  BADCVAR("g_keyhunt_point_limit");
454  BADCVAR("g_keyhunt_teams_override");
455  BADCVAR("g_lms_lives_override");
456  BADCVAR("g_maplist");
457  BADCVAR("g_maxplayers");
458  BADCVAR("g_mirrordamage");
459  BADCVAR("g_nexball_goallimit");
460  BADCVAR("g_norecoil");
461  BADCVAR("g_physics_clientselect");
462  BADCVAR("g_pinata");
463  BADCVAR("g_powerups");
464  BADCVAR("g_powerups_drop_ondeath");
465  BADCVAR("g_player_brightness");
466  BADCVAR("g_rocket_flying");
467  BADCVAR("g_rocket_flying_disabledelays");
468  BADPREFIX("g_spawnshield");
469  BADCVAR("g_start_delay");
470  BADCVAR("g_superspectate");
471  BADCVAR("g_tdm_teams_override");
472  BADCVAR("g_warmup");
473  BADCVAR("g_weapon_stay"); BADPRESUFFIX("g_", "_weapon_stay");
474  BADCVAR("hostname");
475  BADCVAR("log_file");
476  BADCVAR("maxplayers");
477  BADCVAR("minplayers");
478  BADCVAR("minplayers_per_team");
479  BADCVAR("net_address");
480  BADCVAR("port");
481  BADCVAR("rcon_password");
482  BADCVAR("rcon_restricted_commands");
483  BADCVAR("rcon_restricted_password");
484  BADCVAR("skill");
485  BADCVAR("sv_adminnick");
486  BADCVAR("sv_autoscreenshot");
487  BADCVAR("sv_autotaunt");
488  BADCVAR("sv_curl_defaulturl");
489  BADCVAR("sv_defaultcharacter");
490  BADCVAR("sv_defaultcharacterskin");
491  BADCVAR("sv_defaultplayercolors");
492  BADCVAR("sv_defaultplayermodel");
493  BADCVAR("sv_defaultplayerskin");
494  BADCVAR("sv_maxrate");
495  BADCVAR("sv_motd");
496  BADCVAR("sv_public");
497  BADCVAR("sv_showfps");
498  BADCVAR("sv_status_privacy");
499  BADCVAR("sv_taunt");
500  BADCVAR("sv_vote_call");
501  BADCVAR("sv_vote_commands");
502  BADCVAR("sv_vote_majority_factor");
503  BADCVAR("sv_vote_master");
504  BADCVAR("sv_vote_master_commands");
505  BADCVAR("sv_vote_master_password");
506  BADCVAR("sv_vote_simple_majority_factor");
507  BADVALUE("sys_ticrate", "0.0166667");
508  BADVALUE("sys_ticrate", "0.0333333");
509  BADCVAR("teamplay_mode");
510  BADCVAR("timelimit_override");
511  BADPREFIX("g_warmup_");
512  BADPREFIX("sv_info_");
513  BADPREFIX("sv_ready_restart_");
514 
515  // mutators that announce themselves properly to the server browser
516  BADCVAR("g_instagib");
517  BADCVAR("g_new_toys");
518  BADCVAR("g_nix");
519  BADCVAR("g_grappling_hook");
520  BADCVAR("g_jetpack");
521 
522  // temporary for testing
523  // TODO remove before 0.8.3 release
524  BADCVAR("g_ca_weaponarena");
525  BADCVAR("g_freezetag_weaponarena");
526  BADCVAR("g_lms_weaponarena");
527  BADCVAR("g_ctf_stalemate_time");
528 
529 #undef BADPRESUFFIX
530 #undef BADPREFIX
531 #undef BADCVAR
532 #undef BADVALUE
533 
534  if(pureadding)
535  {
536  cvar_purechanges = strcat(cvar_purechanges, k, " \"", v, "\" // \"", d, "\"\n");
537  if(strlen(cvar_purechanges) > 16384)
538  {
539  cvar_purechanges = "// too many settings have been changed to show them here\n";
540  pureadding = 0;
541  }
542  }
544  // WARNING: this variable is used for the server list
545  // NEVER dare to skip this code!
546  // Hacks to intentionally appearing as "pure server" even though you DO have
547  // modified settings may be punished by removal from the server list.
548  // You can do to the variables cvar_changes and cvar_purechanges all you want,
549  // though.
550  }
551  buf_del(h);
552  if(cvar_changes == "")
553  cvar_changes = "// this server runs at default server settings\n";
554  else
555  cvar_changes = strcat("// this server runs at modified server settings:\n", cvar_changes);
557  if(cvar_purechanges == "")
558  cvar_purechanges = "// this server runs at default gameplay settings\n";
559  else
560  cvar_purechanges = strcat("// this server runs at modified gameplay settings:\n", cvar_purechanges);
562 }
563 
565 bool RandomSeed_Send(entity this, entity to, int sf)
566 {
567  WriteHeader(MSG_ENTITY, ENT_CLIENT_RANDOMSEED);
568  WriteShort(MSG_ENTITY, this.cnt);
569  return true;
570 }
572 {
573  this.cnt = bound(0, floor(random() * 65536), 65535);
574  this.nextthink = time + 5;
575 
576  this.SendFlags |= 1;
577 }
579 {
582  Net_LinkEntity(randomseed, false, 0, RandomSeed_Send);
583 
584  getthink(randomseed)(randomseed); // sets random seed and nextthink
585 }
586 
587 spawnfunc(__init_dedicated_server)
588 {
589  // handler for _init/_init map (only for dedicated server initialization)
590 
591  world_initialized = -1; // don't complain
592 
594 
595  entity e = new(GotoFirstMap);
597  e.nextthink = time; // this is usually 1 at this point
598 
599  e = new(info_player_deathmatch); // safeguard against player joining
600 
601  // assign reflectively to avoid "assignment to world" warning
602  for (int i = 0, n = numentityfields(); i < n; ++i) {
603  string k = entityfieldname(i);
604  if (k == "classname") {
605  // safeguard against various stuff ;)
606  putentityfieldstring(i, this, "worldspawn");
607  break;
608  }
609  }
610 
611  // needs to be done so early because of the constants they create
612  static_init();
615 
616  IL_PUSH(g_spawnpoints, e); // just incase
617 
620 }
621 
624 }
625 
627 {
628  maxclients = 0;
629  for (entity head = nextent(NULL); head; head = nextent(head)) {
630  ++maxclients;
631  }
632 }
633 
635 {
636  if(!scores_initialized)
638 }
639 
641 {
642  VoteReset();
643 
644  // find out good world mins/maxs bounds, either the static bounds found by looking for solid, or the mapinfo specified bounds
645  get_mi_min_max(1);
646  // assign reflectively to avoid "assignment to world" warning
647  int done = 0; for (int i = 0, n = numentityfields(); i < n; ++i) {
648  string k = entityfieldname(i); vector v = (k == "mins") ? mi_min : (k == "maxs") ? mi_max : '0 0 0';
649  if (v) {
650  putentityfieldstring(i, world, sprintf("%v", v));
651  if (++done == 2) break;
652  }
653  }
654  // currently, NetRadiant's limit is 131072 qu for each side
655  // distance from one corner of a 131072qu cube to the opposite corner is approx. 227023 qu
656  // set the distance according to map size but don't go over the limit to avoid issues with float precision
657  // in case somebody makes extremely large maps
658  max_shot_distance = min(230000, vlen(world.maxs - world.mins));
659 
661  GameRules_teams(false);
662 
663  if (!cvar_value_issafe(world.fog))
664  {
665  LOG_INFO("The current map contains a potentially harmful fog setting, ignored");
666  world.fog = string_null;
667  }
668  if(MapInfo_Map_fog != "")
669  {
670  if(MapInfo_Map_fog == "none")
671  world.fog = string_null;
672  else
674  }
676 
678 
680 
683 
684  InitializeEntity(NULL, GameplayMode_DelayedInit, INITPRIO_GAMETYPE_FALLBACK);
685 }
686 
688 spawnfunc(worldspawn)
689 {
690  server_is_dedicated = boolean(stof(cvar_defstring("is_dedicated")));
691 
693  {
695  }
696  else
697  {
699  }
700 
701  bool wantrestart = false;
702  {
703  if (!server_is_dedicated)
704  {
705  // force unloading of server pk3 files when starting a listen server
706  // localcmd("\nfs_rescan\n"); // FIXME: does more harm than good, has unintended side effects. What we really want is to unload temporary pk3s only
707  // restore csqc_progname too
708  string expect = "csprogs.dat";
709  wantrestart = cvar_string("csqc_progname") != expect;
710  cvar_set("csqc_progname", expect);
711  }
712  else
713  {
714  // Try to use versioned csprogs from pk3
715  // Only ever use versioned csprogs.dat files on dedicated servers;
716  // we need to reset csqc_progname on clients ourselves, and it's easier if the client's release name is constant
717  string pk3csprogs = "csprogs-" WATERMARK ".dat";
718  // This always works; fall back to it if a versioned csprogs.dat is suddenly missing
719  string select = "csprogs.dat";
720  if (fexists(pk3csprogs)) select = pk3csprogs;
721  if (cvar_string("csqc_progname") != select)
722  {
723  cvar_set("csqc_progname", select);
724  wantrestart = true;
725  }
726  // Check for updates on startup
727  // We do it this way for atomicity so that connecting clients still match the server progs and don't disconnect
728  int sentinel = fopen("progs.txt", FILE_READ);
729  if (sentinel >= 0)
730  {
731  string switchversion = fgets(sentinel);
732  fclose(sentinel);
733  if (switchversion != "" && switchversion != WATERMARK)
734  {
735  LOG_INFOF("Switching progs: " WATERMARK " -> %s", switchversion);
736  // if it doesn't exist, assume either:
737  // a) the current program was overwritten
738  // b) this is a client only update
739  string newprogs = sprintf("progs-%s.dat", switchversion);
740  if (fexists(newprogs))
741  {
742  cvar_set("sv_progs", newprogs);
743  wantrestart = true;
744  }
745  string newcsprogs = sprintf("csprogs-%s.dat", switchversion);
746  if (fexists(newcsprogs))
747  {
748  cvar_set("csqc_progname", newcsprogs);
749  wantrestart = true;
750  }
751  }
752  }
753  }
754  if (wantrestart)
755  {
756  LOG_INFO("Restart requested");
758  // let initialization continue, shutdown depends on it
759  }
760  }
761 
763  error("world already spawned - you may have EXACTLY ONE worldspawn!");
764  world_already_spawned = true;
765 
766  delete_fn = remove_safely; // during spawning, watch what you remove!
767 
768  cvar_changes_init(); // do this very early now so it REALLY matches the server config
769 
770  // default to RACE_RECORD, can be overwritten by gamemodes
772 
773  // needs to be done so early because of the constants they create
774  static_init();
775 
777 
779 
780  // 0 normal
781  lightstyle(0, "m");
782 
783  // 1 FLICKER (first variety)
784  lightstyle(1, "mmnmmommommnonmmonqnmmo");
785 
786  // 2 SLOW STRONG PULSE
787  lightstyle(2, "abcdefghijklmnopqrstuvwxyzyxwvutsrqponmlkjihgfedcba");
788 
789  // 3 CANDLE (first variety)
790  lightstyle(3, "mmmmmaaaaammmmmaaaaaabcdefgabcdefg");
791 
792  // 4 FAST STROBE
793  lightstyle(4, "mamamamamama");
794 
795  // 5 GENTLE PULSE 1
796  lightstyle(5,"jklmnopqrstuvwxyzyxwvutsrqponmlkj");
797 
798  // 6 FLICKER (second variety)
799  lightstyle(6, "nmonqnmomnmomomno");
800 
801  // 7 CANDLE (second variety)
802  lightstyle(7, "mmmaaaabcdefgmmmmaaaammmaamm");
803 
804  // 8 CANDLE (third variety)
805  lightstyle(8, "mmmaaammmaaammmabcdefaaaammmmabcdefmmmaaaa");
806 
807  // 9 SLOW STROBE (fourth variety)
808  lightstyle(9, "aaaaaaaazzzzzzzz");
809 
810  // 10 FLUORESCENT FLICKER
811  lightstyle(10, "mmamammmmammamamaaamammma");
812 
813  // 11 SLOW PULSE NOT FADE TO BLACK
814  lightstyle(11, "abcdefghijklmnopqrrqponmlkjihgfedcba");
815 
816  // styles 32-62 are assigned by the spawnfunc_light program for switchable lights
817 
818  // 63 testing
819  lightstyle(63, "a");
820 
822  CampaignPreInit();
823 
825 
826  PlayerStats_GameReport_Init(); // we need this to be initiated before InitGameplayMode
827 
831  readlevelcvars();
832 
834 
835  if(warmup_limit == 0)
836  warmup_limit = (autocvar_timelimit > 0) ? autocvar_timelimit * 60 : autocvar_timelimit;
837 
838  player_count = 0;
840  if(bot_waypoints_for_items == 1)
843 
844  WaypointSprite_Init();
845 
846  GameLogInit(); // prepare everything
847  // NOTE for matchid:
848  // changing the logic generating it is okay. But:
849  // it HAS to stay <= 64 chars
850  // character set: ASCII 33-126 without the following characters: : ; ' " \ $
852  {
853  string num = strftime_s(); // strftime(false, "%s") isn't reliable, see strftime_s description
854  string s = sprintf("%s.%s.%06d", itos(autocvar_sv_eventlog_files_counter), num, floor(random() * 1000000));
855  matchid = strzone(s);
856 
857  GameLogEcho(strcat(":gamestart:", GetGametype(), "_", GetMapname(), ":", s));
858  s = ":gameinfo:mutators:LIST";
859 
860  MUTATOR_CALLHOOK(BuildMutatorsString, s);
861  s = M_ARGV(0, string);
862 
863  // initialiation stuff, not good in the mutator system
865  s = strcat(s, ":no_use_ammunition");
866 
867  // initialiation stuff, not good in the mutator system
868  if(autocvar_g_pickup_items == 0)
869  s = strcat(s, ":no_pickup_items");
871  s = strcat(s, ":pickup_items");
872 
873  // initialiation stuff, not good in the mutator system
874  if(autocvar_g_weaponarena != "0")
875  s = strcat(s, ":", autocvar_g_weaponarena, " arena");
876 
877  // TODO to mutator system
879  s = strcat(s, ":norecoil");
880 
881  GameLogEcho(s);
882  GameLogEcho(":gameinfo:end");
883  }
884  else
885  matchid = strzone(ftos(random()));
886 
887  cvar_set("nextmap", "");
888 
889  SetDefaultAlpha();
890 
893 
894  Ban_LoadBans();
895 
898 
899  q3compat = BITSET(q3compat, Q3COMPAT_ARENA, fexists(strcat("scripts/", mapname, ".arena")));
900  q3compat = BITSET(q3compat, Q3COMPAT_DEFI, fexists(strcat("scripts/", mapname, ".defi")));
901 
902  if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
903  {
904  int fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ);
905  if(fd != -1)
906  {
907  string s;
908  while((s = fgets(fd)))
909  {
910  int l = tokenize_console(s);
911  if(l < 2)
912  continue;
913  if(argv(0) == "cd")
914  {
915  string trackname = argv(2);
916  LOG_INFO("Found ^1UNSUPPORTED^7 cd loop command in .cfg file; put this line in mapinfo instead:");
917  LOG_INFO(" cdtrack ", trackname);
918  if (cvar_value_issafe(trackname))
919  {
920  string newstuff = strcat(clientstuff, "cd loop \"", trackname, "\"\n");
921  strcpy(clientstuff, newstuff);
922  }
923  }
924  else if(argv(0) == "fog")
925  {
926  LOG_INFO("Found ^1UNSUPPORTED^7 fog command in .cfg file; put this line in worldspawn in the .map/.bsp/.ent file instead:");
927  LOG_INFO(" \"fog\" \"", s, "\"");
928  }
929  else if(argv(0) == "set")
930  {
931  LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:");
932  LOG_INFO(" clientsettemp_for_type all ", argv(1), " ", argv(2));
933  }
934  else if(argv(0) != "//")
935  {
936  LOG_INFO("Found ^1UNSUPPORTED^7 set command in .cfg file; put this line in mapinfo instead:");
937  LOG_INFO(" clientsettemp_for_type all ", argv(0), " ", argv(1));
938  }
939  }
940  fclose(fd);
941  }
942  }
943 
945 
946  Nagger_Init();
947 
948  // set up information replies for clients and server to use
949  maplist_reply = strzone(getmaplist());
950  lsmaps_reply = strzone(getlsmaps());
951  monsterlist_reply = strzone(getmonsterlist());
952  bool records_available = false;
953  for(int i = 0; i < 10; ++i)
954  {
955  string s = getrecords(i);
956  if (s != "")
957  {
958  records_reply[i] = strzone(s);
959  records_available = true;
960  }
961  }
962  if (!records_available)
963  records_reply[0] = "No records available for the current game mode.\n";
964  ladder_reply = strzone(getladder());
965  rankings_reply = strzone(getrankings());
966 
967  // begin other init
971 
972  CheatInit();
973 
974  if (!wantrestart) localcmd("\n_sv_hook_gamestart ", GetGametype(), "\n");
975 
976  // fill sv_curl_serverpackages from .serverpackage files
978  {
979  string s = "csprogs-" WATERMARK ".dat";
980  // remove automatically managed files from the list to prevent duplicates
981  for (int i = 0, n = tokenize_console(cvar_string("sv_curl_serverpackages")); i < n; ++i)
982  {
983  string pkg = argv(i);
984  if (startsWith(pkg, "csprogs-")) continue;
985  if (endsWith(pkg, "-serverpackage.txt")) continue;
986  if (endsWith(pkg, ".serverpackage")) continue; // OLD legacy
987  s = cons(s, pkg);
988  }
989  // add automatically managed files to the list
990  #define X(match) MACRO_BEGIN \
991  int fd = search_begin(match, true, false); \
992  if (fd >= 0) \
993  { \
994  for (int i = 0, j = search_getsize(fd); i < j; ++i) \
995  { \
996  s = cons(s, search_getfilename(fd, i)); \
997  } \
998  search_end(fd); \
999  } \
1000  MACRO_END
1001  X("*-serverpackage.txt");
1002  X("*.serverpackage");
1003  #undef X
1004  cvar_set("sv_curl_serverpackages", s);
1005  }
1006 
1007  // MOD AUTHORS: change this, and possibly remove a few of the blocks below to ignore certain changes
1008  modname = "Xonotic";
1009  // physics/balance/config changes that count as mod
1010  if(cvar_string("g_mod_physics") != cvar_defstring("g_mod_physics"))
1011  modname = cvar_string("g_mod_physics");
1012  if(cvar_string("g_mod_balance") != cvar_defstring("g_mod_balance") && cvar_string("g_mod_balance") != "Testing")
1013  modname = cvar_string("g_mod_balance");
1014  if(cvar_string("g_mod_config") != cvar_defstring("g_mod_config"))
1015  modname = cvar_string("g_mod_config");
1016  // extra mutators that deserve to count as mod
1017  MUTATOR_CALLHOOK(SetModname, modname);
1018  modname = M_ARGV(0, string);
1019 
1020  // save it for later
1021  modname = strzone(modname);
1022 
1023  WinningConditionHelper(this); // set worldstatus
1024 
1025  world_initialized = 1;
1026  __spawnfunc_spawn_all();
1027 }
1028 
1030 {
1031  //makestatic (this); // Who the f___ did that?
1032  delete(this);
1033 }
1034 
1035 bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance)
1036 {
1037  float m = e.dphitcontentsmask;
1038  e.dphitcontentsmask = goodcontents | badcontents;
1039 
1040  vector org = boundmin;
1041  vector delta = boundmax - boundmin;
1042 
1043  vector start, end;
1044  start = end = org;
1045  int j; // used after the loop
1046  for(j = 0; j < attempts; ++j)
1047  {
1048  start.x = org.x + random() * delta.x;
1049  start.y = org.y + random() * delta.y;
1050  start.z = org.z + random() * delta.z;
1051 
1052  // rule 1: start inside world bounds, and outside
1053  // solid, and don't start from somewhere where you can
1054  // fall down to evil
1055  tracebox(start, e.mins, e.maxs, start - '0 0 1' * delta.z, MOVE_NORMAL, e);
1056  if (trace_fraction >= 1)
1057  continue;
1058  if (trace_startsolid)
1059  continue;
1060  if (trace_dphitcontents & badcontents)
1061  continue;
1062  if (trace_dphitq3surfaceflags & badsurfaceflags)
1063  continue;
1064 
1065  // rule 2: if we are too high, lower the point
1066  if (trace_fraction * delta.z > maxaboveground)
1067  start = trace_endpos + '0 0 1' * maxaboveground;
1068  vector enddown = trace_endpos;
1069 
1070  // rule 3: make sure we aren't outside the map. This only works
1071  // for somewhat well formed maps. A good rule of thumb is that
1072  // the map should have a convex outside hull.
1073  // these can be traceLINES as we already verified the starting box
1074  vector mstart = start + 0.5 * (e.mins + e.maxs);
1075  traceline(mstart, mstart + '1 0 0' * delta.x, MOVE_NORMAL, e);
1076  if (trace_fraction >= 1 || trace_dphittexturename == "common/caulk")
1077  continue;
1078  traceline(mstart, mstart - '1 0 0' * delta.x, MOVE_NORMAL, e);
1079  if (trace_fraction >= 1 || trace_dphittexturename == "common/caulk")
1080  continue;
1081  traceline(mstart, mstart + '0 1 0' * delta.y, MOVE_NORMAL, e);
1082  if (trace_fraction >= 1 || trace_dphittexturename == "common/caulk")
1083  continue;
1084  traceline(mstart, mstart - '0 1 0' * delta.y, MOVE_NORMAL, e);
1085  if (trace_fraction >= 1 || trace_dphittexturename == "common/caulk")
1086  continue;
1087  traceline(mstart, mstart + '0 0 1' * delta.z, MOVE_NORMAL, e);
1088  if (trace_fraction >= 1 || trace_dphittexturename == "common/caulk")
1089  continue;
1090 
1091  // rule 4: we must "see" some spawnpoint or item
1092  entity sp = NULL;
1093  IL_EACH(g_spawnpoints, checkpvs(mstart, it),
1094  {
1095  if((traceline(mstart, it.origin, MOVE_NORMAL, e), trace_fraction) >= 1)
1096  {
1097  sp = it;
1098  break;
1099  }
1100  });
1101  if(!sp)
1102  {
1103  int items_checked = 0;
1104  IL_EACH(g_items, checkpvs(mstart, it),
1105  {
1106  if((traceline(mstart, it.origin + (it.mins + it.maxs) * 0.5, MOVE_NORMAL, e), trace_fraction) >= 1)
1107  {
1108  sp = it;
1109  break;
1110  }
1111 
1112  ++items_checked;
1113  if(items_checked >= attempts)
1114  break; // sanity
1115  });
1116 
1117  if(!sp)
1118  continue;
1119  }
1120 
1121  // find a random vector to "look at"
1122  end.x = org.x + random() * delta.x;
1123  end.y = org.y + random() * delta.y;
1124  end.z = org.z + random() * delta.z;
1125  end = start + normalize(end - start) * vlen(delta);
1126 
1127  // rule 4: start TO end must not be too short
1128  tracebox(start, e.mins, e.maxs, end, MOVE_NORMAL, e);
1129  if(trace_startsolid)
1130  continue;
1131  if(trace_fraction < minviewdistance / vlen(delta))
1132  continue;
1133 
1134  // rule 5: don't want to look at sky
1136  continue;
1137 
1138  // rule 6: we must not end up in trigger_hurt
1139  if(tracebox_hits_trigger_hurt(start, e.mins, e.maxs, enddown))
1140  continue;
1141 
1142  break;
1143  }
1144 
1145  e.dphitcontentsmask = m;
1146 
1147  if(j < attempts)
1148  {
1149  setorigin(e, start);
1150  e.angles = vectoangles(end - start);
1151  LOG_DEBUG("Needed ", ftos(j + 1), " attempts");
1152  return true;
1153  }
1154  return false;
1155 }
1156 
1157 float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
1158 {
1159  return MoveToRandomLocationWithinBounds(e, world.mins, world.maxs, goodcontents, badcontents, badsurfaceflags, attempts, maxaboveground, minviewdistance);
1160 }
1161 
1162 /*
1163 ===============================================================================
1164 
1165 RULES
1166 
1167 ===============================================================================
1168 */
1169 
1170 void DumpStats(float final)
1171 {
1172  float file;
1173  string s;
1174  float to_console;
1175  float to_eventlog;
1176  float to_file;
1177  float i;
1178 
1179  to_console = autocvar_sv_logscores_console;
1180  to_eventlog = autocvar_sv_eventlog;
1181  to_file = autocvar_sv_logscores_file;
1182 
1183  if(!final)
1184  {
1185  to_console = true; // always print printstats replies
1186  to_eventlog = false; // but never print them to the event log
1187  }
1188 
1189  if(to_eventlog)
1191  to_console = false; // otherwise we get the output twice
1192 
1193  if(final)
1194  s = ":scores:";
1195  else
1196  s = ":status:";
1197  s = strcat(s, GetGametype(), "_", GetMapname(), ":", ftos(rint(time)));
1198 
1199  if(to_console)
1200  LOG_HELP(s);
1201  if(to_eventlog)
1202  GameLogEcho(s);
1203 
1204  file = -1;
1205  if(to_file)
1206  {
1208  if(file == -1)
1209  to_file = false;
1210  else
1211  fputs(file, strcat(s, "\n"));
1212  }
1213 
1214  s = strcat(":labels:player:", GetPlayerScoreString(NULL, 0));
1215  if(to_console)
1216  LOG_HELP(s);
1217  if(to_eventlog)
1218  GameLogEcho(s);
1219  if(to_file)
1220  fputs(file, strcat(s, "\n"));
1221 
1223  s = strcat(":player:see-labels:", GetPlayerScoreString(it, 0), ":");
1224  s = strcat(s, ftos(rint(time - CS(it).jointime)), ":");
1225  if(IS_PLAYER(it) || INGAME_JOINED(it))
1226  s = strcat(s, ftos(it.team), ":");
1227  else
1228  s = strcat(s, "spectator:");
1229 
1230  if(to_console)
1231  LOG_HELP(s, playername(it.netname, it.team, false));
1232  if(to_eventlog)
1233  GameLogEcho(strcat(s, ftos(it.playerid), ":", playername(it.netname, it.team, false)));
1234  if(to_file)
1235  fputs(file, strcat(s, playername(it.netname, it.team, false), "\n"));
1236  });
1237 
1238  if(teamplay)
1239  {
1240  s = strcat(":labels:teamscores:", GetTeamScoreString(0, 0));
1241  if(to_console)
1242  LOG_HELP(s);
1243  if(to_eventlog)
1244  GameLogEcho(s);
1245  if(to_file)
1246  fputs(file, strcat(s, "\n"));
1247 
1248  for(i = 1; i < 16; ++i)
1249  {
1250  s = strcat(":teamscores:see-labels:", GetTeamScoreString(i, 0));
1251  s = strcat(s, ":", ftos(i));
1252  if(to_console)
1253  LOG_HELP(s);
1254  if(to_eventlog)
1255  GameLogEcho(s);
1256  if(to_file)
1257  fputs(file, strcat(s, "\n"));
1258  }
1259  }
1260 
1261  if(to_console)
1262  LOG_HELP(":end");
1263  if(to_eventlog)
1264  GameLogEcho(":end");
1265  if(to_file)
1266  {
1267  fputs(file, ":end\n");
1268  fclose(file);
1269  }
1270 }
1271 
1272 /*
1273 go to the next level for deathmatch
1274 only called if a time or frag limit has expired
1275 */
1277 {
1278  cvar_set("_endmatch", "0");
1279  game_stopped = true;
1280  intermission_running = true; // game over
1281 
1282  // enforce a wait time before allowing changelevel
1283  if(player_count > 0)
1285  else
1286  intermission_exittime = -1;
1287 
1288  /*
1289  WriteByte (MSG_ALL, SVC_CDTRACK);
1290  WriteByte (MSG_ALL, 3);
1291  WriteByte (MSG_ALL, 3);
1292  // done in FixIntermission
1293  */
1294 
1295  //pos = FindIntermission ();
1296 
1297  VoteReset();
1298 
1299  DumpStats(true);
1300 
1301  // send statistics
1302  PlayerStats_GameReport(true);
1304 
1305  Kill_Notification(NOTIF_ALL, NULL, MSG_CENTER, CPID_Null); // kill all centerprints now
1306 
1308  GameLogEcho(":gameover");
1309 
1310  GameLogClose();
1311 
1312  int winner_team = 0;
1313  FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
1315  if(it.winning)
1316  {
1317  if (teamplay && !winner_team)
1318  {
1319  winner_team = it.team;
1320  bprint(Team_ColorCode(winner_team), Team_ColorName_Upper(winner_team), "^7 team wins the match\n");
1321  }
1322  bprint(playername(it.netname, it.team, false), " ^7wins\n");
1323  }
1324  });
1325 
1326  target_music_kill();
1327 
1330 
1331  MUTATOR_CALLHOOK(MatchEnd);
1332 
1333  localcmd("\nsv_hook_gameend\n");
1334 }
1335 
1336 
1338 {
1339  // Check first whether normal overtimes could be added before initiating suddendeath mode
1340  // - for this timelimit_overtime needs to be >0 of course
1341  // - also check the winning condition calculated in the previous frame and only add normal overtime
1342  // again, if at the point at which timelimit would be extended again, still no winner was found
1346  {
1347  return 1; // need to call InitiateOvertime later
1348  }
1349  else
1350  {
1352  {
1354  {
1355  checkrules_suddendeathend = time; // no suddendeath in campaign
1356  }
1357  else
1358  {
1360  overtimes = -1;
1361  }
1362  if(g_race && !g_race_qualifying)
1364  }
1365  return 0;
1366  }
1367 }
1368 
1369 void InitiateOvertime() // ONLY call this if InitiateSuddenDeath returned true
1370 {
1372  overtimes = checkrules_overtimesadded;
1373  //add one more overtime by simply extending the timelimit
1374  cvar_set("timelimit", ftos(autocvar_timelimit + autocvar_timelimit_overtime));
1375  Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_TIME, autocvar_timelimit_overtime * 60);
1376 }
1377 
1378 float GetWinningCode(float fraglimitreached, float equality)
1379 {
1380  if(autocvar_g_campaign == 1)
1381  {
1382  if(fraglimitreached)
1383  return WINNING_YES;
1384  else
1385  return WINNING_NO;
1386  }
1387  else
1388  {
1389  if(equality)
1390  {
1391  if(fraglimitreached)
1393  else
1394  return WINNING_NEVER;
1395  }
1396  else
1397  {
1398  if(fraglimitreached)
1399  return WINNING_YES;
1400  else
1401  return WINNING_NO;
1402  }
1403  }
1404 }
1405 
1406 // set the .winning flag for exactly those players with a given field value
1407 void SetWinners(.float field, float value)
1408 {
1409  FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = (it.(field) == value); });
1410 }
1411 
1412 // set the .winning flag for those players with a given field value
1413 void AddWinners(.float field, float value)
1414 {
1415  FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), {
1416  if(it.(field) == value)
1417  it.winning = 1;
1418  });
1419 }
1420 
1421 // clear the .winning flags
1423 {
1424  FOREACH_CLIENT(IS_PLAYER(it) || INGAME(it), { it.winning = 0; });
1425 }
1426 
1428 float WinningCondition_Scores(float limit, float leadlimit)
1429 {
1430  // TODO make everything use THIS winning condition (except LMS)
1432 
1433  if(teamplay)
1434  {
1435  for (int i = 1; i < 5; ++i)
1436  {
1439  }
1440  }
1441 
1442  ClearWinners();
1444  WinningConditionHelper_winner.winning = 1;
1447 
1449  {
1452  limit = -limit;
1453  }
1454 
1456  leadlimit = 0; // not supported in this mode
1457 
1458  if(MUTATOR_CALLHOOK(Scores_CountFragsRemaining))
1459  {
1460  float fragsleft;
1462  {
1463  fragsleft = 1;
1464  }
1465  else
1466  {
1467  fragsleft = FLOAT_MAX;
1468  float leadingfragsleft = FLOAT_MAX;
1469  if (limit)
1470  fragsleft = limit - WinningConditionHelper_topscore;
1471  if (leadlimit)
1473 
1474  if (limit && leadlimit && autocvar_leadlimit_and_fraglimit)
1475  fragsleft = max(fragsleft, leadingfragsleft);
1476  else
1477  fragsleft = min(fragsleft, leadingfragsleft);
1478  }
1479 
1480  if (fragsleft_last != fragsleft) // do not announce same remaining frags multiple times
1481  {
1482  if (fragsleft == 1)
1483  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_1);
1484  else if (fragsleft == 2)
1485  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_2);
1486  else if (fragsleft == 3)
1487  Send_Notification(NOTIF_ALL, NULL, MSG_ANNCE, ANNCE_REMAINING_FRAG_3);
1488 
1489  fragsleft_last = fragsleft;
1490  }
1491  }
1492 
1493  bool fraglimit_reached = (limit && WinningConditionHelper_topscore >= limit);
1494  bool leadlimit_reached = (leadlimit && WinningConditionHelper_topscore - WinningConditionHelper_secondscore >= leadlimit);
1495 
1496  bool limit_reached;
1497  // only respect leadlimit_and_fraglimit when both limits are set or the game will never end
1498  if (limit && leadlimit && autocvar_leadlimit_and_fraglimit)
1499  limit_reached = (fraglimit_reached && leadlimit_reached);
1500  else
1501  limit_reached = (fraglimit_reached || leadlimit_reached);
1502 
1503  return GetWinningCode(
1504  WinningConditionHelper_topscore && limit_reached,
1506  );
1507 }
1508 
1510 {
1511  if(have_team_spawns <= 0)
1512  return WINNING_NO;
1513 
1515  return WINNING_NO;
1516 
1518  return WINNING_NO;
1519 
1520  for (int i = 1; i < 5; ++i)
1521  {
1523  }
1524 
1525  FOREACH_CLIENT(IS_PLAYER(it) && !IS_DEAD(it),
1526  {
1527  if (Team_IsValidTeam(it.team))
1528  {
1529  Team_SetTeamScore(Team_GetTeam(it.team), 1);
1530  }
1531  });
1532 
1533  IL_EACH(g_spawnpoints, true,
1534  {
1535  if (Team_IsValidTeam(it.team))
1536  {
1537  Team_SetTeamScore(Team_GetTeam(it.team), 1);
1538  }
1539  });
1540 
1541  ClearWinners();
1542  float team1_score = Team_GetTeamScore(Team_GetTeamFromIndex(1));
1543  float team2_score = Team_GetTeamScore(Team_GetTeamFromIndex(2));
1544  float team3_score = Team_GetTeamScore(Team_GetTeamFromIndex(3));
1545  float team4_score = Team_GetTeamScore(Team_GetTeamFromIndex(4));
1546  if(team1_score + team2_score + team3_score + team4_score == 0)
1547  {
1548  checkrules_equality = true;
1549  return WINNING_YES;
1550  }
1551  else if(team1_score + team2_score + team3_score + team4_score == 1)
1552  {
1553  float t, i;
1554  if(team1_score)
1555  t = 1;
1556  else if(team2_score)
1557  t = 2;
1558  else if(team3_score)
1559  t = 3;
1560  else // if(team4_score)
1561  t = 4;
1563  for(i = 0; i < MAX_TEAMSCORE; ++i)
1564  {
1565  for (int j = 1; j <= NUM_TEAMS; ++j)
1566  {
1567  if (t == j)
1568  {
1569  continue;
1570  }
1571  if (!TeamBalance_IsTeamAllowed(balance, j))
1572  {
1573  continue;
1574  }
1575  TeamScore_AddToTeam(Team_IndexToTeam(j), i, -1000);
1576  }
1577  }
1578 
1579  AddWinners(team, t);
1580  return WINNING_YES;
1581  }
1582  else
1583  return WINNING_NO;
1584 }
1585 
1586 /*
1587 ============
1588 CheckRules_World
1589 
1590 Exit deathmatch games upon conditions
1591 ============
1592 */
1594 {
1595  VoteThink();
1596  MapVote_Think();
1597 
1598  SetDefaultAlpha();
1599 
1600  if (intermission_running) // someone else quit the game already
1601  {
1602  if(player_count == 0) // Nobody there? Then let's go to the next map
1603  MapVote_Start();
1604  // this will actually check the player count in the next frame
1605  // again, but this shouldn't hurt
1606  return;
1607  }
1608 
1609  float timelimit = autocvar_timelimit * 60;
1610  float fraglimit = autocvar_fraglimit;
1611  float leadlimit = autocvar_leadlimit;
1612  if (leadlimit < 0) leadlimit = 0;
1613 
1614  if(warmup_stage || time <= game_starttime) // NOTE: this is <= to prevent problems in the very tic where the game starts
1615  {
1616  if(timelimit > 0)
1617  timelimit = 0; // timelimit is not made for warmup
1618  if(fraglimit > 0)
1619  fraglimit = 0; // no fraglimit for now
1620  leadlimit = 0; // no leadlimit for now
1621  }
1622 
1623  if (autocvar__endmatch || timelimit < 0)
1624  {
1625  // endmatch
1626  NextLevel();
1627  return;
1628  }
1629 
1630  if(timelimit > 0)
1631  timelimit += game_starttime;
1632 
1633  float wantovertime;
1634  wantovertime = 0;
1635 
1637  {
1639  {
1641  if(g_race && !g_race_qualifying)
1642  Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_RACE_FINISHLAP);
1643  else
1644  Send_Notification(NOTIF_ALL, NULL, MSG_CENTER, CENTER_OVERTIME_FRAG);
1645  }
1646  }
1647  else
1648  {
1649  if (timelimit && time >= timelimit)
1650  {
1651  if(g_race && (g_race_qualifying == 2) && timelimit > 0)
1652  {
1653  float totalplayers;
1654  float playerswithlaps;
1655  float readyplayers;
1656  totalplayers = playerswithlaps = readyplayers = 0;
1657  FOREACH_CLIENT(IS_PLAYER(it), {
1658  ++totalplayers;
1659  if(GameRules_scoring_add(it, RACE_FASTEST, 0))
1660  ++playerswithlaps;
1661  if(it.ready)
1662  ++readyplayers;
1663  });
1664 
1665  // at least 2 of the players have completed a lap: start the RACE
1666  // otherwise, the players should end the qualifying on their own
1667  if(readyplayers || playerswithlaps >= 2)
1668  {
1670  ReadyRestart(true); // go to race
1671  return;
1672  }
1673  else
1674  wantovertime |= InitiateSuddenDeath();
1675  }
1676  else
1677  wantovertime |= InitiateSuddenDeath();
1678  }
1679  }
1680 
1682  {
1683  NextLevel();
1684  return;
1685  }
1686 
1687  int checkrules_status = WinningCondition_RanOutOfSpawns();
1688  if(checkrules_status == WINNING_YES)
1689  bprint("Hey! Someone ran out of spawns!\n");
1690  else if(MUTATOR_CALLHOOK(CheckRules_World, checkrules_status, timelimit, fraglimit))
1691  checkrules_status = M_ARGV(0, float);
1692  else
1693  checkrules_status = WinningCondition_Scores(fraglimit, leadlimit);
1694 
1695  if(checkrules_status == WINNING_STARTSUDDENDEATHOVERTIME)
1696  {
1697  checkrules_status = WINNING_NEVER;
1699  wantovertime |= InitiateSuddenDeath();
1700  }
1701 
1702  if(checkrules_status == WINNING_NEVER)
1703  // equality cases! Nobody wins if the overtime ends in a draw.
1704  ClearWinners();
1705 
1706  if(wantovertime)
1707  {
1708  if(checkrules_status == WINNING_NEVER)
1709  InitiateOvertime();
1710  else
1711  checkrules_status = WINNING_YES;
1712  }
1713 
1715  if(checkrules_status != WINNING_NEVER || time >= checkrules_suddendeathend)
1716  checkrules_status = WINNING_YES;
1717 
1718  if(checkrules_status == WINNING_YES)
1719  {
1720  //print("WINNING\n");
1721  NextLevel();
1722  }
1723 }
1724 
1725 float want_weapon(entity weaponinfo, float allguns)
1726 {
1727  int d = 0;
1728  bool allow_mutatorblocked = false;
1729 
1730  if(!weaponinfo.m_id)
1731  return 0;
1732 
1733  bool mutator_returnvalue = MUTATOR_CALLHOOK(WantWeapon, weaponinfo, d, allguns, allow_mutatorblocked);
1734  d = M_ARGV(1, float);
1735  allguns = M_ARGV(2, bool);
1736  allow_mutatorblocked = M_ARGV(3, bool);
1737 
1738  if(allguns)
1739  d = boolean((weaponinfo.spawnflags & WEP_FLAG_NORMAL) && !(weaponinfo.spawnflags & (WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK)));
1740  else if(!mutator_returnvalue)
1741  d = !(!weaponinfo.weaponstart);
1742 
1743  if(!allow_mutatorblocked && (weaponinfo.spawnflags & WEP_FLAG_MUTATORBLOCKED)) // never default mutator blocked guns
1744  d = 0;
1745 
1746  float t = weaponinfo.weaponstartoverride;
1747 
1748  //LOG_INFOF("want_weapon: %s - d: %d t: %d\n", weaponinfo.netname, d, t);
1749 
1750  // bit order in t:
1751  // 1: want or not
1752  // 2: is default?
1753  // 4: is set by default?
1754  if(t < 0)
1755  t = 4 | (3 * d);
1756  else
1757  t |= (2 * d);
1758 
1759  return t;
1760 }
1761 
1764 {
1765  WepSet ret = '0 0 0';
1766  FOREACH(Weapons, it != WEP_Null, {
1767  int w = want_weapon(it, false);
1768  if (w & 1)
1769  ret |= it.m_wepset;
1770  });
1771  return ret;
1772 }
1773 
1775 {
1776  WepSet ret = '0 0 0';
1777  FOREACH(Weapons, it != WEP_Null, {
1778  if (!(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_SPECIALATTACK)))
1779  ret |= it.m_wepset;
1780  });
1781  return ret;
1782 }
1783 
1785 {
1786  WepSet ret = '0 0 0';
1787  FOREACH(Weapons, it != WEP_Null,
1788  {
1789  ret |= it.m_wepset;
1790  });
1791  return ret;
1792 }
1793 
1795 {
1796  WepSet ret = '0 0 0';
1797  FOREACH(Weapons, it != WEP_Null, {
1798  if ((it.spawnflags & WEP_FLAG_NORMAL) && !(it.spawnflags & (WEP_FLAG_MUTATORBLOCKED | WEP_FLAG_HIDDEN | WEP_FLAG_SPECIALATTACK)))
1799  ret |= it.m_wepset;
1800  });
1801  return ret;
1802 }
1803 
1805 {
1806  if (weaponsInMapAll)
1807  {
1809  }
1810  else
1811  {
1812  // if no weapons are available on the map, just fall back to all weapons arena
1814  }
1815 }
1816 
1818 {
1819  if (weaponsInMapAll)
1820  {
1822  }
1823  else
1824  {
1825  // if no weapons are available on the map, just fall back to devall weapons arena
1827  }
1828 }
1829 
1831 {
1832  if (weaponsInMapAll)
1833  {
1835  }
1836  else
1837  {
1838  // if no weapons are available on the map, just fall back to most weapons arena
1840  }
1841 }
1842 
1844 {
1845  // initialize starting values for players
1846  start_weapons = '0 0 0';
1847  start_weapons_default = '0 0 0';
1848  start_weapons_defaultmask = '0 0 0';
1849  start_items = 0;
1850  start_ammo_shells = 0;
1851  start_ammo_nails = 0;
1852  start_ammo_rockets = 0;
1853  start_ammo_cells = 0;
1854  start_ammo_plasma = 0;
1855  if (random_start_ammo == NULL)
1856  {
1858  }
1859  start_health = cvar("g_balance_health_start");
1860  start_armorvalue = cvar("g_balance_armor_start");
1861 
1862  g_weaponarena = 0;
1863  g_weaponarena_weapons = '0 0 0';
1864 
1865  string s = cvar_string("g_weaponarena");
1866 
1867  MUTATOR_CALLHOOK(SetWeaponArena, s);
1868  s = M_ARGV(0, string);
1869 
1870  if (s == "0" || s == "")
1871  {
1872  // no arena
1873  }
1874  else if (s == "off")
1875  {
1876  // forcibly turn off weaponarena
1877  }
1878  else if (s == "all" || s == "1")
1879  {
1880  g_weaponarena = 1;
1881  g_weaponarena_list = "All Weapons";
1883  }
1884  else if (s == "devall")
1885  {
1886  g_weaponarena = 1;
1887  g_weaponarena_list = "Dev All Weapons";
1889  }
1890  else if (s == "most")
1891  {
1892  g_weaponarena = 1;
1893  g_weaponarena_list = "Most Weapons";
1895  }
1896  else if (s == "all_available")
1897  {
1898  g_weaponarena = 1;
1899  g_weaponarena_list = "All Available Weapons";
1900 
1901  // this needs to run after weaponsInMapAll is initialized
1903  }
1904  else if (s == "devall_available")
1905  {
1906  g_weaponarena = 1;
1907  g_weaponarena_list = "Dev All Available Weapons";
1908 
1909  // this needs to run after weaponsInMapAll is initialized
1911  }
1912  else if (s == "most_available")
1913  {
1914  g_weaponarena = 1;
1915  g_weaponarena_list = "Most Available Weapons";
1916 
1917  // this needs to run after weaponsInMapAll is initialized
1919  }
1920  else if (s == "none")
1921  {
1922  g_weaponarena = 1;
1923  g_weaponarena_list = "No Weapons";
1924  }
1925  else
1926  {
1927  g_weaponarena = 1;
1928  float t = tokenize_console(s);
1929  g_weaponarena_list = "";
1930  for (int j = 0; j < t; ++j)
1931  {
1932  s = argv(j);
1933  Weapon wep = Weapon_from_name(s);
1934  if(wep != WEP_Null)
1935  {
1936  g_weaponarena_weapons |= (wep.m_wepset);
1938  }
1939  }
1941  }
1942 
1943  if (g_weaponarena)
1944  {
1945  g_weapon_stay = 0; // incompatible
1947  start_items |= IT_UNLIMITED_AMMO | IT_UNLIMITED_SUPERWEAPONS;
1948  }
1949  else
1950  {
1951  FOREACH(Weapons, it != WEP_Null, {
1952  int w = want_weapon(it, false);
1953  WepSet s = it.m_wepset;
1954  if(w & 1)
1955  start_weapons |= s;
1956  if(w & 2)
1957  start_weapons_default |= s;
1958  if(w & 4)
1960  });
1961  }
1962 
1963  if(cvar("g_balance_superweapons_time") < 0)
1964  start_items |= IT_UNLIMITED_SUPERWEAPONS;
1965 
1966  if(!cvar("g_use_ammunition"))
1967  start_items |= IT_UNLIMITED_AMMO;
1968 
1969  if(start_items & IT_UNLIMITED_AMMO)
1970  {
1971  start_ammo_shells = 999;
1972  start_ammo_nails = 999;
1973  start_ammo_rockets = 999;
1974  start_ammo_cells = 999;
1975  start_ammo_plasma = 999;
1976  start_ammo_fuel = 999;
1977  }
1978  else
1979  {
1980  start_ammo_shells = cvar("g_start_ammo_shells");
1981  start_ammo_nails = cvar("g_start_ammo_nails");
1982  start_ammo_rockets = cvar("g_start_ammo_rockets");
1983  start_ammo_cells = cvar("g_start_ammo_cells");
1984  start_ammo_plasma = cvar("g_start_ammo_plasma");
1985  start_ammo_fuel = cvar("g_start_ammo_fuel");
1986  random_start_weapons_count = cvar("g_random_start_weapons_count");
1987  SetResource(random_start_ammo, RES_SHELLS, cvar("g_random_start_shells"));
1988  SetResource(random_start_ammo, RES_BULLETS, cvar("g_random_start_bullets"));
1989  SetResource(random_start_ammo, RES_ROCKETS, cvar("g_random_start_rockets"));
1990  SetResource(random_start_ammo, RES_CELLS, cvar("g_random_start_cells"));
1991  SetResource(random_start_ammo, RES_PLASMA, cvar("g_random_start_plasma"));
1992  }
1993 
2005 
2006  if (!g_weaponarena)
2007  {
2008  warmup_start_ammo_shells = cvar("g_warmup_start_ammo_shells");
2009  warmup_start_ammo_nails = cvar("g_warmup_start_ammo_nails");
2010  warmup_start_ammo_rockets = cvar("g_warmup_start_ammo_rockets");
2011  warmup_start_ammo_cells = cvar("g_warmup_start_ammo_cells");
2012  warmup_start_ammo_plasma = cvar("g_warmup_start_ammo_plasma");
2013  warmup_start_ammo_fuel = cvar("g_warmup_start_ammo_fuel");
2014  warmup_start_health = cvar("g_warmup_start_health");
2015  warmup_start_armorvalue = cvar("g_warmup_start_armor");
2016  warmup_start_weapons = '0 0 0';
2017  warmup_start_weapons_default = '0 0 0';
2019  FOREACH(Weapons, it != WEP_Null, {
2021  WepSet s = it.m_wepset;
2022  if(w & 1)
2023  warmup_start_weapons |= s;
2024  if(w & 2)
2026  if(w & 4)
2028  });
2029  }
2030 
2031  if (autocvar_g_jetpack)
2032  start_items |= ITEM_Jetpack.m_itemid;
2033 
2034  MUTATOR_CALLHOOK(SetStartItems);
2035 
2036  if (start_items & ITEM_Jetpack.m_itemid)
2037  {
2038  start_items |= ITEM_JetpackRegen.m_itemid;
2039  start_ammo_fuel = max(start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
2040  warmup_start_ammo_fuel = max(warmup_start_ammo_fuel, cvar("g_balance_fuel_rotstable"));
2041  }
2042 
2049  SetResource(random_start_ammo, RES_SHELLS, max(0, GetResource(random_start_ammo, RES_SHELLS)));
2050  SetResource(random_start_ammo, RES_BULLETS, max(0, GetResource(random_start_ammo, RES_BULLETS)));
2051  SetResource(random_start_ammo, RES_ROCKETS, max(0, GetResource(random_start_ammo, RES_ROCKETS)));
2052  SetResource(random_start_ammo, RES_CELLS, max(0, GetResource(random_start_ammo, RES_CELLS)));
2053  SetResource(random_start_ammo, RES_PLASMA, max(0, GetResource(random_start_ammo, RES_PLASMA)));
2054 
2061 }
2062 
2064 {
2065  if(cvar("sv_allow_fullbright"))
2067 
2068  sv_ready_restart_after_countdown = cvar("sv_ready_restart_after_countdown");
2069 
2070  warmup_stage = cvar("g_warmup");
2071  warmup_limit = cvar("g_warmup_limit");
2072 
2073  if(cvar("g_campaign"))
2074  warmup_stage = 0; // no warmup during campaign
2075 
2076  g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon");
2077  g_pickup_respawntime_superweapon = cvar("g_pickup_respawntime_superweapon");
2078  g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo");
2079  g_pickup_respawntime_short = cvar("g_pickup_respawntime_short");
2080  g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium");
2081  g_pickup_respawntime_long = cvar("g_pickup_respawntime_long");
2082  g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup");
2083  g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon");
2084  g_pickup_respawntimejitter_superweapon = cvar("g_pickup_respawntimejitter_superweapon");
2085  g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo");
2086  g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short");
2087  g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium");
2088  g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long");
2089  g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup");
2090 
2091  g_pickup_shells = cvar("g_pickup_shells");
2092  g_pickup_shells_max = cvar("g_pickup_shells_max");
2093  g_pickup_nails = cvar("g_pickup_nails");
2094  g_pickup_nails_max = cvar("g_pickup_nails_max");
2095  g_pickup_rockets = cvar("g_pickup_rockets");
2096  g_pickup_rockets_max = cvar("g_pickup_rockets_max");
2097  g_pickup_cells = cvar("g_pickup_cells");
2098  g_pickup_cells_max = cvar("g_pickup_cells_max");
2099  g_pickup_plasma = cvar("g_pickup_plasma");
2100  g_pickup_plasma_max = cvar("g_pickup_plasma_max");
2101  g_pickup_fuel = cvar("g_pickup_fuel");
2102  g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack");
2103  g_pickup_fuel_max = cvar("g_pickup_fuel_max");
2104  g_pickup_armorsmall = cvar("g_pickup_armorsmall");
2105  g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max");
2106  g_pickup_armorsmall_anyway = cvar("g_pickup_armorsmall_anyway");
2107  g_pickup_armormedium = cvar("g_pickup_armormedium");
2108  g_pickup_armormedium_max = cvar("g_pickup_armormedium_max");
2109  g_pickup_armormedium_anyway = cvar("g_pickup_armormedium_anyway");
2110  g_pickup_armorbig = cvar("g_pickup_armorbig");
2111  g_pickup_armorbig_max = cvar("g_pickup_armorbig_max");
2112  g_pickup_armorbig_anyway = cvar("g_pickup_armorbig_anyway");
2113  g_pickup_armormega = cvar("g_pickup_armormega");
2114  g_pickup_armormega_max = cvar("g_pickup_armormega_max");
2115  g_pickup_armormega_anyway = cvar("g_pickup_armormega_anyway");
2116  g_pickup_healthsmall = cvar("g_pickup_healthsmall");
2117  g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max");
2118  g_pickup_healthsmall_anyway = cvar("g_pickup_healthsmall_anyway");
2119  g_pickup_healthmedium = cvar("g_pickup_healthmedium");
2120  g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max");
2121  g_pickup_healthmedium_anyway = cvar("g_pickup_healthmedium_anyway");
2122  g_pickup_healthbig = cvar("g_pickup_healthbig");
2123  g_pickup_healthbig_max = cvar("g_pickup_healthbig_max");
2124  g_pickup_healthbig_anyway = cvar("g_pickup_healthbig_anyway");
2125  g_pickup_healthmega = cvar("g_pickup_healthmega");
2126  g_pickup_healthmega_max = cvar("g_pickup_healthmega_max");
2127  g_pickup_healthmega_anyway = cvar("g_pickup_healthmega_anyway");
2128 
2129  g_pickup_ammo_anyway = cvar("g_pickup_ammo_anyway");
2130  g_pickup_weapons_anyway = cvar("g_pickup_weapons_anyway");
2131 
2132  g_weapon_stay = cvar(strcat("g_", GetGametype(), "_weapon_stay"));
2133  if(!g_weapon_stay)
2134  g_weapon_stay = cvar("g_weapon_stay");
2135 
2136  MUTATOR_CALLHOOK(ReadLevelCvars);
2137 
2138  if (!warmup_stage)
2139  game_starttime = time + cvar("g_start_delay");
2140 
2141  FOREACH(Weapons, it != WEP_Null, { it.wr_init(it); });
2142 
2144 }
2145 
2146 void InitializeEntity(entity e, void(entity this) func, int order)
2147 {
2148  entity prev, cur;
2149 
2150  if (!e || e.initialize_entity)
2151  {
2152  // make a proxy initializer entity
2153  entity e_old = e;
2154  e = new(initialize_entity);
2155  e.enemy = e_old;
2156  }
2157 
2158  e.initialize_entity = func;
2159  e.initialize_entity_order = order;
2160 
2162  prev = NULL;
2163  for (;;)
2164  {
2165  if (!cur || cur.initialize_entity_order > order)
2166  {
2167  // insert between prev and cur
2168  if (prev)
2169  prev.initialize_entity_next = e;
2170  else
2172  e.initialize_entity_next = cur;
2173  return;
2174  }
2175  prev = cur;
2176  cur = cur.initialize_entity_next;
2177  }
2178 }
2180 {
2181  entity startoflist = initialize_entity_first;
2184  for (entity e = startoflist; e; e = e.initialize_entity_next)
2185  {
2186  e.remove_except_protected_forbidden = 1;
2187  }
2188  for (entity e = startoflist; e; )
2189  {
2190  e.remove_except_protected_forbidden = 0;
2191  e.initialize_entity_order = 0;
2192  entity next = e.initialize_entity_next;
2193  e.initialize_entity_next = NULL;
2194  var void(entity this) func = e.initialize_entity;
2195  e.initialize_entity = func_null;
2196  if (e.classname == "initialize_entity")
2197  {
2198  entity wrappee = e.enemy;
2199  builtin_remove(e);
2200  e = wrappee;
2201  }
2202  //dprint("Delayed initialization: ", e.classname, "\n");
2203  if (func)
2204  {
2205  func(e);
2206  }
2207  else
2208  {
2209  eprint(e);
2210  backtrace(strcat("Null function in: ", e.classname, "\n"));
2211  }
2212  e = next;
2213  }
2215 }
2216 
2217 // deferred dropping
2219 {
2220  WITHSELF(this, builtin_droptofloor());
2221  this.dropped_origin = this.origin;
2222 }
2223 
2225 {
2226  InitializeEntity(this, DropToFloor_Handler, INITPRIO_DROPTOFLOOR);
2227 }
2228 
2230 void RunThink(entity this, float dt)
2231 {
2232  // don't let things stay in the past.
2233  // it is possible to start that way by a trigger with a local time.
2234  if(this.nextthink <= 0 || this.nextthink > time + dt)
2235  return;
2236 
2237  float oldtime = time; // do we need to save this?
2238 
2239  for (int iterations = 0; iterations < 128 && !wasfreed(this); iterations++)
2240  {
2241  time = max(oldtime, this.nextthink);
2242  this.nextthink = 0;
2243 
2244  if(getthink(this))
2245  getthink(this)(this);
2246  // mods often set nextthink to time to cause a think every frame,
2247  // we don't want to loop in that case, so exit if the new nextthink is
2248  // <= the time the qc was told, also exit if it is past the end of the
2249  // frame
2250  if(this.nextthink <= time || this.nextthink > oldtime + dt || !autocvar_sv_gameplayfix_multiplethinksperframe)
2251  break;
2252  }
2253 
2254  time = oldtime;
2255 }
2256 
2259 {
2260  if(autocvar_sv_freezenonclients)
2261  return;
2262 
2263  IL_EACH(g_moveables, true,
2264  {
2265  if(IS_CLIENT(it) || it.move_movetype == MOVETYPE_PHYSICS)
2266  continue;
2267 
2268  //set_movetype(it, it.move_movetype);
2269  // inline the set_movetype function, since this is called a lot
2270  it.movetype = (it.move_qcphysics) ? MOVETYPE_QCENTITY : it.move_movetype;
2271 
2272  if(it.move_qcphysics && it.move_movetype != MOVETYPE_NONE)
2273  Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
2274 
2275  if(it.movetype >= MOVETYPE_USER_FIRST && it.movetype <= MOVETYPE_USER_LAST) // these cases have no think handling
2276  {
2277  if(it.move_movetype == MOVETYPE_PUSH || it.move_movetype == MOVETYPE_FAKEPUSH)
2278  continue; // these movetypes have no regular think function
2279  // handle thinking here
2280  if (getthink(it) && it.nextthink > 0 && it.nextthink <= time + PHYS_INPUT_TIMELENGTH)
2281  RunThink(it, PHYS_INPUT_TIMELENGTH);
2282  }
2283  });
2284 
2285  if(autocvar_sv_gameplayfix_delayprojectiles >= 0)
2286  return;
2287 
2288  // make a second pass to see if any ents spawned this frame and make
2289  // sure they run their move/think. this is verified by checking .move_time, which will never be 0 if the entity has moved
2290  // MOVETYPE_NONE is also checked as .move_time WILL be 0 with that movetype
2291  IL_EACH(g_moveables, it.move_qcphysics,
2292  {
2293  if(IS_CLIENT(it) || it.move_time || it.move_movetype == MOVETYPE_NONE || it.move_movetype == MOVETYPE_PHYSICS)
2294  continue;
2295  Movetype_Physics_NoMatchTicrate(it, PHYS_INPUT_TIMELENGTH, false);
2296  });
2297 }
2298 
2299 void systems_update();
2300 void EndFrame()
2301 {
2303 
2304  Physics_Frame();
2305 
2307  entity e = IS_SPEC(it) ? it.enemy : it;
2308  if (e.typehitsound) {
2309  STAT(TYPEHIT_TIME, it) = time;
2310  } else if (e.killsound) {
2311  STAT(KILL_TIME, it) = time;
2312  } else if (e.hitsound_damage_dealt) {
2313  STAT(HIT_TIME, it) = time;
2314  // NOTE: this is not accurate as client code doesn't need so much accuracy for its purposes
2315  STAT(HITSOUND_DAMAGE_DEALT_TOTAL, it) += ceil(e.hitsound_damage_dealt);
2316  }
2317  });
2318  // add 1 frametime because after this, engine SV_Physics
2319  // increases time by a frametime and then networks the frame
2320  // add another frametime because client shows everything with
2321  // 1 frame of lag (cl_nolerp 0). The last +1 however should not be
2322  // needed!
2323  float altime = time + frametime * (1 + autocvar_g_antilag_nudge);
2324  FOREACH_CLIENT(true, {
2325  it.typehitsound = false;
2326  it.hitsound_damage_dealt = 0;
2327  it.killsound = false;
2328  antilag_record(it, CS(it), altime);
2329  });
2330  IL_EACH(g_monsters, true,
2331  {
2332  antilag_record(it, it, altime);
2333  });
2334  IL_EACH(g_projectiles, it.classname == "nade",
2335  {
2336  antilag_record(it, it, altime);
2337  });
2338  systems_update();
2339  IL_ENDFRAME();
2340 }
2341 
2342 
2343 /*
2344  * RedirectionThink:
2345  * returns true if redirecting
2346  */
2350 {
2351  float clients_found;
2352 
2353  if(redirection_target == "")
2354  return false;
2355 
2356  if(!redirection_timeout)
2357  {
2358  cvar_set("sv_public", "-2");
2359  redirection_timeout = time + 0.6; // this will only try twice... should be able to keep more clients
2360  if(redirection_target == "self")
2361  bprint("^3SERVER NOTICE:^7 restarting the server\n");
2362  else
2363  bprint("^3SERVER NOTICE:^7 redirecting everyone to ", redirection_target, "\n");
2364  }
2365 
2366  if(time < redirection_nextthink)
2367  return true;
2368 
2369  redirection_nextthink = time + 1;
2370 
2371  clients_found = 0;
2373  // TODO add timer
2374  LOG_INFO("Redirecting: sending connect command to ", it.netname);
2375  if(redirection_target == "self")
2376  stuffcmd(it, "\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " reconnect\n");
2377  else
2378  stuffcmd(it, strcat("\ndisconnect; defer ", ftos(autocvar_quit_and_redirect_timer), " \"connect ", redirection_target, "\"\n"));
2379  ++clients_found;
2380  });
2381 
2382  LOG_INFO("Redirecting: ", ftos(clients_found), " clients left.");
2383 
2384  if(time > redirection_timeout || clients_found == 0)
2385  localcmd("\nwait; wait; wait; quit\n");
2386 
2387  return true;
2388 }
2389 
2391 {
2392  // Loaded from a save game
2393  // some things then break, so let's work around them...
2394 
2395  // Progs DB (capture records)
2397 
2398  // Mapinfo
2399  MapInfo_Shutdown();
2402  WeaponStats_Init();
2403 
2404  TargetMusic_RestoreGame();
2405 }
2406 
2407 void Shutdown()
2408 {
2409  game_stopped = 2;
2410 
2411  if(world_initialized > 0)
2412  {
2413  world_initialized = 0;
2414 
2415  // if a timeout is active, reset the slowmo value to normal
2416  if(timeout_status == TIMEOUT_ACTIVE)
2417  cvar_set("slowmo", ftos(orig_slowmo));
2418 
2419  LOG_TRACE("Saving persistent data...");
2420  Ban_SaveBans();
2421 
2422  // playerstats with unfinished match
2423  PlayerStats_GameReport(false);
2424 
2425  if(!cheatcount_total)
2426  {
2429  else
2431  }
2432  if(autocvar_developer > 0)
2433  {
2435  db_dump(TemporaryDB, "server-temp.db");
2436  else
2437  db_save(TemporaryDB, "server-temp.db");
2438  }
2439  CheatShutdown(); // must be after cheatcount check
2442  LOG_TRACE("Saving persistent data... done!");
2443  // tell the bot system the game is ending now
2444  bot_endgame();
2445 
2447  MapInfo_Shutdown();
2448 
2450  }
2451  else if(world_initialized == 0)
2452  {
2453  LOG_INFO("NOTE: crashed before even initializing the world, not saving persistent data");
2454  }
2455  else
2456  {
2458  }
2459 }
#define INGAME(it)
Definition: sv_rules.qh:20
const int NUM_TEAMS
Number of teams in the game.
Definition: teams.qh:3
void DropToFloor_Handler(entity this)
Definition: world.qc:2218
entity random_start_ammo
Entity that contains amount of ammo to give with random start weapons.
Definition: world.qh:97
vector WepSet
Definition: weapon.qh:11
void remove_unsafely(entity e)
Definition: main.qc:248
void RandomSeed_Spawn()
Definition: world.qc:578
float latency_time
Definition: world.qc:55
float checkrules_suddendeathend
Definition: world.qh:33
#define IL_EACH(this, cond, body)
int MapInfo_RequiredFlags()
Definition: mapinfo.qc:1339
float MOVETYPE_NONE
Definition: progsdefs.qc:246
ERASEABLE int db_create()
Definition: map.qh:25
void race_StartCompleting()
Definition: race.qc:1174
float start_ammo_rockets
Definition: world.qh:87
int serverflags
Definition: main.qh:184
float MOVETYPE_USER_LAST
float autocvar_timelimit_overtime
Definition: world.qh:27
string string_null
Definition: nil.qh:9
void Shutdown()
Definition: world.qc:2407
entity world
Definition: csprogsdefs.qc:15
void remove_safely(entity e)
Definition: main.qc:255
entity pingplreport
Definition: world.qc:56
void CampaignPreInit()
Definition: campaign.qc:54
string GetTeamScoreString(float tm, float shortString)
Definition: scores.qc:648
float intermission_exittime
Definition: intermission.qh:10
#define getthink(e)
string getrankings()
Definition: getreplies.qc:46
bool world_already_spawned
Definition: world.qc:687
void GameplayMode_DelayedInit(entity this)
Definition: world.qc:634
float start_ammo_fuel
Definition: world.qh:90
float warmup_start_ammo_shells
Definition: world.qh:104
float trace_dphitq3surfaceflags
WepSet warmup_start_weapons
Definition: world.qh:100
string autocvar_sv_termsofservice_url
Definition: world.qh:51
void GotoNextMap(float reinit)
const float MOVETYPE_PHYSICS
void MapInfo_LoadMapSettings(string s)
Definition: mapinfo.qc:1240
string MapInfo_Map_clientstuff
Definition: mapinfo.qh:11
ERASEABLE int db_load(string filename)
Definition: map.qh:35
WepSet start_weapons
Definition: world.qh:81
float g_pickup_nails_max
Definition: world.qh:70
vector dropped_origin
Definition: world.qh:157
void GameRules_limit_fallbacks()
Set any unspecified rules to their defaults.
Definition: sv_rules.qc:73
#define IS_CLIENT(v)
Definition: utils.qh:13
float g_pickup_weapons_anyway
Definition: world.qh:75
int team
Definition: main.qh:157
void RunThink(entity this, float dt)
Definition: world.qc:2230
void Team_SetTeamScore(entity team_ent, float score)
Sets the score of the team.
Definition: teamplay.qc:80
string GetMapname()
Definition: intermission.qc:18
void GameLogClose()
Definition: gamelog.qc:48
int have_team_spawns
Definition: spawnpoints.qh:16
void SetWinners(.float field, float value)
Definition: world.qc:1407
float TeamScore_AddToTeam(int t, float scorefield, float score)
Adds a score to the given team.
Definition: scores.qc:108
void weaponarena_available_all_update(entity this)
Definition: world.qc:1804
void remove_except_protected(entity e)
Definition: main.qc:241
WepSet warmup_start_weapons_defaultmask
Definition: world.qh:102
void PingPLReport_Think(entity this)
Definition: world.qc:57
float ServerProgsDB
Definition: world.qh:131
float trace_dphitcontents
entity() spawn
prev
Definition: all.qh:66
int player_count
Definition: api.qh:103
const float MOVE_NORMAL
Definition: csprogsdefs.qc:252
ClientState CS(Client this)
Definition: state.qh:47
#define FOREACH_CLIENT(cond, body)
Definition: utils.qh:49
Gametype MapInfo_LoadedGametype
Definition: mapinfo.qh:193
const int SERVERFLAG_ALLOW_FULLBRIGHT
Definition: constants.qh:15
int checkrules_overtimesadded
Definition: world.qh:34
#define GameRules_scoring_add(client, fld, value)
Definition: sv_rules.qh:78
#define static_init()
Definition: static.qh:33
string MapInfo_Type_ToText(Gametype t)
Definition: mapinfo.qc:621
#define BADCVAR(p)
#define static_init_precache()
Definition: static.qh:43
float checkrules_suddendeathwarning
Definition: world.qh:32
const int WINNING_STARTSUDDENDEATHOVERTIME
Definition: world.qh:138
ERASEABLE void db_close(int db)
Definition: map.qh:84
void WeaponStats_Shutdown()
Definition: weaponstats.qc:73
bool autocvar__endmatch
Definition: world.qh:6
void Ban_LoadBans()
Definition: ipban.qc:305
float checkpvs(vector viewpos, entity viewee)
bool warmup_stage
Definition: main.qh:103
#define RACE_RECORD
Definition: util.qh:58
var void delete_fn(entity e)
const float FILE_READ
Definition: csprogsdefs.qc:231
const float FILE_APPEND
Definition: csprogsdefs.qc:232
float redirection_nextthink
Definition: world.qc:2348
int start_items
Definition: world.qh:84
string m_name
M: wepname : human readable name.
Definition: weapon.qh:78
float maxclients
Definition: csprogsdefs.qc:21
float redirection_timeout
Definition: world.qc:2347
float WinningConditionHelper_lowerisbetter
lower is better, duh
Definition: scores.qh:115
int world_initialized
Definition: world.qh:39
bool autocvar__sv_init
Definition: world.qh:5
bool autocvar_sv_gameplayfix_multiplethinksperframe
Definition: world.qc:2229
float MoveToRandomMapLocation(entity e, float goodcontents, float badcontents, float badsurfaceflags, float attempts, float maxaboveground, float minviewdistance)
Definition: world.qc:1157
int fragsleft_last
Definition: world.qc:1427
entity to
Definition: self.qh:96
void RandomSeed_Think(entity this)
Definition: world.qc:571
float start_ammo_shells
Definition: world.qh:85
origin
Definition: ent_cs.qc:114
int MapInfo_ForbiddenFlags()
Definition: mapinfo.qc:1324
const float TIMEOUT_ACTIVE
Definition: common.qh:49
string g_weaponarena_list
Definition: world.qh:79
float ping
Definition: main.qh:138
const int WEP_FLAG_HIDDEN
Definition: weapon.qh:200
#define itos(i)
Definition: int.qh:6
void Movetype_Physics_NoMatchTicrate(entity this, float movedt, bool isclient)
Definition: movetypes.qc:813
void CheckRules_World()
Definition: world.qc:1593
void Nagger_Init()
Definition: vote.qc:97
bool g_race_qualifying
Definition: race.qh:12
const float LATENCY_THINKRATE
Definition: world.qc:52
#define X(match)
void anticheat_endframe()
Definition: anticheat.qc:234
void cvar_changes_init()
Definition: world.qc:149
#define LOG_HELP(...)
Definition: log.qh:95
float spawnflags
Definition: progsdefs.qc:191
WepSet warmup_start_weapons_default
Definition: world.qh:101
void InitializeEntitiesRun()
Definition: world.qc:2179
void WeaponStats_Init()
Definition: weaponstats.qc:9
float warmup_start_ammo_plasma
Definition: world.qh:108
float RedirectionThink()
Definition: world.qc:2349
bool autocvar_g_warmup_allguns
Definition: world.qh:9
#define Q3COMPAT_ARENA
Definition: quake3.qh:4
string clientstuff
Definition: world.qh:55
const int WINNING_YES
Definition: world.qh:136
#define IS_REAL_CLIENT(v)
Definition: utils.qh:17
void ClearWinners()
Definition: world.qc:1422
#define strcpy(this, s)
Definition: string.qh:49
string mapname
Definition: csprogsdefs.qc:26
string trace_dphittexturename
void InitiateOvertime()
Definition: world.qc:1369
string modname
Definition: world.qh:45
entity WinningConditionHelper_winner
the winning player, or NULL if none
Definition: scores.qh:113
spree_cen s1 CPID_Null
Definition: all.inc:583
float autocvar_g_antilag_nudge
Definition: antilag.qh:4
float TemporaryDB
Definition: world.qh:132
void CheatShutdown()
Definition: cheats.qc:53
#define IS_SPEC(v)
Definition: utils.qh:10
float sys_frametime
Definition: common.qh:57
string redirection_target
Definition: world.qh:61
#define buf_create
Definition: dpextensions.qh:63
ERASEABLE void IL_ENDFRAME()
void Map_MarkAsRecent(string m)
int q3compat
Definition: quake3.qh:3
float autocvar_sv_mapchange_delay
Definition: world.qh:22
float WinningConditionHelper_zeroisworst
zero is worst, duh
Definition: scores.qh:116
string matchid
Definition: world.qh:57
void ScoreRules_generic()
Definition: scores_rules.qc:69
Gametype MapInfo_CurrentGametype()
Definition: mapinfo.qc:1150
bool autocvar_sv_eventlog_console
Definition: gamelog.qh:4
float cvar_purechanges_count
Definition: world.qh:43
float Q3SURFACEFLAG_SKY
#define autocvar_g_maplist
Definition: mapvoting.qh:3
float warmup_start_ammo_cells
Definition: world.qh:107
void readlevelcvars()
Definition: world.qc:2063
bool autocvar_g_waypoints_for_items
Definition: api.qh:8
float cnt
Definition: powerups.qc:24
#define g_race
Definition: race.qh:46
float autocvar_quit_and_redirect_timer
Definition: world.qh:13
ERASEABLE entity IL_PUSH(IntrusiveList this, entity it)
Push to tail.
int MapInfo_CurrentFeatures()
Definition: mapinfo.qc:1140
bool autocvar_sv_curl_serverpackages_auto
Definition: world.qh:16
void readplayerstartcvars()
Definition: world.qc:1843
entity scores_initialized
Definition: scores.qh:7
void GameRules_teams(bool value)
Definition: sv_rules.qc:6
void SetResource(entity e, Resource res_type, float amount)
Sets the current amount of resource the given entity will have.
Definition: cl_resources.qc:26
float warmup_start_ammo_fuel
Definition: world.qh:109
bool bot_waypoints_for_items
Definition: api.qh:9
float WinningConditionHelper_secondscore
second highest score
Definition: scores.qh:109
#define LOG_INFOF(...)
Definition: log.qh:71
void droptofloor(entity this)
Definition: world.qc:2224
#define Q3COMPAT_DEFI
Definition: quake3.qh:5
string record_type
Definition: world.qh:49
float ping_packetloss
Definition: main.qh:138
spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 spree_cen s1 f1 s1 strcat(_("Level %s: "), "^BG%s\3\, _("^BGPress ^F2%s^BG to enter the game"))
#define MAX_TEAMSCORE
Definition: scores.qh:142
string cvar_changes
Definition: world.qh:41
void VoteThink()
Definition: vote.qc:324
float start_ammo_cells
Definition: world.qh:88
WepSet weapons_most()
Definition: world.qc:1794
float cheatcount_total
Definition: cheats.qh:10
const int MOVETYPE_QCENTITY
Definition: movetypes.qh:152
string getmaplist()
Definition: getreplies.qc:233
IntrusiveList g_items
Definition: items.qh:126
#define BADPRESUFFIX(p, s)
float g_pickup_rockets_max
Definition: world.qh:71
int autocvar_leadlimit_and_fraglimit
Definition: sv_rules.qh:4
float GetWinningCode(float fraglimitreached, float equality)
Definition: world.qc:1378
void systems_update()
Definition: main.qc:7
void ShuffleMaplist()
ERASEABLE void db_save(int db, string filename)
Definition: map.qh:8
ERASEABLE void db_dump(int db, string filename)
Definition: map.qh:69
void Ban_SaveBans()
Definition: ipban.qc:263
#define NULL
Definition: post.qh:17
string getladder()
Definition: getreplies.qc:71
spawnfunc(__init_dedicated_server)
Definition: world.qc:587
float frametime
Definition: csprogsdefs.qc:17
#define startsWith(haystack, needle)
Definition: string.qh:217
entity randomseed
Definition: world.qc:564
bool autocvar_sv_freezenonclients
Definition: world.qc:2257
#define LOG_INFO(...)
Definition: log.qh:70
void CampaignPostInit()
Definition: campaign.qc:105
string cvar_purechanges
Definition: world.qh:42
void NextLevel()
Definition: world.qc:1276
#define backtrace(msg)
Definition: log.qh:105
float DoNextMapOverride(float reinit)
#define autocvar_g_weaponarena
Definition: world.qh:11
float TeamScore_GetCompareValue(float t)
Returns a value indicating the team score (and higher is better).
Definition: scores.qc:783
float jointime
Definition: client.qh:64
#define BADPREFIX(p)
float g_pickup_fuel_max
Definition: world.qh:74
bool autocvar_g_use_ammunition
Definition: world.qh:7
vector trace_endpos
Definition: csprogsdefs.qc:37
const int WINNING_NEVER
Definition: world.qh:137
float WinningCondition_RanOutOfSpawns()
Definition: world.qc:1509
string getrecords(int page)
Definition: getreplies.qc:35
bool some_spawn_has_been_used
Definition: spawnpoints.qh:15
string autocvar_sessionid
Definition: world.qh:15
void GameLogEcho(string s)
Definition: gamelog.qc:12
float g_pickup_shells_max
Definition: world.qh:69
#define WITHSELF(value, block)
Definition: self.qh:17
const float SPAWNFLAG_NO_WAYPOINTS_FOR_ITEMS
Definition: world.qc:102
void Physics_Frame()
Definition: world.qc:2258
void DumpStats(float final)
Definition: world.qc:1170
string getmonsterlist()
Definition: getreplies.qc:290
#define Team_ColorName_Upper(teamid)
Definition: teams.qh:223
float teamplay
Definition: progsdefs.qc:31
bool RandomSeed_Send(entity this, entity to, int sf)
Definition: world.qc:565
#define M_ARGV(x, type)
Definition: events.qh:17
float latency_sum
Definition: world.qc:53
#define IS_DEAD(s)
Definition: utils.qh:26
void InitGameplayMode()
Definition: world.qc:640
void weaponarena_available_devall_update(entity this)
Definition: world.qc:1817
entity Team_GetTeamFromIndex(int index)
Returns the global team entity at the given index.
Definition: teamplay.qc:57
float nextthink
Definition: csprogsdefs.qc:121
void bot_endgame()
Definition: bot.qc:369
void MapInfo_ClearTemps()
Definition: mapinfo.qc:1299
#define BITSET(var, mask, flag)
Definition: bits.qh:11
float warmup_start_armorvalue
Definition: world.qh:111
void GameLogInit()
Definition: gamelog.qc:42
void __init_dedicated_server_shutdown()
Definition: world.qc:622
#define stuffcmd(cl,...)
Definition: progsdefs.qh:23
vector(float skel, float bonenum) _skel_get_boneabs_hidden
void antilag_record(entity e, entity store, float t)
Definition: antilag.qc:21
bool autocvar_sv_logscores_file
Definition: world.qh:20
#define tokenize_console
Definition: dpextensions.qh:24
next
Definition: all.qh:88
void ReadyRestart(bool forceWarmupEnd)
Definition: vote.qc:484
void MapVote_Think()
Definition: mapvoting.qc:645
IntrusiveList g_projectiles
Definition: common.qh:46
void EndFrame()
Definition: world.qc:2300
string Team_ColorCode(int teamid)
Definition: teams.qh:63
ERASEABLE bool cvar_value_issafe(string s)
Definition: cvar.qh:11
vector v
Definition: ent_cs.qc:116
float GetResource(entity e, Resource res_type)
Returns the current amount of resource the given entity has.
Definition: cl_resources.qc:10
float start_health
Definition: world.qh:98
void InitializeEntity(entity e, void(entity this) func, int order)
Definition: world.qc:2146
bool TeamBalance_IsTeamAllowed(entity balance, int index)
Returns whether the team change to the specified team is allowed.
Definition: teamplay.qc:662
const int WEP_FLAG_SPECIALATTACK
Definition: weapon.qh:211
STATIC_INIT_EARLY(maxclients)
Definition: world.qc:626
string MapInfo_Map_fog
Definition: mapinfo.qh:12
float g_pickup_plasma_max
Definition: world.qh:73
WepSet weapons_devall()
Definition: world.qc:1784
#define LOG_TRACE(...)
Definition: log.qh:81
void GotoFirstMap(entity this)
Definition: world.qc:115
float warmup_start_ammo_rockets
Definition: world.qh:106
float want_weapon(entity weaponinfo, float allguns)
Definition: world.qc:1725
WepSet start_weapons_default
Definition: world.qh:82
bool sv_ready_restart_after_countdown
Definition: world.qh:119
void AddWinners(.float field, float value)
Definition: world.qc:1413
WepSet weapons_all()
Definition: world.qc:1774
float WinningConditionHelper_winnerteam
the color of the winning team, or -1 if none
Definition: scores.qh:110
void FixIntermissionClient(entity e)
void MapVote_Start()
Definition: mapvoting.qc:632
float ping_movementloss
Definition: main.qh:138
entity initialize_entity_first
Definition: world.qh:124
const int WINNING_NO
Definition: world.qh:135
string GetGametype()
Definition: intermission.qc:13
#define INGAME_JOINED(it)
Definition: sv_rules.qh:21
float g_weapon_stay
Definition: world.qh:112
float start_ammo_nails
Definition: world.qh:86
#define tokenizebyseparator
Definition: dpextensions.qh:21
void CampaignPreIntermission()
Definition: campaign.qc:172
bool autocvar_sv_db_saveasdump
Definition: world.qh:17
#define MUTATOR_CALLHOOK(id,...)
Definition: base.qh:140
#define IS_BOT_CLIENT(v)
want: (IS_CLIENT(v) && !IS_REAL_CLIENT(v))
Definition: utils.qh:15
float WinningCondition_Scores(float limit, float leadlimit)
Definition: world.qc:1428
string sv_termsofservice_url_escaped
Definition: world.qh:53
bool autocvar_g_jetpack
Definition: world.qh:8
void RestoreGame()
Definition: world.qc:2390
float warmup_start_health
Definition: world.qh:110
float autocvar_g_maplist_shuffle
Definition: mapvoting.qh:9
#define new_pure(class)
purely logical entities (.origin doesn&#39;t work)
Definition: oo.qh:62
setorigin(ent, v)
noref int autocvar_developer
Definition: log.qh:102
bool autocvar_g_spawn_useallspawns
Definition: spawnpoints.qh:5
float checkrules_equality
Definition: world.qh:31
#define setthink(e, f)
void VoteReset()
Definition: vote.qc:128
bool intermission_running
Definition: intermission.qh:9
IntrusiveList g_moveables
Definition: world.qh:160
int Team_IndexToTeam(int index)
Converts team index into team value.
Definition: teams.qh:169
#define strfree(this)
Definition: string.qh:56
bool autocvar_sv_logscores_console
Definition: world.qh:19
int autocvar_g_pickup_items
Definition: items.qh:11
void SetDefaultAlpha()
Definition: world.qc:104
bool autocvar_g_campaign
Definition: campaign.qh:6
float trace_startsolid
Definition: csprogsdefs.qc:35
const int WEP_FLAG_NORMAL
Definition: weapon.qh:199
ERASEABLE string cons(string a, string b)
Definition: string.qh:257
float default_player_alpha
Definition: world.qh:66
WepSet weapons_start()
Weapons the player normally starts with outside weapon arena.
Definition: world.qc:1763
void CheatInit()
Definition: cheats.qc:48
const int WEP_FLAG_MUTATORBLOCKED
Definition: weapon.qh:203
entity TeamBalance_CheckAllowedTeams(entity for_whom)
Checks whether the player can join teams according to global configuration and mutator settings...
Definition: teamplay.qc:487
int random_start_weapons_count
Number of random start weapons to give to players.
Definition: world.qh:92
bool autocvar_sv_logscores_bots
Definition: world.qh:18
void
Definition: self.qh:83
#define BADVALUE(p, val)
int autocvar_timelimit_overtimes
Definition: world.qh:28
bool autocvar_sv_eventlog
Definition: gamelog.qh:3
string cache_mutatormsg
Definition: world.qh:63
IntrusiveList g_monsters
Definition: sv_monsters.qh:144
fields which are explicitly/manually set are marked with "M", fields set automatically are marked wit...
Definition: weapon.qh:41
float WinningConditionHelper_topscore
highest score
Definition: scores.qh:108
float g_pickup_cells_max
Definition: world.qh:72
float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition: mapinfo.qc:158
float time
Definition: csprogsdefs.qc:16
string gamemode_name
Definition: world.qh:47
float start_armorvalue
Definition: world.qh:99
string GetPlayerScoreString(entity pl, float shortString)
Returns score strings for eventlog etc.
Definition: scores.qc:586
ERASEABLE bool fexists(string f)
Definition: file.qh:4
void MapInfo_Shutdown()
Definition: mapinfo.qc:1311
float WinningConditionHelper_equality
we have no winner
Definition: scores.qh:112
void MapInfo_Enumerate()
Definition: mapinfo.qc:115
float latency_cnt
Definition: world.qc:54
float default_weapon_alpha
Definition: world.qh:67
Weapon Weapon_from_name(string s)
Definition: all.qh:134
int autocvar_sv_eventlog_files_counter
Definition: gamelog.qh:6
float MOVETYPE_USER_FIRST
string getlsmaps()
Definition: getreplies.qc:253
ERASEABLE string strftime_s()
Definition: string.qh:91
WepSet start_weapons_defaultmask
Definition: world.qh:83
float Team_GetTeamScore(entity team_ent)
Returns the score of the team.
Definition: teamplay.qc:75
float trace_fraction
Definition: csprogsdefs.qc:36
float start_ammo_plasma
Definition: world.qh:89
#define FOREACH(list, cond, body)
Definition: iter.qh:19
float autocvar_timelimit_suddendeath
Definition: world.qh:29
void ClientInit_Spawn()
Definition: client.qc:894
string autocvar_sv_logscores_filename
Definition: world.qh:21
#define boolean(value)
Definition: bool.qh:9
bool autocvar_g_norecoil
Definition: tracing.qh:15
WepSet g_weaponarena_weapons
Definition: world.qh:77
bool MoveToRandomLocationWithinBounds(entity e, vector boundmin, vector boundmax, float goodcontents, float badcontents, float badsurfaceflags, int attempts, float maxaboveground, float minviewdistance)
Definition: world.qc:1035
bool server_is_dedicated
Definition: world.qh:37
bool Team_IsValidTeam(int team_num)
Returns whether team value is valid.
Definition: teams.qh:133
#define IS_PLAYER(v)
Definition: utils.qh:9
void PingPLReport_Spawn()
Definition: world.qc:95
#define static_init_late()
Definition: static.qh:38
var void func_null()
float InitiateSuddenDeath()
Definition: world.qc:1337
const float FLOAT_MAX
Definition: float.qh:3
IntrusiveList g_spawnpoints
Definition: spawnpoints.qh:32
void WinningConditionHelper(entity this)
Sets the following results for the current scores entities.
Definition: scores.qc:415
#define LOG_DEBUG(...)
Definition: log.qh:85
string cache_lastmutatormsg
Definition: world.qh:64
float autocvar_g_player_alpha
Definition: client.qh:18
float warmup_start_ammo_nails
Definition: world.qh:105
void weaponarena_available_most_update(entity this)
Definition: world.qc:1830
#define endsWith(this, suffix)
Definition: string.qh:226
float g_weaponarena
Definition: world.qh:76
float orig_slowmo
Definition: common.qh:58