[Scummvm-cvs-logs] CVS: residual README,1.24,1.25 TODO,1.48,1.49 actor.cpp,1.53,1.54 actor.h,1.25,1.26 costume.cpp,1.29,1.30 costume.h,1.15,1.16 debug.h,1.10,1.11 driver_gl.cpp,1.54,1.55 engine.cpp,1.78,1.79 engine.h,1.29,1.30 font.cpp,1.3,1.4 font.h,1.5,1.6 keyframe.cpp,1.11,1.12 lua.cpp,1.141,1.142 model.cpp,1.27,1.28 objectstate.h,1.10,1.11 resource.cpp,1.25,1.26 resource.h,1.16,1.17 scene.cpp,1.43,1.44 scene.h,1.28,1.29 smush.cpp,1.61,1.62 smush.h,1.24,1.25

Erich Edgar Hoover compholio at users.sourceforge.net
Sun Jul 17 16:41:47 CEST 2005


Update of /cvsroot/scummvm/residual
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv19641

Modified Files:
	README TODO actor.cpp actor.h costume.cpp costume.h debug.h 
	driver_gl.cpp engine.cpp engine.h font.cpp font.h keyframe.cpp 
	lua.cpp model.cpp objectstate.h resource.cpp resource.h 
	scene.cpp scene.h smush.cpp smush.h 
Log Message:
Font patch from Andrea Corna - improved keyframe support - SMUSH looping support - improved IMUSE stability - additional error checking

Index: README
===================================================================
RCS file: /cvsroot/scummvm/residual/README,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- README	5 Apr 2005 13:56:30 -0000	1.24
+++ README	17 Jul 2005 23:40:21 -0000	1.25
@@ -1,5 +1,5 @@
 Residual: A LucasArts 3D game interpreter           Version:      0.04-CVS
-(C) 2003-2005 The ScummVM-Residual team             Last Updated: 03 Apr 2005
+(C) 2003-2005 The ScummVM-Residual team             Last Updated: 17 Jul 2005
 ------------------------------------------------------------------------------
 
 What is Residual?
@@ -55,8 +55,15 @@
 What is the state of Residual? 
 ------------------------------- 
 Basic gameplay works, including cutscenes. Some of the game is playable,
-but many features are either missing or unstable. There are no menus,
-save/load features, lighting, etc. Crashes are likely.
+but many features are either missing or unstable. There is no abilitity
+to save/load, lighting, etc. Crashes are likely.
+
+Game currently playable to:
+	Manny reaps Meche (Mercedes Colomar)
+Caveats:
+1) Random crash leaving the scene with the balloon handler
+2) Must press "Esc" after listening to Meche, conversation doesn't
+   continue on its own
 
 What are the default keys?
 --------------------------
@@ -65,7 +72,8 @@
 Shift      : Hold to run
 Enter      : Selects items in inventory, conversation, etc
 Escape     : Skips cutscenes, exits certain screens
-q          : Quit 
+q          : Exit Dialog Menu
+Ctrl + c   : Force Quit (from command-line)
 
 Development/debug keys from the original game
 ---------------------------------------------
@@ -95,7 +103,6 @@
 
 What else should I know?
 ------------------------
-  * Exit with 'q', and don't press f1, as things will go loopy.
   * See TODO for other stuff
 
 Credits:
@@ -109,7 +116,8 @@
  Vincent Hamm                       Various engine code
  Lionel 'bbrox' Ulmer               OpenGL optimisations
  Ori 'salty-horse' Avtalion         Lipsync, LAF support
- Erich 'Compholio' Hoover           x86-64, subtitles fixes, menu support
+ Erich 'Compholio' Hoover           x86-64, various fixes and comments, menu support, improved state support
+ Andrea 'Yak Bizzarro' Corna        Improved font support
 
 Special Thanks To:
 ------------------ 

Index: TODO
===================================================================
RCS file: /cvsroot/scummvm/residual/TODO,v
retrieving revision 1.48
retrieving revision 1.49
diff -u -d -r1.48 -r1.49
--- TODO	3 Apr 2005 11:33:28 -0000	1.48
+++ TODO	17 Jul 2005 23:40:21 -0000	1.49
@@ -1,17 +1,22 @@
 Residual TODO list (in rough order of priority):
 ------------------------------------------------
 Assigned tasks:
+ * Make game playable to the petrified forest (compholio)
  * Finish text drawing support (salty-horse, aquadran)
  * Cross platform GUI for debug input dialogs and path selection (ender)
  * Improved walk box code (frob)
  * Implement FadeInChore and FadeOutChore (frob)
  * Implement texture mapping with light shading in TinyGL (aquadran)
+ * Improve menu support (compholio)
+ * Improve SMUSH looping support (compholio)
 
 Unassigned (help wanted):
+ * Fix random problem with Manny changing between scenes, switching between
+   fe.set and st.set is a good example of where it happens a lot
  * Add configure script (Custom ala main ScummVM, NOT autoconf)
  * Proper light setup in drivers
  * Finish Save/Load support for rest of Engine (Lua and iMuse done)
- * Implement 2D primitives
+ * Finish 2D primitive code
  * Proper vsscanf implementation in textsplit.cpp for platforms without it (MSVC, etc)
  * Make SMUSH work on Linux/PPC (whats wrong with it, exactly? - ender :)
  * Finish panning in 3d position code

Index: actor.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/actor.cpp,v
retrieving revision 1.53
retrieving revision 1.54
diff -u -d -r1.53 -r1.54
--- actor.cpp	10 Jul 2005 18:57:27 -0000	1.53
+++ actor.cpp	17 Jul 2005 23:40:21 -0000	1.54
@@ -34,7 +34,7 @@
 Actor::Actor(const char *name) :
 		_name(name), _talkColor(255, 255, 255), _pos(0, 0, 0),
 		_pitch(0), _yaw(0), _roll(0), _walkRate(0), _turnRate(0),
-		_reflectionAngle(80),
+		_reflectionAngle(80), _setName(""), _setNameTmp(""),
 		_visible(true), _lipSynch(NULL), _turning(false), _walking(false),
 		_restCostume(NULL), _restChore(-1),
 		_walkCostume(NULL), _walkChore(-1), _walkedLast(false), _walkedCur(false),
@@ -278,9 +278,11 @@
 		return;
 	}
 
-	// During movies, SayLine is called for text display only
-	if (!g_smush->isPlaying()) {
-		
+	// During Fullscreen movies SayLine is called for text display only
+	// However, normal SMUSH movies may call SayLine, for example:
+	// When Domino yells at Manny (a SMUSH movie) he does it with
+	// a SayLine request rather than as part of the movie!
+	if (!g_smush->isPlaying() || g_engine->getMode() == ENGINE_MODE_NORMAL) {
 		std::string soundName = msgId;
 		std::string soundLip = msgId;
 		soundName += ".wav";
@@ -306,7 +308,11 @@
 			// Also, some lip synch files have no entries
 			// In these cases, revert to using the mumble chore.
 			_lipSynch = g_resourceloader->loadLipSynch(soundLip.c_str());
-
+			// If there's no lip synch file then load the mumble chore if it exists
+			// (the mumble chore doesn't exist with the cat races announcer)
+			if (_lipSynch == NULL && _mumbleChore != -1)
+				_mumbleCostume->playChoreLooping(_mumbleChore);
+			
 			_talkAnim = -1;
 		}
 	}
@@ -325,7 +331,7 @@
 	// of the screen
 	if (!visible() || !inSet(g_engine->currScene()->name())) {
 		_sayLineText->setX(640 / 2);
-		_sayLineText->setY(440);
+		_sayLineText->setY(420);
 	} else {
 		// render at the top for active actors for now
 		_sayLineText->setX(640 / 2);
@@ -336,11 +342,16 @@
 }
 
 bool Actor::talking() {
+	// If there's no sound file then we're obviously not talking
+	if (strlen(_talkSoundName.c_str()) == 0)
+		return false;
+	
 	return g_imuse->getSoundStatus(_talkSoundName.c_str());
 }
 
 void Actor::shutUp() {
-	g_imuse->stopSound(_talkSoundName.c_str());
+	// Don't stop the sound, the call to stop the sound
+	// is made by the game
 	_talkSoundName = "";
 	if (_lipSynch != NULL) {
 		if ((_talkAnim != -1) && (_talkChore[_talkAnim] >= 0))
@@ -387,6 +398,18 @@
 			freeCostumeChore(_costumeStack.back(), _talkCostume[i], _talkChore[i]);
 		delete _costumeStack.back();
 		_costumeStack.pop_back();
+		Costume *newCost;
+		if (_costumeStack.empty())
+			newCost = NULL;
+		else
+			newCost = _costumeStack.back();
+		if (newCost == NULL) {
+			if (debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("Popped (freed) the last costume for an actor.\n");
+		}
+	} else {
+		if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("Attempted to pop (free) a costume when the stack is empty!");
 	}
 }
 
@@ -487,7 +510,14 @@
 
 	// Update lip synching
 	if (_lipSynch != NULL) {
-		int posSound = g_imuse->getPosIn60HzTicks(_talkSoundName.c_str());
+		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_imuse->getSoundStatus(_talkSoundName.c_str()))
+			posSound = g_imuse->getPosIn60HzTicks(_talkSoundName.c_str());
+		else
+			posSound = -1;
 		if (posSound != -1) {
 			int anim = _lipSynch->getAnim(posSound);
 			if (_talkAnim != anim) {

Index: actor.h
===================================================================
RCS file: /cvsroot/scummvm/residual/actor.h,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- actor.h	10 Jul 2005 18:57:27 -0000	1.25
+++ actor.h	17 Jul 2005 23:40:21 -0000	1.26
@@ -54,7 +54,13 @@
 	float roll() const { return _roll; }
 	void setVisibility(bool val) { _visible = val; }
 	bool visible() const { return _visible; }
-	void putInSet(const char *name) { _setName = name; }
+	// Don't actually change the set immediately, see engine.cpp for details
+	void putInSet(const char *name) { _setNameTmp = name; }
+	void putInSet() {
+		if (_setName != _setNameTmp) {
+			_setName = _setNameTmp;
+		}
+	 }
 	void setTurnRate(float rate) { _turnRate = rate; }
 	float turnRate() const { return _turnRate; }
 	void setWalkRate(float rate) { _walkRate = rate; }
@@ -128,7 +134,8 @@
 
 private:
 	std::string _name;
-	std::string _setName;
+	std::string _setName;    // The actual current set
+	std::string _setNameTmp; // The temporary name for the set
 	Color _talkColor;
 	Vector3d _pos;
 	float _pitch, _yaw, _roll;

Index: costume.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/costume.cpp,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- costume.cpp	10 Jul 2005 18:57:27 -0000	1.29
+++ costume.cpp	17 Jul 2005 23:40:21 -0000	1.30
@@ -565,7 +565,10 @@
 	void setMapName(char *) { }
 	void setKey(int val);
 	void reset();
-	~SoundComponent() { }
+	~SoundComponent() {
+	// Stop the sound if it's in progress
+	reset();
+}
 
 private:
 	std::string _soundName;
@@ -584,14 +587,12 @@
 void SoundComponent::setKey(int val) {
 	switch (val) {
 	case 0: // "Play"
-		if (!g_imuse->getSoundStatus(_soundName.c_str())) {
-//			g_imuse->stopSound(_soundName.c_str());
-//		} else {
-			g_imuse->startSfx(_soundName.c_str());
-			if (g_engine->currScene() && g_currentUpdatedActor) {
-				Vector3d pos = g_currentUpdatedActor->pos();
-				g_engine->currScene()->setSoundPosition(_soundName.c_str(), pos);
-			}
+		// No longer a need to check the sound status, if it's already playing
+		// then it will just use the existing handle
+		g_imuse->startSfx(_soundName.c_str());
+		if (g_engine->currScene() && g_currentUpdatedActor) {
+			Vector3d pos = g_currentUpdatedActor->pos();
+			g_engine->currScene()->setSoundPosition(_soundName.c_str(), pos);
 		}
 		break;
 	case 1: // "Stop"
@@ -607,13 +608,15 @@
 }
 
 void SoundComponent::reset() {
-	g_imuse->stopSound(_soundName.c_str());
+	// A lot of the sound components this gets called against aren't actually running
+	if(g_imuse->getSoundStatus(_soundName.c_str()))
+		g_imuse->stopSound(_soundName.c_str());
 }
 
 Costume::Costume(const char *filename, const char *data, int len, Costume *prevCost) :
 		_fname(filename), _colormap(DEFAULT_COLORMAP) {
 	TextSplitter ts(data, len);
-
+	
 	ts.expectString("costume v0.1");
 	ts.expectString("section tags");
 	int numTags;
@@ -685,8 +688,11 @@
 
 Costume::~Costume() {
 	stopChores();
-	for (int i = _numComponents - 1; i >= 0; i--)
-		delete _components[i];
+	for (int i = _numComponents - 1; i >= 0; i--) {
+		// The "Sprite" component can be NULL
+		if (_components[i] != NULL)
+			delete _components[i];
+	}
 	delete[] _chores;
 }
 
@@ -695,6 +701,7 @@
 	_cost = NULL;
 	setParent(parent);
 	memcpy(_tag, tag, 4);
+	_tag[5] = 0;
 }
 
 void Costume::Component::setParent(Component *newParent) {
@@ -833,6 +840,37 @@
 	return NULL;
 }
 
+Model::HierNode *Costume::getModelNodes()
+{
+		for(int i=0;i<_numComponents;i++) {
+			if (_components[i] == NULL)
+				continue;
+			// Needs to handle Main Models (pigeons) and normal Models
+			// (when Manny climbs the rope)
+			if (std::memcmp(_components[i]->tag(), "mmdl", 4) == 0)
+				return dynamic_cast<ModelComponent *>(_components[i])->hierarchy();
+		}
+		return NULL;
+}
+
+void Costume::playChoreLooping(int num) {
+	if (num < 0 || num >= _numChores) {
+		if (debugLevel == DEBUG_CHORES || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("Requested chore number %d is outside the range of chores (0-%d)!", num, _numChores);
+		return;
+	}
+	_chores[num].playLooping();
+}
+
+void Costume::playChore(int num) {
+	if (num < 0 || num >= _numChores) {
+		if (debugLevel == DEBUG_CHORES || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("Requested chore number %d is outside the range of chores (0-%d)!", num, _numChores);
+		return;
+	}
+	_chores[num].play();
+}
+
 void Costume::stopChores() {
 	for (int i = 0; i < _numChores; i++)
 		_chores[i].stop();

Index: costume.h
===================================================================
RCS file: /cvsroot/scummvm/residual/costume.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- costume.h	10 Jul 2005 18:57:27 -0000	1.15
+++ costume.h	17 Jul 2005 23:40:21 -0000	1.16
@@ -19,6 +19,7 @@
 #define COSTUME_H
 
 #include "matrix4.h"
+#include "model.h"
 
 #include <string>
 
@@ -32,13 +33,13 @@
 	~Costume();
 
 	const char *filename() const { return _fname.c_str(); }
-
-	void playChore(int num) { _chores[num].play(); }
-	void playChoreLooping(int num) { _chores[num].playLooping(); }
+	void playChore(int num);
+	void playChoreLooping(int num);
 	void setChoreLastFrame(int num) { _chores[num].setLastFrame(); }
 	void setChoreLooping(int num, bool val) { _chores[num].setLooping(val); }
 	void stopChore(int num) { _chores[num].stop(); }
 	char *getColormap() { return _colormap; }
+	Model::HierNode *getModelNodes();
 	void setColormap(char *map) {
 		_colormap = map;
 		for(int i=0;i<_numComponents;i++) {
@@ -81,7 +82,7 @@
 		virtual ~Component() { }
 
 	protected:
-		char _tag[4];
+		char _tag[5];
 		int _parentID;
 		Component *_parent, *_child, *_sibling;
 		Matrix4 _matrix;

Index: debug.h
===================================================================
RCS file: /cvsroot/scummvm/residual/debug.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- debug.h	10 Jul 2005 18:57:27 -0000	1.10
+++ debug.h	17 Jul 2005 23:40:21 -0000	1.11
@@ -30,6 +30,7 @@
 	DEBUG_MODEL,
 	DEBUG_STUB,
 	DEBUG_SMUSH,
+	DEBUG_IMUSE,
 	DEBUG_CHORES,
 	DEBUG_ALL
 };
@@ -44,6 +45,7 @@
 	"MODEL",
 	"STUB",
 	"SMUSH",
+	"IMUSE",
 	"CHORE",
 	"ALL"
 };
@@ -56,7 +58,8 @@
 	"Bitmap debug messages will be printed",
 	"Model debug messages will be printed",
 	"Stub (missing function) debug messages will be printed",
-	"SMUSH debug messages will be printed",
+	"SMUSH (video) debug messages will be printed",
+	"IMUSE (audio) debug messages will be printed",
 	"Chore debug messages will be printed",
 	"All debug messages will be printed",
 };

Index: driver_gl.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/driver_gl.cpp,v
retrieving revision 1.54
retrieving revision 1.55
diff -u -d -r1.54 -r1.55
--- driver_gl.cpp	10 Jul 2005 18:57:27 -0000	1.54
+++ driver_gl.cpp	17 Jul 2005 23:40:21 -0000	1.55
@@ -368,8 +368,13 @@
 		glEnable(GL_DEPTH_TEST);
 	} else if (bitmap->_format == 5) {	// ZBuffer image
 		// Only draw the manual zbuffer when enabled
-		if (ZBUFFER_GLOBAL)
-			drawDepthBitmap(bitmap->_x, bitmap->_y, bitmap->_width, bitmap->_height, bitmap->_data[bitmap->_currImage - 1]);
+		if (ZBUFFER_GLOBAL) {
+			if (bitmap->_currImage - 1 < bitmap->_numImages) {
+				drawDepthBitmap(bitmap->_x, bitmap->_y, bitmap->_width, bitmap->_height, bitmap->_data[bitmap->_currImage - 1]);
+			} else {
+				warning("zbuffer image has index out of bounds! %d/%d\n", bitmap->_currImage, bitmap->_numImages);
+			}
+		}
 	}
 	glEnable(GL_LIGHTING);
 }
@@ -508,7 +513,6 @@
 
 	glDisable(GL_LIGHTING);
 	glEnable(GL_TEXTURE_2D);
-
 	// draw
 	glDisable(GL_DEPTH_TEST);
 	glDepthMask(GL_FALSE);

Index: engine.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/engine.cpp,v
retrieving revision 1.78
retrieving revision 1.79
diff -u -d -r1.78 -r1.79
--- engine.cpp	10 Jul 2005 18:57:27 -0000	1.78
+++ engine.cpp	17 Jul 2005 23:40:21 -0000	1.79
@@ -92,6 +92,10 @@
 }
 
 void Engine::handleButton(int operation, int key) {
+	// If we're not supposed to handle the key then don't
+	if (!_controlsEnabled[key])
+		return;
+	
 	lua_beginblock();
 	lua_Object menu = getEventHandler("menuHandler");
 	if (menu != LUA_NOOBJECT && !lua_isnil(menu)) {
@@ -139,27 +143,75 @@
 		// Process events
 		SDL_Event event;
 		while (SDL_PollEvent(&event)) {
-			if (event.type == SDL_KEYDOWN && _controlsEnabled[event.key.keysym.sym])
-				handleButton(SDL_KEYDOWN, event.key.keysym.sym);
-			if (event.type == SDL_KEYUP && _controlsEnabled[event.key.keysym.sym]) {
-				handleButton(SDL_KEYUP, event.key.keysym.sym);
-			}
-			if (event.type == SDL_QUIT) {
-				lua_beginblock();
-				lua_Object handler = getEventHandler("exitHandler");
-				if (handler != LUA_NOOBJECT)
-					lua_callfunction(handler);
-				lua_endblock();
-			}
+			// Handle any button operations
+			if(event.type == SDL_KEYDOWN || event.type == SDL_KEYUP)
+				handleButton(event.type, event.key.keysym.sym);
+			// Check for "Hard" quit"
+			if (event.type == SDL_QUIT)
+				return;
 			if (event.type == SDL_KEYDOWN) {
-				if (event.key.keysym.sym == SDLK_z)
-					g_resourceloader->loadKeyframe("ma_card_hold.key");
+				if (event.key.keysym.sym == SDLK_z
+				 && (event.key.keysym.mod & KMOD_CTRL)) {
+						void *resource;
+						int c, i = 0;
+						char buf[512];
+						
+						// Tool for debugging the loading of a particular resource without
+						// having to actually make it all the way to it in the game
+						fprintf(stderr, "Enter resource to load (extension specifies type): ");
+						while (i < 512 && (c = fgetc(stdin)) != EOF && c != '\n')
+							buf[i++] = c;
+						buf[i] = '\0';
+						if (strncmp(buf, "exp:", 4) == 0)
+							// Export a resource in order to view it directly
+							resource = (void *) g_resourceloader->exportResource(&buf[4]);
+						else if (strstr(buf, ".key"))
+							resource = (void *) g_resourceloader->loadKeyframe(buf);
+						else if (strstr(buf, ".zbm") || strstr(buf, ".bm"))
+							resource = (void *) g_resourceloader->loadBitmap(buf);
+						else if (strstr(buf, ".cmp"))
+							resource = (void *) g_resourceloader->loadColormap(buf);
+						else if (strstr(buf, ".cos"))
+							resource = (void *) g_resourceloader->loadCostume(buf, NULL);
+						else if (strstr(buf, ".lip"))
+							resource = (void *) g_resourceloader->loadLipSynch(buf);
+						else if (strstr(buf, ".snm"))
+							resource = (void *) g_smush->play(buf, 0, 0);
+						else if (strstr(buf, ".wav") || strstr(buf, ".imu")) {
+							g_imuse->startSfx(buf);
+							resource = (void *) 1;
+						} else if (strstr(buf, ".mat")) {
+							CMap *cmap = g_resourceloader->loadColormap("item.cmp");
+							
+							warning("Default colormap applied to resources loaded in this fashion!");
+							resource = (void *) g_resourceloader->loadMaterial(buf, *cmap);
+						} else {
+							warning("Resource type not understood!");
+							break;
+						}
+						if (resource == NULL)
+							warning("Requested resouce (%s) not found!");
+				}
 				if ((event.key.keysym.sym == SDLK_RETURN ||
 				     event.key.keysym.sym == SDLK_KP_ENTER) &&
-				    (event.key.keysym.mod & KMOD_ALT))
+				    (event.key.keysym.mod & KMOD_ALT)) {
 						g_driver->toggleFullscreenMode();
-				if (event.key.keysym.sym == SDLK_q)
-					return;
+				}
+				if (event.key.keysym.sym == SDLK_q) {
+					lua_Object menu = getEventHandler("menuHandler");
+					
+					// Can't handle the exit menu on top of the normal one
+					// at this time, so exit flat-out if we're in a menu
+					if (lua_isnil(menu)) {
+						printf("NOTICE: The left/right arrow keys do not update the quit screen at this time, use Y/N keys instead!\n");
+						lua_beginblock();
+						lua_Object handler = getEventHandler("exitHandler");
+						if (handler != LUA_NOOBJECT)
+							lua_callfunction(handler);
+						lua_endblock();
+					} else
+						return;
+				}
 			}
 		}
 
@@ -170,6 +222,13 @@
 			savegameSave();
 		}
 
+		// It appears that the lua tasks should run before rendering,
+		// if you watch the game loading screen you'll see that it
+		// turns out better to run this beforehand
+		if (!_menuMode)
+			// Run asynchronous tasks
+			lua_runtasks();
+
 		if (_mode == ENGINE_MODE_SMUSH) {
 			if (g_smush->isPlaying()) {
 				_movieTime = g_smush->getMovieTime();
@@ -186,9 +245,16 @@
 		} else if (_mode == ENGINE_MODE_NORMAL) {
 			g_driver->clearScreen();
 
-			// Update actor costumes
+			// Update actor costumes & sets
 			for (ActorListType::iterator i = _actors.begin(); i != _actors.end(); i++) {
 				Actor *a = *i;
+				
+				// Activate the new set
+				// While this doesn't seem to affect anything this should be done here 
+				// instead of inside the lua_runtasks loop, otherwise certain functions
+				// may request a set that was just deactivated
+				a->putInSet();
+				// Update the actor's costumes
 				g_currentUpdatedActor = *i;
 				if (_currScene != NULL && a->inSet(_currScene->name()) && a->visible())
 					a->update();
@@ -201,6 +267,10 @@
 
 			// Draw underlying scene components
 			if (_currScene != NULL) {
+				// Background objects are drawn underneath everything except the background
+				// There are a bunch of these, especially in the tube-switcher room
+				_currScene->drawBitmaps(ObjectState::OBJSTATE_BACKGROUND);
+				// Underlay objects are just above the background
 				_currScene->drawBitmaps(ObjectState::OBJSTATE_UNDERLAY);
 				// State objects are drawn on top of other things, such as the flag
 				// on Manny's message tube
@@ -301,10 +371,6 @@
 			}
 		}
 
-		if (!_menuMode)
-			// Run asynchronous tasks
-			lua_runtasks();
-
 		if (g_imuseState != -1) {
 			g_imuse->setMusicState(g_imuseState);
 			g_imuseState = -1;
@@ -474,6 +540,7 @@
 
 void Engine::setScene(const char *name) {
 	Scene *scene = findScene(name);
+	Scene *lastScene = _currScene;
 	
 	// If the scene already exists then use the existing data
 	if (scene != NULL) {
@@ -483,23 +550,27 @@
 	Block *b = g_resourceloader->getFileBlock(name);
 	if (b == NULL)
 		warning("Could not find scene file %s\n", name);
-	if (_currScene != NULL && !_currScene->locked) {
-		removeScene(_currScene);
-		delete _currScene;
-	}
 	_currScene = new Scene(name, b->data(), b->len());
 	registerScene(_currScene);
 	_currScene->setSoundParameters(20, 127);
+	// should delete the old scene after creating the new one
+	if (lastScene != NULL && !lastScene->locked) {
+		removeScene(lastScene);
+		delete lastScene;
+	}
 	delete b;
 }
 
 void Engine::setScene(Scene *scene) {
-	if (_currScene != NULL && !_currScene->locked) {
-		removeScene(_currScene);
-		delete _currScene;
-	}
+	Scene *lastScene = _currScene;
+	
 	_currScene = scene;
 	_currScene->setSoundParameters(20, 127);
+	// should delete the old scene after setting the new one
+	if (lastScene != NULL && !lastScene->locked) {
+		removeScene(lastScene);
+		delete lastScene;
+	}
 }
 
 void Engine::setTextSpeed(int speed) {

Index: engine.h
===================================================================
RCS file: /cvsroot/scummvm/residual/engine.h,v
retrieving revision 1.29
retrieving revision 1.30
diff -u -d -r1.29 -r1.30
--- engine.h	10 Jul 2005 18:57:27 -0000	1.29
+++ engine.h	17 Jul 2005 23:40:21 -0000	1.30
@@ -94,6 +94,7 @@
 public:
 
 	void setMode(int mode) { _mode = mode; }
+	int getMode() { return _mode; }
 	void setSpeechMode(int mode) { _speechMode = mode; }
 	int getSpeechMode() { return _speechMode; }
 
@@ -101,7 +102,14 @@
 	unsigned frameStart() const { return _frameStart; }
 	unsigned frameTime() const { return _frameTime; }
 
-	float perSecond(float rate) const { return rate * _frameTime / 1000; }
+	float perSecond(float rate) const {
+		// The actor "Doug" at the Kitty races has no _turnRate set by default
+		// so we need to return some sort of time that's non-zero for a rate
+		// value of zero
+		if (rate == 0.0)
+			rate = 100.0;
+		return rate * _frameTime / 1000;
+	}
 
 	int getTextSpeed() { return _textSpeed; }
 	void setTextSpeed(int speed);

Index: font.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/font.cpp,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- font.cpp	5 May 2005 21:23:17 -0000	1.3
+++ font.cpp	17 Jul 2005 23:40:21 -0000	1.4
@@ -82,6 +82,33 @@
 	free(_fontData);
 }
 
+uint16 Font::getCharIndex(unsigned char c)
+{
+	uint16 c2 = uint16(c);
+	
+	// In order to ensure the correct character codes for
+	// accented characters it is necessary to check the
+	// requested code against the index of characters for 
+	// the font.  Previously, signed characters were
+	// causing the problem but it might be possible for
+	// an invalid character to be called for other reasons.
+	//
+	// Example: Without this fix when Manny greets Eva
+	// for the first time and he says "Buenos Días" the
+	// 'í' character will either show up as a different
+	// character or it crashes the game.
+	for (uint i = 0; i < _numChars; ++i) {
+	  if (_charIndex[i] == c2)
+			return i;
+	}
+	if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+		warning("The requsted character (code 0x%x) does not correspond to anything in the font data!\n", c2);
+	// If we couldn't find the character then default to
+	// the first character in the font so that something
+	// gets loaded to prevent the game from crashing
+	return 0;
+}
+
 // Hardcoded default font for GUI, etc
 const uint8 Font::emerFont[][13] = {
 {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 

Index: font.h
===================================================================
RCS file: /cvsroot/scummvm/residual/font.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- font.h	5 May 2005 21:23:17 -0000	1.5
+++ font.h	17 Jul 2005 23:40:21 -0000	1.6
@@ -28,16 +28,17 @@
 	Font(const char *filename, const char *data, int len);
 	~Font();
 
-	int32 getCharWidth(char c) { return _charHeaders[_charIndex[c]].width; }
-	int32 getCharHeight(char c) { return _charHeaders[_charIndex[c]].height; }
-	int32 getCharLogicalWidth(char c) { return _charHeaders[_charIndex[c]].logicalWidth; }
-	int32 getCharStartingCol(char c) { return _charHeaders[_charIndex[c]].startingCol; }
-	int32 getCharStartingLine(char c) { return _charHeaders[_charIndex[c]].startingLine; }
-	const byte *getCharData(char c) { return _fontData + (_charHeaders[_charIndex[c]].offset); }
+	int32 getCharWidth(unsigned char c) { return _charHeaders[getCharIndex(c)].width; }
+	int32 getCharHeight(unsigned char c) { return _charHeaders[getCharIndex(c)].height; }
+	int32 getCharLogicalWidth(unsigned char c) { return _charHeaders[getCharIndex(c)].logicalWidth; }
+	int32 getCharStartingCol(unsigned char c) { return _charHeaders[getCharIndex(c)].startingCol; }
+	int32 getCharStartingLine(unsigned char c) { return _charHeaders[getCharIndex(c)].startingLine; }
+	const byte *getCharData(unsigned char c) { return _fontData + (_charHeaders[getCharIndex(c)].offset); }
 
 	static const uint8 Font::emerFont[][13];
 private:
 
+	uint16 getCharIndex(unsigned char c);
 	struct CharHeader {
 		int32 offset;
 		int32 unknown;

Index: keyframe.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/keyframe.cpp,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- keyframe.cpp	10 Jul 2005 18:57:27 -0000	1.11
+++ keyframe.cpp	17 Jul 2005 23:40:21 -0000	1.12
@@ -35,11 +35,28 @@
 }
 
 void KeyframeAnim::loadBinary(const char *data, int len) {
+	// First four bytes are the FYEK Keyframe identifier code
+	// Next 36 bytes are the filename
+	if (debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL) {
+		char filebuf[37];
+		
+		memcpy(filebuf, data + 4, 36);
+		filebuf[37] = 0;
+		printf("Loading Keyframe '%s'.\n", filebuf);
+	}
+	// Next four bytes are the flags
 	_flags = READ_LE_UINT32(data + 40);
+	// Next four bytes are a duplicate of _numJoints (?)
+	// Next four bytes are the type
 	_type = READ_LE_UINT32(data + 48);
+	// Next four bytes are the frames per second
 	_fps = get_float(data + 52);
+	// Next four bytes are the number of frames
 	_numFrames = READ_LE_UINT32(data + 56);
+	// Next four bytes are the number of joints
 	_numJoints = READ_LE_UINT32(data + 60);
+	// Next four bytes are unknown (?)
+	// Next four bytes are the number of markers
 	_numMarkers = READ_LE_UINT32(data + 68);
 	_markers = new Marker[_numMarkers];
 	for (int i = 0; i < _numMarkers; i++) {
@@ -51,16 +68,22 @@
 	for (int i = 0; i < _numJoints; i++)
 		_nodes[i] = NULL;
 	const char *dataEnd = data + len;
-	data += 180;
+	// The first 136 bytes are for the header, this was originally
+	// listed as 180 bytes since the first operation is usually a
+	// "null" key, however ma_card_hold.key showed that this is
+	// not always the case so we should not skip this operation
+	data += 136;
 	while (data < dataEnd) {
-		// ma_card_hold.key crashes at this part without checking
-		// to make sure nodeNum is valid, unfortunately I believe
-		// whatever data we're losing from this file is what prevents
-		// the game from continuing after Manny reads the message
-		// 
-		// TODO: Find out what really goes wrong when we read
-		// the data in ma_card_hold.key and fix it
-		int nodeNum = READ_LE_UINT32(data + 32);
+		int nodeNum;
+		// The first 32 bytes (of a keyframe) are the name handle
+		// The next four bytes are the node number identifier
+		nodeNum = READ_LE_UINT32(data + 32);
+
+		// Because of the issue above ma_card_hold.key used to crash
+		// at this part without checking to make sure nodeNum is a
+		// valid number, we'll leave this in just in case something
+		// else is still wrong but it should now load correctly in
+		// all cases
 		if (nodeNum >= _numJoints) {
 			if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL) {
 				warning("A node number was greater than the maximum number of nodes (%d/%d)", nodeNum, _numJoints);
@@ -117,10 +140,10 @@
 	if (frame > _numFrames)
 		frame = _numFrames;
 
-	for (int i = 0; i < _numJoints; i++)
+	for (int i = 0; i < _numJoints; i++) {
 		if (_nodes[i] != NULL)
-
-	_nodes[i]->animate(nodes[i], frame, ((_type & nodes[i]._type) != 0 ? priority2 : priority1));
+			_nodes[i]->animate(nodes[i], frame, ((_type & nodes[i]._type) != 0 ? priority2 : priority1));
+	}
 }
 
 void KeyframeAnim::KeyframeEntry::loadBinary(const char *&data) {
@@ -138,13 +161,18 @@
 }
 
 void KeyframeAnim::KeyframeNode::loadBinary(const char *&data) {
-	std::memcpy(_meshName, data, 32);
+	// If the name handle is entirely null (like ma_rest.key)
+	// then we shouldn't try to set the name
+	if (READ_LE_UINT32(data) == 0)
+		std::memcpy(_meshName, "(null)", 32);
+	else
+		std::memcpy(_meshName, data, 32);
 	_numEntries = READ_LE_UINT32(data + 36);
 	data += 44;
 	_entries = new KeyframeEntry[_numEntries];
 	for (int i = 0; i < _numEntries; i++)
 		_entries[i].loadBinary(data);
-	}
+}
 
 void KeyframeAnim::KeyframeNode::loadText(TextSplitter &ts) {
 	ts.scanString("mesh name %s", 1, _meshName);

Index: lua.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/lua.cpp,v
retrieving revision 1.141
retrieving revision 1.142
diff -u -d -r1.141 -r1.142
--- lua.cpp	10 Jul 2005 18:57:27 -0000	1.141
+++ lua.cpp	17 Jul 2005 23:40:21 -0000	1.142
@@ -139,9 +139,26 @@
 	return NULL;
 }
 
-static inline int check_int(int num) {
-	double val = luaL_check_number(num);
+static inline double check_double(int num) {
+	double val;
+	
+	// Have found some instances, such as in Rubacava if you jump there,
+	// where doubles of "zero" are called as nil
+	if(lua_isnil(lua_getparam(num)))
+		return 0.0;
+	
+	return luaL_check_number(num);
+}
 
+static inline int check_int(int num) {
+	double val;
+	
+	// Have found some instances, such as in Rubacava and the tube-switcher
+	// room, where integers of "zero" are called as nil
+	if(lua_isnil(lua_getparam(num)))
+		return 0;
+	
+	val = luaL_check_number(num);
 	return int(round(val));
 }
 
@@ -200,6 +217,7 @@
 		
 		msg.insert(0, "Debug: ");
 		std::fputs(msg.c_str(), stderr);
+		msg.append("\n");
 	}
 }
 
@@ -506,21 +524,13 @@
 
 static void SetActorRot() {
 	float pitch, yaw, roll;
-	lua_Object param3;
 	Actor *act;
 
 	DEBUG_FUNCTION();
-	param3 = lua_getparam(3);
 	act = check_actor(1);
-	pitch = luaL_check_number(2);
-	// param3 can be nil, the tube-switcher scene appears
-	// to call SetActorRot will nil for param3 intentionally
-	if (lua_isnil(param3))
-		yaw = 0;
-	else
-		yaw = luaL_check_number(3);
-	
-	roll = luaL_check_number(4);
+	pitch = check_double(2);
+	yaw = check_double(3);
+	roll = check_double(4);
 	if (getbool(5))
 		act->turnTo(pitch, yaw, roll);
 	else
@@ -582,14 +592,18 @@
 }
 
 static void PutActorInSet() {
-	const char *set = "";
 	Actor *act;
 	
 	DEBUG_FUNCTION();
 	act = check_actor(1);
-	if (!lua_isnil(lua_getparam(2)))
+	if (!lua_isnil(lua_getparam(2))) {
+		const char *set;
+		
 		set = luaL_check_string(2);
-	act->putInSet(set);
+		// Make sure the actor isn't already in the set
+		if (!act->inSet(set))
+			act->putInSet(set);
+	}
 }
 
 static void SetActorWalkRate() {
@@ -742,6 +756,64 @@
 static void PointActorAt() {
 stubWarning("PointActorAt");
 }
+
+/* Get the location of one of the actor's nodes, this is
+ * used by Glottis to watch where Manny is located in 
+ * order to hand him the work order.  This function is
+ * also important for when Velasco hands Manny the logbook
+ * in Rubacava
+ */
+static void GetActorNodeLocation() {
+	Model::HierNode *allNodes;
+	Costume *c;
+	Actor *act;
+	int node;
+	
+	// Should this actually do anything?
+	DEBUG_FUNCTION();
+	act = check_actor(1);
+	node = check_int(2);
+	c = act->currentCostume();
+	if (c == NULL) {
+		lua_pushnil();
+		lua_pushnil();
+		lua_pushnil();
+		if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("GetActorNodeLocation() when actor has no costume (which means no nodes)!");
+		return;
+	}
+	allNodes = c->getModelNodes();
+	if (allNodes == NULL) {
+		lua_pushnil();
+		lua_pushnil();
+		lua_pushnil();
+		if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("GetActorNodeLocation() when actor has no nodes!");
+	}
+	lua_pushnumber(allNodes[node]._pos.x());
+	lua_pushnumber(allNodes[node]._pos.y());
+	lua_pushnumber(allNodes[node]._pos.z());
+}
+
+static void SetActorWalkDominate() {
+	lua_Object param2;
+	Actor *act;
+	
+	// Should this actually do anything?
+	DEBUG_FUNCTION();
+	act = check_actor(1);
+	if (act == NULL) {
+		lua_pushnil();
+		return;
+	}
+	param2 = lua_getparam(2);
+	if (lua_isnil(param2))
+		lua_pushnil();
+	else if (lua_isnumber(param2))
+		lua_pushnumber(lua_getnumber(param2));
+	else
+		warning("Unknown SetActorWalkDominate parameter!");
+}
 static void SetActorColormap() {
 	char *mapname;
 	CMap *_cmap;
@@ -794,10 +866,13 @@
 	DEBUG_FUNCTION();
 	act = check_actor(1);
 	c = act->currentCostume();
-	if (c == NULL)
+	if (c == NULL) {
 		lua_pushnil();
-	else
-		lua_pushstring(const_cast<char *>(c->filename()));
+		if (debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+			printf("GetActorCostume() on '%s' when actor has no costume!", act->name());
+		return;
+	}
+	lua_pushstring(const_cast<char *>(c->filename()));
 }
 
 static void PopActorCostume() {
@@ -957,9 +1032,6 @@
 
 		if (lua_isnumber(y))
 			act->setLookAtRate(luaL_check_number(3));
-
-		act->setLooking(true);
-		return;
 	} else if ( lua_isnumber(x)) { // look at xyz
 		Vector3d vector;
 		float fX;
@@ -988,13 +1060,13 @@
 
 		if (lua_isnumber(y))
 			act->setLookAtRate(luaL_check_number(3));
-	} else if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
-		warning("ActorLookAt: Don't know what to look at!");
+	} else {
+		if (debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
+			warning("ActorLookAt: Don't know what to look at!");
+	}
 
 	act->setLooking(true);
-	// Fixes random bug when changing scenes (?) after we've done a jump
-	// (this function is close to the failure point)
-	lua_pushnil();
+	lua_pushnumber(1);
 }
 
 static void SetActorLookRate() {
@@ -1274,16 +1346,15 @@
 	numSectors = g_engine->currScene()->getSectorCount();
 	for (i = 0; i < numSectors; i++) {
 		Sector *sector = g_engine->currScene()->getSectorBase(i);
-
 		if (sector->visible() && strmatch(sector->name(), name)) {
 			if (sector->isPointInSector(act->pos())) {
 				lua_pushnumber(sector->id());
 				lua_pushstring((char *)sector->name());
 				lua_pushnumber(sector->type());
+				return;
 			}
 		}
 	}
-
 	lua_pushnil();
 }
 
@@ -1431,9 +1502,13 @@
 	soundName = luaL_check_string(1);
 	priority = check_int(2);
 	group = check_int(3);
+	
+	// Start the sound with the appropriate settings
 	if (g_imuse->startSound(soundName, group, 0, 127, 0, priority)) {
 		lua_pushstring(soundName);
 	} else {
+		if (debugLevel == DEBUG_IMUSE || debugLevel == DEBUG_ERROR || debugLevel == DEBUG_ALL)
+			error("ImStartSound failed to start '%s'", soundName);
 		lua_pushnil();
 	}
 }
@@ -1859,6 +1934,7 @@
 
 /* Clean the buffer of text objects and primitives
  * this is known to be used when changing between menus
+ * and when loading some cutscenes
  */
 static void CleanBuffer() {
 	DEBUG_FUNCTION();
@@ -1897,6 +1973,18 @@
 		return NULL;
 }
 
+/* This function sends the SDL signal to
+ * go ahead and exit the game
+ */
+static void Exit() {
+	SDL_Event event;
+	
+	DEBUG_FUNCTION();
+	event.type = SDL_QUIT;
+	if (SDL_PushEvent(&event) != 0)
+		error("Unable to push exit event!");
+}
+
 /* This function provides all of the menu
  * handling that has been observed
  */
@@ -1920,35 +2008,6 @@
 	// get the keycode
 	key = atoi(lua_getstring(keycode));
 
-	// get the item list for most menus
-	itemTable = getTableValue(menuTable, "menu");
-	if (!lua_istable(itemTable)) {
-		// 3D Acceleration Menu
-		itemTable = getTableValue(menuTable, "active_menu");
-		if (!lua_istable(itemTable)) {
-			// Control Help menu
-			lua_Object nextPage = getTableValue(menuTable, "next_page");
-			lua_Object prevPage = getTableValue(menuTable, "prev_page");
-
-			if (lua_isfunction(nextPage) && key == SDLK_RIGHT) {
-				lua_beginblock();
-				lua_pushobject(menuTable);
-				lua_callfunction(nextPage);
-				lua_endblock();
-			} else if (lua_isfunction(prevPage) && key == SDLK_LEFT) {
-				lua_beginblock();
-				lua_pushobject(menuTable);
-				lua_callfunction(prevPage);
-				lua_endblock();
-			}
-			return;
-		}
-	}
-
-	// get the current item
-	menuItem = atoi(lua_getstring(getTableValue(itemTable, "cur_item")));
-	menuItems = atoi(lua_getstring(getTableValue(itemTable, "num_items")));
-
 	// handle hotkeys
 	if (key >= SDLK_a && key <= SDLK_z) {
 		char keychar[2];
@@ -1965,11 +2024,71 @@
 		key = 0;
 		return; // stop processing (we don't need to handle normal keystrokes)
 	}
+	
+	// Handle the correct type of menu
+	if (!lua_isnil(getTableValue(menuTable, "menu"))) {
+		// Get the item list for most menus
+		itemTable = getTableValue(menuTable, "menu");
+	} else if (!lua_isnil(getTableValue(menuTable, "active_menu"))) {
+		// 3D Acceleration Menu
+		itemTable = getTableValue(menuTable, "active_menu");
+	} else if (!lua_isnil(getTableValue(menuTable, "num_choices"))) {
+		// Exit Menu
+		int current_choice = atoi(lua_getstring(getTableValue(menuTable, "current_choice")));
+		int num_choices = atoi(lua_getstring(getTableValue(menuTable, "num_choices")));
+		
+		if (key == SDLK_RIGHT)
+			current_choice++;
+		else if (key == SDLK_LEFT)
+			current_choice--;
+		
+		if (current_choice < 0)
+			current_choice = 0;
+		else if (current_choice >= num_choices)
+			current_choice = num_choices-1;
+		
+		setTableValue(menuTable, "current_choice", current_choice);
+		// TODO: Need to figure out how to update the screen under this
+		// type of menu operation!
+		return;
+	} else if (lua_isfunction(getTableValue(menuTable, "next_page"))
+	 || lua_isfunction(getTableValue(menuTable, "prev_page"))) {
+		// Control Help menu
+		lua_Object nextPage = getTableValue(menuTable, "next_page");
+		lua_Object prevPage = getTableValue(menuTable, "prev_page");
+		
+		if (lua_isfunction(nextPage) && key == SDLK_RIGHT) {
+			lua_beginblock();
+			lua_pushobject(menuTable);
+			lua_callfunction(nextPage);
+			lua_endblock();
+		} else if (lua_isfunction(prevPage) && key == SDLK_LEFT) {
+			lua_beginblock();
+			lua_pushobject(menuTable);
+			lua_callfunction(prevPage);
+			lua_endblock();
+		}
+		return;
+	} else {
+		warning("Unhandled type of menu!");
+		return;
+	}
+
+	// get the current item
+	menuItem = atoi(lua_getstring(getTableValue(itemTable, "cur_item")));
+	menuItems = atoi(lua_getstring(getTableValue(itemTable, "num_items")));
 
 	// hack the "&Return to Game" command so it actually works
 	if (key == SDLK_RETURN && strmatch(itemText(itemTable, menuItem), "/sytx247/"))
 		key = SDLK_ESCAPE;
 
+	// hack the "&Quit" command so it actually works
+	// (at this time it cannot open the exit menu on top of the normal one)
+	if (key == SDLK_RETURN && strmatch(itemText(itemTable, menuItem), "/sytx248/")) {
+		Exit();
+		return;
+	}
+	
 	/* if we're running the menu then we need to manually handle
 	 * a lot of the operations necessary to use the menu
 	 */
@@ -1982,17 +2101,12 @@
 				return;
 
 			lua_Object close = getTableFunction(menuTable, "cancel");
-			lua_Object destroy = getTableFunction(menuTable, "destroy");
 
 			lua_beginblock();
 			lua_pushobject(menuTable);
 			lua_pushnil();
 			lua_callfunction(close);
 			lua_endblock();
-			lua_beginblock();
-			lua_pushnumber(menuItem);
-			lua_callfunction(destroy);
-			lua_endblock();
 			break;
 		}
 		case SDLK_DOWN:
@@ -2031,16 +2145,7 @@
 		lua_endblock();
 	}
 }
-  
-/* Clean the requested menu
- */
-static void destroyMenu() {
-	DEBUG_FUNCTION();
-	CleanBuffer();
-	lua_Object system_table = lua_getglobal("system");
-	setTableValue(system_table, "menuHandler", (lua_Object) 0);
-}
-  
+
 /* Check for an existing object by a certain name
  * this function is used by several functions that look
  * for text objects to see if they need to be created/modified/destroyed.
@@ -2252,14 +2357,18 @@
 	pushbool(g_smush->play(luaL_check_string(1), x, y));
 }
 
+/* Fullscreen movie playing query and normal movie
+ * query should actually detect correctly and not
+ * just return true whenever ANY movie is playing
+ */
 static void IsFullscreenMoviePlaying() {
 	DEBUG_FUNCTION();
-	pushbool(g_smush->isPlaying());
+	pushbool(g_smush->isPlaying() && g_engine->getMode() == ENGINE_MODE_SMUSH);
 }
 
 static void IsMoviePlaying() {
 	DEBUG_FUNCTION();
-	pushbool(g_smush->isPlaying());
+	pushbool(g_smush->isPlaying() && g_engine->getMode() == ENGINE_MODE_NORMAL);
 }
 
 static void StopMovie() {
@@ -2411,11 +2520,6 @@
 
 // Objectstate functions
 static void NewObjectState() {
-	enum ObjectPosition {
-		OBJSTATE_UNDERLAY = 1,
-		OBJSTATE_OVERLAY = 2,
-		OBJSTATE_STATE = 3
-	};
 	ObjectState *state = NULL;
 	ObjectState::Position pos;
 	char *bitmap, *zbitmap;
@@ -2423,6 +2527,7 @@
 	int setupID;
 
 	DEBUG_FUNCTION();
+	// Called with "nil" if you jump to zone "sp"
 	setupID = check_int(1);					// Setup ID
 	pos = check_objstate_pos(2); 		// When to draw
 	bitmap = luaL_check_string(3);	// Bitmap
@@ -2683,18 +2788,30 @@
 	}
 }
 
+/* For now this should just destroy any text
+ * objects that have been created and unlink
+ * the menu (this may be more appropriate under
+ * RenderModeUser, determine later)
+ */
+static void SetGamma() {
+	lua_Object system_table = lua_getglobal("system");
+	
+	// TODO: Make this un-dim the screen
+	stubWarning("SetGamma");
+	
+	CleanBuffer();
+	// Un-Install Menu Key Handler
+	lua_pushobject(system_table);
+	lua_pushstring(const_cast<char *>("menuHandler"));
+	lua_pushnil();
+	lua_settable();
+}
+
 static void Display() {
 	lua_Object system_table;
 	
 	DEBUG_FUNCTION();
 	system_table = lua_getglobal("system");
-	// Install Menu Destroy Handler
-	lua_pushobject(system_table);
-	lua_pushstring(const_cast<char *>("userPaintHandler"));
-	lua_pushobject(lua_gettable());
-	lua_pushstring(const_cast<char *>("destroy"));
-	lua_pushcfunction(destroyMenu);
-	lua_settable();
 	// Install Menu Key Handler
 	lua_pushobject(system_table);
 	lua_pushstring(const_cast<char *>("menuHandler"));
@@ -2838,7 +2955,6 @@
 STUB_FUNC(SetShadowColor)
 STUB_FUNC(DimRegion)
 STUB_FUNC(ForceRefresh)
-STUB_FUNC(SetGamma)
 STUB_FUNC(LightMgrStartup)
 STUB_FUNC(SetLightIntensity)
 STUB_FUNC(SetLightPosition)
@@ -2862,12 +2978,10 @@
 STUB_FUNC(GetPointSector)
 STUB_FUNC(IsPointInSector)
 STUB_FUNC(SetActorFrustrumCull)
-STUB_FUNC(SetActorWalkDominate)
 STUB_FUNC(GetCameraActor)
 STUB_FUNC(DriveActorTo)
 STUB_FUNC(WalkActorVector)
 STUB_FUNC(GetActorRect)
-STUB_FUNC(GetActorNodeLocation)
 STUB_FUNC(SetActorTimeScale)
 STUB_FUNC(SetActorScale)
 STUB_FUNC(GetTranslationMode)
@@ -2876,7 +2990,6 @@
 STUB_FUNC(KillPrimitive)
 STUB_FUNC(WalkActorToAvoiding)
 STUB_FUNC(GetActorChores)
-STUB_FUNC(Exit)
 STUB_FUNC(SetCameraPosition)
 STUB_FUNC(GetCameraFOV)
 STUB_FUNC(SetCameraFOV)

Index: model.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/model.cpp,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -d -r1.27 -r1.28
--- model.cpp	10 Jul 2005 18:57:27 -0000	1.27
+++ model.cpp	17 Jul 2005 23:40:21 -0000	1.28
@@ -263,10 +263,12 @@
 	_materials = new ResPtr<Material>[_numMaterials];
 	_materialNames = new char[_numMaterials][32];
 	for (int i = 0; i < _numMaterials; i++) {
+		char materialName[32];
 		int num;
 		
-		ts.scanString("%d: %32s", 2, &num, _materialNames[num]);
-		_materials[num] = g_resourceloader->loadMaterial(_materialNames[num], cmap);
+		ts.scanString("%d: %32s", 2, &num, materialName);
+		_materials[num] = g_resourceloader->loadMaterial(materialName, cmap);
+		strcpy(_materialNames[num], materialName);
 	}
 
 	ts.expectString("section: geometrydef");
@@ -401,16 +403,17 @@
 	_faces = new Face[_numFaces];
 	_materialid = new int[_numFaces];
 	for (int i = 0; i < _numFaces; i++) {
-		int num, type, geo, light, tex, verts;
+		int num, materialid, type, geo, light, tex, verts;
 		float extralight;
 		int readlen;
 
 		if (ts.eof())
 			error("Expected face data, got EOF\n");
 
-		if (std::sscanf(ts.currentLine(), " %d: %d %i %d %d %d %f %d%n", &num, &_materialid[num], &type, &geo, &light, &tex, &extralight, &verts, &readlen) < 8)
+		if (std::sscanf(ts.currentLine(), " %d: %d %i %d %d %d %f %d%n", &num, &materialid, &type, &geo, &light, &tex, &extralight, &verts, &readlen) < 8)
 			error("Expected face data, got `%s'\n", ts.currentLine());
 
+		_materialid[num] = materialid;
 		_faces[num]._material = materials[_materialid[num]];
 		_faces[num]._type = type;
 		_faces[num]._geo = geo;

Index: objectstate.h
===================================================================
RCS file: /cvsroot/scummvm/residual/objectstate.h,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- objectstate.h	8 Apr 2005 12:41:19 -0000	1.10
+++ objectstate.h	17 Jul 2005 23:40:21 -0000	1.11
@@ -28,9 +28,12 @@
 class ObjectState {
 public:
 	enum Position {
+		OBJSTATE_BACKGROUND = 0,
 		OBJSTATE_UNDERLAY = 1,
 		OBJSTATE_OVERLAY = 2,
 		OBJSTATE_STATE = 3
+// TODO: Find out what ObjectState 6 is supposed to be
+//		OBJSTATE_UNKNOWN = 6
 	};
 
 	ObjectState(int setupID, ObjectState::Position pos, const char *bitmap, const char *zbitmap, bool visible);

Index: resource.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/resource.cpp,v
retrieving revision 1.25
retrieving revision 1.26
diff -u -d -r1.25 -r1.26
--- resource.cpp	10 Jul 2005 18:57:27 -0000	1.25
+++ resource.cpp	17 Jul 2005 23:40:21 -0000	1.26
@@ -285,6 +285,18 @@
 	return result;
 }
 
+bool ResourceLoader::exportResource(const char *filename) {
+	FILE *myFile = fopen(filename, "w");
+	Block *b = getFileBlock(filename);
+	
+	if (b == NULL)
+		return false;
+	fwrite(b->data(), b->len(), 1, myFile);
+	fclose(myFile);
+	delete b;
+	return true;
+}
+
 void ResourceLoader::uncache(const char *filename) {
 	std::string fname = filename;
 	makeLower(fname);

Index: resource.h
===================================================================
RCS file: /cvsroot/scummvm/residual/resource.h,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- resource.h	10 Jul 2005 18:57:27 -0000	1.16
+++ resource.h	17 Jul 2005 23:40:21 -0000	1.17
@@ -91,6 +91,7 @@
 	std::FILE *openNewStream(const char *filename) const;
 	int fileLength(const char *filename) const;
 
+	bool exportResource(const char *filename);
 	Bitmap *loadBitmap(const char *fname);
 	CMap *loadColormap(const char *fname);
 	Costume *loadCostume(const char *fname, Costume *prevCost);

Index: scene.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/scene.cpp,v
retrieving revision 1.43
retrieving revision 1.44
diff -u -d -r1.43 -r1.44
--- scene.cpp	10 Jul 2005 18:57:27 -0000	1.43
+++ scene.cpp	17 Jul 2005 23:40:21 -0000	1.44
@@ -111,17 +111,25 @@
 
 	ts.scanString(" background %256s", 1, buf);
 	_bkgndBm = g_resourceloader->loadBitmap(buf);
-	if(debugLevel == DEBUG_BITMAPS || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
-		printf("Loading scene bitmap: %s\n", buf);
+	if (_bkgndBm == NULL) {
+		if (debugLevel == DEBUG_BITMAPS || debugLevel == DEBUG_ERROR || debugLevel == DEBUG_ALL)
+			printf("Unable to load scene bitmap: %s\n", buf);
+	} else {
+		if (debugLevel == DEBUG_BITMAPS || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+			printf("Loaded scene bitmap: %s\n", buf);
+	}
 
 	// ZBuffer is optional
 	if (!ts.checkString("zbuffer")) {
 		_bkgndZBm = NULL;
 	} else {
 		ts.scanString(" zbuffer %256s", 1, buf);
-		_bkgndZBm = g_resourceloader->loadBitmap(buf);
-		if(debugLevel == DEBUG_BITMAPS || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
-			printf("Loading scene z-buffer bitmap: %s\n", buf);
+		// Don't even try to load if it's the "none" bitmap
+		if (strcmp(buf, "<none>.lbm") != 0) {
+			_bkgndZBm = g_resourceloader->loadBitmap(buf);
+			if (debugLevel == DEBUG_BITMAPS || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("Loading scene z-buffer bitmap: %s\n", buf);
+		}
 	}
 
 	ts.scanString(" position %f %f %f", 3, &_pos.x(), &_pos.y(), &_pos.z());
@@ -186,6 +194,12 @@
 }
 
 void Scene::setSetup(int num) {
+	// Looks like num is zero-based so >= should work to find values
+	// that are out of the range of valid setups
+	if (num >= _numSetups || num < 0) {
+		error("Failed to change scene setup, value out of range!");
+		return;
+	}
 	_currSetup = _setups + num;
 }
 

Index: scene.h
===================================================================
RCS file: /cvsroot/scummvm/residual/scene.h,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- scene.h	10 Jul 2005 18:57:27 -0000	1.28
+++ scene.h	17 Jul 2005 23:40:21 -0000	1.29
@@ -47,10 +47,12 @@
 			_currSetup->_bkgndZBm->draw();
 
 		if (_currSetup->_bkgndBm == NULL) {
-			error("Null background for setup %s in %s", _currSetup->_name.c_str(), _name.c_str());
-			return;
-		} 
-		_currSetup->_bkgndBm->draw();
+			// This should fail softly, for some reason jumping to the signpost (sg) will load
+			// the scene in such a way that the background isn't immediately available
+			warning("Background hasn't loaded yet for setup %s in %s!", _currSetup->_name.c_str(), _name.c_str());
+		} else {
+			_currSetup->_bkgndBm->draw();
+		}
 	}
 	void drawBitmaps(ObjectState::Position stage);
 	void setupCamera() {

Index: smush.cpp
===================================================================
RCS file: /cvsroot/scummvm/residual/smush.cpp,v
retrieving revision 1.61
retrieving revision 1.62
diff -u -d -r1.61 -r1.62
--- smush.cpp	10 Jul 2005 18:57:27 -0000	1.61
+++ smush.cpp	17 Jul 2005 23:40:21 -0000	1.62
@@ -29,6 +29,9 @@
 #include <cstring>
 #include <zlib.h>
 
+#define ANNO_HEADER "MakeAnim animation type 'Bl16' parameters: "
+#define BUFFER_SIZE 16385
+
 Smush *g_smush;
 static uint16 smushDestTable[5786];
 
@@ -49,6 +52,7 @@
 	_videoFinished = false;
 	_videoPause = true;
 	_updateNeeded = false;
+	_startPos = NULL;
 	_stream = NULL;
 	_movieTime = 0;
 	_frame = 0;
@@ -65,6 +69,7 @@
 	_videoFinished = false;
 	_videoPause = false;
 	_updateNeeded = false;
+	_videoLooping = false;
 
 	assert(!_internalBuffer);
 	assert(!_externalBuffer);
@@ -88,6 +93,7 @@
 		_externalBuffer = NULL;
 	}
 
+	_videoLooping = false;
 	_videoFinished = true;
 	_videoPause = true;
 	if (_stream) {
@@ -129,10 +135,34 @@
 
 	tag = _file.readUint32BE();
 	if (tag == MKID_BE('ANNO')) {
-printf("Announcement!\n");
+		char *anno;
+		byte *data;
+		
 		size = _file.readUint32BE();
-		for (int l = 0; l < size; l++)
-			_file.readByte();
+		data = (byte *)malloc(size);
+		_file.read(data, size);
+		anno = (char *)data;
+		if (strncmp(anno, ANNO_HEADER, sizeof(ANNO_HEADER)-1) == 0) {
+			char *annoData = anno + sizeof(ANNO_HEADER);
+			int loop;
+			
+			// Examples:
+			//  Water streaming around boat from Manny's balcony
+			//  MakeAnim animation type 'Bl16' parameters: 10000;12000;100;1;0;0;0;0;25;0;
+			//  Water in front of the Blue Casket
+			//	MakeAnim animation type 'Bl16' parameters: 20000;25000;100;1;0;0;0;0;25;0;
+			if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("Announcement data: %s\n", anno);
+			sscanf(annoData, "%*d;%*d;%*d;%d;%*d;%*d;%*d;%*d;%*d;%*d;%*d;", &loop);
+			_videoLooping = (bool) loop;
+			_startPos = _file.getPos();
+			if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("_videoLooping: %d\n", _videoLooping);
+		} else {
+			if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("Announcement header not understood: %s\n", anno);
+		}
+		free(anno);
 		tag = _file.readUint32BE();
 	}
 
@@ -164,12 +194,19 @@
 	_updateNeeded = true;
 
 	_frame++;
+	_movieTime += _speed / 1000;
 	if (_frame == _nbframes) {
-		_videoFinished = true;
-		g_engine->setMode(ENGINE_MODE_NORMAL);
+		// If we're not supposed to loop (or looping fails) then end the video
+		if(!_videoLooping || !_file.setPos(_startPos)) {
+			_videoFinished = true;
+			g_engine->setMode(ENGINE_MODE_NORMAL);
+			return;
+		}
+		// If the position change succeeded then reset the frame number
+		// for some reason we need to set it to 1 instead of zero or we
+		// won't render a frame
+		_frame = 1;
 	}
-	
-	_movieTime += _speed / 1000;
 }
 
 void Smush::handleFramesHeader() {
@@ -260,9 +297,42 @@
 	close();
 }
 
+struct SAVEPOS *zlibFile::getPos() { 
+	struct SAVEPOS *pos;
+	long position = std::ftell(_handle);
+	
+	if (position == -1 && debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL) {
+		warning("zlibFile::open() unable to find start position!");
+		return NULL;
+	}
+	pos = (struct SAVEPOS *) malloc(sizeof(struct SAVEPOS));
+	pos->filePos = position;
+	inflateCopy(&pos->streamBuf, &_stream);
+	pos->tmpBuf = (char *)calloc(1, BUFFER_SIZE);
+	memcpy(pos->tmpBuf, _inBuf, BUFFER_SIZE);
+	return pos;
+}
+
+bool zlibFile::setPos(struct SAVEPOS *pos) { 
+	int ret;
+	if (_handle == NULL || pos == NULL) {
+		warning("Unable to rewind SMUSH movie (invalid handle)!");
+		return false;
+	}
+	ret = std::fseek(_handle, pos->filePos, SEEK_SET);
+	if (ret == -1) {
+		warning("Unable to rewind SMUSH movie (seek failed)! %m");
+		return false;
+	}
+	memcpy(_inBuf, pos->tmpBuf, BUFFER_SIZE);
+	inflateCopy(&_stream, &pos->streamBuf);
+	_fileDone = false;
+	return true;
+}
+
 bool zlibFile::open(const char *filename) {
 	char flags = 0;
-	_inBuf = (char *)calloc(1, 16385);
+	_inBuf = (char *)calloc(1, BUFFER_SIZE);
 
 	if (_handle) {
 		if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
@@ -287,8 +357,12 @@
 	fread(_inBuf, 6, sizeof(char), _handle);				// XFlags
 
 	// Xtra & Comment
-	if (((((flags & 0x04) != 0) || ((flags & 0x10) != 0))) && (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_ERROR || debugLevel == DEBUG_ALL))
-		error("zlibFile::open() Unsupported header flag");
+	if (((flags & 0x04) != 0) || ((flags & 0x10) != 0)) {
+		if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_ERROR || debugLevel == DEBUG_ALL) {
+			error("zlibFile::open() Unsupported header flag");
+		}
+		return false;
+	}
 
 	if ((flags & 0x08) != 0) {					// Orig. Name
 		do {
@@ -299,7 +373,7 @@
 	if ((flags & 0x02) != 0) // CRC
 		fread(_inBuf, 2, sizeof(char), _handle);
 
-	memset(_inBuf, 0, 16384);			// Zero buffer (debug)
+	memset(_inBuf, 0, BUFFER_SIZE-1);			// Zero buffer (debug)
 	_stream.zalloc = NULL;
 	_stream.zfree = NULL;
 	_stream.opaque = Z_NULL;
@@ -310,7 +384,7 @@
 	_stream.next_in = NULL;
 	_stream.next_out = NULL;
 	_stream.avail_in = 0;
-	_stream.avail_out = 16384;
+	_stream.avail_out = BUFFER_SIZE-1;
 
 	return true;
 }
@@ -350,7 +424,7 @@
 	_fileDone = false;
 	while (_stream.avail_out != 0) {
 		if (_stream.avail_in == 0) {	// !eof
-	        	_stream.avail_in = fread(_inBuf, 1, 16384, _handle);
+			_stream.avail_in = fread(_inBuf, 1, BUFFER_SIZE-1, _handle);
 			if (_stream.avail_in == 0) {
 				fileEOF = true;
 				break;
@@ -360,8 +434,10 @@
 
 		result = inflate(&_stream, Z_NO_FLUSH);
 		if (result == Z_STREAM_END) {	// EOF
-			if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_WARN || debugLevel == DEBUG_ALL)
-				warning("zlibFile::read() Stream ended");
+			// "Stream end" is zlib's way of saying that it's done after the current call,
+			// so as long as no calls are made after we've received this message we're OK
+			if (debugLevel == DEBUG_SMUSH || debugLevel == DEBUG_NORMAL || debugLevel == DEBUG_ALL)
+				printf("zlibFile::read() Stream ended\n");
 			_fileDone = true;
 			break;
 		}

Index: smush.h
===================================================================
RCS file: /cvsroot/scummvm/residual/smush.h,v
retrieving revision 1.24
retrieving revision 1.25
diff -u -d -r1.24 -r1.25
--- smush.h	1 Jan 2005 12:27:56 -0000	1.24
+++ smush.h	17 Jul 2005 23:40:21 -0000	1.25
@@ -29,6 +29,12 @@
 #include <zlib.h>
 #include <cstring>
 
+struct SAVEPOS {
+	long filePos;
+	z_stream streamBuf;
+	char *tmpBuf;
+};
+
 class zlibFile {
 private:
 	FILE *_handle;
@@ -39,7 +45,9 @@
 public:
 	zlibFile();
 	~zlibFile();
+	bool setPos(struct SAVEPOS *pos);
 	bool open(const char *filename);
+	struct SAVEPOS *getPos();
 	void close();
 	bool isOpen();
 
@@ -67,6 +75,8 @@
 	int _freq;
 	bool _videoFinished;
 	bool _videoPause;
+	bool _videoLooping;
+	struct SAVEPOS *_startPos;
 	int _x, _y;
 	int _width, _height;
 	byte *_internalBuffer, *_externalBuffer;





More information about the Scummvm-git-logs mailing list