aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/akos.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/scumm/akos.cpp')
-rw-r--r--engines/scumm/akos.cpp1869
1 files changed, 1869 insertions, 0 deletions
diff --git a/engines/scumm/akos.cpp b/engines/scumm/akos.cpp
new file mode 100644
index 0000000000..d8f484f1d3
--- /dev/null
+++ b/engines/scumm/akos.cpp
@@ -0,0 +1,1869 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2001 Ludvig Strigeus
+ * Copyright (C) 2001-2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/stdafx.h"
+#include "scumm/scumm.h"
+#include "scumm/actor.h"
+#include "scumm/akos.h"
+#include "scumm/bomp.h"
+#include "scumm/imuse.h"
+#include "scumm/imuse_digi/dimuse.h"
+#include "scumm/intern.h"
+#include "scumm/intern_he.h"
+#include "scumm/sound.h"
+#include "scumm/util.h"
+#include "scumm/wiz_he.h"
+
+namespace Scumm {
+
+#if !defined(__GNUC__)
+#pragma START_PACK_STRUCTS
+#endif
+
+struct AkosHeader {
+ byte unk_1[2];
+ byte flags;
+ byte unk_2;
+ uint16 num_anims;
+ uint16 unk_3;
+ uint16 codec;
+} GCC_PACK;
+
+struct AkosOffset {
+ uint32 akcd;
+ uint16 akci;
+} GCC_PACK;
+
+#if !defined(__GNUC__)
+#pragma END_PACK_STRUCTS
+#endif
+
+
+enum AkosOpcodes {
+ AKC_Return = 0xC001,
+ AKC_SetVar = 0xC010,
+ AKC_CmdQue3 = 0xC015,
+ AKC_C016 = 0xC016,
+ AKC_C017 = 0xC017,
+ AKC_C018 = 0xC018,
+ AKC_C019 = 0xC019,
+ AKC_ComplexChan = 0xC020,
+ AKC_C021 = 0xC021,
+ AKC_C022 = 0xC022,
+ AKC_ComplexChan2 = 0xC025,
+ AKC_Jump = 0xC030,
+ AKC_JumpIfSet = 0xC031,
+ AKC_AddVar = 0xC040,
+ AKC_C042 = 0xC042,
+ AKC_C044 = 0xC044,
+ AKC_C045 = 0xC045,
+ AKC_C046 = 0xC046,
+ AKC_C047 = 0xC047,
+ AKC_C048 = 0xC048,
+ AKC_Ignore = 0xC050,
+ AKC_IncVar = 0xC060,
+ AKC_CmdQue3Quick = 0xC061,
+ AKC_JumpStart = 0xC070,
+ AKC_JumpE = 0xC070,
+ AKC_JumpNE = 0xC071,
+ AKC_JumpL = 0xC072,
+ AKC_JumpLE = 0xC073,
+ AKC_JumpG = 0xC074,
+ AKC_JumpGE = 0xC075,
+ AKC_StartAnim = 0xC080,
+ AKC_StartVarAnim = 0xC081,
+ AKC_Random = 0xC082,
+ AKC_SetActorClip = 0xC083,
+ AKC_StartAnimInActor = 0xC084,
+ AKC_SetVarInActor = 0xC085,
+ AKC_HideActor = 0xC086,
+ AKC_SetDrawOffs = 0xC087,
+ AKC_JumpTable = 0xC088,
+ AKC_SoundStuff = 0xC089,
+ AKC_Flip = 0xC08A,
+ AKC_Cmd3 = 0xC08B,
+ AKC_Ignore3 = 0xC08C,
+ AKC_Ignore2 = 0xC08D,
+ AKC_C08E = 0xC08E,
+ AKC_SkipStart = 0xC090,
+ AKC_SkipE = 0xC090,
+ AKC_SkipNE = 0xC091,
+ AKC_SkipL = 0xC092,
+ AKC_SkipLE = 0xC093,
+ AKC_SkipG = 0xC094,
+ AKC_SkipGE = 0xC095,
+ AKC_ClearFlag = 0xC09F,
+ AKC_C0A0 = 0xC0A0,
+ AKC_C0A1 = 0xC0A1,
+ AKC_C0A2 = 0xC0A2,
+ AKC_C0A3 = 0xC0A3,
+ AKC_C0A4 = 0xC0A4,
+ AKC_C0A5 = 0xC0A5,
+ AKC_C0A6 = 0xC0A6,
+ AKC_C0A7 = 0xC0A7,
+ AKC_EndSeq = 0xC0FF
+};
+
+static bool akos_compare(int a, int b, byte cmd) {
+ switch (cmd) {
+ case 0:
+ return a == b;
+ case 1:
+ return a != b;
+ case 2:
+ return a < b;
+ case 3:
+ return a <= b;
+ case 4:
+ return a > b;
+ default:
+ return a >= b;
+ }
+}
+
+void AkosCostumeLoader::loadCostume(int id) {
+ _akos = _vm->getResourceAddress(rtCostume, id);
+ assert(_akos);
+}
+
+bool AkosCostumeLoader::hasManyDirections() {
+ const AkosHeader *akhd;
+
+ akhd = (const AkosHeader *)_vm->findResourceData(MKID('AKHD'), _akos);
+ return (akhd->flags & 2) != 0;
+}
+
+void AkosCostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) {
+ uint anim;
+ const byte *r;
+ const AkosHeader *akhd;
+ uint offs;
+ int i;
+ byte code;
+ uint16 start, len;
+ uint16 mask;
+
+ if (a->_costume == 0)
+ return;
+
+ loadCostume(a->_costume);
+
+ if (_vm->_version >= 7 && hasManyDirections())
+ anim = toSimpleDir(1, a->getFacing()) + frame * 8;
+ else
+ anim = newDirToOldDir(a->getFacing()) + frame * 4;
+
+ akhd = (const AkosHeader *)_vm->findResourceData(MKID('AKHD'), _akos);
+
+ if (anim >= READ_LE_UINT16(&akhd->num_anims))
+ return;
+
+ r = _vm->findResourceData(MKID('AKCH'), _akos);
+ assert(r);
+
+ offs = READ_LE_UINT16(r + anim * sizeof(uint16));
+ if (offs == 0)
+ return;
+ r += offs;
+
+ const uint8 *akstPtr = _vm->findResourceData(MKID('AKST'), _akos);
+ const uint8 *aksfPtr = _vm->findResourceData(MKID('AKSF'), _akos);
+
+ i = 0;
+ mask = READ_LE_UINT16(r); r += 2;
+ do {
+ if (mask & 0x8000) {
+ const uint8 *akst = akstPtr;
+ const uint8 *aksf = aksfPtr;
+
+ code = *r++;
+ if (usemask & 0x8000) {
+ switch (code) {
+ case 1:
+ a->_cost.active[i] = 0;
+ a->_cost.frame[i] = frame;
+ a->_cost.end[i] = 0;
+ a->_cost.start[i] = 0;
+ a->_cost.curpos[i] = 0;
+ a->_cost.heCondMaskTable[i] = 0;
+
+ if (akst) {
+ int size = _vm->getResourceDataSize(akst) / 8;
+ if (size > 0) {
+ bool found = false;
+ while (size--) {
+ if (READ_LE_UINT32(akst) == 0) {
+ a->_cost.heCondMaskTable[i] = READ_LE_UINT32(akst + 4);
+ found = true;
+ break;
+ }
+ akst += 8;
+ }
+ if (!found) {
+ error("Sequence not found in actor 0x%X costume %d", a, a->_costume);
+ }
+ }
+ }
+ break;
+ case 4:
+ a->_cost.stopped |= 1 << i;
+ break;
+ case 5:
+ a->_cost.stopped &= ~(1 << i);
+ break;
+ default:
+ start = READ_LE_UINT16(r); r += 2;
+ len = READ_LE_UINT16(r); r += 2;
+
+ a->_cost.heJumpOffsetTable[i] = 0;
+ a->_cost.heJumpCountTable[i] = 0;
+ if (aksf) {
+ int size = _vm->getResourceDataSize(aksf) / 6;
+ if (size > 0) {
+ bool found = false;
+ while (size--) {
+ if (READ_LE_UINT16(aksf) == start) {
+ a->_cost.heJumpOffsetTable[i] = READ_LE_UINT16(aksf + 2);
+ a->_cost.heJumpCountTable[i] = READ_LE_UINT16(aksf + 4);
+ found = true;
+ break;
+ }
+ aksf += 6;
+ }
+ if (!found) {
+ error("Sequence not found in actor 0x%X costume %d", a, a->_costume);
+ }
+ }
+ }
+
+ a->_cost.active[i] = code;
+ a->_cost.frame[i] = frame;
+ a->_cost.end[i] = start + len;
+ a->_cost.start[i] = start;
+ a->_cost.curpos[i] = start;
+ a->_cost.heCondMaskTable[i] = 0;
+ if (akst) {
+ int size = _vm->getResourceDataSize(akst) / 8;
+ if (size > 0) {
+ bool found = false;
+ while (size--) {
+ if (READ_LE_UINT32(akst) == start) {
+ a->_cost.heCondMaskTable[i] = READ_LE_UINT32(akst + 4);
+ found = true;
+ break;
+ }
+ akst += 8;
+ }
+ if (!found) {
+ error("Sequence not found in actor 0x%X costume %d", a, a->_costume);
+ }
+ }
+ }
+ break;
+ }
+ } else {
+ if (code != 1 && code != 4 && code != 5)
+ r += sizeof(uint16) * 2;
+ }
+ }
+ i++;
+ mask <<= 1;
+ usemask <<= 1;
+ } while ((uint16)mask);
+}
+
+void AkosRenderer::setPalette(byte *new_palette) {
+ uint size, i;
+
+ size = _vm->getResourceDataSize(akpl);
+ if (size == 0)
+ return;
+
+ if (size > 256)
+ error("akos_setPalette: %d is too many colors", size);
+
+ if (_vm->_heversion >= 99 && _paletteNum) {
+ for (i = 0; i < size; i++)
+ palette[i] = (byte)_vm->_hePalettes[_paletteNum * 1024 + 768 + akpl[i]];
+ } else {
+ for (i = 0; i < size; i++) {
+ palette[i] = new_palette[i] != 0xFF ? new_palette[i] : akpl[i];
+ }
+ }
+
+ if (_vm->_heversion == 70) {
+ for (i = 0; i < size; i++)
+ palette[i] = _vm->_HEV7ActorPalette[palette[i]];
+ }
+
+ if (size == 256) {
+ byte color = new_palette[0];
+ if (color == 255) {
+ palette[0] = color;
+ } else {
+ _vm->_bompActorPalettePtr = palette;
+ }
+ }
+}
+
+void AkosRenderer::setCostume(int costume, int shadow) {
+ akos = _vm->getResourceAddress(rtCostume, costume);
+ assert(akos);
+
+ akhd = (const AkosHeader *) _vm->findResourceData(MKID('AKHD'), akos);
+ akof = (const AkosOffset *) _vm->findResourceData(MKID('AKOF'), akos);
+ akci = _vm->findResourceData(MKID('AKCI'), akos);
+ aksq = _vm->findResourceData(MKID('AKSQ'), akos);
+ akcd = _vm->findResourceData(MKID('AKCD'), akos);
+ akpl = _vm->findResourceData(MKID('AKPL'), akos);
+ codec = READ_LE_UINT16(&akhd->codec);
+ akct = _vm->findResourceData(MKID('AKCT'), akos);
+
+ xmap = 0;
+ if (shadow) {
+ const uint8 *xmapPtr = _vm->getResourceAddress(rtImage, shadow);
+ assert(xmapPtr);
+ xmap = _vm->findResourceData(MKID('XMAP'), xmapPtr);
+ assert(xmap);
+ }
+}
+
+void AkosRenderer::setFacing(const Actor *a) {
+ _mirror = (newDirToOldDir(a->getFacing()) != 0 || akhd->flags & 1);
+ if (a->_flip)
+ _mirror = !_mirror;
+}
+
+byte AkosRenderer::drawLimb(const Actor *a, int limb) {
+ uint code;
+ const byte *p;
+ const AkosOffset *off;
+ const CostumeData &cost = a->_cost;
+ const CostumeInfo *costumeInfo;
+ uint i, extra;
+ byte result = 0;
+ int xmoveCur, ymoveCur;
+ uint32 heCondMaskIndex[32];
+ bool useCondMask;
+ int lastDx, lastDy;
+
+ lastDx = lastDy = 0;
+ for (i = 0; i < 32; ++i) {
+ heCondMaskIndex[i] = i;
+ }
+
+ if (_skipLimbs)
+ return 0;
+
+ if (_vm->_heversion >= 70 && cost.active[limb] == 8)
+ return 0;
+
+ if (!cost.active[limb] || cost.stopped & (1 << limb))
+ return 0;
+
+ useCondMask = false;
+ p = aksq + cost.curpos[limb];
+
+ code = p[0];
+ if (code & 0x80)
+ code = (code << 8) | p[1];
+
+ if (code == AKC_C021 || code == AKC_C022) {
+ uint16 s = cost.curpos[limb] + 4;
+ uint j = 0;
+ extra = p[3];
+ uint8 n = extra;
+ assert(n < ARRAYSIZE(heCondMaskIndex));
+ while (n--) {
+ heCondMaskIndex[j++] = aksq[s++];
+ }
+ useCondMask = true;
+ p += extra + 2;
+ code = (code == AKC_C021) ? AKC_ComplexChan : AKC_ComplexChan2;
+ }
+
+ if (code == AKC_Return || code == AKC_EndSeq)
+ return 0;
+
+ if (code != AKC_ComplexChan && code != AKC_ComplexChan2) {
+ off = akof + (code & 0xFFF);
+
+ assert((code & 0xFFF) * 6 < READ_BE_UINT32((const byte *)akof - 4) - 8);
+ assert((code & 0x7000) == 0);
+
+ _srcptr = akcd + READ_LE_UINT32(&off->akcd);
+ costumeInfo = (const CostumeInfo *) (akci + READ_LE_UINT16(&off->akci));
+
+ _width = READ_LE_UINT16(&costumeInfo->width);
+ _height = READ_LE_UINT16(&costumeInfo->height);
+ xmoveCur = _xmove + (int16)READ_LE_UINT16(&costumeInfo->rel_x);
+ ymoveCur = _ymove + (int16)READ_LE_UINT16(&costumeInfo->rel_y);
+ _xmove += (int16)READ_LE_UINT16(&costumeInfo->move_x);
+ _ymove -= (int16)READ_LE_UINT16(&costumeInfo->move_y);
+
+ switch (codec) {
+ case 1:
+ result |= codec1(xmoveCur, ymoveCur);
+ break;
+ case 5:
+ result |= codec5(xmoveCur, ymoveCur);
+ break;
+ case 16:
+ result |= codec16(xmoveCur, ymoveCur);
+ break;
+ default:
+ error("akos_drawLimb: invalid codec %d", codec);
+ }
+ } else {
+ if (code == AKC_ComplexChan2) {
+ lastDx = (int16)READ_LE_UINT16(p + 2);
+ lastDy = (int16)READ_LE_UINT16(p + 4);
+ p += 4;
+ }
+
+ extra = p[2];
+ p += 3;
+ uint32 decflag = heCondMaskIndex[0];
+
+ for (i = 0; i != extra; i++) {
+ code = p[4];
+ if (code & 0x80)
+ code = ((code & 0xF) << 8) | (p[5] & 0xFFF);
+ off = akof + code;
+
+ _srcptr = akcd + READ_LE_UINT32(&off->akcd);
+ costumeInfo = (const CostumeInfo *) (akci + READ_LE_UINT16(&off->akci));
+
+ _width = READ_LE_UINT16(&costumeInfo->width);
+ _height = READ_LE_UINT16(&costumeInfo->height);
+
+ xmoveCur = _xmove + (int16)READ_LE_UINT16(p + 0);
+ ymoveCur = _ymove + (int16)READ_LE_UINT16(p + 2);
+
+ if (i == extra - 1) {
+ _xmove += lastDx;
+ _ymove -= lastDy;
+ }
+
+ uint16 shadowMask = 0;
+
+ if (!useCondMask || !akct) {
+ decflag = 1;
+ } else {
+ uint32 cond = READ_LE_UINT32(akct + cost.heCondMaskTable[limb] + heCondMaskIndex[i] * 4);
+ if (cond == 0) {
+ decflag = 1;
+ } else {
+ uint32 type = cond & ~0x3FFFFFFF;
+ cond &= 0x3FFFFFFF;
+ if (_vm->_heversion >= 90) {
+ shadowMask = cond & 0xE000;
+ cond &= ~0xE000;
+ }
+ if (_vm->_heversion >= 90 && cond == 0) {
+ decflag = 1;
+ } else if (type == 0x40000000) { // restored_bit
+ decflag = (a->_heCondMask & cond) ? 1 : 0;
+ } else if (type == 0x80000000) { // dirty_bit
+ decflag = (a->_heCondMask & cond) ? 0 : 1;
+ } else {
+ decflag = (a->_heCondMask & cond) ? 1 : 0;
+ }
+ }
+ }
+
+ p += (p[4] & 0x80) ? 6 : 5;
+
+ if (decflag == 0)
+ continue;
+
+ if (_vm->_heversion >= 90) {
+ _shadow_mode = ((shadowMask & 0x8000) && xmap) ? 3 : 0;
+ }
+
+ switch (codec) {
+ case 1:
+ result |= codec1(xmoveCur, ymoveCur);
+ break;
+ case 5:
+ result |= codec5(xmoveCur, ymoveCur);
+ break;
+ case 16:
+ result |= codec16(xmoveCur, ymoveCur);
+ break;
+ case 32:
+ result |= codec32(xmoveCur, ymoveCur);
+ break;
+ default:
+ error("akos_drawLimb: invalid codec %d", codec);
+ }
+ }
+ }
+
+ return result;
+}
+
+void AkosRenderer::codec1_genericDecode(Codec1 &v1) {
+ const byte *mask, *src;
+ byte *dst;
+ byte len, maskbit;
+ int y;
+ uint color, height, pcolor;
+ const byte *scaleytab;
+ bool masked;
+ bool skip_column = false;
+
+ y = v1.y;
+ src = _srcptr;
+ dst = v1.destptr;
+ len = v1.replen;
+ color = v1.repcolor;
+ height = _height;
+
+ scaleytab = &v1.scaletable[v1.scaleYindex];
+ maskbit = revBitMask(v1.x & 7);
+ mask = _vm->getMaskBuffer(v1.x - (_vm->virtscr[0].xstart & 7), v1.y, _zbuf);
+
+ if (len)
+ goto StartPos;
+
+ do {
+ len = *src++;
+ color = len >> v1.shr;
+ len &= v1.mask;
+ if (!len)
+ len = *src++;
+
+ do {
+ if (*scaleytab++ < _scaleY) {
+ if (_actorHitMode) {
+ if (color && y == _actorHitY && v1.x == _actorHitX) {
+ _actorHitResult = true;
+ return;
+ }
+ } else {
+ masked = (y < 0 || y >= _out.h) || (*mask & maskbit);
+
+ if (color && !masked && !skip_column) {
+ pcolor = palette[color];
+ if (_shadow_mode == 1) {
+ if (pcolor == 13)
+ pcolor = _shadow_table[*dst];
+ } else if (_shadow_mode == 2) {
+ error("codec1_spec2"); // TODO
+ } else if (_shadow_mode == 3) {
+ if (_vm->_heversion >= 90) {
+ pcolor = (pcolor << 8) + *dst;
+ pcolor = xmap[pcolor];
+ } else if (pcolor < 8) {
+ pcolor = (pcolor << 8) + *dst;
+ pcolor = _shadow_table[pcolor];
+ }
+ }
+ *dst = pcolor;
+ }
+ }
+ dst += _out.pitch;
+ mask += _numStrips;
+ y++;
+ }
+ if (!--height) {
+ if (!--v1.skip_width)
+ return;
+ height = _height;
+ y = v1.y;
+
+ scaleytab = &v1.scaletable[v1.scaleYindex];
+
+ if (_scaleX == 255 || v1.scaletable[v1.scaleXindex] < _scaleX) {
+ v1.x += v1.scaleXstep;
+ if (v1.x < 0 || v1.x >= _out.w)
+ return;
+ maskbit = revBitMask(v1.x & 7);
+ v1.destptr += v1.scaleXstep;
+ skip_column = false;
+ } else
+ skip_column = true;
+ v1.scaleXindex += v1.scaleXstep;
+ dst = v1.destptr;
+ mask = _vm->getMaskBuffer(v1.x - (_vm->virtscr[0].xstart & 7), v1.y, _zbuf);
+ }
+ StartPos:;
+ } while (--len);
+ } while (1);
+}
+
+#ifdef PALMOS_68K
+const byte *bigCostumeScaleTable;
+const byte *smallCostumeScaleTableAKOS;
+#else
+// This is exact duplicate of smallCostumeScaleTable[] in costume.cpp
+// See FIXME below for explanation
+const byte smallCostumeScaleTableAKOS[256] = {
+ 0xFF, 0xFD, 0x7D, 0xBD, 0x3D, 0xDD, 0x5D, 0x9D,
+ 0x1D, 0xED, 0x6D, 0xAD, 0x2D, 0xCD, 0x4D, 0x8D,
+ 0x0D, 0xF5, 0x75, 0xB5, 0x35, 0xD5, 0x55, 0x95,
+ 0x15, 0xE5, 0x65, 0xA5, 0x25, 0xC5, 0x45, 0x85,
+ 0x05, 0xF9, 0x79, 0xB9, 0x39, 0xD9, 0x59, 0x99,
+ 0x19, 0xE9, 0x69, 0xA9, 0x29, 0xC9, 0x49, 0x89,
+ 0x09, 0xF1, 0x71, 0xB1, 0x31, 0xD1, 0x51, 0x91,
+ 0x11, 0xE1, 0x61, 0xA1, 0x21, 0xC1, 0x41, 0x81,
+ 0x01, 0xFB, 0x7B, 0xBB, 0x3B, 0xDB, 0x5B, 0x9B,
+ 0x1B, 0xEB, 0x6B, 0xAB, 0x2B, 0xCB, 0x4B, 0x8B,
+ 0x0B, 0xF3, 0x73, 0xB3, 0x33, 0xD3, 0x53, 0x93,
+ 0x13, 0xE3, 0x63, 0xA3, 0x23, 0xC3, 0x43, 0x83,
+ 0x03, 0xF7, 0x77, 0xB7, 0x37, 0xD7, 0x57, 0x97,
+ 0x17, 0xE7, 0x67, 0xA7, 0x27, 0xC7, 0x47, 0x87,
+ 0x07, 0xEF, 0x6F, 0xAF, 0x2F, 0xCF, 0x4F, 0x8F,
+ 0x0F, 0xDF, 0x5F, 0x9F, 0x1F, 0xBF, 0x3F, 0x7F,
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE
+};
+const byte bigCostumeScaleTable[768] = {
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFE,
+
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFE,
+
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
+ 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
+ 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
+ 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
+ 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
+ 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
+ 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
+ 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
+ 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
+ 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
+ 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
+ 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
+ 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
+ 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
+ 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
+ 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
+ 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
+ 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
+ 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
+ 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
+ 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
+ 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
+};
+#endif
+
+byte AkosRenderer::codec1(int xmoveCur, int ymoveCur) {
+ int num_colors;
+ bool use_scaling;
+ int i, j;
+ int skip = 0, startScaleIndexX, startScaleIndexY;
+ Common::Rect rect;
+ int step;
+ byte drawFlag = 1;
+ Codec1 v1;
+
+ const int scaletableSize = (_vm->_heversion >= 61) ? 128 : 384;
+
+ /* implement custom scale table */
+
+ // FIXME. HACK
+ // For some illogical reason gcc 3.4.x produces wrong code if
+ // smallCostumeScaleTable from costume.cpp is used here
+ // So I had to put copy of it back here as it was before 1.227 revision
+ // of this file.
+ v1.scaletable = (_vm->_heversion >= 61) ? smallCostumeScaleTableAKOS : bigCostumeScaleTable;
+ if (_vm->VAR_CUSTOMSCALETABLE != 0xFF && _vm->res.isResourceLoaded(rtString, _vm->VAR(_vm->VAR_CUSTOMSCALETABLE))) {
+ v1.scaletable = _vm->getStringAddressVar(_vm->VAR_CUSTOMSCALETABLE);
+ }
+
+ // Setup color decoding variables
+ num_colors = _vm->getResourceDataSize(akpl);
+ if (num_colors == 32) {
+ v1.mask = 7;
+ v1.shr = 3;
+ } else if (num_colors == 64) {
+ v1.mask = 3;
+ v1.shr = 2;
+ } else {
+ v1.mask = 15;
+ v1.shr = 4;
+ }
+
+ use_scaling = (_scaleX != 0xFF) || (_scaleY != 0xFF);
+
+ v1.x = _actorX;
+ v1.y = _actorY;
+
+ if (use_scaling) {
+
+ /* Scale direction */
+ v1.scaleXstep = -1;
+ if (xmoveCur < 0) {
+ xmoveCur = -xmoveCur;
+ v1.scaleXstep = 1;
+ }
+
+ if (_mirror) {
+ /* Adjust X position */
+ startScaleIndexX = j = scaletableSize - xmoveCur;
+ for (i = 0; i < xmoveCur; i++) {
+ if (v1.scaletable[j++] < _scaleX)
+ v1.x -= v1.scaleXstep;
+ }
+
+ rect.left = rect.right = v1.x;
+
+ j = startScaleIndexX;
+ for (i = 0, skip = 0; i < _width; i++) {
+ if (rect.right < 0) {
+ skip++;
+ startScaleIndexX = j;
+ }
+ if (v1.scaletable[j++] < _scaleX)
+ rect.right++;
+ }
+ } else {
+ /* No mirror */
+ /* Adjust X position */
+ startScaleIndexX = j = scaletableSize + xmoveCur;
+ for (i = 0; i < xmoveCur; i++) {
+ if (v1.scaletable[j--] < _scaleX)
+ v1.x += v1.scaleXstep;
+ }
+
+ rect.left = rect.right = v1.x;
+
+ j = startScaleIndexX;
+ for (i = 0; i < _width; i++) {
+ if (rect.left >= _out.w) {
+ startScaleIndexX = j;
+ skip++;
+ }
+ if (v1.scaletable[j--] < _scaleX)
+ rect.left--;
+ }
+ }
+
+ if (skip)
+ skip--;
+
+ step = -1;
+ if (ymoveCur < 0) {
+ ymoveCur = -ymoveCur;
+ step = -step;
+ }
+
+ startScaleIndexY = scaletableSize - ymoveCur;
+ for (i = 0; i < ymoveCur; i++) {
+ if (v1.scaletable[startScaleIndexY++] < _scaleY)
+ v1.y -= step;
+ }
+
+ rect.top = rect.bottom = v1.y;
+ startScaleIndexY = scaletableSize - ymoveCur;
+ for (i = 0; i < _height; i++) {
+ if (v1.scaletable[startScaleIndexY++] < _scaleY)
+ rect.bottom++;
+ }
+
+ startScaleIndexY = scaletableSize - ymoveCur;
+ } else {
+ if (!_mirror)
+ xmoveCur = -xmoveCur;
+
+ v1.x += xmoveCur;
+ v1.y += ymoveCur;
+
+ if (_mirror) {
+ rect.left = v1.x;
+ rect.right = v1.x + _width;
+ } else {
+ rect.left = v1.x - _width;
+ rect.right = v1.x;
+ }
+
+ rect.top = v1.y;
+ rect.bottom = rect.top + _height;
+
+ startScaleIndexX = scaletableSize;
+ startScaleIndexY = scaletableSize;
+ }
+
+ v1.scaleXindex = startScaleIndexX;
+ v1.scaleYindex = startScaleIndexY;
+ v1.skip_width = _width;
+ v1.scaleXstep = _mirror ? 1 : -1;
+
+ if (_vm->_heversion >= 71) {
+ if (_clipOverride.right > _clipOverride.left && _clipOverride.bottom > _clipOverride.top) {
+ if (rect.left < _clipOverride.left)
+ rect.left = _clipOverride.left;
+
+ if (rect.right > _clipOverride.right)
+ rect.right = _clipOverride.right;
+
+ if (rect.top < _clipOverride.top)
+ rect.top = _clipOverride.top;
+
+ if (rect.bottom > _clipOverride.bottom)
+ rect.bottom = _clipOverride.bottom;
+ }
+
+ if (rect.isValidRect() == false)
+ return 1;
+ }
+
+ if (_actorHitMode) {
+ if (_actorHitX < rect.left || _actorHitX >= rect.right || _actorHitY < rect.top || _actorHitY >= rect.bottom)
+ return 0;
+ } else
+ markRectAsDirty(rect);
+
+ if (rect.top >= _out.h || rect.bottom <= 0)
+ return 0;
+
+ if (rect.left >= _out.w || rect.right <= 0)
+ return 0;
+
+ v1.replen = 0;
+
+ if (_mirror) {
+ if (!use_scaling)
+ skip = -v1.x;
+ if (skip > 0) {
+ v1.skip_width -= skip;
+ codec1_ignorePakCols(v1, skip);
+ v1.x = 0;
+ } else {
+ skip = rect.right - _out.w;
+ if (skip <= 0) {
+ drawFlag = 2;
+ } else {
+ v1.skip_width -= skip;
+ }
+ }
+ } else {
+ if (!use_scaling)
+ skip = rect.right - _out.w + 1;
+ if (skip > 0) {
+ v1.skip_width -= skip;
+ codec1_ignorePakCols(v1, skip) ;
+ v1.x = _out.w - 1;
+ } else {
+ skip = -1 - rect.left;
+ if (skip <= 0)
+ drawFlag = 2;
+ else
+ v1.skip_width -= skip;
+ }
+ }
+
+ if (v1.skip_width <= 0 || _height <= 0)
+ return 0;
+
+ if (rect.left < 0)
+ rect.left = 0;
+
+ if (rect.top < 0)
+ rect.top = 0;
+
+ if (rect.top > _out.h)
+ rect.top = _out.h;
+
+ if (rect.bottom > _out.h)
+ rect.bottom = _out.h;
+
+ if (_draw_top > rect.top)
+ _draw_top = rect.top;
+ if (_draw_bottom < rect.bottom)
+ _draw_bottom = rect.bottom;
+
+ v1.destptr = (byte *)_out.pixels + v1.y * _out.pitch + v1.x;
+
+ codec1_genericDecode(v1);
+
+ return drawFlag;
+}
+
+void AkosRenderer::markRectAsDirty(Common::Rect rect) {
+ rect.left -= _vm->virtscr[0].xstart & 7;
+ rect.right -= _vm->virtscr[0].xstart & 7;
+ _vm->markRectAsDirty(kMainVirtScreen, rect, _actorID);
+}
+
+byte AkosRenderer::codec5(int xmoveCur, int ymoveCur) {
+ Common::Rect clip;
+ int32 maxw, maxh;
+
+ if (_actorHitMode) {
+ error("codec5: _actorHitMode not yet implemented");
+ return 0;
+ }
+
+ if (!_mirror) {
+ clip.left = (_actorX - xmoveCur - _width) + 1;
+ } else {
+ clip.left = _actorX + xmoveCur - 1;
+ }
+
+ clip.top = _actorY + ymoveCur;
+ clip.right = clip.left + _width;
+ clip.bottom = clip.top + _height;
+ maxw = _out.w;
+ maxh = _out.h;
+
+ markRectAsDirty(clip);
+
+ clip.clip(maxw, maxh);
+
+ if ((clip.left >= clip.right) || (clip.top >= clip.bottom))
+ return 0;
+
+ if (_draw_top > clip.top)
+ _draw_top = clip.top;
+ if (_draw_bottom < clip.bottom)
+ _draw_bottom = clip.bottom;
+
+ BompDrawData bdd;
+
+ bdd.srcwidth = _width;
+ bdd.srcheight = _height;
+ bdd.dst = _out;
+ bdd.dataptr = _srcptr;
+ bdd.scale_x = 255;
+ bdd.scale_y = 255;
+ bdd.shadowMode = _shadow_mode;
+
+ if (!_mirror) {
+ bdd.x = (_actorX - xmoveCur - _width) + 1;
+ } else {
+ bdd.x = _actorX + xmoveCur;
+ }
+ bdd.y = _actorY + ymoveCur;
+
+ bdd.maskPtr = _vm->getMaskBuffer(0, 0, _zbuf);
+ _vm->drawBomp(bdd, !_mirror);
+
+ _vm->_bompActorPalettePtr = NULL;
+
+ return 0;
+}
+
+void AkosRenderer::akos16SetupBitReader(const byte *src) {
+ akos16.unk5 = 0;
+ akos16.numbits = 16;
+ akos16.mask = (1 << *src) - 1;
+ akos16.shift = *(src);
+ akos16.color = *(src + 1);
+ akos16.bits = (*(src + 2) | *(src + 3) << 8);
+ akos16.dataptr = src + 4;
+}
+
+#define AKOS16_FILL_BITS() \
+ if (akos16.numbits <= 8) { \
+ akos16.bits |= (*akos16.dataptr++) << akos16.numbits; \
+ akos16.numbits += 8; \
+ }
+
+#define AKOS16_EAT_BITS(n) \
+ akos16.numbits -= (n); \
+ akos16.bits >>= (n);
+
+
+void AkosRenderer::akos16SkipData(int32 numbytes) {
+ akos16DecodeLine(0, numbytes, 0);
+}
+
+void AkosRenderer::akos16DecodeLine(byte *buf, int32 numbytes, int32 dir) {
+ uint16 bits, tmp_bits;
+
+ while (numbytes != 0) {
+ if (buf) {
+ *buf = akos16.color;
+ buf += dir;
+ }
+
+ if (akos16.unk5 == 0) {
+ AKOS16_FILL_BITS()
+ bits = akos16.bits & 3;
+ if (bits & 1) {
+ AKOS16_EAT_BITS(2)
+ if (bits & 2) {
+ tmp_bits = akos16.bits & 7;
+ AKOS16_EAT_BITS(3)
+ if (tmp_bits != 4) {
+ akos16.color += (tmp_bits - 4);
+ } else {
+ akos16.unk5 = 1;
+ AKOS16_FILL_BITS()
+ akos16.unk6 = (akos16.bits & 0xff) - 1;
+ AKOS16_EAT_BITS(8)
+ AKOS16_FILL_BITS()
+ }
+ } else {
+ AKOS16_FILL_BITS()
+ akos16.color = ((byte)akos16.bits) & akos16.mask;
+ AKOS16_EAT_BITS(akos16.shift)
+ AKOS16_FILL_BITS()
+ }
+ } else {
+ AKOS16_EAT_BITS(1);
+ }
+ } else {
+ if (--akos16.unk6 == 0) {
+ akos16.unk5 = 0;
+ }
+ }
+ numbytes--;
+ }
+}
+
+void AkosRenderer::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) {
+ byte *tmp_buf = akos16.buffer;
+ int maskpitch;
+ byte *maskptr;
+ const byte maskbit = revBitMask(maskLeft & 7);
+
+ if (dir < 0) {
+ dest -= (t_width - 1);
+ tmp_buf += (t_width - 1);
+ }
+
+ akos16SetupBitReader(src);
+
+ if (numskip_before != 0) {
+ akos16SkipData(numskip_before);
+ }
+
+ maskpitch = _numStrips;
+
+ maskptr = _vm->getMaskBuffer(maskLeft, maskTop, zBuf);
+
+ assert(t_height > 0);
+ assert(t_width > 0);
+ while (t_height--) {
+ akos16DecodeLine(tmp_buf, t_width, dir);
+ bompApplyMask(akos16.buffer, maskptr, maskbit, t_width, transparency);
+ bool HE7Check = (_vm->_heversion == 70);
+ bompApplyShadow(_shadow_mode, _shadow_table, akos16.buffer, dest, t_width, transparency, HE7Check);
+
+ if (numskip_after != 0) {
+ akos16SkipData(numskip_after);
+ }
+ dest += pitch;
+ maskptr += maskpitch;
+ }
+}
+
+byte AkosRenderer::codec16(int xmoveCur, int ymoveCur) {
+ Common::Rect clip;
+ int32 minx, miny, maxw, maxh;
+ int32 skip_x, skip_y, cur_x, cur_y;
+ byte transparency = (_vm->_heversion >= 61) ? palette[0] : 255;
+
+ if (_actorHitMode) {
+ error("codec16: _actorHitMode not yet implemented");
+ return 0;
+ }
+
+ if (!_mirror) {
+ clip.left = (_actorX - xmoveCur - _width) + 1;
+ } else {
+ clip.left = _actorX + xmoveCur;
+ }
+
+ clip.top = _actorY + ymoveCur;
+ clip.right = clip.left + _width;
+ clip.bottom = clip.top + _height;
+
+ minx = miny = 0;
+ maxw = _out.w;
+ maxh = _out.h;
+
+ if (_vm->_heversion >= 71) {
+ if (_clipOverride.right > _clipOverride.left && _clipOverride.bottom > _clipOverride.top) {
+ minx = _clipOverride.left;
+ miny = _clipOverride.top;
+ maxw = _clipOverride.right;
+ maxh = _clipOverride.bottom;
+ }
+ }
+
+ markRectAsDirty(clip);
+
+ skip_x = 0;
+ skip_y = 0;
+ cur_x = _width - 1;
+ cur_y = _height - 1;
+
+ if (clip.left < minx) {
+ skip_x = -clip.left;
+ clip.left = 0;
+ }
+
+ if (clip.right > maxw) {
+ cur_x -= clip.right - maxw;
+ clip.right = maxw;
+ }
+
+ if (clip.top < miny) {
+ skip_y -= clip.top;
+ clip.top = 0;
+ }
+
+ if (clip.bottom > maxh) {
+ cur_y -= clip.bottom - maxh;
+ clip.bottom = maxh;
+ }
+
+ if ((clip.left >= clip.right) || (clip.top >= clip.bottom))
+ return 0;
+
+ if (_draw_top > clip.top)
+ _draw_top = clip.top;
+ if (_draw_bottom < clip.bottom)
+ _draw_bottom = clip.bottom;
+
+ int32 width_unk, height_unk;
+
+ height_unk = clip.top;
+ int32 dir;
+
+ if (!_mirror) {
+ dir = -1;
+
+ int tmp_skip_x = skip_x;
+ skip_x = _width - 1 - cur_x;
+ cur_x = _width - 1 - tmp_skip_x;
+ width_unk = clip.right - 1;
+ } else {
+ dir = 1;
+ width_unk = clip.left;
+ }
+
+ int32 out_height;
+
+ out_height = cur_y - skip_y;
+ if (out_height < 0) {
+ out_height = -out_height;
+ }
+ out_height++;
+
+ cur_x -= skip_x;
+ if (cur_x < 0) {
+ cur_x = -cur_x;
+ }
+ cur_x++;
+
+ int32 numskip_before = skip_x + (skip_y * _width);
+ int32 numskip_after = _width - cur_x;
+
+ byte *dst = (byte *)_out.pixels + width_unk + height_unk * _out.pitch;
+
+ akos16Decompress(dst, _out.pitch, _srcptr, cur_x, out_height, dir, numskip_before, numskip_after, transparency, clip.left, clip.top, _zbuf);
+ return 0;
+}
+
+byte AkosRenderer::codec32(int xmoveCur, int ymoveCur) {
+#ifndef DISABLE_HE
+ Common::Rect src, dst;
+
+ if (!_mirror) {
+ dst.left = (_actorX - xmoveCur - _width) + 1;
+ } else {
+ dst.left = _actorX + xmoveCur;
+ }
+
+ src.top = src.left = 0;
+ src.right = _width;
+ src.bottom = _height;
+
+ dst.top = _actorY + ymoveCur;
+ dst.right = dst.left + _width;
+ dst.bottom = dst.top + _height;
+
+ int diff;
+ diff = dst.left - _clipOverride.left;
+ if (diff < 0) {
+ src.left -= diff;
+ dst.left -= diff;
+ }
+ diff = dst.right - _clipOverride.right;
+ if (diff > 0) {
+ src.right -= diff;
+ dst.right -= diff;
+ }
+ diff = dst.top - _clipOverride.top;
+ if (diff < 0) {
+ src.top -= diff;
+ dst.top -= diff;
+ }
+ diff = dst.bottom - _clipOverride.bottom;
+ if (diff > 0) {
+ src.bottom -= diff;
+ dst.bottom -= diff;
+ }
+
+ if (dst.isValidRect() == false)
+ return 0;
+
+ markRectAsDirty(dst);
+
+ if (_draw_top > dst.top)
+ _draw_top = dst.top;
+ if (_draw_bottom < dst.bottom)
+ _draw_bottom = dst.bottom;
+
+ const uint8 *palPtr = NULL;
+ if (_vm->_heversion >= 99) {
+ palPtr = _vm->_hePalettes + 1792;
+ }
+
+ byte *dstPtr = (byte *)_out.pixels + dst.left + dst.top * _out.pitch;
+ if (_shadow_mode == 3) {
+ Wiz::decompressWizImage(dstPtr, _out.pitch, dst, _srcptr, src, 0, palPtr, xmap);
+ } else {
+ Wiz::decompressWizImage(dstPtr, _out.pitch, dst, _srcptr, src, 0, palPtr);
+ }
+#endif
+ return 0;
+}
+
+byte AkosCostumeLoader::increaseAnims(Actor *a) {
+ return _vm->akos_increaseAnims(_akos, a);
+}
+
+bool ScummEngine::akos_increaseAnims(const byte *akos, Actor *a) {
+ const byte *aksq, *akfo;
+ int i;
+ uint size;
+ bool result;
+
+ aksq = findResourceData(MKID('AKSQ'), akos);
+ akfo = findResourceData(MKID('AKFO'), akos);
+
+ size = getResourceDataSize(akfo) / 2;
+
+ result = false;
+ for (i = 0; i < 16; i++) {
+ if (a->_cost.active[i] != 0)
+ result |= akos_increaseAnim(a, i, aksq, (const uint16 *)akfo, size);
+ }
+ return result;
+}
+
+#define GW(o) ((int16)READ_LE_UINT16(aksq+curpos+(o)))
+#define GUW(o) READ_LE_UINT16(aksq+curpos+(o))
+#define GB(o) aksq[curpos+(o)]
+
+bool ScummEngine::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const uint16 *akfo, int numakfo) {
+ byte active;
+ uint old_curpos, curpos, end;
+ uint code;
+ bool flag_value, needRedraw;
+ int tmp, tmp2;
+
+ active = a->_cost.active[chan];
+ end = a->_cost.end[chan];
+ old_curpos = curpos = a->_cost.curpos[chan];
+ flag_value = false;
+ needRedraw = false;
+
+ do {
+
+ code = aksq[curpos];
+ if (code & 0x80)
+ code = (code << 8) | aksq[curpos + 1];
+
+ switch (active) {
+ case 6:
+ case 8:
+ switch (code) {
+ case AKC_JumpIfSet:
+ case AKC_AddVar:
+ case AKC_SetVar:
+ case AKC_SkipGE:
+ case AKC_SkipG:
+ case AKC_SkipLE:
+ case AKC_SkipL:
+
+ case AKC_SkipNE:
+ case AKC_SkipE:
+ case AKC_C016:
+ case AKC_C017:
+ case AKC_C018:
+ case AKC_C019:
+ curpos += 5;
+ break;
+ case AKC_JumpTable:
+ case AKC_SetActorClip:
+ case AKC_Ignore3:
+ case AKC_Ignore2:
+ case AKC_Ignore:
+ case AKC_StartAnim:
+ case AKC_StartVarAnim:
+ case AKC_CmdQue3:
+ case AKC_C042:
+ case AKC_C044:
+ case AKC_C0A3:
+ curpos += 3;
+ break;
+ case AKC_SoundStuff:
+ if (_heversion >= 61)
+ curpos += 6;
+ else
+ curpos += 8;
+ break;
+ case AKC_Cmd3:
+ case AKC_SetVarInActor:
+ case AKC_SetDrawOffs:
+ curpos += 6;
+ break;
+ case AKC_ClearFlag:
+ case AKC_HideActor:
+ case AKC_IncVar:
+ case AKC_CmdQue3Quick:
+ case AKC_Return:
+ case AKC_EndSeq:
+ curpos += 2;
+ break;
+ case AKC_JumpGE:
+ case AKC_JumpG:
+ case AKC_JumpLE:
+ case AKC_JumpL:
+ case AKC_JumpNE:
+ case AKC_JumpE:
+ case AKC_Random:
+ curpos += 7;
+ break;
+ case AKC_Flip:
+ case AKC_Jump:
+ case AKC_StartAnimInActor:
+ case AKC_C0A0:
+ case AKC_C0A1:
+ case AKC_C0A2:
+ curpos += 4;
+ break;
+ case AKC_ComplexChan2:
+ curpos += 4;
+ // Fall through
+ case AKC_ComplexChan:
+ curpos += 3;
+ tmp = aksq[curpos - 1];
+ while (--tmp >= 0) {
+ curpos += 4;
+ curpos += (aksq[curpos] & 0x80) ? 2 : 1;
+ }
+ break;
+ case AKC_C021:
+ case AKC_C022:
+ case AKC_C045:
+ case AKC_C046:
+ case AKC_C047:
+ case AKC_C048:
+ needRedraw = 1;
+ curpos += aksq[curpos + 2];
+ break;
+ case AKC_C08E:
+ akos_queCommand(7, a, GW(2), 0);
+ curpos += 4;
+ break;
+ default:
+ if ((code & 0xC000) == 0xC000)
+ error("akos_increaseAnim: invalid code %x", code);
+ curpos += (code & 0x8000) ? 2 : 1;
+ break;
+ }
+ break;
+ case 2:
+ curpos += (code & 0x8000) ? 2 : 1;
+ if (curpos > end)
+ curpos = a->_cost.start[chan];
+ break;
+ case 3:
+ if (curpos != end)
+ curpos += (code & 0x8000) ? 2 : 1;
+ break;
+ }
+
+ code = aksq[curpos];
+ if (code & 0x80)
+ code = (code << 8) | aksq[curpos + 1];
+
+ if (flag_value && code != AKC_ClearFlag)
+ continue;
+
+ switch (code) {
+ case AKC_StartAnimInActor:
+ akos_queCommand(4, derefActor(a->getAnimVar(GB(2)), "akos_increaseAnim:29"), a->getAnimVar(GB(3)), 0);
+ continue;
+
+ case AKC_Random:
+ a->setAnimVar(GB(6), _rnd.getRandomNumberRng(GW(2), GW(4)));
+ continue;
+ case AKC_JumpGE:
+ case AKC_JumpG:
+ case AKC_JumpLE:
+ case AKC_JumpL:
+ case AKC_JumpNE:
+ case AKC_JumpE:
+ if (akos_compare(a->getAnimVar(GB(4)), GW(5), code - AKC_JumpStart) != 0) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_IncVar:
+ a->setAnimVar(0, a->getAnimVar(0) + 1);
+ continue;
+ case AKC_SetVar:
+ a->setAnimVar(GB(4), GW(2));
+ continue;
+ case AKC_AddVar:
+ a->setAnimVar(GB(4), a->getAnimVar(GB(4)) + GW(2));
+ continue;
+ case AKC_Flip:
+ a->_flip = GW(2) != 0;
+ continue;
+ case AKC_CmdQue3:
+ if (_heversion >= 61)
+ tmp = GB(2);
+ else
+ tmp = GB(2) - 1;
+ if ((uint) tmp < 24)
+ akos_queCommand(3, a, a->_sound[tmp], 0);
+ continue;
+ case AKC_CmdQue3Quick:
+ akos_queCommand(3, a, a->_sound[0], 0);
+ continue;
+ case AKC_StartAnim:
+ akos_queCommand(4, a, GB(2), 0);
+ continue;
+ case AKC_StartVarAnim:
+ akos_queCommand(4, a, a->getAnimVar(GB(2)), 0);
+ continue;
+ case AKC_SetVarInActor:
+ derefActor(a->getAnimVar(GB(2)), "akos_increaseAnim:9")->setAnimVar(GB(3), GW(4));
+ continue;
+ case AKC_HideActor:
+ akos_queCommand(1, a, 0, 0);
+ continue;
+ case AKC_SetActorClip:
+ akos_queCommand(5, a, GB(2), 0);
+ continue;
+ case AKC_SoundStuff:
+ if (_heversion >= 61)
+ continue;
+ tmp = GB(2) - 1;
+ if (tmp >= 8)
+ continue;
+ tmp2 = GB(4);
+ if (tmp2 < 1 || tmp2 > 3)
+ error("akos_increaseAnim:8 invalid code %d", tmp2);
+ akos_queCommand(tmp2 + 6, a, a->_sound[tmp], GB(6));
+ continue;
+ case AKC_SetDrawOffs:
+ akos_queCommand(6, a, GW(2), GW(4));
+ continue;
+ case AKC_JumpTable:
+ if (akfo == NULL)
+ error("akos_increaseAnim: no AKFO table");
+ tmp = a->getAnimVar(GB(2)) - 1;
+ if (_heversion >= 80) {
+ if (tmp < 0 || tmp > a->_cost.heJumpCountTable[chan] - 1)
+ error("akos_increaseAnim: invalid jump value %d", tmp);
+ curpos = READ_LE_UINT16(akfo + a->_cost.heJumpOffsetTable[chan] + tmp * 2);
+ } else {
+ if (tmp < 0 || tmp > numakfo - 1)
+ error("akos_increaseAnim: invalid jump value %d", tmp);
+ curpos = READ_LE_UINT16(&akfo[tmp]);
+ }
+ break;
+ case AKC_JumpIfSet:
+ if (!a->getAnimVar(GB(4)))
+ continue;
+ a->setAnimVar(GB(4), 0);
+ curpos = GUW(2);
+ break;
+
+ case AKC_ClearFlag:
+ flag_value = false;
+ continue;
+
+ case AKC_Jump:
+ curpos = GUW(2);
+ break;
+
+ case AKC_Return:
+ case AKC_EndSeq:
+ case AKC_ComplexChan:
+ case AKC_C08E:
+ case AKC_ComplexChan2:
+ break;
+
+ case AKC_C021:
+ case AKC_C022:
+ needRedraw = 1;
+ break;
+
+ case AKC_Cmd3:
+ case AKC_Ignore:
+ case AKC_Ignore3:
+ continue;
+
+ case AKC_Ignore2:
+ if (_heversion >= 71)
+ akos_queCommand(3, a, a->_sound[a->getAnimVar(GB(2))], 0);
+ continue;
+
+ case AKC_SkipE:
+ case AKC_SkipNE:
+ case AKC_SkipL:
+ case AKC_SkipLE:
+ case AKC_SkipG:
+ case AKC_SkipGE:
+ if (akos_compare(a->getAnimVar(GB(4)), GW(2), code - AKC_SkipStart) == 0)
+ flag_value = true;
+ continue;
+ case AKC_C016:
+ if (_sound->isSoundRunning( a->_sound[a->getAnimVar(GB(4))])) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C017:
+ if (!_sound->isSoundRunning(a->_sound[a->getAnimVar(GB(4))])) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C018:
+ if (_sound->isSoundRunning(a->_sound[GB(4)])) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C019:
+ if (!_sound->isSoundRunning(a->_sound[GB(4)])) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C042:
+ akos_queCommand(9, a, a->_sound[GB(2)], 0);
+ continue;
+ case AKC_C044:
+ akos_queCommand(9, a, a->_sound[a->getAnimVar(GB(2))], 0);
+ continue;
+ case AKC_C045:
+ a->setUserCondition(GB(3), a->getAnimVar(GB(4)));
+ continue;
+ case AKC_C046:
+ a->setAnimVar(GB(4), a->isUserConditionSet(GB(3)));
+ continue;
+ case AKC_C047:
+ a->setTalkCondition(GB(3));
+ continue;
+ case AKC_C048:
+ a->setAnimVar(GB(4), a->isTalkConditionSet(GB(3)));
+ continue;
+ case AKC_C0A0:
+ akos_queCommand(8, a, GB(2), 0);
+ continue;
+ case AKC_C0A1:
+ if (a->_heTalking != 0) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C0A2:
+ if (a->_heTalking == 0) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C0A3:
+ akos_queCommand(8, a, a->getAnimVar(GB(2)), 0);
+ continue;
+ case AKC_C0A4:
+ if (VAR(VAR_TALK_ACTOR) != 0) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ case AKC_C0A5:
+ if (VAR(VAR_TALK_ACTOR) == 0) {
+ curpos = GUW(2);
+ break;
+ }
+ continue;
+ default:
+ if ((code & 0xC000) == 0xC000)
+ error("Undefined uSweat token %X", code);
+ }
+ break;
+ } while (1);
+
+ int code2 = aksq[curpos];
+ if (code2 & 0x80)
+ code2 = (code2 << 8) | aksq[curpos + 1];
+
+ assert((code2 & 0xC000) != 0xC000 || code2 == AKC_ComplexChan || code2 == AKC_Return || code2 == AKC_EndSeq || code2 == AKC_C08E || code2 == AKC_ComplexChan2 || code2 == AKC_C021 || code2 == AKC_C022);
+
+ a->_cost.curpos[chan] = curpos;
+
+ if (needRedraw)
+ return 1;
+ else
+ return curpos != old_curpos;
+}
+
+void ScummEngine::akos_queCommand(byte cmd, Actor *a, int param_1, int param_2) {
+ _akosQueuePos++;
+ checkRange(31, 0, _akosQueuePos, "akos_queCommand overflow");
+
+ _akosQueue[_akosQueuePos].cmd = cmd;
+ _akosQueue[_akosQueuePos].actor = a->_number;
+ _akosQueue[_akosQueuePos].param1 = param_1;
+ _akosQueue[_akosQueuePos].param2 = param_2;
+}
+
+void ScummEngine::akos_processQueue() {
+ byte cmd;
+ int actor, param_1, param_2;
+
+ while (_akosQueuePos) {
+ cmd = _akosQueue[_akosQueuePos].cmd;
+ actor = _akosQueue[_akosQueuePos].actor;
+ param_1 = _akosQueue[_akosQueuePos].param1;
+ param_2 = _akosQueue[_akosQueuePos].param2;
+ _akosQueuePos--;
+
+ Actor *a = derefActor(actor, "akos_processQueue");
+
+ switch (cmd) {
+ case 1:
+ a->putActor(0, 0, 0);
+ break;
+ case 3:
+ _sound->addSoundToQueue(param_1, 0, -1, 0);
+ break;
+ case 4:
+ a->startAnimActor(param_1);
+ break;
+ case 5:
+ a->_forceClip = param_1;
+ break;
+ case 6:
+ a->_offsX = param_1;
+ a->_offsY = param_2;
+ break;
+ case 7:
+#ifndef DISABLE_HE
+ assert(_heversion >= 71);
+ ((ScummEngine_v71he *)this)->queueAuxEntry(a->_number, param_1);
+#endif
+ break;
+ case 8:
+ _actorToPrintStrFor = a->_number;
+
+ a->_talkPosX = a->_heTalkQueue[param_1].posX;
+ a->_talkPosY = a->_heTalkQueue[param_1].posY;
+ a->_talkColor = a->_heTalkQueue[param_1].color;
+
+ _string[0].loadDefault();
+ _string[0].color = a->_talkColor;
+ actorTalk(a->_heTalkQueue[param_1].sentence);
+
+ break;
+ case 9:
+ _sound->addSoundToQueue(param_1, 0, -1, 4);
+ break;
+ default:
+ error("akos_queCommand(%d,%d,%d,%d)", cmd, a->_number, param_1, param_2);
+ }
+ }
+}
+
+#ifndef DISABLE_SCUMM_7_8
+void ScummEngine_v7::akos_processQueue() {
+ byte cmd;
+ int actor, param_1, param_2;
+
+ while (_akosQueuePos) {
+ cmd = _akosQueue[_akosQueuePos].cmd;
+ actor = _akosQueue[_akosQueuePos].actor;
+ param_1 = _akosQueue[_akosQueuePos].param1;
+ param_2 = _akosQueue[_akosQueuePos].param2;
+ _akosQueuePos--;
+
+ Actor *a = derefActor(actor, "akos_processQueue");
+
+ switch (cmd) {
+ case 1:
+ a->putActor(0, 0, 0);
+ break;
+ case 3:
+ if (param_1 != 0) {
+ if (_imuseDigital) {
+ _imuseDigital->startSfx(param_1, 63);
+ }
+ }
+ break;
+ case 4:
+ a->startAnimActor(param_1);
+ break;
+ case 5:
+ a->_forceClip = param_1;
+ break;
+ case 6:
+ a->_offsX = param_1;
+ a->_offsY = param_2;
+ break;
+ case 7:
+ if (param_1 != 0) {
+ if (_imuseDigital) {
+ _imuseDigital->setVolume(param_1, param_2);
+ }
+ }
+ break;
+ case 8:
+ if (param_1 != 0) {
+ if (_imuseDigital) {
+ _imuseDigital->setPan(param_1, param_2);
+ }
+ }
+ break;
+ case 9:
+ if (param_1 != 0) {
+ if (_imuseDigital) {
+ _imuseDigital->setPriority(param_1, param_2);
+ }
+ }
+ break;
+ default:
+ error("akos_queCommand(%d,%d,%d,%d)", cmd, a->_number, param_1, param_2);
+ }
+ }
+}
+#endif
+
+} // End of namespace Scumm
+
+#ifdef PALMOS_68K
+#include "scumm_globals.h"
+
+_GINIT(Akos)
+_GSETPTR(Scumm::bigCostumeScaleTable, GBVARS_BIGSCALETABLE_INDEX, byte, GBVARS_SCUMM)
+//_GSETPTR(Scumm::smallCostumeScaleTableAKOS, GBVARS_SMALLSCALETABLEAKOS_INDEX, byte, GBVARS_SCUMM)
+_GEND
+
+_GRELEASE(Akos)
+_GRELEASEPTR(GBVARS_BIGSCALETABLE_INDEX, GBVARS_SCUMM)
+//_GRELEASEPTR(GBVARS_SMALLSCALETABLEAKOS_INDEX, GBVARS_SCUMM)
+_GEND
+
+#endif