20100212
[gdash.git] / util / any2gdash.c
blob91e510fc93ae490071ce0292847db1495b31116e
1 /*
2 * Copyright (c) 2007, 2008 Czirkos Zoltan <cirix@fw.hu>
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 #include <stdio.h>
17 #include <assert.h>
18 #include <string.h>
20 /* identifiers in output file */
21 static const char *s_bd1="GDashBD1";
22 static const char *s_bd2="GDashBD2";
23 static const char *s_plc="GDashPLC";
24 static const char *s_pca="GDashPCA";
25 static const char *s_crl="GDashCRL";
26 static const char *s_cd7="GDashCD7";
27 static const char *s_1st="GDash1ST";
28 static const char *s_b1a="GDashB1A"; /* boulder dash 1, atari version */
29 static const char *s_b2a="GDashB2A"; /* boulder dash 2, atari version */
31 /* loaded memory map */
32 static unsigned char memory[65536];
33 static unsigned char out[65536];
34 static int outpos;
36 /* default effect table, taken from afl boulder dash. used to detect if
37 game-wide diego effects are present. */
38 static unsigned char default_effect[] = {
39 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x08, 0x09, 0x0a, 0x0b,
40 0x10, 0x10, 0x12, 0x12, 0x14, 0x14, 0x16, 0x16, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
41 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2a, 0x2c, 0x2d, 0x2e, 0x2f,
42 0x30, 0x31, 0x32, 0x33, 0x30, 0x31, 0x32, 0x33, 0x38, 0x38, 0x3a, 0x3a, 0x3c, 0x3d, 0x3e, 0x3f,
43 0x40, 0x60, 0x46, 0x4e, 0x22, 0x2e, 0x62, 0x2e, 0x4a, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64, 0x64,
44 0x64, 0x44, 0x44, 0x44, 0x44, 0x48, 0x48, 0x48, 0x48, 0x00, 0x00, 0x00, 0x66, 0x68, 0x6a, 0x68,
45 0x66, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x62, 0x66, 0x68, 0x6a, 0x00, 0x4e, 0x4e, 0x00, 0x00, 0x00,
46 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x4c, 0x4c, 0x40, 0x40, 0x42, 0x2e, 0x40,
50 /* load file, and fill memory map. returns true if success, prints error and returns false if fail */
51 static int loadfile(const char *filename)
53 const unsigned char magic[]={0x56, 0x49, 0x43, 0x45, 0x20, 0x53, 0x6E, 0x61, 0x70, 0x73, 0x68, 0x6F, 0x74, 0x20, 0x46, 0x69, 0x6C, 0x65, 0x1A, 0x01, 0x00, 0x43, 0x36, 0x34};
54 unsigned char buf[24];
55 int readbytes;
56 FILE *fin;
58 fin=fopen(filename, "rb");
59 if (!fin) {
60 printf("Cannot open file %s\n", filename);
61 return 0;
64 assert(sizeof(magic)==sizeof(buf));
65 readbytes=fread(buf, 1, sizeof(buf), fin);
66 if (readbytes!=sizeof(buf)) {
67 fclose(fin);
68 printf("Could not read %d bytes.\n", (int) sizeof(buf));
69 return 0;
72 if (memcmp(magic, buf, sizeof(buf))==0) {
73 /* FOUND a vice snapshot file. */
74 fseek(fin, 0x80, SEEK_SET);
75 readbytes=fread(memory, 1, 65536, fin);
76 if (readbytes!=65536) {
77 fclose(fin);
78 printf("Could not read 65536 bytes.\n");
79 return 0;
81 printf("%s is a proper vice snapshot.\n", filename);
82 fclose(fin);
83 return 1;
84 } else {
85 int filesize;
87 /* image map */
88 /* check size */
89 fseek(fin, 0, SEEK_END);
90 filesize=ftell(fin);
91 fseek(fin, 0, SEEK_SET);
93 /* 65538 bytes: we hope that this is a full-memory map saved by vice. check it. */
94 if (filesize==65538) {
95 /* check start address */
96 if (fgetc(fin)!=0 || fgetc(fin)!=0) {
97 fclose(fin);
98 printf("Memory map should begin from address 0000.\n");
99 printf("Use save \"filename\" 0 0000 ffff in vice monitor.\n");
100 return 0;
103 readbytes=fread(memory, 1, 65536, fin);
104 if (readbytes!=65536) {
105 fclose(fin);
106 printf("Could not read 65536 bytes\n.\n");
107 return 0;
110 printf("%s looks like a proper vice memory map.\n", filename);
111 fclose(fin);
112 return 1;
113 } else
114 /* or maybe a 64k map saved by atari800. read it. */
115 if (filesize==65536) {
116 readbytes=fread(memory, 1, 65536, fin);
117 if (readbytes!=65536) {
118 fclose(fin);
119 printf("Could not read 65536 bytes\n.\n");
120 return 0;
123 printf("%s lookslike a proper atari800 memory map.\n", filename);
124 fclose(fin);
125 return 1;
126 } else {
127 /* if not 65536, not 65538: report error. */
128 fclose(fin);
129 printf("Memory map file should be 65536+2 bytes long or 65536 bytes long.\n");
130 printf("Use save \"filename\" 0 0000 ffff in vice monitor.\n");
131 printf("Use write 0000 ffff filename in atari800 monitor.\n");
132 return 0;
135 assert(0);
136 return 0;
141 /* save bd1 caves from memory map */
142 /* atari: a boolean value, true if try atari map. */
143 static int try_bd1(int atari)
145 int i;
146 /* there are cave pointers at 0x5806. two byte entries pointing to caves. */
147 /* their value is relative to 0x582e. */
148 /* atari values are 3500 and 3528. */
149 int cavepointers=atari?0x3500:0x5806;
150 int cavestart=atari?0x3528:0x582e;
152 strcpy((char *)out, atari?s_b1a:s_bd1);
153 outpos=12;
154 printf("\n*** Trying to interpret BD1(e) caves...\n");
156 /* try to autodetect */
158 /* fixme what is this? */
159 if (!atari) {
160 if (memory[0x5f3a]!=0x44 || memory[0x5f3b]!=0x44 || memory[0x5f3c]!=0x48 || memory[0x5f3d]!=0x48) {
161 printf("Assumptions failed for BD1(e).\n");
162 return 0;
166 /* 4*5 (4 groups * 5 caves (4cave+1intermission)) */
167 for (i=0; i<4*5; i++) {
168 int lo, hi, j, pos, start;
170 lo=memory[cavepointers+i*2];
171 hi=memory[cavepointers+i*2+1];
172 start=pos=hi*256+lo+cavestart;
173 if (pos>(0xffff-0x0400)) {
174 printf("Cannot interpret memory contents as BD1(e) -- invalid cave pointer.\n");
175 return 0;
177 printf("Cave %d, addr: %04x\n", i+1, pos);
179 /* copy */
180 /* first 32 bytes - cave options */
181 for (j=0; j<32; j++)
182 out[outpos++]=memory[pos++]; /* 5levels: 5random, 5diamond, 5time */
184 /* now cave objects */
185 j=memory[pos++];
186 while (j!=0xFF) { /* végét jelenti; de kiírtuk ezt is */
187 if (pos-start > 0x400) {
188 /* bd1 caves cannot be this long */
189 printf("Cannot interpret memory contents as BD1(e) -- cave data too long.\n");
190 return 0;
192 out[outpos++]=j;
193 if (j==0x0F) {
194 /* crazy cream 3 extension: escape byte 0x0f means raster */
195 out[outpos++]=memory[pos++]; /* param byte 1: object to draw */
196 out[outpos++]=memory[pos++]; /* param byte 2: begin column */
197 out[outpos++]=memory[pos++]; /* param byte 3: begin row */
198 out[outpos++]=memory[pos++]; /* param byte 4: amount of rows */
199 out[outpos++]=memory[pos++]; /* param byte 5: amount of columns */
200 out[outpos++]=memory[pos++]; /* param byte 6: distance between rows */
201 out[outpos++]=memory[pos++]; /* param byte 7: distance between columns */
202 } else {
203 switch (j>>6) {
204 case 0: /* point */
205 out[outpos++]=memory[pos++]; /* x */
206 out[outpos++]=memory[pos++]; /* y */
207 break;
208 case 1: /* line */
209 out[outpos++]=memory[pos++]; /* x */
210 out[outpos++]=memory[pos++]; /* y */
211 out[outpos++]=memory[pos++]; /* len */
212 out[outpos++]=memory[pos++]; /* dir */
213 break;
214 case 2: /* fillrect */
215 out[outpos++]=memory[pos++]; /* x */
216 out[outpos++]=memory[pos++]; /* y */
217 out[outpos++]=memory[pos++]; /* w */
218 out[outpos++]=memory[pos++]; /* h */
219 out[outpos++]=memory[pos++]; /* fill */
220 break;
221 case 3: /* outline */
222 out[outpos++]=memory[pos++]; /* x */
223 out[outpos++]=memory[pos++]; /* y */
224 out[outpos++]=memory[pos++]; /* w */
225 out[outpos++]=memory[pos++]; /* h */
226 break;
229 j=memory[pos++];
231 out[outpos++]=j; /* lezáró 0xff kiírása */
233 printf("Found %d BD1 caves!\n", 20);
234 return 1;
238 /* save plck caves from c64 memory map */
239 static int try_plck()
241 int x, i;
242 int has_names;
243 int has_diego=0;
244 int valid;
245 int ok;
247 strcpy((char *)out, s_plc);
248 outpos=12;
249 printf("\n*** Trying to interpret PLCK caves...\n");
250 /* try plck */
251 valid=0;
252 ok=0;
254 /* try to detect plck cave selection table. assume there are at least 5 caves. */
255 /* selection table without names. */
256 for (x=0; x<5; x++)
257 if (memory[0x5e8b+x]==0x0e || memory[0x5e8b+x]==0x19)
258 ok++;
259 if (ok==5) {
260 valid=1;
261 has_names=0;
264 /* selection table with names. */
265 ok=0;
266 for (x=0; x<5; x++)
267 if (memory[0x5e8b+13*x+12]==0x0e || memory[0x5e8b+13*x+12]==0x19)
268 ok++;
269 if (ok==5) {
270 valid=1;
271 has_names=1;
273 if (!valid) {
274 printf("Assumptions failed for PLCK - could not find cave selection table.\n");
275 return 0;
278 printf(has_names?"PLCK caves have names.\n":"PLCK caves have no names.\n");
280 i=0;
281 /* while present and (selectable or nonselectable) <- find any valid byte in cave selection table. */
282 while ((!has_names && (memory[0x5e8b+i]!=0 && (memory[0x5e8b+i]==0x0e || memory[0x5e8b+i]==0x19)))
283 || (has_names && (memory[0x5e8b+i*13+12]!=0 && (memory[0x5e8b+i*13+12]==0x0e || memory[0x5e8b+i*13+12]==0x19)))) {
284 int j, pos, zero;
286 pos=0x7000+0x200*i;
288 /* check if memory is not filled with zeroes. */
289 zero=1;
290 for (j=0; j<512 && zero; j++)
291 if (memory[pos+j]!=0)
292 zero=0;
293 if (zero)
294 break;
296 /* check for error */
297 if (i>71) {
298 /* caves cannot be this long */
299 printf("Data corrupt or detection failed for plck caves -- too many caves.\n");
300 return 0;
303 printf("Cave %d, addr: %04x ", i+1, pos);
304 if (memory[pos+0x1e5]==0x20 && memory[pos+0x1e6]==0x90 && memory[pos+0x1e7]==0x46) {
305 printf("- has diego effects.");
306 has_diego=1;
308 printf("\n");
310 /* copy 1f0 bytes for cave */
311 for (j=0; j<0x1f0; ++j)
312 out[outpos++]=memory[pos++];
314 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
315 if (has_names) { /* we detected that it has names */
316 out[outpos++]=memory[0x5e8b+i*13+12];
317 out[outpos++]=memory[0x5e8b+i*13+12]+1; /* save twice, add +1 for second for detection in gdash */
318 if (memory[0x5e8b+i*13+12]!=0x0e && memory[0x5e8b+i*13+12]!=0x19)
319 printf("ERROR: cave selection table corrupt or autodetection failed?\n");
320 for (j=0; j<12; j++)
321 out[outpos++]=memory[0x5e8b+i*13+j];
322 out[outpos++]=0; /* fill the rest with zero */
323 out[outpos++]=0;
325 else { /* no names */
326 out[outpos++]=memory[0x5e8b+i];
327 out[outpos++]=memory[0x5e8b+i]+1; /* save twice for detection, add 1 to second one */
328 if (memory[0x5e8b+i]!=0x0e && memory[0x5e8b+i]!=0x19)
329 printf("ERROR: cave selection table corrupt or autodetection failed?\n");
330 for (j=2; j<16; j++)
331 out[outpos++]=0;
334 i++;
336 printf("Found %d PLCK caves in %d bytes!\n", i, outpos);
338 /* now try to do something about diego effects. */
339 /* if we found at least one cave with diego effects, this check can be skipped. */
340 if (!has_diego) {
341 int j;
342 const int numbers=sizeof(default_effect)/sizeof(default_effect[0]);
343 char diffs[numbers];
344 int n;
346 /* check effect table from memory at 3b00. */
347 n=0;
348 for (j=0; j<numbers; j++)
349 if (default_effect[j]!=memory[0x3b00+j]) {
350 n++;
351 diffs[j]=1;
352 } else
353 diffs[j]=0;
354 if (n!=0) {
355 /* found an unstandard effect table */
356 int b_stone_to=memory[0x3b00 + 0x11];
357 int f_diamond_to=memory[0x3b00 + 0x17];
358 int explosion_to=memory[0x3b00 + 0x1e];
359 int dirt_pointer=memory[0x3b00 + 0x42];
360 int growing_pointer=memory[0x3b00 + 0x6b];
362 /* report effect table changes that we are able to convert to the per cave description. */
363 printf ("Found global diego effects!\n");
364 if (b_stone_to != 0x10)
365 printf (" - Effect for bouncing stone.\n");
366 if (f_diamond_to != 0x16)
367 printf (" - Effect for falling diamond.\n");
368 if (explosion_to != 0x1e)
369 printf (" - Effect for explosion.\n");
370 if (dirt_pointer != 0x46)
371 printf (" - Dirt looks like effect.\n");
372 if (growing_pointer != 0x4e)
373 printf (" - Growing wall looks like effect.\n");
375 /* go through all caves and add no1v5.3e compatible flags */
376 for (j=0; j<i; j++) {
377 /* flags used previously on c64; gdash also knows them */
378 out[12+0x0200*j+0x1e5]=0x20;
379 out[12+0x0200*j+0x1e6]=0x90;
380 out[12+0x0200*j+0x1e7]=0x46;
382 /* set detected stuff for cave */
383 out[12+0x0200*j+0x1ea]=b_stone_to;
384 out[12+0x0200*j+0x1eb]=f_diamond_to;
385 out[12+0x0200*j+0x1ec]=explosion_to;
386 out[12+0x0200*j+0x1ed]=dirt_pointer;
387 out[12+0x0200*j+0x1ee]=growing_pointer;
388 out[12+0x0200*j+0x1ef]=200; /* FIXME AMOEBA THRESHOLD */
391 /* null out effects we could handle */
392 diffs[0x11]=0;
393 diffs[0x17]=0;
394 diffs[0x1e]=0;
395 diffs[0x42]=0;
396 diffs[0x6b]=0;
397 /* check if growing wall (delayed)==growing wall in terms of graphics, if it is, then it is no diff to original */
398 if (memory[0x3b00+0x6b]==memory[0x3b00+0x6c])
399 diffs[0x6c]=0;
401 /* and check if there are others we cannot fit into a "standard" cawe */
402 for (j=0; j<numbers; j++)
403 if (diffs[j]) {
404 printf("*** Don't know how to handle effect for element number %x, default %x, this one %x\n", j, default_effect[j], memory[0x3b00+j]);
407 return 1;
412 /* save plck caves from atari memory map */
413 static int try_atari_plck()
415 int x, i;
416 int ok;
417 int has_diego=0;
418 int has_selection;
420 strcpy((char *)out, s_pca);
421 outpos=12;
422 printf("\n*** Trying to interpret Atari PLCK caves...\n");
423 /* try plck */
424 ok=0;
426 /* try to detect the cave selection table. assume there are at least 5 caves. */
427 /* example:
428 6040: 66 60 4A 41 49 4C 20 20 20 20 2E 43 41 56 59 53 f.JAIL .CAVYS
429 6050: 41 46 45 20 20 20 20 2E 43 41 56 59 52 41 49 4E AFE .CAVYRAIN
430 6060: 20 20 20 20 2E 43 41 56 59 45 53 43 41 50 41 44 .CAVYESCAPAD
431 6070: 45 2E 43 41 56 59 43 48 41 53 45 20 20 20 2E 49 E.CAVYCHASE .I
432 6080: 4E 54 4E 52 45 53 43 55 45 20 20 2E 43 41 56 59 NTNRESCUE .CAVY
433 we detect the Y's and N's after CAV or INT
436 /* caves are preceded with $ab $ab $ab $ab CAVENAME */
438 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV.
439 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
440 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
442 /* try to detect this; assume at least 5 caves. */
443 ok=0;
444 for (x=0; x<5; x++) {
445 int pos=0x6ff0 + x*0x200;
446 if (memory[pos]==0xAB && memory[pos+1]==0xAB && memory[pos+2]==0xAB && memory[pos+3]==0xAB)
447 ok++;
449 if (ok!=5) {
450 printf("Assumptions failed for Atari PLCK - could not find $ab $ab $ab $ab before caves.\n");
451 return 0;
454 /* check if it has a selection table */
455 ok=0;
456 for (x=0; x<5; x++) {
457 if (memory[0x604e + x*13]=='Y' || memory[0x604e + x*13]=='N')
458 ok++;
460 has_selection=(ok==5);
461 if (has_selection)
462 printf("Found selection table.\n");
467 i=0;
468 /* detect caves by $ab bytes before them */
469 while (memory[0x6ff0+i*0x200]==0xAB && memory[0x6ff1+i*0x200]==0xAB && memory[0x6ff2+i*0x200]==0xAB && memory[0x6ff3+i*0x200]==0xAB) {
470 int j, pos;
471 int selectable;
473 pos=0x7000+0x200*i;
474 if (has_selection)
475 selectable=memory[0x604e + i*13]=='Y';
476 else
477 /* has no selection table... we make intermissions unselectable. */
478 selectable=memory[pos + 0x1da]==0;
480 /* check for error */
481 if (i>71) {
482 /* caves cannot be this long */
483 printf("Data corrupt or detection failed for plck caves -- too many caves.\n");
484 return 0;
487 printf("Cave %d, addr: %04x, sel: %d", i+1, pos, selectable);
488 if (memory[pos+0x1e5]==0x20 && memory[pos+0x1e6]==0x90 && memory[pos+0x1e7]==0x46) {
489 printf("- has diego effects.");
490 has_diego=1;
492 printf("\n");
494 /* copy 1f0 bytes for cave */
495 for (j=0; j<0x1f0; ++j)
496 out[outpos++]=memory[pos++];
498 /* and fill the rest with our own data. this way we stay compatible, as cave was always 1f0 bytes */
499 /* we have to stay compatible with c64 plck import routine above. */
500 /* so we use 0x19 for selectable caves, 0x0e for nonselectable. */
501 out[outpos++]=selectable?0x19:0x0e;
502 out[outpos++]=(selectable?0x19:0x0e)+1; /* save twice, add +1 for second for detection in gdash */
503 /* copy cave name, which is:
504 6FE0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
505 6FF0: AB AB AB AB 4A 41 49 4C 2E 43 41 56 9B 20 20 20 ....JAIL.CAV. ... cave name
506 7000: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD ... cave data
507 7010: 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 DDDDDDDDDDDDDDDD
508 7020: 44 44 44 44 44 44 44 44 4E 77 77 77 77 77 77 77 DDDDDDDDNwwwwwww
511 pos=0x7000+0x200*i;
512 for (j=0; j<12; j++) {
513 unsigned char c=memory[pos-0x10+4+j];
515 /* somehow this character set the end-of-string in atari version */
516 if (c==0x9b)
517 c=0x20;
518 out[outpos++]=c;
520 out[outpos++]=0; /* fill the rest with zero */
521 out[outpos++]=0;
523 i++;
525 printf("Found %d PLCK caves in %d bytes!\n", i, outpos);
527 return 1;
532 /* save crazy light caves from memory map */
533 static int try_crli()
535 int x, i, b, caves;
537 strcpy((char *)out, s_crl);
538 outpos=12;
540 /* try autodetect */
541 printf("\n*** Trying to interpret crazy light caves...\n");
542 b=1;
543 if (memory[0x6ffc]!='V' || memory[0x6ffd]!='3' || memory[0x6ffe]!='.' || memory[0x6fff]!='0') /* version string */
544 b=0;
545 for (x=0x7060; x<0x7090; x++) /* cave selection table */
546 if (memory[x]!=0 && memory[x]!=1 && memory[x]!=255)
547 b=0;
548 if (!b) {
549 printf("Assumptions failed for crazy light.\n");
550 return 0;
553 caves=0;
554 for (i=0; i<48; i++)
555 if (memory[0x7060+i]!=0xFF) {
556 int j, n;
557 int startpos, pos;
558 int cavepos;
560 caves++;
562 startpos=memory[0x7000+i] + memory[0x7030+i]*256L;
563 pos=startpos;
564 printf("Cave %d, addr: %04x (%d), ", caves, pos, pos);
565 cavepos=0;
566 /* 'decompress' data, to see how many bytes there are */
567 while (cavepos < 0x3b0) { /* <- loop until the uncompressed reaches its size */
568 if (memory[pos] == 0xbf) {
569 /* escaped byte */
570 cavepos+=memory[pos+2]; /* number of bytes */
571 pos += 3;
573 else {
574 /* plain data */
575 cavepos++;
576 pos++;
579 pos+=14; /* add 14 bytes for name */
580 n=pos-startpos; /* bytes to copy */
581 startpos-=14; /* name is BEFORE the cave data */
582 printf("length %d bytes\n", n);
584 out[outpos++]=memory[0x7060+i]; /* is_selectable */
585 for (j=0; j<n; j++)
586 out[outpos++]=memory[startpos++];
588 printf("Found %d crazy light caves in %d bytes!\n", caves, outpos);
589 return 1;
592 static int
593 try_crdr()
595 int i, b, caves;
597 strcpy((char *)out, s_cd7);
598 outpos=12;
600 /* try autodetect */
601 printf("\n*** Trying to interpret crazy dream caves...\n");
602 b=1;
603 // if (memory[0x6ffc]!='V' || memory[0x6ffd]!='3' || memory[0x6ffe]!='.' || memory[0x6fff]!='0') /* version string */
604 // b=0;
606 caves=0;
607 for (i=0; i<20; i++) {
608 int j, n;
609 int startpos, pos;
611 caves++;
613 startpos=memory[0x7500+i] + memory[0x7580+i]*256L;
614 pos=startpos;
615 printf("Cave %d, addr: %04x (%d), ", caves, pos, pos);
617 /* name */
618 for (j=0; j<14; j++)
619 out[outpos++]=memory[0x8c00+i*16+j];
621 /* selectable */
622 /* XXX seems to be broken; rather set unselectable intermissions */
623 out[outpos++]=/*memory[0x7410+caves]*/(caves%5)!=0;
625 /* cave data */
626 for (j=0; j<0x49; j++)
627 out[outpos++]=memory[pos++];
628 /* cave objects */
629 while (memory[pos]!=0xff) {
630 printf("%x ", memory[pos]);
631 switch(memory[pos]) {
632 case 1: /* point */
633 for (j=0; j<4; j++)
634 out[outpos++]=memory[pos++];
635 break;
636 case 2: /* rectangle */
637 for (j=0; j<6; j++)
638 out[outpos++]=memory[pos++];
639 break;
640 case 3: /* fillrect */
641 for (j=0; j<6; j++)
642 out[outpos++]=memory[pos++];
643 break;
644 case 4: /* line */
645 for (j=0; j<6; j++)
646 out[outpos++]=memory[pos++];
647 break;
648 case 6: /* ??? */
649 printf("[");
650 for (j=0; j<5; j++) {
651 printf("%02x ", memory[pos]);
652 out[outpos++]=memory[pos++];
654 printf("]");
655 break;
656 case 7: /* ??? */
657 printf("[");
658 for (j=0; j<3; j++) {
659 printf("%02x ", memory[pos]);
660 out[outpos++]=memory[pos++];
662 printf("]");
663 break;
664 case 11: /* raster */
665 for (j=0; j<8; j++)
666 out[outpos++]=memory[pos++];
667 break;
668 default:
669 printf("\n*** Unknown crdr object code %x...\n", memory[pos]);
670 for (j=0; j<50; j++) {
671 printf("%02x ", memory[pos]);
672 out[outpos++]=memory[pos++];
674 return 0;
675 break;
678 out[outpos++]=memory[pos++]; /* copy $ff */
679 n=pos-startpos; /* bytes to copy */
680 printf("length %d bytes\n", n);
682 printf("Found %d crazy dream caves in %d bytes!\n", caves, outpos);
683 return 1;
688 /* save bd2 caves from memory map */
689 static int try_bd2()
691 int i;
692 int unsupported=0, uns[256];
694 /* 256 counters for the 256 possible bytes (8bit). mark each unsupported extension found. */
695 /* if more than 5 types found, bail out with error */
696 for (i=0; i<256; ++i)
697 uns[i]=0;
699 strcpy((char *)out, s_bd2);
700 outpos=12;
701 printf("\n*** Trying to interpret BD2 caves...\n");
703 /* 4*5 (4 groups * 5 caves (4cave+1intermission)) */
704 for (i=0; i<4*5; i++) {
705 int lo, hi, j, pos, start;
706 int amount, n, mappos;
708 lo=0x89b0+i*2;
709 hi=0x89b0+i*2+1;
710 start=pos=memory[hi]*256L+memory[lo];
711 if (pos> (0xffff-0x0400)) {
712 printf("Cannot interpret memory contents as BD2 -- invalid cave pointer.\n");
713 return 0;
715 if (i<16)
716 printf("Cave %c, addr: %04x\n", i+'A', pos);
717 else
718 printf("Intermission %d, addr: %04x\n", i-15, pos);
720 /* copy */
721 /* first bytes: cave options */
722 for (j=0; j<=0x19; j++)
723 out[outpos++]=memory[pos++]; /* cave options */
725 j=memory[pos++];
726 while (j!=0xFF) { /* végét jelenti; de kiírtuk ezt is */
727 if (pos-start > 0x400) {
728 /* bd1 caves cannot be this long */
729 printf("Data corrupt or detection failed for bd2 caves -- cave data too long.\n");
730 return 0;
732 out[outpos++]=j;
733 switch (j) {
734 case 0: /* line */
735 out[outpos++]=memory[pos++]; /* obj */
736 out[outpos++]=memory[pos++]; /* y */
737 out[outpos++]=memory[pos++]; /* x */
738 out[outpos++]=memory[pos++]; /* dir */
739 out[outpos++]=memory[pos++]; /* len */
740 break;
741 case 1: /* rectangle (outline) */
742 out[outpos++]=memory[pos++]; /* obj */
743 out[outpos++]=memory[pos++]; /* y */
744 out[outpos++]=memory[pos++]; /* x */
745 out[outpos++]=memory[pos++]; /* h */
746 out[outpos++]=memory[pos++]; /* w */
747 break;
748 case 2: /* fillrect */
749 out[outpos++]=memory[pos++]; /* obj */
750 out[outpos++]=memory[pos++]; /* y */
751 out[outpos++]=memory[pos++]; /* x */
752 out[outpos++]=memory[pos++]; /* h */
753 out[outpos++]=memory[pos++]; /* w */
754 out[outpos++]=memory[pos++]; /* fillobj */
755 break;
756 case 3: /* point */
757 out[outpos++]=memory[pos++]; /* obj */
758 out[outpos++]=memory[pos++]; /* y */
759 out[outpos++]=memory[pos++]; /* x */
760 break;
761 case 4: /* raster */
762 out[outpos++]=memory[pos++]; /* obj */
763 out[outpos++]=memory[pos++]; /* y */
764 out[outpos++]=memory[pos++]; /* x */
765 out[outpos++]=memory[pos++]; /* h */
766 out[outpos++]=memory[pos++]; /* w */
767 out[outpos++]=memory[pos++]; /* dy */
768 out[outpos++]=memory[pos++]; /* dx */
769 break;
770 case 5: /* profi boulder extension: bitmap */
771 out[outpos++]=memory[pos++]; /* obj */
772 amount=memory[pos++];
773 out[outpos++]=amount; /* amount */
774 out[outpos++]=memory[pos++]; /* target msb */
775 out[outpos++]=memory[pos++]; /* target lsb */
776 for (n=0; n<amount; ++n)
777 out[outpos++]=memory[pos++]; /* data */
778 break;
779 case 6: /* join */
780 out[outpos++]=memory[pos++]; /* add to this */
781 out[outpos++]=memory[pos++]; /* add this */
782 out[outpos++]=memory[pos++]; /* dy*40+dx */
783 break;
784 case 7: /* slime permeabilty */
785 out[outpos++]=memory[pos++]; /* perm */
786 break;
787 case 9: /* profi boulder extension: plck map */
788 lo=memory[pos++];
789 hi=memory[pos++];
790 mappos=hi*256+lo;
791 out[outpos++]=memory[pos++]; /* inbox y */
792 out[outpos++]=memory[pos++]; /* inbox x */
793 for (n=0; n<40*(22-2)/2; n++) /* 40*20 caves, upper and lower row not contained, 1byte/2 elements */
794 out[outpos++]=memory[mappos+n];
795 break;
796 default:
797 if (uns[j]==0) {
798 /* not seen this extension previously */
799 printf(" Found unsupported bd2 extension n.%d\n", j);
800 unsupported++;
801 uns[j]=1; /* mark the newly found unknown extension */
803 if (unsupported>5) {
804 /* found to many unsupported extensions - this can't be bd2 */
805 printf("Data corrupt or detection failed for bd2 caves --\n too many unknown extensions.\n");
806 return 0;
808 break;
810 j=memory[pos++]; /* read next */
812 out[outpos++]=j; /* closing 0xff */
813 out[outpos++]=memory[pos++]; /* animation */
815 /* color table */
816 lo=0x89d8+i*2;
817 hi=0x89d8+i*2+1;
818 pos=memory[hi]*256L+memory[lo]; /* pointer to the three colors */
819 out[outpos++]=memory[pos++];
820 out[outpos++]=memory[pos++];
821 out[outpos++]=memory[pos++];
824 return 1;
829 /* save bd2 caves from memory map */
830 static int try_bd2_atari()
832 const int cavepointers=0x86b0;
833 const int cavecolors=0x86d8;
834 int i;
835 int unsupported=0, uns[256];
837 /* 256 counters for the 256 possible bytes (8bit). mark each unsupported extension found. */
838 /* if more than 5 types found, bail out with error */
839 for (i=0; i<256; ++i)
840 uns[i]=0;
842 strcpy((char *)out, s_b2a);
843 outpos=12;
844 printf("\n*** Trying to interpret Atari BD2 caves...\n");
846 /* 4*5 (4 groups * 5 caves (4cave+1intermission)) */
847 for (i=0; i<4*5; i++) {
848 int lo, hi, j, pos, start;
849 int amount, n, mappos;
851 lo=cavepointers+i*2;
852 hi=cavepointers+i*2+1;
853 start=pos=memory[hi]*256L+memory[lo];
854 if (pos> (0xffff-0x0400)) {
855 printf("Cannot interpret memory contents as BD2 -- invalid cave pointer.\n");
856 return 0;
858 if (i<16)
859 printf("Cave %c, addr: %04x\n", i+'A', pos);
860 else
861 printf("Intermission %d, addr: %04x\n", i-15, pos);
863 /* copy */
864 /* first bytes: cave options */
865 for (j=0; j<=0x19; j++)
866 out[outpos++]=memory[pos++]; /* cave options */
868 j=memory[pos++];
869 while (j!=0xFF) { /* végét jelenti; de kiírtuk ezt is */
870 if (pos-start > 0x400) {
871 /* bd1 caves cannot be this long */
872 printf("Data corrupt or detection failed for bd2 caves -- cave data too long.\n");
873 return 0;
875 out[outpos++]=j;
876 switch (j) {
877 case 0: /* line */
878 out[outpos++]=memory[pos++]; /* obj */
879 out[outpos++]=memory[pos++]; /* y */
880 out[outpos++]=memory[pos++]; /* x */
881 out[outpos++]=memory[pos++]; /* dir */
882 out[outpos++]=memory[pos++]; /* len */
883 break;
884 case 1: /* rectangle (outline) */
885 out[outpos++]=memory[pos++]; /* obj */
886 out[outpos++]=memory[pos++]; /* y */
887 out[outpos++]=memory[pos++]; /* x */
888 out[outpos++]=memory[pos++]; /* h */
889 out[outpos++]=memory[pos++]; /* w */
890 break;
891 case 2: /* fillrect */
892 out[outpos++]=memory[pos++]; /* obj */
893 out[outpos++]=memory[pos++]; /* y */
894 out[outpos++]=memory[pos++]; /* x */
895 out[outpos++]=memory[pos++]; /* h */
896 out[outpos++]=memory[pos++]; /* w */
897 out[outpos++]=memory[pos++]; /* fillobj */
898 break;
899 case 3: /* point */
900 out[outpos++]=memory[pos++]; /* obj */
901 out[outpos++]=memory[pos++]; /* y */
902 out[outpos++]=memory[pos++]; /* x */
903 break;
904 case 4: /* raster */
905 out[outpos++]=memory[pos++]; /* obj */
906 out[outpos++]=memory[pos++]; /* y */
907 out[outpos++]=memory[pos++]; /* x */
908 out[outpos++]=memory[pos++]; /* h */
909 out[outpos++]=memory[pos++]; /* w */
910 out[outpos++]=memory[pos++]; /* dy */
911 out[outpos++]=memory[pos++]; /* dx */
912 break;
913 case 5: /* profi boulder extension: bitmap */
914 out[outpos++]=memory[pos++]; /* obj */
915 amount=memory[pos++];
916 out[outpos++]=amount; /* amount */
917 out[outpos++]=memory[pos++]; /* target msb */
918 out[outpos++]=memory[pos++]; /* target lsb */
919 for (n=0; n<amount; ++n)
920 out[outpos++]=memory[pos++]; /* data */
921 break;
922 case 6: /* join */
923 out[outpos++]=memory[pos++]; /* add to this */
924 out[outpos++]=memory[pos++]; /* add this */
925 out[outpos++]=memory[pos++]; /* dy*40+dx */
926 break;
927 case 7: /* slime permeabilty */
928 out[outpos++]=memory[pos++]; /* perm */
929 break;
930 case 9: /* profi boulder extension: plck map */
931 lo=memory[pos++];
932 hi=memory[pos++];
933 mappos=hi*256+lo;
934 out[outpos++]=memory[pos++]; /* inbox y */
935 out[outpos++]=memory[pos++]; /* inbox x */
936 for (n=0; n<40*(22-2)/2; n++) /* 40*20 caves, upper and lower row not contained, 1byte/2 elements */
937 out[outpos++]=memory[mappos+n];
938 break;
939 default:
940 if (uns[j]==0) {
941 /* not seen this extension previously */
942 printf(" Found unsupported bd2 extension n.%d\n", j);
943 unsupported++;
944 uns[j]=1; /* mark the newly found unknown extension */
946 if (unsupported>5) {
947 /* found to many unsupported extensions - this can't be bd2 */
948 printf("Data corrupt or detection failed for bd2 caves --\n too many unknown extensions.\n");
949 return 0;
951 break;
953 j=memory[pos++]; /* read next */
955 out[outpos++]=j; /* closing 0xff */
956 out[outpos++]=memory[pos++]; /* animation bits */
958 /* color table */
959 lo=cavecolors+i*2;
960 hi=cavecolors+i*2+1;
961 pos=memory[hi]*256L+memory[lo]; /* pointer to the three colors */
962 out[outpos++]=memory[pos++];
963 out[outpos++]=memory[pos++];
964 out[outpos++]=memory[pos++];
965 out[outpos++]=memory[pos++]; /* slime and amoeba color */
966 out[outpos++]=memory[pos++]; /* background (and border) */
969 return 1;
973 /* save plck caves from memory map */
974 static int try_1stb()
976 int i;
978 strcpy((char *)out, s_1st);
979 outpos=12;
980 printf("\n*** Trying to interpret 1stb caves...\n");
982 /* there must be 20 caves, according to bd inside faq. */
983 for (i=0; i<20; i++) {
984 int j;
985 int pos=0x7010+0x400*i;
987 /* 1stb caves have cave time, diamonds and the like encoded in bcd numbers,
988 one digit in each bytes. check that. */
989 for (j=0x370; j<0x379+3; j++)
990 if (memory[pos+j]>9) {
991 printf("Data corrupt or detection failed for 1stb caves.\n");
992 return 0;
994 printf("Cave %d, addr: %04x\n", i+1, pos);
996 for (j=0; j<0x400; ++j)
997 out[outpos++]=memory[pos++];
999 printf("Found %d 1stb caves!\n", i);
1000 return 1;
1004 static int save(const char *outname)
1006 FILE *fout;
1007 int written;
1009 /* write data length in little endian */
1010 out[8]=((outpos-12))&0xff;
1011 out[9]=((outpos-12)>>8)&0xff;
1012 out[10]=((outpos-12)>>16)&0xff;
1013 out[11]=((outpos-12)>>24)&0xff;
1015 /* output */
1016 fout=fopen(outname, "wb");
1017 if (!fout) {
1018 printf("Cannot open outfile %s\n", outname);
1019 return 0;
1021 written=fwrite(out, 1, outpos, fout);
1022 if (written!=outpos || fclose(fout)!=0) {
1023 printf("File write error to %s\n", outname);
1024 return 0;
1027 printf("Saved to %s\n", outname);
1028 return 1;
1033 int main(int argc, char* argv[])
1035 char outfilename[512];
1036 int result;
1038 if (argc<2 || argc>3) {
1039 printf("Converts memory dumps or vice snapshots of bd games\n");
1040 printf("to formats loadable by gdash.\n");
1041 printf("\n");
1042 printf("Usage: %s <inputfile> [outputfile]\n", argv[0]);
1043 printf(" where inputfile is a memory map or a vice snapshot.\n");
1044 printf("\n");
1045 printf("Use Alt-F11 or Alt-S in vice to create a snapshot file (*.vsf),\n");
1046 printf("or the monitor command s \"filename\" 0 0 ffff for memory contents.\n");
1047 printf("\n");
1048 printf("Beware that memory contents depend on actual memory pages set for cpu,\n");
1049 printf("so snapshot is better. Also load the game completely: wait until the\n");
1050 printf("usual scrolling screen appears, where you press f1 or fire.\n");
1051 printf("Proper extension is added to output file automatically.\n");
1052 printf("\n");
1053 printf("Engines supported: BD1, BD2, PLCK, 1stB, CrLi.\n");
1054 printf("Game-wide Diego effects are also supported, and converted to\n");
1055 printf("cave-specific effects. Unknown effects are reported, so check\n");
1056 printf("output!");
1058 return 0;
1061 if (!loadfile(argv[1]))
1062 return -1;
1063 /* if second cmdline option, treat as output filename */
1064 if (argc==3)
1065 strcpy(outfilename, argv[2]);
1066 else {
1067 strcpy(outfilename, argv[1]); /* use input file name, and change extension */
1069 /* output filename part */
1070 strcpy(outfilename, argv[1]);
1071 if (strchr(outfilename, '/') || strchr(outfilename, '\\')) {
1072 /* yes we have a pathname. */
1073 char *sep, *dot;
1074 sep=strrchr(outfilename, '/');
1075 if (!sep) /* XXX should use #define for windows code */
1076 sep=strrchr(outfilename, '\\');
1077 dot=strrchr(outfilename, '.');
1078 if ((dot-sep) > 1) /* dot later than last separator; >1 ensures that filename is not sg like .asd */
1079 *dot='\0';
1080 } else {
1081 /* we have no pathname */
1082 char *dot=strrchr(outfilename, '.');
1084 /* if we have extension, and filename is not only an extension :) */
1085 if (dot || dot!=outfilename)
1086 *dot='\0';
1090 /* interpreting */
1091 strcat(outfilename, ".gds");
1092 if (try_plck()) {
1093 result=!save(outfilename);
1094 } else
1095 if (try_atari_plck()) {
1096 result=!save(outfilename);
1097 } else
1098 if (try_bd1(0)) { /* try c64 bd1 */
1099 result=!save(outfilename);
1100 } else
1101 if (try_bd1(1)) { /* try atari bd1 */
1102 result=!save(outfilename);
1103 } else
1104 if (try_bd2()) { /* try c64 bd2 */
1105 result=!save(outfilename);
1106 } else
1107 if (try_bd2_atari()) { /* try atari bd2 */
1108 result=!save(outfilename);
1109 } else
1110 if (try_crli()) {
1111 result=!save(outfilename);
1112 } else
1113 if (try_1stb()) {
1114 result=!save(outfilename);
1115 } else
1116 if (try_crdr()) {
1117 result=!save(outfilename);
1118 } else {
1119 printf("Could not export cave data -- unknown cave format!\n");
1120 result=-1;
1123 return result;