aboutsummaryrefslogtreecommitdiff
path: root/engines/draci
diff options
context:
space:
mode:
authorRobert Špalek2009-11-02 02:28:43 +0000
committerRobert Špalek2009-11-02 02:28:43 +0000
commitc45f0343f4c386263025f1c39536ec9c6a2e566e (patch)
treee79aa7095d494462b46188509dd0118b94f75444 /engines/draci
parent9f711bd0ced5368a0dd5a28be7db5d7128849c01 (diff)
downloadscummvm-rg350-c45f0343f4c386263025f1c39536ec9c6a2e566e.tar.gz
scummvm-rg350-c45f0343f4c386263025f1c39536ec9c6a2e566e.tar.bz2
scummvm-rg350-c45f0343f4c386263025f1c39536ec9c6a2e566e.zip
Refactored running loop().
- shouldExitLoop() is a bool again and introduced new flag isReloaded() instead of adding special hacky value 2 - loop() accepts 2 parameters: loop substatus and shouldExit flag, because each caller previously had to set and restore these manually. loop() now also tests whether the substatuses are properly nested. reordered the loop-exitting code. - renamed loop substatuses to logical names - enterNewRoom() returns bool whether loop() should continue so that start() doesn't have to test and clear shouldEndProgram(). it doesn't need force_reload as a parameter anymore. - dialog selections use new inner substatus instead of outer substatus, for consistency svn-id: r45607
Diffstat (limited to 'engines/draci')
-rw-r--r--engines/draci/draci.cpp10
-rw-r--r--engines/draci/game.cpp103
-rw-r--r--engines/draci/game.h23
-rw-r--r--engines/draci/saveload.cpp2
-rw-r--r--engines/draci/script.cpp46
5 files changed, 89 insertions, 95 deletions
diff --git a/engines/draci/draci.cpp b/engines/draci/draci.cpp
index a491ee6fe6..2831ff605a 100644
--- a/engines/draci/draci.cpp
+++ b/engines/draci/draci.cpp
@@ -232,7 +232,7 @@ void DraciEngine::handleEvents() {
break;
case Common::KEYCODE_ESCAPE: {
if (_game->getLoopStatus() == kStatusInventory &&
- _game->getLoopSubstatus() == kSubstatusOrdinary) {
+ _game->getLoopSubstatus() == kOuterLoop) {
_game->inventoryDone();
break;
}
@@ -246,6 +246,8 @@ void DraciEngine::handleEvents() {
// Schedule room change
// TODO: gate 0 is not always the best one for returning from the map
_game->scheduleEnteringRoomUsingGate(escRoom, 0);
+
+ // Immediately cancel any running animation or dubbing.
_game->setExitLoop(true);
// End any currently running GPL programs
@@ -278,7 +280,7 @@ void DraciEngine::handleEvents() {
break;
case Common::KEYCODE_i:
if (_game->getRoomNum() == _game->getMapRoom() ||
- _game->getLoopSubstatus() != kSubstatusOrdinary) {
+ _game->getLoopSubstatus() != kOuterLoop) {
break;
}
if (_game->getLoopStatus() == kStatusInventory) {
@@ -403,7 +405,7 @@ Common::Error DraciEngine::loadGameState(int slot) {
bool DraciEngine::canLoadGameStateCurrently() {
return (_game->getLoopStatus() == kStatusOrdinary) &&
- (_game->getLoopSubstatus() == kSubstatusOrdinary);
+ (_game->getLoopSubstatus() == kOuterLoop);
}
Common::Error DraciEngine::saveGameState(int slot, const char *desc) {
@@ -412,7 +414,7 @@ Common::Error DraciEngine::saveGameState(int slot, const char *desc) {
bool DraciEngine::canSaveGameStateCurrently() {
return (_game->getLoopStatus() == kStatusOrdinary) &&
- (_game->getLoopSubstatus() == kSubstatusOrdinary);
+ (_game->getLoopSubstatus() == kOuterLoop);
}
} // End of namespace Draci
diff --git a/engines/draci/game.cpp b/engines/draci/game.cpp
index 67b7b04ef6..64c959af57 100644
--- a/engines/draci/game.cpp
+++ b/engines/draci/game.cpp
@@ -149,36 +149,24 @@ Game::Game(DraciEngine *vm) : _vm(vm) {
void Game::start() {
while (!shouldQuit()) {
- debugC(1, kDraciGeneralDebugLevel, "Game::start()");
-
- // Whenever the top-level loop is entered, it should not finish unless
- // the exit is triggered by a script
- const bool force_reload = shouldExitLoop() > 1;
- setExitLoop(false);
- _vm->_script->endCurrentProgram(false);
-
- enterNewRoom(force_reload);
-
- if (_vm->_script->shouldEndProgram()) {
- // Room changed during the initialization (intro or Escape pressed).
- continue;
+ if (enterNewRoom()) {
+ // Call the outer loop doing all the hard job.
+ loop(kOuterLoop, false);
}
-
- // Call the outer loop doing all the hard job.
- loop();
}
}
void Game::init() {
setQuit(false);
setExitLoop(false);
+ setIsReloaded(false);
_scheduledPalette = 0;
_fadePhases = _fadePhase = 0;
setEnableQuickHero(true);
setWantQuickHero(false);
setEnableSpeedText(true);
setLoopStatus(kStatusGate);
- setLoopSubstatus(kSubstatusOrdinary);
+ setLoopSubstatus(kOuterLoop);
_animUnderCursor = kOverlayImage;
@@ -240,22 +228,32 @@ void Game::init() {
_pushedNewRoom = _pushedNewGate = -1;
}
-void Game::loop() {
+void Game::loop(LoopSubstatus substatus, bool shouldExit) {
+ assert(getLoopSubstatus() == kOuterLoop);
+ setLoopSubstatus(substatus);
+ setExitLoop(shouldExit);
+
// Can run both as an outer and inner loop. In both mode it updates
- // the screen according to the timer. It the outer mode
- // (kSubstatusOrdinary) it also reacts to user events. In the inner
- // mode (all other kSubstatus* enums), the loop runs until its stopping
- // condition, possibly stopping earlier if the user interrupts it,
- // however no other user intervention is allowed.
+ // the screen according to the timer. It the outer mode (kOuterLoop)
+ // it also reacts to user events. In the inner mode (all kInner*
+ // enums), the loop runs until its stopping condition, possibly
+ // stopping earlier if the user interrupts it, however no other user
+ // intervention is allowed.
Surface *surface = _vm->_screen->getSurface();
+ // Always enter the first pass of the loop, even if shouldExitLoop() is
+ // true, exactly to ensure to make at least one pass.
do {
debugC(4, kDraciLogicDebugLevel, "loopstatus: %d, loopsubstatus: %d",
_loopStatus, _loopSubstatus);
_vm->handleEvents();
- if (shouldExitLoop() > 1) // after loading
+ if (isReloaded()) {
+ // Cannot continue with the same animation objects,
+ // because the real data structures of the game have
+ // completely been changed.
break;
+ }
if (_fadePhase > 0 && (_vm->_system->getMillis() - _fadeTick) >= kFadingTimeUnit) {
_fadeTick = _vm->_system->getMillis();
@@ -263,7 +261,7 @@ void Game::loop() {
const byte *startPal = _currentRoom._palette >= 0 ? _vm->_paletteArchive->getFile(_currentRoom._palette)->_data : NULL;
const byte *endPal = getScheduledPalette() >= 0 ? _vm->_paletteArchive->getFile(getScheduledPalette())->_data : NULL;
_vm->_screen->interpolatePalettes(startPal, endPal, 0, kNumColours, _fadePhases - _fadePhase, _fadePhases);
- if (_loopSubstatus == kSubstatusFade && _fadePhase == 0) {
+ if (_loopSubstatus == kInnerWhileFade && _fadePhase == 0) {
setExitLoop(true);
// Rewrite the palette index of the current
// room. This is necessary when two fadings
@@ -277,7 +275,7 @@ void Game::loop() {
int x = _vm->_mouse->getPosX();
int y = _vm->_mouse->getPosY();
- if (_loopStatus == kStatusDialogue && _loopSubstatus == kSubstatusOrdinary) {
+ if (_loopStatus == kStatusDialogue && _loopSubstatus == kInnerDuringDialogue) {
Text *text;
for (int i = 0; i < kDialogueLines; ++i) {
text = reinterpret_cast<Text *>(_dialogueAnims[i]->getCurrentFrame());
@@ -306,7 +304,7 @@ void Game::loop() {
// During the normal game-play, in particular not when
// running the init-scripts, enable interactivity.
- if (_loopStatus == kStatusOrdinary && _loopSubstatus == kSubstatusOrdinary) {
+ if (_loopStatus == kStatusOrdinary && _loopSubstatus == kOuterLoop) {
if (_vm->_mouse->lButtonPressed()) {
_vm->_mouse->lButtonSet(false);
@@ -380,7 +378,7 @@ void Game::loop() {
}
}
- if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) {
+ if (_loopStatus == kStatusInventory && _loopSubstatus == kOuterLoop) {
if (_inventoryExit) {
inventoryDone();
}
@@ -455,7 +453,7 @@ void Game::loop() {
debugC(5, kDraciLogicDebugLevel, "Anim under cursor: %d", _animUnderCursor);
// Handle character talking (if there is any)
- if (_loopSubstatus == kSubstatusTalk) {
+ if (_loopSubstatus == kInnerWhileTalk) {
// If the current speech text has expired or the user clicked a mouse button,
// advance to the next line of text
if ((getEnableSpeedText() && (_vm->_mouse->lButtonPressed() || _vm->_mouse->rButtonPressed())) ||
@@ -467,20 +465,27 @@ void Game::loop() {
_vm->_mouse->rButtonSet(false);
}
+ // A script has scheduled changing the room (either triggered
+ // by the user clicking on something or run at the end of a
+ // gate script in the intro).
+ if ((_loopStatus == kStatusOrdinary || _loopStatus == kStatusGate) && _newRoom != getRoomNum()) {
+ setExitLoop(true);
+ }
+
// This returns true if we got a signal to quit the game
- if (shouldQuit())
- return;
+ if (shouldQuit()) {
+ setExitLoop(true);
+ }
// Advance animations and redraw screen
_vm->_anims->drawScene(surface);
_vm->_screen->copyToScreen();
_vm->_system->delayMillis(20);
- // HACK: Won't be needed once the game loop is implemented properly
- setExitLoop(shouldExitLoop() || (_newRoom != getRoomNum() &&
- (_loopStatus == kStatusOrdinary || _loopStatus == kStatusGate)));
-
} while (!shouldExitLoop());
+
+ setLoopSubstatus(kOuterLoop);
+ setExitLoop(false);
}
void Game::updateCursor() {
@@ -502,7 +507,7 @@ void Game::updateCursor() {
// If we are in inventory mode, we do a different kind of updating that handles
// inventory items and return early
- if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) {
+ if (_loopStatus == kStatusInventory && _loopSubstatus == kOuterLoop) {
if (_itemUnderCursor != kNoItem) {
const GameItem *item = &_items[_itemUnderCursor];
@@ -708,7 +713,7 @@ void Game::putItem(int itemID, int position) {
// If we are in inventory mode, we need to play the item animation, immediately
// upon returning it to its slot but *not* in other modes because it should be
// invisible then (along with the inventory)
- if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) {
+ if (_loopStatus == kStatusInventory && _loopSubstatus == kOuterLoop) {
_vm->_anims->play(anim_id);
}
}
@@ -850,8 +855,7 @@ int Game::dialogueDraw() {
// Call the game loop to enable interactivity until the user
// selects his choice.
_vm->_mouse->cursorOn();
- setExitLoop(false);
- loop();
+ loop(kInnerDuringDialogue, false);
_vm->_mouse->cursorOff();
bool notDialogueAnim = true;
@@ -1302,9 +1306,10 @@ int Game::playingObjectAnimation(const GameObject *obj) const {
return -1;
}
-void Game::enterNewRoom(bool force_reload) {
- if (_newRoom == getRoomNum() && !force_reload) {
- return;
+bool Game::enterNewRoom() {
+ if (_newRoom == getRoomNum() && !isReloaded()) {
+ // If the game has been reloaded, force reloading all animations.
+ return true;
}
debugC(1, kDraciLogicDebugLevel, "Entering room %d using gate %d", _newRoom, _newGate);
@@ -1357,7 +1362,9 @@ void Game::enterNewRoom(bool force_reload) {
// Set the appropriate loop statu before loading the room
setLoopStatus(kStatusGate);
- setLoopSubstatus(kSubstatusOrdinary);
+ // Reset the flag allowing to run the scripts. It may have been turned
+ // on by pressing Escape in the intro or in the map room.
+ _vm->_script->endCurrentProgram(false);
loadRoom(_newRoom);
loadOverlays();
@@ -1379,6 +1386,16 @@ void Game::enterNewRoom(bool force_reload) {
setLoopStatus(kStatusOrdinary);
_vm->_mouse->setCursorType(kNormalCursor);
+
+ setIsReloaded(false);
+ if (_vm->_script->shouldEndProgram()) {
+ // Escape pressed during the intro or map animations run in the
+ // init scripts. This flag was turned on to skip the rest of
+ // those programs. Return false to make start() rerun us from
+ // the beginning, because the room number has changed.
+ return false;
+ }
+ return true;
}
void Game::runGateProgram(int gate) {
diff --git a/engines/draci/game.h b/engines/draci/game.h
index 3cd55a77ea..168da220f6 100644
--- a/engines/draci/game.h
+++ b/engines/draci/game.h
@@ -166,10 +166,11 @@ enum LoopStatus {
};
enum LoopSubstatus {
- kSubstatusOrdinary, // outer loop: everything is allowed
- kSubstatusTalk, // playing a voice: inner loop will exit afterwards
- kSubstatusFade, // fading a palette: inner loop will exit when done
- kSubstatusStrange // other inner loop: either immediately exiting or waiting for an animation to end (whose callback ends the loop)
+ kOuterLoop, // outer loop: everything is allowed
+ kInnerWhileTalk, // playing a voice: inner loop will exit afterwards
+ kInnerWhileFade, // fading a palette: inner loop will exit when done
+ kInnerDuringDialogue, // selecting continuation block: inner block will exit afterwards
+ kInnerUntilExit // other inner loop: either immediately exiting or waiting for an animation to end (whose callback ends the loop)
};
class Game {
@@ -179,7 +180,7 @@ public:
void init();
void start();
- void loop();
+ void loop(LoopSubstatus substatus, bool shouldExit);
// HACK: this is only for testing
int nextRoomNum() const {
@@ -271,9 +272,10 @@ public:
bool shouldQuit() const { return _shouldQuit; }
void setQuit(bool quit) { _shouldQuit = quit; }
-
- int shouldExitLoop() const { return _shouldExitLoop; }
- void setExitLoop(int exit) { _shouldExitLoop = exit; }
+ bool shouldExitLoop() const { return _shouldExitLoop; }
+ void setExitLoop(bool exit) { _shouldExitLoop = exit; }
+ bool isReloaded() const { return _isReloaded; }
+ void setIsReloaded(bool value) { _isReloaded = value; }
void setSpeechTiming(uint tick, uint duration);
void shiftSpeechAndFadeTick(int delta);
@@ -318,7 +320,7 @@ public:
void DoSync(Common::Serializer &s);
private:
- void enterNewRoom(bool force_reload);
+ bool enterNewRoom(); // Returns false if another room change has been triggered and therefore loop() shouldn't be called yet.
void loadRoom(int roomNum);
void runGateProgram(int gate);
void redrawWalkingPath(int id, byte colour, const WalkingMap::Path &path);
@@ -367,7 +369,8 @@ private:
LoopSubstatus _loopSubstatus;
bool _shouldQuit;
- int _shouldExitLoop; // 0=false and 1=true are normal, 2=immediate exit after loading
+ bool _shouldExitLoop;
+ bool _isReloaded;
uint _speechTick;
uint _speechDuration;
diff --git a/engines/draci/saveload.cpp b/engines/draci/saveload.cpp
index 56f22ea420..318d1fcad1 100644
--- a/engines/draci/saveload.cpp
+++ b/engines/draci/saveload.cpp
@@ -152,7 +152,7 @@ Common::Error loadSavegameData(int saveGameIdx, DraciEngine *vm) {
// Post-processing
vm->_game->scheduleEnteringRoomUsingGate(vm->_game->getRoomNum(), 0);
vm->_game->setRoomNum(vm->_game->getPreviousRoomNum());
- vm->_game->setExitLoop(2); // 2 > true means immediate exit for the loop
+ vm->_game->setIsReloaded(true);
vm->_game->inventoryReload();
diff --git a/engines/draci/script.cpp b/engines/draci/script.cpp
index f938737728..6a2eaeddd4 100644
--- a/engines/draci/script.cpp
+++ b/engines/draci/script.cpp
@@ -359,11 +359,7 @@ void Script::play(Common::Queue<int> &params) {
// Runs just one phase of the loop and exits. Used when waiting for a
// particular animation phase to come.
- _vm->_game->setLoopSubstatus(kSubstatusStrange);
- _vm->_game->setExitLoop(true);
- _vm->_game->loop();
- _vm->_game->setExitLoop(false);
- _vm->_game->setLoopSubstatus(kSubstatusOrdinary);
+ _vm->_game->loop(kInnerUntilExit, true);
}
Animation *Script::loadObjectAnimation(GameObject *obj, int animID) {
@@ -463,19 +459,14 @@ void Script::startPlay(Common::Queue<int> &params) {
anim->registerCallback(&Animation::exitGameLoop);
- _vm->_game->setLoopSubstatus(kSubstatusStrange);
-
bool visible = (obj->_location == _vm->_game->getRoomNum() && obj->_visible);
-
if (objID == kDragonObject || visible) {
_vm->_anims->play(animID);
}
// Runs an inner loop until the animation ends.
- _vm->_game->loop();
- _vm->_game->setExitLoop(false);
+ _vm->_game->loop(kInnerUntilExit, false);
_vm->_anims->stop(animID);
- _vm->_game->setLoopSubstatus(kSubstatusOrdinary);
anim->registerCallback(&Animation::doNothing);
}
@@ -677,17 +668,12 @@ void Script::walkOnPlay(Common::Queue<int> &params) {
int y = params.pop();
SightDirection dir = static_cast<SightDirection> (params.pop());
- // HACK: This should be an onDest action when hero walking is properly implemented
- // For now, we just go throught the loop-body once to redraw the screen.
- _vm->_game->setExitLoop(true);
-
_vm->_game->walkHero(x, y, dir);
- _vm->_game->setLoopSubstatus(kSubstatusStrange);
- _vm->_game->loop();
- _vm->_game->setLoopSubstatus(kSubstatusOrdinary);
-
- _vm->_game->setExitLoop(false);
+ // HACK: This (shouldExit==true) should be an onDest action when hero
+ // walking is properly implemented For now, we just go throught the
+ // loop-body once to redraw the screen.
+ _vm->_game->loop(kInnerUntilExit, true);
}
void Script::newRoom(Common::Queue<int> &params) {
@@ -737,9 +723,6 @@ void Script::talk(Common::Queue<int> &params) {
speechFrame->setFont(_vm->_smallFont);
}
- // Set the loop substatus to an appropriate value
- _vm->_game->setLoopSubstatus(kSubstatusTalk);
-
// Speak the dubbing if possible
uint dubbingDuration = 0;
if (sample) {
@@ -776,12 +759,8 @@ void Script::talk(Common::Queue<int> &params) {
speechFrame->setX(x);
speechFrame->setY(y);
- // Prevent the loop from exiting early if other things left the loop in the
- // "exit immediately" state
- _vm->_game->setExitLoop(false);
-
// Call the game loop to enable interactivity until the text expires.
- _vm->_game->loop();
+ _vm->_game->loop(kInnerWhileTalk, false);
// Delete the text
_vm->_screen->getSurface()->markDirtyRect(speechFrame->getRect(kNoDisplacement));
@@ -793,10 +772,6 @@ void Script::talk(Common::Queue<int> &params) {
_vm->_sound->stopVoice();
sample->close();
}
-
- // Revert to "normal" loop status
- _vm->_game->setLoopSubstatus(kSubstatusOrdinary);
- _vm->_game->setExitLoop(false);
}
void Script::dialogue(Common::Queue<int> &params) {
@@ -877,7 +852,7 @@ void Script::fadePalette(Common::Queue<int> &params) {
int phases = params.pop();
// Let the palette fade in the background while the game continues.
- // Since we don't set substatus to kSubstatusFade, the outer loop will
+ // Since we don't set substatus to kInnerWhileFade, the outer loop will
// just continue rather than exit.
_vm->_game->initializeFading(phases);
}
@@ -889,10 +864,7 @@ void Script::fadePalettePlay(Common::Queue<int> &params) {
_vm->_game->initializeFading(phases);
// Call the game loop to enable interactivity until the fading is done.
- _vm->_game->setLoopSubstatus(kSubstatusFade);
- _vm->_game->loop();
- _vm->_game->setExitLoop(false);
- _vm->_game->setLoopSubstatus(kSubstatusOrdinary);
+ _vm->_game->loop(kInnerWhileFade, false);
}
void Script::setPalette(Common::Queue<int> &params) {