diff options
-rw-r--r-- | scumm/actor.cpp | 43 | ||||
-rw-r--r-- | scumm/actor.h | 11 | ||||
-rw-r--r-- | scumm/akos.cpp | 168 | ||||
-rw-r--r-- | scumm/akos.h | 7 | ||||
-rw-r--r-- | scumm/base-costume.cpp | 4 | ||||
-rw-r--r-- | scumm/base-costume.h | 4 | ||||
-rw-r--r-- | scumm/costume.cpp | 3 | ||||
-rw-r--r-- | scumm/costume.h | 2 | ||||
-rw-r--r-- | scumm/script_v72he.cpp | 5 |
9 files changed, 213 insertions, 34 deletions
diff --git a/scumm/actor.cpp b/scumm/actor.cpp index cbd00bdaef..e4c488c83b 100644 --- a/scumm/actor.cpp +++ b/scumm/actor.cpp @@ -82,7 +82,7 @@ void Actor::initActor(int mode) { } else if (mode == 2) { facing = 180; } - + condMask = 1; elevation = 0; skipLimb = false; width = 24; @@ -1068,7 +1068,7 @@ void Actor::drawActorCostume(bool hitTestMode) { // If the actor is partially hidden, redraw it next frame. // Only done for pre-AKOS, though. - if (bcr->drawCostume(_vm->virtscr[0], cost, drawToBackBuf) & 1) { + if (bcr->drawCostume(_vm->virtscr[0], this, drawToBackBuf) & 1) { needRedraw = (_vm->_version <= 6); } @@ -1816,6 +1816,45 @@ bool Actor::isPlayer() { return isInClass(kObjectClassPlayer); } +void Actor::setUserCondition(int slot, int set) { + debug(1, "Actor::setUserCondition(%d, %d)", slot, set); + assert(slot >= 1 && slot <= 0x20); + if (set == 0) { + condMask &= ~(1 << (slot + 0xF)); + } else { + condMask |= 1 << (slot + 0xF); + } + if (condMask & 0x3FF) { + condMask &= ~1; + } else { + condMask |= 1; + } +} + +bool Actor::isUserConditionSet(int slot) { + assert(slot >= 1 && slot <= 0x20); + return condMask & (1 << (slot + 0xF)); +} + +void Actor::setTalkCondition(int slot) { + debug(1, "Actor::setTalkCondition(%d)", slot); + assert(slot >= 1 && slot <= 0x10); + condMask = (condMask & ~0x3FF) | 1; + if (slot != 1) { + condMask |= 1 << (slot - 1); + if (condMask & 0x3FF) { + condMask &= ~1; + } else { + condMask |= 1; + } + } +} + +bool Actor::isTalkConditionSet(int slot) { + assert(slot >= 1 && slot <= 0x10); + return condMask & (1 << (slot - 1)); +} + const SaveLoadEntry *Actor::getSaveLoadEntries() { static const SaveLoadEntry actorEntries[] = { diff --git a/scumm/actor.h b/scumm/actor.h index 56469d70a9..88e557eb18 100644 --- a/scumm/actor.h +++ b/scumm/actor.h @@ -58,6 +58,10 @@ struct CostumeData { uint16 end[16]; uint16 frame[16]; + uint16 seq1[16]; + uint16 seq2[16]; + uint32 seq3[16]; + void reset() { stopped = 0; for (int i = 0; i < 16; i++) { @@ -119,6 +123,7 @@ public: int8 layer; uint16 sound[32]; CostumeData cost; + uint32 condMask; // XXX save/load protected: byte palette[256]; int elevation; @@ -235,6 +240,12 @@ public: void classChanged(int cls, bool value); + void setUserCondition(int slot, int set); + bool isUserConditionSet(int slot); + + void setTalkCondition(int slot); + bool isTalkConditionSet(int slot); + // Used by the save/load syste: static const SaveLoadEntry *getSaveLoadEntries(); diff --git a/scumm/akos.cpp b/scumm/akos.cpp index b48f46ab01..028b78e5d0 100644 --- a/scumm/akos.cpp +++ b/scumm/akos.cpp @@ -64,6 +64,7 @@ enum AkosOpcodes { AKC_C019 = 0xC019, AKC_ComplexChan = 0xC020, AKC_C021 = 0xC021, + AKC_C022 = 0xC022, AKC_ComplexChan2 = 0xC025, AKC_Jump = 0xC030, AKC_JumpIfSet = 0xC031, @@ -184,9 +185,11 @@ void ScummEngine::akos_decodeData(Actor *a, int frame, uint usemask) { return; r += offs; + const uint8 *akst = findResourceData(MKID('AKST'), akos); + const uint8 *aksf = findResourceData(MKID('AKSF'), akos); + i = 0; - mask = READ_LE_UINT16(r); - r += sizeof(uint16); + mask = READ_LE_UINT16(r); r += 2; do { if (mask & 0x8000) { code = *r++; @@ -198,6 +201,25 @@ void ScummEngine::akos_decodeData(Actor *a, int frame, uint usemask) { a->cost.end[i] = 0; a->cost.start[i] = 0; a->cost.curpos[i] = 0; + a->cost.seq3[i] = 0; + + if (akst) { + int size = getResourceDataSize(akst) / 8; + if (size > 0) { + bool found = false; + while (size--) { + if (READ_LE_UINT32(akst) == 0) { + a->cost.seq3[i] = READ_LE_UINT32(akst + 4); + found = true; + break; + } + akst += 8; + } + if (!found) { + warning("Sequence not found in actor 0x%X costume %d", a, a->costume); + } + } + } break; case 4: a->cost.stopped |= 1 << i; @@ -206,15 +228,53 @@ void ScummEngine::akos_decodeData(Actor *a, int frame, uint usemask) { a->cost.stopped &= ~(1 << i); break; default: - start = READ_LE_UINT16(r); - len = READ_LE_UINT16(r + sizeof(uint16)); - r += sizeof(uint16) * 2; + start = READ_LE_UINT16(r); r += 2; + len = READ_LE_UINT16(r); r += 2; + + a->cost.seq1[i] = 0; + a->cost.seq2[i] = 0; + if (aksf) { + int size = getResourceDataSize(aksf) / 6; + if (size > 0) { + bool found = false; + while (size--) { + if (READ_LE_UINT16(aksf) == start) { + a->cost.seq1[i] = READ_LE_UINT16(aksf + 2); + a->cost.seq2[i] = READ_LE_UINT16(aksf + 4); + found = true; + break; + } + aksf += 6; + } + if (!found) { + warning("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.seq3[i] = 0; + if (akst) { + int size = getResourceDataSize(akst); + if (size > 0) { + bool found = false; + while (size--) { + if (READ_LE_UINT32(akst) == start) { + a->cost.seq3[i] = READ_LE_UINT32(akst + 4); + found = true; + break; + } + akst += 8; + } + if (!found) { + warning("Sequence not found in actor 0x%X costume %d", a, a->costume); + } + } + } break; } } else { @@ -266,6 +326,7 @@ void AkosRenderer::setCostume(int costume) { akcd = _vm->findResourceData(MKID('AKCD'), akos); akpl = _vm->findResourceData(MKID('AKPL'), akos); codec = READ_LE_UINT16(&akhd->codec); + akct = _vm->findResourceData(MKID('AKCT'), akos); } void AkosRenderer::setFacing(Actor *a) { @@ -274,14 +335,23 @@ void AkosRenderer::setFacing(Actor *a) { _mirror = !_mirror; } -byte AkosRenderer::drawLimb(const CostumeData &cost, int limb) { +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; + int xmoveCur, ymoveCur, dxCur, dyCur; + uint32 seq3Idx[32]; + uint8 hasSeq3Idx; + int lastDx, lastDy; + + lastDx = lastDy = 0; + for (i = 0; i < 32; ++i) { + seq3Idx[i] = i; + } if (_skipLimb) return 0; @@ -292,21 +362,29 @@ byte AkosRenderer::drawLimb(const CostumeData &cost, int limb) { if (!cost.active[limb] || cost.stopped & (1 << limb)) return 0; + hasSeq3Idx = 0; p = aksq + cost.curpos[limb]; code = p[0]; if (code & 0x80) code = (code << 8) | p[1]; - if (code == AKC_Return || code == AKC_EndSeq) - return 0; + if (code == AKC_C021 || code == AKC_C022) { + uint16 s = cost.curpos[limb] + 4; + uint j = 0; + extra = p[3]; + uint8 n = extra; + while (n--) { + seq3Idx[j++] = aksq[s++]; + } + hasSeq3Idx = 1; + p += extra + 2; + code = (code == AKC_C021) ? AKC_ComplexChan : AKC_ComplexChan2; + } - //HACK Until support is added. - if (code == AKC_C021) + if (code == AKC_Return || code == AKC_EndSeq) return 0; - // Code 0xC025 reads 4 bytes of extra information - if (code != AKC_ComplexChan && code != AKC_ComplexChan2) { off = akof + (code & 0xFFF); @@ -342,11 +420,15 @@ byte AkosRenderer::drawLimb(const CostumeData &cost, int limb) { error("akos_drawLimb: invalid codec %d", codec); } } else { - if (code == AKC_ComplexChan2) + 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 = seq3Idx[0]; for (i = 0; i != extra; i++) { code = p[4]; @@ -363,8 +445,41 @@ byte AkosRenderer::drawLimb(const CostumeData &cost, int limb) { xmoveCur = _xmove + (int16)READ_LE_UINT16(p + 0); ymoveCur = _ymove + (int16)READ_LE_UINT16(p + 2); + if (i >= extra - 1) { + dxCur = lastDx; + dyCur = lastDy; + } else { + dxCur = 0; + dyCur = 0; + } + + xmoveCur += dxCur; + ymoveCur -= dyCur; + + if (!hasSeq3Idx || !akct) { + decflag = 1; + } else { + uint32 cond = READ_LE_UINT32(akct + cost.seq3[limb] + seq3Idx[i] * 4); + if (cond == 0) { + decflag = 1; + } else { + uint32 type = cond & 0xC0000000; + cond &= 0x3FFFFFFF; + if (type == 0x40000000) { + decflag = (a->condMask & cond) ? 1 : 0; + } else if (type == 0x80000000) { + decflag = (a->condMask & cond) ? 0 : 1; + } else { + decflag = (a->condMask & cond) ? 1 : 0; + } + } + } + p += (p[4] & 0x80) ? 6 : 5; + if (decflag == 0) + continue; + switch (codec) { case 1: result |= codec1(xmoveCur, ymoveCur); @@ -1338,9 +1453,15 @@ bool ScummEngine::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const if (akfo == NULL) error("akos_increaseAnim: no AKFO table"); tmp = a->getAnimVar(GB(2)) - 1; - if (tmp < 0 || tmp > numakfo - 1) - error("akos_increaseAnim: invalid jump value %d", tmp); - curpos = READ_LE_UINT16(&akfo[tmp]); + if (_heversion >= 80) { + if (tmp < 0 || tmp > a->cost.seq2[chan] - 1) + error("akos_increaseAnim: invalid jump value %d", tmp); + curpos = READ_LE_UINT16(akfo + a->cost.seq1[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))) @@ -1434,19 +1555,19 @@ bool ScummEngine::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const continue; case AKC_C045: - //actorSetUserCondition(a, GB(3), a->getAnimVar(GB(4))); + a->setUserCondition(GB(3), a->getAnimVar(GB(4))); continue; case AKC_C046: - //a->setAnimVar(GB(4), actorIsUserConditionSet(a, GB(3))); + a->setAnimVar(GB(4), a->isUserConditionSet(GB(3))); continue; case AKC_C047: - //actorSetTalkCondition(a, GB(3)); + a->setTalkCondition(GB(3)); continue; case AKC_C048: - //a->setAnimVar(GB(4), actorIsTalkConditionSet(a, GB(3))); + a->setAnimVar(GB(4), a->isTalkConditionSet(GB(3))); continue; default: @@ -1459,7 +1580,8 @@ bool ScummEngine::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const 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); + + assert((code2 & 0xC000) != 0xC000 || code2 == AKC_ComplexChan || code2 == AKC_Return || code2 == AKC_EndSeq || code2 == AKC_C08E || code2 == AKC_ComplexChan2 || code2 == AKC_C021 || code == AKC_C022); a->cost.curpos[chan] = curpos; @@ -1471,7 +1593,7 @@ bool ScummEngine::akos_increaseAnim(Actor *a, int chan, const byte *aksq, const void ScummEngine::akos_queCommand(byte cmd, Actor *a, int param_1, int param_2) { checkRange(32, 0, _queuePos, "akos_queCommand overflow"); -; + _queuePos++; _queueCmd[_queuePos] = cmd; _queueActor[_queuePos] = a->number; diff --git a/scumm/akos.h b/scumm/akos.h index c38622b2f4..3bd2a0ac18 100644 --- a/scumm/akos.h +++ b/scumm/akos.h @@ -51,6 +51,8 @@ protected: const byte *akpl, *akci, *aksq; const AkosOffset *akof; const byte *akcd; + + const byte *akct; struct { byte unk5; @@ -73,6 +75,7 @@ public: aksq = 0; akof = 0; akcd = 0; + akct = 0; _actorHitMode = false; } @@ -85,13 +88,11 @@ public: void setCostume(int costume); protected: - byte drawLimb(const CostumeData &cost, int limb); + byte drawLimb(const Actor *a, int limb); byte codec1(int xmoveCur, int ymoveCur); void codec1_genericDecode(); - byte codec5(int xmoveCur, int ymoveCur); - byte codec16(int xmoveCur, int ymoveCur); void akos16SetupBitReader(const byte *src); void akos16SkipData(int32 numskip); diff --git a/scumm/base-costume.cpp b/scumm/base-costume.cpp index 9ce7bbf286..63dae0686c 100644 --- a/scumm/base-costume.cpp +++ b/scumm/base-costume.cpp @@ -25,7 +25,7 @@ namespace Scumm { -byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, const CostumeData &cost, bool drawToBackBuf) { +byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, const Actor *a, bool drawToBackBuf) { int i; byte result = 0; @@ -48,7 +48,7 @@ byte BaseCostumeRenderer::drawCostume(const VirtScreen &vs, const CostumeData &c _xmove = _ymove = 0; } for (i = 0; i < 16; i++) - result |= drawLimb(cost, i); + result |= drawLimb(a, i); return result; } diff --git a/scumm/base-costume.h b/scumm/base-costume.h index 82f2e14648..03ca48f90e 100644 --- a/scumm/base-costume.h +++ b/scumm/base-costume.h @@ -132,11 +132,11 @@ public: virtual void setCostume(int costume) = 0; - byte drawCostume(const VirtScreen &vs, const CostumeData &cost, bool drawToBackBuf); + byte drawCostume(const VirtScreen &vs, const Actor *a, bool drawToBackBuf); protected: - virtual byte drawLimb(const CostumeData &cost, int limb) = 0; + virtual byte drawLimb(const Actor *a, int limb) = 0; void codec1_ignorePakCols(int num); }; diff --git a/scumm/costume.cpp b/scumm/costume.cpp index 7b9f4282ff..0ed1ed1616 100644 --- a/scumm/costume.cpp +++ b/scumm/costume.cpp @@ -594,10 +594,11 @@ void LoadedCostume::loadCostume(int id) { _animCmds = _baseptr + READ_LE_UINT16(ptr); } -byte CostumeRenderer::drawLimb(const CostumeData &cost, int limb) { +byte CostumeRenderer::drawLimb(const Actor *a, int limb) { int i; int code; const byte *frameptr; + const CostumeData &cost = a->cost; // If the specified limb is stopped or not existing, do nothing. if (cost.curpos[limb] == 0xFFFF || cost.stopped & (1 << limb)) diff --git a/scumm/costume.h b/scumm/costume.h index 52293d2134..0578a710a7 100644 --- a/scumm/costume.h +++ b/scumm/costume.h @@ -69,7 +69,7 @@ public: void setCostume(int costume); protected: - byte drawLimb(const CostumeData &cost, int limb); + byte drawLimb(const Actor *a, int limb); void proc3(); void proc3_ami(); diff --git a/scumm/script_v72he.cpp b/scumm/script_v72he.cpp index 48d39aee92..408d3a5432 100644 --- a/scumm/script_v72he.cpp +++ b/scumm/script_v72he.cpp @@ -852,11 +852,16 @@ void ScummEngine_v72he::o72_actorOps() { case 21: // HE 80+ k = getStackList(args, ARRAYSIZE(args)); + for (i = 0; i < k; ++i) { + a->setUserCondition(args[i] & 0x7F, args[i] & 0x80); + } debug(1,"o72_actorOps: case 21 (%d)", k); break; case 24: // HE 80+ k = pop(); +// a->byte_45737A = 1; + a->setTalkCondition(k); debug(1,"o72_actorOps: case 24 (%d)", k); break; case 43: |