1 /*
2
3 Copyright 2021, dettus@dettus.net
4
5 Redistribution and use in source and binary forms, with or without modification,
6 are permitted provided that the following conditions are met:
7
8 1. Redistributions of source code must retain the above copyright notice, this
9 list of conditions and the following disclaimer.
10
11 2. Redistributions in binary form must reproduce the above copyright notice,
12 this list of conditions and the following disclaimer in the documentation
13 and/or other materials provided with the distribution.
14
15 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26
27 */
28
29 // the purpose of this file is to read the D64 disk image files
30 // and to translate them into the .mag/.gfx format.
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include "loader_d64.h"
36 #include "loader_common.h"
37 #include "configuration.h"
38 #include "vm68k_macros.h"
39
40 #define D64_IMAGESIZE 174848
41 #define D64_TRACKNUM 40
42 #define D64_SECTORSIZE 256
43 #define D64_MAXENTRIES 64
44 #define D64_BITMASKSIZE 6080 // pictures have a resolution of 160x152 pixels
45
46 typedef enum _eGame
47 {
48 GAME_UNKNOWN,
49 GAME_JINXTER,
50 GAME_CORRUPTION,
51 GAME_FISH,
52 GAME_MYTH,
53 GAME_PAWN,
54 GAME_GUILD
55 } eGame;
56
57 typedef enum _eFileType
58 {
59 TYPE_UNKNOWN,
60 TYPE_CODE1,
61 TYPE_CODE2,
62 TYPE_CODE1_ENCRYPTED,
63 TYPE_CODE2_ENCRYPTED,
64 TYPE_STRING1,
65 TYPE_STRING2,
66 TYPE_DICTIONARY,
67 TYPE_PICTURE,
68 TYPE_CAMEO
69 } eFileType;
70
71 typedef struct _tFileEntry
72 {
73 unsigned int offset; // where in the image is the file?
74 unsigned char track; // track
75 unsigned char sector; // sector
76 int len; // do not trust this one
77 int side; // A, B or both?
78 eFileType fileType;
79 } tFileEntry;
80
81
82 typedef struct _tGameInfo
83 {
84 eGame game; // the enumeration for the game
85 int sides; // how many floppy sides did this game occupy?
86 char magicword[5]; // the word, that is hidden in the second sector of the disk image
87 int version; // the virtual machine's version
88 char name[32]; // human readable
89 signed char order[32]; // the order in which the pictures can be found in the images are not the same as in other releases.
90 } tGameInfo;
91
92 const tGameInfo loader_d64_gameinfo[6]=
93 {
94 // the pictures are ordered different from the other releases. there, this list would have been 0 1 2 3 4...
95 // but the C64 had only a limited amount of floppy disk space.
96 {GAME_JINXTER ,2,"ARSE",2,"Jinxter", { 4, 0, 5, 6, 7,-1, 8, 1, 9,10,11,12, 13,14,15,16, 17, 2, 3,27, 18,19,20,21, 22,23,24,25, 26,27,26,26}},
97 {GAME_CORRUPTION,2,"COKE",3,"Corruption", { 24, 8, 9,25, 10,13,15,16, 17, 1,18,23, 21, 6, 5, 4, 12,14, 2, 3, 11,20, 7,22, 19, 0,-1,-1, -1,-1,-1,-1 }},
98 {GAME_FISH ,2,"GLUG",3,"Fish!", { 3,21, 8,11, 18,16,17, 4, 2, 5, 1, 6, 9,10,14,20, 22,24,25, 0, 15,23, 7,19, 13,-1,26,-1, -1,-1,-1,-1 }},
99 {GAME_MYTH ,1,"GODS",3,"Myth", { 0, 1, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1}},
100 {GAME_PAWN ,2,"PAWN",0,"The Pawn", { 4,26,13,23, 0, 8,29, 5, 18,19, 3, 9, 12,11,16,22, 17,21,28, 6, 27,25,24, 2, 1,20,14, 7, 15,10,-1,-1 }},
101 {GAME_GUILD ,2,"SWAG",1,"The Guild of Thieves", { 9,17,20, 0,26,19,11,12, 4, 5, 2,13,14, 8, 6, 1,15,16, 3,24,21,28,22,25,18,23, 7,10,27,-1,-1,-1}},
102 };
103
loader_d64_detectgame(unsigned char * diskram)104 int loader_d64_detectgame(unsigned char* diskram)
105 {
106
107 // find the magic word
108 int i;
109 char tmp[5];
110 #define MAGIC_WORD_LOCATION 0x1eb
111 // at those positions in the image, a magic word is hidden.
112 // it can be used to detect the game
113 tmp[0]=diskram[MAGIC_WORD_LOCATION+0];
114 tmp[1]=diskram[MAGIC_WORD_LOCATION+1];
115 tmp[2]=diskram[MAGIC_WORD_LOCATION+2];
116 tmp[3]=diskram[MAGIC_WORD_LOCATION+3];
117 tmp[4]=0;
118
119 for (i=0;i<6;i++)
120 {
121 if (strncmp(tmp,loader_d64_gameinfo[i].magicword,4)==0) return i;
122 }
123
124 return -1;
125 }
126 const unsigned char loader_d64_sectorcnt[D64_TRACKNUM]=
127 {
128 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, // track 1-17
129 19,19,19,19,19,19,19, // track 18-24
130 18,18,18,18,18,18, // track 25-30
131 17,17,17,17,17,17,17,17,17,17 // track 31-40
132 };
133
loader_d64_readEntries(unsigned char * d64image,int d64size,tFileEntry * pEntries,int * pEntrynum)134 void loader_d64_readEntries(unsigned char* d64image,int d64size,tFileEntry* pEntries,int* pEntrynum)
135 {
136 int i;
137 int offsets[40];
138 int cnt;
139
140 // first step: calculate the offsets for the tracks
141 offsets[0]=0;
142 for (i=1;i<D64_TRACKNUM;i++)
143 {
144 offsets[i]=offsets[i-1]+loader_d64_sectorcnt[i-1]*D64_SECTORSIZE;
145 }
146 cnt=0;
147 // read the entries, and translate it into offsets within the d64 image
148 for (i=0;i<D64_MAXENTRIES;i++)
149 {
150 unsigned char track;
151 unsigned char sect;
152 unsigned char side;
153 unsigned char len;
154 int newoffs;
155
156 // 1, entry, 4 bytes. in sector 2.
157 track=d64image[2*D64_SECTORSIZE+i*4+0];
158 sect =d64image[2*D64_SECTORSIZE+i*4+1];
159 len =d64image[2*D64_SECTORSIZE+i*4+2];
160 side =d64image[2*D64_SECTORSIZE+i*4+3]&3;
161
162
163 if (len)
164 {
165 newoffs=offsets[track]+sect*D64_SECTORSIZE;
166 pEntries[cnt].offset=newoffs;
167 pEntries[cnt].track=track;
168 pEntries[cnt].sector=sect;
169 pEntries[cnt].len=len;
170 pEntries[cnt].side=side;
171 pEntries[cnt].fileType=TYPE_UNKNOWN;
172
173 cnt++;
174 }
175 }
176 *pEntrynum=cnt;
177 }
178
loader_d64_readSector(unsigned char * d64image,int track,int sect,unsigned char * buf)179 void loader_d64_readSector(unsigned char* d64image,int track,int sect,unsigned char* buf)
180 {
181 int i;
182 int offset;
183
184 // first step: calculate the offsets for the tracks
185 offset=sect*D64_SECTORSIZE;
186 for (i=1;i<track;i++)
187 {
188 offset+=loader_d64_sectorcnt[i-1]*D64_SECTORSIZE;
189 }
190 if ((offset+256)>D64_IMAGESIZE)
191 {
192 return;
193 }
194 for (i=0;i<256;i++) buf[i]=d64image[offset++];
195 }
196
loader_d64_identifyEntries(unsigned char * d64image,tFileEntry * pEntries,int entryNum)197 void loader_d64_identifyEntries(unsigned char* d64image,tFileEntry* pEntries,int entryNum)
198 {
199 int i;
200 unsigned char tmp1[256];
201 unsigned char tmp2[256];
202 int sideoffsets[4]={-1,-1,-1,-1};
203
204 // some file types have a fixed position in the list
205 pEntries[2].fileType=TYPE_STRING1;
206 pEntries[3].fileType=TYPE_STRING2;
207 pEntries[4].fileType=TYPE_CAMEO;
208 // first: find the code block
209 for (i=0;i<entryNum;i++)
210 {
211 loader_d64_readSector(&d64image[0],pEntries[i].track,pEntries[i].sector,tmp1);
212 loader_d64_readSector(&d64image[D64_IMAGESIZE],pEntries[i].track,pEntries[i].sector,tmp2);
213
214 if (tmp1[0]==0x49 && tmp1[1]==0xfa) // 0x49fa is ALWAYS the first instruction.
215 {
216 pEntries[i].fileType=TYPE_CODE1;
217 pEntries[1].fileType=TYPE_CODE2;
218 pEntries[i+1].fileType=TYPE_DICTIONARY;
219 sideoffsets[pEntries[i].side]=0;
220 }
221 else if (tmp2[0]==0x49 && tmp2[1]==0xfa) // 0x49fa is ALWAYS the first instruction.
222 {
223 pEntries[i].fileType=TYPE_CODE1;
224 pEntries[1].fileType=TYPE_CODE2;
225 pEntries[i+1].fileType=TYPE_DICTIONARY;
226 sideoffsets[pEntries[i].side]=D64_IMAGESIZE;
227 } else {
228 loader_common_descramble(tmp1,tmp1,0,NULL,0);
229 loader_common_descramble(tmp2,tmp2,0,NULL,0);
230 if ((tmp1[0]==0x49 || tmp1[2]==0x49) && (tmp1[1]==0xfa || tmp1[3]==0xfa)) // 0x49fa is ALWAYS the first instruction. run level encoded files start with a 2 byte header.
231 {
232 pEntries[i].fileType=TYPE_CODE1_ENCRYPTED;
233 pEntries[1].fileType=TYPE_CODE2_ENCRYPTED;
234 pEntries[i+1].fileType=TYPE_DICTIONARY;
235 sideoffsets[pEntries[i].side]=0;
236 }
237 if ((tmp2[0]==0x49 || tmp2[2]==0x49) && (tmp2[1]==0xfa || tmp2[3]==0xfa)) // 0x49fa is ALWAYS the first instruction. run level encoded files start with a 2 byte header.
238 {
239 pEntries[i].fileType=TYPE_CODE1_ENCRYPTED;
240 pEntries[1].fileType=TYPE_CODE2_ENCRYPTED;
241 pEntries[i+1].fileType=TYPE_DICTIONARY;
242 sideoffsets[pEntries[i].side]=D64_IMAGESIZE;
243 }
244 }
245 }
246 if (sideoffsets[1]==-1) sideoffsets[1]=D64_IMAGESIZE-sideoffsets[2];
247 else if (sideoffsets[2]==-1) sideoffsets[2]=D64_IMAGESIZE-sideoffsets[1];
248 sideoffsets[0]=0;
249 sideoffsets[3]=0;
250
251 // step2: identify all the pictures
252 // maybe there is a proper way to determine it from the data. through some form of directory i have not found yet.
253 // so here is what i do: I just check if the sector starts with the sequence 3d 82 81... or 3e 82 81, heralding
254 // the size of the huffman tree and the first two branches which are never a terminal symbol.
255 // (at least in the releases I dealt with)
256 for (i=0;i<entryNum;i++)
257 {
258 pEntries[i].offset+=sideoffsets[pEntries[i].side];
259 if (pEntries[i].fileType==TYPE_UNKNOWN)
260 {
261 loader_d64_readSector(&d64image[sideoffsets[pEntries[i].side]],pEntries[i].track,pEntries[i].sector,tmp1);
262 if ((tmp1[0]==0x3d || tmp1[0]==0x3e) && tmp1[1]==0x82 && tmp1[2]==0x81) pEntries[i].fileType=TYPE_PICTURE;
263 }
264 }
265
266 }
loader_d64_advanceSector(int * pTrack,int * pSector)267 void loader_d64_advanceSector(int *pTrack,int *pSector)
268 {
269 int sect;
270 int track;
271
272 track=*pTrack;
273 sect=*pSector;
274 sect=sect+1;
275 if (sect==loader_d64_sectorcnt[track-1])
276 {
277 sect=0;
278 track++;
279 if (track==18) track+=1; // skip the directory track
280 }
281 *pTrack=track;
282 *pSector=sect;
283 }
284
loader_d64_readCode1(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pCode1Buf,int * pCode1Size)285 int loader_d64_readCode1(unsigned char* d64image,tFileEntry *pEntries,int entryNum,unsigned char* pCode1Buf,int* pCode1Size)
286 {
287 int i;
288 int j;
289 int outcnt;
290 int rle;
291 int inputsize;
292 int track;
293 int sect;
294 int len;
295 int offset;
296 int encrypted;
297 unsigned char tmp[256];
298
299 outcnt=0;
300 rle=0;
301 offset=0;
302 encrypted=0;
303
304 track=sect=len=0;
305 inputsize=len*256;
306 for (i=0;i<entryNum;i++)
307 {
308 if (pEntries[i].fileType==TYPE_CODE1 || pEntries[i].fileType==TYPE_CODE1_ENCRYPTED)
309 {
310 if (pEntries[i].fileType==TYPE_CODE1_ENCRYPTED) encrypted=1;
311 if (pEntries[i].offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE;
312
313 track=pEntries[i].track;
314 sect =pEntries[i].sector;
315 len =pEntries[i].len;
316 }
317 }
318
319 rle=0;
320 inputsize=len*D64_SECTORSIZE;
321 for (i=0;i<len;i++)
322 {
323 int start;
324 loader_d64_readSector(&d64image[offset],track,sect,tmp);
325 loader_d64_advanceSector(&track,§);
326 start=0;
327 if (encrypted)
328 {
329 loader_common_descramble(tmp,tmp,i,NULL,0);
330 }
331 if (i==0)
332 {
333 if (tmp[0]==0x49 && tmp[1]==0xfa)
334 {
335 rle=0;
336 } else {
337 inputsize=tmp[0]*256+tmp[1]-2;
338 rle=1;
339 start=2;
340 }
341 }
342 for (j=start;j<D64_SECTORSIZE && inputsize;j++,inputsize--)
343 {
344 if (rle==2)
345 {
346 int k;
347 for (k=0;k<tmp[j]-1;k++) pCode1Buf[outcnt++]=0;
348 rle=1;
349 } else {
350 pCode1Buf[outcnt++]=tmp[j];
351 }
352 if (tmp[j]==0x00 && rle==1)
353 {
354 rle=2;
355 }
356 }
357 }
358 *pCode1Size=outcnt;
359 return 0;
360 }
361
loader_d64_readCode2(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pCode2Buf,int * pCode2Size)362 int loader_d64_readCode2(unsigned char* d64image,tFileEntry *pEntries,int entryNum,unsigned char* pCode2Buf,int* pCode2Size)
363 {
364 int i;
365 int j;
366 int outcnt;
367 int track,sect,len;
368 int offset;
369 int encrypted;
370 int scrambleoffs;
371 unsigned char tmp[256];
372
373 track=sect=len=0;
374 offset=0;
375 encrypted=0;
376 scrambleoffs=0;
377 for (i=0;i<entryNum;i++)
378 {
379 if (pEntries[i].fileType==TYPE_CODE1_ENCRYPTED)
380 {
381 scrambleoffs=pEntries[i].len;
382 }
383 if (pEntries[i].fileType==TYPE_CODE2 || pEntries[i].fileType==TYPE_CODE2_ENCRYPTED)
384 {
385 if (pEntries[i].fileType==TYPE_CODE2_ENCRYPTED) encrypted=1;
386 if (pEntries[i].offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE;
387 track=pEntries[i].track;
388 sect =pEntries[i].sector;
389 len =pEntries[i].len;
390 }
391 }
392
393
394 outcnt=0;
395 for (i=0;i<len;i++)
396 {
397 loader_d64_readSector(&d64image[offset],track,sect,tmp);
398 if (encrypted) loader_common_descramble(tmp,tmp,i+scrambleoffs,NULL,0);
399 loader_d64_advanceSector(&track,§);
400 for (j=0;j<256;j++)
401 {
402 pCode2Buf[outcnt++]=tmp[j];
403 }
404 }
405 *pCode2Size=outcnt;
406 return 0;
407 }
loader_d64_readStrings(unsigned char * d64image,tFileEntry * pEntries,int entryNum,unsigned char * pStringBuf,int * string1size,int * string2size,int * dictsize)408 int loader_d64_readStrings(unsigned char* d64image,tFileEntry* pEntries,int entryNum,unsigned char* pStringBuf,int* string1size,int* string2size,int* dictsize)
409 {
410 int i;
411 int j;
412 int k;
413 int outcnt;
414 unsigned char tmp[256];
415 int track,sect,len;
416 int cnt[3]={0};
417 int number=0;
418 int offset;
419 int encrypted;
420
421
422 outcnt=0;
423 for (i=0;i<entryNum;i++)
424 {
425 track=sect=len=offset=0;
426
427 if (pEntries[i].fileType==TYPE_STRING1 || pEntries[i].fileType==TYPE_STRING2 || pEntries[i].fileType==TYPE_DICTIONARY)
428 {
429 encrypted=0;
430 track=pEntries[i].track;
431 sect =pEntries[i].sector;
432 len =pEntries[i].len;
433 if (pEntries[i].fileType==TYPE_DICTIONARY)
434 {
435 encrypted=1;
436 }
437 if (pEntries[i].offset>=D64_IMAGESIZE)
438 {
439 offset=D64_IMAGESIZE;
440 } else {
441 offset=0;
442 }
443
444 for (j=0;j<len;j++)
445 {
446 loader_d64_readSector(&d64image[offset],track,sect,tmp);
447 if (encrypted) loader_common_descramble(tmp,tmp,j,NULL,0);
448 loader_d64_advanceSector(&track,§);
449 for (k=0;k<256;k++)
450 {
451 pStringBuf[outcnt++]=tmp[k];
452 }
453 cnt[number]+=256;
454 }
455 number++;
456 }
457 }
458 *string1size =cnt[0];
459 *string2size =cnt[1];
460 *dictsize =cnt[2];
461 return 0;
462 }
loader_d64(char * d64name,char * magbuf,int * magsize,char * gfxbuf,int * gfxsize)463 int loader_d64(char* d64name,
464 char *magbuf,int* magsize,
465 char* gfxbuf,int* gfxsize)
466 {
467 char* filename[2];
468 int i;
469 int l;
470 int gfxsize0;
471 unsigned char *d64image;
472 int sidecnt;
473 int gameID;
474 int entryNum;
475 tFileEntry entries[D64_MAXENTRIES];
476 FILE *f;
477 int code1size,code2size,string1size,string2size,dictsize;
478 unsigned char *gfxptr;
479
480
481 // i am using the gfx buffer as temporary memory. I suppose I could malloc. But why? ;)
482 gfxsize0=*gfxsize;
483 gfxptr=(unsigned char*)gfxbuf;
484
485 if (gfxsize0<4*D64_IMAGESIZE)
486 {
487 fprintf(stderr,"not enough memory to load D64 images. sorry.\n");
488 return -1;
489 }
490
491 d64image=(unsigned char*)&gfxbuf[2*D64_IMAGESIZE];
492
493 filename[0]=&d64name[0];
494 filename[1]=&d64name[0];
495 sidecnt=1;
496 l=strlen(d64name);
497 for (i=0;i<l;i++)
498 {
499 if (d64name[i]==',')
500 {
501 d64name[i]=0;
502 filename[1]=&d64name[i+1];
503 sidecnt++;
504 if (sidecnt>2)
505 {
506 fprintf(stderr,"Please provide no more than 2 filenames, separated by ,\n");
507 return -1;
508 }
509 }
510 }
511 // load the game
512 for (i=0;i<sidecnt;i++)
513 {
514 int n;
515 f=fopen(filename[i],"rb");
516 if (!f)
517 {
518 fprintf(stderr,"unable to open [%s]. Sorry.\n",filename[i]);
519 return -1;
520 }
521 n=fread(&d64image[i*D64_IMAGESIZE],sizeof(char),D64_IMAGESIZE,f);
522 fclose(f);
523 if (n!=D64_IMAGESIZE)
524 {
525 fprintf(stderr,"[%s] does not look like a D64 image\n",filename[i]);
526 return -1;
527 }
528 }
529 // now the images are in memory. now we can parse them.
530 // first, find out which game it is
531 gameID=loader_d64_detectgame(d64image);
532 if (gameID==-1)
533 {
534 fprintf(stderr,"unable to determine the game\n");
535 return -1;
536 }
537
538 if (loader_d64_gameinfo[gameID].sides!=sidecnt)
539 {
540 fprintf(stderr,"please provide all the floppy images.\n");
541 return -1;
542 }
543
544 // then, find the entries in the file list
545 loader_d64_readEntries(d64image,D64_IMAGESIZE,entries,&entryNum);
546 loader_d64_identifyEntries(d64image,entries,entryNum); // and figure out if they are code, pictures or something else
547
548
549 {
550 int huffmantreeidx;
551 int magidx;
552 ////////////////// LOAD THE MAG BUFFER /////////////////
553 magidx=42; // leave some room for the header
554 loader_d64_readCode1(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&code1size);
555 magidx+=code1size;
556 loader_d64_readCode2(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&code2size);
557 magidx+=code2size;
558 loader_d64_readStrings(d64image,entries,entryNum,(unsigned char*)&magbuf[magidx],&string1size,&string2size,&dictsize);
559 huffmantreeidx=0;
560
561 // within the string buffer, there is the beginning of the huffman tree
562 if (loader_d64_gameinfo[gameID].version<=1)
563 {
564 huffmantreeidx=string1size; // the PAWN and GUILD of Thieves had the beginning of the huffman tree in the second string buffer.
565 } else {
566 int i;
567 // there might be a better way to look for it, but in every C64 game, it starts with 01 02 03.
568 // and before that, there are a handful of bytes that are =0.
569 // in addition to this, it is aligned to sectors, so its indes has to be a multiple of 256.
570 for (i=0x100;i<string1size+string2size;i+=0x100)
571 {
572 if ( magbuf[magidx+i-3]==0x00 && magbuf[magidx+i-2]==0x00 && magbuf[magidx+i-1]==0x00 && // the previous sector ends with 0x00
573 magbuf[magidx+i+0]==0x01 && magbuf[magidx+i+1]==0x02 && magbuf[magidx+i+2]==0x03) huffmantreeidx=i; // the sector with the huffmann tree starts with 0x01 0x02 0x03
574 }
575 }
576
577 magidx+=string1size+string2size+dictsize;
578 loader_common_addmagheader((unsigned char*)magbuf,magidx,loader_d64_gameinfo[gameID].version,code1size+code2size,string1size,string2size,dictsize,huffmantreeidx);
579
580 if (loader_d64_gameinfo[gameID].game==GAME_MYTH && magbuf[0x3080]==0x66) magbuf[0x3080]=0x60; // final touch
581
582 *magsize=magidx;
583 /////////// MAG IS FINISHED ////////////////////////////////
584 }
585 {
586 unsigned int picoffs[32]={0};
587 int side;
588 int piccnt;
589 int gfxidx;
590
591
592
593 side=-1;
594 piccnt=0;
595
596 ////////////// LOAD THE GFX BUFFER /////////////////
597 gfxidx=4+4*32+1; // leave some room for the magic word, offsets and the game's version
598
599 // just copy the picture data into the GFX buffer. It will be parsed and unpacked later.
600 for (i=0;i<entryNum;i++)
601 {
602 if (entries[i].fileType==TYPE_PICTURE)
603 {
604 int track,sector,offset,len;
605 int j;
606 if (side==-1)
607 {
608 side=entries[i].side;
609 }
610 else if (side!=entries[i].side)
611 {
612 side=entries[i].side;
613 }
614 track =entries[i].track;
615 sector =entries[i].sector;
616 offset =entries[i].offset;if (offset>=D64_IMAGESIZE) offset=D64_IMAGESIZE; else offset=0;
617 len =entries[i].len;
618
619 picoffs[piccnt]=gfxidx;
620 for (j=0;j<len && track<36;j++)
621 {
622 loader_d64_readSector(&d64image[offset],track,sector,(unsigned char*)&gfxbuf[gfxidx]);
623 loader_d64_advanceSector(&track,§or);
624 gfxidx+=D64_SECTORSIZE;
625 }
626 piccnt++;
627 }
628 }
629
630 *gfxsize=gfxidx;
631
632 gfxidx=0;
633 // now the buffer is complete. write the header.
634 gfxbuf[gfxidx++]='M';
635 gfxbuf[gfxidx++]='a';
636 gfxbuf[gfxidx++]='P';
637 gfxbuf[gfxidx++]='5';
638 for (i=0;i<32;i++)
639 {
640 int order;
641 order=loader_d64_gameinfo[gameID].order[i];
642 WRITE_INT32BE(gfxptr,gfxidx ,(order==-1)?0xffffffff:picoffs[loader_d64_gameinfo[gameID].order[i]]);
643 gfxidx+=4;
644 }
645 gfxbuf[4+4*32]=loader_d64_gameinfo[gameID].version;
646 /////////// GFX is finished ///////////////
647 }
648 return 0;
649 }
650
651
652