1 /*
2  * file cfg_demo.c - configuration data for recorded demos
3  *
4  * $Id: cfg_demo.c,v 1.11 2006/02/24 21:29:16 fzago Exp $
5  *
6  * Program XBLAST
7  * (C) by Oliver Vogel (e-mail: m.vogel@ndh.net)
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published
11  * by the Free Software Foundation; either version 2; or (at your option)
12  * any later version
13  *
14  * This program is distributed in the hope that it will be entertaining,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILTY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17  * Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along
20  * with this program; if not, write to the Free Software Foundation, Inc.
21  * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  */
23 
24 #include "xblast.h"
25 
26 /*
27  * global variables
28  */
29 
30 /* current demo */
31 DBRoot *dbDemo = NULL;
32 
33 /*
34  * local variables
35  */
36 
37 /* list of all demos */
38 static DBRoot *dbList = NULL;
39 /* action keys for current demo */
40 static DBSection *frameSection = NULL;
41 
42 /**********************
43  * managing all demos *
44  **********************/
45 
46 /*
47  * initialize current demo and list
48  */
49 void
LoadDemoConfig(void)50 LoadDemoConfig (void)
51 {
52 	/* create demo database for current demo */
53 	dbDemo = DB_Create (DT_Demo, atomDemo);
54 	assert (NULL != dbDemo);
55 	/* load list of recorded demos */
56 	dbList = DB_Create (DT_Config, atomDemo);
57 	assert (NULL != dbDemo);
58 	Dbg_Config ("loading list of demos\n");
59 	if (DB_LoadDir (dbList, "demo", "dem", DT_Demo, atomTime, atomInfo, NULL, XBFalse)) {
60 		SaveDemoConfig ();
61 	}
62 	else {
63 		Dbg_Config ("no changes found\n");
64 	}
65 }								/* LoadDemoConfig */
66 
67 /*
68  * store current list of demos in config
69  */
70 void
SaveDemoConfig(void)71 SaveDemoConfig (void)
72 {
73 	/* list of demos database */
74 	assert (dbList != NULL);
75 	if (DB_Changed (dbList)) {
76 		Dbg_Config ("saving list of demos\n");
77 		DB_Store (dbList);
78 	}
79 }								/* SaveDemoConfig */
80 
81 /*
82  * clear current demo and list
83  */
84 void
FinishDemoConfig(void)85 FinishDemoConfig (void)
86 {
87 	/* remove single demo database */
88 	assert (dbDemo != NULL);
89 	DB_Delete (dbDemo);
90 	dbDemo = NULL;
91 	/* save and remove list of demos database */
92 	SaveDemoConfig ();
93 	DB_Delete (dbList);
94 	dbList = NULL;
95 	Dbg_Config ("demo config cleared\n");
96 }								/* FinishDemoConfig */
97 
98 /*
99  * compare to demo entries by time
100  */
101 static int
CompareDemoEntries(const void * a,const void * b)102 CompareDemoEntries (const void *a, const void *b)
103 {
104 	assert (NULL != a);
105 	assert (NULL != b);
106 	return ((const CFGDemoEntry *) b)->time - ((const CFGDemoEntry *) a)->time;
107 }								/* CompareDemoEntries */
108 
109 /*
110  * create list with all demos available
111  */
112 CFGDemoEntry *
CreateDemoList(size_t * num)113 CreateDemoList (size_t * num)
114 {
115 	CFGDemoEntry *list;
116 	size_t i, j;
117 	XBAtom atom;
118 	const DBSection *section;
119 
120 	/* sanity check */
121 	assert (NULL != dbList);
122 	assert (NULL != num);
123 	/* alloc data */
124 	*num = DB_NumSections (dbList);
125 	if (0 == *num) {
126 		return NULL;
127 	}
128 	list = calloc (*num, sizeof (CFGDemoEntry));
129 	/* build list */
130 	for (i = 0, j = 0; i < *num; i++) {
131 		atom = DB_IndexSection (dbList, i);
132 		section = DB_GetSection (dbList, atom);
133 		assert (NULL != section);
134 		list[j].atom = atom;
135 		(void)DB_GetEntryAtom (section, atomLevel, &list[j].level);
136 		if (NULL == GetLevelNameByAtom (list[j].level)) {
137 			continue;
138 		}
139 		(void)DB_GetEntryInt (section, atomNumPlayers, &list[j].numPlayers);
140 		(void)DB_GetEntryTime (section, atomRecorded, &list[j].time);
141 		j++;
142 	}
143 	*num = j;
144 	/* sort it */
145 	qsort (list, *num, sizeof (CFGDemoEntry), CompareDemoEntries);
146 	return list;
147 }								/* CreateDemoList */
148 
149 /*****************************
150  * current demo from/to file *
151  *****************************/
152 
153 /*
154  * load current demo from file
155  */
156 XBBool
LoadDemoFromFile(XBAtom atom)157 LoadDemoFromFile (XBAtom atom)
158 {
159 	/* clear current demo */
160 	assert (NULL != dbDemo);
161 	DB_Delete (dbDemo);
162 	/* create new demo */
163 	dbDemo = DB_Create (DT_Demo, atom);
164 	assert (NULL != dbDemo);
165 	/* load and return success */
166 	return DB_Load (dbDemo);
167 }								/* LoadDemoFromFile */
168 
169 /*
170  * store current demo in file
171  */
172 void
SaveCurrentDemo(const char * filename)173 SaveCurrentDemo (const char *filename)
174 {
175 	/* set file name for output */
176 	DB_SetAtom (dbDemo, GUI_StringToAtom (filename));
177 	/* single demo */
178 	assert (NULL != dbDemo);
179 	DB_Store (dbDemo);
180 	/* TODO: add file to demoList !!! */
181 }								/* SaveCurrentDemo */
182 
183 /***********************
184  * current demo config *
185  ***********************/
186 
187 /*
188  * store config data for a demo in current database
189  */
190 void
StoreDemoConfig(const CFGDemoInfo * cfgDemo)191 StoreDemoConfig (const CFGDemoInfo * cfgDemo)
192 {
193 	DBSection *section;
194 	/* sanity checks */
195 	assert (NULL != cfgDemo);
196 	assert (NULL != dbDemo);
197 	/* create empty section */
198 	DB_DeleteSection (dbDemo, atomInfo);
199 	section = DB_CreateSection (dbDemo, atomInfo);
200 	assert (NULL != section);
201 	/* store data */
202 	(void)DB_CreateEntryInt (section, atomNumPlayers, cfgDemo->numPlayers);
203 	(void)DB_CreateEntryInt (section, atomNumFrames, cfgDemo->numFrames);
204 	(void)DB_CreateEntryAtom (section, atomLevel, cfgDemo->level);
205 	(void)DB_CreateEntryInt (section, atomRandomSeed, cfgDemo->randomSeed);
206 	(void)DB_CreateEntryTime (section, atomRecorded, cfgDemo->time);
207 	(void)DB_CreateEntryInt (section, atomLives, cfgDemo->numLives);
208 	(void)DB_CreateEntryInt (section, atomFrameRate, cfgDemo->frameRate);
209 	(void)DB_CreateEntryBool (section, atomRandomPlayers, cfgDemo->randomPlayers);
210 	(void)DB_CreateEntryInt (section, atomWinner, cfgDemo->winner);
211 }								/* StoreDemoConfig */
212 
213 /*
214  * get config data for current demo from database
215  */
216 XBBool
RetrieveDemoConfig(CFGDemoInfo * cfgDemo)217 RetrieveDemoConfig (CFGDemoInfo * cfgDemo)
218 {
219 	const DBSection *section;
220 	/* sanity checks */
221 	assert (NULL != cfgDemo);
222 	assert (NULL != dbDemo);
223 	/* find section */
224 	if (NULL == (section = DB_GetSection (dbDemo, atomInfo))) {
225 		return XBFalse;
226 	}
227 	/* get data */
228 	if (!DB_GetEntryInt (section, atomNumPlayers, &cfgDemo->numPlayers) ||
229 		!DB_GetEntryInt (section, atomNumFrames, &cfgDemo->numFrames) ||
230 		!DB_GetEntryAtom (section, atomLevel, &cfgDemo->level) ||
231 		!DB_GetEntryInt (section, atomRandomSeed, &cfgDemo->randomSeed) ||
232 		!DB_GetEntryTime (section, atomRecorded, &cfgDemo->time) ||
233 		!DB_GetEntryInt (section, atomLives, &cfgDemo->numLives) ||
234 		!DB_GetEntryInt (section, atomFrameRate, &cfgDemo->frameRate) ||
235 		!DB_GetEntryBool (section, atomRandomPlayers, &cfgDemo->randomPlayers)) {
236 		return XBFalse;
237 	}
238 	return XBTrue;
239 }								/* RetrieveDemoConfig */
240 
241 /****************************
242  * current demo: frame data *
243  ****************************/
244 
245 /*
246  * store data for single frame in current demo database
247  */
248 void
StoreDemoFrame(int gameTime,int numPlayers,const unsigned char * buf)249 StoreDemoFrame (int gameTime, int numPlayers, const unsigned char *buf)
250 {
251 	int i;
252 	size_t len = 0;
253 	char tmp[3 * MAX_PLAYER + 1] = "";
254 	/* create frame section if needed */
255 	if (NULL == frameSection) {
256 		assert (NULL != dbDemo);
257 		frameSection = DB_CreateSection (dbDemo, atomFrames);
258 		assert (NULL != frameSection);
259 	}
260 	/* create the entry */
261 	for (i = 0; i < numPlayers; i++) {
262 		len += sprintf (tmp + len, "%02X ", (unsigned)buf[i]);
263 	}
264 	(void)DB_CreateEntryString (frameSection, GUI_IntToAtom (gameTime), tmp);
265 }								/* StoreDemoFrame */
266 
267 /*
268  * copy frames of current demo into a buffer
269  */
270 XBBool
RetrieveDemoFrames(int numPlayers,unsigned char (* buffer)[MAX_PLAYER])271 RetrieveDemoFrames (int numPlayers, unsigned char (*buffer)[MAX_PLAYER])
272 {
273 	const DBSection *section;
274 	size_t i, j, num;
275 	int frame;
276 	const char *s;
277 	unsigned value;
278 	/* sanity check */
279 	assert (numPlayers <= MAX_PLAYER);
280 	assert (buffer != NULL);
281 	assert (dbDemo != NULL);
282 	/* find frames section */
283 	if (NULL == (section = DB_GetSection (dbDemo, atomFrames))) {
284 		return XBFalse;
285 	}
286 	/* get number of entries */
287 	num = DB_NumEntries (section);
288 	/* loop through entries */
289 	for (i = 0; i < num; i++) {
290 		/* get indexed entry */
291 		XBAtom atom = DB_IndexEntry (section, i);
292 		assert (ATOM_INVALID != atom);
293 		/* check for valid game time */
294 		frame = GUI_AtomToInt (atom);
295 		if (frame < 0 || frame >= GAME_TIME) {
296 			return XBFalse;
297 		}
298 		/* get action string */
299 		if (!DB_GetEntryString (section, atom, &s)) {
300 			return XBFalse;
301 		}
302 		/* validate length */
303 		if (strlen (s) < 2 * numPlayers) {
304 			return XBFalse;
305 		}
306 		/* try to extract keys for each player */
307 		for (j = 0; j < numPlayers; j++) {
308 			if (1 != sscanf (s + 3 * j, "%x", &value)) {
309 				return XBFalse;
310 			}
311 			/* store in buffer */
312 			buffer[frame][j] = (unsigned char)value;
313 		}
314 	}
315 	return XBTrue;
316 }								/* RetrieveDemoFrames */
317 
318 /*
319  * clear frame section of current database
320  */
321 void
DeleteDemoFrames(void)322 DeleteDemoFrames (void)
323 {
324 	assert (NULL != dbDemo);
325 	DB_DeleteSection (dbDemo, atomFrames);
326 	frameSection = NULL;
327 }								/* ClearDemoFrames */
328 
329 /*
330  * end of file cfg_demo.c
331  */
332