diff options
Diffstat (limited to 'engines/scumm/akos.cpp')
-rw-r--r-- | engines/scumm/akos.cpp | 1869 |
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 |