Develop and Download Open Source Software

Browse CVS Repository

Contents of /mame32jp/mame32jp/src/hiscore.c

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Wed Apr 24 03:53:20 2002 UTC (21 years, 11 months ago) by zero
Branch: MAIN
CVS Tags: ver_0_60_1, ver0_59_13, ver0_59_14, ver0_60_2, ver0_60_3, ver0_60_4, ver0_60_5, HEAD
Changes since 1.4: +0 -0 lines
File MIME type: text/x-csrc
*** empty log message ***

1 /* hiscore.c
2 ** generalized high score save/restore support
3 */
4
5 #include "driver.h"
6 #include "hiscore.h"
7
8 #define MAX_CONFIG_LINE_SIZE 48
9
10 #define VERBOSE 0
11
12 #if VERBOSE
13 #define LOG(x) logerror x
14 #else
15 #define LOG(x)
16 #endif
17
18 char *db_filename = "hiscore.dat"; /* high score definition file */
19
20 static struct
21 {
22 int hiscores_have_been_loaded;
23
24 struct mem_range
25 {
26 UINT32 cpu, addr, num_bytes, start_value, end_value;
27 struct mem_range *next;
28 } *mem_range;
29 } state;
30
31 /*****************************************************************************/
32
33 static void copy_to_memory (int cpu, int addr, const UINT8 *source, int num_bytes)
34 {
35 int i;
36 for (i=0; i<num_bytes; i++)
37 {
38 cpunum_write_byte (cpu, addr+i, source[i]);
39 }
40 }
41
42 static void copy_from_memory (int cpu, int addr, UINT8 *dest, int num_bytes)
43 {
44 int i;
45 for (i=0; i<num_bytes; i++)
46 {
47 dest[i] = cpunum_read_byte (cpu, addr+i);
48 }
49 }
50
51 /*****************************************************************************/
52
53 /* hexstr2num extracts and returns the value of a hexadecimal field from the
54 character buffer pointed to by pString.
55
56 When hexstr2num returns, *pString points to the character following
57 the first non-hexadecimal digit, or NULL if an end-of-string marker
58 (0x00) is encountered.
59
60 */
61 static UINT32 hexstr2num (const char **pString)
62 {
63 const char *string = *pString;
64 UINT32 result = 0;
65 if (string)
66 {
67 for(;;)
68 {
69 char c = *string++;
70 int digit;
71
72 if (c>='0' && c<='9')
73 {
74 digit = c-'0';
75 }
76 else if (c>='a' && c<='f')
77 {
78 digit = 10+c-'a';
79 }
80 else if (c>='A' && c<='F')
81 {
82 digit = 10+c-'A';
83 }
84 else
85 {
86 /* not a hexadecimal digit */
87 /* safety check for premature EOL */
88 if (!c) string = NULL;
89 break;
90 }
91 result = result*16 + digit;
92 }
93 *pString = string;
94 }
95 return result;
96 }
97
98 /* given a line in the hiscore.dat file, determine if it encodes a
99 memory range (or a game name).
100 For now we assume that CPU number is always a decimal digit, and
101 that no game name starts with a decimal digit.
102 */
103 static int is_mem_range (const char *pBuf)
104 {
105 char c;
106 for(;;)
107 {
108 c = *pBuf++;
109 if (c == 0) return 0; /* premature EOL */
110 if (c == ':') break;
111 }
112 c = *pBuf; /* character following first ':' */
113
114 return (c>='0' && c<='9') ||
115 (c>='a' && c<='f') ||
116 (c>='A' && c<='F');
117 }
118
119 /* matching_game_name is used to skip over lines until we find <gamename>: */
120 static int matching_game_name (const char *pBuf, const char *name)
121 {
122 while (*name)
123 {
124 if (*name++ != *pBuf++) return 0;
125 }
126 return (*pBuf == ':');
127 }
128
129 /*****************************************************************************/
130
131 /* safe_to_load checks the start and end values of each memory range */
132 static int safe_to_load (void)
133 {
134 struct mem_range *mem_range = state.mem_range;
135 while (mem_range)
136 {
137 if (cpunum_read_byte (mem_range->cpu, mem_range->addr) !=
138 mem_range->start_value)
139 {
140 return 0;
141 }
142 if (cpunum_read_byte (mem_range->cpu, mem_range->addr + mem_range->num_bytes - 1) !=
143 mem_range->end_value)
144 {
145 return 0;
146 }
147 mem_range = mem_range->next;
148 }
149 return 1;
150 }
151
152 /* hs_free disposes of the mem_range linked list */
153 static void hs_free (void)
154 {
155 struct mem_range *mem_range = state.mem_range;
156 while (mem_range)
157 {
158 struct mem_range *next = mem_range->next;
159 free (mem_range);
160 mem_range = next;
161 }
162 state.mem_range = NULL;
163 }
164
165 static void hs_load (void)
166 {
167 void *f = osd_fopen (Machine->gamedrv->name, 0, OSD_FILETYPE_HIGHSCORE, 0);
168 state.hiscores_have_been_loaded = 1;
169 LOG(("hs_load\n"));
170 if (f)
171 {
172 struct mem_range *mem_range = state.mem_range;
173 LOG(("loading...\n"));
174 while (mem_range)
175 {
176 UINT8 *data = malloc (mem_range->num_bytes);
177 if (data)
178 {
179 /* this buffer will almost certainly be small
180 enough to be dynamically allocated, but let's
181 avoid memory trashing just in case
182 */
183 osd_fread (f, data, mem_range->num_bytes);
184 copy_to_memory (mem_range->cpu, mem_range->addr, data, mem_range->num_bytes);
185 free (data);
186 }
187 mem_range = mem_range->next;
188 }
189 osd_fclose (f);
190 }
191 }
192
193 static void hs_save (void)
194 {
195 void *f = osd_fopen (Machine->gamedrv->name, 0, OSD_FILETYPE_HIGHSCORE, 1);
196 LOG(("hs_save\n"));
197 if (f)
198 {
199 struct mem_range *mem_range = state.mem_range;
200 LOG(("saving...\n"));
201 while (mem_range)
202 {
203 UINT8 *data = malloc (mem_range->num_bytes);
204 if (data)
205 {
206 /* this buffer will almost certainly be small
207 enough to be dynamically allocated, but let's
208 avoid memory trashing just in case
209 */
210 copy_from_memory (mem_range->cpu, mem_range->addr, data, mem_range->num_bytes);
211 osd_fwrite(f, data, mem_range->num_bytes);
212 }
213 mem_range = mem_range->next;
214 }
215 osd_fclose(f);
216 }
217 }
218
219 /*****************************************************************************/
220 /* public API */
221
222 /* call hs_open once after loading a game */
223 void hs_open (const char *name)
224 {
225 void *f = osd_fopen (NULL, db_filename, OSD_FILETYPE_HIGHSCORE_DB, 0);
226 state.mem_range = NULL;
227
228 LOG(("hs_open: '%s'\n", name));
229
230 if (f)
231 {
232 char buffer[MAX_CONFIG_LINE_SIZE];
233 enum { FIND_NAME, FIND_DATA, FETCH_DATA } mode;
234 mode = FIND_NAME;
235
236 while (osd_fgets (buffer, MAX_CONFIG_LINE_SIZE, f))
237 {
238 if (mode==FIND_NAME)
239 {
240 if (matching_game_name (buffer, name))
241 {
242 mode = FIND_DATA;
243 LOG(("hs config found!\n"));
244 }
245 }
246 else if (is_mem_range (buffer))
247 {
248 const char *pBuf = buffer;
249 struct mem_range *mem_range = malloc(sizeof(struct mem_range));
250 if (mem_range)
251 {
252 mem_range->cpu = hexstr2num (&pBuf);
253 mem_range->addr = hexstr2num (&pBuf);
254 mem_range->num_bytes = hexstr2num (&pBuf);
255 mem_range->start_value = hexstr2num (&pBuf);
256 mem_range->end_value = hexstr2num (&pBuf);
257
258 mem_range->next = NULL;
259 {
260 struct mem_range *last = state.mem_range;
261 while (last && last->next) last = last->next;
262 if (last == NULL)
263 {
264 state.mem_range = mem_range;
265 }
266 else
267 {
268 last->next = mem_range;
269 }
270 }
271
272 mode = FETCH_DATA;
273 }
274 else
275 {
276 hs_free();
277 break;
278 }
279 }
280 else
281 {
282 /* line is a game name */
283 if (mode == FETCH_DATA) break;
284 }
285 }
286 osd_fclose (f);
287 }
288 }
289
290 /* call hs_init when emulation starts, and when the game is reset */
291 void hs_init (void)
292 {
293 struct mem_range *mem_range = state.mem_range;
294 state.hiscores_have_been_loaded = 0;
295
296 while (mem_range)
297 {
298 cpunum_write_byte(
299 mem_range->cpu,
300 mem_range->addr,
301 ~mem_range->start_value
302 );
303
304 cpunum_write_byte(
305 mem_range->cpu,
306 mem_range->addr + mem_range->num_bytes-1,
307 ~mem_range->end_value
308 );
309 mem_range = mem_range->next;
310 }
311 }
312
313 /* call hs_update periodically (i.e. once per frame) */
314 void hs_update (void)
315 {
316 if (state.mem_range)
317 {
318 if (!state.hiscores_have_been_loaded)
319 {
320 if (safe_to_load()) hs_load();
321 }
322 }
323 }
324
325 /* call hs_close when done playing game */
326 void hs_close (void)
327 {
328 if (state.hiscores_have_been_loaded) hs_save();
329 hs_free();
330 }

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26