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

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Sun Apr 20 16:47:37 CEST 2008


Revision: 31600
          http://scummvm.svn.sourceforge.net/scummvm/?rev=31600&view=rev
Author:   thebluegr
Date:     2008-04-20 07:47:37 -0700 (Sun, 20 Apr 2008)

Log Message:
-----------
Initial import of the work in progress M4 engine

Added Paths:
-----------
    scummvm/trunk/engines/m4/
    scummvm/trunk/engines/m4/actor.cpp
    scummvm/trunk/engines/m4/actor.h
    scummvm/trunk/engines/m4/animation.cpp
    scummvm/trunk/engines/m4/animation.h
    scummvm/trunk/engines/m4/assets.cpp
    scummvm/trunk/engines/m4/assets.h
    scummvm/trunk/engines/m4/burger_data.h
    scummvm/trunk/engines/m4/compression.cpp
    scummvm/trunk/engines/m4/compression.h
    scummvm/trunk/engines/m4/console.cpp
    scummvm/trunk/engines/m4/console.h
    scummvm/trunk/engines/m4/converse.cpp
    scummvm/trunk/engines/m4/converse.h
    scummvm/trunk/engines/m4/detection.cpp
    scummvm/trunk/engines/m4/events.cpp
    scummvm/trunk/engines/m4/events.h
    scummvm/trunk/engines/m4/font.cpp
    scummvm/trunk/engines/m4/font.h
    scummvm/trunk/engines/m4/globals.cpp
    scummvm/trunk/engines/m4/globals.h
    scummvm/trunk/engines/m4/graphics.cpp
    scummvm/trunk/engines/m4/graphics.h
    scummvm/trunk/engines/m4/gui.cpp
    scummvm/trunk/engines/m4/gui.h
    scummvm/trunk/engines/m4/hotspot.cpp
    scummvm/trunk/engines/m4/hotspot.h
    scummvm/trunk/engines/m4/m4.cpp
    scummvm/trunk/engines/m4/m4.h
    scummvm/trunk/engines/m4/m4_menus.cpp
    scummvm/trunk/engines/m4/m4_menus.h
    scummvm/trunk/engines/m4/m4_views.cpp
    scummvm/trunk/engines/m4/m4_views.h
    scummvm/trunk/engines/m4/mads_anim.cpp
    scummvm/trunk/engines/m4/mads_anim.h
    scummvm/trunk/engines/m4/mads_menus.cpp
    scummvm/trunk/engines/m4/mads_menus.h
    scummvm/trunk/engines/m4/midi.cpp
    scummvm/trunk/engines/m4/midi.h
    scummvm/trunk/engines/m4/module.mk
    scummvm/trunk/engines/m4/rails.cpp
    scummvm/trunk/engines/m4/rails.h
    scummvm/trunk/engines/m4/resource.cpp
    scummvm/trunk/engines/m4/resource.h
    scummvm/trunk/engines/m4/saveload.cpp
    scummvm/trunk/engines/m4/saveload.h
    scummvm/trunk/engines/m4/scene.cpp
    scummvm/trunk/engines/m4/scene.h
    scummvm/trunk/engines/m4/script.cpp
    scummvm/trunk/engines/m4/script.h
    scummvm/trunk/engines/m4/scripttab.h
    scummvm/trunk/engines/m4/sound.cpp
    scummvm/trunk/engines/m4/sound.h
    scummvm/trunk/engines/m4/sprite.cpp
    scummvm/trunk/engines/m4/sprite.h
    scummvm/trunk/engines/m4/viewmgr.cpp
    scummvm/trunk/engines/m4/viewmgr.h
    scummvm/trunk/engines/m4/woodscript.cpp
    scummvm/trunk/engines/m4/woodscript.h
    scummvm/trunk/engines/m4/ws_machine.cpp
    scummvm/trunk/engines/m4/ws_sequence.cpp

Added: scummvm/trunk/engines/m4/actor.cpp
===================================================================
--- scummvm/trunk/engines/m4/actor.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/actor.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,202 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/system.h"
+#include "common/array.h"
+#include "m4/actor.h"
+#include "m4/m4_views.h"
+#include "m4/assets.h"
+
+namespace M4 {
+
+#define WALKER_BURGER "Wilbur0%i"	// wilbur, with a number denoting his current direction
+
+Actor::Actor(M4Engine *vm) : _vm(vm) {
+	_scaling = 100;
+	_direction = 5;
+	_walkerSprites.resize(10);
+	loadWalkers();
+}
+
+Actor::~Actor() {
+	unloadWalkers();
+}
+
+int Actor::getWalkerWidth() { return _walkerSprites[kFacingSouth]->getFrame(0)->w; }
+int Actor::getWalkerHeight() { return _walkerSprites[kFacingSouth]->getFrame(0)->h; }
+
+void Actor::placeWalkerSpriteAt(int spriteNum, int x, int y) {
+	if (_direction < 1 || _direction > 9) {
+		warning("Direction is %i, fixing", _direction);
+		_direction = 1;		// TODO: this is a temporary fix
+	}
+	SpriteInfo info;
+	info.sprite = _walkerSprites[_direction]->getFrame(spriteNum);
+	info.hotX = info.hotY = 0;
+	info.width = info.sprite->w;
+	info.height = info.sprite->h;
+	info.scaleX = info.scaleY = _scaling;
+	info.palette = _walkerSprites[_direction]->getPalette();
+	info.inverseColorTable = _vm->_scene->getInverseColorTable();
+
+	_vm->_scene->drawSprite(x, y, info, Common::Rect(640, 400));
+}
+
+void Actor::loadWalkers() {
+	for (uint8 i = 1; i < 10; i++) {
+		if (i == 6)
+			continue;	// walker sprite 6 is unused
+		loadWalkerDirection(i);
+	}
+}
+
+void Actor::loadWalkerDirection(uint8 direction) {
+	char name[20];
+	Common::SeekableReadStream *walkerS;
+
+	if (_vm->getGameType() == GType_Burger) {
+		sprintf(name, WALKER_BURGER, direction);
+	} else {
+		//warning("Actor::loadWalkerDirection: unspecified walker type, not loading walker");
+		// TODO: Master Lu walkers
+		return;
+	}
+
+	walkerS = _vm->res()->get(name);
+	_walkerSprites.insert_at(direction, new SpriteAsset(_vm, walkerS, walkerS->size(), name));
+	_vm->res()->toss(name);
+}
+
+void Actor::unloadWalkers() {
+	for (uint8 i = 9; i > 0; i--) {
+		if (i == 6)
+			continue;	// walker sprite 6 is unused
+		SpriteAsset *tempSprite = _walkerSprites[i];
+		_walkerSprites.remove_at(i);
+		if (tempSprite)
+			delete tempSprite;
+	}
+}
+
+void Actor::setWalkerPalette() {
+	_vm->_palette->setPalette(_walkerSprites[kFacingSouthEast]->getPalette(), 0, 
+							  _walkerSprites[kFacingSouthEast]->getColorCount());
+}
+
+Inventory::Inventory(M4Engine *vm) : _vm(vm) {
+}
+
+Inventory::~Inventory() {
+	_inventory.clear();
+}
+
+void Inventory::registerObject(char* name, int32 scene, int32 icon) {
+	InventoryObject *newObject = new InventoryObject();
+	int newObjectIndex = 0;
+
+	// Capitalize registered inventory object names
+	str_upper(name);
+
+	newObject->name = strdup(name);
+	newObject->scene = scene;
+	newObject->icon = icon;
+
+	newObjectIndex = _inventory.size();
+
+	_inventory.push_back(newObject);
+
+	if (scene == BACKPACK)
+		addToBackpack(newObjectIndex);
+}
+
+void Inventory::moveObject(char* name, int32 scene) {
+	uint i = 0;
+
+	for (i = 0; i < _inventory.size(); i++) {
+		if (!scumm_stricmp(_inventory[i]->name, name)) {
+			if (_inventory[i]->scene == BACKPACK && scene != BACKPACK)
+				removeFromBackpack(i);
+
+			_inventory[i]->scene = scene;
+
+			if (scene == BACKPACK)
+				addToBackpack(i);
+
+			return;
+		}
+	}
+}
+
+void Inventory::addToBackpack(uint32 objectIndex) {
+	_vm->_interfaceView->inventoryAdd(_inventory[objectIndex]->name, "", _inventory[objectIndex]->icon);
+}
+
+void Inventory::removeFromBackpack(uint32 objectIndex) {
+	_vm->_interfaceView->inventoryRemove(_inventory[objectIndex]->name);
+}
+
+bool Inventory::isInCurrentScene(char* name) { 
+	return (getScene(name) == _vm->_scene->getCurrentScene());
+}
+
+int Inventory::getScene(char* name) {
+	uint i = 0;
+
+	for (i = 0; i < _inventory.size(); i++) {
+		if (!scumm_stricmp(_inventory[i]->name, name))
+			return _inventory[i]->scene;
+	}
+	return UNKNOWN_OBJECT;
+}
+
+int Inventory::getIcon(char* name) {
+	uint i = 0;
+
+	for (i = 0; i < _inventory.size(); i++) {
+		if (!scumm_stricmp(_inventory[i]->name, name))
+			return _inventory[i]->icon;
+	}
+	return UNKNOWN_OBJECT;
+}
+
+int Inventory::getIndex(char* name) {
+	uint i = 0;
+
+	for (i = 0; i < _inventory.size(); i++) {
+		if (!scumm_stricmp(_inventory[i]->name, name))
+			return i;
+	}
+	return UNKNOWN_OBJECT;
+}
+
+void Inventory::clear() {
+	for (uint i = 0; i < _inventory.size(); i++) {
+		delete _inventory[i]->name;
+		delete _inventory[i];
+		_inventory.remove_at(i);		
+	}
+}
+	
+} // End of namespace M4


Property changes on: scummvm/trunk/engines/m4/actor.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/actor.h
===================================================================
--- scummvm/trunk/engines/m4/actor.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/actor.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,117 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef M4_ACTOR_H
+#define M4_ACTOR_H
+
+#include "common/array.h"
+
+#include "m4/m4.h"
+#include "m4/scene.h"
+#include "m4/graphics.h"
+#include "m4/assets.h"
+
+namespace M4 {
+
+struct InventoryObject {
+	const char* name;
+	int32 scene;
+	int32 icon;
+};
+
+enum inventoryObjectFlags {
+	UNKNOWN_OBJECT = 997,
+	BACKPACK = 998,
+	NOWHERE = 999
+};
+
+enum WalkerDirection {
+	kFacingNorth		= 1,	// has shadow
+	kFacingNorthEast	= 2,	// has shadow
+	kFacingEast			= 3,	// has shadow
+	kFacingSouthEast	= 4,	// has shadow
+	kFacingSouth		= 5,	// has shadow
+	// 6 is unused
+	kFacingSouthAlt		= 7,	// no shadow
+	kFacingSouthWest	= 8,	// no shadow
+	kFacingWest			= 9		// no shadow
+};
+
+class Actor {
+public:
+	Actor(M4Engine *vm);
+	~Actor();
+	void placeWalkerSpriteAt(int spriteNum, int x, int y);
+	void setWalkerScaling(int scaling) { _scaling = scaling; }
+	int getWalkerScaling() { return _scaling; }
+	void setWalkerDirection(uint8 direction) { _direction = direction; }
+	uint8 getWalkerDirection() { return _direction; }
+	void setWalkerPalette();
+	int getWalkerWidth();
+	int getWalkerHeight();
+private:
+	M4Engine *_vm;
+	int _scaling;
+	uint8 _direction;
+	Common::Array<SpriteAsset*> _walkerSprites;
+
+	void loadWalkers();
+	void loadWalkerDirection(uint8 direction);
+	void unloadWalkers();
+};
+
+// TODO: perhaps the inventory and its view could be merged?
+// TODO: the original game capitalizes all inventory object names
+// internally, which we do as well, but perhaps we could make sure
+// that all object names are parsed with the same case and avoid
+// case-insensitive string comparing through scumm_stricmp, using 
+// the normal strcmp method instead
+class Inventory {
+public:
+	Inventory(M4Engine *vm);
+	~Inventory();
+	void clear();
+	void registerObject(char* name, int32 scene, int32 icon);
+	void moveObject(char* name, int32 scene);
+	void giveToPlayer(char* name) { moveObject(name, BACKPACK); }
+	void addToBackpack(uint32 objectIndex);
+	void removeFromBackpack(uint32 objectIndex);
+	bool isInBackpack(char* name) { return (getScene(name) == BACKPACK); }
+	bool isInScene(char* name, int32 scene) { return (getScene(name) == scene); }
+	bool isInCurrentScene(char* name);
+	int getScene(char* name);
+	int getIcon(char* name);
+	int getIndex(char* name);
+	int getTotalItems() { return _inventory.size(); }
+
+private:
+	M4Engine *_vm;
+	Common::Array<InventoryObject *> _inventory;
+};
+
+} // End of namespace M4
+
+
+#endif


Property changes on: scummvm/trunk/engines/m4/actor.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/animation.cpp
===================================================================
--- scummvm/trunk/engines/m4/animation.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/animation.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,210 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "m4/assets.h"
+#include "m4/animation.h"
+#include "m4/compression.h"
+
+namespace M4 {
+
+// TODO: this code needs cleanup
+
+Animation::Animation(M4Engine *vm) {
+	_vm = vm;
+	_playing = false;
+}
+
+void Animation::loadFullScreen(const char *filename) {
+	_vm->_palette->deleteAllRanges();
+	load(filename);
+}
+
+void Animation::load(const char *filename) {
+	MadsPack anim(filename, _vm);
+	char buffer[20];
+
+	// Chunk 1: header
+	// header
+	// TODO: there are some unknown fields here, plus we don't read
+	// the entire chunk
+	Common::SeekableReadStream *animStream = anim.getItemStream(0);
+	Common::SeekableReadStream *spriteSeriesStream;
+	//printf("Chunk 0, size %i\n", animStream->size());
+	_seriesCount = animStream->readUint16LE();
+	_frameCount = animStream->readUint16LE();
+	_frameEntryCount = animStream->readUint16LE();
+
+	// Unknown
+	for (int i = 0; i < 43; i++)
+		animStream->readByte();
+
+	_spriteSeriesNames = new Common::String[_seriesCount];
+	printf("%i sprite series\n", _seriesCount);
+
+	// TODO: for now, we only load the first sprite series
+	if (_seriesCount > 1)
+		printf("TODO: Anim has %i sprite series, for now, we only load the first one\n", _seriesCount);
+	_seriesCount = 1;		// TODO
+
+	for (int i = 0; i < _seriesCount; i++) {
+		animStream->read(buffer, 13);
+		_spriteSeriesNames[i] = Common::String(buffer);
+		//printf("%03d: %s\n", i, _spriteSeriesNames[i].c_str());
+
+		spriteSeriesStream = _vm->res()->get(_spriteSeriesNames[i].c_str());
+		_spriteSeries = new SpriteAsset(_vm, spriteSeriesStream, 
+										spriteSeriesStream->size(), _spriteSeriesNames[i].c_str());
+		_vm->res()->toss(_spriteSeriesNames[i].c_str());
+
+		// Adjust the palette of the sprites in the sprite series
+		// so that they can be displayed on screen correctly
+		RGBList *palData = new RGBList(_spriteSeries->getColorCount(), _spriteSeries->getPalette(), true);
+		_vm->_palette->addRange(palData);
+
+		for (int k = 0; k < _spriteSeries->getCount(); k++) {
+			M4Sprite *spr = _spriteSeries->getFrame(k);
+			spr->translate(palData);		// sprite pixel translation
+		}
+	}
+
+	//printf("End pos: %i\n", animStream->pos());
+
+	delete animStream;
+
+	// ------------------
+
+	// Chunk 2: anim info
+	AnimationFrame frame;
+	animStream = anim.getItemStream(1);
+	//printf("Chunk 1, size %i\n", animStream->size());
+
+	_frameEntries = new AnimationFrame[_frameEntryCount];
+	
+	for (int i = 0; i < _frameEntryCount; i++) {
+
+		frame.animFrameIndex = animStream->readUint16LE();
+		frame.u = animStream->readByte();
+		frame.seriesIndex = animStream->readByte();
+		frame.seriesFrameIndex = animStream->readUint16LE();
+		frame.x = animStream->readUint16LE();
+		frame.y = animStream->readUint16LE();
+		frame.v = animStream->readByte();
+		frame.w = animStream->readByte();
+		
+		_frameEntries[i] = frame;
+
+		/*
+		printf(
+		"animFrameIndex = %4d, "
+		"u = %3d, "
+		"seriesIndex = %3d, "
+		"seriesFrameIndex = %6d, "
+		"x = %3d, "
+		"y = %3d, "
+		"v = %3d, "
+		"w = %3d\n",
+
+		frame.animFrameIndex,
+		frame.u,
+		frame.seriesIndex,
+		frame.seriesFrameIndex,
+		frame.x,
+		frame.y,
+		frame.v,
+		frame.w
+		);
+		*/
+	}
+	//printf("End pos: %i\n", animStream->pos());
+
+	delete animStream;
+
+	// Chunk 3: unknown (seems to be sound data?)
+	// TODO
+}
+
+Animation::~Animation() {
+	//delete[] _spriteSeriesNames;
+	//delete[] _spriteSeries;
+	//delete[] _frameEntries;
+}
+
+void Animation::start() {
+	_curFrame = 0;
+	_curFrameEntry = 0;
+	//for (int i = 0; i < _seriesCount; i++) {
+		//_spriteSeries[i] = new SpriteSeries((char*)_spriteSeriesNames[i].c_str());
+	//}
+	_playing = true;
+	updateAnim();
+}
+
+bool Animation::updateAnim() {
+	if (!_playing)
+		return true;
+
+	// Get the scene background surface
+	M4Surface *bg = _vm->_scene->getBackgroundSurface();
+
+	while (_frameEntries[_curFrameEntry].animFrameIndex == _curFrame) {
+		AnimationFrame *frame = &_frameEntries[_curFrameEntry];
+		int seriesFrameIndex = (frame->seriesFrameIndex & 0x7FFF) - 1;
+
+		// Write the sprite onto the screen
+		M4Sprite *spr = _spriteSeries->getFrame(seriesFrameIndex);
+
+		// FIXME: We assume that the transparent color is the color of the top left pixel
+		byte *transparentColor = (byte *)spr->pixels;
+
+		// FIXME: correct x, y
+		spr->copyTo(bg, frame->x, frame->y, (int)*transparentColor);
+
+		// HACK: wait a bit
+		g_system->delayMillis(100);
+
+		//printf("_curFrameEntry = %d\n", _curFrameEntry);
+		_curFrameEntry++;
+	}
+	
+	//printf("_curFrame = %d\n", _curFrame);
+
+	_curFrame++;
+	if (_curFrame >= _frameCount)		// anim done
+		stop();
+
+	return _curFrame >= _frameCount;
+}
+
+void Animation::stop() {
+	_playing = false;
+
+	for (int i = 0; i < _seriesCount; i++) {
+		// TODO: cleanup
+		//delete _spriteSeries[i];
+		//_spriteSeries[i] = NULL;
+	}
+}
+
+} // End of namespace M4


Property changes on: scummvm/trunk/engines/m4/animation.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/animation.h
===================================================================
--- scummvm/trunk/engines/m4/animation.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/animation.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,69 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef M4_ANIMATION_H
+#define M4_ANIMATION_H
+
+#include "m4/m4.h"
+#include "m4/graphics.h"
+#include "m4/assets.h"
+
+namespace M4 {
+
+struct AnimationFrame {
+    uint16 animFrameIndex;
+    byte u;
+    byte seriesIndex;
+    uint16 seriesFrameIndex;
+    uint16 x, y;
+    byte v, w;
+};
+
+class Animation {
+    public:
+		Animation(M4Engine *vm);
+        ~Animation();
+
+        void load(const char *filename);
+		void loadFullScreen(const char *filename);
+        void start();
+        bool updateAnim();
+        void stop();
+        
+    private:
+		bool _playing;
+		M4Engine *_vm;
+        int _seriesCount;
+        int _frameCount;
+        int _frameEntryCount;
+        AnimationFrame *_frameEntries;
+        Common::String *_spriteSeriesNames;
+        SpriteAsset *_spriteSeries;
+        int _curFrame, _curFrameEntry;
+};
+
+} // End of namespace M4
+
+#endif


Property changes on: scummvm/trunk/engines/m4/animation.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/assets.cpp
===================================================================
--- scummvm/trunk/engines/m4/assets.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/assets.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,544 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "m4/assets.h"
+#include "m4/globals.h"
+#include "m4/compression.h"
+
+namespace M4 {
+
+BaseAsset::BaseAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : _vm(vm) {
+}
+
+BaseAsset::~BaseAsset() {
+}
+
+MachineAsset::MachineAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+	uint32 stateCount = stream->readUint32LE();
+	for (uint32 curState = 0; curState < stateCount; curState++) {
+		uint32 stateOffset = stream->readUint32LE();
+		_stateTable.push_back(stateOffset);
+	}
+	_codeSize = size - 4 - 4 * stateCount;
+	_code = new byte[_codeSize];
+	stream->read(_code, _codeSize);
+}
+
+MachineAsset::~MachineAsset() {
+	delete[] _code;
+}
+
+void MachineAsset::getCode(byte *&code, uint32 &codeSize) {
+	code = _code;
+	codeSize = _codeSize;
+}
+
+uint32 MachineAsset::getStateOffset(uint32 state) {
+	assert(state < _stateTable.size());
+	return _stateTable[state];
+}
+
+SequenceAsset::SequenceAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+	_localVarCount = stream->readUint32LE();
+	_codeSize = size - 4;
+	_code = new byte[_codeSize];
+	stream->read(_code, _codeSize);
+}
+
+SequenceAsset::~SequenceAsset() {
+	delete[] _code;
+}
+
+void SequenceAsset::getCode(byte *&code, uint32 &codeSize) {
+	code = _code;
+	codeSize = _codeSize;
+}
+
+
+DataAsset::DataAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name) : BaseAsset(vm, stream, size, name) {
+
+	_recCount = stream->readUint32LE();
+	_recSize = stream->readUint32LE();
+	_dataSize = _recCount * _recSize;
+	_data = new long[_dataSize];
+	for (uint32 i = 0; i < _dataSize; i++)
+		_data[i] = (long)stream->readUint32LE();
+
+}
+
+DataAsset::~DataAsset() {
+	delete _data;
+}
+
+long *DataAsset::getRow(int index) {
+	assert(index < _recCount);
+	return &_data[_recSize * index];
+}
+
+SpriteAsset::SpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream) : BaseAsset(vm, stream, size, name) {
+	_stream = stream;
+
+	if (_vm->isM4()) {
+		loadM4SpriteAsset(vm, stream, asStream);
+	} else {
+		loadMadsSpriteAsset(vm, stream);
+	}
+}
+
+void SpriteAsset::loadM4SpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream, bool asStream) {
+	bool isBigEndian = false;
+	uint32 frameOffset;
+
+	uint32 header = _stream->readUint32LE();
+	if (header == HEAD_M4SS) {
+		printf("LE-encoded sprite\n");
+	} else {
+		printf("BE-encoded sprite\n");
+		isBigEndian = true;
+	}
+
+	_srcSize = parseSprite(isBigEndian);
+
+	_stream->readUint32LE();
+	_frameRate = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	_pixelSpeed = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	_maxWidth = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	_maxHeight = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	_stream->skip(6 * 4);
+	_frameCount = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+
+	printf("SpriteAsset::SpriteAsset() srcSize = %d; frameRate = %04X; pixelSpeed = %04X; maxWidth = %d; maxHeight = %d; frameCount = %d\n", _srcSize, _frameRate, _pixelSpeed, _maxWidth, _maxHeight, _frameCount);
+
+	for (int curFrame = 0; curFrame < _frameCount; curFrame++) {
+		frameOffset = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+		_frameOffsets.push_back(frameOffset);
+	}
+	_frameOffsets.push_back(_srcSize - 48 - _frameCount * 4);
+
+	_frameStartOffset = _stream->pos();
+
+	// We don't need to load frames when streaming
+	if (asStream)
+		return;
+
+	for (int curFrame = 0; curFrame < _frameCount; curFrame++) {
+		frameOffset = _frameStartOffset + _frameOffsets[curFrame];
+		_stream->seek(frameOffset);
+
+		SpriteAssetFrame frame;
+		loadFrameHeader(frame, isBigEndian);
+
+		// Load & unpack RLE data if it's not a streaming animation
+		if (frame.stream != 1) {
+		
+			frame.frame = new M4Sprite(stream, frame.x, frame.y, frame.w, frame.h, true, frame.comp);
+#if 0
+			char fn[512];
+			sprintf(fn, "%04d.raw", curFrame);
+			FILE *h = fopen(fn, "wb");
+			fwrite((byte*)frame.frame->getData(), frame.w * frame.h, 1, h);
+			fclose(h);
+#endif
+		}
+
+		_frames.push_back(frame);
+
+	}
+
+}
+
+void SpriteAsset::loadMadsSpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream) {
+	int curFrame = 0;
+	uint32 frameOffset = 0;
+	MadsPack sprite(stream);
+	_frameRate = 0;
+	_pixelSpeed = 0;
+	_maxWidth = 0;
+	_maxHeight = 0;
+
+	Common::SeekableReadStream *spriteStream = sprite.getItemStream(0);
+	for (int i = 0; i < 19; i++) {
+		spriteStream->readUint16LE();
+	}
+	_frameCount = spriteStream->readUint16LE();
+	// we skip the rest of the data
+	delete spriteStream;
+
+	// Get the palette data
+	spriteStream = sprite.getItemStream(2);
+	int numColors = 0;
+	RGB8 *palData = Palette::decodeMadsPalette(spriteStream, &numColors);
+	Common::copy(palData, &palData[numColors], &_palette[0]);
+	if (numColors < 256) 
+		Common::set_to((byte *)&_palette[numColors], (byte *)&_palette[256], 0);
+	_colorCount = numColors;
+	delete[] palData;
+	delete spriteStream;
+
+	spriteStream = sprite.getItemStream(1);
+	Common::SeekableReadStream *spriteDataStream = sprite.getItemStream(3);
+	SpriteAssetFrame frame;
+	for (curFrame = 0; curFrame < _frameCount; curFrame++) {
+		frame.comp = 0;
+		frameOffset = spriteStream->readUint32LE();
+		_frameOffsets.push_back(frameOffset);
+		spriteStream->readUint32LE();	// frame size
+		frame.x = spriteStream->readUint16LE();
+		frame.y = spriteStream->readUint16LE();
+		frame.w = spriteStream->readUint16LE();
+		frame.h = spriteStream->readUint16LE();
+		if (curFrame == 0)
+			printf("%i frames, x = %i, y = %i, w = %i, h = %i\n", _frameCount, frame.x, frame.y, frame.w, frame.h);
+
+		frame.frame = new M4Sprite(spriteDataStream, frame.x, frame.y, frame.w, frame.h, false);
+		_frames.push_back(frame);
+	}
+	delete spriteStream;
+	delete spriteDataStream;
+}
+
+SpriteAsset::~SpriteAsset() {
+	for (Common::Array<SpriteAssetFrame>::iterator it = _frames.begin(); it != _frames.end(); it++) {
+		delete (*it).frame;
+	}
+}
+
+int32 SpriteAsset::parseSprite(bool isBigEndian) {
+
+	uint32 format, chunkType, chunkSize = 0;
+
+	_colorCount = 0;
+
+	format = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+
+	chunkType = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+
+	if (chunkType == CELS__PAL) {
+		chunkSize = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+		uint32 numColors = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+		// TODO
+		//if (palette) {
+			// TODO: A sprite set palette specifies the indexes, which need not start at 
+			// index 0. For now, I'm simply preloading the currently active palette
+			// before starting to replace existing entries
+
+			_vm->_palette->grabPalette((byte *) _palette, 0, 256);
+			_colorCount = 0;
+
+			for (uint32 i = 0; i < numColors; i++) {
+				uint32 paletteEntry = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+				uint index = (paletteEntry >> 24) & 0xFF;
+
+				_palette[index].r = ((paletteEntry >> 16) & 0xFF) << 2;
+				_palette[index].g = ((paletteEntry >> 8) & 0xFF) << 2;
+				_palette[index].b = (paletteEntry & 0xFF) << 2;
+
+				_colorCount = MAX(_colorCount, index);
+			}
+
+		/*
+		} else {
+			stream.seek(colorCount, )
+			data += colorCount * 4;
+		}
+		*/
+		chunkType = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	}
+
+	if (chunkType == CELS___SS) {
+		chunkSize = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	} else {
+		warning("SpriteAsset::parseSprite() Expected chunk type %08X, got %08X", CELS___SS, chunkType);
+	}
+
+	return chunkSize;
+
+}
+
+void SpriteAsset::loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndian) {
+	_stream->readUint32LE();
+	frameHeader.stream = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.x = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.y = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.w = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.h = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.comp = (!isBigEndian) ? _stream->readUint32LE() : _stream->readUint32BE();
+	frameHeader.frame = NULL;
+	_stream->seek(8 * 4, SEEK_CUR);
+	//printf("SpriteAsset::loadFrameHeader() stream = %d; x = %d; y = %d; w = %d; h = %d; comp = %d\n", frameHeader.stream, frameHeader.x, frameHeader.y, frameHeader.w, frameHeader.h, frameHeader.comp);
+}
+
+M4Sprite *SpriteAsset::getFrame(int frameIndex) {
+	return _frames[frameIndex].frame;
+}
+
+void SpriteAsset::loadStreamingFrame(M4Sprite *frame, int frameIndex, int destX, int destY) {
+	uint32 frameOffset = _frameStartOffset + _frameOffsets[frameIndex];
+	_stream->seek(frameOffset);
+
+	SpriteAssetFrame frameHeader;
+	loadFrameHeader(frameHeader);
+
+	if (frameHeader.w > 0 && frameHeader.h > 0) {
+		Common::MemoryReadStream *frameData = _stream->readStream(getFrameSize(frameIndex));
+		if (frameHeader.stream) {
+			frame->loadDeltaRle(frameData, destX - frameHeader.x, destY - frameHeader.y);
+		} else {
+			frame->loadRle(frameData);
+		}
+		delete frameData;
+	}
+
+}
+
+RGBList *SpriteAsset::getRgbList() {
+	RGBList *result = new RGBList(_colorCount);
+	Common::copy((byte *)&_palette[0], (byte *)&_palette[_colorCount], (byte *)result->data());
+	return result;
+}
+
+void SpriteAsset::translate(RGBList *list, bool isTransparent) {
+	for (int frameIndex = 0; frameIndex < _frameCount; ++frameIndex) 
+		_frames[frameIndex].frame->translate(list, isTransparent);
+}
+
+int32 SpriteAsset::getFrameSize(int index) {
+	/*
+	if (index + 1 == _frameCount) {
+	} else {
+	
+	}
+	*/
+	return _frameOffsets[index + 1] - _frameOffsets[index];
+}
+
+AssetManager::AssetManager(M4Engine *vm) {
+
+	_vm = vm;
+
+	/* Initialize asset arrays */
+	for (int i = 0; i < 256; i++) {
+		_MACH[i] = NULL;
+		_SEQU[i] = NULL;
+		_DATA[i] = NULL;
+		_CELS[i] = NULL;
+	}
+
+}
+
+AssetManager::~AssetManager() {
+	// unload all remaining assets
+	clearAssets(kAssetTypeMACH, 0, 255);
+	clearAssets(kAssetTypeSEQU, 0, 255);
+	clearAssets(kAssetTypeCELS, 0, 255);
+	clearAssets(kAssetTypeDATA, 0, 255);
+}
+
+bool AssetManager::clearAssets(AssetType assetType, int32 minHash, int32 maxHash) {
+
+	minHash = MAX(0, minHash);
+	maxHash = MIN(maxHash, 255);
+
+	switch (assetType) {
+	case kAssetTypeMACH:
+		for (int i = minHash; i <= maxHash; i++)
+			if (_MACH[i]) {
+				delete _MACH[i];
+				_MACH[i] = NULL;
+			}
+		break;
+	case kAssetTypeSEQU:
+		for (int i = minHash; i <= maxHash; i++)
+			if (_SEQU[i]) {
+				delete _SEQU[i];
+				_SEQU[i] = NULL;
+			}
+		break;
+	case kAssetTypeDATA:
+		for (int i = minHash; i <= maxHash; i++)
+			if (_DATA[i]) {
+				delete _DATA[i];
+				_DATA[i] = NULL;
+			}
+		break;
+	case kAssetTypeCELS:
+		for (int i = minHash; i <= maxHash; i++)
+			if (_CELS[i]) {
+				delete _CELS[i];
+				_CELS[i] = NULL;
+			}
+		break;
+	}
+
+	// FIXME: no value is returned, returning true for now
+	return true;
+}
+
+bool AssetManager::loadAsset(const char *assetName, RGB8 *palette) {
+
+	printf("AssetManager::loadAsset() %s\n", assetName);
+
+	// TODO, better use MemoryReadStreamEndian?
+	//convertAssetToLE(assetData, assetSize);
+
+	Common::SeekableReadStream *assetS = _vm->res()->get(assetName);
+
+	while (assetS->pos() + 12 < assetS->size()) {
+		uint32 chunkType, chunkSize, chunkHash;
+
+		chunkType = assetS->readUint32LE();
+		chunkSize = assetS->readUint32LE() - 12; // sub 12 for the chunk header
+		chunkHash = assetS->readUint32LE();
+
+		printf("hash = %d\n", chunkHash);
+
+		// Until loading code is complete, so that chunks not fully read are skipped correctly
+		uint32 nextOfs = assetS->pos() + chunkSize;
+		
+		switch (chunkType) {
+		case CHUNK_MACH:
+			printf("MACH\n");
+			clearAssets(kAssetTypeMACH, chunkHash, chunkHash);
+			_MACH[chunkHash] = new MachineAsset(_vm, assetS, chunkSize, assetName);
+			break;
+		case CHUNK_SEQU:
+			printf("SEQU\n");
+			clearAssets(kAssetTypeSEQU, chunkHash, chunkHash);
+			_SEQU[chunkHash] = new SequenceAsset(_vm, assetS, chunkSize, assetName);
+			break;
+		case CHUNK_DATA:
+			printf("DATA\n");
+			clearAssets(kAssetTypeDATA, chunkHash, chunkHash);
+			_DATA[chunkHash] = new DataAsset(_vm, assetS, chunkSize, assetName);
+			break;
+		case CHUNK_CELS:
+			printf("CELS\n");
+			clearAssets(kAssetTypeCELS, chunkHash, chunkHash);
+			_CELS[chunkHash] = new SpriteAsset(_vm, assetS, chunkSize, assetName);
+			break;
+		default:
+			printf("AssetManager::loadAsset() Unknown chunk type %08X\n", chunkType);
+		}
+
+		// Until loading code is complete (see above)
+		assetS->seek(nextOfs);
+
+	}
+
+	_vm->res()->toss(assetName);
+
+	// FIXME: no value is returned, returning true for now
+	return true;
+}
+
+int32 AssetManager::addSpriteAsset(const char *assetName, int32 hash, RGB8 *palette) {
+
+	bool alreadyLoaded = false;
+
+	if (hash < 0) {
+		for (int i = 0; i <= 255; i++) {
+			if (_CELS[i] != NULL) {
+				if (_CELS[i]->getName() == assetName) {
+					alreadyLoaded = true;
+					hash = i;
+					break;
+				}
+			} else {
+				hash = i;
+				break;
+			}
+		}
+	} else {
+		alreadyLoaded = _CELS[hash] != NULL && _CELS[hash]->getName() == assetName;
+	}
+
+	/* Not loaded and no empty slots */
+	if (hash < 0)
+		return -1;
+
+	if (!alreadyLoaded) {
+
+		printf("AssetManager::addSpriteAsset() asset %s not loaded, loading into %d\n", assetName, hash);
+
+		clearAssets(kAssetTypeCELS, hash, hash);
+			
+		Common::SeekableReadStream *assetS = _vm->res()->get(assetName);
+		_CELS[hash] = new SpriteAsset(_vm, assetS, assetS->size(), assetName);
+		_vm->res()->toss(assetName);
+
+	} else {
+
+		printf("AssetManager::addSpriteAsset()  asset %s already loaded in %d\n", assetName, hash);
+
+		/* TODO/FIXME
+		if (_CELS[hash].palOffset >= 0 && palette)
+			restorePalette(palette, _CELS[hash].data + _CELS[hash].palOffset);
+		*/
+
+	}
+
+	return hash;
+
+}
+
+void AssetManager::restorePalette(RGB8 *palette, byte *data) {
+	// TODO
+}
+
+void AssetManager::convertAssetToLE(byte *assetData, uint32 assetSize) {
+
+}
+
+MachineAsset *AssetManager::getMachine(int32 hash) {
+	assert(_MACH[hash] != NULL);
+	return _MACH[hash];
+}
+
+SequenceAsset *AssetManager::getSequence(int32 hash) {
+	assert(_SEQU[hash] != NULL);
+	return _SEQU[hash];
+}
+
+DataAsset *AssetManager::getData(int32 hash) {
+	assert(_DATA[hash] != NULL);
+	return _DATA[hash];
+}
+
+SpriteAsset *AssetManager::getSprite(int32 hash) {
+	assert(_CELS[hash] != NULL);
+	return _CELS[hash];
+}
+
+M4Sprite *AssetManager::getSpriteFrame(int32 hash, int frameIndex) {
+	assert(_CELS[hash] != NULL);
+	return _CELS[hash]->getFrame(frameIndex);
+}
+
+int32 AssetManager::getSpriteFrameCount(int32 hash) {
+	assert(_CELS[hash] != NULL);
+	return _CELS[hash]->getCount();
+}
+
+} // End of namespace M4


Property changes on: scummvm/trunk/engines/m4/assets.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/assets.h
===================================================================
--- scummvm/trunk/engines/m4/assets.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/assets.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,184 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+#ifndef M4_ASSETS_H
+#define M4_ASSETS_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+
+#include "m4/sprite.h"
+
+namespace M4 {
+	
+// Sequence chunks
+#define CHUNK_SCEN MKID_BE('SCEN')
+#define CHUNK_MACH MKID_BE('MACH')
+#define CHUNK_SEQU MKID_BE('SEQU')
+#define CHUNK_DATA MKID_BE('DATA')
+#define CHUNK_CELS MKID_BE('CELS')
+
+// Sprite chunks
+#define HEAD_M4SS MKID_BE('M4SS')	//'M4SS'
+#define CELS__PAL MKID_BE(' PAL')	//' PAL'
+#define CELS___SS MKID_BE('  SS')	//'  SS'
+
+class M4Engine;
+
+class BaseAsset {
+public:
+	BaseAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+	~BaseAsset();
+	const Common::String getName() const { return _name; }
+protected:
+	M4Engine *_vm;
+	Common::String _name;
+};
+
+class MachineAsset : public BaseAsset {
+public:
+	MachineAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+	~MachineAsset();
+	void getCode(byte *&code, uint32 &codeSize);
+	uint32 getStateOffset(uint32 state);
+protected:
+	Common::Array<uint32> _stateTable;
+	byte *_code;
+	uint32 _codeSize;
+};
+
+class SequenceAsset : public BaseAsset {
+public:
+	SequenceAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+	~SequenceAsset();
+	void getCode(byte *&code, uint32 &codeSize);
+	int localVarCount() const { return _localVarCount; }
+protected:
+	int _localVarCount;
+	byte *_code;
+	uint32 _codeSize;
+};
+
+class DataAsset : public BaseAsset {
+public:
+	DataAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name);
+	~DataAsset();
+	int getCount() const { return _recCount; }
+	long *getRow(int index);
+protected:
+	long *_data;
+	uint32 _recSize, _dataSize;
+	int _recCount;
+};
+
+struct SpriteAssetFrame {
+	uint32 stream;
+	int x, y, w, h;
+	uint32 comp;
+	M4Sprite *frame;
+};
+
+class SpriteAsset : public BaseAsset {
+public:
+	SpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream, int size, const char *name, bool asStream = false);
+	~SpriteAsset();
+	void loadM4SpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream, bool asStream);
+	void loadMadsSpriteAsset(M4Engine *vm, Common::SeekableReadStream* stream);
+	int32 getCount() { return _frameCount; }
+	int32 getFrameRate() const { return _frameRate; }
+	int32 getPixelSpeed() const { return _pixelSpeed; }
+	int32 getFrameWidth(int index);
+	int32 getFrameHeight(int index);
+	int32 getMaxFrameWidth() const { return _maxWidth; }
+	int32 getMaxFrameHeight() const { return _maxHeight; }
+	M4Sprite *getFrame(int frameIndex);
+	void loadStreamingFrame(M4Sprite *frame, int frameIndex, int destX, int destY);
+	RGB8* getPalette() { return _palette; }
+	int getColorCount() { return _colorCount; }
+	RGBList *getRgbList();
+	void translate(RGBList *list, bool isTransparent = false);
+	int32 getFrameSize(int index);
+	M4Sprite *operator[](int index) { return getFrame(index); }
+protected:
+	RGB8 _palette[256];
+	uint32 _colorCount;
+	uint32 _srcSize;
+	int32 _frameRate, _pixelSpeed;
+	int _maxWidth, _maxHeight;
+	int _frameCount;
+	Common::Array<uint32> _frameOffsets;
+	Common::Array<SpriteAssetFrame> _frames;
+	uint32 _frameStartOffset;
+	Common::SeekableReadStream *_stream;
+	int32 parseSprite(bool isBigEndian = false);
+	void loadFrameHeader(SpriteAssetFrame &frameHeader, bool isBigEndian = false);
+};
+
+enum AssetType {
+	kAssetTypeMACH,
+	kAssetTypeSEQU,
+	kAssetTypeDATA,
+	kAssetTypeCELS
+};
+
+enum CallbackHandlers {
+	kCallbackTriggerDispatch
+};
+
+class AssetManager {
+public:
+
+	AssetManager(M4Engine *vm);
+	~AssetManager();
+
+	bool clearAssets(AssetType assetType, int32 minHash, int32 maxHash);
+	bool loadAsset(const char *assetName, RGB8 *palette);
+	int32 addSpriteAsset(const char *assetName, int32 hash, RGB8 *palette);
+
+	// TODO: Move to Palette class
+	void restorePalette(RGB8 *palette, byte *data);
+
+	MachineAsset *getMachine(int32 hash);
+	SequenceAsset *getSequence(int32 hash);
+	DataAsset *getData(int32 hash);
+	SpriteAsset *getSprite(int32 hash);
+	M4Sprite *getSpriteFrame(int32 hash, int frameIndex);
+	int32 getSpriteFrameCount(int32 hash);
+
+protected:
+	// TODO: Check if we need _vm
+	M4Engine *_vm;
+
+	MachineAsset *_MACH[256];
+	SequenceAsset *_SEQU[256];
+	DataAsset *_DATA[256];
+	SpriteAsset *_CELS[256];
+
+	void convertAssetToLE(byte *assetData, uint32 assetSize);
+
+};
+
+} // End of namespace M4
+
+#endif


Property changes on: scummvm/trunk/engines/m4/assets.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/burger_data.h
===================================================================
--- scummvm/trunk/engines/m4/burger_data.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/burger_data.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,85 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef M4_BURGER_DATA_H
+#define M4_BURGER_DATA_H
+
+#include "m4/graphics.h"
+#include "m4/actor.h"
+
+namespace M4 {
+
+InventoryObject burger_inventory [] = {
+	// name 					scene	icon
+	//--------------------		-----	-----
+	{ "empty jug",				303,	14 },
+	{ "distilled juice",		999,	15 },
+	{ "broken puz dispenser",	999,	16 },
+	{ "puz dispenser",			999,	17 },
+	{ "broken mouse trap",		999,	18 },
+	{ "mouse trap",				999,	19 },
+	{ "kindling",				999,	20 },
+	{ "burning kindling", 		999,	21 },
+	{ "lights",					508,	22 },
+	{ "lights on",				508,	23 },
+	{ "bottle",					999,	24 },
+	{ "carrot juice",			999,	25 },
+	{ "soapy water",			999,	26 },
+	{ "iron filings",			999,	27 },
+	{ "waxed hair",				999,	28 },
+	{ "fish",					999,	29 },
+	{ "hook",					999,	30 },
+	{ "keys",					999,	31 },
+	{ "records",				999,	32 },
+	{ "collar",					999,	33 },
+	{ "amp",					999,	34 },
+	{ "rubber gloves",			999,	35 },
+	{ "sock",					504,	36 },
+	{ "jaws of life",			999,	37 },
+	{ "deed",					999,	38 },
+	{ "burger morsel",			999,	39 },
+	{ "whistle",				999,	40 },
+	{ "coin",					999,	41 },
+	{ "matches",				999,	42 },
+	{ "phone cord",				999,	43 },
+	{ "kibble",					602,	44 },		// picked up from tray
+	{ "pantyhose",				999,	45 },
+	{ "fan belt",				999,	46 },
+	{ "spring",					999,	47 },
+	{ "mirror",					999,	48 },
+	{ "grate",					999,	49 },
+	{ "ray gun",				604,	50 },		// given to Wilbur when he enters 604
+	{ "grasshoppers",			999,	51 },
+	{ "rolling pin",			999,	52 },
+	{ "rubber duck",			999,	53 },
+	{ "ladder",					999,	54 },
+	{ "money",					999,	55 },
+	{ "crow bar",				999,	56 },
+	{ "Wilbur",					999,	57 }
+};
+
+} // End of namespace M4
+
+#endif


Property changes on: scummvm/trunk/engines/m4/burger_data.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/compression.cpp
===================================================================
--- scummvm/trunk/engines/m4/compression.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/compression.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,189 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "m4/compression.h"
+#include "m4/m4.h"
+
+namespace M4 {
+
+const char *madsPackString = "MADSPACK";
+
+bool MadsPack::isCompressed(Common::SeekableReadStream *stream) {
+	// Check whether the passed stream is packed
+
+	char tempBuffer[8];
+	stream->seek(0);
+	if (stream->read(tempBuffer, 8) == 8) {
+		if (!strncmp(tempBuffer, madsPackString, 8)) 
+			return true;
+	}
+
+	return false;
+}
+
+MadsPack::MadsPack(Common::SeekableReadStream *stream) {
+	initialise(stream);
+}
+
+MadsPack::MadsPack(const char *resourceName, M4Engine* vm) {
+	Common::SeekableReadStream *stream = vm->_resourceManager->get(resourceName);
+	initialise(stream);
+	vm->_resourceManager->toss(resourceName);
+}
+
+void MadsPack::initialise(Common::SeekableReadStream *stream) {
+	if (!MadsPack::isCompressed(stream))
+		error("Attempted to decompress a resource that was not MadsPacked");
+
+	stream->seek(14);
+	_count = stream->readUint16LE();
+	_items = new MadsPackEntry[_count];
+	
+	byte *headerData = new byte[0xA0];
+	byte *header = headerData;
+	stream->read(headerData, 0xA0);
+
+	for (int i = 0; i < _count; ++i, header += 10) {
+		// Get header data
+		_items[i].hash = READ_LE_UINT16(header);
+		_items[i].size = READ_LE_UINT32(header + 2);
+		_items[i].compressedSize = READ_LE_UINT32(header + 6);
+
+		_items[i].data = new byte[_items[i].size];
+		if (_items[i].size == _items[i].compressedSize) {
+			// Entry isn't compressed
+			stream->read(_items[i].data, _items[i].size);
+		} else {
+			// Decompress the entry
+			byte *compressedData = new byte[_items[i].compressedSize];
+			stream->read(compressedData, _items[i].compressedSize);
+			
+			FabDecompressor fab;
+			fab.decompress(compressedData, _items[i].compressedSize, _items[i].data, _items[i].size);
+			delete[] compressedData;
+		}
+	}
+
+	delete[] headerData;
+	_dataOffset = stream->pos();
+}
+
+MadsPack::~MadsPack() {
+	for (int i = 0; i < _count; ++i)
+		delete[] _items[i].data;
+	delete[] _items;
+}
+
+//--------------------------------------------------------------------------
+
+const char *FabInputExceededError = "FabDecompressor - Passed end of input buffer during decompression";
+const char *FabOutputExceededError = "FabDecompressor - Decompressed data exceeded specified size";
+
+void FabDecompressor::decompress(const byte *srcData, int srcSize, byte *destData, int destSize) {
+	byte copyLen, copyOfsShift, copyOfsMask, copyLenMask;
+	unsigned long copyOfs;
+	byte *destP;
+	
+	// Validate that the data starts with the FAB header
+	if (strncmp((const char *)srcData, "FAB", 3) != 0)
+		error("FabDecompressor - Invalid compressed data");
+
+	int shiftVal = srcData[3];
+	if ((shiftVal < 10) || (shiftVal > 13))
+		error("FabDecompressor - Invalid shift start");
+
+	copyOfsShift = 16 - shiftVal;
+	copyOfsMask = 0xFF << (shiftVal - 8);
+	copyLenMask = (1 << copyOfsShift) - 1;
+	copyOfs = 0xFFFF0000;
+	destP = destData;
+
+	// Initialise data fields
+	_srcData = srcData;
+	_srcP = _srcData + 6;
+	_srcSize = srcSize;
+	_bitsLeft = 16;	
+	_bitBuffer = READ_LE_UINT16(srcData + 4);
+
+	for (;;) {
+		if (getBit() == 0) {
+			if (getBit() == 0) {
+				copyLen = ((getBit() << 1) | getBit()) + 2;
+				copyOfs = *_srcP++ | 0xFFFFFF00;
+			} else {
+				copyOfs = (((_srcP[1] >> copyOfsShift) | copyOfsMask) << 8) | _srcP[0];
+				copyLen = _srcP[1] & copyLenMask;
+				_srcP += 2;
+				if (copyLen == 0) {
+					copyLen = *_srcP++;
+					if (copyLen == 0)
+						break;
+					else if (copyLen == 1)
+						continue;
+					else
+						copyLen++;
+				} else {
+					copyLen += 2;
+				}
+				copyOfs |= 0xFFFF0000;
+			}
+			while (copyLen-- > 0) {
+				if (destP - destData == destSize)
+					error(FabOutputExceededError);
+
+				*destP = destP[(signed int)copyOfs];
+				destP++;
+			}
+		} else {
+			if (_srcP - srcData == srcSize)
+				error(FabInputExceededError);
+			if (destP - destData == destSize)
+				error(FabOutputExceededError);
+
+			*destP++ = *_srcP++;
+		}
+	}
+
+	if (destP - destData != destSize)
+		error("FabDecompressor - Decompressed data does not match header decompressed size");
+}
+
+int FabDecompressor::getBit() {
+	_bitsLeft--;
+	if (_bitsLeft == 0) {
+		if (_srcP - _srcData == _srcSize)
+			error(FabInputExceededError);
+
+		_bitBuffer = (READ_LE_UINT16(_srcP) << 1) | (_bitBuffer & 1);
+		_srcP += 2;
+		_bitsLeft = 16;
+	}
+
+	int bit = _bitBuffer & 1;
+	_bitBuffer >>= 1;
+	return bit;
+}
+
+} // End of namespace M4


Property changes on: scummvm/trunk/engines/m4/compression.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/compression.h
===================================================================
--- scummvm/trunk/engines/m4/compression.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/compression.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,82 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef M4_COMPRESSION_H
+#define M4_COMPRESSION_H
+
+#include "common/scummsys.h"
+#include "common/stream.h"
+#include "common/endian.h"
+
+#include "m4/m4.h"
+
+namespace M4 {
+
+struct MadsPackEntry {
+public:
+	uint16 hash;
+	uint32 size;
+	uint32 compressedSize;
+	byte *data;
+};
+
+class MadsPack {
+private:
+	MadsPackEntry *_items;
+	int _count;
+	int _dataOffset;
+
+	void initialise(Common::SeekableReadStream *stream);
+public:
+	static bool isCompressed(Common::SeekableReadStream *stream);
+	MadsPack(Common::SeekableReadStream *stream);
+	MadsPack(const char *resourceName, M4Engine* _vm);
+	~MadsPack();
+
+	int getCount() const { return _count; }
+	MadsPackEntry &getItem(int index) const { return _items[index]; }
+	MadsPackEntry &operator[](int index) const { return _items[index]; }
+	Common::MemoryReadStream *getItemStream(int index) {
+		return new Common::MemoryReadStream(_items[index].data, _items[index].size, false);
+	}
+	int getDataOffset() const { return _dataOffset; }
+};
+
+class FabDecompressor {
+private:
+    int _bitsLeft;
+    uint32 _bitBuffer;
+	const byte *_srcData, *_srcP;
+	int _srcSize;
+
+	int getBit();
+public:
+	void decompress(const byte *srcData, int srcSize, byte *destData, int destSize);
+};
+
+} // End of namespace M4
+
+
+#endif


Property changes on: scummvm/trunk/engines/m4/compression.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/console.cpp
===================================================================
--- scummvm/trunk/engines/m4/console.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/console.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,287 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "m4/m4.h"
+#include "m4/console.h"
+#include "m4/scene.h"
+
+namespace M4 {
+
+Console::Console(M4Engine *vm) : GUI::Debugger() {
+	_vm = vm;
+
+	DCmd_Register("scene",			WRAP_METHOD(Console, cmdLoadScene));
+	DCmd_Register("start",			WRAP_METHOD(Console, cmdStartingScene));
+	DCmd_Register("scene_info",		WRAP_METHOD(Console, cmdSceneInfo));
+	DCmd_Register("show_hotspots",	WRAP_METHOD(Console, cmdShowHotSpots));
+	DCmd_Register("list_hotspots",	WRAP_METHOD(Console, cmdListHotSpots));
+	DCmd_Register("play_sound",		WRAP_METHOD(Console, cmdPlaySound));
+	DCmd_Register("play_dsr_sound",	WRAP_METHOD(Console, cmdPlayDSRSound));
+	DCmd_Register("show_resources",	WRAP_METHOD(Console, cmdShowResources));
+	DCmd_Register("show_codes",		WRAP_METHOD(Console, cmdShowCodes));
+	DCmd_Register("dump_file",		WRAP_METHOD(Console, cmdDumpFile));
+	DCmd_Register("sprite",			WRAP_METHOD(Console, cmdShowSprite));
+	DCmd_Register("start_conv",		WRAP_METHOD(Console, cmdStartConversation));
+	DCmd_Register("textview",		WRAP_METHOD(Console, cmdShowTextview));
+	DCmd_Register("animview",		WRAP_METHOD(Console, cmdShowAnimview));
+	DCmd_Register("anim",			WRAP_METHOD(Console, cmdPlayAnimation));
+}
+
+Console::~Console() {
+}
+
+bool Console::cmdLoadScene(int argc, const char **argv) {
+	if (argc != 2) {
+		DebugPrintf("Usage: %s <scene number>\n", argv[0]);
+		return true;
+	} else {
+		if (_vm->isM4())
+			_vm->_kernel->newRoom = atoi(argv[1]);
+		else
+			_vm->_scene->loadScene(atoi(argv[1]));
+		return false;
+	}
+}
+
+bool Console::cmdStartingScene(int argc, const char **argv) {
+	if (_vm->getGameType() != GType_Riddle) {
+		if (_vm->isM4())
+			_vm->_kernel->newRoom = FIRST_SCENE;
+		else
+			_vm->_scene->loadScene(FIRST_SCENE);
+		return false;
+	} else {
+		DebugPrintf("%s: Riddle of Master Lu is not supported", argv[0]);
+		return true;
+	}
+}
+
+bool Console::cmdShowHotSpots(int argc, const char **argv) {
+	_vm->_scene->showHotSpots();
+	return false;
+}
+
+bool Console::cmdSceneInfo(int argc, const char **argv) {
+	DebugPrintf("Current scene is: %i\n", _vm->_scene->getCurrentScene());
+	if (_vm->isM4()) {
+		DebugPrintf("Scene resources:\n");
+		DebugPrintf("artBase: %s\n", _vm->_scene->getSceneResources().artBase);
+		DebugPrintf("pictureBase: %s\n", _vm->_scene->getSceneResources().pictureBase);
+		DebugPrintf("hotspotCount: %i\n", _vm->_scene->getSceneResources().hotspotCount);
+		DebugPrintf("parallaxCount: %i\n", _vm->_scene->getSceneResources().parallaxCount);
+		DebugPrintf("propsCount: %i\n", _vm->_scene->getSceneResources().propsCount);
+		DebugPrintf("frontY: %i\n", _vm->_scene->getSceneResources().frontY);
+		DebugPrintf("backY: %i\n", _vm->_scene->getSceneResources().backY);
+		DebugPrintf("frontScale: %i\n", _vm->_scene->getSceneResources().frontScale);
+		DebugPrintf("backScale: %i\n", _vm->_scene->getSceneResources().backScale);
+		DebugPrintf("depthTable: ");
+		for (uint i = 0; i < 16; i++)
+			DebugPrintf("%i ", _vm->_scene->getSceneResources().depthTable[i]);
+		DebugPrintf("\n");
+		DebugPrintf("railNodeCount: %i\n", _vm->_scene->getSceneResources().railNodeCount);
+	}
+	return true;
+}
+
+bool Console::cmdListHotSpots(int argc, const char **argv) {
+	DebugPrintf("Scene hotspots\n");
+	_vm->_scene->getSceneResources().hotspots->dump();
+	if (_vm->isM4()) {
+		DebugPrintf("Scene parallax\n");
+		_vm->_scene->getSceneResources().parallax->dump();
+		DebugPrintf("Scene props\n");
+		_vm->_scene->getSceneResources().props->dump();
+	}
+	return true;
+}
+
+bool Console::cmdPlaySound(int argc, const char **argv) {
+	if (argc != 2) {
+		DebugPrintf("Usage: %s <sound file>\n", argv[0]);
+	} else {
+		_vm->_sound->playSound(argv[1], 255, false);
+	}
+	return true;
+}
+
+bool Console::cmdPlayDSRSound(int argc, const char **argv) {
+	if (argc != 2 && argc != 3) {
+		DebugPrintf("Usage: %s <sound index> <DSR file>\n", argv[0]);
+		DebugPrintf("The DSR file parameter is optional, and specifies which DSR to load\n", argv[0]);
+	} else {
+		if (argc == 3)
+			_vm->_sound->loadDSRFile(argv[2]);
+		_vm->_sound->playDSRSound(atoi(argv[1]), 255, false);
+	}
+	return true;
+}
+
+bool Console::cmdShowResources(int argc, const char **argv) {
+	_vm->res()->dump();
+	return true;
+}
+
+bool Console::cmdShowCodes(int argc, const char **argv) {
+	if (_vm->getGameType() != GType_RexNebular)
+		_vm->_scene->showCodes();
+	else
+		DebugPrintf("Pathfinding codes not done yet for Rex Nebular");
+	return false;
+}
+
+bool Console::cmdDumpFile(int argc, const char **argv) {
+	if (argc != 2 && argc != 3) {
+		DebugPrintf("Usage: %s <file> <uncompress>\n", argv[0]);
+		DebugPrintf("If uncompress is 1, the file is uncompressed (for MADS games)\n");
+	} else {
+		if (argc == 2) {
+			_vm->dumpFile(strdup(argv[1]));
+		} else {
+			if (argc == 3 && atoi(argv[2]) == 1)
+				_vm->dumpFile(strdup(argv[1]), true);
+			else
+				_vm->dumpFile(strdup(argv[1]));
+		}
+	}
+	return true;
+}
+
+bool Console::cmdShowSprite(int argc, const char **argv) {
+	View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+	if (view == NULL) 
+		DebugPrintf("The scene view isn't currently active\n");
+	else if (argc < 2) 
+		DebugPrintf("Usage: %s resource_name\n", argv[0]);
+	else {
+		char resourceName[20];
+		strncpy(resourceName, argv[1], 15);
+		resourceName[15] = '\0';
+		if (!strchr(resourceName, '.'))
+			strcat(resourceName, ".SS");
+
+		_vm->_viewManager->moveToFront(view);
+		Common::SeekableReadStream *data = _vm->res()->get(resourceName);
+		SpriteAsset *asset = new SpriteAsset(_vm, data, data->size(), resourceName);
+		_vm->res()->toss(resourceName);
+
+		RGBList *palData = new RGBList(asset->getColorCount(), asset->getPalette(), true);
+		_vm->_palette->addRange(palData);
+		
+		// Get the scene background surface
+		M4Surface *bg = _vm->_scene->getBackgroundSurface();
+
+		// Write the sprite onto the screen
+		int x = 0, y = 0, yMax = 0;
+		for (int index = 0; index < asset->getCount(); index++) {
+			M4Sprite *spr = asset->getFrame(index);
+			spr->translate(palData);		// sprite pixel translation
+
+			if ((x + spr->width() >= bg->width()) && (yMax != 0)) {
+				x = 0;
+				y += yMax;
+				yMax = 0;
+			}
+
+			if (y >= bg->height())
+				break;
+
+			// FIXME: We assume that the transparent color is the color of the top left pixel
+			byte *transparentColor = (byte *)spr->pixels;
+
+			spr->copyTo(bg, x, y, (int)*transparentColor);
+
+			x += spr->width();
+			yMax = MAX(yMax, spr->height());
+		}
+
+		view->restore(0, 0, view->width(), view->height());
+		return false;
+	}
+
+	return true;
+}
+
+bool Console::cmdStartConversation(int argc, const char **argv) {
+	if (argc != 2) {
+		DebugPrintf("Usage: %s <conversation file name>\n", argv[0]);
+		return true;
+	} else {
+		_vm->_converse->startConversation(argv[1]);
+		return false;
+	}
+}
+
+bool Console::cmdShowTextview(int argc, const char **argv) {
+	if (argc != 2) {
+		DebugPrintf("Usage: %s <txr resource>\n", argv[0]);
+		return true;
+	}
+
+	_vm->_viewManager->showTextView(argv[1], false);
+	return false;
+}
+
+bool Console::cmdShowAnimview(int argc, const char **argv) {
+	if (argc != 2) {
+		DebugPrintf("Usage: %s <res resource>\n", argv[0]);
+		return true;
+	}
+
+	char resName[80];
+	strcpy(resName, "@");
+	strcat(resName, *argv[1] == '@' ? argv[1] + 1 : argv[1]);
+
+	_vm->_viewManager->showAnimView(resName, false);
+	return false;
+}
+
+bool Console::cmdPlayAnimation(int argc, const char **argv) {
+	View *view = _vm->_viewManager->getView(VIEWID_SCENE);
+	if (view == NULL) {
+		DebugPrintf("The scene view isn't currently active\n");
+	} else if (argc != 2 && argc != 3) {
+		DebugPrintf("Usage: %s <anim resource (*.aa)> <fullscreen>\n", argv[0]);
+		DebugPrintf("If fullscreen is 1, the screen palette is replaced with the palette of the animation\n");
+	} else {
+		char resourceName[20];
+		strncpy(resourceName, argv[1], 15);
+		resourceName[15] = '\0';
+		if (!strchr(resourceName, '.'))
+			strcat(resourceName, ".AA");
+
+		_vm->_viewManager->moveToFront(view);
+		if (argc == 3 && atoi(argv[2]) == 1)
+			_vm->_animation->loadFullScreen(resourceName);
+		else
+			_vm->_animation->load(resourceName);
+		_vm->_animation->start();
+		view->restore(0, 0, view->width(), view->height());
+		return false;
+	}
+
+	return true;
+}
+
+} // End of namespace M4


Property changes on: scummvm/trunk/engines/m4/console.cpp
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/console.h
===================================================================
--- scummvm/trunk/engines/m4/console.h	                        (rev 0)
+++ scummvm/trunk/engines/m4/console.h	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,64 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef M4_CONSOLE_H
+#define M4_CONSOLE_H
+
+#include "gui/debugger.h"
+
+namespace M4 {
+
+class M4Engine;
+
+class Console : public GUI::Debugger {
+public:
+	Console(M4Engine *vm);
+	virtual ~Console(void);
+
+private:
+	bool cmdLoadScene(int argc, const char **argv);
+	bool cmdStartingScene(int argc, const char **argv);
+	bool cmdSceneInfo(int argc, const char **argv);
+	bool cmdShowHotSpots(int argc, const char **argv);
+	bool cmdListHotSpots(int argc, const char **argv);
+	bool cmdPlaySound(int argc, const char **argv);
+	bool cmdPlayDSRSound(int argc, const char **argv);
+	bool cmdShowResources(int argc, const char **argv);
+	bool cmdShowCodes(int argc, const char **argv);
+	bool cmdDumpFile(int argc, const char **argv);
+	bool cmdShowSprite(int argc, const char **argv);
+	bool cmdStartConversation(int argc, const char **argv);
+	bool cmdShowTextview(int argc, const char **argv);
+	bool cmdShowAnimview(int argc, const char **argv);
+	bool cmdPlayAnimation(int argc, const char **argv);
+
+private:
+	M4Engine *_vm;
+};
+
+} // End of namespace M4
+
+
+#endif


Property changes on: scummvm/trunk/engines/m4/console.h
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Date Rev Author URL Id
Name: svn:eol-style
   + native

Added: scummvm/trunk/engines/m4/converse.cpp
===================================================================
--- scummvm/trunk/engines/m4/converse.cpp	                        (rev 0)
+++ scummvm/trunk/engines/m4/converse.cpp	2008-04-20 14:47:37 UTC (rev 31600)
@@ -0,0 +1,1211 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/array.h"
+#include "common/hashmap.h"
+
+#include "m4/converse.h"
+#include "m4/resource.h"
+#include "m4/globals.h"
+#include "m4/m4_views.h"
+#include "m4/compression.h"
+
+namespace M4 {
+
+#define CONV_ENTRIES_X_OFFSET 20
+#define CONV_ENTRIES_Y_OFFSET 4
+#define CONV_ENTRIES_HEIGHT 20
+#define CONV_MAX_SHOWN_ENTRIES 5
+
+#define CONVERSATION_ENTRY_HIGHLIGHTED 22 
+#define	CONVERSATION_ENTRY_NORMAL 3
+
+// Conversation chunks
+// Header
+#define  HEAD_CONV MKID_BE('CONV')		// conversation
+#define CHUNK_DECL MKID_BE('DECL')		// declaration
+#define CHUNK_NODE MKID_BE('NODE')		// node
+#define CHUNK_LNOD MKID_BE('LNOD')		// linear node
+#define CHUNK_ETRY MKID_BE('ETRY')		// entry
+#define CHUNK_TEXT MKID_BE('TEXT')		// text
+#define CHUNK_MESG MKID_BE('MESG')		// message
+// Conversation chunks - entry related (unconditional)
+#define CHUNK_RPLY MKID_BE('RPLY')		// reply
+#define CHUNK_HIDE MKID_BE('HIDE')		// hide entry
+#define CHUNK_UHID MKID_BE('UHID')		// unhide entry
+#define CHUNK_DSTR MKID_BE('DSTR')		// destroy entry
+// Conversation chunks - entry related (conditional)
+#define CHUNK_CRPL MKID_BE('CRPL')		// reply
+#define CHUNK_CHDE MKID_BE('CHDE')		// hide entry
+#define CHUNK_CUHD MKID_BE('CUHD')		// unhide entry
+#define CHUNK_CDST MKID_BE('DDTS')		// destroy entry
+// Conversation chunks - branching and logic (unconditional)
+#define CHUNK_ASGN MKID_BE('ASGN')		// assign
+#define CHUNK_GOTO MKID_BE('GOTO')		// goto chunk
+#define CHUNK_EXIT MKID_BE('EXIT')		// exit/return from goto
+// Conversation chunks - branching and logic (conditional)
+#define CHUNK_CASN MKID_BE('CASN')		// assign
+#define CHUNK_CCGO MKID_BE('CCGO')		// goto chunk
+#define CHUNK_CEGO MKID_BE('CEGO')		// exit/return from goto
+// Others
+#define CHUNK_FALL MKID_BE('FALL')		// fallthrough
+#define CHUNK_WRPL MKID_BE('WRPL')		// weighted reply chunk
+#define CHUNK_WPRL MKID_BE('WPRL')		// weighted preply chunk
+
+
+ConversationView::ConversationView(M4Engine *vm): View(vm, Common::Rect(0, 
+		vm->_screen->height() - INTERFACE_HEIGHT, vm->_screen->width(), vm->_screen->height())) {
+
+	_screenType = VIEWID_CONVERSATION;
+	_screenFlags.layer = LAYER_INTERFACE;
+	_screenFlags.visible = false;
+	_screenFlags.get = SCREVENT_MOUSE;
+	_conversationState = kNoConversation;
+	_currentHandle = NULL;
+}
+
+ConversationView::~ConversationView() {
+	_activeItems.clear();
+}
+
+void ConversationView::setNode(int32 nodeIndex) {
+	_highlightedIndex = -1;
+	_xEnd = CONV_ENTRIES_X_OFFSET;
+	_vm->_font->setFont(FONT_CONVERSATION);
+
+	// TODO: Conversation styles and colors
+	_vm->_font->setColors(2, 1, 3);
+
+	_currentNodeIndex = nodeIndex;
+
+	_activeItems.clear();
+
+	if (nodeIndex != -1) {
+		ConvEntry *node = _vm->_converse->getNode(nodeIndex);
+
+		for (uint i = 0; i < node->entries.size(); ++i) {
+			if (!node->entries[i]->visible)
+				continue;
+
+			if ((int)_activeItems.size() > CONV_MAX_SHOWN_ENTRIES) {
+				warning("TODO: scrolling. Max shown entries are %i, skipping entry %i", 
+						CONV_MAX_SHOWN_ENTRIES, i);
+			}
+
+			// Add node to active items list
+			_activeItems.push_back(node->entries[i]);
+
+			if (node->entries[i]->autoSelect || strlen(node->entries[i]->text) == 0) {
+				//printf("Auto selecting entry %i of node %i\n", i, nodeIndex);
+				selectEntry(i);
+				return;
+			}
+
+			// Figure out the longest string to determine where option highlighting ends
+			int tempX = _vm->_font->getWidth(node->entries[i]->text, 0) + 
+				CONV_ENTRIES_X_OFFSET + 10;
+			_xEnd = MAX(_xEnd, tempX);
+		}
+
+		// Make sure that there aren't too many entries
+		//assert((int)_activeItems.size() < (height() - CONV_ENTRIES_Y_OFFSET) / CONV_ENTRIES_HEIGHT);
+
+		// Fallthrough
+		if (node->fallthroughMinEntries >= 0 && node->fallthroughOffset >= 0) {
+			//printf("Current node falls through node at offset %i when entries are less or equal than %i\n", 
+			//		node->fallthroughOffset, node->fallthroughMinEntries);
+			if (_activeItems.size() <= (uint32)node->fallthroughMinEntries) {
+				const EntryInfo *entryInfo = _vm->_converse->getEntryInfo(node->fallthroughOffset);
+				//printf("Entries are less than or equal to %i, falling through to node at offset %i, index %i\n",
+				//		node->fallthroughMinEntries, node->fallthroughOffset, entryInfo->nodeIndex);
+				setNode(entryInfo->nodeIndex);
+				return;
+			}
+		}
+
+		_entriesShown = true;
+		_conversationState = kConversationOptionsShown;
+	}
+}
+
+void ConversationView::onRefresh(RectList *rects, M4Surface *destSurface) {
+	//if (!this->isVisible())
+	//	return;
+	empty();
+
+	if (_entriesShown) {
+		// Write out the conversation options
+		_vm->_font->setFont(FONT_CONVERSATION);
+		for (int i = 0; i < (int)_activeItems.size(); ++i) {
+			// TODO: scrolling
+			if (i > CONV_MAX_SHOWN_ENTRIES - 1)
+				break;
+
+			_vm->_font->setColor((_highlightedIndex == i) ? CONVERSATION_ENTRY_HIGHLIGHTED :
+				CONVERSATION_ENTRY_NORMAL);
+
+			_vm->_font->writeString(this, _activeItems[i]->text, CONV_ENTRIES_X_OFFSET, 
+				CONV_ENTRIES_Y_OFFSET + CONV_ENTRIES_HEIGHT * i, 0, 0);
+		}
+	}
+	View::onRefresh(rects, destSurface);
+}
+
+bool ConversationView::onEvent(M4EventType eventType, int param, int x, int y, bool &captureEvents) {
+	//if (!this->isVisible())
+	//	return false;
+	if (!_entriesShown)
+		return false;
+	if (eventType == KEVENT_KEY) 
+		return false;
+
+	int localY = y - _coords.top;
+	int selectedIndex = _highlightedIndex;
+
+	switch (eventType) {
+	case MEVENT_MOVE:
+		if ((x < CONV_ENTRIES_X_OFFSET) || (x >= _xEnd) || (localY < CONV_ENTRIES_Y_OFFSET))
+			_highlightedIndex = -1;
+		else {
+			int index = (localY - CONV_ENTRIES_Y_OFFSET) / CONV_ENTRIES_HEIGHT;
+			_highlightedIndex = (index >= (int)_activeItems.size()) ? -1 : index;
+		}
+		break;
+
+	case MEVENT_LEFT_RELEASE:
+		if (_highlightedIndex != -1) {
+			selectEntry(selectedIndex);
+		}
+		break;
+
+	default:
+		break;
+	}
+
+	return true;
+}
+
+void ConversationView::selectEntry(int entryIndex) {
+	char buffer[20];
+	sprintf(buffer, "%s.raw", _activeItems[entryIndex]->voiceFile);
+
+	_entriesShown = false;
+	_conversationState = kEntryIsActive;
+	_vm->_player->setCommandsAllowed(false);
+	// Necessary, as entries can be selected programmatically
+	_highlightedIndex = entryIndex;
+
+	// Play the selected entry's voice
+	if (strlen(_activeItems[entryIndex]->voiceFile) > 0) {
+		_currentHandle = _vm->_sound->getHandle();
+		_vm->_sound->playVoice(buffer, 255);
+	} else {
+		_currentHandle = NULL;
+	}
+
+	// Hide selected entry, unless it has a persistent flag set
+	if (!(_activeItems[entryIndex]->flags & kEntryPersists)) {
+		//printf("Hiding selected entry\n");
+		_vm->_converse->getNode(_currentNodeIndex)->entries[entryIndex]->visible = false;
+	} else {
+		//printf("Selected entry is persistent, not hiding it\n");
+	}
+}
+
+void ConversationView::updateState() {
+	switch(_conversationState) {
+		case kConversationOptionsShown:
+			return;
+		case kEntryIsActive:
+		case kReplyIsActive:
+			// FIXME: for now, we determine whether a conversation entry is
+			// finished by waiting for its associated speech file to finish playing
+			if (_currentHandle != NULL && _vm->_sound->isHandleActive(_currentHandle)) {
+				return;
+			} else {
+				playNextReply();
+			}	// end else
+			break;
+		case kNoConversation:
+			return;
+		default:
+			error("Unknown converstation state");
+			break;
+	}
+}
+
+void ConversationView::playNextReply() {
+	char buffer[20];
+
+	assert(_highlightedIndex >= 0);
+
+	// Start playing the first reply
+	for (uint32 i = 0; i < _activeItems[_highlightedIndex]->entries.size(); i++) {
+		ConvEntry *currentEntry = _activeItems[_highlightedIndex]->entries[i];
+
+		if (currentEntry->isConditional) {
+			if (!_vm->_converse->evaluateCondition(
+				_vm->_converse->getValue(currentEntry->condition.offset), 
+				currentEntry->condition.op, currentEntry->condition.val))
+				continue;	// don't play this reply
+		}
+
+		if (currentEntry->entryType != kWeightedReply) {
+			sprintf(buffer, "%s.raw", currentEntry->voiceFile);
+			if (strlen(currentEntry->voiceFile) > 0) {
+				_currentHandle = _vm->_sound->getHandle();
+				_vm->_sound->playVoice(buffer, 255);
+				// Remove reply from the list of replies
+				_activeItems[_highlightedIndex]->entries.remove_at(i);
+				_conversationState = kReplyIsActive;
+				return;
+			} else {
+				_currentHandle = NULL;
+			}
+		} else {
+			int selectedWeight = _vm->_random->getRandomNumber(currentEntry->totalWeight - 1) + 1;
+			//printf("Selected weight: %i\n", selectedWeight);
+			int previousWeight = 1;
+			int currentWeight = 0;
+
+			for(uint32 j = 0; j < currentEntry->entries.size(); j++) {
+				currentWeight += currentEntry->entries[j]->weight;
+				if (selectedWeight >= previousWeight && selectedWeight <= currentWeight) {
+					sprintf(buffer, "%s.raw", currentEntry->entries[j]->voiceFile);
+					if (strlen(currentEntry->entries[j]->voiceFile) > 0) {
+						_currentHandle = _vm->_sound->getHandle();
+						_vm->_sound->playVoice(buffer, 255);
+						// Remove reply from the list of replies
+						_activeItems[_highlightedIndex]->entries.remove_at(i);
+						_conversationState = kReplyIsActive;
+						return;
+					} else {
+						_currentHandle = NULL;
+					}
+					break;
+				}
+				previousWeight += currentWeight;
+			}	// end for j
+		}	// end if
+	}	// end for i
+
+	// If we reached here, there are no more replies, so perform the active entry's actions
+
+	//printf("Current selection does %i actions\n", _activeItems[entryIndex]->actions.size()); 
+	for (uint32 i = 0; i < _activeItems[_highlightedIndex]->actions.size(); i++) {
+		if (!_vm->_converse->performAction(_activeItems[_highlightedIndex]->actions[i]))
+			break;
+	}	// end for
+
+	// Refresh the conversation node, in case it hasn't changed
+	setNode(_currentNodeIndex);
+
+	_entriesShown = true;
+	_vm->_player->setCommandsAllowed(true);
+
+	// Check if the conversation has been ended
+	if (_currentNodeIndex == -1) {
+		_conversationState = kNoConversation;	
+	}
+}
+
+//--------------------------------------------------------------------------
+
+void Converse::startConversation(const char *convName, bool showConverseBox, ConverseStyle style) {
+	if (_vm->isM4())
+		loadConversation(convName);
+	else
+		loadConversationMads(convName);
+
+	if (!_vm->isM4()) showConverseBox = false;		// TODO: remove
+
+	_playerCommandsAllowed = _vm->_player->commandsAllowed;
+	if (_vm->isM4())	// TODO: remove (interface not implemented yet in MADS games)
+		_interfaceWasVisible = _vm->_interfaceView->isVisible();
+	_vm->_player->setCommandsAllowed(false);
+	_style = style;
+
+	if (showConverseBox) {
+		_vm->_conversationView->show();
+		_vm->_mouse->lockCursor(CURSOR_ARROW);
+		
+		if (_interfaceWasVisible)
+			_vm->_interfaceView->hide();
+
+		_vm->_conversationView->setNode(0);
+		_vm->_conversationView->show();
+	}
+}
+
+void Converse::endConversation() {
+	_vm->_conversationView->setNode(-1);
+	_vm->_conversationView->hide();
+	// TODO: do a more proper cleanup here
+	_convNodes.clear();
+	_variables.clear();
+	_offsetMap.clear();
+	_vm->_player->setCommandsAllowed(_playerCommandsAllowed);
+	if (_interfaceWasVisible)
+		_vm->_interfaceView->show();
+}
+
+void Converse::loadConversation(const char *convName) {
+	char name[40];
+	char buffer[256];
+	sprintf(name, "%s.chk", convName);
+	Common::SeekableReadStream *convS = _vm->res()->get(name);
+	uint32 header = convS->readUint32LE();
+	uint32 size;
+	uint32 chunk;
+	uint32 data;
+	uint32 i;
+	ConvEntry* curEntry = NULL;
+	ConvEntry* replyEntry = NULL;
+	int32 currentWeightedEntry = -1;
+	EntryAction* curAction = NULL;
+	uint32 curNode = 0;
+	uint32 chunkPos = 0;
+	uint32 val;
+	int32 autoSelectIndex = -1;
+	int returnAddress = -1;
+
+	bool debugFlag = false;		// set to true for debug messages
+
+	// Conversation *.chk files contain a 'CONV' header in LE format
+	if (header != HEAD_CONV) {
+		warning("Unexpected conversation file external header");
+		return;
+	} 
+	size = convS->readUint32LE();	// is this used at all?
+	if (debugFlag) printf("Conv chunk size (external header): %i\n", size);
+
+	// Conversation name, which is the conversation file's name
+	// without the extension
+	convS->read(buffer, 8);
+	if (debugFlag) printf("Conversation name: %s\n", buffer);
+
+	while(!convS->eos()) {
+		chunkPos = convS->pos();
+		if (debugFlag) printf("***** Pos: %i -> ", chunkPos);
+		chunk = convS->readUint32LE();	// read chunk
+		switch(chunk) {
+			case CHUNK_DECL:	// Declare
+				if (debugFlag) printf("DECL chunk\n");
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Tag: %i\n", data);
+				if (data > 0)
+					warning("Tag > 0 in DECL chunk, value is: %i", data);		// TODO
+				val = convS->readUint32LE();
+				if (debugFlag) printf("Value: %i\n", val);
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Flags: %i\n", data);
+				if (data > 0)
+					warning("Flags != 0 in DECL chunk, value is %i", data);		// TODO
+				setValue(chunkPos, val);
+				break;
+			// ----------------------------------------------------------------------------
+			case CHUNK_NODE:	// Node
+			case CHUNK_LNOD:	// Linear node
+				// Create new node
+				curEntry = new ConvEntry();
+				curEntry->offset = chunkPos;
+				curEntry->entryType = (chunk == CHUNK_NODE) ? kNode : kLinearNode;
+				curEntry->fallthroughMinEntries = -1;
+				curEntry->fallthroughOffset = -1;
+				if (chunk == CHUNK_NODE) {
+					if (debugFlag) printf("NODE chunk\n");
+				} else {
+					if (debugFlag) printf("LNOD chunk\n");
+				}
+				curNode = convS->readUint32LE();
+				if (debugFlag) printf("Node number: %i\n", curNode);
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Tag: %i\n", data);
+				if (chunk == CHUNK_LNOD) {
+					autoSelectIndex = convS->readUint32LE();
+					if (debugFlag) printf("Autoselect entry number: %i\n", autoSelectIndex);
+				}
+				size = convS->readUint32LE();
+				if (debugFlag) printf("Number of entries: %i\n", size);
+				for (i = 0; i < size; i++) {
+					data = convS->readUint32LE();
+					if (debugFlag) printf("Entry %i: %i\n", i + 1, data);
+				}
+				_convNodes.push_back(curEntry);
+				setEntryInfo(curEntry->offset, curEntry->entryType, curNode, -1);
+				break;
+			case CHUNK_ETRY:	// Entry
+				// Create new entry
+				curEntry = new ConvEntry();
+				curEntry->offset = chunkPos;
+				curEntry->entryType = kEntry;
+				strcpy(curEntry->voiceFile, "");
+				strcpy(curEntry->text, "");
+				if (debugFlag) printf("ETRY chunk\n");
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Unknown (attributes perhaps?): %i\n", data);
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Entry flags: ");
+				if (debugFlag) if (data & kEntryInitial) printf ("Initial ");
+				if (debugFlag) if (data & kEntryPersists) printf ("Persists ");
+				if (debugFlag) printf("\n");
+				curEntry->flags = data;
+				curEntry->visible = (curEntry->flags & kEntryInitial) ? true : false;
+				if (autoSelectIndex >= 0) {
+					if (_convNodes[curNode]->entries.size() == (uint32)autoSelectIndex) {
+						curEntry->autoSelect = true;
+						autoSelectIndex = -1;
+					} else {
+						curEntry->autoSelect = false;
+					}
+				} else {
+					curEntry->autoSelect = false;
+				}
+				_convNodes[curNode]->entries.push_back(curEntry);
+				setEntryInfo(curEntry->offset, curEntry->entryType, 
+							 curNode, _convNodes[curNode]->entries.size() - 1);
+				replyEntry = NULL;
+				break;
+			case CHUNK_WPRL:	// Weighted preply
+				// WPRL chunks are random entries that the character would say, not an NPC
+				// They don't seem to be used in Orion Burger
+				warning("WPRL chunk - treating as WRPL chunk");
+			case CHUNK_WRPL:	// Weighted reply
+			case CHUNK_CRPL:	// Conditional reply
+			case CHUNK_RPLY:	// Reply
+				{
+				ConvEntry* weightedEntry = NULL;
+				// Create new reply
+				replyEntry = new ConvEntry();
+				replyEntry->offset = chunkPos;
+				strcpy(replyEntry->voiceFile, "");
+
+				// Conditional part
+				if (chunk == CHUNK_CRPL) {
+					replyEntry->isConditional = true;
+					replyEntry->condition.offset = convS->readUint32LE();
+					replyEntry->condition.op = convS->readUint32LE();
+					replyEntry->condition.val = convS->readUint32LE();
+				} else {
+					replyEntry->isConditional = false;
+				}
+
+				if (chunk == CHUNK_WPRL || chunk == CHUNK_WRPL) {
+					replyEntry->entryType = kWeightedReply;
+					replyEntry->totalWeight = 0;
+					if (debugFlag) printf("WRPL chunk\n");
+					size = convS->readUint32LE();
+					if (debugFlag) printf("Weighted reply %i - %i entries:\n", i, size);
+					for (i = 0; i < size; i++) {
+						weightedEntry = new ConvEntry();
+						weightedEntry->offset = chunkPos;
+						strcpy(weightedEntry->voiceFile, "");
+						weightedEntry->entryType = kWeightedReply;
+						data = convS->readUint32LE();
+						if (debugFlag) printf("- Weight: %i ", data);
+						weightedEntry->weight = data;
+						replyEntry->totalWeight += weightedEntry->weight;
+						data = convS->readUint32LE();
+						if (debugFlag) printf("offset: %i\n", data);
+						replyEntry->entries.push_back(weightedEntry);
+					}
+					currentWeightedEntry = 0;
+				} else {
+					replyEntry->entryType = kReply;
+					if (debugFlag) printf("RPLY chunk\n");
+					data = convS->readUint32LE();
+					if (debugFlag) printf("Reply data offset: %i\n", data);
+				}
+
+				curEntry->entries.push_back(replyEntry);
+				setEntryInfo(replyEntry->offset, replyEntry->entryType, 
+							 curNode, _convNodes[curNode]->entries.size() - 1);
+				// Seek to chunk data (i.e. TEXT/MESG tag, which is usually right
+				// after this chunk but it can be further on in conditional reply chunks
+				assert(data >= convS->pos());
+				// If the entry's data is not right after the entry, remember the position
+				// to return to after the data is read
+				if (chunk == CHUNK_CRPL && data != convS->pos())
+					returnAddress = convS->pos();
+				convS->seek(data, SEEK_SET);
+				}
+				break;
+			// ----------------------------------------------------------------------------
+			case CHUNK_TEXT:	// Text (contains text and voice)
+			case CHUNK_MESG:	// Message (contains voice only)
+				{
+				ConvEntry* parentEntry = NULL;
+				if (chunk == CHUNK_TEXT) {
+					if (debugFlag) printf("TEXT chunk\n");
+				} else {
+					if (debugFlag) printf("MESG chunk\n");
+				}
+
+				if (replyEntry == NULL) {
+					parentEntry = curEntry; 
+				} else if (replyEntry != NULL && replyEntry->entryType != kWeightedReply) {
+					parentEntry = replyEntry; 
+				} else if (replyEntry != NULL && replyEntry->entryType == kWeightedReply) {
+					parentEntry = replyEntry->entries[currentWeightedEntry];
+					currentWeightedEntry++;
+				}
+
+				size = convS->readUint32LE();
+				if (debugFlag) printf("Entry data size: %i\n", size);
+				convS->read(buffer, 8);
+				size -= 8;		// subtract maximum length of voice file name
+				// If the file name is 8 characters, it will not be 0-terminated, so use strncpy
+				strncpy(parentEntry->voiceFile, buffer, 8);
+				parentEntry->voiceFile[8] = '\0';
+				if (debugFlag) printf("Voice file: %s\n", parentEntry->voiceFile);
+
+				if (chunk == CHUNK_TEXT) {
+					convS->read(buffer, size);
+					if (debugFlag) printf("Text: %s\n", buffer);
+					sprintf(parentEntry->text, "%s", buffer);
+				} else {
+					while (size > 0) {
+						data = convS->readUint32LE();
+						if (debugFlag) printf("Unknown: %i\n", data);	// TODO
+						size -= 4;
+					}
+				}
+				// Now that the data chunk has been read, if we skipped a reply node,
+				// jump back to it
+				if (returnAddress != -1) {
+					convS->seek(returnAddress, SEEK_SET);
+					returnAddress = -1;
+				}
+				}
+				break;
+			// ----------------------------------------------------------------------------
+			// Entry action chunks
+			case CHUNK_CASN:	// Conditional assign
+			case CHUNK_ASGN:	// Assign
+				curAction = new EntryAction();
+				if (debugFlag) printf("ASGN chunk\n");
+				curAction->actionType = kAssignValue;
+
+				// Conditional part
+				if (chunk == CHUNK_CASN) {
+					curAction->isConditional = true;
+					curAction->condition.offset = convS->readUint32LE();
+					curAction->condition.op = convS->readUint32LE();
+					curAction->condition.val = convS->readUint32LE();
+				} else {
+					curAction->isConditional = false;
+				}
+
+				curAction->targetOffset = convS->readUint32LE();
+				assert(convS->readUint32LE() == kOpAssign);
+				curAction->value = convS->readUint32LE();
+				break;
+			case CHUNK_CCGO:	// Conditional go to entry
+			case CHUNK_CHDE:	// Conditional hide entry
+			case CHUNK_CUHD:	// Conditional unhide entry
+			case CHUNK_CDST:	// Conditional destroy entry
+			case CHUNK_CEGO:	// Conditional exit conversation / go to
+
+			case CHUNK_GOTO:	// Go to entry
+			case CHUNK_HIDE:	// Hide entry
+			case CHUNK_UHID:	// Unhide entry
+			case CHUNK_DSTR:	// Destroy entry
+			case CHUNK_EXIT:	// Exit conversation
+				curAction = new EntryAction();
+				
+				// Conditional part
+				if (chunk == CHUNK_CCGO || chunk == CHUNK_CHDE || chunk == CHUNK_CUHD ||
+					chunk == CHUNK_CDST || chunk == CHUNK_CEGO) {
+					curAction->isConditional = true;
+					curAction->condition.offset = convS->readUint32LE();
+					curAction->condition.op = convS->readUint32LE();
+					curAction->condition.val = convS->readUint32LE();
+				} else {
+					curAction->isConditional = false;
+				}
+
+				if (chunk == CHUNK_GOTO || chunk == CHUNK_CCGO) {
+					curAction->actionType = kGotoEntry;
+					if (debugFlag) printf("GOTO chunk\n");
+				} else if (chunk == CHUNK_HIDE || chunk == CHUNK_CHDE) {
+					curAction->actionType = kHideEntry;
+					if (debugFlag) printf("HIDE chunk\n");
+				} else if (chunk == CHUNK_UHID || chunk == CHUNK_CUHD) {
+					curAction->actionType = kUnhideEntry;
+					if (debugFlag) printf("UHID chunk\n");
+				} else if (chunk == CHUNK_DSTR || chunk == CHUNK_CDST) {
+					curAction->actionType = kDestroyEntry;
+					if (debugFlag) printf("DSTR chunk\n");
+				} else if (chunk == CHUNK_EXIT || chunk == CHUNK_CEGO) {
+					curAction->actionType = kExitConv;
+					if (debugFlag) printf("EXIT chunk\n");
+				}
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Offset: %i\n", data);
+				curAction->targetOffset = data;
+				curEntry->actions.push_back(curAction);
+				break;
+			case CHUNK_FALL:	// Fallthrough
+				if (debugFlag) printf("FALL chunk\n");
+				size = convS->readUint32LE();
+				if (debugFlag) printf("Minimum nodes: %i\n", size);
+				_convNodes[curNode]->fallthroughMinEntries = size;
+				data = convS->readUint32LE();
+				if (debugFlag) printf("Offset: %i\n", data);
+				_convNodes[curNode]->fallthroughOffset = data;
+				break;
+			// ----------------------------------------------------------------------------
+			default:
+				// Should never happen
+				error("Unknown conversation chunk");
+				break;
+		}
+	}
+
+	_vm->res()->toss(name);
+}
+
+void Converse::loadConversationMads(const char *convName) {
+	char name[40];
+	char buffer[256];
+	char *buf;
+	Common::SeekableReadStream *convS;
+	int curPos = 0;
+	int unk = 0;
+	uint32 stringIndex = 0;
+	uint32 stringCount = 0;
+	int offset = 0;
+	int flags = 0;
+	int count = 0;
+	uint32 i, j;
+	ConvEntry* curEntry = NULL;
+	MessageEntry *curMessage;
+	Common::Array<char *> messageList;
+	// TODO
+
+	// CND file
+	sprintf(name, "%s.cnd", convName);
+	MadsPack convDataD(name, _vm);
+
+	// ------------------------------------------------------------
+	// Chunk 0
+	convS = convDataD.getItemStream(0);
+	printf("Chunk 0\n");
+	printf("Conv stream size: %i\n", convS->size());
+
+	while(!convS->eos()) {
+		printf("%i ", convS->readByte());
+	}
+	printf("\n");
+
+	// ------------------------------------------------------------
+	// Chunk 1
+	convS = convDataD.getItemStream(1);
+	printf("Chunk 1\n");
+	printf("Conv stream size: %i\n", convS->size());
+
+	while(!convS->eos()) {
+		printf("%i ", convS->readByte());
+	}
+	printf("\n");
+
+	// ------------------------------------------------------------
+	// Chunk 2
+	convS = convDataD.getItemStream(2);
+	printf("Chunk 2\n");
+	printf("Conv stream size: %i\n", convS->size());
+
+	while(!convS->eos()) {
+		printf("%i ", convS->readByte());
+	}
+	printf("\n");
+
+	// ------------------------------------------------------------
+	// CNV file
+	sprintf(name, "%s.cnv", convName);
+	MadsPack convData(name, _vm);
+	// *.cnv files have 7 chunks
+	// Here is the chunk output of conv001.cnv (from the dump_file command)
+	/*
+	Dumping conv001.cnv, size: 3431
+	Dumping compressed chunk 1 of 7, size is 150
+	Dumping compressed chunk 2 of 7, size is 130
+	Dumping compressed chunk 3 of 7, size is 224
+	Dumping compressed chunk 4 of 7, size is 92
+	Dumping compressed chunk 5 of 7, size is 168
+	Dumping compressed chunk 6 of 7, size is 4064
+	Dumping compressed chunk 7 of 7, size is 2334
+	*/
+
+	// ------------------------------------------------------------
+	// TODO: finish this
+	// Chunk 0
+	convS = convData.getItemStream(0);
+	printf("Chunk 0\n");
+	printf("Conv stream size: %i\n", convS->size());
+	printf("%i ", convS->readUint16LE());
+	printf("%i ", convS->readUint16LE());
+	printf("%i ", convS->readUint16LE());
+	printf("%i ", convS->readUint16LE());
+	printf("%i ", convS->readUint16LE());
+	printf("%i ", convS->readUint16LE());
+	printf("\n");
+	count = convS->readUint16LE();	// conversation face count (usually 2)
+	printf("Conversation faces: %i\n", count);
+	for (i = 0; i < 5; i++) {
+		convS->read(buffer, 16);
+		printf("Face %i: %s ", i + 1, buffer);
+	}
+	printf("\n");
+
+	// 5 face slots
+	// 1 = face slot has a face (with the filename specified above)
+	// 0 = face slot doesn't contain face data
+	for (i = 0; i < 5; i++) {
+		printf("%i ", convS->readUint16LE());
+	}
+	printf("\n");
+
+	convS->read(buffer, 14);		// speech file
+	printf("Speech file: %s\n", buffer);
+
+	while(!convS->eos()) {
+		printf("%i ", convS->readByte());
+	}
+	printf("\n");
+
+	delete convS;
+
+	// ------------------------------------------------------------
+	// Chunk 1: Conversation nodes
+	convS = convData.getItemStream(1);
+	printf("Chunk 1: conversation nodes\n");
+	printf("Conv stream size: %i\n", convS->size());
+
+	while(!convS->eos()) {
+		curEntry = new ConvEntry();
+		curEntry->id = convS->readUint16LE();
+		curEntry->entryCount = convS->readUint16LE();
+		curEntry->flags = convS->readUint16LE();
+		if (curEntry->entryCount == 1 && curEntry->flags != 65535) {
+			warning("Entry count is 1 and flags is not 65535 (it's %i)", flags);
+		} else if (curEntry->entryCount != 1 && flags != 0) {
+			warning("Entry count > 1 and flags is not 0 (it's %i)", flags);
+		}
+		unk = convS->readUint16LE();
+		assert (unk == 65535);
+		unk = convS->readUint16LE();
+		assert (unk == 65535);
+		_convNodes.push_back(curEntry);
+		printf("Node %i, ID %i, entries %i\n", _convNodes.size(), curEntry->id, curEntry->entryCount);
+		// flags = 0: node has more than 1 entry
+		// flags = 65535: node has 1 entry
+	}
+	printf("Conversation has %i nodes\n", _convNodes.size());
+	printf("\n");
+
+	delete convS;
+
+	// ------------------------------------------------------------
+	// Chunk 4 contains the conversation string offsets of chunk 5
+	// (unused, as it's unneeded - we find the offsets ourselves)
+
+	// ------------------------------------------------------------
+	// Chunk 5 contains the conversation strings
+	convS = convData.getItemStream(5);
+	//printf("Chunk 5: conversation strings\n");
+	//printf("Conv stream size: %i\n", convS->size());
+
+	*buffer = 0;
+
+	while(!convS->eos()) {
+		//if (curPos == 0)
+		//	printf("%i: Offset %i: ", _convStrings.size(), convS->pos());
+		buffer[curPos++] = convS->readByte();
+		if (buffer[curPos - 1] == '~') {		// filter out special characters
+			curPos--;
+			continue;
+		}
+		if (buffer[curPos - 1] == '\0') {
+			// end of string
+			//printf("%s\n", buffer);
+			buf = new char[strlen(buffer)];
+			sprintf(buf, "%s", buffer);
+			_convStrings.push_back(buf);
+			curPos = 0;
+			*buffer = 0;
+		}
+	}
+
+	delete convS;
+
+	// ------------------------------------------------------------
+	// Chunk 2: entry data
+	convS = convData.getItemStream(2);
+	//printf("Chunk 2 - entry data\n");
+	//printf("Conv stream size: %i\n", convS->size());
+
+	for (i = 0; i < _convNodes.size(); i++) {
+		for (j = 0; j < _convNodes[i]->entryCount; j++) {
+			curEntry = new ConvEntry();
+			stringIndex = convS->readUint16LE();
+			if (stringIndex != 65535)
+				sprintf(curEntry->text, "%s", _convStrings[stringIndex]);
+			else
+				*curEntry->text = 0;
+			curEntry->id = convS->readUint16LE();
+			curEntry->offset = convS->readUint16LE();
+			curEntry->size = convS->readUint16LE();
+			
+			_convNodes[i]->entries.push_back(curEntry);
+			//printf("Node %i, entry %i, id %i, offset %i, size %i, text: %s\n", 
+			//		i, j, curEntry->id, curEntry->offset, curEntry->size, curEntry->text);
+		}
+	}
+
+	delete convS;
+
+	// ------------------------------------------------------------
+	// Chunk 3: message (MESG) chunks, created from the strings of chunk 5
+	convS = convData.getItemStream(3);
+	//printf("Chunk 3 - MESG chunk data\n");
+	//printf("Conv stream size: %i\n", convS->size());
+
+	while(!convS->eos()) {
+		curMessage = new MessageEntry();
+		stringIndex = convS->readUint16LE();
+		stringCount = convS->readUint16LE();
+		*buffer = 0;
+		//printf("Message: %i\n", _madsMessageList.size());
+		for (i = stringIndex; i < stringIndex + stringCount; i++) {
+			//printf("%i: %s\n", i, _convStrings[i]);
+			curMessage->messageStrings.push_back(_convStrings[i]);
+		}
+		_madsMessageList.push_back(curMessage);
+		//printf("----------\n");
+	}
+	//printf("\n");
+
+	delete convS;
+
+	// ------------------------------------------------------------
+	// TODO: finish this
+	// Chunk 6: conversation script
+	convS = convData.getItemStream(6);
+	printf("Chunk 6\n");
+	printf("Conv stream size: %i\n", convS->size());
+	/*while(!convS->eos()) {
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("%i ", convS->readByte());
+		printf("\n");
+	}
+	return;*/
+
+	for (i = 0; i < _convNodes.size(); i++) {
+		for (j = 0; j < _convNodes[i]->entryCount; j++) {
+			printf("*** Node %i entry %i data size %i\n", i, j, _convNodes[i]->entries[j]->size);
+			printf("Entry ID %i, text %s\n", _convNodes[i]->entries[j]->id, _convNodes[i]->entries[j]->text);
+			Common::SubReadStream *entryStream = new Common::SubReadStream(convS, _convNodes[i]->entries[j]->size);
+			readConvEntryActions(entryStream, _convNodes[i]->entries[j]);
+			delete entryStream;
+			printf("--------------------\n");
+		}
+	}
+
+	delete convS;
+}
+
+void Converse::readConvEntryActions(Common::SubReadStream *convS, ConvEntry *curEntry) {
+	uint8 chunk;
+	uint8 type;	// 255: normal, 11: conditional
+	uint8 hasText1, hasText2;
+	int target;
+	int count = 0;
+	int var, val;
+	int messageIndex = 0;
+	int unk = 0;
+
+	while(!convS->eos()) {
+		chunk = convS->readByte();
+		type = convS->readByte();
+
+		switch (chunk) {
+		case 1:
+			printf("TODO: chunk type %i\n", chunk);
+			break;
+		case 2:
+			printf("HIDE\n");
+			convS->readByte();
+			count = convS->readByte();
+			printf("%i entries: ", count);
+			for (int i = 0; i < count; i++)
+				printf("%i %d", i, convS->readUint16LE());
+			printf("\n");
+			break;
+		case 3:
+			printf("UNHIDE\n");
+			convS->readByte();
+			count = convS->readByte();
+			printf("%i entries: ", count);
+			for (int i = 0; i < count; i++)
+				printf("%i %d", i, convS->readUint16LE());
+			printf("\n");
+			break;
+		case 4:		// MESSAGE
+			printf("MESSAGE\n");
+
+			if (type == 255) {
+				//printf("unconditional\n");
+			} else if (type == 11) {
+				//printf("conditional\n");
+			} else {
+				printf("unknown type: %i\n", type);
+			}
+
+			// Conditional part
+			if (type == 11) {
+				unk = convS->readUint16LE();	//	1
+				if (unk != 1)
+					printf("Message: unk != 1 (it's %i)\n", unk);
+
+					var = convS->readUint16LE();
+					val = convS->readUint16LE();
+					printf("Var %i == %i\n", var, val);
+			}
+			unk = convS->readUint16LE();	//	256
+			if (unk != 256)
+				printf("Message: unk != 256 (it's %i)\n", unk);
+
+			// it seems that the first text entry is set when the message
+			// chunk is supposed to be shown unconditionally, whereas the second text
+			// entry is set when the message is supposed to be shown conditionally
+			hasText1 = convS->readByte();
+			hasText2 = convS->readByte();
+
+			if (hasText1 == 1) {
+				messageIndex = convS->readUint16LE();
+				printf("Message 1 index: %i, text:\n", messageIndex);	
+				for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
+					printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+				}
+			}
+
+			if (hasText2 == 1) {
+				messageIndex = convS->readUint16LE();
+				if (hasText1 == 0) {
+					printf("Message 2 index: %i, text:\n", messageIndex);	
+					for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
+						printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+					}
+				}
+			}
+
+			break;
+		case 5:		// AUTO
+			printf("AUTO\n");
+			for (int k = 0; k < 4; k++)
+				convS->readByte();
+			messageIndex = convS->readUint16LE();
+			printf("Message index: %i, text:\n", messageIndex);	
+			for (uint32 i = 0; i < _madsMessageList[messageIndex]->messageStrings.size(); i++) {
+				printf("%s\n", _madsMessageList[messageIndex]->messageStrings[i]);
+			}
+
+			convS->readUint16LE();
+			break;
+		case 6:
+			printf("TODO: chunk type %i\n", chunk);
+			break;
+		case 7:		// GOTO
+			unk = convS->readUint32LE();	// 0
+			if (unk != 0 && unk != 1)
+				printf("Goto: unk != 0 or 1 (it's %i)\n", unk);
+
+			target = convS->readUint16LE();
+			convS->readUint16LE();	// 255
+
+			if (unk != 0)
+				printf("Goto: unk != 0 (it's %i)\n", unk);
+
+			if (target != 65535)
+				printf("GOTO node %i\n", target);
+			else
+				printf("GOTO exit\n");
+			break;
+		case 8:
+			printf("TODO: chunk type %i\n", chunk);
+			break;
+		case 9:		// ASSIGN
+			//printf("ASSIGN\n");
+			unk = convS->readUint32LE();	// 0
+
+			if (unk != 0)
+				printf("Assign: unk != 0 (it's %i)\n", unk);
+
+			val = convS->readUint16LE();
+			var = convS->readUint16LE();
+			//printf("Var %i = %i\n", var, val);
+			break;
+		default:
+			printf ("Unknown chunk type! (%i)\n", chunk);
+			break;
+		}
+	}
+	printf("\n");
+}
+
+void Converse::setEntryInfo(int32 offset, EntryType type, int32 nodeIndex, int32 entryIndex) {
+	char hashOffset[10];
+	sprintf(hashOffset, "%i", offset);
+	EntryInfo info;
+	info.targetType = type;
+	info.nodeIndex = nodeIndex;
+	info.entryIndex = entryIndex;
+	_offsetMap[hashOffset] = info;
+	//printf("Set entry info: offset %i, type %i, node %i, entry %i\n", offset, type, nodeIndex, entryIndex);
+}
+
+const EntryInfo* Converse::getEntryInfo(int32 offset) { 
+	char hashOffset[10];
+	sprintf(hashOffset, "%i", offset);
+	OffsetHashMap::const_iterator entry = _offsetMap.find(hashOffset);
+	if (entry != _offsetMap.end())
+		return &(entry->_value);
+	else
+		error("Undeclared entry offset: %i", offset);
+}
+
+void Converse::setValue(int32 offset, int32 value) {
+	char hashOffset[10];
+	sprintf(hashOffset, "%i", offset);
+	_variables[hashOffset] = value;
+}
+
+const int32 Converse::getValue(int32 offset) {
+	char hashOffset[10];
+	sprintf(hashOffset, "%i", offset);
+	ConvVarHashMap::const_iterator entry = _variables.find(hashOffset);
+	if (entry != _variables.end())
+		return entry->_value;
+	else
+		error("Undeclared variable offset: %i", offset);
+}
+
+bool Converse::evaluateCondition(int32 leftVal, int32 op, int32 rightVal) {
+	switch (op) {
+	case kOpPercent:
+		return (leftVal % rightVal == 0);
+	case kOpGreaterOrEqual:

@@ Diff output truncated at 100000 characters. @@

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