]> de.git.xonotic.org Git - xonotic/xonotic-data.pk3dir.git/blobdiff - qcsrc/common/mapinfo.qc
Gametypes: propagate entity references, set limit to 24 due to use of bitflags
[xonotic/xonotic-data.pk3dir.git] / qcsrc / common / mapinfo.qc
index 2ec902f68556d121bdceb8122adbef84f4edc999..13e4185bc114553d2df9d6d3b497a2e0f94faca9 100644 (file)
@@ -150,7 +150,11 @@ float _MapInfo_FilterList_cmp(float i, float j, entity pass)
        return strcasecmp(a, b);
 }
 
-float MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
+float MapInfo_FilterGametype(Gametype pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
+{
+       return _MapInfo_FilterGametype(pGametype.m_flags, pFeatures, pFlagsRequired, pFlagsForbidden, pAbortOnGenerate);
+}
+float _MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, int pFlagsForbidden, bool pAbortOnGenerate)
 {
        float i, j;
        if (!_MapInfo_filtered_allocated)
@@ -161,7 +165,7 @@ float MapInfo_FilterGametype(int pGametype, int pFeatures, int pFlagsRequired, i
        MapInfo_count = 0;
        for(i = 0, j = -1; i < _MapInfo_globcount; ++i)
        {
-               if(MapInfo_Get_ByName(_MapInfo_GlobItem(i), 1, 0) == 2) // if we generated one... BAIL OUT and let the caller continue in the next frame.
+               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.
                        if(pAbortOnGenerate)
                        {
                                LOG_TRACE("Autogenerated a .mapinfo, doing the rest later.\n");
@@ -249,7 +253,7 @@ string unquote(string s)
 
 float MapInfo_Get_ByID(float i)
 {
-       if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, 0))
+       if(MapInfo_Get_ByName(MapInfo_BSPName_ByID(i), 0, NULL))
                return 1;
        return 0;
 }
@@ -346,19 +350,19 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
                        else if(k == "classname")
                        {
                                if(v == "dom_controlpoint")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DOMINATION.m_flags;
                                else if(v == "item_flag_team2")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF.m_flags;
                                else if(v == "team_CTF_blueflag")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTF.m_flags;
                                else if(v == "invasion_spawnpoint")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_INVASION;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_INVASION.m_flags;
                                else if(v == "target_assault_roundend")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ASSAULT.m_flags;
                                else if(v == "onslaught_generator")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_ONSLAUGHT.m_flags;
                                else if(substring(v, 0, 8) == "nexball_" || substring(v, 0, 4) == "ball")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_NEXBALL;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_NEXBALL.m_flags;
                                else if(v == "info_player_team1")
                                        ++spawnpoints;
                                else if(v == "info_player_team2")
@@ -368,9 +372,9 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
                                else if(v == "info_player_deathmatch")
                                        ++spawnpoints;
                                else if(v == "trigger_race_checkpoint")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RACE;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_RACE.m_flags;
                                else if(v == "target_startTimer")
-                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS;
+                                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
                                else if(v == "weapon_nex")
                                        { }
                                else if(v == "weapon_railgun")
@@ -395,7 +399,7 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
        }
        diameter = vlen(mapMaxs - mapMins);
 
-       twoBaseModes = MapInfo_Map_supportedGametypes & (MAPINFO_TYPE_CTF | MAPINFO_TYPE_ASSAULT | MAPINFO_TYPE_RACE | MAPINFO_TYPE_NEXBALL);
+       twoBaseModes = MapInfo_Map_supportedGametypes & (MAPINFO_TYPE_CTF.m_flags | MAPINFO_TYPE_ASSAULT.m_flags | MAPINFO_TYPE_RACE.m_flags | MAPINFO_TYPE_NEXBALL.m_flags);
        if(twoBaseModes && (MapInfo_Map_supportedGametypes == twoBaseModes))
        {
                // we have a CTF-only or Assault-only map. Don't add other modes then,
@@ -403,24 +407,24 @@ float _MapInfo_Generate(string pFilename) // 0: failure, 1: ok ent, 2: ok bsp
        }
        else
        {
-               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH;      // DM always works
-               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS;             // LMS always works
-               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY;                // Keepaway always works
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_DEATHMATCH.m_flags;      // DM always works
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_LMS.m_flags;             // LMS always works
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEEPAWAY.m_flags;                // Keepaway always works
 
                if(spawnpoints >= 8  && diameter > 4096) {
-                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH;
-                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_FREEZETAG;
-                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CA;
+                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_TEAM_DEATHMATCH.m_flags;
+                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_FREEZETAG.m_flags;
+                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CA.m_flags;
                }
                if(spawnpoints >= 12 && diameter > 5120)
-                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT;
+                       MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_KEYHUNT.m_flags;
        }
 
-       if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE)
+       if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_RACE.m_flags)
        if(!spawnplaces)
        {
-               MapInfo_Map_supportedGametypes &= ~MAPINFO_TYPE_RACE;
-               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS;
+               MapInfo_Map_supportedGametypes &= ~MAPINFO_TYPE_RACE.m_flags;
+               MapInfo_Map_supportedGametypes |= MAPINFO_TYPE_CTS.m_flags;
        }
 
        LOG_TRACE("-> diameter ",    ftos(diameter));
@@ -447,7 +451,7 @@ void _MapInfo_Map_Reset()
        MapInfo_Map_maxs = '0 0 0';
 }
 
-string _MapInfo_GetDefault(float t)
+string _MapInfo_GetDefault(Gametype t)
 {
        switch(t)
        {
@@ -472,11 +476,11 @@ string _MapInfo_GetDefault(float t)
        }
 }
 
-void _MapInfo_Map_ApplyGametype(string s, int pWantedType, int pThisType, int load_default)
+void _MapInfo_Map_ApplyGametype(string s, Gametype pWantedType, Gametype pThisType, int load_default)
 {
        string sa;
-       MapInfo_Map_supportedGametypes |= pThisType;
-       if(!(pThisType & pWantedType))
+       MapInfo_Map_supportedGametypes |= pThisType.m_flags;
+       if(!(pThisType.m_flags & pWantedType.m_flags))
                return;
 
        if(load_default)
@@ -595,22 +599,20 @@ void _MapInfo_Map_ApplyGametype(string s, int pWantedType, int pThisType, int lo
        }
 }
 
-string _MapInfo_GetDefaultEx(float t)
+string _MapInfo_GetDefaultEx(Gametype t)
 {
-       FOREACH(Gametypes, it.items == t, return it.model2);
-       return "";
+       return t ? t.model2 : "";
 }
 
-float _MapInfo_GetTeamPlayBool(float t)
+float _MapInfo_GetTeamPlayBool(Gametype t)
 {
-       FOREACH(Gametypes, it.items == t, return it.team);
-       return false;
+       return t ? t.team : false;
 }
 
-void _MapInfo_Map_ApplyGametypeEx(string s, int pWantedType, int pThisType)
+void _MapInfo_Map_ApplyGametypeEx(string s, Gametype pWantedType, Gametype pThisType)
 {
-       MapInfo_Map_supportedGametypes |= pThisType;
-       if (!(pThisType & pWantedType))
+       MapInfo_Map_supportedGametypes |= pThisType.m_flags;
+       if (!(pThisType.m_flags & pWantedType.m_flags))
                return;
 
        // reset all the cvars to their defaults
@@ -683,13 +685,7 @@ void _MapInfo_Map_ApplyGametypeEx(string s, int pWantedType, int pThisType)
        }
 }
 
-Gametype MapInfo_Type(int t)
-{
-       FOREACH(Gametypes, it.items == t, return it);
-       return NULL;
-}
-
-int MapInfo_Type_FromString(string t)
+Gametype MapInfo_Type_FromString(string t)
 {
 #define deprecate(from, to) MACRO_BEGIN { \
        if (t == #from) { \
@@ -704,31 +700,25 @@ int MapInfo_Type_FromString(string t)
        deprecate(invasion, inv);
        deprecate(assault, as);
        deprecate(race, rc);
-       if (t == "all") return MAPINFO_TYPE_ALL;
-       FOREACH(Gametypes, it.mdl == t, return it.items);
-       return 0;
+       FOREACH(Gametypes, it.mdl == t, return it);
+       return NULL;
 #undef deprecate
 }
 
-string MapInfo_Type_Description(float t)
+string MapInfo_Type_Description(Gametype t)
 {
-       FOREACH(Gametypes, it.items == t, return it.gametype_description);
-       return "";
+       return t ? t.gametype_description : "";
 }
 
-string MapInfo_Type_ToString(float t)
+string MapInfo_Type_ToString(Gametype t)
 {
-       if(t == MAPINFO_TYPE_ALL)
-               return "all";
-       FOREACH(Gametypes, it.items == t, return it.mdl);
-       return "";
+       return t ? t.mdl : "";
 }
 
-string MapInfo_Type_ToText(float t)
+string MapInfo_Type_ToText(Gametype t)
 {
-       FOREACH(Gametypes, it.items == t, return it.message);
        /* xgettext:no-c-format */
-       return _("@!#%'n Tuba Throwing");
+       return t ? t.message : _("@!#%'n Tuba Throwing");
 }
 
 void _MapInfo_Parse_Settemp(string pFilename, string acl, float type, string s, float recurse)
@@ -857,7 +847,7 @@ float MapInfo_isRedundant(string fn, string t)
 }
 
 // load info about a map by name into the MapInfo_Map_* globals
-float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int pGametypeToSet)
+float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, Gametype pGametypeToSet)
 {
        string fn;
        string s, t;
@@ -874,7 +864,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                return 0;
        }
 
-       if(pGametypeToSet == 0)
+       if(pGametypeToSet == NULL)
                if(MapInfo_Cache_Retrieve(pFilename))
                        return 1;
 
@@ -939,9 +929,9 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                        if(MapInfo_Map_flags & MAPINFO_FLAG_FRUSTRATING)
                                fputs(fh, "frustrating\n");
 
-                       for(i = 1; i <= MapInfo_Map_supportedGametypes; i *= 2)
-                               if(MapInfo_Map_supportedGametypes & i)
-                                       fputs(fh, sprintf("gametype %s // defaults: %s\n", MapInfo_Type_ToString(i), _MapInfo_GetDefaultEx(i)));
+                       FOREACH(Gametypes, MapInfo_Map_supportedGametypes & it.m_flags, {
+                               fputs(fh, sprintf("gametype %s // defaults: %s\n", MapInfo_Type_ToString(it), _MapInfo_GetDefaultEx(it)));
+                       });
 
                        if(fexists(strcat("scripts/", pFilename, ".arena")))
                                fputs(fh, "settemp_for_type all sv_q3acompat_machineshotgunswap 1\n");
@@ -1025,7 +1015,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                else if(t == "type")
                {
                        t = car(s); s = cdr(s);
-                       f = MapInfo_Type_FromString(t);
+                       Gametype f = MapInfo_Type_FromString(t);
                        LOG_MAPWARN("Map ", pFilename, " contains the legacy 'type' keyword which is deprecated and will be removed in the future. Please migrate the mapinfo file to 'gametype'.\n");
                        if(f)
                                _MapInfo_Map_ApplyGametype (s, pGametypeToSet, f, true);
@@ -1035,7 +1025,7 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                else if(t == "gametype")
                {
                        t = car(s); s = cdr(s);
-                       f = MapInfo_Type_FromString(t);
+                       Gametype f = MapInfo_Type_FromString(t);
                        if(f)
                                _MapInfo_Map_ApplyGametypeEx (s, pGametypeToSet, f);
                        else
@@ -1075,9 +1065,10 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                else if(t == "settemp_for_type")
                {
                        t = car(s); s = cdr(s);
+                       Gametype f;
                        if((f = MapInfo_Type_FromString(t)))
                        {
-                               if(f & pGametypeToSet)
+                               if(f.m_flags & pGametypeToSet.m_flags)
                                {
                                        _MapInfo_Parse_Settemp(pFilename, acl, 0, s, 1);
                                }
@@ -1090,9 +1081,10 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
                else if(t == "clientsettemp_for_type")
                {
                        t = car(s); s = cdr(s);
+                       Gametype f;
                        if((f = MapInfo_Type_FromString(t)))
                        {
-                               if(f & pGametypeToSet)
+                               if(f.m_flags & pGametypeToSet.m_flags)
                                {
                                        _MapInfo_Parse_Settemp(pFilename, acl, 1, s, 1);
                                }
@@ -1146,21 +1138,21 @@ float MapInfo_Get_ByName_NoFallbacks(string pFilename, int pAllowGenerate, int p
        LOG_MAPWARN("Map ", pFilename, " supports no game types, ignored\n");
        return 0;
 }
-float MapInfo_Get_ByName(string pFilename, float pAllowGenerate, int pGametypeToSet)
+int MapInfo_Get_ByName(string pFilename, float pAllowGenerate, Gametype pGametypeToSet)
 {
-       float r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
+       int r = MapInfo_Get_ByName_NoFallbacks(pFilename, pAllowGenerate, pGametypeToSet);
 
        if(cvar("g_tdm_on_dm_maps"))
        {
                // if this is set, all DM maps support TDM too
-               if (!(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH))
-                       if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH)
+               if (!(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_TEAM_DEATHMATCH.m_flags))
+                       if(MapInfo_Map_supportedGametypes & MAPINFO_TYPE_DEATHMATCH.m_flags)
                                _MapInfo_Map_ApplyGametypeEx ("", pGametypeToSet, MAPINFO_TYPE_TEAM_DEATHMATCH);
        }
 
        if(pGametypeToSet)
        {
-               if(!(MapInfo_Map_supportedGametypes & pGametypeToSet))
+               if(!(MapInfo_Map_supportedGametypes & pGametypeToSet.m_flags))
                {
                        error("Can't select the requested game type. This should never happen as the caller should prevent it!\n");
                        //_MapInfo_Map_ApplyGametypeEx("", pGametypeToSet, MAPINFO_TYPE_DEATHMATCH);
@@ -1233,19 +1225,18 @@ int MapInfo_CurrentFeatures()
        return req;
 }
 
-int MapInfo_CurrentGametype()
+Gametype MapInfo_CurrentGametype()
 {
-       int prev = cvar("gamecfg");
-       FOREACH(Gametypes, cvar(it.netname) && it.items != prev, return it.items);
-       if (prev) return prev;
-       return MAPINFO_TYPE_DEATHMATCH;
+       Gametype prev = Gametypes_from(cvar("gamecfg"));
+       FOREACH(Gametypes, cvar(it.netname) && it != prev, return it);
+       return prev ? prev : MAPINFO_TYPE_DEATHMATCH;
 }
 
 float _MapInfo_CheckMap(string s) // returns 0 if the map can't be played with the current settings, 1 otherwise
 {
-       if(!MapInfo_Get_ByName(s, 1, 0))
+       if(!MapInfo_Get_ByName(s, 1, NULL))
                return 0;
-       if((MapInfo_Map_supportedGametypes & MapInfo_CurrentGametype()) == 0)
+       if((MapInfo_Map_supportedGametypes & MapInfo_CurrentGametype().m_flags) == 0)
                return 0;
        if((MapInfo_Map_supportedFeatures & MapInfo_CurrentFeatures()) != MapInfo_CurrentFeatures())
                return 0;
@@ -1260,9 +1251,9 @@ float MapInfo_CheckMap(string s) // returns 0 if the map can't be played with th
        return r;
 }
 
-void MapInfo_SwitchGameType(int t)
+void MapInfo_SwitchGameType(Gametype t)
 {
-       FOREACH(Gametypes, true, cvar_set(it.netname, (it.items == t) ? "1" : "0"));
+       FOREACH(Gametypes, true, cvar_set(it.netname, (it == t) ? "1" : "0"));
 }
 
 void MapInfo_LoadMap(string s, float reinit)
@@ -1272,7 +1263,7 @@ void MapInfo_LoadMap(string s, float reinit)
        //if(!MapInfo_CheckMap(s))
        //{
        //      print("EMERGENCY: can't play the selected map in the given game mode. Falling back to DM.\n");
-       //      MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH);
+       //      MapInfo_SwitchGameType(MAPINFO_TYPE_DEATHMATCH.m_flags);
        //}
 
        cvar_settemp_restore();
@@ -1282,7 +1273,7 @@ void MapInfo_LoadMap(string s, float reinit)
                localcmd(strcat("\nchangelevel ", s, "\n"));
 }
 
-string MapInfo_ListAllowedMaps(float type, float pRequiredFlags, float pForbiddenFlags)
+string MapInfo_ListAllowedMaps(Gametype type, float pRequiredFlags, float pForbiddenFlags)
 {
        string out;
        float i;
@@ -1304,7 +1295,7 @@ string MapInfo_ListAllAllowedMaps(float pRequiredFlags, float pForbiddenFlags)
 
        // to make absolutely sure:
        MapInfo_Enumerate();
-       MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, pRequiredFlags, pForbiddenFlags, 0);
+       _MapInfo_FilterGametype(MAPINFO_TYPE_ALL, 0, pRequiredFlags, pForbiddenFlags, 0);
 
        out = "";
        for(i = 0; i < MapInfo_count; ++i)
@@ -1315,18 +1306,16 @@ string MapInfo_ListAllAllowedMaps(float pRequiredFlags, float pForbiddenFlags)
        return substring(out, 1, strlen(out) - 1);
 }
 
-void MapInfo_LoadMapSettings_SaveGameType(float t)
+void MapInfo_LoadMapSettings_SaveGameType(Gametype t)
 {
        MapInfo_SwitchGameType(t);
-       cvar_set("gamecfg", ftos(t));
+       cvar_set("gamecfg", ftos(t.m_id));
        MapInfo_LoadedGametype = t;
 }
 
 void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
 {
-       float t;
-
-       t = MapInfo_CurrentGametype();
+       Gametype t = MapInfo_CurrentGametype();
        MapInfo_LoadMapSettings_SaveGameType(t);
 
        if(!_MapInfo_CheckMap(s)) // with underscore, it keeps temps
@@ -1341,18 +1330,19 @@ void MapInfo_LoadMapSettings(string s) // to be called from worldspawn
                if(MapInfo_Map_supportedGametypes == 0)
                {
                        LOG_SEVERE("Mapinfo system is not functional at all. Assuming deathmatch.\n");
-                       MapInfo_Map_supportedGametypes = MAPINFO_TYPE_DEATHMATCH;
+                       MapInfo_Map_supportedGametypes = MAPINFO_TYPE_DEATHMATCH.m_flags;
                        MapInfo_LoadMapSettings_SaveGameType(MAPINFO_TYPE_DEATHMATCH);
                        _MapInfo_Map_ApplyGametypeEx("", MAPINFO_TYPE_DEATHMATCH, MAPINFO_TYPE_DEATHMATCH);
                        return; // do not call Get_ByName!
                }
 
-               t = 1;
+               int _t = 1;
                while(!(MapInfo_Map_supportedGametypes & 1))
                {
-                       t *= 2;
-                       MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes / 2);
+                       _t <<= 1;
+                       MapInfo_Map_supportedGametypes = floor(MapInfo_Map_supportedGametypes >> 1);
                }
+               FOREACH(Gametypes, it.m_flags == _t, { t = it; break; });
 
                // t is now a supported mode!
                LOG_WARNING("can't play the selected map in the given game mode. Falling back to a supported mode.\n");