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 #include "common/file.h"
24 #include "common/system.h"
25 #include "common/textconsole.h"
26 
27 #include "graphics/surface.h"
28 
29 #include "agos/agos.h"
30 #include "agos/intern.h"
31 
32 namespace AGOS {
33 
loadIconFile()34 void AGOSEngine::loadIconFile() {
35 	Common::File in;
36 	uint32 srcSize;
37 
38 	in.open(getFileName(GAME_ICONFILE));
39 	if (in.isOpen() == false)
40 		error("Can't open icons file '%s'", getFileName(GAME_ICONFILE));
41 
42 	srcSize = in.size();
43 
44 	if (getGameType() == GType_WW && getPlatform() == Common::kPlatformAmiga) {
45 		byte *srcBuf = (byte *)malloc(srcSize);
46 		in.read(srcBuf, srcSize);
47 
48 		uint32 dstSize = READ_BE_UINT32(srcBuf + srcSize - 4);
49 		_iconFilePtr = (byte *)malloc(dstSize);
50 		if (_iconFilePtr == NULL)
51 			error("Out of icon memory");
52 
53 		decrunchFile(srcBuf, _iconFilePtr, srcSize);
54 		free(srcBuf);
55 	} else if (getGameType() == GType_PN && getPlatform() == Common::kPlatformAtariST) {
56 		// The icon data is hard coded in the program file.
57 		_iconFilePtr = (byte *)malloc(15038);
58 		if (_iconFilePtr == NULL)
59 			error("Out of icon memory");
60 
61 		in.seek(48414);
62 		in.read(_iconFilePtr, 15038);
63 	} else {
64 		_iconFilePtr = (byte *)malloc(srcSize);
65 		if (_iconFilePtr == NULL)
66 			error("Out of icon memory");
67 
68 		in.read(_iconFilePtr, srcSize);
69 	}
70 	in.close();
71 }
72 
loadIconData()73 void AGOSEngine::loadIconData() {
74 	loadZone(8);
75 	VgaPointersEntry *vpe = &_vgaBufferPointers[8];
76 
77 	byte *src = vpe->vgaFile2 + READ_LE_UINT32(vpe->vgaFile2 + 8);
78 
79 	_iconFilePtr = (byte *)malloc(43 * 336);
80 	if (_iconFilePtr == NULL)
81 		error("Out of icon memory");
82 
83 	memcpy(_iconFilePtr, src, 43 * 336);
84 	unfreezeBottom();
85 }
86 
87 // Thanks to Stuart Caie for providing the original
88 // C conversion upon which this function is based.
decompressIconPlanar(byte * dst,byte * src,uint width,uint height,byte base,uint pitch,bool decompress=true)89 static void decompressIconPlanar(byte *dst, byte *src, uint width, uint height, byte base, uint pitch, bool decompress = true) {
90 	byte *i, *icon_pln, *o, *srcPtr;
91 	byte x, y;
92 
93 	icon_pln = 0;
94 	srcPtr = src;
95 
96 	if (decompress) {
97 		icon_pln = (byte *)calloc(width * height, 1);
98 
99 		// Decode RLE planar icon data
100 		i = src;
101 		o = icon_pln;
102 		while (o < &icon_pln[width * height]) {
103 			x = *i++;
104 			if (x < 128) {
105 				do {
106 					*o++ = *i++;
107 					*o++ = *i++;
108 					*o++ = *i++;
109 				} while (x-- > 0);
110 			} else {
111 				x = 256 - x;
112 				do {
113 					*o++ = i[0];
114 					*o++ = i[1];
115 					*o++ = i[2];
116 				} while (x-- > 0);
117 				i += 3;
118 			}
119 		}
120 		srcPtr = icon_pln;
121 	}
122 
123 	// Translate planar data to chunky (very slow method)
124 	for (y = 0; y < height * 2; y++) {
125 		for (x = 0; x < width; x++) {
126 			byte pixel =
127 				  (srcPtr[((height * 0 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 1 : 0)
128 				| (srcPtr[((height * 2 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 2 : 0)
129 				| (srcPtr[((height * 4 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 4 : 0)
130 				| (srcPtr[((height * 6 + y) * 3) + (x >> 3)] & (1 << (7 - (x & 7))) ? 8 : 0);
131 			if (pixel)
132 				dst[x] = pixel | base;
133 		}
134 		dst += pitch;
135 	}
136 
137 	free(icon_pln);
138 }
139 
decompressIcon(byte * dst,byte * src,uint width,uint height,byte base,uint pitch)140 static void decompressIcon(byte *dst, byte *src, uint width, uint height, byte base, uint pitch) {
141 	int8 reps;
142 	byte color_1, color_2;
143 	byte *dst_org = dst;
144 	uint h = height;
145 
146 	for (;;) {
147 		reps = *src++;
148 		if (reps < 0) {
149 			reps--;
150 			color_1 = *src >> 4;
151 			if (color_1 != 0)
152 				color_1 |= base;
153 			color_2 = *src++ & 0xF;
154 			if (color_2 != 0)
155 				color_2 |= base;
156 
157 			do {
158 				if (color_1 != 0)
159 					*dst = color_1;
160 				dst += pitch;
161 				if (color_2 != 0)
162 					*dst = color_2;
163 				dst += pitch;
164 
165 				// reached bottom?
166 				if (--h == 0) {
167 					// reached right edge?
168 					if (--width == 0)
169 						return;
170 					dst = ++dst_org;
171 					h = height;
172 				}
173 			} while (++reps != 0);
174 		} else {
175 			do {
176 				color_1 = *src >> 4;
177 				if (color_1 != 0)
178 					*dst = color_1 | base;
179 				dst += pitch;
180 
181 				color_2 = *src++ & 0xF;
182 				if (color_2 != 0)
183 					*dst = color_2 | base;
184 				dst += pitch;
185 
186 				// reached bottom?
187 				if (--h == 0) {
188 					// reached right edge?
189 					if (--width == 0)
190 						return;
191 					dst = ++dst_org;
192 					h = height;
193 				}
194 			} while (--reps >= 0);
195 		}
196 	}
197 }
198 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)199 void AGOSEngine_Simon2::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
200 	byte *dst;
201 	byte *src;
202 
203 	_videoLockOut |= 0x8000;
204 
205 	Graphics::Surface *screen = _system->lockScreen();
206 	dst = (byte *)screen->getPixels();
207 
208 	dst += 110;
209 	dst += x;
210 	dst += (y + window->y) * screen->pitch;
211 
212 	src = _iconFilePtr;
213 	src += READ_LE_UINT16(src + icon * 4 + 0);
214 	decompressIcon(dst, src, 20, 10, 224, screen->pitch);
215 
216 	src = _iconFilePtr;
217 	src += READ_LE_UINT16(src + icon * 4 + 2);
218 	decompressIcon(dst, src, 20, 10, 208, screen->pitch);
219 
220 	_system->unlockScreen();
221 
222 	_videoLockOut &= ~0x8000;
223 }
224 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)225 void AGOSEngine_Simon1::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
226 	byte *dst;
227 	byte *src;
228 
229 	_videoLockOut |= 0x8000;
230 
231 	Graphics::Surface *screen = _system->lockScreen();
232 	dst = (byte *)screen->getPixels();
233 
234 	dst += (x + window->x) * 8;
235 	dst += (y * 25 + window->y) * screen->pitch;
236 
237 	if (getPlatform() == Common::kPlatformAmiga) {
238 		src = _iconFilePtr;
239 		src += READ_BE_UINT32(src + icon * 4);
240 		uint8 color = (getFeatures() & GF_32COLOR) ? 224 : 240;
241 		decompressIconPlanar(dst, src, 24, 12, color, screen->pitch);
242 	} else {
243 		src = _iconFilePtr;
244 		src += READ_LE_UINT16(src + icon * 2);
245 		decompressIcon(dst, src, 24, 12, 224, screen->pitch);
246 	}
247 
248 	_system->unlockScreen();
249 
250 	_videoLockOut &= ~0x8000;
251 }
252 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)253 void AGOSEngine_Waxworks::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
254 	byte *dst;
255 	byte *src;
256 
257 	_videoLockOut |= 0x8000;
258 
259 	Graphics::Surface *screen = _system->lockScreen();
260 	dst = (byte *)screen->getPixels();
261 
262 	dst += (x + window->x) * 8;
263 	dst += (y * 20 + window->y) * screen->pitch;
264 
265 	uint8 color = dst[0] & 0xF0;
266 	if (getPlatform() == Common::kPlatformAmiga) {
267 		src = _iconFilePtr;
268 		src += READ_BE_UINT32(src + icon * 4);
269 		decompressIconPlanar(dst, src, 24, 10, color, screen->pitch);
270 	} else {
271 		src = _iconFilePtr;
272 		src += READ_LE_UINT16(src + icon * 2);
273 		decompressIcon(dst, src, 24, 10, color, screen->pitch);
274 	}
275 
276 	_system->unlockScreen();
277 
278 	_videoLockOut &= ~0x8000;
279 }
280 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)281 void AGOSEngine_Elvira2::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
282 	byte *dst;
283 	byte *src;
284 
285 	_videoLockOut |= 0x8000;
286 
287 	Graphics::Surface *screen = _system->lockScreen();
288 	dst = (byte *)screen->getPixels();
289 
290 	dst += (x + window->x) * 8;
291 	dst += (y * 8 + window->y) * screen->pitch;
292 
293 	uint color = dst[0] & 0xF0;
294 	if (getFeatures() & GF_PLANAR) {
295 		src = _iconFilePtr;
296 		src += READ_BE_UINT32(src + icon * 4);
297 		decompressIconPlanar(dst, src, 24, 12, color, screen->pitch);
298 	} else {
299 		src = _iconFilePtr;
300 		src += READ_LE_UINT16(src + icon * 2);
301 		decompressIcon(dst, src, 24, 12, color, screen->pitch);
302 	}
303 
304 	_system->unlockScreen();
305 
306 	_videoLockOut &= ~0x8000;
307 }
308 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)309 void AGOSEngine_Elvira1::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
310 	byte *dst;
311 	byte *src;
312 
313 	_videoLockOut |= 0x8000;
314 
315 	Graphics::Surface *screen = _system->lockScreen();
316 	dst = (byte *)screen->getPixels();
317 
318 	dst += (x + window->x) * 8;
319 	dst += (y * 8 + window->y) * screen->pitch;
320 
321 	if (getFeatures() & GF_PLANAR) {
322 		src = _iconFilePtr;
323 		src += READ_BE_UINT16(src + icon * 2);
324 		decompressIconPlanar(dst, src, 24, 12, 16, screen->pitch);
325 	} else {
326 		src = _iconFilePtr;
327 		src += icon * 288;
328 		decompressIconPlanar(dst, src, 24, 12, 16, screen->pitch, false);
329 	}
330 
331 	_system->unlockScreen();
332 
333 	_videoLockOut &= ~0x8000;
334 }
335 
drawIcon(WindowBlock * window,uint icon,uint x,uint y)336 void AGOSEngine::drawIcon(WindowBlock *window, uint icon, uint x, uint y) {
337 	byte *dst;
338 	byte *src;
339 
340 	_videoLockOut |= 0x8000;
341 
342 	Graphics::Surface *screen = _system->lockScreen();
343 	dst = (byte *)screen->getBasePtr(x * 8, y);
344 	src = _iconFilePtr + icon * 146;
345 
346 	if (icon == 0xFF) {
347 		// Draw Blank Icon
348 		for (int yp = 0; yp < 24; yp++) {
349 			memset(dst, 0, 24);
350 			dst += screen->pitch;
351 		}
352 	} else {
353 		uint8 palette[4];
354 		palette[0] = *src >> 4;
355 		palette[1] = *src++ & 0xf;
356 		palette[2] = *src >> 4;
357 		palette[3] = *src++ & 0xf;
358 		for (int yp = 0; yp < 24; ++yp, src += 6) {
359 			// Get bit-set representing the 24 pixels for the line
360 			uint32 v1 = (READ_BE_UINT16(src) << 8) | *(src + 4);
361 			uint32 v2 = (READ_BE_UINT16(src + 2) << 8) | *(src + 5);
362 			for (int xp = 0; xp < 24; ++xp, v1 >>= 1, v2 >>= 1) {
363 				dst[yp * screen->pitch + (23 - xp)] = palette[((v1 & 1) << 1) | (v2 & 1)];
364 			}
365 		}
366 	}
367 
368 	_system->unlockScreen();
369 
370 	_videoLockOut &= ~0x8000;
371 }
372 
373 #ifdef ENABLE_AGOS2
drawIconArray(uint num,Item * itemRef,int line,int classMask)374 void AGOSEngine_Feeble::drawIconArray(uint num, Item *itemRef, int line, int classMask) {
375 	Item *item_ptr_org = itemRef;
376 	WindowBlock *window;
377 	uint16 flagnumber = 201;
378 	uint16 iconperline = 458;
379 	uint16 iconsdown = 384;
380 	uint16 idone = 0;
381 	uint16 icount = 0;
382 	uint16 xp = 188, yp = 306;
383 	int k;
384 	_iOverflow = 0;
385 
386 	line = _variableArray[30];
387 	if (line == 0)
388 		_variableArray[31] = 0;
389 
390 	window = _windowArray[num & 7];
391 	if (window == NULL)
392 		return;
393 
394 	for (k = flagnumber; k <= flagnumber + 18; k++)
395 		_variableArray[k] = 0;
396 
397 	if (window->iconPtr)
398 		removeIconArray(num);
399 
400 	window->iconPtr=(IconBlock *)malloc(sizeof(IconBlock));
401 	window->iconPtr->itemRef = itemRef;
402 	window->iconPtr->upArrow = -1;
403 	window->iconPtr->downArrow = -1;
404 	window->iconPtr->line = line;
405 	window->iconPtr->classMask = classMask;
406 
407 	itemRef = derefItem(itemRef->child);
408 	k = flagnumber;
409 
410 	while (itemRef && (line > 65)) {
411 		uint16 ct = xp;
412 		while (itemRef && ct < iconperline) {
413 			if ((classMask == 0) || ((itemRef->classFlags & classMask) != 0)) {
414 				if (hasIcon(itemRef)) {
415 					ct += 45;
416 					k++;
417 				}
418 			}
419 			itemRef = derefItem(itemRef->next);
420 		}
421 		line -= 52;
422 		if (k == (flagnumber + 18))
423 			k = flagnumber;
424 	}
425 	yp -= line;	// Adjust starting y
426 
427 	if (itemRef == NULL) {
428 		window->iconPtr->line = 0;
429 		itemRef = derefItem(item_ptr_org->child);
430 	}
431 
432 	while (itemRef) {
433 		if ((classMask != 0) && ((itemRef->classFlags & classMask) == 0))
434 			goto l1;
435 		if (hasIcon(itemRef) == 0)
436 			goto l1;
437 		if (!idone) {
438 /*
439  *	Create thee icon and graphics rendering
440  */
441 			window->iconPtr->iconArray[icount].item = itemRef;
442 			_variableArray[k] = itemGetIconNumber(itemRef);
443 			window->iconPtr->iconArray[icount++].boxCode =
444 				setupIconHitArea(window, k++, xp, yp, itemRef);
445 		} else {
446 /*
447  *	Just remember the overflow has occurred
448  */
449 			window->iconPtr->iconArray[icount].item = NULL;	/* END MARKINGS */
450 			_iOverflow = 1;
451 		}
452 		xp += 45;
453 		if (xp >= iconperline) {	/* End of line ? */
454 			if (k == (flagnumber + 18))
455 				k = flagnumber;
456 			xp = 188;
457 			yp += 52;		/* Move down */
458 			if (yp >= iconsdown) {	/* Full ? */
459 				idone = 1;	/* Note completed screen */
460 			}
461 		}
462 l1:;		itemRef = derefItem(itemRef->next);
463 	}
464 	window->iconPtr->iconArray[icount].item = NULL;	/* END MARKINGS */
465 	if (_variableArray[30] == 0) {
466 		if (yp != 306)
467 			_variableArray[31] = 52;
468 		if ((xp == 188) && (yp == 358))
469 			_variableArray[31] = 0;
470 	}
471 
472 	/* Plot arrows and add their boxes */
473 	addArrows(window, num);
474 	window->iconPtr->upArrow = _scrollUpHitArea;
475 	window->iconPtr->downArrow = _scrollDownHitArea;
476 }
477 #endif
478 
drawIconArray(uint num,Item * itemRef,int line,int classMask)479 void AGOSEngine::drawIconArray(uint num, Item *itemRef, int line, int classMask) {
480 	Item *item_ptr_org = itemRef;
481 	WindowBlock *window;
482 	uint width, height;
483 	uint k, curWidth;
484 	bool item_again, showArrows;
485 	uint x_pos, y_pos;
486 	const int iconSize = (getGameType() == GType_SIMON2) ? 20 : 1;
487 
488 	window = _windowArray[num & 7];
489 
490 	if (getGameType() == GType_SIMON2) {
491 		width = 100;
492 		height = 40;
493 	} else if (getGameType() == GType_WW) {
494 		width = window->width / 3;
495 		height = window->height / 2;
496 	} else {
497 		width = window->width / 3;
498 		height = window->height / 3;
499 	}
500 
501 	if (window == NULL)
502 		return;
503 
504 	if (window->iconPtr)
505 		removeIconArray(num);
506 
507 	window->iconPtr = (IconBlock *) malloc(sizeof(IconBlock));
508 	window->iconPtr->itemRef = itemRef;
509 	window->iconPtr->upArrow = -1;
510 	window->iconPtr->downArrow = -1;
511 	window->iconPtr->line = line;
512 	window->iconPtr->classMask = classMask;
513 
514 	itemRef = derefItem(itemRef->child);
515 
516 	while (itemRef && line-- != 0) {
517 		curWidth = 0;
518 		while (itemRef && width > curWidth) {
519 			if ((classMask == 0 || itemRef->classFlags & classMask) && hasIcon(itemRef))
520 				curWidth += iconSize;
521 			itemRef = derefItem(itemRef->next);
522 		}
523 	}
524 
525 	if (itemRef == NULL) {
526 		window->iconPtr->line = 0;
527 		itemRef = derefItem(item_ptr_org->child);
528 	}
529 
530 	x_pos = 0;
531 	y_pos = 0;
532 	k = 0;
533 	item_again = false;
534 	showArrows = false;
535 
536 	while (itemRef) {
537 		if ((classMask == 0 || itemRef->classFlags & classMask) && hasIcon(itemRef)) {
538 			if (item_again == false) {
539 				window->iconPtr->iconArray[k].item = itemRef;
540 				if (getGameType() == GType_SIMON2) {
541 					drawIcon(window, itemGetIconNumber(itemRef), x_pos, y_pos);
542 					window->iconPtr->iconArray[k].boxCode =
543 						setupIconHitArea(window, 0, x_pos, y_pos, itemRef);
544 				} else if (getGameType() == GType_SIMON1 || getGameType() == GType_WW) {
545 					drawIcon(window, itemGetIconNumber(itemRef), x_pos * 3, y_pos);
546 					window->iconPtr->iconArray[k].boxCode =
547 						setupIconHitArea(window, 0, x_pos * 3, y_pos, itemRef);
548 				} else {
549 					drawIcon(window, itemGetIconNumber(itemRef), x_pos * 3, y_pos * 3);
550 					window->iconPtr->iconArray[k].boxCode =
551 						setupIconHitArea(window, 0, x_pos * 3, y_pos * 3, itemRef);
552 				}
553 				k++;
554 			} else {
555 				window->iconPtr->iconArray[k].item = NULL;
556 				showArrows = 1;
557 			}
558 
559 			x_pos += iconSize;
560 			if (x_pos >= width) {
561 				x_pos = 0;
562 				y_pos += iconSize;
563 				if (y_pos >= height)
564 					item_again = true;
565 			}
566 		}
567 		itemRef = derefItem(itemRef->next);
568 	}
569 
570 	window->iconPtr->iconArray[k].item = NULL;
571 
572 	if (showArrows != 0 || window->iconPtr->line != 0) {
573 		/* Plot arrows and add their boxes */
574 		addArrows(window, num);
575 		window->iconPtr->upArrow = _scrollUpHitArea;
576 		window->iconPtr->downArrow = _scrollDownHitArea;
577 	}
578 }
579 
580 #ifdef ENABLE_AGOS2
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)581 uint AGOSEngine_Feeble::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
582 	HitArea *ha = findEmptyHitArea();
583 
584 	ha->x = x;
585 	ha->y = y;
586 	ha->itemPtr = itemPtr;
587 	ha->width = 45;
588 	ha->height = 44;
589 	ha->flags = kBFBoxInUse | kBFBoxItem;
590 	ha->id = num;
591 	ha->priority = 100;
592 	ha->verb = 208;
593 
594 	return ha - _hitAreas;
595 }
596 #endif
597 
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)598 uint AGOSEngine_Simon2::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
599 	HitArea *ha = findEmptyHitArea();
600 
601 	ha->x = x + 110;
602 	ha->y = window->y + y;
603 	ha->itemPtr = itemPtr;
604 	ha->width = 20;
605 	ha->height = 20;
606 	ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
607 	ha->id = 0x7FFD;
608 	ha->priority = 100;
609 	ha->verb = 208;
610 
611 	return ha - _hitAreas;
612 }
613 
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)614 uint AGOSEngine_Simon1::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
615 	HitArea *ha = findEmptyHitArea();
616 
617 	ha->x = (x + window->x) * 8;
618 	ha->y = y * 25 + window->y;
619 	ha->itemPtr = itemPtr;
620 	ha->width = 24;
621 	ha->height = 24;
622 	ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
623 	ha->id = 0x7FFD;
624 	ha->priority = 100;
625 	ha->verb = 208;
626 
627 	return ha - _hitAreas;
628 }
629 
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)630 uint AGOSEngine_Waxworks::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
631 	HitArea *ha = findEmptyHitArea();
632 
633 	ha->x = (x + window->x) * 8;
634 	ha->y = y * 20 + window->y;
635 	ha->itemPtr = itemPtr;
636 	ha->width = 24;
637 	ha->height = 20;
638 	ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
639 	ha->id = 0x7FFD;
640 	ha->priority = 100;
641 	ha->verb = 208;
642 
643 	return ha - _hitAreas;
644 }
645 
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)646 uint AGOSEngine_Elvira2::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
647 	HitArea *ha = findEmptyHitArea();
648 
649 	ha->x = (x + window->x) * 8;
650 	ha->y = y * 8 + window->y;
651 	ha->itemPtr = itemPtr;
652 	ha->width = 24;
653 	ha->height = 24;
654 	ha->id = 0x7FFD;
655 	ha->priority = 100;
656 
657 	if (window->iconPtr->classMask == 2) {
658 		ha->flags = kBFDragBox | kBFBoxInUse;
659 		ha->verb = 248 + 0x4000;
660 	} else {
661 		ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
662 		ha->verb = 208;
663 	}
664 
665 	return ha - _hitAreas;
666 }
667 
setupIconHitArea(WindowBlock * window,uint num,uint x,uint y,Item * itemPtr)668 uint AGOSEngine::setupIconHitArea(WindowBlock *window, uint num, uint x, uint y, Item *itemPtr) {
669 	HitArea *ha = findEmptyHitArea();
670 
671 	ha->x = (x + window->x) * 8;
672 	ha->y = y * 8 + window->y;
673 	ha->itemPtr = itemPtr;
674 	ha->width = 24;
675 	ha->height = 24;
676 	ha->flags = kBFDragBox | kBFBoxInUse | kBFBoxItem;
677 	ha->id = 0x7FFD;
678 	ha->priority = 100;
679 	ha->verb = 253;
680 
681 	return ha - _hitAreas;
682 }
683 
684 #ifdef ENABLE_AGOS2
addArrows(WindowBlock * window,uint8 num)685 void AGOSEngine_Feeble::addArrows(WindowBlock *window, uint8 num) {
686 	HitArea *ha;
687 
688 	ha = findEmptyHitArea();
689 	_scrollUpHitArea = ha - _hitAreas;
690 
691 	ha->x = 496;
692 	ha->y = 279;
693 	ha->width = 30;
694 	ha->height = 45;
695 	ha->flags = kBFBoxInUse | kBFNoTouchName;
696 	ha->id = 0x7FFB;
697 	ha->priority = 100;
698 	ha->window = window;
699 	ha->verb = 1;
700 
701 	ha = findEmptyHitArea();
702 	_scrollDownHitArea = ha - _hitAreas;
703 
704 	ha->x = 496;
705 	ha->y = 324;
706 	ha->width = 30;
707 	ha->height = 44;
708 	ha->flags = kBFBoxInUse | kBFNoTouchName;
709 	ha->id = 0x7FFC;
710 	ha->priority = 100;
711 	ha->window = window;
712 	ha->verb = 1;
713 }
714 #endif
715 
addArrows(WindowBlock * window,uint8 num)716 void AGOSEngine_Simon2::addArrows(WindowBlock *window, uint8 num) {
717 	HitArea *ha;
718 
719 	ha = findEmptyHitArea();
720 	_scrollUpHitArea = ha - _hitAreas;
721 
722 	ha->x = 81;
723 	ha->y = 158;
724 	ha->width = 12;
725 	ha->height = 26;
726 	ha->flags = kBFBoxInUse | kBFNoTouchName;
727 	ha->id = 0x7FFB;
728 	ha->priority = 100;
729 	ha->window = window;
730 	ha->verb = 1;
731 
732 	ha = findEmptyHitArea();
733 	_scrollDownHitArea = ha - _hitAreas;
734 
735 	ha->x = 227;
736 	ha->y = 162;
737 	ha->width = 12;
738 	ha->height = 26;
739 	ha->flags = kBFBoxInUse | kBFNoTouchName;
740 	ha->id = 0x7FFC;
741 	ha->priority = 100;
742 	ha->window = window;
743 	ha->verb = 1;
744 }
745 
addArrows(WindowBlock * window,uint8 num)746 void AGOSEngine_Simon1::addArrows(WindowBlock *window, uint8 num) {
747 	HitArea *ha;
748 
749 	ha = findEmptyHitArea();
750 	_scrollUpHitArea = ha - _hitAreas;
751 
752 	ha->x = 308;
753 	ha->y = 149;
754 	ha->width = 12;
755 	ha->height = 17;
756 	ha->flags = kBFBoxInUse | kBFNoTouchName;
757 	ha->id = 0x7FFB;
758 	ha->priority = 100;
759 	ha->window = window;
760 	ha->verb = 1;
761 
762 	ha = findEmptyHitArea();
763 	_scrollDownHitArea = ha - _hitAreas;
764 
765 	ha->x = 308;
766 	ha->y = 176;
767 	ha->width = 12;
768 	ha->height = 17;
769 	ha->flags = kBFBoxInUse | kBFNoTouchName;
770 	ha->id = 0x7FFC;
771 	ha->priority = 100;
772 	ha->window = window;
773 	ha->verb = 1;
774 
775 	_videoLockOut |= 0x8;
776 
777 	VgaPointersEntry *vpe = &_vgaBufferPointers[1];
778 	byte *curVgaFile2Orig = _curVgaFile2;
779 	uint16 windowNumOrig = _windowNum;
780 	uint8 palette = (getPlatform() == Common::kPlatformAmiga) ? 15 : 14;
781 
782 	_windowNum = 0;
783 	_curVgaFile2 = vpe->vgaFile2;
784 	drawImage_init(1, palette, 38, 150, 4);
785 
786 	_curVgaFile2 = curVgaFile2Orig;
787 	_windowNum = windowNumOrig;
788 
789 	_videoLockOut &= ~0x8;
790 }
791 
addArrows(WindowBlock * window,uint8 num)792 void AGOSEngine_Waxworks::addArrows(WindowBlock *window, uint8 num) {
793 	HitArea *ha;
794 
795 	ha = findEmptyHitArea();
796 	_scrollUpHitArea = ha - _hitAreas;
797 
798 	setBitFlag(22, true);
799 	ha->x = 255;
800 	ha->y = 153;
801 	ha->width = 9;
802 	ha->height = 11;
803 	ha->flags = kBFBoxInUse | kBFNoTouchName;
804 	ha->id = 0x7FFB;
805 	ha->priority = 100;
806 	ha->window = window;
807 	ha->verb = 1;
808 
809 	ha = findEmptyHitArea();
810 	_scrollDownHitArea = ha - _hitAreas;
811 
812 	ha->x = 255;
813 	ha->y = 170;
814 	ha->width = 9;
815 	ha->height = 11;
816 	ha->flags = kBFBoxInUse | kBFNoTouchName;
817 	ha->id = 0x7FFC;
818 	ha->priority = 100;
819 	ha->window = window;
820 	ha->verb = 1;
821 	setWindowImageEx(6, 103);
822 }
823 
addArrows(WindowBlock * window,uint8 num)824 void AGOSEngine_Elvira2::addArrows(WindowBlock *window, uint8 num) {
825 	HitArea *ha;
826 
827 	ha = findEmptyHitArea();
828 	_scrollUpHitArea = ha - _hitAreas;
829 
830 	setBitFlag(21, true);
831 	ha->x = 54;
832 	ha->y = 154;
833 	ha->width = 12;
834 	ha->height = 10;
835 	ha->flags = kBFBoxInUse;
836 	ha->id = 0x7FFB;
837 	ha->priority = 100;
838 	ha->window = window;
839 	ha->verb = 1;
840 
841 	ha = findEmptyHitArea();
842 	_scrollDownHitArea = ha - _hitAreas;
843 
844 	ha->x = 54;
845 	ha->y = 178;
846 	ha->width = 12;
847 	ha->height = 10;
848 	ha->flags = kBFBoxInUse;
849 	ha->id = 0x7FFC;
850 	ha->priority = 100;
851 	ha->window = window;
852 	ha->verb = 1;
853 	setWindowImageEx(6, 106);
854 }
855 
addArrows(WindowBlock * window,uint8 num)856 void AGOSEngine::addArrows(WindowBlock *window, uint8 num) {
857 	HitArea *ha;
858 	uint16 x, y;
859 
860 	x = 30;
861 	y = 151;
862 	if (num != 2) {
863 		y = window->y + window->height * 4 - 19;
864 		x = window->x + window->width;
865 	}
866 	drawArrow(x, y, 16);
867 
868 	ha = findEmptyHitArea();
869 	_scrollUpHitArea = ha - _hitAreas;
870 
871 	ha->x = x * 8;
872 	ha->y = y;
873 	ha->width = 16;
874 	ha->height = 19;
875 	ha->flags = kBFBoxInUse;
876 	ha->id = 0x7FFB;
877 	ha->priority = 100;
878 	ha->window = window;
879 	ha->verb = 1;
880 
881 	x = 30;
882 	y = 170;
883 	if (num != 2) {
884 		y = window->y + window->height * 4;
885 		x = window->x + window->width;
886 	}
887 	drawArrow(x, y, -16);
888 
889 	ha = findEmptyHitArea();
890 	_scrollDownHitArea = ha - _hitAreas;
891 
892 	ha->x = x * 8;
893 	ha->y = y;
894 	ha->width = 16;
895 	ha->height = 19;
896 	ha->flags = kBFBoxInUse;
897 	ha->id = 0x7FFC;
898 	ha->priority = 100;
899 	ha->window = window;
900 	ha->verb = 1;
901 }
902 
903 static const byte _arrowImage[] = {
904 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
905 	0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
906 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
907 	0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
908 	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b,
909 	0x0a, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
910 	0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0a,
911 	0x0d, 0x0a, 0x0b, 0x0a, 0x00, 0x00, 0x00, 0x00,
912 	0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0a, 0x0d,
913 	0x03, 0x0d, 0x0a, 0x0b, 0x0a, 0x00, 0x00, 0x00,
914 	0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0a, 0x0d, 0x03,
915 	0x04, 0x03, 0x0d, 0x0a, 0x0b, 0x0a, 0x00, 0x00,
916 	0x00, 0x00, 0x0a, 0x0b, 0x0a, 0x0d, 0x03, 0x04,
917 	0x0f, 0x04, 0x03, 0x0d, 0x0a, 0x0b, 0x0a, 0x00,
918 	0x00, 0x0a, 0x0b, 0x0a, 0x0d, 0x0d, 0x0d, 0x03,
919 	0x04, 0x03, 0x0d, 0x0d, 0x0d, 0x0a, 0x0b, 0x0a,
920 	0x00, 0x0b, 0x0a, 0x0a, 0x0a, 0x0a, 0x09, 0x0d,
921 	0x03, 0x0d, 0x09, 0x0a, 0x0a, 0x0a, 0x0a, 0x0b,
922 	0x00, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x0d,
923 	0x0d, 0x0d, 0x0a, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
924 	0x00, 0x0a, 0x0a, 0x0a, 0x0e, 0x0b, 0x0b, 0x0c,
925 	0x0e, 0x0c, 0x0b, 0x0b, 0x0e, 0x0a, 0x0a, 0x0a,
926 	0x00, 0x00, 0x02, 0x02, 0x0a, 0x0b, 0x0a, 0x0d,
927 	0x0d, 0x0d, 0x0a, 0x0b, 0x0a, 0x02, 0x02, 0x00,
928 	0x00, 0x00, 0x00, 0x02, 0x0a, 0x0b, 0x0b, 0x0c,
929 	0x0e, 0x0c, 0x0b, 0x0b, 0x0a, 0x02, 0x00, 0x00,
930 	0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0a, 0x0d,
931 	0x0d, 0x0d, 0x0a, 0x0b, 0x0a, 0x00, 0x00, 0x00,
932 	0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0b, 0x0c,
933 	0x0e, 0x0c, 0x0b, 0x0b, 0x0a, 0x00, 0x00, 0x00,
934 	0x00, 0x00, 0x00, 0x00, 0x0a, 0x0b, 0x0b, 0x0b,
935 	0x0b, 0x0b, 0x0b, 0x0b, 0x0a, 0x00, 0x00, 0x00,
936 	0x00, 0x00, 0x00, 0x00, 0x02, 0x0e, 0x0a, 0x0a,
937 	0x0e, 0x0a, 0x0a, 0x0e, 0x02, 0x00, 0x00, 0x00,
938 	0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00,
939 	0x0a, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00,
940 	0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00,
941 	0x02, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00,
942 };
943 
drawArrow(uint16 x,uint16 y,int8 dir)944 void AGOSEngine::drawArrow(uint16 x, uint16 y, int8 dir) {
945 	const byte *src;
946 	uint8 w, h;
947 
948 	if (dir < 0) {
949 		src = _arrowImage + 288;
950 	} else {
951 		src = _arrowImage;
952 	}
953 
954 	Graphics::Surface *screen = _system->lockScreen();
955 	byte *dst = (byte *)screen->getBasePtr(x * 8, y);
956 
957 	for (h = 0; h < 19; h++) {
958 		for (w = 0; w < 16; w++) {
959 			if (src[w])
960 				dst[w] = src[w] + 16;
961 		}
962 
963 		src += dir;
964 		dst+= screen->pitch;
965 	}
966 
967 	_system->unlockScreen();
968 }
969 
removeArrows(WindowBlock * window,uint num)970 void AGOSEngine_Simon1::removeArrows(WindowBlock *window, uint num) {
971 	if (getGameType() == GType_SIMON1) {
972 		restoreBlock(304, 146, 320, 200);
973 	}
974 }
975 
removeArrows(WindowBlock * window,uint num)976 void AGOSEngine_Waxworks::removeArrows(WindowBlock *window, uint num) {
977 	setBitFlag(22, false);
978 	setWindowImageEx(6, 103);
979 }
980 
removeArrows(WindowBlock * window,uint num)981 void AGOSEngine_Elvira2::removeArrows(WindowBlock *window, uint num) {
982 	setBitFlag(21, false);
983 	setWindowImageEx(6, 106);
984 }
985 
removeArrows(WindowBlock * window,uint num)986 void AGOSEngine::removeArrows(WindowBlock *window, uint num) {
987 	if (num != 2) {
988 		uint y = window->y + window->height * 4 - 19;
989 		uint x = (window->x + window->width) * 8;
990 		restoreBlock(x, y, x + 16, y + 38);
991 	} else {
992 		colorBlock(window, 240, 151, 16, 38);
993 	}
994 }
995 
removeIconArray(uint num)996 void AGOSEngine::removeIconArray(uint num) {
997 	WindowBlock *window;
998 	uint16 curWindow;
999 	uint16 i;
1000 
1001 	window = _windowArray[num & 7];
1002 	curWindow = _curWindow;
1003 
1004 	if (window == NULL || window->iconPtr == NULL)
1005 		return;
1006 
1007 	if (getGameType() != GType_FF && getGameType() != GType_PP) {
1008 		changeWindow(num);
1009 		sendWindow(12);
1010 		changeWindow(curWindow);
1011 	}
1012 
1013 	for (i = 0; window->iconPtr->iconArray[i].item != NULL; i++) {
1014 		freeBox(window->iconPtr->iconArray[i].boxCode);
1015 	}
1016 
1017 	if (window->iconPtr->upArrow != -1) {
1018 		freeBox(window->iconPtr->upArrow);
1019 	}
1020 
1021 	if (window->iconPtr->downArrow != -1) {
1022 		freeBox(window->iconPtr->downArrow);
1023 		removeArrows(window, num);
1024 	}
1025 
1026 	free(window->iconPtr);
1027 	window->iconPtr = NULL;
1028 
1029 	_fcsData1[num] = 0;
1030 	_fcsData2[num] = 0;
1031 }
1032 
1033 static const byte hitBarData[12 * 7] = {
1034 	0x3C, 0x00, 0x80, 0x00, 0x88, 0x00, 0x00, 0x03, 0x80, 0x00, 0x00, 0x00,
1035 	0x20, 0x00, 0x04, 0x00, 0xD8, 0x00, 0x00, 0x04, 0x48, 0x00, 0x00, 0x00,
1036 	0x20, 0x89, 0x8E, 0x00, 0xA8, 0x86, 0x10, 0x04, 0x08, 0x21, 0x88, 0x00,
1037 	0x38, 0x50, 0x84, 0x00, 0x89, 0x49, 0x28, 0x04, 0x08, 0x52, 0x14, 0x00,
1038 	0x20, 0x20, 0x84, 0x00, 0x89, 0x48, 0x38, 0x04, 0x08, 0x53, 0x9C, 0x00,
1039 	0x20, 0x50, 0x84, 0x00, 0x89, 0x48, 0x20, 0x04, 0x48, 0x50, 0x90, 0x00,
1040 	0x3C, 0x89, 0xC3, 0x00, 0x88, 0x88, 0x18, 0x03, 0x86, 0x23, 0x0C, 0x00
1041 };
1042 
1043 // Personal Nightmare specific
drawIconHitBar()1044 void AGOSEngine_PN::drawIconHitBar() {
1045 	Graphics::Surface *screen = _system->lockScreen();
1046 	byte *dst = (byte *)screen->getBasePtr(6 * 8, 3);
1047 	const byte *src = hitBarData;
1048 	uint8 color = (getPlatform() == Common::kPlatformDOS) ? 7 : 15;
1049 
1050 	for (int h = 0; h < 7; h++) {
1051 		for (int w = 0; w < 12; w++) {
1052 			int8 b = *src++;
1053 			for (int i = 0; i < 8; i++) {
1054 				if (b < 0) {
1055 					dst[w * 8 + i] = color;
1056 				}
1057 
1058 				b <<= 1;
1059 			}
1060 		}
1061 		dst += screen->pitch;
1062 	}
1063 
1064 	_system->unlockScreen();
1065 }
1066 
iconPage()1067 void AGOSEngine_PN::iconPage() {
1068 	_objectCountS = -1;
1069 
1070 	mouseOff();
1071 
1072 	uint8 objRoom = getptr(_quickptr[12] + _variableArray[210] * _quickshort[5] + 20);
1073 	uint8 iconNum = getptr(_quickptr[0] + objRoom * _quickshort[0] + 4);
1074 
1075 	drawIcon(NULL, iconNum, 6, 12);
1076 
1077 	HitArea *ha = _invHitAreas + 5;
1078 	for (uint8 r = 0; r < 5; r++) {
1079 		for (uint8 i = 0; i < 7; i++) {
1080 			printIcon(ha, i, r);
1081 			ha++;
1082 		}
1083 	}
1084 
1085 	mouseOn();
1086 }
1087 
ifObjectInInv(uint16 a)1088 bool AGOSEngine_PN::ifObjectInInv(uint16 a) {
1089 	return _variableArray[210] == getptr(_quickptr[11] + a * _quickshort[4] + 2);
1090 }
1091 
testContainer(uint16 a)1092 bool AGOSEngine_PN::testContainer(uint16 a) {
1093 	return bitextract(_quickptr[1] + a * _quickshort[1], 0) != 0;
1094 }
1095 
testObvious(uint16 a)1096 bool AGOSEngine_PN::testObvious(uint16 a) {
1097 	return bitextract(_quickptr[1] + a * _quickshort[1], 4) != 0;
1098 }
1099 
testSeen(uint16 a)1100 bool AGOSEngine_PN::testSeen(uint16 a) {
1101 	return bitextract(_quickptr[1] + a * _quickshort[1], 3) != 0;
1102 }
1103 
printIcon(HitArea * ha,uint8 i,uint8 r)1104 void AGOSEngine_PN::printIcon(HitArea *ha, uint8 i, uint8 r) {
1105 	 if (_objects == _objectCountS) {
1106 		ha->flags |= kOBFBoxDisabled;
1107 		drawIcon(NULL, 0xFF, 12 + i * 3, 12 + 24 * r);
1108 	} else {
1109 		_objectCountS++;
1110 		if (!ifObjectInInv(_objectCountS) || !testObvious(_objectCountS)) {
1111 			printIcon(ha, i, r);
1112 		} else {
1113 
1114 			uint8 iconNum = getptr(_quickptr[0] + _objectCountS * _quickshort[0] + 4);
1115 			drawIcon(NULL, iconNum, 12 + i * 3, 12 + 24 * r);
1116 
1117 			ha->msg1 = _objectCountS | 0x8000;
1118 			ha->flags &= ~kOBFBoxDisabled;
1119 		}
1120 	}
1121 }
1122 
1123 } // End of namespace AGOS
1124