diff options
-rw-r--r-- | engines/scumm/actor.cpp | 65 | ||||
-rw-r--r-- | engines/scumm/actor.h | 8 | ||||
-rw-r--r-- | engines/scumm/costume.cpp | 207 | ||||
-rw-r--r-- | engines/scumm/costume.h | 6 | ||||
-rw-r--r-- | engines/scumm/script_v0.cpp | 19 |
5 files changed, 247 insertions, 58 deletions
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 88c258a2e6..3033904357 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -527,9 +527,15 @@ void Actor_v2::walkActor() { if (_moving & MF_TURN) { new_dir = updateActorDirection(false); // FIXME: is this correct? - if (_facing != new_dir) + if (_facing != new_dir) { + + // Actor never stops walking when an object has been selected without this + if (_vm->_game.version ==0) + _moving = 0; + setDirection(new_dir); - else + + } else _moving = 0; return; } @@ -817,6 +823,16 @@ void Actor::setDirection(int direction) { if (_costume == 0) return; + // V0 MM + if (_vm->_game.version == 0) { + if (_moving) + _vm->_costumeLoader->costumeDecodeData(this, _walkFrame, 0); + else + _vm->_costumeLoader->costumeDecodeData(this, _standFrame, 0); + _needRedraw = true; + return; + } + // Update the costume for the new direction (and mark the actor for redraw) aMask = 0x8000; for (i = 0; i < 16; i++, aMask >>= 1) { @@ -1224,7 +1240,10 @@ void Actor::showActor() { _vm->ensureResourceLoaded(rtCostume, _costume); - if (_vm->_game.version <= 2) { + if (_vm->_game.version == 0) { + _cost.reset(); + startAnimActor(_standFrame); + } else if (_vm->_game.version <= 2) { _cost.reset(); startAnimActor(_standFrame); startAnimActor(_initFrame); @@ -1380,6 +1399,13 @@ void ScummEngine::processActors() { Actor** end = _sortedActors + numactors; for (Actor** ac = _sortedActors; ac != end; ++ac) { Actor* a = *ac; + + // V0 MM: 0x057B + if (_game.version == 0) { + ActorC64 *A = (ActorC64*) a; + if ((A->_speaking & 1)) + A->_speaking ^= 0xFE; + } // Draw and animate the actors, except those w/o a costume. // Note: We could 'optimize' this a little bit by only putting // actors with a costume into the _sortedActors array in the @@ -1572,6 +1598,8 @@ void Actor_v2::prepareDrawActorCostume(BaseCostumeRenderer *bcr) { // we need to shift it 8 pixels to the left if (_facing == 90) bcr->_actorX -= 8; + } else if (_vm->_game.version == 0) { + bcr->_actorX += 12; } else if (_vm->_game.version <= 2) { // HACK: We have to adjust the x position by one strip (8 pixels) in // V2 games. However, it is not quite clear to me why. And to fully @@ -1703,6 +1731,12 @@ void Actor::animateActor(int anim) { case 4: // turn to new direction turnToDirection(dir); break; + case 64: + if (_vm->_game.version == 0) { + _moving &= ~MF_TURN; + setDirection(dir); + break; + } default: if (_vm->_game.version <= 2) startAnimActor(anim / 4); @@ -2167,21 +2201,38 @@ void Actor::setActorCostume(int c) { } } -static const char* v0ActorNames[7] = { +static const char* v0ActorNames[0x19] = { "Syd", "Razor", "Dave", "Michael", "Bernard", "Wendy", - "Jeff" + "Jeff", + "", + "Dr Fred", + "Nurse Edna", + "Weird Ed", + "Dead Cousin Ted", + "Purple Tentacle", + "Green Tentacle", + "Meteor", + "Plant", + "", + "", + "", + "", + "", + "", + "Sandy" }; const byte *Actor::getActorName() { - const byte *ptr; + const byte *ptr = NULL; if (_vm->_game.version == 0) { - ptr = (const byte *)v0ActorNames[_number - 1]; + if (_number) + ptr = (const byte *)v0ActorNames[_number - 1]; } else { ptr = _vm->getResourceAddress(rtActorName, _number); } diff --git a/engines/scumm/actor.h b/engines/scumm/actor.h index 3e8fe6626b..3f67d42a50 100644 --- a/engines/scumm/actor.h +++ b/engines/scumm/actor.h @@ -380,11 +380,15 @@ protected: class ActorC64 : public Actor_v2 { public: - // FIXME: This flag is never saved, which might lead to broken save states. + // FIXME: These vars are never saved, which might lead to broken save states. byte _miscflags; + byte _speaking, _speakingPrev; + byte _costCommand, _costFrame; public: - ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) {} + ActorC64(ScummEngine *scumm, int id) : Actor_v2(scumm, id) { + _speaking = _speakingPrev = _costCommand = _costFrame = 0; + } virtual void initActor(int mode) { Actor_v2::initActor(mode); if (mode == -1) { diff --git a/engines/scumm/costume.cpp b/engines/scumm/costume.cpp index 82497de87a..3c6c8620b0 100644 --- a/engines/scumm/costume.cpp +++ b/engines/scumm/costume.cpp @@ -1040,26 +1040,25 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (limb >= 8) return 0; + if (a->_cost.start[limb] == 0xFFFF) + return 0; + if (limb == 0) { _draw_top = 200; _draw_bottom = 0; } + + bool flipped = (a->_cost.start[limb] & 0x80) != 0; + byte frameStart = _loaded._frameOffsets[a->_cost.frame[limb]]; + byte frame = _loaded._frameOffsets[frameStart + a->_cost.curpos[limb]]; + if (frame == 0xFF) + return 0; - // TODO: - // get out how animations are handled - byte state = a->_moving != 0 ? 0 : 1; - byte unk1 = (_loaded._animCmds + (state*32) + newDirToOldDir(a->getFacing()) * 8)[limb]; - byte unk2 = _loaded._frameOffsets[_loaded._frameOffsets[limb] + (unk1 & 0x7f)]; - bool flipped = (unk1 & 0x80) != 0; - - byte p1 = _loaded._frameOffsets[unk2]; - byte temp1 = _loaded._baseptr[p1]; - byte temp2 = temp1 + _loaded._dataOffsets[4]; - int offL = _loaded._baseptr[temp1 + 2]; - int offH = _loaded._baseptr[temp2]; - int off = (offH << 8) + offL; + byte ptrLow = _loaded._baseptr[frame]; + byte ptrHigh = ptrLow + _loaded._dataOffsets[4]; + int frameOffset = (_loaded._baseptr[ptrHigh] << 8) + _loaded._baseptr[ptrLow + 2]; // 0x23EF / 0x2400 - const byte *data = _loaded._baseptr + off; + const byte *data = _loaded._baseptr + frameOffset; // Set up the palette data byte palette[4] = { 0, 0, 0, 0 }; @@ -1077,8 +1076,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int offsetY = *data++; // these two fields seems to be most times zero // byte6 was one time 255 in one costume I tried -// int byte5 = *data++; -// int byte6 = *data++; +// int byte5 = *data++; // 0x1F80 // This value is never used +// int byte6 = *data++; // 0x1F86 // This value is subtracted from ?actor drawy? at 0x2383 // debug(3, "byte5: %d", byte5); // debug(3, "byte6: %d", byte6); data += 2; @@ -1091,17 +1090,13 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { if (flipped) { if (offsetX) - xpos += (offsetX-1) * 8; + xpos += (offsetX - 1) * 8; } else { xpos += offsetX * 8; } - // + 4 could be commented, because maybe the _actorX position is - // wrong, I looked at the scumm-c64 interpreter by lloyd - // and there Bernhard is directly on the right in the intro - // but here in ScummVM he is 4 pixel left of the other position. - xpos += _actorX - (a->_width / 2) + 4; - ypos += _actorY - _loaded._maxHeight; + xpos += _actorX - (a->_width / 2); + ypos += (_actorY - _loaded._maxHeight) + 1; // +1 as we appear to be 1 pixel away from the original interpreter // This code is very similar to procC64() for (int y = 0; y < height; ++y) { @@ -1111,9 +1106,9 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { int realX = 0; if (flipped) { if (offsetX == 0||offsetX == 1) { - realX = width-(x+1); + realX = width-(x + 1); } else if (offsetX == 2) { - realX = width-(x+2); + realX = width-(x + 2); } } else { realX = x; @@ -1134,10 +1129,8 @@ byte C64CostumeRenderer::drawLimb(const Actor *a, int limb) { } _draw_top = MIN(_draw_top, ypos); - _draw_bottom = MAX(_draw_bottom, ypos+height); - // if +4 above is NOT commented, here "+(flipped ? 4 : 0)" can be commented out - // and other way round - _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos+(width*8)/*+(flipped ? 4 : 0)*/, ypos, ypos+height, _actorID); + _draw_bottom = MAX(_draw_bottom, ypos + height); + _vm->markRectAsDirty(kMainVirtScreen, xpos, xpos + (width * 8), ypos, ypos + height, _actorID); return 0; } @@ -1151,6 +1144,7 @@ void C64CostumeRenderer::setCostume(int costume, int shadow) { void C64CostumeLoader::loadCostume(int id) { const byte *ptr = _vm->getResourceAddress(rtCostume, id); + _id = id; _baseptr = ptr + 9; @@ -1165,33 +1159,152 @@ void C64CostumeLoader::loadCostume(int id) { _animCmds = _baseptr + READ_LE_UINT16(ptr + 7); _maxHeight = 0; - for (int i = 0; i < 8; ++i) { - int pid = _frameOffsets[_frameOffsets[i]]; - byte p1 = _frameOffsets[pid]; - byte b = _baseptr[p1]; - byte c = b + _dataOffsets[4]; - int offL = _baseptr[b + 2]; - int offH = _baseptr[c]; - int off = (offH << 8) + offL; - const byte *data = _baseptr + off; - - if (data[3] > _maxHeight) { - _maxHeight = data[3]; // data[3] is libs's Y offset +} + +void C64CostumeLoader::frameUpdate(ActorC64 *a, int cmd ) { + byte limbFrames = 0; + + // Each costume-command has 8 limbs (0x2622) + cmd <<= 3; + + for (int limb = 0, pos = 0; limb < 8; ++limb, pos = 0) { + // get a limb frames ptr from the costume command + limbFrames = ((_animCmds + cmd)[limb]); + + // Dont change limb if entry is invalid + if (limbFrames == 0xFF) + continue; + + // Has limb frames ptr changed since last update? + if (a->_cost.start[limb] == limbFrames) + continue; + + // Set new limb command addresses + a->_cost.start[limb] = limbFrames; + a->_cost.frame[limb] = _frameOffsets[limb] + (limbFrames & 0x7f); // limb animation-frames ptr + + // Get first entry of a limbs' frames + byte frameStart = _frameOffsets[ a->_cost.frame[limb]]; + + // Loop each frame in this limb until we reach the end marker + while (pos != 0xFF) { // This is just so we dont overflow + byte frame = _frameOffsets[frameStart + pos]; + + // Each animation-frame until we find end + if (frame == 0xFF) + break; + + byte ptrLow = _baseptr[frame]; + byte ptrHigh = ptrLow + _dataOffsets[4]; + int frameOffset = (_baseptr[ptrHigh] << 8) + _baseptr[ptrLow + 2]; // 0x23EF / 0x2400 + + const byte *data = _baseptr + frameOffset; + + if (data[3] > _maxHeight) + _maxHeight = data[3] + 1; + + ++pos; } + + // Set ending position of limb frames + a->_cost.end[limb] = pos - 1; + a->_cost.curpos[limb] = 0; } - ++_maxHeight; } -void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { +// based on 0x2BCA, doesn't match disassembly because 'oldDir' variable +// is not the same value as stored in the original interpreter +int C64CostumeLoader::dirToDirStop( int oldDir ) { + switch (oldDir) { + case 0: + return 4; // Left + case 1: + return 5; // Right + case 2: + return 6; // Face Camera + case 3: + return 7; // Face Away + } + // shouldnt' be reached + return 4; } -byte C64CostumeLoader::increaseAnims(Actor *a) { - return 0; +void C64CostumeLoader::actorSpeak(ActorC64 *a, int &cmd) { + if ((a->_speaking & 0x80)) + cmd += 0x0C; + else + cmd += 0x10; } -byte C64CostumeLoader::increaseAnim(Actor *a, int slot) { - return 0; +void C64CostumeLoader::costumeDecodeData(Actor *a, int frame, uint usemask) { + ActorC64 *A = (ActorC64*) a; + int dir = newDirToOldDir(a->getFacing()); + int command = dir; + + loadCostume(a->_costume); + + // Enable/Disable speaking flag + if (frame == a->_talkStartFrame) { + A->_speaking = 1; + return; + } + if (frame == a->_talkStopFrame) { + A->_speaking = 0; + return; + } + + // Different command for stand frame + if (frame == a->_standFrame) + command = dirToDirStop(dir); + + // Update the limb frames + frameUpdate(A, command); + + // Keep current command/frame mode + A->_costCommand = dir; + A->_costFrame = frame; + + // Update 'speaking' frames? + if (A->_speaking) { + command = dir; // Incase standing frame was set as cmd + actorSpeak(A, command); + + // Update the limb speak frames + frameUpdate(A, command); + } } +byte C64CostumeLoader::increaseAnims(Actor *a) { + ActorC64 *A = (ActorC64*) a; + + // check if the actor speak flag has changed since last frame increase + if (A->_speaking != A->_speakingPrev) { + int cmd = A->_costCommand; + A->_speakingPrev = A->_speaking; + + // Update to use speak frame + if (A->_speaking & 0x80) { + actorSpeak(A, cmd); + + } else { + // Update to use stand frame + if (A->_costFrame == A->_standFrame) + cmd = dirToDirStop(cmd); + } + + // Update the limb frames + frameUpdate(A, cmd); + } + + // increase each frame pos + for (int limb = 0; limb < 8; ++limb) { + if (a->_cost.curpos[limb] < a->_cost.end[limb]) + a->_cost.curpos[limb]++; + else + a->_cost.curpos[limb] = 0; + } + + return 1; +} } // End of namespace Scumm diff --git a/engines/scumm/costume.h b/engines/scumm/costume.h index 003bd6ce2b..03de9c0510 100644 --- a/engines/scumm/costume.h +++ b/engines/scumm/costume.h @@ -79,8 +79,12 @@ public: byte increaseAnims(Actor *a); int _maxHeight; + protected: - byte increaseAnim(Actor *a, int slot); + void actorSpeak(ActorC64 *a, int &cmd); + int dirToDirStop( int oldDir ); + void frameUpdate(ActorC64 *A, int cmd); + }; class ClassicCostumeRenderer : public BaseCostumeRenderer { diff --git a/engines/scumm/script_v0.cpp b/engines/scumm/script_v0.cpp index 1b8368d636..50c4a89e0a 100644 --- a/engines/scumm/script_v0.cpp +++ b/engines/scumm/script_v0.cpp @@ -666,7 +666,19 @@ void ScummEngine_v0::o_animateActor() { int unk = fetchScriptByte(); debug(0,"o_animateActor: unk %d", unk); - Actor *a = derefActor(act, "o_animateActor"); + ActorC64 *a = (ActorC64*) derefActor(act, "o_animateActor"); + + // 0x6993 + if (anim == 0xFE) { + a->_speaking = 0x80; // Enabled, but not switching + return; + } + // 0x69A3 + if (anim == 0xFD) { + a->_speaking = 0x00; + return; + } + a->animateActor(anim); } @@ -738,8 +750,13 @@ void ScummEngine_v0::o_setActorBitVar() { byte act = getVarOrDirectByte(PARAM_1); byte mask = getVarOrDirectByte(PARAM_2); byte mod = getVarOrDirectByte(PARAM_3); + + // 0x63ED + if (act >= _numActors) + return; ActorC64 *a = (ActorC64 *)derefActor(act, "o_setActorBitVar"); + if (mod) a->_miscflags |= mask; else |