Xonotic
mapinfo.qc
Go to the documentation of this file.
1 #include "mapinfo.qh"
2 #if defined(CSQC)
3  #include <common/util.qh>
4  #include <common/weapons/_all.qh>
5 #elif defined(MENUQC)
6 #elif defined(SVQC)
7  #include <common/util.qh>
8  #include <common/monsters/_mod.qh>
9 #endif
10 
11 #ifdef MENUQC
12 #define WARN_COND false
13 #else
15 #define WARN_COND (!autocvar_g_mapinfo_ignore_warnings && MapInfo_Map_bspname == mi_shortname)
16 #endif
17 
18 // generic string stuff
19 
23 
25 {
27  return;
28 
32 }
33 
35 {
40 }
41 
43 {
45  return;
46 
48 }
49 
51 {
52  float i;
53  string s;
55  return;
56 
58  if(s == "")
59  {
60  i = buf_getsize(_MapInfo_Cache_Buf_IndexToMapData);
62  }
63  else
64  i = stof(s);
65 
66  // now store all the stuff
75 }
76 
77 float MapInfo_Cache_Retrieve(string map)
78 {
79  float i;
80  string s;
82  return 0;
83 
85  if(s == "")
86  return 0;
87  i = stof(s);
88 
89  // now retrieve all the stuff
98 
99  return 1;
100 }
101 
102 // GLOB HANDLING (for all BSP files)
106 string _MapInfo_GlobItem(float i)
107 {
108  string s;
109  if(!_MapInfo_globopen)
110  return string_null;
112  return substring(s, 5, strlen(s) - 9); // without maps/ and .bsp
113 }
114 
116 {
118  {
120  _MapInfo_globopen = 0;
121  }
123  _MapInfo_globhandle = search_begin("maps/*.bsp", true, true);
124  if(_MapInfo_globhandle >= 0)
125  {
127  _MapInfo_globopen = 1;
128  }
129  else
130  _MapInfo_globcount = 0;
131 }
132 
133 // filter the info by game type mask (updates MapInfo_count)
134 //
138 {
139  return stof(bufstr_get(_MapInfo_filtered, i));
140 }
141 
142 void _MapInfo_FilterList_swap(float i, float j, entity pass)
143 {
144  string h;
145  h = bufstr_get(_MapInfo_filtered, i);
146  bufstr_set(_MapInfo_filtered, i, bufstr_get(_MapInfo_filtered, j));
147  bufstr_set(_MapInfo_filtered, j, h);
148 }
149 
150 float _MapInfo_FilterList_cmp(float i, float j, entity pass)
151 {
152  string a, b;
153  a = _MapInfo_GlobItem(stof(bufstr_get(_MapInfo_filtered, i)));
154  b = _MapInfo_GlobItem(stof(bufstr_get(_MapInfo_filtered, j)));
155  return strcasecmp(a, b);
156 }
157 
158 float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
159 {
160  return _MapInfo_FilterGametype(pGametype.m_flags, pFeatures, pFlagsRequired, pFlagsForbidden, pAbortOnGenerate);
161 }
162 float _MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
163 {
164  float i, j;
166  {
169  }
170  MapInfo_count = 0;
171  for(i = 0, j = -1; i < _MapInfo_globcount; ++i)
172  {
173  if(MapInfo_Get_ByName(_MapInfo_GlobItem(i), 1, NULL) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
174  if(pAbortOnGenerate)
175  {
176  LOG_TRACE("Autogenerated a .mapinfo, doing the rest later.");
178  return 0;
179  }
180  if((MapInfo_Map_supportedGametypes & pGametype) != 0)
181  if((MapInfo_Map_supportedFeatures & pFeatures) == pFeatures)
182  if((MapInfo_Map_flags & pFlagsForbidden) == 0)
183  if((MapInfo_Map_flags & pFlagsRequired) == pFlagsRequired)
184  bufstr_set(_MapInfo_filtered, ++j, ftos(i));
185  }
186  MapInfo_count = j + 1;
188 
189  // sometimes the glob isn't sorted nicely, so fix it here...
191 
192  return 1;
193 }
194 void MapInfo_FilterString(string sf)
195 {
196  // this function further filters _MapInfo_filtered, which is prepared by MapInfo_FilterGametype by string
197  float i, j;
198  string title;
199 
200  for(i = 0, j = -1; i < MapInfo_count; ++i)
201  {
202  if (MapInfo_Get_ByID(i))
203  {
204  // prepare for keyword filter
205  if (MapInfo_Map_title && strstrofs(MapInfo_Map_title, "<TITLE>", 0) == -1)
206  title = MapInfo_Map_title;
207  else
208  title = MapInfo_Map_bspname;
209  // keyword filter
210  if((strstrofs(strtolower(title), strtolower(sf), 0)) >= 0)
211  bufstr_set(_MapInfo_filtered, ++j, bufstr_get(_MapInfo_filtered, i));
212  }
213  }
214  MapInfo_count = j + 1;
216 
217  // sometimes the glob isn't sorted nicely, so fix it here...
219 }
220 
222 {
224  {
225  buf_del(_MapInfo_filtered);
227  }
228 }
229 
230 // load info about the i-th map into the MapInfo_Map_* globals
231 string MapInfo_BSPName_ByID(float i)
232 {
234 }
235 
236 string unquote(string s)
237 {
238  float l = strlen(s);
239  for(float i = 0; i < l; ++i)
240  {
241  string ch = substring(s, i, 1);
242  if((ch != " ") && (ch != "\""))
243  {
244  for(float j = l - i - 1; j > 0; --j)
245  {
246  ch = substring(s, i+j, 1);
247  if(ch != " ") if(ch != "\"")
248  return substring(s, i, j+1);
249  }
250  return substring(s, i, 1);
251  }
252  }
253  return "";
254 }
255 
256 bool MapInfo_Get_ByID(int i)
257 {
258  return MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, NULL) ? true : false;
259 }
260 
262 
263 float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
264 {
265  string fn;
266  float fh;
267  string s, k, v;
268  vector o;
269  float i;
270  float inWorldspawn;
271  float r;
272  float diameter, spawnpoints;
273  float spawnplaces;
274 
275  vector mapMins, mapMaxs;
276 
277  r = 1;
278  fn = strcat("maps/", pFilename, ".ent");
279  fh = fopen(fn, FILE_READ);
280  if(fh < 0)
281  {
282  r = 2;
283  fn = strcat("maps/", pFilename, ".bsp");
284  fh = fopen(fn, FILE_READ);
285  }
286  if(fh < 0)
287  return 0;
288  LOG_INFO("Analyzing ", fn, " to generate initial mapinfo");
289 
290  inWorldspawn = 2;
291  MapInfo_Map_flags = 0;
293  spawnpoints = 0;
294  spawnplaces = 0;
296  mapMins = '0 0 0';
297  mapMaxs = '0 0 0';
298 
299  for (;;)
300  {
301  if (!((s = fgets(fh))))
302  break;
303  if(inWorldspawn == 1)
304  if(startsWith(s, "}"))
305  inWorldspawn = 0;
306  k = unquote(car(s));
307  v = unquote(cdr(s));
308  if(inWorldspawn)
309  {
310  if(k == "classname" && v == "worldspawn")
311  inWorldspawn = 1;
312  else if(k == "author")
314  else if(k == "_description")
316  else if(k == "music")
318  else if(k == "noise")
320  else if(k == "message")
321  {
322  i = strstrofs(v, " by ", 0);
323  if(MapInfo_Map_author == "<AUTHOR>" && i >= 0)
324  {
325  MapInfo_Map_title = substring(v, 0, i);
326  MapInfo_Map_author = substring(v, i + 4, strlen(v) - (i + 4));
327  }
328  else
330  }
331  }
332  else
333  {
334  if(k == "origin")
335  {
336  o = stov(strcat("'", v, "'"));
337  mapMins.x = min(mapMins.x, o.x);
338  mapMins.y = min(mapMins.y, o.y);
339  mapMins.z = min(mapMins.z, o.z);
340  mapMaxs.x = max(mapMaxs.x, o.x);
341  mapMaxs.y = max(mapMaxs.y, o.y);
342  mapMaxs.z = max(mapMaxs.z, o.z);
343  }
344  else if(k == "race_place")
345  {
346  if(stof(v) > 0)
347  spawnplaces = 1;
348  }
349  else if(k == "classname")
350  {
351  if(v == "info_player_team1")
352  ++spawnpoints;
353  else if(v == "info_player_team2")
354  ++spawnpoints;
355  else if(v == "info_player_start")
356  ++spawnpoints;
357  else if(v == "info_player_deathmatch")
358  ++spawnpoints;
359  else if(v == "weapon_nex")
360  { }
361  else if(v == "weapon_railgun")
362  { }
363  else if(startsWith(v, "weapon_"))
365  else if(startsWith(v, "turret_"))
367  else if(startsWith(v, "vehicle_"))
369  else if(startsWith(v, "monster_"))
371  else if(v == "target_music" || v == "trigger_music")
372  _MapInfo_Map_worldspawn_music = string_null; // don't use regular BGM
373  else
374  FOREACH(Gametypes, true, it.m_generate_mapinfo(it, v));
375  }
376  }
377  }
378  if(inWorldspawn)
379  {
380  LOG_WARN(fn, " ended still in worldspawn, BUG");
381  return 0;
382  }
383  diameter = vlen(mapMaxs - mapMins);
384 
385  int twoBaseModes = 0;
386  FOREACH(Gametypes, it.m_isTwoBaseMode(), twoBaseModes |= it.m_flags);
387  if(twoBaseModes && (twoBaseModes &= MapInfo_Map_supportedGametypes))
388  {
389  // we have a symmetrical map, don't add the modes without bases
390  }
391  else
392  {
393  FOREACH(Gametypes, it.m_isAlwaysSupported(it, spawnpoints, diameter), MapInfo_Map_supportedGametypes |= it.m_flags);
394  }
395 
396  if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE.m_flags)
397  if(!spawnplaces)
398  {
399  MapInfo_Map_supportedGametypes &= ~MAPINFO_TYPE_RACE.m_flags;
400  MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
401  }
402 
403  LOG_TRACE("-> diameter ", ftos(diameter));
404  LOG_TRACE("; spawnpoints ", ftos(spawnpoints));
406 
407  fclose(fh);
408 
409  return r;
410 }
411 
413 {
414  MapInfo_Map_title = "<TITLE>";
415  MapInfo_Map_titlestring = "<TITLE>";
416  MapInfo_Map_description = "<DESCRIPTION>";
417  MapInfo_Map_author = "<AUTHOR>";
420  MapInfo_Map_flags = 0;
422  MapInfo_Map_fog = "";
423  MapInfo_Map_mins = '0 0 0';
424  MapInfo_Map_maxs = '0 0 0';
425 }
426 
428 {
429  return t.m_legacydefaults;
430 }
431 
432 void _MapInfo_Map_ApplyGametype(string s, Gametype pWantedType, Gametype pThisType, int load_default)
433 {
434  string sa;
435  MapInfo_Map_supportedGametypes |= pThisType.m_flags;
436  if(!(pThisType.m_flags & pWantedType.m_flags))
437  return;
438 
439  if(load_default)
440  _MapInfo_Map_ApplyGametype(_MapInfo_GetDefault(pThisType), pWantedType, pThisType, false);
441 
442  if(!pWantedType.frags) // these modes don't use fraglimit
443  {
444  cvar_set("fraglimit", "0");
445  }
446  else
447  {
448  sa = car(s);
449  if(sa != "")
450  cvar_set("fraglimit", sa);
451  s = cdr(s);
452  }
453 
454  sa = car(s);
455  if(sa != "")
456  cvar_set("timelimit", sa);
457  s = cdr(s);
458 
459  if(pWantedType.m_setTeams)
460  {
461  sa = car(s);
462  if(sa != "")
463  pWantedType.m_setTeams(sa);
464  s = cdr(s);
465  }
466 
467  // rc = timelimit timelimit_qualification laps laps_teamplay
468  if(pWantedType == MAPINFO_TYPE_RACE)
469  {
470  cvar_set("fraglimit", "0"); // special case!
471 
472  sa = car(s); if(sa == "") sa = cvar_string("timelimit");
473  cvar_set("g_race_qualifying_timelimit", sa);
474  s = cdr(s);
475 
476  sa = car(s);
477  if(sa != "")
478  if(cvar("g_race_teams") < 2)
479  cvar_set("fraglimit", sa);
480  s = cdr(s);
481 
482  sa = car(s);
483  if(sa != "")
484  if(cvar("g_race_teams") >= 2)
485  cvar_set("fraglimit", sa);
486  s = cdr(s);
487  }
488 
489  if(!pWantedType.frags) // these modes don't use fraglimit
490  {
491  cvar_set("leadlimit", "0");
492  }
493  else
494  {
495  sa = car(s);
496  if(sa != "")
497  cvar_set("leadlimit", sa);
498  s = cdr(s);
499  }
500 }
501 
503 {
504  return t ? t.model2 : "";
505 }
506 
508 {
509  return t ? t.team : false;
510 }
511 
512 void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThisType)
513 {
514  MapInfo_Map_supportedGametypes |= pThisType.m_flags;
515  if (!(pThisType.m_flags & pWantedType.m_flags))
516  return;
517 
518  // reset all the cvars to their defaults
519 
520  cvar_set("timelimit", cvar_defstring("timelimit"));
521  cvar_set("leadlimit", cvar_defstring("leadlimit"));
522  cvar_set("fraglimit", cvar_defstring("fraglimit"));
523  FOREACH(Gametypes, true, it.m_parse_mapinfo(string_null, string_null));
524 
525  string fraglimit_normal = string_null;
526  string fraglimit_teams = string_null;
527 
528  for (s = strcat(_MapInfo_GetDefaultEx(pWantedType), " ", s); s != ""; s = cdr(s)) {
529  string sa = car(s);
530  if (sa == "") continue;
531  int p = strstrofs(sa, "=", 0);
532  if (p < 0) {
533  if(WARN_COND)
534  LOG_WARNF("Invalid gametype setting in mapinfo for gametype %s: %s", MapInfo_Type_ToString(pWantedType), sa);
535  continue;
536  }
537  string k = substring(sa, 0, p);
538  string v = substring(sa, p + 1, -1);
539  bool handled = true;
540  switch (k) {
541  case "timelimit":
542  {
543  cvar_set("timelimit", v);
544  break;
545  }
546  case "leadlimit":
547  {
548  cvar_set("leadlimit", v);
549  break;
550  }
551  case "pointlimit":
552  case "fraglimit":
553  case "lives":
554  case "laplimit":
555  case "caplimit":
556  {
557  fraglimit_normal = v;
558  break;
559  }
560  case "teampointlimit":
561  case "teamlaplimit":
562  {
563  fraglimit_teams = v;
564  break;
565  }
566  default:
567  {
568  handled = false;
569  break;
570  }
571  }
572  FOREACH(Gametypes, true, handled |= it.m_parse_mapinfo(k, v));
573  if (!handled && WARN_COND)
574  LOG_WARNF("Invalid gametype setting in mapinfo for gametype %s: %s", MapInfo_Type_ToString(pWantedType), sa);
575  }
576 
577  if (pWantedType == MAPINFO_TYPE_RACE && cvar("g_race_teams") >= 2)
578  {
579  if(fraglimit_teams)
580  cvar_set("fraglimit", fraglimit_teams);
581  }
582  else
583  {
584  if(fraglimit_normal)
585  cvar_set("fraglimit", fraglimit_normal);
586  }
587 }
588 
589 Gametype MapInfo_Type_FromString(string gtype, bool dowarn)
590 {
591  string replacement = "";
592  switch (gtype)
593  {
594  case "nexball": replacement = "nb"; break;
595  case "freezetag": replacement = "ft"; break;
596  case "keepaway": replacement = "ka"; break;
597  case "invasion": replacement = "inv"; break;
598  case "assault": replacement = "as"; break;
599  case "race": replacement = "rc"; break;
600  }
601  if (replacement != "")
602  {
603  if (dowarn && WARN_COND)
604  LOG_WARNF("MapInfo_Type_FromString (probably %s): using deprecated name '%s'. Should use '%s'.", MapInfo_Map_bspname, gtype, replacement);
605  gtype = replacement;
606  }
607  FOREACH(Gametypes, it.mdl == gtype, return it);
608  return NULL;
609 }
610 
612 {
613  return t ? t.gametype_description : "";
614 }
615 
617 {
618  return t ? t.mdl : "";
619 }
620 
622 {
623  /* xgettext:no-c-format */
624  return t ? t.message : _("@!#%'n Tuba Throwing");
625 }
626 
627 void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse)
628 {
629  string t;
630  float o;
631  // tabs are invalid, treat them as "empty"
632  s = strreplace("\t", "", s);
633 
634  t = car(s); s = cdr(s);
635 
636  // limited support of "" and comments
637  // remove trailing and leading " of t
638  if(substring(t, 0, 1) == "\"")
639  {
640  if(substring(t, -1, 1) == "\"")
641  t = substring(t, 1, -2);
642  }
643 
644  // remove leading " of s
645  if(substring(s, 0, 1) == "\"")
646  {
647  s = substring(s, 1, -1);
648  }
649  // remove trailing " of s, and all that follows (cvar description)
650  o = strstrofs(s, "\"", 0);
651  if(o >= 0)
652  s = substring(s, 0, o);
653 
654  // remove // comments
655  o = strstrofs(s, "//", 0);
656  if(o >= 0)
657  s = substring(s, 0, o);
658 
659  // remove trailing spaces
660  while(substring(s, -1, 1) == " ")
661  s = substring(s, 0, -2);
662 
663  if(t == "#include")
664  {
665  if(recurse > 0)
666  {
667  float fh = fopen(s, FILE_READ);
668  if(fh < 0)
669  {
670  if(WARN_COND)
671  LOG_WARN("Map ", pFilename, " references not existing config file ", s);
672  }
673  else
674  {
675  while((s = fgets(fh)))
676  {
677  s = strreplace("\t", "", s); // treat tabs as "empty", perform here first to ensure coments are detected
678  // catch different sorts of comments
679  if(s == "") // empty lines
680  continue;
681  if(substring(s, 0, 1) == "#") // UNIX style
682  continue;
683  if(substring(s, 0, 2) == "//") // C++ style
684  continue;
685  if(substring(s, 0, 1) == "_") // q3map style
686  continue;
687 
688  if(substring(s, 0, 4) == "set ")
689  s = substring(s, 4, -1);
690  if(substring(s, 0, 5) == "seta ")
691  s = substring(s, 5, -1);
692 
693  _MapInfo_Parse_Settemp(pFilename, acl, type, s, recurse - 1);
694  }
695  fclose(fh);
696  }
697  }
698  else if(WARN_COND)
699  LOG_WARN("Map ", pFilename, " uses too many levels of inclusion");
700  }
701  else if(t == ""
702  || !cvar_value_issafe(t)
703  || !cvar_value_issafe(s)
705  {
706  if (WARN_COND)
707  LOG_WARN("Map ", pFilename, " contains a potentially harmful setting, ignored");
708  }
709  else if(matchacl(acl, t) <= 0)
710  {
711  if (WARN_COND)
712  LOG_WARN("Map ", pFilename, " contains a denied setting, ignored");
713  }
714  else
715  {
716  if(type == 0) // server set
717  {
718  LOG_TRACE("Applying temporary setting ", t, " := ", s);
719  #if 0
720  if(cvar("g_campaign"))
721  cvar_set(t, s); // this is a wrapper and is always temporary anyway; no need to backup old values then
722  else
723  #endif
724  cvar_settemp(t, s);
725  }
726  else
727  {
728  LOG_TRACE("Applying temporary client setting ", t, " := ", s);
730  MapInfo_Map_clientstuff, "cl_cmd settemp \"", t, "\" \"", s, "\"\n"
731  );
732  }
733  }
734 }
735 
736 float MapInfo_isRedundant(string fn, string t)
737 {
738  // normalize file name
739  fn = strreplace("_", "", fn);
740  fn = strreplace("-", "", fn);
741 
742  // normalize visible title
743  t = strreplace(":", "", t);
744  t = strreplace(" ", "", t);
745  t = strreplace("_", "", t);
746  t = strreplace("-", "", t);
747  t = strreplace("'", "", t);
748  t = strdecolorize(t);
749 
750  // we allow the visible title to have punctuation the file name does
751  // not, but not vice versa
752  if(!strcasecmp(fn, t))
753  return true;
754 
755  return false;
756 }
757 
758 // load info about a map by name into the MapInfo_Map_* globals
759 float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gametype pGametypeToSet)
760 {
761  string fn;
762  string s, t;
763  float fh;
764  int f, i;
765  float r, n, p;
766  string acl;
767 
769 
770  if(strstrofs(pFilename, "/", 0) >= 0)
771  {
772  LOG_WARN("Invalid character in map name, ignored");
773  return 0;
774  }
775 
776  if(pGametypeToSet == NULL)
777  if(MapInfo_Cache_Retrieve(pFilename))
778  return 1;
779 
780  r = 1;
781 
782  MapInfo_Map_bspname = pFilename;
783 
784  // default all generic fields so they have "good" values in case something fails
785  fn = strcat("maps/", pFilename, ".mapinfo");
786  fh = fopen(fn, FILE_READ);
787  if(fh < 0)
788  {
789  fn = strcat("maps/autogenerated/", pFilename, ".mapinfo");
790  fh = fopen(fn, FILE_READ);
791  if(fh < 0)
792  {
793  if(!pAllowGenerate)
794  return 0;
796  r = _MapInfo_Generate(pFilename);
797  if(!r)
798  return 0;
799  fh = fopen(fn, FILE_WRITE);
800  fputs(fh, strcat("title ", MapInfo_Map_title, "\n"));
801  fputs(fh, strcat("description ", MapInfo_Map_description, "\n"));
802  fputs(fh, strcat("author ", MapInfo_Map_author, "\n"));
804  {
805  if(
807  ||
809  )
811  else
812  fputs(fh, strcat("cdtrack ", _MapInfo_Map_worldspawn_music, "\n"));
813  }
814  else
815  {
816  n = tokenize_console(cvar_string("g_cdtracks_remaplist"));
817  s = strcat(" ", cvar_string("g_cdtracks_dontusebydefault"), " ");
818  for (;;)
819  {
820  i = floor(random() * n);
821  if(strstrofs(s, strcat(" ", argv(i), " "), 0) < 0)
822  break;
823  }
824  fputs(fh, strcat("cdtrack ", ftos(i + 1), "\n"));
825  }
827  fputs(fh, "has weapons\n");
828  else
829  fputs(fh, "// uncomment this if you added weapon pickups: has weapons\n");
831  fputs(fh, "has turrets\n");
832  else
833  fputs(fh, "// uncomment this if you added turrets: has turrets\n");
835  fputs(fh, "has vehicles\n");
836  else
837  fputs(fh, "// uncomment this if you added vehicles: has vehicles\n");
839  fputs(fh, "frustrating\n");
840 
841  FOREACH(Gametypes, MapInfo_Map_supportedGametypes & it.m_flags, {
842  fputs(fh, sprintf("gametype %s // defaults: %s\n", MapInfo_Type_ToString(it), _MapInfo_GetDefaultEx(it)));
843  });
844 
845  fputs(fh, "// optional: fog density red green blue alpha mindist maxdist\n");
846  fputs(fh, "// optional: settemp_for_type (all|gametypename) cvarname value\n");
847  fputs(fh, "// optional: clientsettemp_for_type (all|gametypename) cvarname value\n");
848  fputs(fh, "// optional: size mins_x mins_y mins_z maxs_x maxs_y maxs_z\n");
849  fputs(fh, "// optional: hidden\n");
850 
851  fclose(fh);
852  r = 2;
853  // return r;
854  fh = fopen(fn, FILE_READ);
855  if(fh < 0)
856  error("... but I just wrote it!");
857  }
858 
859  if(WARN_COND)
860  LOG_WARN("autogenerated mapinfo file ", fn, " has been loaded; please edit that file and move it to maps/", pFilename, ".mapinfo");
861  }
862 
864  for (;;)
865  {
866  if (!((s = fgets(fh))))
867  break;
868 
869  // catch different sorts of comments
870  if(s == "") // empty lines
871  continue;
872  if(substring(s, 0, 1) == "#") // UNIX style
873  continue;
874  if(substring(s, 0, 2) == "//") // C++ style
875  continue;
876  if(substring(s, 0, 1) == "_") // q3map style
877  continue;
878 
879  p = strstrofs(s, "//", 0);
880  if(p >= 0)
881  s = substring(s, 0, p);
882 
883  t = car(s); s = cdr(s);
884  if(t == "title")
885  MapInfo_Map_title = s;
886  else if(t == "description")
888  else if(t == "author")
889  MapInfo_Map_author = s;
890  else if(t == "has")
891  {
892  t = car(s); // s = cdr(s);
894  else if(t == "turrets") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_TURRETS;
895  else if(t == "vehicles") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_VEHICLES;
896  else if(t == "monsters") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_MONSTERS;
897  else if(t == "new_toys") MapInfo_Map_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
898  else if(WARN_COND)
899  LOG_WARN("Map ", pFilename, " supports unknown feature ", t, ", ignored");
900  }
901  else if(t == "hidden")
902  {
904  }
905  else if(t == "forbidden")
906  {
908  }
909  else if(t == "frustrating")
910  {
912  }
913  else if(t == "noautomaplist")
914  {
916  }
917  else if(t == "gameversion_min")
918  {
919  if (cvar("gameversion") < stof(s))
921  }
922  else if(t == "type")
923  {
924  t = car(s); s = cdr(s);
925  Gametype f = MapInfo_Type_FromString(t, true);
926  //if(WARN_COND)
927  //LOG_WARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.");
928  if(f)
929  _MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, true);
930  else if(WARN_COND)
931  LOG_DEBUG("Map ", pFilename, " supports unknown game type ", t, ", ignored");
932  }
933  else if(t == "gametype")
934  {
935  t = car(s); s = cdr(s);
936  Gametype f = MapInfo_Type_FromString(t, true);
937  if(f)
938  _MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
939  else if(WARN_COND)
940  LOG_DEBUG("Map ", pFilename, " supports unknown game type ", t, ", ignored");
941  }
942  else if(t == "size")
943  {
944  float a, b, c, d, e;
945  t = car(s); s = cdr(s); a = stof(t);
946  t = car(s); s = cdr(s); b = stof(t);
947  t = car(s); s = cdr(s); c = stof(t);
948  t = car(s); s = cdr(s); d = stof(t);
949  t = car(s); s = cdr(s); e = stof(t);
950  if(s == "")
951  {
952  if(WARN_COND)
953  LOG_WARN("Map ", pFilename, " contains an incorrect size line (not enough params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z");
954  }
955  else
956  {
957  t = car(s); s = cdr(s); f = stof(t);
958  if(s != "")
959  {
960  if(WARN_COND)
961  LOG_WARN("Map ", pFilename, " contains an incorrect size line (too many params), syntax: size mins_x mins_y mins_z maxs_x maxs_y maxs_z");
962  }
963  else
964  {
965  if(a >= d || b >= e || c >= f)
966  {
967  if(WARN_COND)
968  LOG_WARN("Map ", pFilename, " contains an incorrect size line, mins have to be < maxs");
969  }
970  else
971  {
972  MapInfo_Map_mins.x = a;
973  MapInfo_Map_mins.y = b;
974  MapInfo_Map_mins.z = c;
975  MapInfo_Map_maxs.x = d;
976  MapInfo_Map_maxs.y = e;
977  MapInfo_Map_maxs.z = f;
978  }
979  }
980  }
981  }
982  else if(t == "settemp_for_type")
983  {
984  t = car(s); s = cdr(s);
985  bool all = t == "all";
986  Gametype f = NULL;
987  if(all || (f = MapInfo_Type_FromString(t, true)))
988  {
989  if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
990  {
991  _MapInfo_Parse_Settemp(pFilename, acl, 0, s, 1);
992  }
993  }
994  else
995  {
996  LOG_DEBUG("Map ", pFilename, " has a setting for unknown game type ", t, ", ignored");
997  }
998  }
999  else if(t == "clientsettemp_for_type")
1000  {
1001  t = car(s); s = cdr(s);
1002  bool all = t == "all";
1003  Gametype f = NULL;
1004  if(all || (f = MapInfo_Type_FromString(t, true)))
1005  {
1006  if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
1007  {
1008  _MapInfo_Parse_Settemp(pFilename, acl, 1, s, 1);
1009  }
1010  }
1011  else
1012  {
1013  LOG_DEBUG("Map ", pFilename, " has a client setting for unknown game type ", t, ", ignored");
1014  }
1015  }
1016  else if(t == "fog")
1017  {
1018  if (!cvar_value_issafe(s))
1019  {
1020  if(WARN_COND)
1021  LOG_WARN("Map ", pFilename, " contains a potentially harmful fog setting, ignored");
1022  }
1023  else
1024  MapInfo_Map_fog = s;
1025  }
1026  else if(t == "cdtrack")
1027  {
1028  t = car(s); s = cdr(s);
1029  // We do this only if pGametypeToSet even though this
1030  // content is theoretically game type independent,
1031  // because MapInfo_Map_clientstuff contains otherwise
1032  // game type dependent stuff. That way this value stays
1033  // empty when not setting a game type to not set any
1034  // false expectations.
1035  if(pGametypeToSet)
1036  {
1037  if (!cvar_value_issafe(t))
1038  {
1039  if(WARN_COND)
1040  LOG_WARN("Map ", pFilename, " contains a potentially harmful cdtrack, ignored");
1041  }
1042  else
1044  MapInfo_Map_clientstuff, "cd loop \"", t, "\"\n"
1045  );
1046  }
1047  }
1048  else if(WARN_COND)
1049  LOG_WARN("Map ", pFilename, " provides unknown info item ", t, ", ignored");
1050  }
1051  fclose(fh);
1052 
1053  if(MapInfo_Map_title == "<TITLE>")
1057  else
1059 
1062  return r;
1063  if (WARN_COND)
1064  LOG_WARN("Map ", pFilename, " supports no game types, ignored");
1065  return 0;
1066 }
1067 int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
1068 {
1069  int r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
1070 
1071  FOREACH(Gametypes, it.m_isForcedSupported(it), _MapInfo_Map_ApplyGametypeEx("", pGametypeToSet, it));
1072 
1073  if(pGametypeToSet)
1074  {
1075  if(!(MapInfo_Map_supportedGametypes & pGametypeToSet.m_flags))
1076  {
1077  error("Can't select the requested game type. This should never happen as the caller should prevent it!\n");
1078  //_MapInfo_Map_ApplyGametypeEx("", pGametypeToSet, MAPINFO_TYPE_DEATHMATCH);
1079  //return;
1080  }
1081  }
1082 
1083  return r;
1084 }
1085 
1086 float MapInfo_FindName(string s)
1087 {
1088  // if there is exactly one map of prefix s, return it
1089  // if not, return the null string
1090  // note that DP sorts glob results... so I can use a binary search
1091  float l, r, m, cmp;
1092  l = 0;
1093  r = MapInfo_count;
1094  // invariants: r is behind s, l-1 is equal or before
1095  while(l != r)
1096  {
1097  m = floor((l + r) / 2);
1100  if(cmp == 0)
1101  return m; // found and good
1102  if(cmp < 0)
1103  l = m + 1; // l-1 is before s
1104  else
1105  r = m; // behind s
1106  }
1109  // r == l, so: l is behind s, l-1 is before
1110  // SO: if there is any, l is the one with the right prefix
1111  // and l+1 may be one too
1112  if(l == MapInfo_count)
1113  {
1116  return -1; // no MapInfo_FindName_match, behind last item
1117  }
1119  {
1122  return -1; // wrong prefix
1123  }
1124  if(l == MapInfo_count - 1)
1125  return l; // last one, nothing can follow => unique
1127  {
1129  return -1; // ambigous MapInfo_FindName_match
1130  }
1131  return l;
1132 }
1133 
1134 string MapInfo_FixName(string s)
1135 {
1136  MapInfo_FindName(s);
1137  return MapInfo_FindName_match;
1138 }
1139 
1141 {
1142  int req = 0;
1143  // TODO: find a better way to check if weapons are required on the map
1144  if(!(cvar("g_instagib") || cvar("g_overkill") || cvar("g_nix") || cvar("g_weaponarena") || !cvar("g_pickup_items") || !cvar("g_melee_only")
1145  || cvar("g_race") || cvar("g_cts") || cvar("g_nexball") || cvar("g_ca") || cvar("g_freezetag") || cvar("g_lms")))
1146  req |= MAPINFO_FEATURE_WEAPONS;
1147  return req;
1148 }
1149 
1151 {
1152  Gametype prev = MapInfo_Type_FromString(cvar_string("gamecfg"), false);
1153  FOREACH(Gametypes, cvar(it.netname) && it != prev, return it);
1154  return prev ? prev : MAPINFO_TYPE_DEATHMATCH;
1155 }
1156 
1157 float _MapInfo_CheckMap(string s, bool gametype_only) // returns 0 if the map can't be played with the current settings, 1 otherwise
1158 {
1159  if(!MapInfo_Get_ByName(s, 1, NULL))
1160  return 0;
1162  return 0;
1163  if (gametype_only)
1164  return 1;
1166  return 0;
1167  return 1;
1168 }
1169 
1170 float MapInfo_CheckMap(string s) // returns 0 if the map can't be played with the current settings, 1 otherwise
1171 {
1172  float r;
1173  r = _MapInfo_CheckMap(s, false);
1175  return r;
1176 }
1177 
1179 {
1180  FOREACH(Gametypes, true, cvar_set(it.netname, (it == t) ? "1" : "0"));
1181 }
1182 
1183 void MapInfo_LoadMap(string s, float reinit)
1184 {
1186  // we shouldn't need this, as LoadMapSettings already fixes the gametype
1187  //if(!MapInfo_CheckMap(s))
1188  //{
1189  // print("EMERGENCY: can't play the selected map in the given game mode. Falling back to DM.\n");
1190  // MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH.m_flags);
1191  //}
1192 
1193  LOG_INFO("Switching to map ", s);
1194 
1196  if(reinit)
1197  localcmd(strcat("\nmap ", s, "\n"));
1198  else
1199  localcmd(strcat("\nchangelevel ", s, "\n"));
1200 }
1201 
1202 string MapInfo_ListAllowedMaps(Gametype type, float pRequiredFlags, float pForbiddenFlags)
1203 {
1204  string out;
1205 
1206  // to make absolutely sure:
1208  MapInfo_FilterGametype(type, MapInfo_CurrentFeatures(), pRequiredFlags, pForbiddenFlags, 0);
1209 
1210  out = "";
1211  for(float i = 0; i < MapInfo_count; ++i)
1212  out = strcat(out, " ", _MapInfo_GlobItem(MapInfo_FilterList_Lookup(i)));
1213  return substring(out, 1, strlen(out) - 1);
1214 }
1215 
1216 string MapInfo_ListAllAllowedMaps(float pRequiredFlags, float pForbiddenFlags)
1217 {
1218  string out;
1219 
1220  // to make absolutely sure:
1222  _MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, pRequiredFlags, pForbiddenFlags, 0);
1223 
1224  out = "";
1225  for(float i = 0; i < MapInfo_count; ++i)
1226  out = strcat(out, " ", _MapInfo_GlobItem(MapInfo_FilterList_Lookup(i)));
1227 
1228  MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), pRequiredFlags, pForbiddenFlags, 0);
1229 
1230  return substring(out, 1, strlen(out) - 1);
1231 }
1232 
1234 {
1236  cvar_set("gamecfg", t.mdl);
1238 }
1239 
1240 void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
1241 {
1244 
1245  if(!_MapInfo_CheckMap(s, true)) // with underscore, it keeps temps
1246  {
1247  if(cvar("g_mapinfo_allow_unsupported_modes_and_let_stuff_break"))
1248  {
1249  LOG_SEVERE("can't play the selected map in the given game mode. Working with only the override settings.");
1250  _MapInfo_Map_ApplyGametypeEx("", t, t);
1251  return; // do not call Get_ByName!
1252  }
1253 
1255  {
1257  FOREACH(Gametypes, it.m_priority == 2,
1258  {
1259  MapInfo_Map_supportedGametypes |= it.m_flags;
1260  RandomSelection_AddEnt(it, 1, 1);
1261  });
1264  LOG_SEVEREF("Mapinfo system is not functional at all. Falling back to a preferred mode (%s).", t.mdl);
1266  _MapInfo_Map_ApplyGametypeEx("", t, t);
1267  return; // do not call Get_ByName!
1268  }
1269 
1270 #if 0
1271  // find the lowest bit in the supported gametypes
1272  // unnecessary now that we select one at random
1273  int _t = 1;
1274  while(!(MapInfo_Map_supportedGametypes & 1))
1275  {
1276  _t <<= 1;
1278  }
1279 #endif
1281  Gametype t_prev = t;
1282  FOREACH(Gametypes, MapInfo_Map_supportedGametypes & it.m_flags,
1283  {
1284  RandomSelection_AddEnt(it, 1, it.m_priority);
1285  });
1288 
1289  // t is now a supported mode!
1290  LOG_WARNF("can't play the selected map in the given game mode (%s). Falling back to a supported mode (%s).", t_prev.mdl, t.mdl);
1292  }
1293  if(!_MapInfo_CheckMap(s, false)) { // with underscore, it keeps temps
1294  LOG_WARNF("the selected map lacks features required by current settings; playing anyway.");
1295  }
1296  MapInfo_Get_ByName(s, 1, t);
1297 }
1298 
1300 {
1309 }
1310 
1312 {
1316  if(_MapInfo_globopen)
1317  {
1319  _MapInfo_globhandle = -1;
1320  _MapInfo_globopen = false;
1321  }
1322 }
1323 
1325 {
1326  int f = MAPINFO_FLAG_FORBIDDEN;
1327 
1328 #ifdef GAMEQC
1329  if (!cvar("g_maplist_allow_hidden"))
1330 #endif
1331  f |= MAPINFO_FLAG_HIDDEN;
1332 
1333  if (!cvar("g_maplist_allow_frustrating"))
1335 
1336  return f;
1337 }
1338 
1340 {
1341  int f = 0;
1342 
1343  if(cvar("g_maplist_allow_frustrating") > 1)
1345 
1346  return f;
1347 }
string MapInfo_Type_ToString(Gametype t)
Definition: mapinfo.qc:616
#define WARN_COND
Definition: mapinfo.qc:15
int MapInfo_RequiredFlags()
Definition: mapinfo.qc:1339
ERASEABLE int db_create()
Definition: map.qh:25
ERASEABLE void db_put(int db, string key, string value)
Definition: map.qh:101
#define LOG_WARN(...)
Definition: log.qh:66
string string_null
Definition: nil.qh:9
float _MapInfo_CheckMap(string s, bool gametype_only)
Definition: mapinfo.qc:1157
float MapInfo_Cache_Retrieve(string map)
Definition: mapinfo.qc:77
float _MapInfo_globopen
Definition: mapinfo.qc:103
float MapInfo_FilterList_Lookup(float i)
Definition: mapinfo.qc:137
void _MapInfo_Map_Reset()
Definition: mapinfo.qc:412
void MapInfo_LoadMapSettings(string s)
Definition: mapinfo.qc:1240
string MapInfo_Map_clientstuff
Definition: mapinfo.qh:11
float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gametype pGametypeToSet)
Definition: mapinfo.qc:759
vector MapInfo_Map_maxs
Definition: mapinfo.qh:17
float _MapInfo_GetTeamPlayBool(Gametype t)
Definition: mapinfo.qc:507
int MapInfo_Map_supportedFeatures
Definition: mapinfo.qh:14
float cvar_settemp(string tmp_cvar, string tmp_value)
Definition: util.qc:696
int _MapInfo_Cache_Active
Definition: mapinfo.qc:20
ERASEABLE void RandomSelection_Init()
Definition: random.qc:4
int MAPINFO_TYPE_ALL
Definition: mapinfo.qh:26
float MapInfo_progress
Definition: mapinfo.qh:151
entity() spawn
prev
Definition: all.qh:66
const int MAPINFO_FEATURE_WEAPONS
Definition: mapinfo.qh:134
Gametype MapInfo_LoadedGametype
Definition: mapinfo.qh:193
void MapInfo_LoadMapSettings_SaveGameType(Gametype t)
Definition: mapinfo.qc:1233
ERASEABLE string cdr(string s)
returns all but first word
Definition: string.qh:249
string MapInfo_ListAllAllowedMaps(float pRequiredFlags, float pForbiddenFlags)
Definition: mapinfo.qc:1216
string MapInfo_Type_ToText(Gametype t)
Definition: mapinfo.qc:621
ERASEABLE void db_close(int db)
Definition: map.qh:84
const float FILE_READ
Definition: csprogsdefs.qc:231
ERASEABLE void heapsort(int n, swapfunc_t swap, comparefunc_t cmp, entity pass)
Definition: sort.qh:9
bool MapInfo_Get_ByID(int i)
Definition: mapinfo.qc:256
int MapInfo_ForbiddenFlags()
Definition: mapinfo.qc:1324
int m_flags
Definition: mapinfo.qh:27
ERASEABLE string car(string s)
returns first word
Definition: string.qh:240
string MapInfo_Map_description
Definition: mapinfo.qh:9
string _MapInfo_GlobItem(float i)
Definition: mapinfo.qc:106
int _MapInfo_Cache_DB_NameToIndex
Definition: mapinfo.qc:21
float matchacl(string acl, string str)
Definition: util.qc:1203
int MapInfo_Map_flags
Definition: mapinfo.qh:15
float _MapInfo_globhandle
Definition: mapinfo.qc:105
string MapInfo_FindName_match
Definition: mapinfo.qh:168
string MapInfo_Map_author
Definition: mapinfo.qh:10
#define LOG_WARNF(...)
Definition: log.qh:67
#define LOG_SEVEREF(...)
Definition: log.qh:63
float _MapInfo_Generate(string pFilename)
Definition: mapinfo.qc:263
#define buf_create
Definition: dpextensions.qh:63
int MapInfo_Map_supportedGametypes
Definition: mapinfo.qh:13
void MapInfo_Cache_Destroy()
Definition: mapinfo.qc:24
float MapInfo_count
Definition: mapinfo.qh:144
Gametype MapInfo_Type_FromString(string gtype, bool dowarn)
Definition: mapinfo.qc:589
Gametype MapInfo_CurrentGametype()
Definition: mapinfo.qc:1150
void MapInfo_Filter_Free()
Definition: mapinfo.qc:221
void MapInfo_Cache_Create()
Definition: mapinfo.qc:34
bool frags
does this gametype use a point limit?
Definition: mapinfo.qh:42
int MapInfo_CurrentFeatures()
Definition: mapinfo.qc:1140
const int MAPINFO_FEATURE_VEHICLES
Definition: mapinfo.qh:135
string MapInfo_ListAllowedMaps(Gametype type, float pRequiredFlags, float pForbiddenFlags)
Definition: mapinfo.qc:1202
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"))
entity RandomSelection_chosen_ent
Definition: random.qh:5
void _MapInfo_FilterList_swap(float i, float j, entity pass)
Definition: mapinfo.qc:142
vector MapInfo_Map_mins
Definition: mapinfo.qh:16
int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
Definition: mapinfo.qc:1067
#define NULL
Definition: post.qh:17
#define startsWith(haystack, needle)
Definition: string.qh:217
void _MapInfo_Map_ApplyGametype(string s, Gametype pWantedType, Gametype pThisType, int load_default)
Definition: mapinfo.qc:432
#define LOG_INFO(...)
Definition: log.qh:70
ERASEABLE bool startsWithNocase(string haystack, string needle)
Definition: string.qh:220
float _MapInfo_globcount
Definition: mapinfo.qc:104
string m_legacydefaults
DO NOT USE, this is compatibility for legacy maps!
Definition: mapinfo.qh:60
bool autocvar_g_mapinfo_ignore_warnings
Definition: mapinfo.qc:14
#define strstrofs
Definition: dpextensions.qh:42
const int MAPINFO_FLAG_FORBIDDEN
Definition: mapinfo.qh:140
ERASEABLE string db_get(int db, string key)
Definition: map.qh:91
bool team
does this gametype support teamplay?
Definition: mapinfo.qh:40
float MapInfo_CheckMap(string s)
Definition: mapinfo.qc:1170
void MapInfo_ClearTemps()
Definition: mapinfo.qc:1299
int _MapInfo_Cache_Buf_IndexToMapData
Definition: mapinfo.qc:22
float _MapInfo_filtered_allocated
Definition: mapinfo.qc:136
string MapInfo_Map_title
Definition: mapinfo.qh:7
float MapInfo_isRedundant(string fn, string t)
Definition: mapinfo.qc:736
vector(float skel, float bonenum) _skel_get_boneabs_hidden
float MapInfo_FindName_firstResult
Definition: mapinfo.qh:169
float MapInfo_FindName(string s)
Definition: mapinfo.qc:1086
#define tokenize_console
Definition: dpextensions.qh:24
const float FILE_WRITE
Definition: csprogsdefs.qc:233
string MapInfo_Type_Description(Gametype t)
Definition: mapinfo.qc:611
void MapInfo_Cache_Store()
Definition: mapinfo.qc:50
ERASEABLE bool cvar_value_issafe(string s)
Definition: cvar.qh:11
vector v
Definition: ent_cs.qc:116
float _MapInfo_filtered
Definition: mapinfo.qc:135
#define MAPINFO_SETTEMP_ACL_SYSTEM
Definition: mapinfo.qh:206
void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThisType)
Definition: mapinfo.qc:512
string MapInfo_Map_bspname
Definition: mapinfo.qh:6
string MapInfo_Map_fog
Definition: mapinfo.qh:12
#define LOG_TRACE(...)
Definition: log.qh:81
void MapInfo_FilterString(string sf)
Definition: mapinfo.qc:194
const int MAPINFO_FLAG_HIDDEN
Definition: mapinfo.qh:139
const int MAPINFO_FLAG_FRUSTRATING
Definition: mapinfo.qh:141
float _MapInfo_FilterList_cmp(float i, float j, entity pass)
Definition: mapinfo.qc:150
#define LOG_SEVERE(...)
Definition: log.qh:62
string MapInfo_FixName(string s)
Definition: mapinfo.qc:1134
int cvar_settemp_restore()
Definition: util.qc:736
const int MAPINFO_FEATURE_TURRETS
Definition: mapinfo.qh:136
float _MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition: mapinfo.qc:162
#define MAPINFO_SETTEMP_ACL_USER
Definition: mapinfo.qh:205
void MapInfo_LoadMap(string s, float reinit)
Definition: mapinfo.qc:1183
float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
Definition: mapinfo.qc:158
#define strcasecmp
Definition: dpextensions.qh:57
string unquote(string s)
Definition: mapinfo.qc:236
string _MapInfo_GetDefaultEx(Gametype t)
Definition: mapinfo.qc:502
#define pass(name, colormin, colormax)
void MapInfo_Shutdown()
Definition: mapinfo.qc:1311
void MapInfo_Enumerate()
Definition: mapinfo.qc:115
const int MAPINFO_FEATURE_MONSTERS
Definition: mapinfo.qh:137
string MapInfo_BSPName_ByID(float i)
Definition: mapinfo.qc:231
void MapInfo_SwitchGameType(Gametype t)
Definition: mapinfo.qc:1178
#define FOREACH(list, cond, body)
Definition: iter.qh:19
const int MAPINFO_FLAG_NOAUTOMAPLIST
Definition: mapinfo.qh:142
string _MapInfo_GetDefault(Gametype t)
Definition: mapinfo.qc:427
void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse)
Definition: mapinfo.qc:627
void MapInfo_Cache_Invalidate()
Definition: mapinfo.qc:42
#define true
Definition: csprogsdefs.qh:5
string _MapInfo_Map_worldspawn_music
Definition: mapinfo.qc:261
#define LOG_DEBUG(...)
Definition: log.qh:85
string MapInfo_Map_titlestring
Definition: mapinfo.qh:8