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