aboutsummaryrefslogtreecommitdiff
path: root/scumm
diff options
context:
space:
mode:
Diffstat (limited to 'scumm')
-rw-r--r--scumm/actor.cpp43
-rw-r--r--scumm/actor.h11
-rw-r--r--scumm/akos.cpp168
-rw-r--r--scumm/akos.h7
-rw-r--r--scumm/base-costume.cpp4
-rw-r--r--scumm/base-costume.h4
-rw-r--r--scumm/costume.cpp3
-rw-r--r--scumm/costume.h2
-rw-r--r--scumm/script_v72he.cpp5
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: