aboutsummaryrefslogtreecommitdiff
path: root/engines/scumm/actor.cpp
diff options
context:
space:
mode:
authorMax Horn2006-10-18 14:01:28 +0000
committerMax Horn2006-10-18 14:01:28 +0000
commit92adf6a65c9432a2e177b8f7bcbcf235110345b8 (patch)
tree6e283c61cd80f4bcaf6bc80a868d227268091c66 /engines/scumm/actor.cpp
parentf51e01a0aa1fa89e381044f04dd7b1e3483b35f5 (diff)
downloadscummvm-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.cpp1345
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) {