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

spalek at users.sourceforge.net spalek at users.sourceforge.net
Wed Nov 4 01:42:37 CET 2009


Revision: 45648
          http://scummvm.svn.sourceforge.net/scummvm/?rev=45648&view=rev
Author:   spalek
Date:     2009-11-04 00:42:37 +0000 (Wed, 04 Nov 2009)

Log Message:
-----------
Implemented and debugged the walking framework.

The hero does not walk yet (it still teleports to the target immediately),
but that is just because the actual walking algorithm is left trivial first.
However, the main game loop, callbacks, and waiting all already work with
the general framework.

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

Modified: scummvm/trunk/engines/draci/draci.cpp
===================================================================
--- scummvm/trunk/engines/draci/draci.cpp	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/draci.cpp	2009-11-04 00:42:37 UTC (rev 45648)
@@ -84,6 +84,7 @@
 	Common::addDebugChannel(kDraciLogicDebugLevel, "logic", "Game logic debug info");
 	Common::addDebugChannel(kDraciAnimationDebugLevel, "animation", "Animation debug info");
 	Common::addDebugChannel(kDraciSoundDebugLevel, "sound", "Sound debug info");
+	Common::addDebugChannel(kDraciWalkingDebugLevel, "walking", "Walking debug info");
 
 	// Don't forget to register your random source
 	g_eventRec.registerRandomSource(_rnd, "draci");

Modified: scummvm/trunk/engines/draci/draci.h
===================================================================
--- scummvm/trunk/engines/draci/draci.h	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/draci.h	2009-11-04 00:42:37 UTC (rev 45648)
@@ -105,7 +105,8 @@
 	kDraciArchiverDebugLevel  = 1 << 2,
 	kDraciLogicDebugLevel     = 1 << 3,
 	kDraciAnimationDebugLevel = 1 << 4,
-	kDraciSoundDebugLevel     = 1 << 5
+	kDraciSoundDebugLevel     = 1 << 5,
+	kDraciWalkingDebugLevel   = 1 << 6
 };
 
 } // End of namespace Draci

Modified: scummvm/trunk/engines/draci/game.cpp
===================================================================
--- scummvm/trunk/engines/draci/game.cpp	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/game.cpp	2009-11-04 00:42:37 UTC (rev 45648)
@@ -248,16 +248,17 @@
 
 				_walkingState.setCallback(&obj->_program, obj->_look);
 
-				if (!obj->_imLook) {
+				if (obj->_imLook || !_currentRoom._heroOn) {
+					_walkingState.callback();
+				} else {
 					if (obj->_lookDir == kDirectionLast) {
 						walkHero(x, y, obj->_lookDir);
 					} else {
 						walkHero(obj->_lookX, obj->_lookY, obj->_lookDir);
 					}
 				}
-
-				_walkingState.callback();
 			} else {
+				_walkingState.setCallback(NULL, 0);
 				walkHero(x, y, kDirectionLast);
 			}
 		}
@@ -272,16 +273,17 @@
 			if (_vm->_script->testExpression(obj->_program, obj->_canUse)) {
 				_walkingState.setCallback(&obj->_program, obj->_use);
 
-				if (!obj->_imUse) {
+				if (obj->_imUse || !_currentRoom._heroOn) {
+					_walkingState.callback();
+				} else {
 					if (obj->_useDir == kDirectionLast) {
 						walkHero(x, y, obj->_useDir);
 					} else {
 						walkHero(obj->_useX, obj->_useY, obj->_useDir);
 					}
 				}
-
-				_walkingState.callback();
 			} else {
+				_walkingState.setCallback(NULL, 0);
 				walkHero(x, y, kDirectionLast);
 			}
 		} else {
@@ -289,6 +291,7 @@
 				_walkingState.setCallback(&_currentRoom._program, _currentRoom._use);
 				_walkingState.callback();
 			} else {
+				_walkingState.setCallback(NULL, 0);
 				walkHero(x, y, kDirectionLast);
 			}
 		}
@@ -436,6 +439,29 @@
 		setExitLoop(true);
 	}
 
+	// Walk the hero.  The WalkingState class handles everything including
+	// proper timing.
+	if (_walkingState.isActive()) {
+		if (!_walkingState.continueWalking()) {
+			// Walking has finished.
+			bool exitLoop = false;
+			if (_loopSubstatus == kInnerUntilExit) {
+				// The callback may run another inner loop (for
+				// example, a dialogue).  Reset the loop
+				// substatus temporarily to the outer one.
+				exitLoop = true;
+				setLoopSubstatus(kOuterLoop);
+			}
+			debugC(2, kDraciWalkingDebugLevel, "Finished walking");
+			_walkingState.callback();	// clears callback pointer first
+			if (exitLoop) {
+				debugC(3, kDraciWalkingDebugLevel, "Exiting from the inner loop");
+				setExitLoop(true);
+				setLoopSubstatus(kInnerUntilExit);
+			}
+		}
+	}
+
 	// Advance animations (this may also call setExitLoop(true) in the
 	// callbacks) and redraw screen
 	_vm->_anims->drawScene(_vm->_screen->getSurface());
@@ -942,7 +968,7 @@
 }
 
 void Game::positionHero(const Common::Point &p, SightDirection dir) {
-	debugC(3, kDraciLogicDebugLevel, "Jump to x: %d y: %d", p.x, p.y);
+	debugC(3, kDraciWalkingDebugLevel, "Jump to x: %d y: %d", p.x, p.y);
 
 	_hero = p;
 	Movement movement = kStopRight;
@@ -965,33 +991,38 @@
 	playHeroAnimation(movement);
 }
 
+Common::Point Game::findNearestWalkable(int x, int y) const {
+	Surface *surface = _vm->_screen->getSurface();
+	return _walkingMap.findNearestWalkable(x, y, surface->getDimensions());
+}
+
 void Game::walkHero(int x, int y, SightDirection dir) {
-	// Needed for the map room with empty walking map.  For some reason,
-	// findNearestWalkable() takes several seconds with 100% CPU to finish
-	// (correctly).
-	if (!_currentRoom._heroOn)
+	if (!_currentRoom._heroOn) {
+		// Nothing to do.  Happens for example in the map.
 		return;
+	}
 
-	Common::Point target;
-	Surface *surface = _vm->_screen->getSurface();
-	target = _walkingMap.findNearestWalkable(x, y, surface->getDimensions());
-	debugC(3, kDraciLogicDebugLevel, "Walk to x: %d y: %d", target.x, target.y);
+	Common::Point target = findNearestWalkable(x, y);
 
 	// Compute the shortest and obliqued path.
 	WalkingPath shortestPath, obliquePath;
 	_walkingMap.findShortestPath(_hero, target, &shortestPath);
 	// TODO: test reachability and react
 	_walkingMap.obliquePath(shortestPath, &obliquePath);
+	debugC(2, kDraciWalkingDebugLevel, "Walking path lengths: shortest=%d oblique=%d", shortestPath.size(), obliquePath.size());
 	if (_vm->_showWalkingMap) {
 		redrawWalkingPath(kWalkingShortestPathOverlay, kWalkingShortestPathOverlayColour, shortestPath);
 		redrawWalkingPath(kWalkingObliquePathOverlay, kWalkingObliquePathOverlayColour, obliquePath);
 	}
 
-	_walkingState.setPath(_hero, target, Common::Point(x, y),
+	// Start walking.  Walking will be gradually advanced by
+	// advanceAnimationsAndTestLoopExit(), which also handles calling the
+	// callback and stopping the walk at the end.  If the hero is already
+	// walking at this point, this command will cancel the previous path
+	// and replace it by the current one (the callback has already been
+	// reset by our caller).
+	_walkingState.startWalking(_hero, target, Common::Point(x, y), dir,
 		_walkingMap.getDelta(), obliquePath);
-
-	// FIXME: Need to add proper walking (this only warps the dragon to position)
-	positionHero(target, dir);
 }
 
 void Game::loadItem(int itemID) {

Modified: scummvm/trunk/engines/draci/game.h
===================================================================
--- scummvm/trunk/engines/draci/game.h	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/game.h	2009-11-04 00:42:37 UTC (rev 45648)
@@ -206,9 +206,10 @@
 		return n;
 	}
 
-	void clearPath() { _walkingState.clearPath(); }
-	void positionHero(const Common::Point &p, SightDirection dir);
-	void walkHero(int x, int y, SightDirection dir);
+	Common::Point findNearestWalkable(int x, int y) const;
+	void stopWalking() { _walkingState.stopWalking(); }	// and clear callback
+	void positionHero(const Common::Point &p, SightDirection dir);	// teleport the dragon
+	void walkHero(int x, int y, SightDirection dir);	// start walking and leave callback as is
 	int getHeroX() const { return _hero.x; }
 	int getHeroY() const { return _hero.y; }
 	void positionAnimAsHero(Animation *anim);

Modified: scummvm/trunk/engines/draci/script.cpp
===================================================================
--- scummvm/trunk/engines/draci/script.cpp	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/script.cpp	2009-11-04 00:42:37 UTC (rev 45648)
@@ -660,8 +660,8 @@
 	SightDirection dir = static_cast<SightDirection> (params.pop());
 
 	// Jumps into the given position regardless of the walking map.
-	_vm->_game->positionHero(Common::Point(x, y), dir);
-	_vm->_game->clearPath();
+	_vm->_game->stopWalking();
+	_vm->_game->positionHero(_vm->_game->findNearestWalkable(x, y), dir);
 }
 
 void Script::walkOn(Common::Queue<int> &params) {
@@ -675,6 +675,7 @@
 
 	// Constructs an optimal path and starts walking there.  No callback
 	// will be called at the end nor will the loop-body exit.
+	_vm->_game->stopWalking();
 	_vm->_game->walkHero(x, y, dir);
 }
 
@@ -687,12 +688,12 @@
 	int y = params.pop();
 	SightDirection dir = static_cast<SightDirection> (params.pop());
 
+	_vm->_game->stopWalking();
 	_vm->_game->walkHero(x, y, dir);
 
-	// 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);
+	// Walk in an inner loop until the hero has arrived at the target
+	// point.  Then the loop-body will exit.
+	_vm->_game->loop(kInnerUntilExit, false);
 }
 
 void Script::newRoom(Common::Queue<int> &params) {

Modified: scummvm/trunk/engines/draci/walking.cpp
===================================================================
--- scummvm/trunk/engines/draci/walking.cpp	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/walking.cpp	2009-11-04 00:42:37 UTC (rev 45648)
@@ -422,14 +422,17 @@
 	return improved;
 }
 
-void WalkingState::clearPath() {
+void WalkingState::stopWalking() {
 	_path.clear();
 	_callback = NULL;
 }
 
-void WalkingState::setPath(const Common::Point &p1, const Common::Point &p2, const Common::Point &mouse, const Common::Point &delta, const WalkingPath& path) {
+void WalkingState::startWalking(const Common::Point &p1, const Common::Point &p2,
+	const Common::Point &mouse, SightDirection dir,
+	const Common::Point &delta, const WalkingPath& path) {
 	_path = path;
 	_mouse = mouse;
+	_dir = dir;
 
 	if (!_path.size()) {
 		return;
@@ -440,6 +443,8 @@
 		// they are different pixels.
 		_path.push_back(p2);
 	}
+	debugC(2, kDraciWalkingDebugLevel, "Starting walking [%d,%d] -> [%d,%d] in %d segments",
+		p1.x, p1.y, p2.x, p2.y, _path.size());
 
 	// The first and last point are available with pixel accurracy.
 	_path[0] = p1;
@@ -461,6 +466,7 @@
 	if (!_callback) {
 		return;
 	}
+	debugC(2, kDraciWalkingDebugLevel, "Calling walking callback");
 
 	// Fetch the dedicated objects' title animation / current frame
 	Animation *titleAnim = _vm->_anims->getAnimation(kTitleText);
@@ -470,8 +476,21 @@
 	titleAnim->markDirtyRect(_vm->_screen->getSurface());
 	title->setText("");
 
-	_vm->_script->run(*_callback, _callbackOffset);
+	const GPL2Program *originalCallback = _callback;
+	_callback = NULL;
+	_vm->_script->run(*originalCallback, _callbackOffset);
+
 	_vm->_mouse->cursorOn();
 }
 
+bool WalkingState::continueWalking() {
+	// FIXME: do real walking instead of immediately exiting.  Compare the
+	// current dragon's animation phase with the stored one, and if they
+	// differ, walk another step.
+	debugC(2, kDraciWalkingDebugLevel, "Continuing walking");
+	_vm->_game->positionHero(_path[_path.size() - 1], _dir);
+	_path.clear();
+	return false;	// finished
 }
+
+}

Modified: scummvm/trunk/engines/draci/walking.h
===================================================================
--- scummvm/trunk/engines/draci/walking.h	2009-11-03 23:20:28 UTC (rev 45647)
+++ scummvm/trunk/engines/draci/walking.h	2009-11-04 00:42:37 UTC (rev 45648)
@@ -99,21 +99,32 @@
 
 class WalkingState {
 public:
-	explicit WalkingState(DraciEngine *vm) : _vm(vm) { clearPath(); }
+	explicit WalkingState(DraciEngine *vm) : _vm(vm) { stopWalking(); }
 	~WalkingState() {}
 
-	void clearPath();
-	void setPath(const Common::Point &p1, const Common::Point &p2, const Common::Point &mouse, const Common::Point &delta, const WalkingPath& path);
+	void stopWalking();
+	void startWalking(const Common::Point &p1, const Common::Point &p2,
+		const Common::Point &mouse, SightDirection dir,
+		const Common::Point &delta, const WalkingPath& path);
 	const WalkingPath& getPath() const { return _path; }
 
 	void setCallback(const GPL2Program *program, uint16 offset);
 	void callback();
 
+	bool isActive() const { return _path.size() > 0; }
+
+	// Advances the hero along the path and changes animation accordingly.
+	// Walking MUST be active when calling this method.  When the hero has
+	// arrived to the target, clears the path and returns false, but leaves
+	// the callback untouched (the caller must call it).
+	bool continueWalking();
+
 private:
 	DraciEngine *_vm;
 
 	WalkingPath _path;
 	Common::Point _mouse;
+	SightDirection _dir;
 
 	const GPL2Program *_callback;
 	uint16 _callbackOffset;


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