aboutsummaryrefslogtreecommitdiff
path: root/scumm/akos.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scumm/akos.cpp')
-rw-r--r--scumm/akos.cpp168
1 files changed, 145 insertions, 23 deletions
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;