void Actor::update(uint frameTime) { // Snap actor to walkboxes if following them. This might be // necessary for example after activating/deactivating // walkboxes, etc. if (_constrain && !_walking) { g_grim->getCurrSet()->findClosestSector(_pos, NULL, &_pos); } if (_turning) { float turnAmt = g_grim->getPerSecond(_turnRate) * 5.f; Math::Angle dyaw = _moveYaw - _yaw; dyaw.normalize(-180); // If the actor won't turn because the rate is set to zero then // have the actor turn all the way to the destination yaw. // Without this some actors will lock the interface on changing // scenes, this affects the Bone Wagon in particular. if (turnAmt == 0 || turnAmt >= fabsf(dyaw.getDegrees())) { setYaw(_moveYaw); _turning = false; } else if (dyaw > 0) { setYaw(_yaw + turnAmt); } else { setYaw(_yaw - turnAmt); } _currTurnDir = (dyaw > 0 ? 1 : -1); } if (_walking) { updateWalk(); } if (_walkChore.isValid()) { if (_walkedCur) { if (!_walkChore.isPlaying()) { _walkChore.playLooping(true); } if (_restChore.isPlaying()) { _restChore.stop(true); } } else { if (_walkedLast && _walkChore.isPlaying()) { _walkChore.stop(true); if (!_restChore.isPlaying()) { _restChore.playLooping(true); } } } } if (_leftTurnChore.isValid()) { if (_walkedCur || _walkedLast) _currTurnDir = 0; if (_restChore.isValid()) { if (_currTurnDir != 0) { if (getTurnChore(_currTurnDir)->isPlaying() && _restChore.isPlaying()) { _restChore.stop(true, 500); } } else if (_lastTurnDir != 0) { if (!_walkedCur && getTurnChore(_lastTurnDir)->isPlaying()) { _restChore.playLooping(true); } } } if (_lastTurnDir != 0 && _lastTurnDir != _currTurnDir) { getTurnChore(_lastTurnDir)->stop(true); } if (_currTurnDir != 0 && _currTurnDir != _lastTurnDir) { getTurnChore(_currTurnDir)->playLooping(true, 500); } } else { _currTurnDir = 0; } // The rest chore might have been stopped because of a // StopActorChore(nil). Restart it if so. if (!_walkedCur && _currTurnDir == 0 && !_restChore.isPlaying()) { _restChore.playLooping(true); } _walkedLast = _walkedCur; _walkedCur = false; _lastTurnDir = _currTurnDir; _currTurnDir = 0; // Update lip syncing if (_lipSync) { int posSound; // While getPosIn60HzTicks will return "-1" to indicate that the // sound is no longer playing, it is more appropriate to check first if (g_grim->getSpeechMode() != GrimEngine::TextOnly && g_sound->getSoundStatus(_talkSoundName.c_str())) posSound = g_sound->getPosIn60HzTicks(_talkSoundName.c_str()); else posSound = -1; if (posSound != -1) { int anim = _lipSync->getAnim(posSound); if (_talkAnim != anim) { if (anim != -1) { if (_talkChore[anim].isValid()) { stopMumbleChore(); if (_talkAnim != -1) { _talkChore[_talkAnim].stop(); } // Run the stop_talk chore so that it resets the components // to the right visibility. stopTalking(); _talkAnim = anim; _talkChore[_talkAnim].play(); } else if (_mumbleChore.isValid() && !_mumbleChore.isPlaying()) { _mumbleChore.playLooping(); _talkAnim = -1; } } else { stopMumbleChore(); if (_talkAnim != -1) _talkChore[_talkAnim].stop(); _talkAnim = 0; stopTalking(); } } } } frameTime = (uint)(frameTime * _timeScale); for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) { Costume *c = *i; c->setPosRotate(_pos, _pitch, _yaw, _roll); int marker = c->update(frameTime); if (marker > 0) { costumeMarkerCallback(marker); } } for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) { Costume *c = *i; c->animate(); } for (Common::List<Costume *>::iterator i = _costumeStack.begin(); i != _costumeStack.end(); ++i) { Costume *c = *i; c->moveHead(_lookingMode, _lookAtVector); } }