]> git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/commitdiff
Merge branch 'master' into Mario/q3compat_sanity
authorMario <mario.mario@y7mail.com>
Sun, 1 Nov 2020 06:01:28 +0000 (16:01 +1000)
committerMario <mario.mario@y7mail.com>
Sun, 1 Nov 2020 06:01:28 +0000 (16:01 +1000)
1  2 
qcsrc/client/mapvoting.qc
qcsrc/common/mapinfo.qc
qcsrc/common/mapinfo.qh
qcsrc/server/world.qc
qcsrc/server/world.qh

index e517e76dee4300bc6ec16589efabf9e59219a93e,5be42cda965546119a7f2ef45425de9889cca315..96b7ecb761cbcc79db85bca3612d8394a71f3690
@@@ -1,6 -1,5 +1,5 @@@
  #include "mapvoting.qh"
  
- #include <client/autocvars.qh>
  #include <client/draw.qh>
  #include <client/hud/_mod.qh>
  #include <client/hud/panel/scoreboard.qh>
@@@ -648,7 -647,7 +647,7 @@@ void GameTypeVote_ReadOption(int i
        }
        else
        {
 -              Gametype type = MapInfo_Type_FromString(gt, false);
 +              Gametype type = MapInfo_Type_FromString(gt, false, false);
                mv_pk3[i] = strzone(MapInfo_Type_ToText(type));
                mv_desc[i] = MapInfo_Type_Description(type);
        }
diff --combined qcsrc/common/mapinfo.qc
index 384b3a5558b21ec3e3a5cac7a3037903c8a2611e,3ef0b74b7eee71f936a4fbaed611eae65c0aceef..4f23862d2e8979a48596f257f8fbc27f4c8e935b
@@@ -8,9 -8,6 +8,9 @@@
        #include <common/monsters/_mod.qh>
  #endif
  
 +bool autocvar_g_mapinfo_arena_compat = true;
 +bool autocvar_g_mapinfo_arena_generate = false;
 +
  #ifdef MENUQC
  #define WARN_COND false
  #else
@@@ -256,11 -253,9 +256,9 @@@ string unquote(string s
        return "";
  }
  
float MapInfo_Get_ByID(float i)
bool MapInfo_Get_ByID(int i)
  {
-       if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, NULL))
-               return 1;
-       return 0;
+       return MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, NULL) ? true : false;
  }
  
  string _MapInfo_Map_worldspawn_music;
@@@ -301,25 -296,6 +299,25 @@@ float _MapInfo_Generate(string pFilenam
        mapMins = '0 0 0';
        mapMaxs = '0 0 0';
  
 +      if(autocvar_g_mapinfo_arena_generate)
 +      {
 +              // try for .arena or .defi files, as they may have more accurate information
 +              bool isdefi = false;
 +              string arena_fn = _MapInfo_FindArenaFile(pFilename, ".arena");
 +              int arena_fh = fopen(arena_fn, FILE_READ);
 +              if(arena_fh < 0)
 +              {
 +                      isdefi = true;
 +                      arena_fn = _MapInfo_FindArenaFile(pFilename, ".defi");
 +                      arena_fh = fopen(arena_fn, FILE_READ);
 +              }
 +              if(arena_fh >= 0)
 +              {
 +                      _MapInfo_ParseArena(arena_fn, arena_fh, pFilename, NULL, isdefi, true);
 +                      fclose(arena_fh);
 +              }
 +      }
 +
        for (;;)
        {
                if (!((s = fgets(fh))))
@@@ -610,10 -586,9 +608,10 @@@ void _MapInfo_Map_ApplyGametypeEx(strin
        }
  }
  
 -Gametype MapInfo_Type_FromString(string gtype, bool dowarn)
 +Gametype MapInfo_Type_FromString(string gtype, bool dowarn, bool is_q3compat)
  {
        string replacement = "";
 +      bool do_warn = true;
        switch (gtype)
        {
                case "nexball":   replacement = "nb"; break;
                case "invasion":  replacement = "inv"; break;
                case "assault":   replacement = "as"; break;
                case "race":      replacement = "rc"; break;
 +              // quake 3 compat
 +              case "ffa":       replacement = "dm"; do_warn = false; break;
 +              case "cctf":
 +              case "oneflag":   replacement = "ctf"; do_warn = false; break;
 +              case "tourney":   replacement = "duel"; do_warn = false; break;
 +              case "arena":     if(is_q3compat) { replacement = "ca"; do_warn = false; } break;
        }
        if (replacement != "")
        {
@@@ -782,193 -751,6 +780,193 @@@ float MapInfo_isRedundant(string fn, st
        return false;
  }
  
 +bool _MapInfo_ParseArena(string arena_filename, int fh, string pFilename, Gametype pGametypeToSet, bool isdefi, bool isgenerator)
 +{
 +      // NOTE: .arena files can hold more than 1 map's information!
 +      // to handle this, we're going to store gathered information in local variables and save it if we encounter the correct map name
 +      bool in_brackets = false; // testing a potential mapinfo section (within brackets)
 +      bool dosave = (arena_filename == strcat("scripts/", pFilename, ((isdefi) ? ".defi" : ".arena"))); // if the map is using the fallback, just accept the first found mapinfo (it's probably correct!)
 +      string stored_Map_description = "";
 +      string stored_Map_title = "";
 +      string stored_Map_author = "";
 +      int stored_supportedGametypes = 0;
 +      int stored_supportedFeatures = 0;
 +      int stored_flags = 0;
 +      string t, s;
 +      for (;;)
 +      {
 +              if (!((s = fgets(fh))))
 +                      break;
 +
 +              // catch different sorts of comments
 +              if(s == "")                    // empty lines
 +                      continue;
 +              if(substring(s, 0, 1) == "#")  // UNIX style
 +                      continue;
 +              if(substring(s, 0, 2) == "//") // C++ style
 +                      continue;
 +              if(substring(s, 0, 1) == "_")  // q3map style
 +                      continue;
 +              if(strstrofs(s, "{", 0) >= 0)
 +              {
 +                      if(in_brackets)
 +                              return false; // edge case? already in a bracketed section!
 +                      in_brackets = true;
 +                      continue;
 +              }
 +              else if(!in_brackets)
 +              {
 +                      // if we're not inside a bracket, don't process map info
 +                      continue;
 +              }
 +              if(strstrofs(s, "}", 0) >= 0)
 +              {
 +                      if(!in_brackets)
 +                              return false; // no starting bracket! let the mapinfo generation system handle it
 +                      in_brackets = false;
 +                      if(dosave)
 +                      {
 +                              MapInfo_Map_description = stored_Map_description;
 +                              if(stored_Map_title != "")
 +                                      MapInfo_Map_title = stored_Map_title;
 +                              MapInfo_Map_author = stored_Map_author;
 +                              if(isgenerator)
 +                                      MapInfo_Map_supportedGametypes = stored_supportedGametypes;
 +                              else
 +                              {
 +                                      FOREACH(Gametypes, it.m_flags & stored_supportedGametypes,
 +                                      {
 +                                              _MapInfo_Map_ApplyGametype ("", pGametypeToSet, it, true);
 +                                      });
 +                              }
 +                              MapInfo_Map_supportedFeatures = stored_supportedFeatures;
 +                              MapInfo_Map_flags = stored_flags;
 +                              return true; // no need to continue through the file, we have our map!
 +                      }
 +                      else
 +                      {
 +                              // discard any gathered locals, we're not using the correct map!
 +                              stored_Map_description = "";
 +                              stored_Map_title = "";
 +                              stored_Map_author = "";
 +                              stored_supportedGametypes = 0;
 +                              stored_supportedFeatures = 0;
 +                              stored_flags = 0;
 +                              continue;
 +                      }
 +              }
 +
 +              s = strreplace("\t", " ", s);
 +
 +              float p = strstrofs(s, "//", 0);
 +              if(p >= 0)
 +                      s = substring(s, 0, p);
 +
 +              // perform an initial trim to ensure the first argument is properly obtained
 +              //   remove leading spaces
 +              while(substring(s, 0, 1) == " ")
 +                      s = substring(s, 1, -1);
 +
 +              t = car(s); s = cdr(s);
 +              t = strtolower(t); // apparently some q3 maps use capitalized parameters
 +
 +              //   remove trailing spaces
 +              while(substring(t, -1, 1) == " ")
 +                      t = substring(t, 0, -2);
 +
 +              //   remove trailing spaces
 +              while(substring(s, -1, 1) == " ")
 +                      s = substring(s, 0, -2);
 +              //   remove leading spaces
 +              while(substring(s, 0, 1) == " ")
 +                      s = substring(s, 1, -1);
 +              // limited support of ""
 +              //   remove trailing and leading " of s
 +              if(substring(s, 0, 1) == "\"")
 +              {
 +                      if(substring(s, -1, 1) == "\"")
 +                              s = substring(s, 1, -2);
 +              }
 +              if(t == "longname")
 +                      stored_Map_title = s;
 +              else if(t == "author")
 +                      stored_Map_author = s;
 +              else if(t == "type")
 +              {
 +                      // if there is a valid gametype in this .arena file, include it in the menu
 +                      stored_supportedFeatures |= MAPINFO_FEATURE_WEAPONS;
 +                      // type in quake 3 holds all the supported gametypes, so we must loop through all of them
 +                      string types = strreplace("team", "tdm ft", s); // TODO: handle support here better to include more Xonotic teamplay modes
 +                      FOREACH_WORD(types, true,
 +                      {
 +                              Gametype f = MapInfo_Type_FromString(it, false, true);
 +                              if(f)
 +                                      stored_supportedGametypes |= f.m_flags;
 +                      });
 +              }
 +              else if(t == "style" && isdefi)
 +              {
 +                      // we have a defrag map on our hands, add CTS!
 +                      // TODO: styles
 +                      stored_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
 +              }
 +              else if(t == "map")
 +              {
 +                      if(strtolower(s) == strtolower(pFilename))
 +                              dosave = true; // yay, found our map!
 +              }
 +              else if(t == "quote")
 +                      stored_Map_description = s;
 +              // TODO: fraglimit
 +      }
 +
 +      // if the map wasn't found in the .arena, fall back to generated .mapinfo
 +      return false;
 +}
 +
 +#if defined(CSQC) || defined(MENUQC)
 +string(string filename) whichpack = #503;
 +#endif
 +string _MapInfo_FindArenaFile(string pFilename, string extension)
 +{
 +      string fallback = strcat("scripts/", pFilename, extension);
 +      if(!checkextension("DP_QC_FS_SEARCH_PACKFILE"))
 +              return fallback;
 +      string base_pack = whichpack(strcat("maps/", pFilename, ".bsp"));
 +      if(base_pack == "") // this map isn't packaged!
 +              return fallback;
 +
 +      int glob = search_packfile_begin(strcat("scripts/*", extension), true, true, base_pack);
 +      if(glob < 0)
 +              return fallback;
 +      int n = search_getsize(glob);
 +      for(int j = 0; j < n; ++j)
 +      {
 +              string file = search_getfilename(glob, j);
 +
 +              int fh = fopen(file, FILE_READ);
 +              if(fh < 0)
 +                      continue; // how?
 +              for(string s; (s = fgets(fh)); )
 +              {
 +                      int offset = strstrofs(s, "map", 0);
 +                      if(offset >= 0)
 +                      {
 +                              if(strstrofs(strtolower(s), strcat("\"", strtolower(pFilename), "\""), offset) >= 0) // quake 3 is case insensitive
 +                              {
 +                                      fclose(fh);
 +                                      search_end(glob);
 +                                      return file; // FOUND IT!
 +                              }
 +                      }
 +              }
 +              fclose(fh);
 +      }
 +
 +      search_end(glob);
 +      return fallback; // if we get here, a valid .arena file could not be found
 +}
 +
  // load info about a map by name into the MapInfo_Map_* globals
  float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gametype pGametypeToSet)
  {
        string s, t;
        float fh;
        int f, i;
 -      float r, n, p;
 +      float r, n;
        string acl;
  
        acl = MAPINFO_SETTEMP_ACL_USER;
        fh = fopen(fn, FILE_READ);
        if(fh < 0)
        {
 +              if(autocvar_g_mapinfo_arena_compat)
 +              {
 +                      // try for .arena or .defi files if no .mapinfo exists
 +                      bool isdefi = false;
 +                      fn = _MapInfo_FindArenaFile(pFilename, ".arena");
 +                      fh = fopen(fn, FILE_READ);
 +                      if(fh < 0)
 +                      {
 +                              isdefi = true;
 +                              fn = _MapInfo_FindArenaFile(pFilename, ".defi");
 +                              fh = fopen(fn, FILE_READ);
 +                      }
 +                      if(fh >= 0)
 +                      {
 +                              _MapInfo_Map_Reset();
 +                              if(_MapInfo_ParseArena(fn, fh, pFilename, pGametypeToSet, isdefi, false))
 +                                      goto mapinfo_handled; // skip generation
 +                      }
 +              }
 +
                fn = strcat("maps/autogenerated/", pFilename, ".mapinfo");
                fh = fopen(fn, FILE_READ);
                if(fh < 0)
                if(substring(s, 0, 1) == "_")  // q3map style
                        continue;
  
 -              p = strstrofs(s, "//", 0);
 +              float p = strstrofs(s, "//", 0);
                if(p >= 0)
                        s = substring(s, 0, p);
  
                else if(t == "type")
                {
                        t = car(s); s = cdr(s);
 -                      Gametype f = MapInfo_Type_FromString(t, true);
 +                      Gametype f = MapInfo_Type_FromString(t, true, false);
                        //if(WARN_COND)
                                //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'.");
                        if(f)
                else if(t == "gametype")
                {
                        t = car(s); s = cdr(s);
 -                      Gametype f = MapInfo_Type_FromString(t, true);
 +                      Gametype f = MapInfo_Type_FromString(t, true, false);
                        if(f)
                                _MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
                        else if(WARN_COND)
                        t = car(s); s = cdr(s);
                        bool all = t == "all";
                        Gametype f = NULL;
 -                      if(all || (f = MapInfo_Type_FromString(t, true)))
 +                      if(all || (f = MapInfo_Type_FromString(t, true, false)))
                        {
                                if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
                                {
                        t = car(s); s = cdr(s);
                        bool all = t == "all";
                        Gametype f = NULL;
 -                      if(all || (f = MapInfo_Type_FromString(t, true)))
 +                      if(all || (f = MapInfo_Type_FromString(t, true, false)))
                        {
                                if((all ? MAPINFO_TYPE_ALL : f.m_flags) & pGametypeToSet.m_flags)
                                {
                else if(WARN_COND)
                        LOG_WARN("Map ", pFilename, " provides unknown info item ", t, ", ignored");
        }
 +      LABEL(mapinfo_handled)
        fclose(fh);
  
        if(MapInfo_Map_title == "<TITLE>")
@@@ -1384,7 -1145,7 +1382,7 @@@ int MapInfo_CurrentFeatures(
  
  Gametype MapInfo_CurrentGametype()
  {
 -      Gametype prev = MapInfo_Type_FromString(cvar_string("gamecfg"), false);
 +      Gametype prev = MapInfo_Type_FromString(cvar_string("gamecfg"), false, false);
        FOREACH(Gametypes, cvar(it.netname) && it != prev, return it);
        return prev ? prev : MAPINFO_TYPE_DEATHMATCH;
  }
diff --combined qcsrc/common/mapinfo.qh
index b10f930d0c0b292df98714fb18e3c9888491e4a1,2d350b2fed3c1b26c46cab2e3c58bcb598ce1436..7b1bfc2ba3be1ff2c4594c6755d7a6c49d7c0d8e
@@@ -151,7 -151,7 +151,7 @@@ int MapInfo_ForbiddenFlags(); // retrie
  int MapInfo_RequiredFlags(); // retrieves current flags from cvars
  
  // load info about the i-th map into the MapInfo_Map_* globals
float MapInfo_Get_ByID(float i); // 1 on success, 0 on failure
bool MapInfo_Get_ByID(int i); // 1 on success, 0 on failure
  string MapInfo_BSPName_ByID(float i);
  
  // load info about a map by name into the MapInfo_Map_* globals
@@@ -175,7 -175,7 +175,7 @@@ string MapInfo_ListAllAllowedMaps(floa
  // gets a gametype from a string
  string _MapInfo_GetDefaultEx(Gametype t);
  float _MapInfo_GetTeamPlayBool(Gametype t);
 -Gametype MapInfo_Type_FromString(string t, bool dowarn);
 +Gametype MapInfo_Type_FromString(string t, bool dowarn, bool is_q3compat);
  string MapInfo_Type_Description(Gametype t);
  string MapInfo_Type_ToString(Gametype t);
  string MapInfo_Type_ToText(Gametype t);
@@@ -189,10 -189,6 +189,10 @@@ void MapInfo_Cache_Destroy(); // disabl
  void MapInfo_Cache_Create(); // enable caching
  void MapInfo_Cache_Invalidate(); // delete cache if any, but keep enabled
  
 +bool _MapInfo_ParseArena(string arena_filename, int fh, string pFilename, Gametype pGametypeToSet, bool isdefi, bool isgenerator);
 +
 +string _MapInfo_FindArenaFile(string pFilename, string extension);
 +
  void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse);
  
  void MapInfo_ClearTemps(); // call this when done with mapinfo for this frame
diff --combined qcsrc/server/world.qc
index 4ebab9f07e133c83abc56b12ee717a88e3ff8c23,5531d223f72c6b226af5bb20633e5ca911671208..32f4840c9b5c3e282ca308e4c58cad29f4804867
@@@ -37,6 -37,7 +37,7 @@@
  #include <server/hook.qh>
  #include <server/intermission.qh>
  #include <server/ipban.qh>
+ #include <server/items/items.qh>
  #include <server/main.qh>
  #include <server/mapvoting.qh>
  #include <server/mutators/_mod.qh>
@@@ -887,34 -888,12 +888,34 @@@ spawnfunc(worldspawn
        MapInfo_Enumerate();
        MapInfo_FilterGametype(MapInfo_CurrentGametype(), MapInfo_CurrentFeatures(), MapInfo_RequiredFlags(), MapInfo_ForbiddenFlags(), 1);
  
 -      if(fexists(strcat("scripts/", mapname, ".arena")))
 +      if(fexists(_MapInfo_FindArenaFile(mapname, ".arena")))
                cvar_settemp("sv_q3acompat_machineshotgunswap", "1");
  
 -      if(fexists(strcat("scripts/", mapname, ".defi")))
 +      if(fexists(_MapInfo_FindArenaFile(mapname, ".defi")))
                cvar_settemp("sv_q3defragcompat", "1");
  
 +      // quake 3 music support
 +      if(world.music || world.noise)
 +      {
 +              // prefer .music over .noise
 +              string chosen_music;
 +              string oldstuff;
 +              if(world.music)
 +                      chosen_music = world.music;
 +              else
 +                      chosen_music = world.noise;
 +              if(
 +                      substring(chosen_music, strlen(chosen_music) - 4, 4) == ".wav"
 +                      ||
 +                      substring(chosen_music, strlen(chosen_music) - 4, 4) == ".ogg"
 +              )
 +                      oldstuff = strcat(clientstuff, "cd loop \"", chosen_music, "\"\n");
 +              else
 +                      oldstuff = strcat(clientstuff, "cd loop \"", chosen_music, "\"\n");
 +
 +              strcpy(clientstuff, oldstuff);
 +      }
 +
        if(whichpack(strcat("maps/", mapname, ".cfg")) != "")
        {
                int fd = fopen(strcat("maps/", mapname, ".cfg"), FILE_READ);
diff --combined qcsrc/server/world.qh
index e351624701a7c6370b0dd6ed49c838b93e83b332,4141c99e29182a49daff6c1678b52dadad704c3d..018fea6b821a4f56537bbbfdcfa45ca45a627f7e
@@@ -2,6 -2,31 +2,31 @@@
  
  #include <common/weapons/_all.qh>
  
+ bool autocvar__sv_init;
+ bool autocvar_g_use_ammunition;
+ bool autocvar_g_jetpack;
+ bool autocvar_g_warmup_allguns;
+ bool autocvar_g_warmup_allow_timeout;
+ #define autocvar_g_weaponarena cvar_string("g_weaponarena")
+ string autocvar_quit_and_redirect;
+ float autocvar_quit_and_redirect_timer;
+ bool autocvar_quit_when_empty;
+ string autocvar_sessionid;
+ bool autocvar_sv_curl_serverpackages_auto;
+ bool autocvar_sv_db_saveasdump;
+ bool autocvar_sv_logscores_bots;
+ bool autocvar_sv_logscores_console;
+ bool autocvar_sv_logscores_file;
+ string autocvar_sv_logscores_filename;
+ float autocvar_sv_mapchange_delay;
+ float autocvar_timelimit_increment;
+ float autocvar_timelimit_decrement;
+ float autocvar_timelimit_min;
+ float autocvar_timelimit_max;
+ float autocvar_timelimit_overtime;
+ int autocvar_timelimit_overtimes;
+ float autocvar_timelimit_suddendeath;
  float checkrules_equality;
  float checkrules_suddendeathwarning;
  float checkrules_suddendeathend;
@@@ -116,10 -141,6 +141,10 @@@ float MoveToRandomMapLocation(entity e
  void CheckRules_World();
  float RedirectionThink();
  
 +// quake 3 music compatibility
 +.string music;
 +.string noise;
 +
  void readplayerstartcvars();
  
  void readlevelcvars();