1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 // AGOS debug functions
24
25 #include "common/file.h"
26 #include "common/textconsole.h"
27
28 #include "agos/debug.h"
29 #include "agos/agos.h"
30 #include "agos/intern.h"
31 #include "agos/vga.h"
32
33 namespace AGOS {
34
dumpOpcode(const byte * p)35 const byte *AGOSEngine::dumpOpcode(const byte *p) {
36 uint16 opcode;
37 const char *s, *st;
38
39 if (getGameType() == GType_ELVIRA1) {
40 opcode = READ_BE_UINT16(p);
41 p += 2;
42 if (opcode == 10000)
43 return NULL;
44 } else {
45 opcode = *p++;
46 if (opcode == 255)
47 return NULL;
48 }
49
50 if (getGameType() == GType_PP) {
51 st = s = puzzlepack_opcodeNameTable[opcode];
52 } else if (getGameType() == GType_FF) {
53 st = s = feeblefiles_opcodeNameTable[opcode];
54 } else if (getGameType() == GType_SIMON2 && getFeatures() & GF_TALKIE) {
55 st = s = simon2talkie_opcodeNameTable[opcode];
56 } else if (getGameType() == GType_SIMON2) {
57 st = s = simon2dos_opcodeNameTable[opcode];
58 } else if (getFeatures() & GF_TALKIE) {
59 st = s = simon1talkie_opcodeNameTable[opcode];
60 } else if (getGameType() == GType_SIMON1) {
61 st = s = simon1dos_opcodeNameTable[opcode];
62 } else if (getGameType() == GType_WW) {
63 st = s = waxworks_opcodeNameTable[opcode];
64 } else if (getGameType() == GType_ELVIRA2) {
65 st = s = elvira2_opcodeNameTable[opcode];
66 } else {
67 st = s = elvira1_opcodeNameTable[opcode];
68 }
69
70 if (s == NULL) {
71 error("dumpOpcode: INVALID OPCODE %d", opcode);
72 }
73
74 while (*st != '|')
75 st++;
76 debugN("%s ", st + 1);
77
78 for (;;) {
79 switch (*s++) {
80 case 'x':
81 debugN("\n");
82 return NULL;
83 case '|':
84 debugN("\n");
85 return p;
86 case 'B':{
87 byte b = *p++;
88 if (b == 255)
89 debugN("[%d] ", *p++);
90 else
91 debugN("%d ", b);
92 break;
93 }
94 case 'V':{
95 byte b = *p++;
96 if (b == 255)
97 debugN("[[%d]] ", *p++);
98 else
99 debugN("[%d] ", b);
100 break;
101 }
102
103 case 'W':{
104 uint16 n = READ_BE_UINT16(p);
105 p += 2;
106 if (getGameType() == GType_PP) {
107 if (n >= 60000 && n < 62048)
108 debugN("[%d] ", n - 60000);
109 else
110 debugN("%d ", n);
111
112 } else {
113 if (n >= 30000 && n < 30512)
114 debugN("[%d] ", n - 30000);
115 else
116 debugN("%d ", n);
117 }
118 break;
119 }
120
121 case 'w':{
122 int n = (int16)READ_BE_UINT16(p);
123 p += 2;
124 debugN("%d ", n);
125 break;
126 }
127
128 case 'I':{
129 int n = (int16)READ_BE_UINT16(p);
130 p += 2;
131 if (n == -1)
132 debugN("SUBJECT_ITEM ");
133 else if (n == -3)
134 debugN("OBJECT_ITEM ");
135 else if (n == -5)
136 debugN("ME_ITEM ");
137 else if (n == -7)
138 debugN("ACTOR_ITEM ");
139 else if (n == -9)
140 debugN("ITEM_A_PARENT ");
141 else
142 debugN("<%d> ", n);
143 break;
144 }
145
146 case 'J':{
147 debugN("-> ");
148 }
149 break;
150
151 case 'T':{
152 uint n = READ_BE_UINT16(p);
153 p += 2;
154 if (n != 0xFFFF)
155 debugN("\"%s\"(%d) ", getStringPtrByID(n), n);
156 else
157 debugN("NULL_STRING ");
158 }
159 break;
160 }
161 }
162 }
163
dumpSubroutineLine(SubroutineLine * sl,Subroutine * sub)164 void AGOSEngine::dumpSubroutineLine(SubroutineLine *sl, Subroutine *sub) {
165 const byte *p;
166
167 debugN("; ****\n");
168
169 p = (byte *)sl + SUBROUTINE_LINE_SMALL_SIZE;
170 if (sub->id == 0) {
171 debugN("; verb=%d, noun1=%d, noun2=%d\n", sl->verb, sl->noun1, sl->noun2);
172 p = (byte *)sl + SUBROUTINE_LINE_BIG_SIZE;
173 }
174
175 for (;;) {
176 p = dumpOpcode(p);
177 if (p == NULL)
178 break;
179 }
180 }
181
dumpSubroutine(Subroutine * sub)182 void AGOSEngine::dumpSubroutine(Subroutine *sub) {
183 SubroutineLine *sl;
184
185 debugN("\n******************************************\n;Subroutine, ID=%d:\nSUB_%d:\n", sub->id, sub->id);
186 sl = (SubroutineLine *)((byte *)sub + sub->first);
187 for (; (byte *)sl != (byte *)sub; sl = (SubroutineLine *)((byte *)sub + sl->next)) {
188 dumpSubroutineLine(sl, sub);
189 }
190 debugN("\nEND ******************************************\n");
191 }
192
dumpSubroutines()193 void AGOSEngine::dumpSubroutines() {
194 Subroutine *sub = _subroutineList;
195 for (; sub; sub = sub->next) {
196 dumpSubroutine(sub);
197 }
198 }
199
dumpAllSubroutines()200 void AGOSEngine::dumpAllSubroutines() {
201 for (int i = 0; i < 65536; i++) {
202 Subroutine *sub = getSubroutineByID(i);
203 if (sub != NULL) {
204 dumpSubroutine(sub);
205 }
206 }
207 }
208
dumpVideoScript(const byte * src,bool singeOpcode)209 void AGOSEngine::dumpVideoScript(const byte *src, bool singeOpcode) {
210 uint16 opcode;
211 const char *str, *strn;
212
213 do {
214 if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP) {
215 opcode = *src++;
216 } else {
217 opcode = READ_BE_UINT16(src);
218 src += 2;
219 }
220
221 if (opcode >= _numVideoOpcodes) {
222 error("dumpVideoScript: Opcode %d out of range (%d)", opcode, _numVideoOpcodes);
223 }
224
225 if (getGameType() == GType_PP) {
226 strn = str = puzzlepack_videoOpcodeNameTable[opcode];
227 } else if (getGameType() == GType_FF) {
228 strn = str = feeblefiles_videoOpcodeNameTable[opcode];
229 } else if (getGameType() == GType_SIMON2) {
230 strn = str = simon2_videoOpcodeNameTable[opcode];
231 } else if (getGameType() == GType_SIMON1) {
232 strn = str = simon1_videoOpcodeNameTable[opcode];
233 } else if (getGameType() == GType_WW) {
234 strn = str = ww_videoOpcodeNameTable[opcode];
235 } else if (getGameType() == GType_ELVIRA2) {
236 strn = str = elvira2_videoOpcodeNameTable[opcode];
237 } else if (getGameType() == GType_ELVIRA1) {
238 strn = str = elvira1_videoOpcodeNameTable[opcode];
239 } else {
240 strn = str = pn_videoOpcodeNameTable[opcode];
241 }
242
243 if (strn == NULL) {
244 error("dumpVideoScript: Invalid Opcode %d", opcode);
245 }
246
247 while (*strn != '|')
248 strn++;
249 debugN("%.2d: %s ", opcode, strn + 1);
250
251 int end = (getGameType() == GType_FF || getGameType() == GType_PP) ? 9999 : 999;
252 for (; *str != '|'; str++) {
253 switch (*str) {
254 case 'x':
255 debugN("\n");
256 return;
257 case 'b': {
258 debugN("%d ", *src++);
259 break;
260 }
261 case 'w': {
262 int16 v = (int16)readUint16Wrapper(src);
263 src += 2;
264 if (v < 0)
265 debugN("[%d] ", -v);
266 else
267 debugN("%d ", v);
268 break;
269 }
270 case 'd': {
271 debugN("%d ", (int16)readUint16Wrapper(src));
272 src += 2;
273 break;
274 }
275 case 'v': {
276 debugN("[%d] ", readUint16Wrapper(src));
277 src += 2;
278 break;
279 }
280 case 'i': {
281 debugN("%d ", (int16)readUint16Wrapper(src));
282 src += 2;
283 break;
284 }
285 case 'j': {
286 debugN("-> ");
287 break;
288 }
289 case 'q': {
290 while (readUint16Wrapper(src) != end) {
291 debugN("(%d,%d) ", readUint16Wrapper(src),
292 readUint16Wrapper(src + 2));
293 src += 4;
294 }
295 src += 2;
296 break;
297 }
298 default:
299 error("dumpVideoScript: Invalid fmt string '%c' in decompile VGA", *str);
300 }
301 }
302
303 debugN("\n");
304 } while (!singeOpcode);
305 }
306
dumpVgaScript(const byte * ptr,uint16 res,uint16 id)307 void AGOSEngine::dumpVgaScript(const byte *ptr, uint16 res, uint16 id) {
308 dumpVgaScriptAlways(ptr, res, id);
309 }
310
dumpVgaScriptAlways(const byte * ptr,uint16 res,uint16 id)311 void AGOSEngine::dumpVgaScriptAlways(const byte *ptr, uint16 res, uint16 id) {
312 debugN("; address=%x, vgafile=%d vgasprite=%d\n",
313 (unsigned int)(ptr - _vgaBufferPointers[res].vgaFile1), res, id);
314 dumpVideoScript(ptr, false);
315 debugN("; end\n");
316 }
317
dumpAllVgaImageFiles()318 void AGOSEngine::dumpAllVgaImageFiles() {
319 const uint8 start = (getGameType() == GType_PN) ? 0 : 2;
320
321 for (int z = start; z < _numZone; z++) {
322 loadZone(z, false);
323 dumpVgaBitmaps(z);
324 }
325 }
326
dumpAllVgaScriptFiles()327 void AGOSEngine::dumpAllVgaScriptFiles() {
328 const uint8 start = (getGameType() == GType_PN) ? 0 : 2;
329
330 for (int z = start; z < _numZone; z++) {
331 uint16 zoneNum = (getGameType() == GType_PN) ? 0 : z;
332 loadZone(z, false);
333
334 VgaPointersEntry *vpe = &_vgaBufferPointers[zoneNum];
335 if (vpe->vgaFile1 != NULL) {
336 _curVgaFile1 = vpe->vgaFile1;
337 dumpVgaFile(_curVgaFile1);
338 }
339 }
340 }
341
342 #ifdef ENABLE_AGOS2
dumpVgaFile(const byte * vga)343 void AGOSEngine_Feeble::dumpVgaFile(const byte *vga) {
344 const byte *pp;
345 const byte *p;
346 int16 count;
347
348 pp = vga;
349 p = pp + READ_LE_UINT16(pp + 2);
350 count = READ_LE_UINT16(&((const VgaFile1Header_Feeble *) p)->animationCount);
351 p = pp + READ_LE_UINT16(&((const VgaFile1Header_Feeble *) p)->animationTable);
352
353 while (--count >= 0) {
354 uint16 id = READ_LE_UINT16(&((const AnimationHeader_Feeble *) p)->id);
355
356 dumpVgaScriptAlways(vga + READ_LE_UINT16(&((const AnimationHeader_Feeble *) p)->scriptOffs), id / 100, id);
357 p += sizeof(AnimationHeader_Feeble);
358 }
359
360 pp = vga;
361 p = pp + READ_LE_UINT16(pp + 2);
362 count = READ_LE_UINT16(&((const VgaFile1Header_Feeble *) p)->imageCount);
363 p = pp + READ_LE_UINT16(&((const VgaFile1Header_Feeble *) p)->imageTable);
364
365 while (--count >= 0) {
366 uint16 id = READ_LE_UINT16(&((const ImageHeader_Feeble *) p)->id);
367
368 dumpVgaScriptAlways(vga + READ_LE_UINT16(&((const ImageHeader_Feeble *) p)->scriptOffs), id / 100, id);
369 p += sizeof(ImageHeader_Feeble);
370 }
371 }
372 #endif
373
dumpVgaFile(const byte * vga)374 void AGOSEngine_Simon1::dumpVgaFile(const byte *vga) {
375 const byte *pp;
376 const byte *p;
377 int16 count;
378
379 pp = vga;
380 p = pp + READ_BE_UINT16(pp + 4);
381 count = READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->animationCount);
382 p = pp + READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->animationTable);
383
384 while (--count >= 0) {
385 uint16 id = READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->id);
386
387 dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const AnimationHeader_Simon *) p)->scriptOffs), id / 100, id);
388 p += sizeof(AnimationHeader_Simon);
389 }
390
391 pp = vga;
392 p = pp + READ_BE_UINT16(pp + 4);
393 count = READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->imageCount);
394 p = pp + READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->imageTable);
395
396 while (--count >= 0) {
397 uint16 id = READ_BE_UINT16(&((const ImageHeader_Simon *) p)->id);
398
399 dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const ImageHeader_Simon *) p)->scriptOffs), id / 100, id);
400 p += sizeof(ImageHeader_Simon);
401 }
402 }
403
dumpVgaFile(const byte * vga)404 void AGOSEngine::dumpVgaFile(const byte *vga) {
405 const byte *pp;
406 const byte *p;
407 int16 count;
408
409 pp = vga;
410 p = pp + READ_BE_UINT16(pp + 10) + 20;
411 count = READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->animationCount);
412 p = pp + READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->animationTable);
413
414 while (--count >= 0) {
415 uint16 id = READ_BE_UINT16(&((const AnimationHeader_WW *) p)->id);
416
417 dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const AnimationHeader_WW *) p)->scriptOffs), id / 100, id);
418 p += sizeof(AnimationHeader_WW);
419 }
420
421 pp = vga;
422 p = pp + READ_BE_UINT16(pp + 10) + 20;
423 count = READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->imageCount);
424 p = pp + READ_BE_UINT16(&((const VgaFile1Header_Common *) p)->imageTable);
425
426 while (--count >= 0) {
427 uint16 id = READ_BE_UINT16(&((const ImageHeader_WW *) p)->id);
428
429 dumpVgaScriptAlways(vga + READ_BE_UINT16(&((const ImageHeader_WW *) p)->scriptOffs), id / 100, id);
430 p += sizeof(ImageHeader_WW);
431 }
432 }
433
434 static const byte bmp_hdr[] = {
435 0x42, 0x4D,
436 0x9E, 0x14, 0x00, 0x00, /* offset 2, file size */
437 0x00, 0x00, 0x00, 0x00,
438 0x36, 0x04, 0x00, 0x00,
439 0x28, 0x00, 0x00, 0x00,
440
441 0x3C, 0x00, 0x00, 0x00, /* image width */
442 0x46, 0x00, 0x00, 0x00, /* image height */
443 0x01, 0x00, 0x08, 0x00,
444 0x00, 0x00, 0x00, 0x00,
445 0x00, 0x00, 0x00, 0x00,
446 0x00, 0x00, 0x00, 0x00,
447 0x00, 0x00, 0x00, 0x00,
448
449 0x00, 0x01, 0x00, 0x00,
450 0x00, 0x01, 0x00, 0x00,
451 };
452
dumpBMP(const char * filename,int16 w,int16 h,const byte * bytes,const byte * palette)453 void dumpBMP(const char *filename, int16 w, int16 h, const byte *bytes, const byte *palette) {
454 Common::DumpFile out;
455 byte my_hdr[sizeof(bmp_hdr)];
456 int i;
457
458 out.open(filename);
459 if (!out.isOpen())
460 return;
461
462 memcpy(my_hdr, bmp_hdr, sizeof(bmp_hdr));
463
464 *(uint32 *)(my_hdr + 2) = w * h + 1024 + sizeof(bmp_hdr);
465 *(uint32 *)(my_hdr + 18) = w;
466 *(uint32 *)(my_hdr + 22) = h;
467
468
469 out.write(my_hdr, sizeof(my_hdr));
470
471 for (i = 0; i != 256; i++, palette += 3) {
472 byte color[4];
473 color[0] = palette[2];
474 color[1] = palette[1];
475 color[2] = palette[0];
476 color[3] = 0;
477 out.write(color, 4);
478 }
479
480 while (--h >= 0) {
481 out.write(bytes + h * ((w + 3) & ~3), ((w + 3) & ~3));
482 }
483 }
484
dumpBitmap(const char * filename,const byte * offs,uint16 w,uint16 h,int flags,const byte * palette,byte base)485 void AGOSEngine::dumpBitmap(const char *filename, const byte *offs, uint16 w, uint16 h, int flags, const byte *palette,
486 byte base) {
487
488 byte *imageBuffer = (byte *)malloc(w * h);
489 assert(imageBuffer);
490
491 VC10_state state;
492 state.depack_cont = -0x80;
493 state.srcPtr = offs;
494 state.dh = h;
495 state.height = h;
496 state.width = w / 16;
497
498 if (getFeatures() & GF_PLANAR) {
499 state.srcPtr = convertImage(&state, (getGameType() == GType_PN || (flags & 0x80) != 0));
500 flags &= ~0x80;
501 }
502
503 const byte *src = state.srcPtr;
504 byte *dst = imageBuffer;
505 int i, j;
506
507 if (w > _screenWidth) {
508 for (i = 0; i < w; i += 8) {
509 decodeColumn(dst, src + readUint32Wrapper(src), h, w);
510 dst += 8;
511 src += 4;
512 }
513 } else if (h > _screenHeight) {
514 for (i = 0; i < h; i += 8) {
515 decodeRow(dst, src + readUint32Wrapper(src), w, w);
516 dst += 8 * w;
517 src += 4;
518 }
519 } else if (getGameType() == GType_FF || getGameType() == GType_PP) {
520 if ((flags & 0x80)) {
521 for (i = 0; i != w; i++) {
522 byte *c = vc10_depackColumn(&state);
523 for (j = 0; j != h; j++) {
524 dst[j * w + i] = c[j];
525 }
526 }
527 } else {
528 for (j = 0; j != h; j++) {
529 for (i = 0; i != w; i++) {
530 dst[i] = src[i];
531 }
532 }
533 dst += w;
534 src += w;
535 }
536 } else if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) && w == 320 && (h == 134 || h == 135 || h == 200)) {
537 for (j = 0; j != h; j++) {
538 uint16 count = w / 8;
539
540 byte *dstPtr = dst;
541 do {
542 uint32 bits = (src[0] << 24) | (src[1] << 16) | (src[2] << 8) | (src[3]);
543
544 dstPtr[0] = (byte)((bits >> (32 - 5)) & 31);
545 dstPtr[1] = (byte)((bits >> (32 - 10)) & 31);
546 dstPtr[2] = (byte)((bits >> (32 - 15)) & 31);
547 dstPtr[3] = (byte)((bits >> (32 - 20)) & 31);
548 dstPtr[4] = (byte)((bits >> (32 - 25)) & 31);
549 dstPtr[5] = (byte)((bits >> (32 - 30)) & 31);
550
551 bits = (bits << 8) | src[4];
552
553 dstPtr[6] = (byte)((bits >> (40 - 35)) & 31);
554 dstPtr[7] = (byte)((bits) & 31);
555
556 dstPtr += 8;
557 src += 5;
558 } while (--count);
559 dst += w;
560 }
561 } else if (flags & 0x80) {
562 for (i = 0; i != w; i += 2) {
563 byte *c = vc10_depackColumn(&state);
564 for (j = 0; j != h; j++) {
565 byte col = c[j];
566 dst[j * w + i] = (col >> 4) | base;
567 dst[j * w + i + 1] = (col & 0xF) | base;
568 }
569 }
570 } else {
571 for (j = 0; j != h; j++) {
572 for (i = 0; i != w / 2; i ++) {
573 byte col = src[i];
574 dst[i * 2] = (col >> 4) | base;
575 dst[i * 2 + 1] = (col & 0xF) | base;
576 }
577 dst += w;
578 src += w / 2;
579 }
580 }
581
582 dumpBMP(filename, w, h, imageBuffer, palette);
583 free(imageBuffer);
584 }
585
dumpSingleBitmap(int file,int image,const byte * offs,int w,int h,byte base)586 void AGOSEngine::dumpSingleBitmap(int file, int image, const byte *offs, int w, int h, byte base) {
587 char buf[40];
588
589 sprintf(buf, "dumps/File%d_Image%d.bmp", file, image);
590
591 if (Common::File::exists(buf))
592 return;
593
594 dumpBitmap(buf, offs, w, h, 0, _displayPalette, base);
595 }
596
palLoad(byte * pal,const byte * vga1,int a,int b)597 void AGOSEngine::palLoad(byte *pal, const byte *vga1, int a, int b) {
598 const byte *src;
599 uint16 num, palSize;
600 byte *palptr = (byte *)&pal[0];
601
602 if (getGameType() == GType_FF || getGameType() == GType_PP) {
603 num = 256;
604 palSize = 768;
605 } else {
606 num = 32;
607 palSize = 96;
608 }
609
610 if (getGameType() == GType_PN && (getFeatures() & GF_EGA)) {
611 memcpy(palptr, _displayPalette, 3 * 16);
612 } else if (getGameType() == GType_PN || getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_WW) {
613 src = vga1 + READ_BE_UINT16(vga1 + 6) + b * 32;
614
615 do {
616 uint16 color = READ_BE_UINT16(src);
617 palptr[0] = ((color & 0xf00) >> 8) * 32;
618 palptr[1] = ((color & 0x0f0) >> 4) * 32;
619 palptr[2] = ((color & 0x00f) >> 0) * 32;
620
621 palptr += 3;
622 src += 2;
623 } while (--num);
624 } else {
625 src = vga1 + 6 + b * palSize;
626
627 do {
628 palptr[0] = src[0] << 2;
629 palptr[1] = src[1] << 2;
630 palptr[2] = src[2] << 2;
631
632 palptr += 3;
633 src += 3;
634 } while (--num);
635 }
636 }
637
dumpVgaBitmaps(uint16 zoneNum)638 void AGOSEngine::dumpVgaBitmaps(uint16 zoneNum) {
639 uint16 width, height, flags;
640 uint32 offs, offsEnd;
641 const byte *p2;
642 byte pal[768];
643
644 uint16 zone = (getGameType() == GType_PN) ? 0 : zoneNum;
645 VgaPointersEntry *vpe = &_vgaBufferPointers[zone];
646 if (vpe->vgaFile1 == NULL || vpe->vgaFile2 == NULL)
647 return;
648
649 const byte *vga1 = vpe->vgaFile1;
650 const byte *vga2 = vpe->vgaFile2;
651 uint32 imageBlockSize = vpe->vgaFile2End - vpe->vgaFile2;
652
653 memset(pal, 0, sizeof(pal));
654 palLoad(pal, vga1, 0, 0);
655
656 offsEnd = readUint32Wrapper(vga2 + 8);
657 for (uint i = 1; ; i++) {
658 if ((i * 8) >= offsEnd)
659 break;
660
661 p2 = vga2 + i * 8;
662 offs = readUint32Wrapper(p2);
663
664 width = readUint16Wrapper(p2 + 6);
665 if (getGameType() == GType_FF || getGameType() == GType_PP) {
666 height = READ_LE_UINT16(p2 + 4) & 0x7FFF;
667 flags = p2[5];
668 } else {
669 height = p2[5];
670 flags = p2[4];
671 }
672
673 debug(1, "Zone %d: Image %d. Offs= %d Width=%d, Height=%d, Flags=0x%X", zoneNum, i, offs, width, height, flags);
674 if (offs >= imageBlockSize || width == 0 || height == 0)
675 break;
676
677 /* dump bitmap */
678 char buf[40];
679 sprintf(buf, "dumps/Res%d_Image%d.bmp", zoneNum, i);
680
681 dumpBitmap(buf, vga2 + offs, width, height, flags, pal, 0);
682 }
683 }
684
685 } // End of namespace AGOS
686