[Scummvm-cvs-logs] SF.net SVN: scummvm:[45607] scummvm/trunk/engines/draci

spalek at users.sourceforge.net spalek at users.sourceforge.net
Mon Nov 2 03:28:44 CET 2009


Revision: 45607
          http://scummvm.svn.sourceforge.net/scummvm/?rev=45607&view=rev
Author:   spalek
Date:     2009-11-02 02:28:43 +0000 (Mon, 02 Nov 2009)

Log Message:
-----------
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

Modified Paths:
--------------
    scummvm/trunk/engines/draci/draci.cpp
    scummvm/trunk/engines/draci/game.cpp
    scummvm/trunk/engines/draci/game.h
    scummvm/trunk/engines/draci/saveload.cpp
    scummvm/trunk/engines/draci/script.cpp

Modified: scummvm/trunk/engines/draci/draci.cpp
===================================================================
--- scummvm/trunk/engines/draci/draci.cpp	2009-11-01 23:20:46 UTC (rev 45606)
+++ scummvm/trunk/engines/draci/draci.cpp	2009-11-02 02:28:43 UTC (rev 45607)
@@ -232,7 +232,7 @@
 				break;
 			case Common::KEYCODE_ESCAPE: {
 				if (_game->getLoopStatus() == kStatusInventory &&
-				   _game->getLoopSubstatus() == kSubstatusOrdinary) {
+				   _game->getLoopSubstatus() == kOuterLoop) {
 					_game->inventoryDone();
 					break;
 				}
@@ -246,6 +246,8 @@
 					// 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 @@
 				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 @@
 
 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 @@
 
 bool DraciEngine::canSaveGameStateCurrently() {
 	return (_game->getLoopStatus() == kStatusOrdinary) &&
-		(_game->getLoopSubstatus() == kSubstatusOrdinary);
+		(_game->getLoopSubstatus() == kOuterLoop);
 }
 
 } // End of namespace Draci

Modified: scummvm/trunk/engines/draci/game.cpp
===================================================================
--- scummvm/trunk/engines/draci/game.cpp	2009-11-01 23:20:46 UTC (rev 45606)
+++ scummvm/trunk/engines/draci/game.cpp	2009-11-02 02:28:43 UTC (rev 45607)
@@ -149,36 +149,24 @@
 
 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 @@
 	_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 @@
 			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 @@
 		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 @@
 
 			// 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 @@
 				}
 			}
 
-			if (_loopStatus == kStatusInventory && _loopSubstatus == kSubstatusOrdinary) {
+			if (_loopStatus == kStatusInventory && _loopSubstatus == kOuterLoop) {
 				if (_inventoryExit) {
 					inventoryDone();
 				}
@@ -455,7 +453,7 @@
 		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 @@
 			_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());
 
-	} while (!shouldExitLoop());
+	setLoopSubstatus(kOuterLoop);
+	setExitLoop(false);
 }
 
 void Game::updateCursor() {
@@ -502,7 +507,7 @@
 
 	// 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 @@
 	// 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 @@
 		// 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 @@
 	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 @@
 
 	// 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 @@
 	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) {

Modified: scummvm/trunk/engines/draci/game.h
===================================================================
--- scummvm/trunk/engines/draci/game.h	2009-11-01 23:20:46 UTC (rev 45606)
+++ scummvm/trunk/engines/draci/game.h	2009-11-02 02:28:43 UTC (rev 45607)
@@ -166,10 +166,11 @@
 };
 
 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 @@
 
 	void init();
 	void start();
-	void loop();
+	void loop(LoopSubstatus substatus, bool shouldExit);
 
 	// HACK: this is only for testing
 	int nextRoomNum() const {
@@ -271,10 +272,11 @@
 
 	bool shouldQuit() const { return _shouldQuit; }
 	void setQuit(bool quit) { _shouldQuit = quit; }
+	bool shouldExitLoop() const { return _shouldExitLoop; }
+	void setExitLoop(bool exit) { _shouldExitLoop = exit; }
+	bool isReloaded() const { return _isReloaded; }
+	void setIsReloaded(bool value) { _isReloaded = value; }
 
-	int shouldExitLoop() const { return _shouldExitLoop; }
-	void setExitLoop(int exit) { _shouldExitLoop = exit; }
-
 	void setSpeechTiming(uint tick, uint duration);
 	void shiftSpeechAndFadeTick(int delta);
 
@@ -318,7 +320,7 @@
 	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 @@
 	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;

Modified: scummvm/trunk/engines/draci/saveload.cpp
===================================================================
--- scummvm/trunk/engines/draci/saveload.cpp	2009-11-01 23:20:46 UTC (rev 45606)
+++ scummvm/trunk/engines/draci/saveload.cpp	2009-11-02 02:28:43 UTC (rev 45607)
@@ -152,7 +152,7 @@
 	// 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();
 

Modified: scummvm/trunk/engines/draci/script.cpp
===================================================================
--- scummvm/trunk/engines/draci/script.cpp	2009-11-01 23:20:46 UTC (rev 45606)
+++ scummvm/trunk/engines/draci/script.cpp	2009-11-02 02:28:43 UTC (rev 45607)
@@ -359,11 +359,7 @@
 
 	// 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 @@
 
 	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 @@
 	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 @@
 		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 @@
 	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 @@
 		_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 @@
 	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 @@
 	_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) {


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list