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 "scumm/scumm.h"
24 #include "scumm/actor.h"
25 #include "scumm/akos.h"
26 #include "scumm/bomp.h"
27 #include "scumm/imuse/imuse.h"
28 #include "scumm/imuse_digi/dimuse.h"
29 #include "scumm/he/intern_he.h"
30 #include "scumm/resource.h"
31 #include "scumm/scumm_v7.h"
32 #include "scumm/sound.h"
33 #include "scumm/util.h"
34 #include "scumm/he/wiz_he.h"
35 
36 namespace Scumm {
37 
38 #include "common/pack-start.h"	// START STRUCT PACKING
39 
40 struct AkosHeader {
41 	byte unk_1[2];
42 	byte flags;
43 	byte unk_2;
44 	uint16 num_anims;
45 	uint16 unk_3;
46 	uint16 codec;
47 } PACKED_STRUCT;
48 
49 struct AkosOffset {
50 	uint32 akcd;	// offset into the akcd data
51 	uint16 akci;	// offset into the akci data
52 } PACKED_STRUCT;
53 
54 #include "common/pack-end.h"	// END STRUCT PACKING
55 
56 
57 enum AkosOpcodes {
58 	AKC_Return = 0xC001,
59 	AKC_SetVar = 0xC010,
60 	AKC_CmdQue3 = 0xC015,
61 	AKC_C016 = 0xC016,
62 	AKC_C017 = 0xC017,
63 	AKC_C018 = 0xC018,
64 	AKC_C019 = 0xC019,
65 	AKC_ComplexChan = 0xC020,
66 	AKC_C021 = 0xC021,
67 	AKC_C022 = 0xC022,
68 	AKC_ComplexChan2 = 0xC025,
69 	AKC_Jump = 0xC030,
70 	AKC_JumpIfSet = 0xC031,
71 	AKC_AddVar = 0xC040,
72 	AKC_C042 = 0xC042,
73 	AKC_C044 = 0xC044,
74 	AKC_C045 = 0xC045,
75 	AKC_C046 = 0xC046,
76 	AKC_C047 = 0xC047,
77 	AKC_C048 = 0xC048,
78 	AKC_Ignore = 0xC050,
79 	AKC_IncVar = 0xC060,
80 	AKC_CmdQue3Quick = 0xC061,
81 	AKC_JumpStart = 0xC070,
82 	AKC_JumpE = 0xC070,
83 	AKC_JumpNE = 0xC071,
84 	AKC_JumpL = 0xC072,
85 	AKC_JumpLE = 0xC073,
86 	AKC_JumpG = 0xC074,
87 	AKC_JumpGE = 0xC075,
88 	AKC_StartAnim = 0xC080,
89 	AKC_StartVarAnim = 0xC081,
90 	AKC_Random = 0xC082,
91 	AKC_SetActorClip = 0xC083,
92 	AKC_StartAnimInActor = 0xC084,
93 	AKC_SetVarInActor = 0xC085,
94 	AKC_HideActor = 0xC086,
95 	AKC_SetDrawOffs = 0xC087,
96 	AKC_JumpTable = 0xC088,
97 	AKC_SoundStuff = 0xC089,
98 	AKC_Flip = 0xC08A,
99 	AKC_Cmd3 = 0xC08B,
100 	AKC_Ignore3 = 0xC08C,
101 	AKC_Ignore2 = 0xC08D,
102 	AKC_C08E = 0xC08E,
103 	AKC_SkipStart = 0xC090,
104 	AKC_SkipE = 0xC090,
105 	AKC_SkipNE = 0xC091,
106 	AKC_SkipL = 0xC092,
107 	AKC_SkipLE = 0xC093,
108 	AKC_SkipG = 0xC094,
109 	AKC_SkipGE = 0xC095,
110 	AKC_ClearFlag = 0xC09F,
111 	AKC_C0A0 = 0xC0A0,
112 	AKC_C0A1 = 0xC0A1,
113 	AKC_C0A2 = 0xC0A2,
114 	AKC_C0A3 = 0xC0A3,
115 	AKC_C0A4 = 0xC0A4,
116 	AKC_C0A5 = 0xC0A5,
117 	AKC_C0A6 = 0xC0A6,
118 	AKC_C0A7 = 0xC0A7,
119 	AKC_EndSeq = 0xC0FF
120 };
121 
akos_compare(int a,int b,byte cmd)122 static bool akos_compare(int a, int b, byte cmd) {
123 	switch (cmd) {
124 	case 0:
125 		return a == b;
126 	case 1:
127 		return a != b;
128 	case 2:
129 		return a < b;
130 	case 3:
131 		return a <= b;
132 	case 4:
133 		return a > b;
134 	default:
135 		return a >= b;
136 	}
137 }
138 
loadCostume(int id)139 void AkosCostumeLoader::loadCostume(int id) {
140 	_akos = _vm->getResourceAddress(rtCostume, id);
141 	assert(_akos);
142 }
143 
hasManyDirections()144 bool AkosCostumeLoader::hasManyDirections() {
145 	const AkosHeader *akhd;
146 
147 	akhd = (const AkosHeader *)_vm->findResourceData(MKTAG('A','K','H','D'), _akos);
148 	return (akhd->flags & 2) != 0;
149 }
150 
costumeDecodeData(Actor * a,int frame,uint usemask)151 void AkosCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) {
152 	uint anim;
153 	const byte *r;
154 	const AkosHeader *akhd;
155 	uint offs;
156 	int i;
157 	byte code;
158 	uint16 start, len;
159 	uint16 mask;
160 
161 	if (a->_costume == 0)
162 		return;
163 
164 	loadCostume(a->_costume);
165 
166 	if (_vm->_game.version >= 7 && hasManyDirections())
167 		anim = toSimpleDir(1, a->getFacing()) + frame * 8;
168 	else
169 		anim = newDirToOldDir(a->getFacing()) + frame * 4;
170 
171 	akhd = (const AkosHeader *)_vm->findResourceData(MKTAG('A','K','H','D'), _akos);
172 
173 	if (anim >= READ_LE_UINT16(&akhd->num_anims))
174 		return;
175 
176 	r = _vm->findResourceData(MKTAG('A','K','C','H'), _akos);
177 	assert(r);
178 
179 	offs = READ_LE_UINT16(r + anim * sizeof(uint16));
180 	if (offs == 0)
181 		return;
182 	r += offs;
183 
184 	const uint8 *akstPtr = _vm->findResourceData(MKTAG('A','K','S','T'), _akos);
185 	const uint8 *aksfPtr = _vm->findResourceData(MKTAG('A','K','S','F'), _akos);
186 
187 	i = 0;
188 	mask = READ_LE_UINT16(r); r += 2;
189 	do {
190 		if (mask & 0x8000) {
191 			const uint8 *akst = akstPtr;
192 			const uint8 *aksf = aksfPtr;
193 
194 			code = *r++;
195 			if (usemask & 0x8000) {
196 				switch (code) {
197 				case 1:
198 					a->_cost.active[i] = 0;
199 					a->_cost.frame[i] = frame;
200 					a->_cost.end[i] = 0;
201 					a->_cost.start[i] = 0;
202 					a->_cost.curpos[i] = 0;
203 					a->_cost.heCondMaskTable[i] = 0;
204 
205 					if (akst) {
206 						int size = _vm->getResourceDataSize(akst) / 8;
207 						if (size > 0) {
208 							bool found = false;
209 							while (size--) {
210 								if (READ_LE_UINT32(akst) == 0) {
211 									a->_cost.heCondMaskTable[i] = READ_LE_UINT32(akst + 4);
212 									found = true;
213 									break;
214 								}
215 								akst += 8;
216 							}
217 							if (!found) {
218 								error("Sequence not found in actor %p costume %d", (void *)a, a->_costume);
219 							}
220 						}
221 					}
222 					break;
223 				case 4:
224 					a->_cost.stopped |= 1 << i;
225 					break;
226 				case 5:
227 					a->_cost.stopped &= ~(1 << i);
228 					break;
229 				default:
230 					start = READ_LE_UINT16(r); r += 2;
231 					len = READ_LE_UINT16(r); r += 2;
232 
233 					a->_cost.heJumpOffsetTable[i] = 0;
234 					a->_cost.heJumpCountTable[i] = 0;
235 					if (aksf) {
236 						int size = _vm->getResourceDataSize(aksf) / 6;
237 						if (size > 0) {
238 							bool found = false;
239 							while (size--) {
240 								if (READ_LE_UINT16(aksf) == start) {
241 									a->_cost.heJumpOffsetTable[i] = READ_LE_UINT16(aksf + 2);
242 									a->_cost.heJumpCountTable[i] = READ_LE_UINT16(aksf + 4);
243 									found = true;
244 									break;
245 								}
246 								aksf += 6;
247 							}
248 							if (!found) {
249 								error("Sequence not found in actor %p costume %d", (void *)a, a->_costume);
250 							}
251 						}
252 					}
253 
254 					a->_cost.active[i] = code;
255 					a->_cost.frame[i] = frame;
256 					a->_cost.end[i] = start + len;
257 					a->_cost.start[i] = start;
258 					a->_cost.curpos[i] = start;
259 					a->_cost.heCondMaskTable[i] = 0;
260 					if (akst) {
261 						int size = _vm->getResourceDataSize(akst) / 8;
262 						if (size > 0) {
263 							bool found = false;
264 							while (size--) {
265 								if (READ_LE_UINT32(akst) == start) {
266 									a->_cost.heCondMaskTable[i] = READ_LE_UINT32(akst + 4);
267 									found = true;
268 									break;
269 								}
270 								akst += 8;
271 							}
272 							if (!found) {
273 								error("Sequence not found in actor %p costume %d", (void *)a, a->_costume);
274 							}
275 						}
276 					}
277 					break;
278 				}
279 			} else {
280 				if (code != 1 && code != 4 && code != 5)
281 					r += sizeof(uint16) * 2;
282 			}
283 		}
284 		i++;
285 		mask <<= 1;
286 		usemask <<= 1;
287 	} while ((uint16)mask);
288 }
289 
setPalette(uint16 * new_palette)290 void AkosRenderer::setPalette(uint16 *new_palette) {
291 	uint size, i;
292 
293 	size = _vm->getResourceDataSize(akpl);
294 	if (size == 0)
295 		return;
296 
297 	if (size > 256)
298 		error("akos_setPalette: %d is too many colors", size);
299 
300 	if (_vm->_game.features & GF_16BIT_COLOR) {
301 		if (_paletteNum) {
302 			for (i = 0; i < size; i++)
303 				_palette[i] = READ_LE_UINT16(_vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768 + akpl[i] * 2);
304 		} else if (rgbs) {
305 			for (i = 0; i < size; i++) {
306 				if (new_palette[i] == 0xFF) {
307 					uint8 col = akpl[i];
308 					_palette[i] = _vm->get16BitColor(rgbs[col * 3 + 0], rgbs[col * 3 + 1], rgbs[col * 3 + 2]);
309 				} else {
310 					_palette[i] = new_palette[i];
311 				}
312 			}
313 		}
314 	} else if (_vm->_game.heversion >= 99 && _paletteNum) {
315 		for (i = 0; i < size; i++)
316 			_palette[i] = (byte)_vm->_hePalettes[_paletteNum * _vm->_hePaletteSlot + 768 + akpl[i]];
317 	} else {
318 		for (i = 0; i < size; i++) {
319 			_palette[i] = new_palette[i] != 0xFF ? new_palette[i] : akpl[i];
320 		}
321 	}
322 
323 	if (_vm->_game.heversion == 70) {
324 		for (i = 0; i < size; i++)
325 			_palette[i] = _vm->_HEV7ActorPalette[_palette[i]];
326 	}
327 
328 	if (size == 256) {
329 		byte color = new_palette[0];
330 		if (color == 255) {
331 			_palette[0] = color;
332 		} else {
333 			_useBompPalette = true;
334 		}
335 	}
336 }
337 
setCostume(int costume,int shadow)338 void AkosRenderer::setCostume(int costume, int shadow) {
339 	const byte *akos = _vm->getResourceAddress(rtCostume, costume);
340 	assert(akos);
341 
342 	akhd = (const AkosHeader *) _vm->findResourceData(MKTAG('A','K','H','D'), akos);
343 	akof = (const AkosOffset *) _vm->findResourceData(MKTAG('A','K','O','F'), akos);
344 	akci = _vm->findResourceData(MKTAG('A','K','C','I'), akos);
345 	aksq = _vm->findResourceData(MKTAG('A','K','S','Q'), akos);
346 	akcd = _vm->findResourceData(MKTAG('A','K','C','D'), akos);
347 	akpl = _vm->findResourceData(MKTAG('A','K','P','L'), akos);
348 	_codec = READ_LE_UINT16(&akhd->codec);
349 	akct = _vm->findResourceData(MKTAG('A','K','C','T'), akos);
350 	rgbs = _vm->findResourceData(MKTAG('R','G','B','S'), akos);
351 
352 	xmap = 0;
353 	if (shadow) {
354 		const uint8 *xmapPtr = _vm->getResourceAddress(rtImage, shadow);
355 		assert(xmapPtr);
356 		xmap = _vm->findResourceData(MKTAG('X','M','A','P'), xmapPtr);
357 		assert(xmap);
358 	}
359 }
360 
setFacing(const Actor * a)361 void AkosRenderer::setFacing(const Actor *a) {
362 	_mirror = (newDirToOldDir(a->getFacing()) != 0 || akhd->flags & 1);
363 	if (a->_flip)
364 		_mirror = !_mirror;
365 }
366 
drawLimb(const Actor * a,int limb)367 byte AkosRenderer::drawLimb(const Actor *a, int limb) {
368 	uint code;
369 	const byte *p;
370 	const AkosOffset *off;
371 	const CostumeData &cost = a->_cost;
372 	const CostumeInfo *costumeInfo;
373 	uint i, extra;
374 	byte result = 0;
375 	int xmoveCur, ymoveCur;
376 	uint32 heCondMaskIndex[32];
377 	bool useCondMask;
378 	int lastDx, lastDy;
379 
380 	lastDx = lastDy = 0;
381 	for (i = 0; i < 32; ++i) {
382 		heCondMaskIndex[i] = i;
383 	}
384 
385 	if (_skipLimbs)
386 		return 0;
387 
388 	if (_vm->_game.heversion >= 70 && cost.active[limb] == 8)
389 		return 0;
390 
391 	if (!cost.active[limb] || cost.stopped & (1 << limb))
392 		return 0;
393 
394 	useCondMask = false;
395 	p = aksq + cost.curpos[limb];
396 
397 	code = p[0];
398 	if (code & 0x80)
399 		code = READ_BE_UINT16(p);
400 
401 	if (_vm->_game.heversion >= 90)
402 		_shadow_mode = 0;
403 
404 	if (code == AKC_C021 || code == AKC_C022) {
405 		uint16 s = cost.curpos[limb] + 4;
406 		uint j = 0;
407 		extra = p[3];
408 		uint8 n = extra;
409 		assert(n <= ARRAYSIZE(heCondMaskIndex));
410 		while (n--) {
411 			heCondMaskIndex[j++] = aksq[s++];
412 		}
413 		useCondMask = true;
414 		p += extra + 2;
415 		code = (code == AKC_C021) ? AKC_ComplexChan : AKC_ComplexChan2;
416 	}
417 
418 	if (code == AKC_Return || code == AKC_EndSeq)
419 		return 0;
420 
421 	if (code != AKC_ComplexChan && code != AKC_ComplexChan2) {
422 		off = akof + (code & 0xFFF);
423 
424 		assert((code & 0xFFF) * 6 < READ_BE_UINT32((const byte *)akof - 4) - 8);
425 		assert((code & 0x7000) == 0);
426 
427 		_srcptr = akcd + READ_LE_UINT32(&off->akcd);
428 		costumeInfo = (const CostumeInfo *) (akci + READ_LE_UINT16(&off->akci));
429 
430 		_width = READ_LE_UINT16(&costumeInfo->width);
431 		_height = READ_LE_UINT16(&costumeInfo->height);
432 		xmoveCur = _xmove + (int16)READ_LE_UINT16(&costumeInfo->rel_x);
433 		ymoveCur = _ymove + (int16)READ_LE_UINT16(&costumeInfo->rel_y);
434 		_xmove += (int16)READ_LE_UINT16(&costumeInfo->move_x);
435 		_ymove -= (int16)READ_LE_UINT16(&costumeInfo->move_y);
436 
437 		switch (_codec) {
438 		case 1:
439 			result |= codec1(xmoveCur, ymoveCur);
440 			break;
441 		case 5:
442 			result |= codec5(xmoveCur, ymoveCur);
443 			break;
444 		case 16:
445 			result |= codec16(xmoveCur, ymoveCur);
446 			break;
447 		default:
448 			error("akos_drawLimb: invalid _codec %d", _codec);
449 		}
450 	} else {
451 		if (code == AKC_ComplexChan2)  {
452 			lastDx = (int16)READ_LE_UINT16(p + 2);
453 			lastDy = (int16)READ_LE_UINT16(p + 4);
454 			p += 4;
455 		}
456 
457 		extra = p[2];
458 		p += 3;
459 		uint32 decflag = heCondMaskIndex[0];
460 
461 		for (i = 0; i != extra; i++) {
462 			code = p[4];
463 			if (code & 0x80)
464 				code = READ_BE_UINT16(p + 4);
465 			off = akof + (code & 0xFFF);
466 
467 			_srcptr = akcd + READ_LE_UINT32(&off->akcd);
468 			costumeInfo = (const CostumeInfo *) (akci + READ_LE_UINT16(&off->akci));
469 
470 			_width = READ_LE_UINT16(&costumeInfo->width);
471 			_height = READ_LE_UINT16(&costumeInfo->height);
472 
473 			xmoveCur = _xmove + (int16)READ_LE_UINT16(p + 0);
474 			ymoveCur = _ymove + (int16)READ_LE_UINT16(p + 2);
475 
476 			if (i == extra - 1) {
477 				_xmove += lastDx;
478 				_ymove -= lastDy;
479 			}
480 
481 			uint16 shadowMask = 0;
482 
483 			if (!useCondMask || !akct) {
484 				decflag = 1;
485 			} else {
486 				uint32 cond = READ_LE_UINT32(akct + cost.heCondMaskTable[limb] + heCondMaskIndex[i] * 4);
487 				if (cond == 0) {
488 					decflag = 1;
489 				} else {
490 					uint32 type = cond & ~0x3FFFFFFF;
491 					cond &= 0x3FFFFFFF;
492 					if (_vm->_game.heversion >= 90) {
493 						shadowMask = cond & 0xE000;
494 						cond &= ~0xE000;
495 					}
496 					if (_vm->_game.heversion >= 90 && cond == 0) {
497 						decflag = 1;
498 					} else if (type == 0x40000000) { // restored_bit
499 						decflag = (a->_heCondMask & cond) == cond ? 1 : 0;
500 					} else if (type == 0x80000000) { // dirty_bit
501 						decflag = (a->_heCondMask & cond) ? 0 : 1;
502 					} else {
503 						decflag = (a->_heCondMask & cond) ? 1 : 0;
504 					}
505 				}
506 			}
507 
508 			p += (p[4] & 0x80) ? 6 : 5;
509 
510 			if (decflag == 0)
511 				continue;
512 
513 			if (_vm->_game.heversion >= 90) {
514 				if (_vm->_game.heversion >= 99)
515 					_shadow_mode = 0;
516 				if (xmap && (shadowMask & 0x8000))
517 					_shadow_mode = 3;
518 			}
519 
520 			switch (_codec) {
521 			case 1:
522 				result |= codec1(xmoveCur, ymoveCur);
523 				break;
524 			case 5:
525 				result |= codec5(xmoveCur, ymoveCur);
526 				break;
527 			case 16:
528 				result |= codec16(xmoveCur, ymoveCur);
529 				break;
530 			case 32:
531 				result |= codec32(xmoveCur, ymoveCur);
532 				break;
533 			default:
534 				error("akos_drawLimb: invalid _codec %d", _codec);
535 			}
536 		}
537 	}
538 
539 	return result;
540 }
541 
codec1_genericDecode(Codec1 & v1)542 void AkosRenderer::codec1_genericDecode(Codec1 &v1) {
543 	const byte *mask, *src;
544 	byte *dst;
545 	byte len, maskbit;
546 	int lastColumnX, y;
547 	uint16 color, height, pcolor;
548 	const byte *scaleytab;
549 	bool masked;
550 
551 	lastColumnX = -1;
552 	y = v1.y;
553 	src = _srcptr;
554 	dst = v1.destptr;
555 	len = v1.replen;
556 	color = v1.repcolor;
557 	height = _height;
558 
559 	scaleytab = &v1.scaletable[v1.scaleYindex];
560 	maskbit = revBitMask(v1.x & 7);
561 	mask = _vm->getMaskBuffer(v1.x - (_vm->_virtscr[kMainVirtScreen].xstart & 7), v1.y, _zbuf);
562 
563 	if (len)
564 		goto StartPos;
565 
566 	do {
567 		len = *src++;
568 		color = len >> v1.shr;
569 		len &= v1.mask;
570 		if (!len)
571 			len = *src++;
572 
573 		do {
574 			if (_scaleY == 255 || *scaleytab++ < _scaleY) {
575 				if (_actorHitMode) {
576 					if (color && y == _actorHitY && v1.x == _actorHitX) {
577 						_actorHitResult = true;
578 						return;
579 					}
580 				} else {
581 					masked = (y < v1.boundsRect.top || y >= v1.boundsRect.bottom) || (v1.x < 0 || v1.x >= v1.boundsRect.right) || (*mask & maskbit);
582 					bool skipColumn = false;
583 
584 					if (color && !masked) {
585 						pcolor = _palette[color];
586 						if (_shadow_mode == 1) {
587 							if (pcolor == 13) {
588 								// In shadow mode 1 skipColumn works more or less the same way as in shadow
589 								// mode 3. It is only ever checked and applied if pcolor is 13.
590 								skipColumn = (lastColumnX == v1.x);
591 								pcolor = _shadow_table[*dst];
592 							}
593 						} else if (_shadow_mode == 2) {
594 							error("codec1_spec2"); // TODO
595 						} else if (_shadow_mode == 3) {
596 							if (_vm->_game.features & GF_16BIT_COLOR) {
597 								// I add the column skip here, too, although I don't know whether it always
598 								// applies. But this is the only way to prevent recursive shading of pixels.
599 								// This might need more fine tuning...
600 								skipColumn = (lastColumnX == v1.x);
601 								uint16 srcColor = (pcolor >> 1) & 0x7DEF;
602 								uint16 dstColor = (READ_UINT16(dst) >> 1) & 0x7DEF;
603 								pcolor = srcColor + dstColor;
604 							} else if (_vm->_game.heversion >= 90) {
605 								// I add the column skip here, too, although I don't know whether it always
606 								// applies. But this is the only way to prevent recursive shading of pixels.
607 								// This might need more fine tuning...
608 								skipColumn = (lastColumnX == v1.x);
609 								pcolor = (pcolor << 8) + *dst;
610 								pcolor = xmap[pcolor];
611 							} else if (pcolor < 8 ) {
612 								// This mode is used in COMI. The column skip only takes place when the shading
613 								// is actually applied (for pcolor < 8). The skip avoids shading of pixels that
614 								// already have been shaded.
615 								skipColumn = (lastColumnX == v1.x);
616 								pcolor = (pcolor << 8) + *dst;
617 								pcolor = _shadow_table[pcolor];
618 							}
619 						}
620 						if (!skipColumn) {
621 							if (_vm->_bytesPerPixel == 2) {
622 								WRITE_UINT16(dst, pcolor);
623 							} else {
624 								*dst = pcolor;
625 							}
626 						}
627 					}
628 				}
629 				dst += _out.pitch;
630 				mask += _numStrips;
631 				y++;
632 			}
633 			if (!--height) {
634 				if (!--v1.skip_width)
635 					return;
636 				height = _height;
637 				y = v1.y;
638 
639 				scaleytab = &v1.scaletable[v1.scaleYindex];
640 				lastColumnX = v1.x;
641 
642 				if (_scaleX == 255 || v1.scaletable[v1.scaleXindex] < _scaleX) {
643 					v1.x += v1.scaleXstep;
644 					if (v1.x < 0 || v1.x >= v1.boundsRect.right)
645 						return;
646 					maskbit = revBitMask(v1.x & 7);
647 					v1.destptr += v1.scaleXstep * _vm->_bytesPerPixel;
648 				}
649 
650 				v1.scaleXindex += v1.scaleXstep;
651 				dst = v1.destptr;
652 				mask = _vm->getMaskBuffer(v1.x - (_vm->_virtscr[kMainVirtScreen].xstart & 7), v1.y, _zbuf);
653 			}
654 		StartPos:;
655 		} while (--len);
656 	} while (1);
657 }
658 
659 // This is exact duplicate of smallCostumeScaleTable[] in costume.cpp
660 // See FIXME below for explanation
661 const byte smallCostumeScaleTableAKOS[256] = {
662 	0xFF, 0xFD, 0x7D, 0xBD, 0x3D, 0xDD, 0x5D, 0x9D,
663 	0x1D, 0xED, 0x6D, 0xAD, 0x2D, 0xCD, 0x4D, 0x8D,
664 	0x0D, 0xF5, 0x75, 0xB5, 0x35, 0xD5, 0x55, 0x95,
665 	0x15, 0xE5, 0x65, 0xA5, 0x25, 0xC5, 0x45, 0x85,
666 	0x05, 0xF9, 0x79, 0xB9, 0x39, 0xD9, 0x59, 0x99,
667 	0x19, 0xE9, 0x69, 0xA9, 0x29, 0xC9, 0x49, 0x89,
668 	0x09, 0xF1, 0x71, 0xB1, 0x31, 0xD1, 0x51, 0x91,
669 	0x11, 0xE1, 0x61, 0xA1, 0x21, 0xC1, 0x41, 0x81,
670 	0x01, 0xFB, 0x7B, 0xBB, 0x3B, 0xDB, 0x5B, 0x9B,
671 	0x1B, 0xEB, 0x6B, 0xAB, 0x2B, 0xCB, 0x4B, 0x8B,
672 	0x0B, 0xF3, 0x73, 0xB3, 0x33, 0xD3, 0x53, 0x93,
673 	0x13, 0xE3, 0x63, 0xA3, 0x23, 0xC3, 0x43, 0x83,
674 	0x03, 0xF7, 0x77, 0xB7, 0x37, 0xD7, 0x57, 0x97,
675 	0x17, 0xE7, 0x67, 0xA7, 0x27, 0xC7, 0x47, 0x87,
676 	0x07, 0xEF, 0x6F, 0xAF, 0x2F, 0xCF, 0x4F, 0x8F,
677 	0x0F, 0xDF, 0x5F, 0x9F, 0x1F, 0xBF, 0x3F, 0x7F,
678 	0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
679 	0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
680 	0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
681 	0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
682 	0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
683 	0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
684 	0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
685 	0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
686 	0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
687 	0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
688 	0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
689 	0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
690 	0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
691 	0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
692 	0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
693 	0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE
694 };
695 const byte bigCostumeScaleTable[768] = {
696 	0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
697 	0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
698 	0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
699 	0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
700 	0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
701 	0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
702 	0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
703 	0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
704 	0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
705 	0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
706 	0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
707 	0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
708 	0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
709 	0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
710 	0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
711 	0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
712 	0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
713 	0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
714 	0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
715 	0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
716 	0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
717 	0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
718 	0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
719 	0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
720 	0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
721 	0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
722 	0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
723 	0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
724 	0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
725 	0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
726 	0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
727 	0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFE,
728 
729 	0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
730 	0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
731 	0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
732 	0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
733 	0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
734 	0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
735 	0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
736 	0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
737 	0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
738 	0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
739 	0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
740 	0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
741 	0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
742 	0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
743 	0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
744 	0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
745 	0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
746 	0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
747 	0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
748 	0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
749 	0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
750 	0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
751 	0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
752 	0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
753 	0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
754 	0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
755 	0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
756 	0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
757 	0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
758 	0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
759 	0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
760 	0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFE,
761 
762 	0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
763 	0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
764 	0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
765 	0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
766 	0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
767 	0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
768 	0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
769 	0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
770 	0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
771 	0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
772 	0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
773 	0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
774 	0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
775 	0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
776 	0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
777 	0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
778 	0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
779 	0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
780 	0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
781 	0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
782 	0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
783 	0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
784 	0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
785 	0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
786 	0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
787 	0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
788 	0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
789 	0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
790 	0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
791 	0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
792 	0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
793 	0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
794 };
795 
codec1(int xmoveCur,int ymoveCur)796 byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) {
797 	int num_colors;
798 	bool use_scaling;
799 	int i, j;
800 	int skip = 0, startScaleIndexX, startScaleIndexY;
801 	Common::Rect rect;
802 	int step;
803 	byte drawFlag = 1;
804 	Codec1 v1;
805 
806 	const int scaletableSize = (_vm->_game.heversion >= 61) ? 128 : 384;
807 
808 	/* implement custom scale table */
809 
810 	// FIXME. HACK
811 	// For some illogical reason gcc 3.4.x produces wrong code if
812 	// smallCostumeScaleTable from costume.cpp is used here
813 	// So I had to put copy of it back here as it was before 1.227 revision
814 	// of this file.
815 	v1.scaletable = (_vm->_game.heversion >= 61) ? smallCostumeScaleTableAKOS : bigCostumeScaleTable;
816 	if (_vm->VAR_CUSTOMSCALETABLE != 0xFF && _vm->_res->isResourceLoaded(rtString, _vm->VAR(_vm->VAR_CUSTOMSCALETABLE))) {
817 		v1.scaletable = _vm->getStringAddressVar(_vm->VAR_CUSTOMSCALETABLE);
818 	}
819 
820 	// Setup color decoding variables
821 	num_colors = _vm->getResourceDataSize(akpl);
822 	if (num_colors == 32) {
823 		v1.mask = 7;
824 		v1.shr = 3;
825 	} else if (num_colors == 64) {
826 		v1.mask = 3;
827 		v1.shr = 2;
828 	} else {
829 		v1.mask = 15;
830 		v1.shr = 4;
831 	}
832 
833 	use_scaling = (_scaleX != 0xFF) || (_scaleY != 0xFF);
834 
835 	v1.x = _actorX;
836 	v1.y = _actorY;
837 
838 	v1.boundsRect.left = 0;
839 	v1.boundsRect.top = 0;
840 	v1.boundsRect.right = _out.w;
841 	v1.boundsRect.bottom = _out.h;
842 
843 	if (use_scaling) {
844 
845 		/* Scale direction */
846 		v1.scaleXstep = -1;
847 		if (xmoveCur < 0) {
848 			xmoveCur = -xmoveCur;
849 			v1.scaleXstep = 1;
850 		}
851 
852 		if (_mirror) {
853 			/* Adjust X position */
854 			startScaleIndexX = j = scaletableSize - xmoveCur;
855 			for (i = 0; i < xmoveCur; i++) {
856 				if (v1.scaletable[j++] < _scaleX)
857 					v1.x -= v1.scaleXstep;
858 			}
859 
860 			rect.left = rect.right = v1.x;
861 
862 			j = startScaleIndexX;
863 			for (i = 0, skip = 0; i < _width; i++) {
864 				if (rect.right < 0) {
865 					skip++;
866 					startScaleIndexX = j;
867 				}
868 				if (v1.scaletable[j++] < _scaleX)
869 					rect.right++;
870 			}
871 		} else {
872 			/* No mirror */
873 			/* Adjust X position */
874 			startScaleIndexX = j = scaletableSize + xmoveCur;
875 			for (i = 0; i < xmoveCur; i++) {
876 				if (v1.scaletable[j--] < _scaleX)
877 					v1.x += v1.scaleXstep;
878 			}
879 
880 			rect.left = rect.right = v1.x;
881 
882 			j = startScaleIndexX;
883 			for (i = 0; i < _width; i++) {
884 				if (rect.left >= v1.boundsRect.right) {
885 					startScaleIndexX = j;
886 					skip++;
887 				}
888 				if (v1.scaletable[j--] < _scaleX)
889 					rect.left--;
890 			}
891 		}
892 
893 		if (skip)
894 			skip--;
895 
896 		step = -1;
897 		if (ymoveCur < 0) {
898 			ymoveCur = -ymoveCur;
899 			step = -step;
900 		}
901 
902 		startScaleIndexY = scaletableSize - ymoveCur;
903 		for (i = 0; i < ymoveCur; i++) {
904 			if (v1.scaletable[startScaleIndexY++] < _scaleY)
905 				v1.y -= step;
906 		}
907 
908 		rect.top = rect.bottom = v1.y;
909 		startScaleIndexY = scaletableSize - ymoveCur;
910 		for (i = 0; i < _height; i++) {
911 			if (v1.scaletable[startScaleIndexY++] < _scaleY)
912 				rect.bottom++;
913 		}
914 
915 		startScaleIndexY = scaletableSize - ymoveCur;
916 	} else {
917 		if (!_mirror)
918 			xmoveCur = -xmoveCur;
919 
920 		v1.x += xmoveCur;
921 		v1.y += ymoveCur;
922 
923 		if (_mirror) {
924 			rect.left = v1.x;
925 			rect.right = v1.x + _width;
926 		} else {
927 			rect.left = v1.x - _width;
928 			rect.right = v1.x;
929 		}
930 
931 		rect.top = v1.y;
932 		rect.bottom = rect.top + _height;
933 
934 		startScaleIndexX = scaletableSize;
935 		startScaleIndexY = scaletableSize;
936 	}
937 
938 	v1.scaleXindex = startScaleIndexX;
939 	v1.scaleYindex = startScaleIndexY;
940 	v1.skip_width = _width;
941 	v1.scaleXstep = _mirror ? 1 : -1;
942 
943 	if (_vm->_game.heversion >= 71 && !use_scaling) {
944 		if (_clipOverride.right > _clipOverride.left && _clipOverride.bottom > _clipOverride.top) {
945 			v1.boundsRect = _clipOverride;
946 		}
947 	}
948 
949 	if (_actorHitMode) {
950 		if (_actorHitX < rect.left || _actorHitX >= rect.right || _actorHitY < rect.top || _actorHitY >= rect.bottom)
951 			return 0;
952 	} else
953 		markRectAsDirty(rect);
954 
955 	if (rect.top >= v1.boundsRect.bottom || rect.bottom <= v1.boundsRect.top)
956 		return 0;
957 
958 	if (rect.left >= v1.boundsRect.right || rect.right <= v1.boundsRect.left)
959 		return 0;
960 
961 	v1.replen = 0;
962 
963 	if (_mirror) {
964 		if (!use_scaling)
965 			skip = v1.boundsRect.left - v1.x;
966 
967 		if (skip > 0) {
968 			v1.skip_width -= skip;
969 			codec1_ignorePakCols(v1, skip);
970 			v1.x = v1.boundsRect.left;
971 		} else {
972 			skip = rect.right - v1.boundsRect.right;
973 			if (skip <= 0) {
974 				drawFlag = 2;
975 			} else {
976 				v1.skip_width -= skip;
977 			}
978 		}
979 	} else {
980 		if (!use_scaling)
981 			skip = rect.right - v1.boundsRect.right + 1;
982 		if (skip > 0) {
983 			v1.skip_width -= skip;
984 			codec1_ignorePakCols(v1, skip)	;
985 			v1.x = v1.boundsRect.right - 1;
986 		} else {
987 			skip = (v1.boundsRect.left -1) - rect.left;
988 
989 			if (skip <= 0)
990 				drawFlag = 2;
991 			else
992 				v1.skip_width -= skip;
993 		}
994 	}
995 
996 	if (v1.skip_width <= 0 || _height <= 0)
997 		return 0;
998 
999 	if (rect.left < v1.boundsRect.left)
1000 		rect.left = v1.boundsRect.left;
1001 
1002 	if (rect.top < v1.boundsRect.top)
1003 		rect.top = v1.boundsRect.top;
1004 
1005 	if (rect.top > v1.boundsRect.bottom)
1006 		rect.top = v1.boundsRect.bottom;
1007 
1008 	if (rect.bottom > v1.boundsRect.bottom)
1009 		rect.bottom = v1.boundsRect.bottom;
1010 
1011 	if (_draw_top > rect.top)
1012 		_draw_top = rect.top;
1013 	if (_draw_bottom < rect.bottom)
1014 		_draw_bottom = rect.bottom;
1015 
1016 	v1.width = _out.w;
1017 	v1.height = _out.h;
1018 	v1.destptr = (byte *)_out.getBasePtr(v1.x, v1.y);
1019 
1020 	codec1_genericDecode(v1);
1021 
1022 	return drawFlag;
1023 }
1024 
markRectAsDirty(Common::Rect rect)1025 void AkosRenderer::markRectAsDirty(Common::Rect rect) {
1026 	rect.left -= _vm->_virtscr[kMainVirtScreen].xstart & 7;
1027 	rect.right -= _vm->_virtscr[kMainVirtScreen].xstart & 7;
1028 	_vm->markRectAsDirty(kMainVirtScreen, rect, _actorID);
1029 }
1030 
codec5(int xmoveCur,int ymoveCur)1031 byte AkosRenderer::codec5(int xmoveCur, int ymoveCur) {
1032 	Common::Rect clip;
1033 	int32 maxw, maxh;
1034 
1035 	if (_actorHitMode) {
1036 		error("codec5: _actorHitMode not yet implemented");
1037 		return 0;
1038 	}
1039 
1040 	if (!_mirror) {
1041 		clip.left = (_actorX - xmoveCur - _width) + 1;
1042 	} else {
1043 		clip.left = _actorX + xmoveCur - 1;
1044 	}
1045 
1046 	clip.top = _actorY + ymoveCur;
1047 	clip.right = clip.left + _width;
1048 	clip.bottom = clip.top + _height;
1049 	maxw = _out.w;
1050 	maxh = _out.h;
1051 
1052 	markRectAsDirty(clip);
1053 
1054 	clip.clip(maxw, maxh);
1055 
1056 	if ((clip.left >= clip.right) || (clip.top >= clip.bottom))
1057 		return 0;
1058 
1059 	if (_draw_top > clip.top)
1060 		_draw_top = clip.top;
1061 	if (_draw_bottom < clip.bottom)
1062 		_draw_bottom = clip.bottom;
1063 
1064 	BompDrawData bdd;
1065 
1066 	bdd.dst = _out;
1067 	if (!_mirror) {
1068 		bdd.x = (_actorX - xmoveCur - _width) + 1;
1069 	} else {
1070 		bdd.x = _actorX + xmoveCur;
1071 	}
1072 	bdd.y = _actorY + ymoveCur;
1073 
1074 	bdd.src = _srcptr;
1075 	bdd.srcwidth = _width;
1076 	bdd.srcheight = _height;
1077 
1078 	bdd.scale_x = 255;
1079 	bdd.scale_y = 255;
1080 
1081 	bdd.maskPtr = _vm->getMaskBuffer(0, 0, _zbuf);
1082 	bdd.numStrips = _numStrips;
1083 
1084 	bdd.shadowMode = _shadow_mode;
1085 	bdd.shadowPalette = _vm->_shadowPalette;
1086 
1087 	bdd.actorPalette = _useBompPalette ? _palette : 0;
1088 
1089 	bdd.mirror = !_mirror;
1090 
1091 	drawBomp(bdd);
1092 
1093 	_useBompPalette = false;
1094 
1095 	return 0;
1096 }
1097 
akos16SetupBitReader(const byte * src)1098 void AkosRenderer::akos16SetupBitReader(const byte *src) {
1099 	_akos16.repeatMode = false;
1100 	_akos16.numbits = 16;
1101 	_akos16.mask = (1 << *src) - 1;
1102 	_akos16.shift = *(src);
1103 	_akos16.color = *(src + 1);
1104 	_akos16.bits = (*(src + 2) | *(src + 3) << 8);
1105 	_akos16.dataptr = src + 4;
1106 }
1107 
1108 #define AKOS16_FILL_BITS()                                        \
1109 		if (_akos16.numbits <= 8) {                                \
1110 		  _akos16.bits |= (*_akos16.dataptr++) << _akos16.numbits;   \
1111 		  _akos16.numbits += 8;                                    \
1112 		}
1113 
1114 #define AKOS16_EAT_BITS(n)                                        \
1115 		_akos16.numbits -= (n);                                    \
1116 		_akos16.bits >>= (n);
1117 
1118 
akos16SkipData(int32 numbytes)1119 void AkosRenderer::akos16SkipData(int32 numbytes) {
1120 	akos16DecodeLine(0, numbytes, 0);
1121 }
1122 
akos16DecodeLine(byte * buf,int32 numbytes,int32 dir)1123 void AkosRenderer::akos16DecodeLine(byte *buf, int32 numbytes, int32 dir) {
1124 	uint16 bits, tmp_bits;
1125 
1126 	while (numbytes != 0) {
1127 		if (buf) {
1128 			*buf = _akos16.color;
1129 			buf += dir;
1130 		}
1131 
1132 		if (!_akos16.repeatMode) {
1133 			AKOS16_FILL_BITS()
1134 			bits = _akos16.bits & 3;
1135 			if (bits & 1) {
1136 				AKOS16_EAT_BITS(2)
1137 				if (bits & 2) {
1138 					tmp_bits = _akos16.bits & 7;
1139 					AKOS16_EAT_BITS(3)
1140 					if (tmp_bits != 4) {
1141 						// A color change
1142 						_akos16.color += (tmp_bits - 4);
1143 					} else {
1144 						// Color does not change, but rather identical pixels get repeated
1145 						_akos16.repeatMode = true;
1146 						AKOS16_FILL_BITS()
1147 						_akos16.repeatCount = (_akos16.bits & 0xff) - 1;
1148 						AKOS16_EAT_BITS(8)
1149 						AKOS16_FILL_BITS()
1150 					}
1151 				} else {
1152 					AKOS16_FILL_BITS()
1153 					_akos16.color = ((byte)_akos16.bits) & _akos16.mask;
1154 					AKOS16_EAT_BITS(_akos16.shift)
1155 					AKOS16_FILL_BITS()
1156 				}
1157 			} else {
1158 				AKOS16_EAT_BITS(1);
1159 			}
1160 		} else {
1161 			if (--_akos16.repeatCount == 0) {
1162 				_akos16.repeatMode = false;
1163 			}
1164 		}
1165 		numbytes--;
1166 	}
1167 }
1168 
akos16Decompress(byte * dest,int32 pitch,const byte * src,int32 t_width,int32 t_height,int32 dir,int32 numskip_before,int32 numskip_after,byte transparency,int maskLeft,int maskTop,int zBuf)1169 void AkosRenderer::akos16Decompress(byte *dest, int32 pitch, const byte *src, int32 t_width, int32 t_height, int32 dir,
1170 		int32 numskip_before, int32 numskip_after, byte transparency, int maskLeft, int maskTop, int zBuf) {
1171 	byte *tmp_buf = _akos16.buffer;
1172 	int maskpitch;
1173 	byte *maskptr;
1174 	const byte maskbit = revBitMask(maskLeft & 7);
1175 
1176 	if (dir < 0) {
1177 		dest -= (t_width - 1);
1178 		tmp_buf += (t_width - 1);
1179 	}
1180 
1181 	akos16SetupBitReader(src);
1182 
1183 	if (numskip_before != 0) {
1184 		akos16SkipData(numskip_before);
1185 	}
1186 
1187 	maskpitch = _numStrips;
1188 
1189 	maskptr = _vm->getMaskBuffer(maskLeft, maskTop, zBuf);
1190 
1191 	assert(t_height > 0);
1192 	assert(t_width > 0);
1193 	while (t_height--) {
1194 		akos16DecodeLine(tmp_buf, t_width, dir);
1195 		bompApplyMask(_akos16.buffer, maskptr, maskbit, t_width, transparency);
1196 		bool HE7Check = (_vm->_game.heversion == 70);
1197 		bompApplyShadow(_shadow_mode, _shadow_table, _akos16.buffer, dest, t_width, transparency, HE7Check);
1198 
1199 		if (numskip_after != 0)	{
1200 			akos16SkipData(numskip_after);
1201 		}
1202 		dest += pitch;
1203 		maskptr += maskpitch;
1204 	}
1205 }
1206 
codec16(int xmoveCur,int ymoveCur)1207 byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) {
1208 	assert(_vm->_bytesPerPixel == 1);
1209 
1210 	Common::Rect clip;
1211 	int32 minx, miny, maxw, maxh;
1212 	int32 skip_x, skip_y, cur_x, cur_y;
1213 	byte transparency = (_vm->_game.heversion >= 61) ? _palette[0] : 255;
1214 
1215 	if (_actorHitMode) {
1216 		error("codec16: _actorHitMode not yet implemented");
1217 		return 0;
1218 	}
1219 
1220 	if (!_mirror) {
1221 		clip.left = (_actorX - xmoveCur - _width) + 1;
1222 	} else {
1223 		clip.left = _actorX + xmoveCur;
1224 	}
1225 
1226 	clip.top = _actorY + ymoveCur;
1227 	clip.right = clip.left + _width;
1228 	clip.bottom = clip.top + _height;
1229 
1230 	minx = miny = 0;
1231 	maxw = _out.w;
1232 	maxh = _out.h;
1233 
1234 	if (_vm->_game.heversion >= 71) {
1235 		if (_clipOverride.right > _clipOverride.left && _clipOverride.bottom > _clipOverride.top) {
1236 			minx = _clipOverride.left;
1237 			miny = _clipOverride.top;
1238 			maxw = _clipOverride.right;
1239 			maxh = _clipOverride.bottom;
1240 		}
1241 	}
1242 
1243 	markRectAsDirty(clip);
1244 
1245 	skip_x = 0;
1246 	skip_y = 0;
1247 	cur_x = _width - 1;
1248 	cur_y = _height - 1;
1249 
1250 	if (clip.left < minx) {
1251 		skip_x = -clip.left;
1252 		clip.left = 0;
1253 	}
1254 
1255 	if (clip.right > maxw) {
1256 		cur_x -= clip.right - maxw;
1257 		clip.right = maxw;
1258 	}
1259 
1260 	if (clip.top < miny) {
1261 		skip_y -= clip.top;
1262 		clip.top = 0;
1263 	}
1264 
1265 	if (clip.bottom > maxh) {
1266 		cur_y -= clip.bottom - maxh;
1267 		clip.bottom = maxh;
1268 	}
1269 
1270 	if ((clip.left >= clip.right) || (clip.top >= clip.bottom))
1271 		return 0;
1272 
1273 	if (_draw_top > clip.top)
1274 		_draw_top = clip.top;
1275 	if (_draw_bottom < clip.bottom)
1276 		_draw_bottom = clip.bottom;
1277 
1278 	int32 width_unk, height_unk;
1279 
1280 	height_unk = clip.top;
1281 	int32 dir;
1282 
1283 	if (!_mirror) {
1284 		dir = -1;
1285 
1286 		int tmp_skip_x = skip_x;
1287 		skip_x = _width - 1 - cur_x;
1288 		cur_x = _width - 1 - tmp_skip_x;
1289 		width_unk = clip.right - 1;
1290 	} else {
1291 		dir = 1;
1292 		width_unk = clip.left;
1293 	}
1294 
1295 	int32 out_height;
1296 
1297 	out_height = cur_y - skip_y;
1298 	if (out_height < 0) {
1299 		out_height = -out_height;
1300 	}
1301 	out_height++;
1302 
1303 	cur_x -= skip_x;
1304 	if (cur_x < 0) {
1305 		cur_x = -cur_x;
1306 	}
1307 	cur_x++;
1308 
1309 	int32 numskip_before = skip_x + (skip_y * _width);
1310 	int32 numskip_after = _width - cur_x;
1311 
1312 	byte *dst = (byte *)_out.getBasePtr(width_unk, height_unk);
1313 
1314 	akos16Decompress(dst, _out.pitch, _srcptr, cur_x, out_height, dir, numskip_before, numskip_after, transparency, clip.left, clip.top, _zbuf);
1315 	return 0;
1316 }
1317 
codec32(int xmoveCur,int ymoveCur)1318 byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) {
1319 #ifdef ENABLE_HE
1320 	Common::Rect src, dst;
1321 
1322 	if (!_mirror) {
1323 		dst.left = (_actorX - xmoveCur - _width) + 1;
1324 	} else {
1325 		dst.left = _actorX + xmoveCur;
1326 	}
1327 
1328 	src.top = src.left = 0;
1329 	src.right = _width;
1330 	src.bottom = _height;
1331 
1332 	dst.top = _actorY + ymoveCur;
1333 	dst.right = dst.left + _width;
1334 	dst.bottom = dst.top + _height;
1335 
1336 	int diff;
1337 	diff = dst.left - _clipOverride.left;
1338 	if (diff < 0) {
1339 		src.left -= diff;
1340 		dst.left -= diff;
1341 	}
1342 	diff = dst.right - _clipOverride.right;
1343 	if (diff > 0) {
1344 		src.right -= diff;
1345 		dst.right -= diff;
1346 	}
1347 	diff = dst.top - _clipOverride.top;
1348 	if (diff < 0) {
1349 		src.top -= diff;
1350 		dst.top -= diff;
1351 	}
1352 	diff = dst.bottom - _clipOverride.bottom;
1353 	if (diff > 0) {
1354 		src.bottom -= diff;
1355 		dst.bottom -= diff;
1356 	}
1357 
1358 	if (dst.isValidRect() == false)
1359 		return 0;
1360 
1361 	markRectAsDirty(dst);
1362 
1363 	if (_draw_top > dst.top)
1364 		_draw_top = dst.top;
1365 	if (_draw_bottom < dst.bottom)
1366 		_draw_bottom = dst.bottom;
1367 
1368 	const uint8 *palPtr = NULL;
1369 	if (_vm->_game.features & GF_16BIT_COLOR) {
1370 		palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768;
1371 		if (_paletteNum) {
1372 			palPtr = _vm->_hePalettes + _paletteNum * _vm->_hePaletteSlot + 768;
1373 		} else if (rgbs) {
1374 			for (uint i = 0; i < 256; i++)
1375 				WRITE_LE_UINT16(_palette + i, _vm->get16BitColor(rgbs[i * 3 + 0], rgbs[i * 3 + 1], rgbs[i * 3 + 2]));
1376 			palPtr = (uint8 *)_palette;
1377 		}
1378 	} else if (_vm->_game.heversion >= 99) {
1379 		palPtr = _vm->_hePalettes + _vm->_hePaletteSlot + 768;
1380 	}
1381 
1382 	byte *dstPtr = (byte *)_out.getBasePtr(dst.left, dst.top);
1383 	if (_shadow_mode == 3) {
1384 		Wiz::decompressWizImage<kWizXMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, xmap, _vm->_bytesPerPixel);
1385 	} else {
1386 		if (palPtr != NULL) {
1387 			Wiz::decompressWizImage<kWizRMap>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, palPtr, NULL, _vm->_bytesPerPixel);
1388 		} else {
1389 			Wiz::decompressWizImage<kWizCopy>(dstPtr, _out.pitch, kDstScreen, _srcptr, src, 0, NULL, NULL, _vm->_bytesPerPixel);
1390 		}
1391 	}
1392 #endif
1393 	return 0;
1394 }
1395 
increaseAnims(Actor * a)1396 byte AkosCostumeLoader::increaseAnims(Actor *a) {
1397 	return ((ScummEngine_v6 *)_vm)->akos_increaseAnims(_akos, a);
1398 }
1399 
akos_increaseAnims(const byte * akos,Actor * a)1400 bool ScummEngine_v6::akos_increaseAnims(const byte *akos, Actor *a) {
1401 	const byte *aksq, *akfo;
1402 	int i;
1403 	uint size;
1404 	bool result;
1405 
1406 	aksq = findResourceData(MKTAG('A','K','S','Q'), akos);
1407 	akfo = findResourceData(MKTAG('A','K','F','O'), akos);
1408 
1409 	size = getResourceDataSize(akfo) / 2;
1410 
1411 	result = false;
1412 	for (i = 0; i < 16; i++) {
1413 		if (a->_cost.active[i] != 0)
1414 			result |= akos_increaseAnim(a, i, aksq, (const uint16 *)akfo, size);
1415 	}
1416 	return result;
1417 }
1418 
1419 #define GW(o) ((int16)READ_LE_UINT16(aksq+curpos+(o)))
1420 #define GUW(o) READ_LE_UINT16(aksq+curpos+(o))
1421 #define GB(o) aksq[curpos+(o)]
1422 
akos_increaseAnim(Actor * a,int chan,const byte * aksq,const uint16 * akfo,int numakfo)1423 bool ScummEngine_v6::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const uint16 *akfo, int numakfo) {
1424 	byte active;
1425 	uint old_curpos, curpos, end;
1426 	uint code;
1427 	bool flag_value, needRedraw;
1428 	int tmp, tmp2;
1429 
1430 	active = a->_cost.active[chan];
1431 	end = a->_cost.end[chan];
1432 	old_curpos = curpos = a->_cost.curpos[chan];
1433 	flag_value = false;
1434 	needRedraw = false;
1435 
1436 	do {
1437 
1438 		code = aksq[curpos];
1439 		if (code & 0x80)
1440 			code = READ_BE_UINT16(aksq + curpos);
1441 
1442 		switch (active) {
1443 		case 6:
1444 		case 8:
1445 			switch (code) {
1446 			case AKC_JumpIfSet:
1447 			case AKC_AddVar:
1448 			case AKC_SetVar:
1449 			case AKC_SkipGE:
1450 			case AKC_SkipG:
1451 			case AKC_SkipLE:
1452 			case AKC_SkipL:
1453 
1454 			case AKC_SkipNE:
1455 			case AKC_SkipE:
1456 			case AKC_C016:
1457 			case AKC_C017:
1458 			case AKC_C018:
1459 			case AKC_C019:
1460 				curpos += 5;
1461 				break;
1462 			case AKC_JumpTable:
1463 			case AKC_SetActorClip:
1464 			case AKC_Ignore3:
1465 			case AKC_Ignore2:
1466 			case AKC_Ignore:
1467 			case AKC_StartAnim:
1468 			case AKC_StartVarAnim:
1469 			case AKC_CmdQue3:
1470 			case AKC_C042:
1471 			case AKC_C044:
1472 			case AKC_C0A3:
1473 				curpos += 3;
1474 				break;
1475 			case AKC_SoundStuff:
1476 				if (_game.heversion >= 61)
1477 					curpos += 6;
1478 				else
1479 					curpos += 8;
1480 				break;
1481 			case AKC_Cmd3:
1482 			case AKC_SetVarInActor:
1483 			case AKC_SetDrawOffs:
1484 				curpos += 6;
1485 				break;
1486 			case AKC_ClearFlag:
1487 			case AKC_HideActor:
1488 			case AKC_IncVar:
1489 			case AKC_CmdQue3Quick:
1490 			case AKC_Return:
1491 			case AKC_EndSeq:
1492 				curpos += 2;
1493 				break;
1494 			case AKC_JumpGE:
1495 			case AKC_JumpG:
1496 			case AKC_JumpLE:
1497 			case AKC_JumpL:
1498 			case AKC_JumpNE:
1499 			case AKC_JumpE:
1500 			case AKC_Random:
1501 				curpos += 7;
1502 				break;
1503 			case AKC_Flip:
1504 			case AKC_Jump:
1505 			case AKC_StartAnimInActor:
1506 			case AKC_C0A0:
1507 			case AKC_C0A1:
1508 			case AKC_C0A2:
1509 				curpos += 4;
1510 				break;
1511 			case AKC_ComplexChan2:
1512 				curpos += 4;
1513 				// Fall through
1514 			case AKC_ComplexChan:
1515 				curpos += 3;
1516 				tmp = aksq[curpos - 1];
1517 				while (--tmp >= 0) {
1518 					curpos += 4;
1519 					curpos += (aksq[curpos] & 0x80) ? 2 : 1;
1520 				}
1521 				break;
1522 			case AKC_C021:
1523 			case AKC_C022:
1524 			case AKC_C045:
1525 			case AKC_C046:
1526 			case AKC_C047:
1527 			case AKC_C048:
1528 				needRedraw = 1;
1529 				curpos += aksq[curpos + 2];
1530 				break;
1531 			case AKC_C08E:
1532 				akos_queCommand(7, a, GW(2), 0);
1533 				curpos += 4;
1534 				break;
1535 			default:
1536 				curpos += (code & 0x8000) ? 2 : 1;
1537 				break;
1538 			}
1539 			break;
1540 		case 2:
1541 			curpos += (code & 0x8000) ? 2 : 1;
1542 			if (curpos > end)
1543 				curpos = a->_cost.start[chan];
1544 			break;
1545 		case 3:
1546 			if (curpos != end)
1547 				curpos += (code & 0x8000) ? 2 : 1;
1548 			break;
1549 		default:
1550 			break;
1551 		}
1552 
1553 		code = aksq[curpos];
1554 		if (code & 0x80)
1555 			code = READ_BE_UINT16(aksq + curpos);
1556 
1557 		if (flag_value && code != AKC_ClearFlag)
1558 			continue;
1559 
1560 		switch (code) {
1561 		case AKC_StartAnimInActor:
1562 			akos_queCommand(4, derefActor(a->getAnimVar(GB(2)), "akos_increaseAnim:29"), a->getAnimVar(GB(3)), 0);
1563 			continue;
1564 
1565 		case AKC_Random:
1566 			a->setAnimVar(GB(6), _rnd.getRandomNumberRng(GW(2), GW(4)));
1567 			continue;
1568 		case AKC_JumpGE:
1569 		case AKC_JumpG:
1570 		case AKC_JumpLE:
1571 		case AKC_JumpL:
1572 		case AKC_JumpNE:
1573 		case AKC_JumpE:
1574 			if (akos_compare(a->getAnimVar(GB(4)), GW(5), code - AKC_JumpStart) != 0) {
1575 				curpos = GUW(2);
1576 				break;
1577 			}
1578 			continue;
1579 		case AKC_IncVar:
1580 			a->setAnimVar(0, a->getAnimVar(0) + 1);
1581 			continue;
1582 		case AKC_SetVar:
1583 			a->setAnimVar(GB(4), GW(2));
1584 			continue;
1585 		case AKC_AddVar:
1586 			a->setAnimVar(GB(4), a->getAnimVar(GB(4)) + GW(2));
1587 			continue;
1588 		case AKC_Flip:
1589 			a->_flip = GW(2) != 0;
1590 			continue;
1591 		case AKC_CmdQue3:
1592 			if (_game.heversion >= 61)
1593 				tmp = GB(2);
1594 			else
1595 				tmp = GB(2) - 1;
1596 			if ((uint) tmp < 24)
1597 				akos_queCommand(3, a, a->_sound[tmp], 0);
1598 			continue;
1599 		case AKC_CmdQue3Quick:
1600 			akos_queCommand(3, a, a->_sound[0], 0);
1601 			continue;
1602 		case AKC_StartAnim:
1603 			akos_queCommand(4, a, GB(2), 0);
1604 			continue;
1605 		case AKC_StartVarAnim:
1606 			akos_queCommand(4, a, a->getAnimVar(GB(2)), 0);
1607 			continue;
1608 		case AKC_SetVarInActor:
1609 			derefActor(a->getAnimVar(GB(2)), "akos_increaseAnim:9")->setAnimVar(GB(3), GW(4));
1610 			continue;
1611 		case AKC_HideActor:
1612 			akos_queCommand(1, a, 0, 0);
1613 			continue;
1614 		case AKC_SetActorClip:
1615 			akos_queCommand(5, a, GB(2), 0);
1616 			continue;
1617 		case AKC_SoundStuff:
1618 			if (_game.heversion >= 61)
1619 				continue;
1620 			tmp = GB(2) - 1;
1621 			if (tmp >= 8)
1622 				continue;
1623 			tmp2 = GB(4);
1624 			if (tmp2 < 1 || tmp2 > 3)
1625 				error("akos_increaseAnim:8 invalid code %d", tmp2);
1626 			akos_queCommand(tmp2 + 6, a, a->_sound[tmp], GB(6));
1627 			continue;
1628 		case AKC_SetDrawOffs:
1629 			akos_queCommand(6, a, GW(2), GW(4));
1630 			continue;
1631 		case AKC_JumpTable:
1632 			if (akfo == NULL)
1633 				error("akos_increaseAnim: no AKFO table");
1634 			tmp = a->getAnimVar(GB(2)) - 1;
1635 			if (_game.heversion >= 80) {
1636 				if (tmp < 0 || tmp > a->_cost.heJumpCountTable[chan] - 1)
1637 					error("akos_increaseAnim: invalid jump value %d", tmp);
1638 				curpos = READ_LE_UINT16(akfo + a->_cost.heJumpOffsetTable[chan] + tmp * 2);
1639 			} else {
1640 				if (tmp < 0 || tmp > numakfo - 1)
1641 					error("akos_increaseAnim: invalid jump value %d", tmp);
1642 				curpos = READ_LE_UINT16(&akfo[tmp]);
1643 			}
1644 			break;
1645 		case AKC_JumpIfSet:
1646 			if (!a->getAnimVar(GB(4)))
1647 				continue;
1648 			a->setAnimVar(GB(4), 0);
1649 			curpos = GUW(2);
1650 			break;
1651 
1652 		case AKC_ClearFlag:
1653 			flag_value = false;
1654 			continue;
1655 
1656 		case AKC_Jump:
1657 			curpos = GUW(2);
1658 
1659 			// WORKAROUND bug #3813: In the German version of SPY Fox 3: Operation Ozone
1660 			// the wig maker room 21 contains a costume animation 352 of an LED ticker
1661 			// with a jump to an erroneous position 846.
1662 			// To prevent an undefined 'uSweat token' the animation is reset to its start.
1663 			if (_game.id == GID_HEGAME && _language == Common::DE_DEU && \
1664 			    _currentRoom == 21 && a->_costume == 352 && curpos == 846) {
1665 				curpos = a->_cost.start[chan];
1666 			}
1667 			break;
1668 
1669 		case AKC_Return:
1670 		case AKC_EndSeq:
1671 		case AKC_ComplexChan:
1672 		case AKC_C08E:
1673 		case AKC_ComplexChan2:
1674 			break;
1675 
1676 		case AKC_C021:
1677 		case AKC_C022:
1678 			needRedraw = 1;
1679 			break;
1680 
1681 		case AKC_Cmd3:
1682 		case AKC_Ignore:
1683 		case AKC_Ignore3:
1684 			continue;
1685 
1686 		case AKC_Ignore2:
1687 			if (_game.heversion >= 71)
1688 				akos_queCommand(3, a, a->_sound[a->getAnimVar(GB(2))], 0);
1689 			continue;
1690 
1691 		case AKC_SkipE:
1692 		case AKC_SkipNE:
1693 		case AKC_SkipL:
1694 		case AKC_SkipLE:
1695 		case AKC_SkipG:
1696 		case AKC_SkipGE:
1697 			if (akos_compare(a->getAnimVar(GB(4)), GW(2), code - AKC_SkipStart) == 0)
1698 				flag_value = true;
1699 			continue;
1700 		case AKC_C016:
1701 			if (_sound->isSoundRunning( a->_sound[a->getAnimVar(GB(4))]))  {
1702 				curpos = GUW(2);
1703 				break;
1704 			}
1705 			continue;
1706 		case AKC_C017:
1707 			if (!_sound->isSoundRunning(a->_sound[a->getAnimVar(GB(4))])) {
1708 				curpos = GUW(2);
1709 				break;
1710 			}
1711 			continue;
1712 		case AKC_C018:
1713 			if (_sound->isSoundRunning(a->_sound[GB(4)])) {
1714 				curpos = GUW(2);
1715 				break;
1716 			}
1717 			continue;
1718 		case AKC_C019:
1719 			if (!_sound->isSoundRunning(a->_sound[GB(4)])) {
1720 				curpos = GUW(2);
1721 				break;
1722 			}
1723 			continue;
1724 		case AKC_C042:
1725 			akos_queCommand(9, a, a->_sound[GB(2)], 0);
1726 			continue;
1727 		case AKC_C044:
1728 			akos_queCommand(9, a, a->_sound[a->getAnimVar(GB(2))], 0);
1729 			continue;
1730 		case AKC_C045:
1731 			((ActorHE *)a)->setUserCondition(GB(3), a->getAnimVar(GB(4)));
1732 			continue;
1733 		case AKC_C046:
1734 			a->setAnimVar(GB(4), ((ActorHE *)a)->isUserConditionSet(GB(3)));
1735 			continue;
1736 		case AKC_C047:
1737 			((ActorHE *)a)->setTalkCondition(GB(3));
1738 			continue;
1739 		case AKC_C048:
1740 			a->setAnimVar(GB(4), ((ActorHE *)a)->isTalkConditionSet(GB(3)));
1741 			continue;
1742 		case AKC_C0A0:
1743 			akos_queCommand(8, a, GB(2), 0);
1744 			continue;
1745 		case AKC_C0A1:
1746 			if (((ActorHE *)a)->_heTalking != 0) {
1747 				curpos = GUW(2);
1748 				break;
1749 			}
1750 			continue;
1751 		case AKC_C0A2:
1752 			if (((ActorHE *)a)->_heTalking == 0) {
1753 				curpos = GUW(2);
1754 				break;
1755 			}
1756 			continue;
1757 		case AKC_C0A3:
1758 			akos_queCommand(8, a, a->getAnimVar(GB(2)), 0);
1759 			continue;
1760 		case AKC_C0A4:
1761 			if (VAR(VAR_TALK_ACTOR) != 0) {
1762 				curpos = GUW(2);
1763 				break;
1764 			}
1765 			continue;
1766 		case AKC_C0A5:
1767 			if (VAR(VAR_TALK_ACTOR) == 0) {
1768 				curpos = GUW(2);
1769 				break;
1770 			}
1771 			continue;
1772 		default:
1773 			if ((code & 0xC000) == 0xC000)
1774 				error("Undefined uSweat token %X", code);
1775 		}
1776 		break;
1777 	} while (1);
1778 
1779 	int code2 = aksq[curpos];
1780 	if (code2 & 0x80)
1781 		code2 = READ_BE_UINT16(aksq + curpos);
1782 
1783 	if ((code2 & 0xC000) == 0xC000 && code2 != AKC_ComplexChan && code2 != AKC_Return && code2 != AKC_EndSeq && code2 != AKC_C08E && code2 != AKC_ComplexChan2 && code2 != AKC_C021 && code2 != AKC_C022)
1784 		error("Ending with undefined uSweat token %X", code2);
1785 
1786 	a->_cost.curpos[chan] = curpos;
1787 
1788 	if (needRedraw)
1789 		return 1;
1790 	else
1791 		return curpos != old_curpos;
1792 }
1793 
akos_queCommand(byte cmd,Actor * a,int param_1,int param_2)1794 void ScummEngine_v6::akos_queCommand(byte cmd, Actor *a, int param_1, int param_2) {
1795 	_akosQueuePos++;
1796 	assertRange(0, _akosQueuePos, 31, "akos_queCommand: _akosQueuePos");
1797 
1798 	_akosQueue[_akosQueuePos].cmd = cmd;
1799 	_akosQueue[_akosQueuePos].actor = a->_number;
1800 	_akosQueue[_akosQueuePos].param1 = param_1;
1801 	_akosQueue[_akosQueuePos].param2 = param_2;
1802 }
1803 
akos_processQueue()1804 void ScummEngine_v6::akos_processQueue() {
1805 	byte cmd;
1806 	int actor, param_1, param_2;
1807 
1808 	while (_akosQueuePos) {
1809 		cmd = _akosQueue[_akosQueuePos].cmd;
1810 		actor = _akosQueue[_akosQueuePos].actor;
1811 		param_1 = _akosQueue[_akosQueuePos].param1;
1812 		param_2 = _akosQueue[_akosQueuePos].param2;
1813 		_akosQueuePos--;
1814 
1815 		Actor *a = derefActor(actor, "akos_processQueue");
1816 
1817 		switch (cmd) {
1818 		case 1:
1819 			a->putActor(0, 0, 0);
1820 			break;
1821 		case 3:
1822 			_sound->addSoundToQueue(param_1, 0, -1, 0);
1823 			break;
1824 		case 4:
1825 			a->startAnimActor(param_1);
1826 			break;
1827 		case 5:
1828 			a->_forceClip = param_1;
1829 			break;
1830 		case 6:
1831 			a->_heOffsX = param_1;
1832 			a->_heOffsY = param_2;
1833 			break;
1834 		case 7:
1835 #ifdef ENABLE_HE
1836 			assert(_game.heversion >= 71);
1837 			((ScummEngine_v71he *)this)->queueAuxEntry(a->_number, param_1);
1838 #endif
1839 			break;
1840 		case 8:
1841 			_actorToPrintStrFor = a->_number;
1842 
1843 			a->_talkPosX = ((ActorHE *)a)->_heTalkQueue[param_1].posX;
1844 			a->_talkPosY = ((ActorHE *)a)->_heTalkQueue[param_1].posY;
1845 			a->_talkColor = ((ActorHE *)a)->_heTalkQueue[param_1].color;
1846 
1847 			_string[0].loadDefault();
1848 			_string[0].color = a->_talkColor;
1849 			actorTalk(((ActorHE *)a)->_heTalkQueue[param_1].sentence);
1850 
1851 			break;
1852 		case 9:
1853 			_sound->addSoundToQueue(param_1, 0, -1, 4);
1854 			break;
1855 		default:
1856 			error("akos_queCommand(%d,%d,%d,%d)", cmd, a->_number, param_1, param_2);
1857 		}
1858 	}
1859 }
1860 
1861 #ifdef ENABLE_SCUMM_7_8
akos_processQueue()1862 void ScummEngine_v7::akos_processQueue() {
1863 	byte cmd;
1864 	int actor, param_1, param_2;
1865 
1866 	while (_akosQueuePos) {
1867 		cmd = _akosQueue[_akosQueuePos].cmd;
1868 		actor = _akosQueue[_akosQueuePos].actor;
1869 		param_1 = _akosQueue[_akosQueuePos].param1;
1870 		param_2 = _akosQueue[_akosQueuePos].param2;
1871 		_akosQueuePos--;
1872 
1873 		Actor *a = derefActor(actor, "akos_processQueue");
1874 
1875 		switch (cmd) {
1876 		case 1:
1877 			a->putActor(0, 0, 0);
1878 			break;
1879 		case 3:
1880 			if (param_1 != 0) {
1881 				if (_imuseDigital) {
1882 					_imuseDigital->startSfx(param_1, 63);
1883 				}
1884 			}
1885 			break;
1886 		case 4:
1887 			a->startAnimActor(param_1);
1888 			break;
1889 		case 5:
1890 			a->_forceClip = param_1;
1891 			break;
1892 		case 6:
1893 			a->_heOffsX = param_1;
1894 			a->_heOffsY = param_2;
1895 			break;
1896 		case 7:
1897 			if (param_1 != 0) {
1898 				if (_imuseDigital) {
1899 					_imuseDigital->setVolume(param_1, param_2);
1900 				}
1901 			}
1902 			break;
1903 		case 8:
1904 			if (param_1 != 0) {
1905 				if (_imuseDigital) {
1906 					_imuseDigital->setPan(param_1, param_2);
1907 				}
1908 			}
1909 			break;
1910 		case 9:
1911 			if (param_1 != 0) {
1912 				if (_imuseDigital) {
1913 					_imuseDigital->setPriority(param_1, param_2);
1914 				}
1915 			}
1916 			break;
1917 		default:
1918 			error("akos_queCommand(%d,%d,%d,%d)", cmd, a->_number, param_1, param_2);
1919 		}
1920 	}
1921 }
1922 #endif
1923 
1924 } // End of namespace Scumm
1925