UFO: Alien Invasion
sv_mapcycle.cpp
Go to the documentation of this file.
1 #include "server.h"
2 #include "../shared/parse.h"
3 
7 typedef struct mapcycle_s {
8  char* map;
9  char* type;
10  bool day;
11  struct mapcycle_s* next;
12 } mapcycle_t;
13 
15 static int mapcycleCount;
20 void SV_NextMapcycle (void)
21 {
22  const char* map = nullptr, *gameType = nullptr;
23  bool day = true;
24  char expanded[MAX_QPATH];
25  mapcycle_t* mapcycle = mapcycleList;
26 
27  if (sv->name[0]) {
28  Com_Printf("current map: %s\n", sv->name);
29  for (int i = 0; i < mapcycleCount; i++) {
30  /* random maps may have a theme - but that's not stored in sv->name
31  * but in sv->assembly */
32  if (mapcycle->map[0] == '+') {
33  Q_strncpyz(expanded, mapcycle->map, sizeof(expanded));
34  char* base = strstr(expanded, " ");
35  if (base) {
36  char assembly[MAX_QPATH];
37  base[0] = '\0'; /* split the strings */
38  Q_strncpyz(assembly, base + 1, sizeof(assembly));
39  /* get current position */
40  if (Q_streq(sv->name, expanded) && Q_streq(sv->assembly, assembly)) {
41  /* next map in cycle */
42  if (mapcycle->next) {
43  map = mapcycle->next->map;
44  day = mapcycle->next->day;
45  gameType = mapcycle->next->type;
46  Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
47  /* switch back to first list on cycle - if there is one */
48  } else {
49  map = mapcycleList->map;
50  day = mapcycleList->day;
51  gameType = mapcycleList->type;
52  Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
53  }
54  break;
55  }
56  } else {
57  Com_Printf("ignore mapcycle entry for random map (%s) with"
58  " no assembly given\n", mapcycle->map);
59  }
60  } else {
61  /* get current position */
62  if (Q_streq(sv->name, mapcycle->map)) {
63  /* next map in cycle */
64  if (mapcycle->next) {
65  map = mapcycle->next->map;
66  day = mapcycle->next->day;
67  gameType = mapcycle->next->type;
68  Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: next one: '%s' (gametype: %s)\n", map, gameType);
69  /* switch back to first list on cycle - if there is one */
70  } else {
71  map = mapcycleList->map;
72  day = mapcycleList->day;
73  gameType = mapcycleList->type;
74  Com_DPrintf(DEBUG_SERVER, "SV_NextMapcycle: first one: '%s' (gametype: %s)\n", map, gameType);
75  }
76  Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
77 
78  /* check for bsp file */
79  if (map[0] != '+' && FS_CheckFile("%s", expanded) < 0) {
80  Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
81  "Use the 'maplist' command to get a list of valid maps\n", expanded);
82  map = nullptr;
83  gameType = nullptr;
84  } else
85  break;
86  }
87  }
88  mapcycle = mapcycle->next;
89  }
90  }
91 
92  if (!map) {
93  if (mapcycleCount > 0) {
94  map = mapcycleList->map;
95  day = mapcycleList->day;
96  gameType = mapcycleList->type;
97  if (map[0] != '+') {
98  Com_sprintf(expanded, sizeof(expanded), "maps/%s.bsp", map);
99 
100  /* check for bsp file */
101  if (FS_CheckFile("%s", expanded) < 0) {
102  Com_Printf("SV_NextMapcycle: Can't find '%s' - mapcycle error\n"
103  "Use the 'maplist' command to get a list of valid maps\n", expanded);
104  return;
105  }
106  }
107  } else if (sv->name[0]) {
108  Com_Printf("No mapcycle - restart the current map (%s)\n", sv->name);
109  map = sv->name;
110  gameType = nullptr;
111  } else {
112  Com_Printf("No mapcycle and no running map\n");
113  return;
114  }
115  /* still not set? */
116  if (!map)
117  return;
118  }
119 
120  /* check whether we want to change the gametype, too */
121  if (gameType && gameType[0] != '\0') {
122  Cvar_Set("sv_gametype", "%s", gameType);
123  Com_SetGameType();
124  sv_gametype->modified = false;
125  }
126 
127  if (day)
128  Cbuf_AddText("map day %s", map);
129  else
130  Cbuf_AddText("map night %s", map);
131 }
132 
137 void SV_MapcycleClear (void)
138 {
139  mapcycle_t* mapcycle = mapcycleList;
140 
141  for (int i = 0; i < mapcycleCount; i++) {
142  mapcycle_t* oldMapcycle = mapcycle;
143  mapcycle = mapcycle->next;
144  Mem_Free(oldMapcycle->type);
145  Mem_Free(oldMapcycle->map);
146  Mem_Free(oldMapcycle);
147  }
148 
149  /* reset the mapcycle data */
150  mapcycleList = nullptr;
151  mapcycleCount = 0;
152 }
153 
159 static void SV_MapcycleAdd (const char* mapName, bool day, const char* gameType)
160 {
162  mapcycle->map = Mem_PoolStrDup(mapName, sv_genericPool, 0);
163  mapcycle->day = day;
164  mapcycle->type = Mem_PoolStrDup(gameType, sv_genericPool, 0);
165  mapcycle->next = 0;
166  Com_DPrintf(DEBUG_SERVER, "mapcycle add: '%s' type '%s'\n", mapcycle->map, mapcycle->type);
167 
168  /* Append to end of list. */
169  mapcycle_t** anchor = &mapcycleList;
170  while (*anchor) anchor = &(*anchor)->next;
171  *anchor = mapcycle;
172 
173  ++mapcycleCount;
174 }
175 
181 static void SV_ParseMapcycle (void)
182 {
183  int length = 0;
184  byte* buffer = nullptr;
185  const char* buf;
186 
187  mapcycleCount = 0;
188  mapcycleList = nullptr;
189 
190  length = FS_LoadFile("mapcycle.txt", &buffer);
191  if (length == -1 || !buffer)
192  return;
193 
194  if (length != -1) {
195  buf = (const char*)buffer;
196  do {
197  bool day = false;
198  const char* token;
199  char map[MAX_VAR], gameType[MAX_VAR];
200  /* parse map name */
201  token = Com_Parse(&buf);
202  if (!buf)
203  break;
204  Q_strncpyz(map, token, sizeof(map));
205  /* parse day or night */
206  token = Com_Parse(&buf);
207  if (!buf)
208  break;
209  if (Q_streq(token, "day"))
210  day = true;
211  else if (!Q_streq(token, "night")) {
212  Com_Printf("Skip mapcycle parsing, expected day or night.");
213  break;
214  }
215  /* parse gametype */
216  token = Com_Parse(&buf);
217  if (!buf)
218  break;
219  Q_strncpyz(gameType, token, sizeof(gameType));
220  SV_MapcycleAdd(map, day, gameType);
221  } while (buf);
222 
223  Com_Printf("added %i maps to the mapcycle\n", mapcycleCount);
224  }
225  FS_FreeFile(buffer);
226 }
227 
228 static void SV_MapcycleList_f (void)
229 {
230  const mapcycle_t* mapcycle = mapcycleList;
231 
232  Com_Printf("current mapcycle has %i entries\n", mapcycleCount);
233  for (int i = 0; i < mapcycleCount; i++) {
234  Com_Printf(" %s (%s)\n", mapcycle->map, mapcycle->type);
235  mapcycle = mapcycle->next;
236  }
237 }
238 
239 static void SV_MapcycleAdd_f (void)
240 {
241  if (Cmd_Argc() == 4) {
242  const char* map = Cmd_Argv(1);
243  const char* day = Cmd_Argv(2);
244  const char* gametype = Cmd_Argv(3);
245  if (!SV_CheckMap(map, nullptr)) {
246  Com_Printf("map '%s' isn't a valid map\n", map);
247  return;
248  }
249  Com_Printf("adding map '%s' with gametype '%s' to mapcycle (to add this permanently edit your mapcycle.txt)\n", map, gametype);
250  if (Q_streq(day, "day"))
251  SV_MapcycleAdd(map, true, gametype);
252  else
253  SV_MapcycleAdd(map, false, gametype);
254  } else {
255  Com_Printf("Usage: %s <mapname> <day|night> <gametype>\n", Cmd_Argv(0));
256  Com_Printf(" ...to get a list of valid maps type 'maplist'\n"
257  " ...to get a list of valid gametypes 'gametypelist'\n");
258  }
259 }
260 
261 static void SV_MapcycleNext_f (void)
262 {
263  if (mapcycleCount > 0)
264  SV_NextMapcycle();
265  else
266  Com_Printf("no mapcycle.txt\n");
267 }
268 
269 void SV_MapcycleInit (void)
270 {
272 
273  Cmd_AddCommand("mapcyclelist", SV_MapcycleList_f, "Print the current mapcycle");
274  Cmd_AddCommand("mapcyclenext", SV_MapcycleNext_f, "Start the next map from the cycle");
275  Cmd_AddCommand("mapcycleclear", SV_MapcycleClear, "Delete the current mapcycle");
276  Cmd_AddCommand("mapcycleadd", SV_MapcycleAdd_f, "Add new maps to the mapcycle");
277 }
const char * Cmd_Argv(int arg)
Returns a given argument.
Definition: cmd.cpp:516
void Cmd_AddCommand(const char *cmdName, xcommand_t function, const char *desc)
Add a new command to the script interface.
Definition: cmd.cpp:744
int FS_CheckFile(const char *fmt,...)
Just returns the filelength and -1 if the file wasn&#39;t found.
Definition: files.cpp:298
#define DEBUG_SERVER
Definition: defines.h:60
bool Com_sprintf(char *dest, size_t size, const char *fmt,...)
copies formatted string with buffer-size checking
Definition: shared.cpp:494
static void SV_ParseMapcycle(void)
Parses the server mapcycle.
struct mapcycle_s * next
Definition: sv_mapcycle.cpp:11
void Cbuf_AddText(const char *format,...)
Adds command text at the end of the buffer.
Definition: cmd.cpp:126
static int mapcycleCount
Definition: sv_mapcycle.cpp:15
memPool_t * sv_genericPool
Definition: sv_main.cpp:55
static void SV_MapcycleAdd_f(void)
int FS_LoadFile(const char *path, byte **buffer)
Filenames are relative to the quake search path.
Definition: files.cpp:384
cvar_t * sv_gametype
Definition: common.cpp:56
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
char * type
Definition: sv_mapcycle.cpp:9
static mapcycle_t * mapcycleList
Definition: sv_mapcycle.cpp:14
voidpf void * buf
Definition: ioapi.h:42
static void SV_MapcycleNext_f(void)
serverInstanceGame_t * sv
Definition: sv_init.cpp:36
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
#define MAX_VAR
Definition: shared.h:36
QGL_EXTERN GLuint GLsizei GLsizei * length
Definition: r_gl.h:110
int Cmd_Argc(void)
Return the number of arguments of the current command. "command parameter" will result in a argc of 2...
Definition: cmd.cpp:505
Main server include file.
void Com_DPrintf(int level, const char *fmt,...)
A Com_Printf that only shows up if the "developer" cvar is set.
Definition: common.cpp:398
bool SV_CheckMap(const char *map, const char *assembly)
Checks whether a map exists.
Definition: sv_ccmds.cpp:101
const char * Com_Parse(const char *data_p[], char *target, size_t size, bool replaceWhitespaces)
Parse a token out of a string.
Definition: parse.cpp:107
void SV_NextMapcycle(void)
Start the next map in the cycle.
Definition: sv_mapcycle.cpp:20
#define MAX_QPATH
Definition: filesys.h:40
QGL_EXTERN GLint i
Definition: r_gl.h:113
char name[MAX_QPATH]
Definition: server.h:109
#define Mem_Free(ptr)
Definition: mem.h:35
static void SV_MapcycleAdd(const char *mapName, bool day, const char *gameType)
Append a new mapname to the list of maps for the cycle.
void Com_SetGameType(void)
Definition: common.cpp:815
static void SV_MapcycleList_f(void)
char * map
Definition: sv_mapcycle.cpp:8
char assembly[MAX_QPATH]
Definition: server.h:110
cvar_t * Cvar_Set(const char *varName, const char *value,...)
Sets a cvar value.
Definition: cvar.cpp:615
map cycle list element
Definition: sv_mapcycle.cpp:7
#define Q_streq(a, b)
Definition: shared.h:136
#define Mem_PoolStrDup(in, pool, tagNum)
Definition: mem.h:50
#define Mem_PoolAllocType(type, pool)
Definition: mem.h:43
bool modified
Definition: cvar.h:79
uint8_t byte
Definition: ufotypes.h:34
void SV_MapcycleClear(void)
Empty the mapcycle list.
static const char * mapName
void FS_FreeFile(void *buffer)
Definition: files.cpp:411
void SV_MapcycleInit(void)