00001 #include "server.h"
00002 #include "../shared/parse.h"
00003
00007 typedef struct mapcycle_s {
00008 char *map;
00009 char *type;
00010 qboolean day;
00011 struct mapcycle_s* next;
00012 } mapcycle_t;
00013
00014 static mapcycle_t *mapcycleList;
00015 static int mapcycleCount;
00020 void SV_NextMapcycle (void)
00021 {
00022 const char *map = NULL, *gameType = NULL;
00023 qboolean day = qtrue;
00024 char *base;
00025 char assembly[MAX_QPATH];
00026 char expanded[MAX_QPATH];
00027 char cmd[MAX_QPATH];
00028 mapcycle_t *mapcycle;
00029
00030 mapcycle = mapcycleList;
00031 if (sv.name[0]) {
00032 int i;
00033 Com_Printf("current map: %s\n", sv.name);
00034 for (i = 0; i < mapcycleCount; i++) {
00035
00036
00037 if (mapcycle->map[0] == '+') {
00038 Q_strncpyz(expanded, mapcycle->map, sizeof(expanded));
00039 base = strstr(expanded, " ");
00040 if (base) {
00041 base[0] = '\0';
00042 Q_strncpyz(assembly, base + 1, sizeof(assembly));
00043
00044 if (!strcmp(sv.name, expanded) && !strcmp(sv.assembly, assembly)) {
00045
00046 if (mapcycle->next) {
00047 map = mapcycle->next->map;
00048 day = mapcycle->next->day;
00049 gameType = mapcycle->next->type;
00050 Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
00051
00052 } else {
00053 map = mapcycleList->map;
00054 day = mapcycleList->day;
00055 gameType = mapcycleList->type;
00056 Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
00057 }
00058 break;
00059 }
00060 } else {
00061 Com_Printf("ignore mapcycle entry for random map (%s) with"
00062 " no assembly given\n", mapcycle->map);
00063 }
00064 } else {
00065
00066 if (!strcmp(sv.name, mapcycle->map)) {
00067
00068 if (mapcycle->next) {
00069 map = mapcycle->next->map;
00070 day = mapcycle->next->day;
00071 gameType = mapcycle->next->type;
00072 Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
00073
00074 } else {
00075 map = mapcycleList->map;
00076 day = mapcycleList->day;
00077 gameType = mapcycleList->type;
00078 Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
00079 }
00080 Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
00081
00082
00083 if (map[0] != '+' && FS_CheckFile("%s", expanded) < 0) {
00084 Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
00085 "Use the 'maplist' command to get a list of valid maps\n", expanded);
00086 map = NULL;
00087 gameType = NULL;
00088 } else
00089 break;
00090 }
00091 }
00092 mapcycle = mapcycle->next;
00093 }
00094 }
00095
00096 if (!map) {
00097 if (mapcycleCount > 0) {
00098 map = mapcycleList->map;
00099 day = mapcycleList->day;
00100 gameType = mapcycleList->type;
00101 if (map[0] != '+') {
00102 Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
00103
00104
00105 if (FS_CheckFile("%s", expanded) < 0) {
00106 Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
00107 "Use the 'maplist' command to get a list of valid maps\n", expanded);
00108 return;
00109 }
00110 }
00111 } else if (sv.name[0]) {
00112 Com_Printf("No mapcycle - restart the current map (%s)\n", sv.name);
00113 map = sv.name;
00114 gameType = NULL;
00115 } else {
00116 Com_Printf("No mapcycle and no running map\n");
00117 return;
00118 }
00119
00120 if (!map)
00121 return;
00122 }
00123
00124
00125 if (gameType && gameType[0] != '\0') {
00126 Cvar_Set("sv_gametype", gameType);
00127 Com_SetGameType();
00128 sv_gametype->modified = qfalse;
00129 }
00130
00131 if (day)
00132 Com_sprintf(cmd, sizeof(cmd), "map day %s", map);
00133 else
00134 Com_sprintf(cmd, sizeof(cmd), "map night %s", map);
00135 Cbuf_AddText(cmd);
00136 }
00137
00142 void SV_MapcycleClear (void)
00143 {
00144 int i;
00145 mapcycle_t *mapcycle;
00146
00147 mapcycle = mapcycleList;
00148 for (i = 0; i < mapcycleCount; i++) {
00149 mapcycle_t *oldMapcycle = mapcycle;
00150 mapcycle = mapcycle->next;
00151 Mem_Free(oldMapcycle->type);
00152 Mem_Free(oldMapcycle->map);
00153 Mem_Free(oldMapcycle);
00154 }
00155
00156
00157 mapcycleList = NULL;
00158 mapcycleCount = 0;
00159 }
00160
00166 static void SV_MapcycleAdd (const char* mapName, qboolean day, const char* gameType)
00167 {
00168 mapcycle_t *mapcycle;
00169
00170 if (!mapcycleList) {
00171 mapcycleList = Mem_PoolAlloc(sizeof(*mapcycle), sv_genericPool, 0);
00172 mapcycle = mapcycleList;
00173 } else {
00174
00175 mapcycle = mapcycleList;
00176 while (mapcycle->next)
00177 mapcycle = mapcycle->next;
00178 mapcycle->next = Mem_PoolAlloc(sizeof(*mapcycle), sv_genericPool, 0);
00179 mapcycle = mapcycle->next;
00180 }
00181 mapcycle->map = Mem_PoolStrDup(mapName, sv_genericPool, 0);
00182 mapcycle->day = day;
00183 mapcycle->type = Mem_PoolStrDup(gameType, sv_genericPool, 0);
00184 Com_DPrintf(DEBUG_SERVER, "mapcycle add: '%s' type '%s'\n", mapcycle->map, mapcycle->type);
00185 mapcycle->next = NULL;
00186 mapcycleCount++;
00187 }
00188
00194 static void SV_ParseMapcycle (void)
00195 {
00196 int length = 0;
00197 byte *buffer = NULL;
00198 const char *token;
00199 const char *buf;
00200 char map[MAX_VAR], gameType[MAX_VAR];
00201
00202 mapcycleCount = 0;
00203 mapcycleList = NULL;
00204
00205 length = FS_LoadFile("mapcycle.txt", &buffer);
00206 if (length == -1 || !buffer)
00207 return;
00208
00209 if (length != -1) {
00210 buf = (const char*)buffer;
00211 do {
00212 qboolean day = qfalse;
00213
00214 token = Com_Parse(&buf);
00215 if (!buf)
00216 break;
00217 Q_strncpyz(map, token, sizeof(map));
00218
00219 token = Com_Parse(&buf);
00220 if (!buf)
00221 break;
00222 if (!strcmp(token, "day"))
00223 day = qtrue;
00224 else if (strcmp(token, "night")) {
00225 Com_Printf("Skip mapcycle parsing, expected day or night.");
00226 break;
00227 }
00228
00229 token = Com_Parse(&buf);
00230 if (!buf)
00231 break;
00232 Q_strncpyz(gameType, token, sizeof(gameType));
00233 SV_MapcycleAdd(map, day, gameType);
00234 } while (buf);
00235
00236 Com_Printf("added %i maps to the mapcycle\n", mapcycleCount);
00237 }
00238 FS_FreeFile(buffer);
00239 }
00240
00241 static void SV_MapcycleList_f (void)
00242 {
00243 int i;
00244 const mapcycle_t* mapcycle;
00245
00246 mapcycle = mapcycleList;
00247 Com_Printf("current mapcycle has %i entries\n", mapcycleCount);
00248 for (i = 0; i < mapcycleCount; i++) {
00249 Com_Printf(" %s (%s)\n", mapcycle->map, mapcycle->type);
00250 mapcycle = mapcycle->next;
00251 }
00252 }
00253
00254 static void SV_MapcycleAdd_f (void)
00255 {
00256 if (Cmd_Argc() == 4) {
00257 const char *map = Cmd_Argv(1);
00258 const char *day = Cmd_Argv(2);
00259 const char *gametype = Cmd_Argv(3);
00260 if (!SV_CheckMap(map, NULL)) {
00261 Com_Printf("map '%s' isn't a valid map\n", map);
00262 return;
00263 }
00264 Com_Printf("adding map '%s' with gametype '%s' to mapcycle (to add this permanently edit your mapcycle.txt)\n", map, gametype);
00265 if (!strcmp(day, "day"))
00266 SV_MapcycleAdd(map, qtrue, gametype);
00267 else
00268 SV_MapcycleAdd(map, qfalse, gametype);
00269 } else {
00270 Com_Printf("Usage: %s <mapname> <day|night> <gametype>\n", Cmd_Argv(0));
00271 Com_Printf(" ...to get a list of valid maps type 'maplist'\n"
00272 " ...to get a list of valid gametypes 'gametypelist'\n");
00273 }
00274 }
00275
00276 static void SV_MapcycleNext_f (void)
00277 {
00278 if (mapcycleCount > 0)
00279 SV_NextMapcycle();
00280 else
00281 Com_Printf("no mapcycle.txt\n");
00282 }
00283
00284 void SV_MapcycleInit (void)
00285 {
00286 SV_ParseMapcycle();
00287
00288 Cmd_AddCommand("mapcyclelist", SV_MapcycleList_f, "Print the current mapcycle");
00289 Cmd_AddCommand("mapcyclenext", SV_MapcycleNext_f, "Start the next map from the cycle");
00290 Cmd_AddCommand("mapcycleclear", SV_MapcycleClear, "Delete the current mapcycle");
00291 Cmd_AddCommand("mapcycleadd", SV_MapcycleAdd_f, "Add new maps to the mapcycle");
00292 }