diff --git a/source/src/protocol.cpp b/source/src/protocol.cpp index 977c86d8..0b83f22f 100644 --- a/source/src/protocol.cpp +++ b/source/src/protocol.cpp @@ -399,6 +399,34 @@ const char *mmfullname(int n) { return (n>=0 && n < MM_NUM) ? mmfullnames[n] : " int defaultgamelimit(int gamemode) { return m_teammode ? 15 : 10; } +int gmode_possible(bool hasffaspawns, bool hasteamspawns, bool hasflags) // return bitmask of playable modes, according to existing spawn and flag entities +{ + return ((hasffaspawns ? GMMASK__FFASPAWN : 0) | (hasteamspawns ? GMMASK__TEAMSPAWN : 0)) & ~(hasflags ? 0 : GMMASK__FLAGENTS); +} + +int gmode_parse(const char *list) // convert a list of mode acronyms to a bitmask +{ + char *buf = newstring(list), *b; + int res = 0; + for(char *p = strtok_r(buf, "|", &b); p; p = strtok_r(NULL, "|", &b)) + { + loopi(GMODE_NUM) if(!strcasecmp(p, modeacronymnames[i + 1])) res |= 1 << i; + } + delete buf; + return res; +} + +char *gmode_enum(int gm, char *buf) // convert mode bitmask to string with sorted list of mode acronyms +{ + vector mas; + loopi(GMODE_NUM) if(gm & (1 << i)) mas.add(modeacronymnames[i + 1]); + mas.sort(stringsortignorecase); + buf[0] = '\0'; + loopv(mas) concatformatstring(buf, "%s%s", i ? "|" : "", mas[i]); + filtertext(buf, buf, FTXT_TOLOWER); + return buf; +} + static const int msgsizes[] = // size inclusive message token, 0 for variable or not-checked sizes { SV_SERVINFO, 5, SV_WELCOME, 2, SV_INITCLIENT, 0, SV_POS, 0, SV_POSC, 0, SV_POSN, 0, SV_TEXT, 0, SV_TEAMTEXT, 0, SV_TEXTME, 0, SV_TEAMTEXTME, 0, SV_TEXTPRIVATE, 0, diff --git a/source/src/protos.h b/source/src/protos.h index 7fe06307..c6a5a8ca 100644 --- a/source/src/protos.h +++ b/source/src/protos.h @@ -951,6 +951,9 @@ extern const char *docgetdesc(const char *name); extern const char *acronymmodestr(int n); extern const char *fullmodestr(int n); extern int defaultgamelimit(int gamemode); +extern int gmode_possible(bool hasffaspawns, bool hasteamspawns, bool hasflags); +extern int gmode_parse(const char *list); +extern char *gmode_enum(int gm, char *buf); // crypto #define TIGERHASHSIZE 24 diff --git a/source/src/server.cpp b/source/src/server.cpp index ccee245b..4b26721b 100644 --- a/source/src/server.cpp +++ b/source/src/server.cpp @@ -2084,7 +2084,11 @@ void startgame(const char *newname, int newmode, int newtime, bool notify) if(localmap) { localmap->load(); - if(localmap->isok) sm = localmap; + if(localmap->isok) + { + sm = localmap; + if(!(sm->entstats.modes_possible & 1 << sg->smode)) conoutf("\f3map %s does not support game mode %s", sm->fname, fullmodestr(sg->smode)); + } else conoutf("\f3local server failed to load map \"%s%s\", error: %s", lpath, sg->smapname, localmap->err); } } diff --git a/source/src/tools.cpp b/source/src/tools.cpp index 747f3305..99362ea8 100644 --- a/source/src/tools.cpp +++ b/source/src/tools.cpp @@ -320,6 +320,7 @@ void calcentitystats(entitystats_s &es, const persistent_entity *pents, int pent es.pickupdistance[r]++; } es.pickups = picks.length(); + es.modes_possible = gmode_possible(es.hasffaspawns, es.hasteamspawns, es.hasflags); } #if 0 const char *rateentitystats(entitystats_s &es)