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