diff options
author | Max Horn | 2006-10-18 14:01:28 +0000 |
---|---|---|
committer | Max Horn | 2006-10-18 14:01:28 +0000 |
commit | 92adf6a65c9432a2e177b8f7bcbcf235110345b8 (patch) | |
tree | 6e283c61cd80f4bcaf6bc80a868d227268091c66 /engines/scumm/actor.cpp | |
parent | f51e01a0aa1fa89e381044f04dd7b1e3483b35f5 (diff) | |
download | scummvm-rg350-92adf6a65c9432a2e177b8f7bcbcf235110345b8.tar.gz scummvm-rg350-92adf6a65c9432a2e177b8f7bcbcf235110345b8.tar.bz2 scummvm-rg350-92adf6a65c9432a2e177b8f7bcbcf235110345b8.zip |
SCUMM: reordered contents of actor.cpp, grouping methods in a hopefully somewhat more logical fashion
svn-id: r24367
Diffstat (limited to 'engines/scumm/actor.cpp')
-rw-r--r-- | engines/scumm/actor.cpp | 1345 |
1 files changed, 693 insertions, 652 deletions
diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 137d457b1c..e9f6b87739 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -159,6 +159,54 @@ void Actor::initActor(int mode) { _vm->_classData[_number] = (_vm->_game.version >= 7) ? _vm->_classData[0] : 0; } +void Actor::setBox(int box) { + _walkbox = box; + setupActorScale(); +} + +void Actor::setupActorScale() { + + if (_vm->_game.features & GF_NO_SCALING) { + _scalex = 0xFF; + _scaley = 0xFF; + return; + } + + if (_ignoreBoxes) + return; + + // For some boxes, we ignore the scaling and use whatever values the + // scripts set. This is used e.g. in the Mystery Vortex in Sam&Max. + // Older games used the flag 0x20 differently, though. + if (_vm->_game.id == GID_SAMNMAX && (_vm->getBoxFlags(_walkbox) & kBoxIgnoreScale)) + return; + + _boxscale = _vm->getBoxScale(_walkbox); + + uint16 scale = _vm->getScale(_walkbox, _pos.x, _pos.y); + assert(scale <= 0xFF); + + _scalex = _scaley = (byte)scale; +} + + +#pragma mark - +#pragma mark --- Actor walking --- +#pragma mark - + + +void ScummEngine::walkActors() { + int i; + + for (i = 1; i < _numActors; i++) { + if (_actors[i].isInCurrentRoom()) + if (_game.version <= 3) + _actors[i].walkActorOld(); + else + _actors[i].walkActor(); + } +} + void Actor::stopActorMoving() { if (_walkScript) _vm->stopScript(_walkScript); @@ -177,8 +225,8 @@ void Actor::setActorWalkSpeed(uint newSpeedX, uint newSpeedY) { } } -int ScummEngine::getAngleFromPos(int x, int y) const { - if (_game.id == GID_DIG || _game.id == GID_CMI) { +int getAngleFromPos(int x, int y, bool useATAN) { + if (useATAN) { double temp = atan2((double)x, (double)-y); return normalizeAngle((int)(temp * 180 / PI)); } else { @@ -236,11 +284,396 @@ int Actor::calcMovementFactor(const Common::Point& next) { _walkdata.xfrac = 0; _walkdata.yfrac = 0; - _targetFacing = _vm->getAngleFromPos(deltaXFactor, deltaYFactor); + _targetFacing = getAngleFromPos(deltaXFactor, deltaYFactor, (_vm->_game.id == GID_DIG || _vm->_game.id == GID_CMI)); return actorWalkStep(); } +int Actor::actorWalkStep() { + int tmpX, tmpY; + Common::Point _actorPos; + int distX, distY; + int nextFacing; + + _needRedraw = true; + + nextFacing = updateActorDirection(true); + if (!(_moving & MF_IN_LEG) || _facing != nextFacing) { + if (_walkFrame != _frame || _facing != nextFacing) { + startWalkAnim(1, nextFacing); + } + _moving |= MF_IN_LEG; + } + + _actorPos = _pos; + + if (_walkbox != _walkdata.curbox && _vm->checkXYInBoxBounds(_walkdata.curbox, _actorPos.x, _actorPos.y)) { + setBox(_walkdata.curbox); + } + + distX = ABS(_walkdata.next.x - _walkdata.cur.x); + distY = ABS(_walkdata.next.y - _walkdata.cur.y); + + if (ABS(_actorPos.x - _walkdata.cur.x) >= distX && ABS(_actorPos.y - _walkdata.cur.y) >= distY) { + _moving &= ~MF_IN_LEG; + return 0; + } + + tmpX = (_actorPos.x << 16) + _walkdata.xfrac + (_walkdata.deltaXFactor >> 8) * _scalex; + _walkdata.xfrac = (uint16)tmpX; + _actorPos.x = (tmpX >> 16); + + tmpY = (_actorPos.y << 16) + _walkdata.yfrac + (_walkdata.deltaYFactor >> 8) * _scaley; + _walkdata.yfrac = (uint16)tmpY; + _actorPos.y = (tmpY >> 16); + + if (ABS(_actorPos.x - _walkdata.cur.x) > distX) { + _actorPos.x = _walkdata.next.x; + } + + if (ABS(_actorPos.y - _walkdata.cur.y) > distY) { + _actorPos.y = _walkdata.next.y; + } + + _pos = _actorPos; + + if (_vm->_game.version >= 4 && _vm->_game.version <= 6 && _pos == _walkdata.next) { + _moving &= ~MF_IN_LEG; + return 0; + } + return 1; +} + +void Actor::startWalkActor(int destX, int destY, int dir) { + AdjustBoxResult abr; + + if (!isInCurrentRoom() && _vm->_game.version >= 7) { + debugC(DEBUG_ACTORS, "startWalkActor: attempting to walk actor %d who is not in this room", _number); + return; + } + + if (_vm->_game.version <= 4) { + abr.x = destX; + abr.y = destY; + } else { + abr = adjustXYToBeInBox(destX, destY); + } + + if (!isInCurrentRoom() && _vm->_game.version <= 6) { + _pos.x = abr.x; + _pos.y = abr.y; + if (!_ignoreTurns && dir != -1) + _facing = dir; + return; + } + + if (_ignoreBoxes) { + abr.box = kInvalidBox; + _walkbox = kInvalidBox; + } else { + if (_vm->checkXYInBoxBounds(_walkdata.destbox, abr.x, abr.y)) { + abr.box = _walkdata.destbox; + } else { + abr = adjustXYToBeInBox(abr.x, abr.y); + } + if (_moving && _walkdata.destdir == dir && _walkdata.dest.x == abr.x && _walkdata.dest.y == abr.y) + return; + } + + if (_pos.x == abr.x && _pos.y == abr.y) { + if (dir != _facing) + turnToDirection(dir); + return; + } + + _walkdata.dest.x = abr.x; + _walkdata.dest.y = abr.y; + _walkdata.destbox = abr.box; + _walkdata.destdir = dir; + _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG; + _walkdata.point3.x = 32000; + + _walkdata.curbox = _walkbox; +} + +void Actor::startWalkAnim(int cmd, int angle) { + if (angle == -1) + angle = _facing; + + /* Note: walk scripts aren't required to make the Dig + * work as usual + */ + if (_walkScript) { + int args[16]; + memset(args, 0, sizeof(args)); + args[0] = _number; + args[1] = cmd; + args[2] = angle; + _vm->runScript(_walkScript, 1, 0, args); + } else { + switch (cmd) { + case 1: /* start walk */ + setDirection(angle); + startAnimActor(_walkFrame); + break; + case 2: /* change dir only */ + setDirection(angle); + break; + case 3: /* stop walk */ + turnToDirection(angle); + startAnimActor(_standFrame); + break; + } + } +} + +void Actor::walkActor() { + int new_dir, next_box; + Common::Point foundPath; + + if (_vm->_game.version >= 7) { + if (_moving & MF_FROZEN) { + if (_moving & MF_TURN) { + new_dir = updateActorDirection(false); + if (_facing != new_dir) + setDirection(new_dir); + else + _moving &= ~MF_TURN; + } + return; + } + } + + if (!_moving) + return; + + if (!(_moving & MF_NEW_LEG)) { + if (_moving & MF_IN_LEG && actorWalkStep()) + return; + + if (_moving & MF_LAST_LEG) { + _moving = 0; + setBox(_walkdata.destbox); + if (_vm->_game.version <= 6) { + startAnimActor(_standFrame); + if (_targetFacing != _walkdata.destdir) + turnToDirection(_walkdata.destdir); + } else { + startWalkAnim(3, _walkdata.destdir); + } + return; + } + + if (_moving & MF_TURN) { + new_dir = updateActorDirection(false); + if (_facing != new_dir) + setDirection(new_dir); + else + _moving = 0; + return; + } + + setBox(_walkdata.curbox); + _moving &= MF_IN_LEG; + } + + _moving &= ~MF_NEW_LEG; + do { + + if (_walkbox == kInvalidBox) { + setBox(_walkdata.destbox); + _walkdata.curbox = _walkdata.destbox; + break; + } + + if (_walkbox == _walkdata.destbox) + break; + + next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); + if (next_box < 0) { + _walkdata.destbox = _walkbox; + _moving |= MF_LAST_LEG; + return; + } + + _walkdata.curbox = next_box; + + if (findPathTowards(_walkbox, next_box, _walkdata.destbox, foundPath)) + break; + + if (calcMovementFactor(foundPath)) + return; + + setBox(_walkdata.curbox); + } while (1); + + _moving |= MF_LAST_LEG; + calcMovementFactor(_walkdata.dest); +} + +/* +void Actor::walkActorV12() { + Common::Point foundPath, tmp; + int new_dir, next_box; + + if (_moving & MF_TURN) { + new_dir = updateActorDirection(false); + if (_facing != new_dir) + setDirection(new_dir); + else + _moving = 0; + return; + } + + if (!_moving) + return; + + if (_moving & MF_IN_LEG) { + actorWalkStep(); + } else { + if (_moving & MF_LAST_LEG) { + _moving = 0; + startAnimActor(_standFrame); + if (_targetFacing != _walkdata.destdir) + turnToDirection(_walkdata.destdir); + } else { + setBox(_walkdata.curbox); + if (_walkbox == _walkdata.destbox) { + foundPath = _walkdata.dest; + _moving |= MF_LAST_LEG; + } else { + next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); + if (next_box < 0) { + _moving |= MF_LAST_LEG; + return; + } + + // Can't walk through locked boxes + int flags = _vm->getBoxFlags(next_box); + if (flags & kBoxLocked && !(flags & kBoxPlayerOnly && !isPlayer())) { + _moving |= MF_LAST_LEG; + } + + _walkdata.curbox = next_box; + + getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), x, y, tmp.x, tmp.y); + getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), tmp.x, tmp.y, foundPath.x, foundPath.y); + } + calcMovementFactor(foundPath); + } + } +} +*/ + +void Actor::walkActorOld() { + Common::Point p2, p3; // Gate locations + int new_dir, next_box; + + if (!_moving) + return; + + if (!(_moving & MF_NEW_LEG)) { + if (_moving & MF_IN_LEG && actorWalkStep()) + return; + + if (_moving & MF_LAST_LEG) { + _moving = 0; + startAnimActor(_standFrame); + if (_targetFacing != _walkdata.destdir) + turnToDirection(_walkdata.destdir); + return; + } + + if (_moving & MF_TURN) { + new_dir = updateActorDirection(false); + if (_facing != new_dir) + setDirection(new_dir); + else + _moving = 0; + return; + } + + if (_walkdata.point3.x != 32000) { + if (calcMovementFactor(_walkdata.point3)) { + _walkdata.point3.x = 32000; + return; + } + _walkdata.point3.x = 32000; + } + + setBox(_walkdata.curbox); + _moving &= MF_IN_LEG; + } + + _moving &= ~MF_NEW_LEG; + do { + if (_walkbox == kInvalidBox) { + setBox(_walkdata.destbox); + _walkdata.curbox = _walkdata.destbox; + break; + } + + if (_walkbox == _walkdata.destbox) + break; + + next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); + + // WORKAROUND: To fully fix bug #774783, we add a special case + // here, resulting in a different next_box value for Hitler. + if ((_vm->_game.id == GID_INDY3) && _vm->_roomResource == 46 && _walkbox == 1 && _walkdata.destbox == 0 && _number == 9) + next_box = 1; + + if (next_box < 0) { + _moving |= MF_LAST_LEG; + return; + } + + // Can't walk through locked boxes + int flags = _vm->getBoxFlags(next_box); + if (flags & kBoxLocked && !(flags & kBoxPlayerOnly && !isPlayer())) { + _moving |= MF_LAST_LEG; +// FIXME: Work in progress +// _walkdata.destdir = _facing; + return; + } + + _walkdata.curbox = next_box; + + if (_vm->_game.version <= 2) { + getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), _pos.x, _pos.y, p2.x, p2.y); + getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), p2.x, p2.y, p3.x, p3.y); +// FIXME: Work in progress +// calcMovementFactor(p3); +// return; + } else { + findPathTowardsOld(_walkbox, next_box, _walkdata.destbox, p2, p3); + if (p2.x == 32000 && p3.x == 32000) { + break; + } + + if (p2.x != 32000) { + if (calcMovementFactor(p2)) { + _walkdata.point3 = p3; + return; + } + } + } + if (calcMovementFactor(p3)) + return; + + setBox(_walkdata.destbox); + } while (1); + + _moving |= MF_LAST_LEG; + calcMovementFactor(_walkdata.dest); +} + + +#pragma mark - +#pragma mark --- Actor direction --- +#pragma mark - + + int Actor::remapDirection(int dir, bool is_walking) { int specdir; byte flags; @@ -370,198 +803,6 @@ int Actor::updateActorDirection(bool is_walking) { return dir; } -void Actor::setBox(int box) { - _walkbox = box; - setupActorScale(); -} - -int Actor::actorWalkStep() { - int tmpX, tmpY; - Common::Point _actorPos; - int distX, distY; - int nextFacing; - - _needRedraw = true; - - nextFacing = updateActorDirection(true); - if (!(_moving & MF_IN_LEG) || _facing != nextFacing) { - if (_walkFrame != _frame || _facing != nextFacing) { - startWalkAnim(1, nextFacing); - } - _moving |= MF_IN_LEG; - } - - _actorPos = _pos; - - if (_walkbox != _walkdata.curbox && _vm->checkXYInBoxBounds(_walkdata.curbox, _actorPos.x, _actorPos.y)) { - setBox(_walkdata.curbox); - } - - distX = ABS(_walkdata.next.x - _walkdata.cur.x); - distY = ABS(_walkdata.next.y - _walkdata.cur.y); - - if (ABS(_actorPos.x - _walkdata.cur.x) >= distX && ABS(_actorPos.y - _walkdata.cur.y) >= distY) { - _moving &= ~MF_IN_LEG; - return 0; - } - - tmpX = (_actorPos.x << 16) + _walkdata.xfrac + (_walkdata.deltaXFactor >> 8) * _scalex; - _walkdata.xfrac = (uint16)tmpX; - _actorPos.x = (tmpX >> 16); - - tmpY = (_actorPos.y << 16) + _walkdata.yfrac + (_walkdata.deltaYFactor >> 8) * _scaley; - _walkdata.yfrac = (uint16)tmpY; - _actorPos.y = (tmpY >> 16); - - if (ABS(_actorPos.x - _walkdata.cur.x) > distX) { - _actorPos.x = _walkdata.next.x; - } - - if (ABS(_actorPos.y - _walkdata.cur.y) > distY) { - _actorPos.y = _walkdata.next.y; - } - - _pos = _actorPos; - - if (_vm->_game.version >= 4 && _vm->_game.version <= 6 && _pos == _walkdata.next) { - _moving &= ~MF_IN_LEG; - return 0; - } - return 1; -} - - -void Actor::setupActorScale() { - - if (_vm->_game.features & GF_NO_SCALING) { - _scalex = 0xFF; - _scaley = 0xFF; - return; - } - - if (_ignoreBoxes) - return; - - // For some boxes, we ignore the scaling and use whatever values the - // scripts set. This is used e.g. in the Mystery Vortex in Sam&Max. - // Older games used the flag 0x20 differently, though. - if (_vm->_game.id == GID_SAMNMAX && (_vm->getBoxFlags(_walkbox) & kBoxIgnoreScale)) - return; - - _boxscale = _vm->getBoxScale(_walkbox); - - uint16 scale = _vm->getScale(_walkbox, _pos.x, _pos.y); - assert(scale <= 0xFF); - - _scalex = _scaley = (byte)scale; -} - -void Actor::startAnimActor(int f) { - if (_vm->_game.version >= 7 && !((_vm->_game.id == GID_FT) && (_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC))) { - switch (f) { - case 1001: - f = _initFrame; - break; - case 1002: - f = _walkFrame; - break; - case 1003: - f = _standFrame; - break; - case 1004: - f = _talkStartFrame; - break; - case 1005: - f = _talkStopFrame; - break; - } - - if (_costume != 0) { - _animProgress = 0; - _needRedraw = true; - if (f == _initFrame) - _cost.reset(); - _vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1); - _frame = f; - } - } else { - switch (f) { - case 0x38: - f = _initFrame; - break; - case 0x39: - f = _walkFrame; - break; - case 0x3A: - f = _standFrame; - break; - case 0x3B: - f = _talkStartFrame; - break; - case 0x3C: - f = _talkStopFrame; - break; - } - - assert(f != 0x3E); - - if (isInCurrentRoom() && _costume != 0) { - _animProgress = 0; - _cost.animCounter = 0; - _needRedraw = true; - // V1 - V2 games don't seem to need a _cost.reset() at this point. - // Causes Zak to lose his body in several scenes, see bug #771508 - if (_vm->_game.version >= 3 && f == _initFrame) { - _cost.reset(); - _auxBlock.reset(); - } - _vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1); - _frame = f; - } - } -} - -void Actor::animateActor(int anim) { - int cmd, dir; - - if (_vm->_game.version >= 7 && !((_vm->_game.id == GID_FT) && (_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC))) { - - if (anim == 0xFF) - anim = 2000; - - cmd = anim / 1000; - dir = anim % 1000; - - } else { - - cmd = anim / 4; - dir = oldDirToNewDir(anim % 4); - - // Convert into old cmd code - cmd = 0x3F - cmd + 2; - - } - - switch (cmd) { - case 2: // stop walking - startAnimActor(_standFrame); - stopActorMoving(); - break; - case 3: // change direction immediatly - _moving &= ~MF_TURN; - setDirection(dir); - break; - case 4: // turn to new direction - turnToDirection(dir); - break; - default: - if (_vm->_game.version <= 2) - startAnimActor(anim / 4); - else - startAnimActor(anim); - } -} - void Actor::setDirection(int direction) { uint aMask; int i; @@ -590,29 +831,52 @@ void Actor::setDirection(int direction) { _needRedraw = true; } -void Actor::drawActorToBackBuf(int x, int y) { - int curTop = _top; - int curBottom = _bottom; +void Actor::faceToObject(int obj) { + int x2, y2, dir; - _pos.x = x; - _pos.y = y; + if (!isInCurrentRoom()) + return; - _drawToBackBuf = true; - _needRedraw = true; - drawActorCostume(); + if (_vm->getObjectOrActorXY(obj, x2, y2) == -1) + return; - _drawToBackBuf = false; - _needRedraw = true; - drawActorCostume(); - _needRedraw = false; + dir = (x2 > _pos.x) ? 90 : 270; + turnToDirection(dir); +} - if (_top > curTop) - _top = curTop; - if (_bottom < curBottom) - _bottom = curBottom; +void Actor::turnToDirection(int newdir) { + if (newdir == -1 || _ignoreTurns) + return; + + if (_vm->_game.version <= 6) { + _moving = MF_TURN; + _targetFacing = newdir; + } else { + _moving &= ~MF_TURN; + if (newdir != _facing) { + _moving |= MF_TURN; + _targetFacing = newdir; + } + } } +#pragma mark - +#pragma mark --- Actor position --- +#pragma mark - + + +void ScummEngine::putActors() { + Actor *a; + int i; + + for (i = 1; i < _numActors; i++) { + a = &_actors[i]; + if (a && a->isInCurrentRoom()) + a->putActor(a->_pos.x, a->_pos.y, a->_room); + } +} + void Actor::putActor(int dstX, int dstY, byte newRoom) { if (_visible && _vm->_currentRoom != newRoom && _vm->getTalkingActor() == _number) { _vm->stopTalk(); @@ -766,34 +1030,47 @@ void Actor::adjustActorPos() { } } -void Actor::faceToObject(int obj) { - int x2, y2, dir; +int ScummEngine::getActorFromPos(int x, int y) { + int i; - if (!isInCurrentRoom()) - return; + if (!testGfxAnyUsageBits(x / 8)) + return 0; - if (_vm->getObjectOrActorXY(obj, x2, y2) == -1) - return; + for (i = 1; i < _numActors; i++) { + if (testGfxUsageBit(x / 8, i) && !getClass(i, kObjectClassUntouchable) + && y >= _actors[i]._top && y <= _actors[i]._bottom) { + if (_game.version > 2 || i != VAR(VAR_EGO)) + return i; + } + } - dir = (x2 > _pos.x) ? 90 : 270; - turnToDirection(dir); + return 0; } -void Actor::turnToDirection(int newdir) { - if (newdir == -1 || _ignoreTurns) - return; +#ifndef DISABLE_HE +int ScummEngine_v70he::getActorFromPos(int x, int y) { + int curActor, i; - if (_vm->_game.version <= 6) { - _moving = MF_TURN; - _targetFacing = newdir; - } else { - _moving &= ~MF_TURN; - if (newdir != _facing) { - _moving |= MF_TURN; - _targetFacing = newdir; - } + if (!testGfxAnyUsageBits(x / 8)) + return 0; + + curActor = 0; + for (i = 1; i < _numActors; i++) { + if (testGfxUsageBit(x / 8, i) && !getClass(i, kObjectClassUntouchable) + && y >= _actors[i]._top && y <= _actors[i]._bottom + && (_actors[i]._pos.y > _actors[curActor]._pos.y || curActor == 0)) + curActor = i; } + + return curActor; } +#endif + + +#pragma mark - +#pragma mark --- TODO --- +#pragma mark - + void Actor::hideActor() { if (!_visible) @@ -835,67 +1112,6 @@ void Actor::showActor() { _needRedraw = true; } -// V1 Maniac doesn't have a ScummVar for VAR_TALK_ACTOR, and just uses -// an internal variable. Emulate this to prevent overwriting script vars... -// Maniac NES (V1), however, DOES have a ScummVar for VAR_TALK_ACTOR -int ScummEngine::getTalkingActor() { - if (_game.id == GID_MANIAC && _game.version <= 1 && !(_game.platform == Common::kPlatformNES)) - return _V1TalkingActor; - else - return VAR(VAR_TALK_ACTOR); -} - -void ScummEngine::setTalkingActor(int value) { - - if (value == 255) { - _system->clearFocusRectangle(); - } else { - // Work out the screen co-ordinates of the actor - int x = _actors[value]._pos.x - (camera._cur.x - (_screenWidth >> 1)); - int y = _actors[value]._top - (camera._cur.y - (_screenHeight >> 1)); - - // Set the focus area to the calculated position - // TODO: Make the size adjust depending on what it's focusing on. - Common::Rect rect(x - 96, y - 64, x + 96, y + 64); - _system->setFocusRectangle(rect); - } - - if (_game.id == GID_MANIAC && _game.version <= 1 && !(_game.platform == Common::kPlatformNES)) - _V1TalkingActor = value; - else - VAR(VAR_TALK_ACTOR) = value; -} - -void ScummEngine::putActors() { - Actor *a; - int i; - - for (i = 1; i < _numActors; i++) { - a = &_actors[i]; - if (a && a->isInCurrentRoom()) - a->putActor(a->_pos.x, a->_pos.y, a->_room); - } -} - -static const int c64MMActorTalkColor[25] = { - 1, 7, 2, 14, 8, 15, 3, 7, 7, 15, 1, 13, 1, 4, 5, 5, 4, 3, 1, 5, 1, 1, 1, 1, 7 -}; -static const int v1MMActorTalkColor[25] = { - 1, 7, 2, 14, 8, 1, 3, 7, 7, 12, 1, 13, 1, 4, 5, 5, 4, 3, 1, 5, 1, 1, 1, 7, 7 -}; - -void ScummEngine::resetV1ActorTalkColor() { - int i; - - for (i = 1; i < _numActors; i++) { - if (_game.platform == Common::kPlatformC64) { - _actors[i]._talkColor = c64MMActorTalkColor[i]; - } else { - _actors[i]._talkColor = v1MMActorTalkColor[i]; - } - } -} - void ScummEngine::showActors() { int i; @@ -905,18 +1121,6 @@ void ScummEngine::showActors() { } } -void ScummEngine::walkActors() { - int i; - - for (i = 1; i < _numActors; i++) { - if (_actors[i].isInCurrentRoom()) - if (_game.version <= 3) - _actors[i].walkActorOld(); - else - _actors[i].walkActor(); - } -} - /* Used in Scumm v5 only. Play sounds associated with actors */ void ScummEngine::playActorSounds() { int i; @@ -964,6 +1168,12 @@ Actor *ScummEngine::derefActorSafe(int id, const char *errmsg) const { return &_actors[id]; } + +#pragma mark - +#pragma mark --- Actor drawing --- +#pragma mark - + + void ScummEngine::processActors() { int numactors = 0; @@ -1220,6 +1430,112 @@ bool Actor::actorHitTest(int x, int y) { } #endif +void Actor::startAnimActor(int f) { + if (_vm->_game.version >= 7 && !((_vm->_game.id == GID_FT) && (_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC))) { + switch (f) { + case 1001: + f = _initFrame; + break; + case 1002: + f = _walkFrame; + break; + case 1003: + f = _standFrame; + break; + case 1004: + f = _talkStartFrame; + break; + case 1005: + f = _talkStopFrame; + break; + } + + if (_costume != 0) { + _animProgress = 0; + _needRedraw = true; + if (f == _initFrame) + _cost.reset(); + _vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1); + _frame = f; + } + } else { + switch (f) { + case 0x38: + f = _initFrame; + break; + case 0x39: + f = _walkFrame; + break; + case 0x3A: + f = _standFrame; + break; + case 0x3B: + f = _talkStartFrame; + break; + case 0x3C: + f = _talkStopFrame; + break; + } + + assert(f != 0x3E); + + if (isInCurrentRoom() && _costume != 0) { + _animProgress = 0; + _cost.animCounter = 0; + _needRedraw = true; + // V1 - V2 games don't seem to need a _cost.reset() at this point. + // Causes Zak to lose his body in several scenes, see bug #771508 + if (_vm->_game.version >= 3 && f == _initFrame) { + _cost.reset(); + _auxBlock.reset(); + } + _vm->_costumeLoader->costumeDecodeData(this, f, (uint) - 1); + _frame = f; + } + } +} + +void Actor::animateActor(int anim) { + int cmd, dir; + + if (_vm->_game.version >= 7 && !((_vm->_game.id == GID_FT) && (_vm->_game.features & GF_DEMO) && (_vm->_game.platform == Common::kPlatformPC))) { + + if (anim == 0xFF) + anim = 2000; + + cmd = anim / 1000; + dir = anim % 1000; + + } else { + + cmd = anim / 4; + dir = oldDirToNewDir(anim % 4); + + // Convert into old cmd code + cmd = 0x3F - cmd + 2; + + } + + switch (cmd) { + case 2: // stop walking + startAnimActor(_standFrame); + stopActorMoving(); + break; + case 3: // change direction immediatly + _moving &= ~MF_TURN; + setDirection(dir); + break; + case 4: // turn to new direction + turnToDirection(dir); + break; + default: + if (_vm->_game.version <= 2) + startAnimActor(anim / 4); + else + startAnimActor(anim); + } +} + void Actor::animateCostume() { if (_costume == 0) return; @@ -1329,41 +1645,84 @@ void ScummEngine::resetActorBgs() { } } -int ScummEngine::getActorFromPos(int x, int y) { - int i; +// HE specific +void Actor::drawActorToBackBuf(int x, int y) { + int curTop = _top; + int curBottom = _bottom; - if (!testGfxAnyUsageBits(x / 8)) - return 0; + _pos.x = x; + _pos.y = y; - for (i = 1; i < _numActors; i++) { - if (testGfxUsageBit(x / 8, i) && !getClass(i, kObjectClassUntouchable) - && y >= _actors[i]._top && y <= _actors[i]._bottom) { - if (_game.version > 2 || i != VAR(VAR_EGO)) - return i; - } + _drawToBackBuf = true; + _needRedraw = true; + drawActorCostume(); + + _drawToBackBuf = false; + _needRedraw = true; + drawActorCostume(); + _needRedraw = false; + + if (_top > curTop) + _top = curTop; + if (_bottom < curBottom) + _bottom = curBottom; +} + + +#pragma mark - +#pragma mark --- Actor talking --- +#pragma mark - + + +// V1 Maniac doesn't have a ScummVar for VAR_TALK_ACTOR, and just uses +// an internal variable. Emulate this to prevent overwriting script vars... +// Maniac NES (V1), however, DOES have a ScummVar for VAR_TALK_ACTOR +int ScummEngine::getTalkingActor() { + if (_game.id == GID_MANIAC && _game.version <= 1 && !(_game.platform == Common::kPlatformNES)) + return _V1TalkingActor; + else + return VAR(VAR_TALK_ACTOR); +} + +void ScummEngine::setTalkingActor(int value) { + + if (value == 255) { + _system->clearFocusRectangle(); + } else { + // Work out the screen co-ordinates of the actor + int x = _actors[value]._pos.x - (camera._cur.x - (_screenWidth >> 1)); + int y = _actors[value]._top - (camera._cur.y - (_screenHeight >> 1)); + + // Set the focus area to the calculated position + // TODO: Make the size adjust depending on what it's focusing on. + Common::Rect rect(x - 96, y - 64, x + 96, y + 64); + _system->setFocusRectangle(rect); } - return 0; + if (_game.id == GID_MANIAC && _game.version <= 1 && !(_game.platform == Common::kPlatformNES)) + _V1TalkingActor = value; + else + VAR(VAR_TALK_ACTOR) = value; } -#ifndef DISABLE_HE -int ScummEngine_v70he::getActorFromPos(int x, int y) { - int curActor, i; +static const int c64MMActorTalkColor[25] = { + 1, 7, 2, 14, 8, 15, 3, 7, 7, 15, 1, 13, 1, 4, 5, 5, 4, 3, 1, 5, 1, 1, 1, 1, 7 +}; +static const int v1MMActorTalkColor[25] = { + 1, 7, 2, 14, 8, 1, 3, 7, 7, 12, 1, 13, 1, 4, 5, 5, 4, 3, 1, 5, 1, 1, 1, 7, 7 +}; - if (!testGfxAnyUsageBits(x / 8)) - return 0; +void ScummEngine::resetV1ActorTalkColor() { + int i; - curActor = 0; for (i = 1; i < _numActors; i++) { - if (testGfxUsageBit(x / 8, i) && !getClass(i, kObjectClassUntouchable) - && y >= _actors[i]._top && y <= _actors[i]._bottom - && (_actors[i]._pos.y > _actors[curActor]._pos.y || curActor == 0)) - curActor = i; + if (_game.platform == Common::kPlatformC64) { + _actors[i]._talkColor = c64MMActorTalkColor[i]; + } else { + _actors[i]._talkColor = v1MMActorTalkColor[i]; + } } - - return curActor; } -#endif #ifndef DISABLE_SCUMM_7_8 void ScummEngine_v7::actorTalk(const byte *msg) { @@ -1523,6 +1882,12 @@ void ScummEngine::stopTalk() { } } + +#pragma mark - +#pragma mark --- TODO --- +#pragma mark - + + void Actor::setActorCostume(int c) { int i; @@ -1600,330 +1965,6 @@ void Actor::setActorCostume(int c) { } } -void Actor::startWalkActor(int destX, int destY, int dir) { - AdjustBoxResult abr; - - if (!isInCurrentRoom() && _vm->_game.version >= 7) { - debugC(DEBUG_ACTORS, "startWalkActor: attempting to walk actor %d who is not in this room", _number); - return; - } - - if (_vm->_game.version <= 4) { - abr.x = destX; - abr.y = destY; - } else { - abr = adjustXYToBeInBox(destX, destY); - } - - if (!isInCurrentRoom() && _vm->_game.version <= 6) { - _pos.x = abr.x; - _pos.y = abr.y; - if (!_ignoreTurns && dir != -1) - _facing = dir; - return; - } - - if (_ignoreBoxes) { - abr.box = kInvalidBox; - _walkbox = kInvalidBox; - } else { - if (_vm->checkXYInBoxBounds(_walkdata.destbox, abr.x, abr.y)) { - abr.box = _walkdata.destbox; - } else { - abr = adjustXYToBeInBox(abr.x, abr.y); - } - if (_moving && _walkdata.destdir == dir && _walkdata.dest.x == abr.x && _walkdata.dest.y == abr.y) - return; - } - - if (_pos.x == abr.x && _pos.y == abr.y) { - if (dir != _facing) - turnToDirection(dir); - return; - } - - _walkdata.dest.x = abr.x; - _walkdata.dest.y = abr.y; - _walkdata.destbox = abr.box; - _walkdata.destdir = dir; - _moving = (_moving & MF_IN_LEG) | MF_NEW_LEG; - _walkdata.point3.x = 32000; - - _walkdata.curbox = _walkbox; -} - -void Actor::startWalkAnim(int cmd, int angle) { - if (angle == -1) - angle = _facing; - - /* Note: walk scripts aren't required to make the Dig - * work as usual - */ - if (_walkScript) { - int args[16]; - memset(args, 0, sizeof(args)); - args[0] = _number; - args[1] = cmd; - args[2] = angle; - _vm->runScript(_walkScript, 1, 0, args); - } else { - switch (cmd) { - case 1: /* start walk */ - setDirection(angle); - startAnimActor(_walkFrame); - break; - case 2: /* change dir only */ - setDirection(angle); - break; - case 3: /* stop walk */ - turnToDirection(angle); - startAnimActor(_standFrame); - break; - } - } -} - -void Actor::walkActor() { - int new_dir, next_box; - Common::Point foundPath; - - if (_vm->_game.version >= 7) { - if (_moving & MF_FROZEN) { - if (_moving & MF_TURN) { - new_dir = updateActorDirection(false); - if (_facing != new_dir) - setDirection(new_dir); - else - _moving &= ~MF_TURN; - } - return; - } - } - - if (!_moving) - return; - - if (!(_moving & MF_NEW_LEG)) { - if (_moving & MF_IN_LEG && actorWalkStep()) - return; - - if (_moving & MF_LAST_LEG) { - _moving = 0; - setBox(_walkdata.destbox); - if (_vm->_game.version <= 6) { - startAnimActor(_standFrame); - if (_targetFacing != _walkdata.destdir) - turnToDirection(_walkdata.destdir); - } else { - startWalkAnim(3, _walkdata.destdir); - } - return; - } - - if (_moving & MF_TURN) { - new_dir = updateActorDirection(false); - if (_facing != new_dir) - setDirection(new_dir); - else - _moving = 0; - return; - } - - setBox(_walkdata.curbox); - _moving &= MF_IN_LEG; - } - - _moving &= ~MF_NEW_LEG; - do { - - if (_walkbox == kInvalidBox) { - setBox(_walkdata.destbox); - _walkdata.curbox = _walkdata.destbox; - break; - } - - if (_walkbox == _walkdata.destbox) - break; - - next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); - if (next_box < 0) { - _walkdata.destbox = _walkbox; - _moving |= MF_LAST_LEG; - return; - } - - _walkdata.curbox = next_box; - - if (findPathTowards(_walkbox, next_box, _walkdata.destbox, foundPath)) - break; - - if (calcMovementFactor(foundPath)) - return; - - setBox(_walkdata.curbox); - } while (1); - - _moving |= MF_LAST_LEG; - calcMovementFactor(_walkdata.dest); -} - -/* -void Actor::walkActorV12() { - Common::Point foundPath, tmp; - int new_dir, next_box; - - if (_moving & MF_TURN) { - new_dir = updateActorDirection(false); - if (_facing != new_dir) - setDirection(new_dir); - else - _moving = 0; - return; - } - - if (!_moving) - return; - - if (_moving & MF_IN_LEG) { - actorWalkStep(); - } else { - if (_moving & MF_LAST_LEG) { - _moving = 0; - startAnimActor(_standFrame); - if (_targetFacing != _walkdata.destdir) - turnToDirection(_walkdata.destdir); - } else { - setBox(_walkdata.curbox); - if (_walkbox == _walkdata.destbox) { - foundPath = _walkdata.dest; - _moving |= MF_LAST_LEG; - } else { - next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); - if (next_box < 0) { - _moving |= MF_LAST_LEG; - return; - } - - // Can't walk through locked boxes - int flags = _vm->getBoxFlags(next_box); - if (flags & kBoxLocked && !(flags & kBoxPlayerOnly && !isPlayer())) { - _moving |= MF_LAST_LEG; - } - - _walkdata.curbox = next_box; - - getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), x, y, tmp.x, tmp.y); - getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), tmp.x, tmp.y, foundPath.x, foundPath.y); - } - calcMovementFactor(foundPath); - } - } -} -*/ - -void Actor::walkActorOld() { - Common::Point p2, p3; // Gate locations - int new_dir, next_box; - - if (!_moving) - return; - - if (!(_moving & MF_NEW_LEG)) { - if (_moving & MF_IN_LEG && actorWalkStep()) - return; - - if (_moving & MF_LAST_LEG) { - _moving = 0; - startAnimActor(_standFrame); - if (_targetFacing != _walkdata.destdir) - turnToDirection(_walkdata.destdir); - return; - } - - if (_moving & MF_TURN) { - new_dir = updateActorDirection(false); - if (_facing != new_dir) - setDirection(new_dir); - else - _moving = 0; - return; - } - - if (_walkdata.point3.x != 32000) { - if (calcMovementFactor(_walkdata.point3)) { - _walkdata.point3.x = 32000; - return; - } - _walkdata.point3.x = 32000; - } - - setBox(_walkdata.curbox); - _moving &= MF_IN_LEG; - } - - _moving &= ~MF_NEW_LEG; - do { - if (_walkbox == kInvalidBox) { - setBox(_walkdata.destbox); - _walkdata.curbox = _walkdata.destbox; - break; - } - - if (_walkbox == _walkdata.destbox) - break; - - next_box = _vm->getPathToDestBox(_walkbox, _walkdata.destbox); - - // WORKAROUND: To fully fix bug #774783, we add a special case - // here, resulting in a different next_box value for Hitler. - if ((_vm->_game.id == GID_INDY3) && _vm->_roomResource == 46 && _walkbox == 1 && _walkdata.destbox == 0 && _number == 9) - next_box = 1; - - if (next_box < 0) { - _moving |= MF_LAST_LEG; - return; - } - - // Can't walk through locked boxes - int flags = _vm->getBoxFlags(next_box); - if (flags & kBoxLocked && !(flags & kBoxPlayerOnly && !isPlayer())) { - _moving |= MF_LAST_LEG; -// FIXME: Work in progress -// _walkdata.destdir = _facing; - return; - } - - _walkdata.curbox = next_box; - - if (_vm->_game.version <= 2) { - getClosestPtOnBox(_vm->getBoxCoordinates(_walkdata.curbox), _pos.x, _pos.y, p2.x, p2.y); - getClosestPtOnBox(_vm->getBoxCoordinates(_walkbox), p2.x, p2.y, p3.x, p3.y); -// FIXME: Work in progress -// calcMovementFactor(p3); -// return; - } else { - findPathTowardsOld(_walkbox, next_box, _walkdata.destbox, p2, p3); - if (p2.x == 32000 && p3.x == 32000) { - break; - } - - if (p2.x != 32000) { - if (calcMovementFactor(p2)) { - _walkdata.point3 = p3; - return; - } - } - } - if (calcMovementFactor(p3)) - return; - - setBox(_walkdata.destbox); - } while (1); - - _moving |= MF_LAST_LEG; - calcMovementFactor(_walkdata.dest); -} - byte *Actor::getActorName() { byte *ptr = _vm->getResourceAddress(rtActorName, _number); if (ptr == NULL) { |