[Scummvm-cvs-logs] scummvm master -> 46354d5772f9f2ac408bd81590e534ffd2eddc39

sev- sev at scummvm.org
Sun Aug 14 00:36:08 CEST 2011


This automated email contains information about 32 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
ab784944ea AGI: Implement note fetch routine for AGI v2.001 sound resources
3fd26de379 AGI: Detect the bootable floppy version of Donald Duck's Playground
010315dc0c AGI: Implement resource loader for the DDP booter game
1f680ecbc8 AGI: Detect the end of V1 sound resources correctly, fixing crashes
4d4a558f7b AGI: Do not try to pass filenames of disk images from the detector to engine
7405140474 AGI: Cleanup
8183103777 AGI: Simplify sector offset calculation
24bb5da228 AGI: Add a layer of abstraction between the sound chip and the two players
d8e1b392d2 AGI: Use a jump table for test commands instead of switch/case
1507fe4e79 AGI: Fix detection of IIgs sample resources
7a80c4cdb3 AGI: Fix row duration in V1 SOUND resource player
eb797b692f AGI: Simplify handling of IF conditions
e1153cf11f AGI: Comment cleanup
a4e0cd53f0 AGI: Refactor interpreter core (somewhat akin to SCI)
41dccce00c AGI: Execute test commands only when needed
d273f58b3c AGI: AgiLoader_v1: Precalculate final resource offsets
04353038ae AGI: Add loader and detection for Black Cauldron booter
0b6b670803 AGI: Add still incomplete V1 instruction tables
c731f1f48c AGI: Implement common internal dictionary for different words.tok formats
368a3722a3 AGI: Implement loader for V1 words.tok dictionary
d02251fa4d AGI: Formatting (+ a few debug prints)
9bc25749d6 AGI: Implement V1 SAID test commands
09f937126e AGI: Fix and clarify IF expression handling
2289ba88b6 AGI: Rename cmd_what_ever to cmdWhatEver
e4a1193d22 AGI: Add last undefined V1 test command that tests if a bit of var is set
d2f9087f20 AGI: Fix warning messages about undefined opcodes
1dbe5bfccf AGI: Implement loader for V1 "object" file
af691e46c4 AGI: Updates to V1 instruction table, plus an outcommented experiment
3fb50b815e AGI: Further work on v1 opcode difference
be9c5c0427 AGI: Checked V1 instructions till 0x20
3cb41b5dfc AGI: Checked V1 instructions till 0x2c
46354d5772 AGI: Switched booters detection to AD


Commit: ab784944eac1530fa257191ee7b21a154d9f639f
    https://github.com/scummvm/scummvm/commit/ab784944eac1530fa257191ee7b21a154d9f639f
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:19-07:00

Commit Message:
AGI: Implement note fetch routine for AGI v2.001 sound resources

I suspect this is the format for AGI V1 sound resources as well. It is
currently implemented by splitting getNextNote() to getNextNote_v2() and
getNextNote_v1(). Since the V1 format consists of simple register values
to the sound chip in PCjr, this could probably be made more cleanly by
refactoring the code to resemble the chip more closely, so that its state
is updated by writing to the registers.

Changed paths:
    engines/agi/sound.cpp
    engines/agi/sound.h
    engines/agi/sound_pcjr.cpp
    engines/agi/sound_pcjr.h



diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index f2d7af3..f44b34c 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -41,6 +41,10 @@ AgiSound *AgiSound::createFromRawResource(uint8 *data, uint32 len, int resnum, S
 		return NULL;
 	uint16 type = READ_LE_UINT16(data);
 
+	// For V1 sound resources
+	if ((type & 0xFF) == 0x01)
+		return new PCjrSound(data, len, resnum, manager);
+
 	switch (type) { // Create a sound object based on the type
 	case AGI_SOUND_SAMPLE:
 		return new IIgsSample(data, len, resnum, manager);
@@ -62,6 +66,11 @@ PCjrSound::PCjrSound(uint8 *data, uint32 len, int resnum, SoundMgr &manager) : A
 	_data = data; // Save the resource pointer
 	_len  = len;  // Save the resource's length
 	_type = READ_LE_UINT16(data); // Read sound resource's type
+
+	// Detect V1 sound resources
+	if ((_type & 0xFF) == 0x01)
+		_type = AGI_SOUND_4CHN;
+
 	_isValid = (_type == AGI_SOUND_4CHN) && (_data != NULL) && (_len >= 2);
 
 	if (!_isValid) // Check for errors
diff --git a/engines/agi/sound.h b/engines/agi/sound.h
index 0ee1987..bd175d3 100644
--- a/engines/agi/sound.h
+++ b/engines/agi/sound.h
@@ -122,6 +122,8 @@ public:
 	~PCjrSound() { free(_data); }
 	virtual uint16 type() { return _type; }
 	const uint8 *getVoicePointer(uint voiceNum);
+	uint8 *getData() { return _data; }
+	uint32 getLength() { return _len; }
 protected:
 	uint8 *_data; ///< Raw sound resource data
 	uint32 _len;  ///< Length of the raw sound resource
diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index fdebf16..f5cb5e7 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -153,6 +153,9 @@ void SoundGenPCJr::play(int resnum) {
 		_tchannel[i].genType = kGenTone;
 		_tchannel[i].genTypePrev = -1;
 	}
+
+	_v1data = pcjrSound->getData() + 1;
+	_v1size = pcjrSound->getLength() - 1;
 }
 
 void SoundGenPCJr::stop(void) {
@@ -214,11 +217,22 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) {
 	return attenuation;
 }
 
+int SoundGenPCJr::getNextNote(int ch, Tone *tone)
+{
+	if (_vm->getVersion() > 0x2001)
+		return getNextNote_v2(ch, tone);
+	else
+		return getNextNote_v1(ch, tone);
+
+	return -1;
+}
+
 // read the next channel data.. fill it in *tone
 // if tone isn't touched.. it should be inited so it just plays silence
 // return 0 if it's passing more data
 // return -1 if it's passing nothing (end of data)
-int SoundGenPCJr::getNextNote(int ch, Tone *tone) {
+
+int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
 	ToneChan *tpcm;
 	SndGenChan *chan;
 	const byte *data;
@@ -305,6 +319,89 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone) {
 	return 0;
 }
 
+int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
+{
+	static bool fetched[4] = { false, false, false, false };
+	static int duration = 0;
+	
+	// Get previously fetched data if possible
+	if (fetched[ch]) {
+		fetched[ch] = false;
+	
+		tone->freqCount = _channel[ch].freqCount;
+		tone->atten = _channel[ch].attenuation;
+		tone->type = _channel[ch].genType;
+		
+		return 0;
+	}
+
+	// In the V1 player the default duration for a row is 2 ticks
+	if (duration > 0) {
+		duration--;
+
+		tone->freqCount = _channel[ch].freqCount;
+		tone->atten = _channel[ch].attenuation;
+		tone->type = _channel[ch].genType;
+
+		return 0;
+	}
+	duration = 2 * CHAN_MAX;
+
+	// Otherwise fetch a row of data for all channels
+	byte *data = _v1data;
+	uint32 len = _v1size;
+	int reg = 0;
+
+	if (len <= 0 || data == NULL)
+		return -1;
+
+	fetched[0] = fetched[1] = fetched[2] = fetched[3] = true;
+
+	while (*data) {
+		if ((*data & 0x90) == 0x90) {
+			reg = (*data >> 5) & 0x3;
+			_channel[reg].attenuation = *data & 0xF;
+		} else if ((*data & 0xF0) == 0xE0) {
+			_channel[3].genType = (data[3] & 0x4) ? kGenWhite : kGenPeriod;
+			int noiseFreq = data[3] & 0x03;
+			switch (noiseFreq) {
+			case 0:
+				_channel[3].freqCount = 32;
+				break;
+			case 1:
+				_channel[3].freqCount = 64;
+				break;
+			case 2:
+				_channel[3].freqCount = 128;
+				break;
+			case 3:
+				_channel[3].freqCount = _channel[2].freqCount * 2;
+				break;
+			}
+		} else if (*data & 0x80) {
+			reg = (*data >> 5) & 0x3;
+			_channel[reg].freqCount = *data & 0xF;
+			_channel[reg].genType = kGenTone;
+		} else {
+			_channel[reg].freqCount |= (*data & 0x3F) << 4;
+		}
+
+		data++;
+		len--;
+	}
+	data++;
+	len--;
+
+	_v1data = data;
+	_v1size = len;
+
+	tone->freqCount = _channel[ch].freqCount;
+	tone->atten = _channel[ch].attenuation;
+	tone->type = _channel[ch].genType;
+
+	return 0;
+}
+
 // Formulas for noise generator
 // bit0 = output
 
@@ -348,9 +445,13 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
 
 	retVal = -1;
 
+	debugC(5, kDebugLevelSound, "chanGen()");
+
 	while (len > 0) {
 		if (tpcm->noteCount <= 0) {
 			// get new tone data
+			tpcm->avail=1;
+			debugC(5, kDebugLevelSound, "new note data (avail=%d)", tpcm->avail);
 			toneNew.freqCount = 0;
 			toneNew.atten = 0xF;
 			toneNew.type = kGenTone;
diff --git a/engines/agi/sound_pcjr.h b/engines/agi/sound_pcjr.h
index 4317e86..d9ced4a 100644
--- a/engines/agi/sound_pcjr.h
+++ b/engines/agi/sound_pcjr.h
@@ -103,6 +103,8 @@ public:
 
 private:
 	int getNextNote(int ch, Tone *tone);
+	int getNextNote_v2(int ch, Tone *tone);
+	int getNextNote_v1(int ch, Tone *tone);
 	int volumeCalc(SndGenChan *chan);
 
 	int chanGen(int chan, int16 *stream, int len);
@@ -117,6 +119,9 @@ private:
 	int _chanAllocated;
 
 	int _dissolveMethod;
+
+	uint8 *_v1data;
+	uint32 _v1size;
 };
 
 } // End of namespace Agi


Commit: 3fd26de37978a404e228f9500883936c979da032
    https://github.com/scummvm/scummvm/commit/3fd26de37978a404e228f9500883936c979da032
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:22-07:00

Commit Message:
AGI: Detect the bootable floppy version of Donald Duck's Playground

Also create a framework into which more booter games can be added.

Changed paths:
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/detection_tables.h



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 0155caf..2bc1144 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -646,6 +646,28 @@ public:
 	virtual int loadWords(const char *) = 0;
 };
 
+class AgiLoader_v1 : public AgiLoader {
+private:
+	AgiEngine *_vm;
+	Common::String _dsk0Name;
+	Common::String _dsk1Name;
+
+public:
+	AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) {
+		_vm = vm;
+		_dsk0Name = dsk0;
+		_dsk1Name = dsk1;
+	}
+
+	virtual int init() { return 0; }
+	virtual int deinit() { return 0; }
+	virtual int detectGame() { return 0; }
+	virtual int loadResource(int, int) { return 0; }
+	virtual int unloadResource(int, int) { return 0; }
+	virtual int loadObjects(const char *) { return 0; }
+	virtual int loadWords(const char *) { return 0; }
+};
+
 class AgiLoader_v2 : public AgiLoader {
 private:
 	AgiEngine *_vm;
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 93fcd2d..854658c 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -28,6 +28,7 @@
 #include "engines/advancedDetector.h"
 #include "common/config-manager.h"
 #include "common/file.h"
+#include "common/md5.h"
 #include "common/savefile.h"
 #include "common/textconsole.h"
 #include "graphics/thumbnail.h"
@@ -47,6 +48,9 @@ struct AGIGameDescription {
 	int gameType;
 	uint32 features;
 	uint16 version;
+
+	Common::String dsk0Name;
+	Common::String dsk1Name;
 };
 
 uint32 AgiBase::getGameID() const {
@@ -290,7 +294,9 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
 
 const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
 	typedef Common::HashMap<Common::String, int32> IntMap;
+	typedef Common::HashMap<Common::String, Common::FSNode> NodeMap;
 	IntMap allFiles;
+	NodeMap allNodes;
 	bool matchedUsingFilenames = false;
 	bool matchedUsingWag = false;
 	int wagFileCount = 0;
@@ -317,7 +323,8 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 		if (file->isDirectory()) continue;
 		Common::String filename = file->getName();
 		filename.toLowercase();
-		allFiles[filename] = true; // Save the filename in a hash table
+		allFiles[filename] = true;   // Save the filename in a hash table
+		allNodes[filename] = *file;  // ...and also the FSNode
 
 		if (filename.hasSuffix(".wag")) {
 			// Save latest found *.wag file's path (Can be used to open the file, the name can't)
@@ -420,6 +427,46 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 		warning("More than one (%d) *.wag files found. WAG files ignored", wagFileCount);
 	}
 
+	// Try to detect disk images of AGI v1 and AGI v2.001 booter games
+	if (!matchedUsingFilenames && !matchedUsingWag) {
+		int index = -1;
+		
+		for (IntMap::const_iterator f = allFiles.begin(); f != allFiles.end(); ++f) {
+			if (f->_key.hasSuffix(".dsk") || f->_key.hasSuffix(".img")) {
+				Common::File file;
+				file.open(allNodes[f->_key]);
+				Common::String md5str = Common::computeStreamMD5AsString(file, detectionParams.md5Bytes);
+				debug(3, "Agi::fallbackDetector: disk image (%s) found with md5 sum (%s) ", f->_key.c_str(), md5str.c_str());
+
+				for (int i = 0; !booterDescription[i].md5str_dsk0.empty(); i++) {
+					if (booterDescription[i].md5str_dsk0 == md5str) {
+						index = i;
+						g_fallbackDesc.dsk0Name = f->_key;
+					}
+					if (booterDescription[i].md5str_dsk1 == md5str) {
+						index = i;
+						g_fallbackDesc.dsk1Name = f->_key;
+					}
+				}
+			}
+		}
+		
+		if (index >= 0) {
+			if ((booterDescription[index].md5str_dsk0.empty() == g_fallbackDesc.dsk0Name.empty()) &&
+				(booterDescription[index].md5str_dsk1.empty() == g_fallbackDesc.dsk1Name.empty())) {
+				g_fallbackDesc.gameID = booterDescription[index].gameID;
+				g_fallbackDesc.gameType = booterDescription[index].gameType;
+				g_fallbackDesc.features = booterDescription[index].features;
+				g_fallbackDesc.version = booterDescription[index].version;
+
+				g_fallbackDesc.desc.gameid = booterDescription[index].id.c_str();
+				g_fallbackDesc.desc.extra = booterDescription[index].extra.c_str();
+
+				return (const ADGameDescription *)&g_fallbackDesc;
+			}
+		}
+	}
+
 	// Check that the AGI interpreter version is a supported one
 	if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) {
 		warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version);
@@ -477,7 +524,9 @@ int AgiEngine::agiDetectGame() {
 
 	assert(_gameDescription != NULL);
 
-	if (getVersion() <= 0x2999) {
+	if (getVersion() <= 0x2001) {
+		_loader = new AgiLoader_v1(this, _gameDescription->dsk0Name, _gameDescription->dsk1Name);
+	} else if (getVersion() <= 0x2999) {
 		_loader = new AgiLoader_v2(this);
 	} else {
 		_loader = new AgiLoader_v3(this);
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index cd3edf5..ade4524 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -38,6 +38,8 @@ using Common::GUIO_NONE;
 		interp, \
 		features, \
 		ver, \
+		"", \
+		"" \
 	}
 
 #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \
@@ -54,6 +56,8 @@ using Common::GUIO_NONE;
 		interp, \
 		features, \
 		ver, \
+		"", \
+		"" \
 	}
 
 #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
@@ -197,6 +201,8 @@ static const AGIGameDescription gameDescriptions[] = {
 		GType_V3,
 		GF_MACGOLDRUSH,
 		0x3149,
+		"",
+		""
 	},
 
 
@@ -515,6 +521,8 @@ static const AGIGameDescription gameDescriptions[] = {
 		GType_V2,
 		0,
 		0x2936,
+		"",
+		""
 	},
 
 
@@ -660,6 +668,8 @@ static const AGIGameDescription gameDescriptions[] = {
 		GType_V2,
 		GF_AGDS,
 		0x2440,
+		"",
+		""
 	},
 
 	{
@@ -677,6 +687,8 @@ static const AGIGameDescription gameDescriptions[] = {
 		GType_V2,
 		0,
 		0x2440,
+		"",
+		""
 	},
 
 	FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE),
@@ -832,6 +844,8 @@ static const AGIGameDescription gameDescriptions[] = {
 		GType_V3,
 		GF_FANMADE,
 		0x3149,
+		"",
+		"",
 	},
 	FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3),
 
@@ -839,7 +853,7 @@ static const AGIGameDescription gameDescriptions[] = {
 	FANMADE("Voodoo Girl - Queen of the Darned (v1.2 2002 Mar 29)", "11d0417b7b886f963d0b36789dac4c8f"),
 	FANMADE("Wizaro (v0.1)", "abeec1eda6eaf8dbc52443ea97ff140c"),
 
-	{ AD_TABLE_END_MARKER, 0, 0, 0, 0 }
+	{ AD_TABLE_END_MARKER, 0, 0, 0, 0, "", "" }
 };
 
 /**
@@ -860,6 +874,25 @@ static AGIGameDescription g_fallbackDesc = {
 	GType_V2,
 	GF_FANMADE,
 	0x2917,
+	"",
+	""
+};
+
+/**
+ * Detection table for booter games.
+ */
+static const struct {
+	Common::String md5str_dsk0;
+	Common::String md5str_dsk1;
+	Common::String id;
+	Common::String extra;
+	int gameID;
+	int gameType;
+	uint32 features;
+	uint16 version;
+} booterDescription[] = {
+	{ "f323f10abf8140ffb2668b09af2e7b87", "", "ddp", "booter", GID_DDP, GType_V2, ADGF_NO_FLAGS, 0x2001 },
+	{ "", "", "", "", 0, 0, 0, 0 }
 };
 
 } // End of namespace Agi


Commit: 010315dc0c1862de6778130e416880388b9d0bdf
    https://github.com/scummvm/scummvm/commit/010315dc0c1862de6778130e416880388b9d0bdf
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:24-07:00

Commit Message:
AGI: Implement resource loader for the DDP booter game

Changed paths:
  A engines/agi/loader_v1.cpp
    engines/agi/agi.h
    engines/agi/module.mk



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 2bc1144..bf730fc 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -652,6 +652,9 @@ private:
 	Common::String _dsk0Name;
 	Common::String _dsk1Name;
 
+	int loadDir(AgiDir *agid, int offset, int num);
+	uint8 *loadVolRes(AgiDir *agid);
+
 public:
 	AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) {
 		_vm = vm;
@@ -659,13 +662,13 @@ public:
 		_dsk1Name = dsk1;
 	}
 
-	virtual int init() { return 0; }
-	virtual int deinit() { return 0; }
-	virtual int detectGame() { return 0; }
-	virtual int loadResource(int, int) { return 0; }
-	virtual int unloadResource(int, int) { return 0; }
-	virtual int loadObjects(const char *) { return 0; }
-	virtual int loadWords(const char *) { return 0; }
+	virtual int init();
+	virtual int deinit();
+	virtual int detectGame();
+	virtual int loadResource(int, int);
+	virtual int unloadResource(int, int);
+	virtual int loadObjects(const char *);
+	virtual int loadWords(const char *);
 };
 
 class AgiLoader_v2 : public AgiLoader {
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
new file mode 100644
index 0000000..40f7972
--- /dev/null
+++ b/engines/agi/loader_v1.cpp
@@ -0,0 +1,249 @@
+/* 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.
+ *
+ */
+
+#include "agi/agi.h"
+
+#define offsetTHS(track,head,sector) (512 * ((((track) * 2 + (head)) * 9) + (sector)))
+#define offset(sector) offsetTHS(sector / 18, (sector % 18) / 9, (sector % 18) % 9)
+
+#define BASE_SECTOR	0x1C2
+
+#define LOGDIR_SEC	offset(171) + 5
+#define LOGDIR_NUM	43
+
+#define PICDIR_SEC	offset(180) + 5
+#define PICDIR_NUM	30
+
+#define VIEWDIR_SEC	offset(189) + 5
+#define VIEWDIR_NUM	171
+
+#define SNDDIR_SEC	offset(198) + 5
+#define SNDDIR_NUM	64
+
+namespace Agi {
+
+int AgiLoader_v1::detectGame() {
+	return _vm->setupV2Game(_vm->getVersion());
+}
+
+int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
+	Common::File fp;
+	
+	if (!fp.open(_dsk0Name))
+		return errBadFileOpen;
+
+	// Cleanup
+	for (int i = 0; i < MAX_DIRS; i++) {
+		agid[i].volume = 0xFF;
+		agid[i].offset = _EMPTY;
+	}
+	
+	fp.seek(offset, SEEK_SET);
+	for (int i = 0; i < num; i++) {
+		int b0 = fp.readByte();
+		int b1 = fp.readByte();
+		int b2 = fp.readByte();
+		
+		if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) {
+			agid[i].volume = 0xFF;
+			agid[i].offset = _EMPTY;
+		} else {
+			int sec = (BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1;
+			int off = ((b1 & 0x1) << 8) | b2;
+			agid[i].volume = 0;
+			agid[i].offset = (sec << 16) | off;
+		}
+	}
+
+	fp.close();
+
+	return errOK;
+}
+
+int AgiLoader_v1::init() {
+	int ec = errOK;
+
+	ec = loadDir(_vm->_game.dirLogic, LOGDIR_SEC, LOGDIR_NUM);
+	if (ec == errOK)
+		ec = loadDir(_vm->_game.dirPic, PICDIR_SEC, PICDIR_NUM);
+	if (ec == errOK)
+		ec = loadDir(_vm->_game.dirView, VIEWDIR_SEC, VIEWDIR_NUM);
+	if (ec == errOK)
+		ec = loadDir(_vm->_game.dirSound, SNDDIR_SEC, SNDDIR_NUM);
+
+	return ec;
+}
+
+int AgiLoader_v1::deinit() {
+	int ec = errOK;
+	return ec;
+}
+
+uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
+	uint8 *data = NULL;
+	Common::File fp;
+
+	if (agid->offset == _EMPTY)
+		return NULL;
+	
+	int sec = agid->offset >> 16;
+	int off = agid->offset & 0xFFFF;
+	
+	fp.open(_dsk0Name);
+	fp.seek(offset(sec) + off, SEEK_SET);
+
+	int signature = fp.readUint16BE();
+	if (signature != 0x1234) {
+		warning("AgiLoader_v1::loadVolRes: bad signature %04x", signature);
+		return NULL;
+	}
+
+	fp.readByte();
+	agid->len = fp.readUint16LE();
+	data = (uint8 *)calloc(1, agid->len + 32);
+	fp.read(data, agid->len);
+	
+	fp.close();
+
+	return data;
+}
+
+int AgiLoader_v1::loadResource(int t, int n) {
+	int ec = errOK;
+	uint8 *data = NULL;
+
+	debugC(3, kDebugLevelResources, "(t = %d, n = %d)", t, n);
+	if (n > MAX_DIRS)
+		return errBadResource;
+
+	switch (t) {
+	case rLOGIC:
+		if (~_vm->_game.dirLogic[n].flags & RES_LOADED) {
+			debugC(3, kDebugLevelResources, "loading logic resource %d", n);
+			unloadResource(rLOGIC, n);
+
+			// load raw resource into data
+			data = loadVolRes(&_vm->_game.dirLogic[n]);
+
+			_vm->_game.logics[n].data = data;
+			ec = data ? _vm->decodeLogic(n) : errBadResource;
+
+			_vm->_game.logics[n].sIP = 2;
+		}
+
+		// if logic was cached, we get here
+		// reset code pointers incase it was cached
+
+		_vm->_game.logics[n].cIP = _vm->_game.logics[n].sIP;
+		break;
+	case rPICTURE:
+		// if picture is currently NOT loaded *OR* cacheing is off,
+		// unload the resource (caching == off) and reload it
+
+		debugC(3, kDebugLevelResources, "loading picture resource %d", n);
+		if (_vm->_game.dirPic[n].flags & RES_LOADED)
+			break;
+
+		// if loaded but not cached, unload it
+		// if cached but not loaded, etc
+		unloadResource(rPICTURE, n);
+		data = loadVolRes(&_vm->_game.dirPic[n]);
+
+		if (data != NULL) {
+			_vm->_game.pictures[n].rdata = data;
+			_vm->_game.dirPic[n].flags |= RES_LOADED;
+		} else {
+			ec = errBadResource;
+		}
+		break;
+	case rSOUND:
+		debugC(3, kDebugLevelResources, "loading sound resource %d", n);
+		if (_vm->_game.dirSound[n].flags & RES_LOADED)
+			break;
+
+		data = loadVolRes(&_vm->_game.dirSound[n]);
+
+		if (data != NULL) {
+			// Freeing of the raw resource from memory is delegated to the createFromRawResource-function
+			_vm->_game.sounds[n] = AgiSound::createFromRawResource(data, _vm->_game.dirSound[n].len, n, *_vm->_sound, _vm->_soundemu);
+			_vm->_game.dirSound[n].flags |= RES_LOADED;
+		} else {
+			ec = errBadResource;
+		}
+		break;
+	case rVIEW:
+		// Load a VIEW resource into memory...
+		// Since VIEWS alter the view table ALL the time
+		// can we cache the view? or must we reload it all
+		// the time?
+		if (_vm->_game.dirView[n].flags & RES_LOADED)
+			break;
+
+		debugC(3, kDebugLevelResources, "loading view resource %d", n);
+		unloadResource(rVIEW, n);
+		data = loadVolRes(&_vm->_game.dirView[n]);
+		if (data) {
+			_vm->_game.views[n].rdata = data;
+			_vm->_game.dirView[n].flags |= RES_LOADED;
+			ec = _vm->decodeView(n);
+		} else {
+			ec = errBadResource;
+		}
+		break;
+	default:
+		ec = errBadResource;
+		break;
+	}
+
+	return ec;
+}
+
+int AgiLoader_v1::unloadResource(int t, int n) {
+	switch (t) {
+	case rLOGIC:
+		_vm->unloadLogic(n);
+		break;
+	case rPICTURE:
+		_vm->_picture->unloadPicture(n);
+		break;
+	case rVIEW:
+		_vm->unloadView(n);
+		break;
+	case rSOUND:
+		_vm->_sound->unloadSound(n);
+		break;
+	}
+
+	return errOK;
+}
+
+// TODO: Find the disk image equivalent.
+int AgiLoader_v1::loadObjects(const char *fname) {
+	return _vm->loadObjects(fname);
+}
+
+// TODO: Find the disk image equivalent.
+int AgiLoader_v1::loadWords(const char *fname) {
+	return _vm->loadObjects(fname);
+}
+
+}
diff --git a/engines/agi/module.mk b/engines/agi/module.mk
index 2339d10..3bb4dac 100644
--- a/engines/agi/module.mk
+++ b/engines/agi/module.mk
@@ -11,6 +11,7 @@ MODULE_OBJS := \
 	id.o \
 	inv.o \
 	keyboard.o \
+	loader_v1.o \
 	loader_v2.o \
 	loader_v3.o \
 	logic.o \


Commit: 1f680ecbc83f34749911dd45be130b0580eb37a9
    https://github.com/scummvm/scummvm/commit/1f680ecbc83f34749911dd45be130b0580eb37a9
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:27-07:00

Commit Message:
AGI: Detect the end of V1 sound resources correctly, fixing crashes

Changed paths:
    engines/agi/sound_pcjr.cpp



diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index f5cb5e7..d5c6935 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -126,6 +126,9 @@ SoundGenPCJr::SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer) : SoundGen(vm, p
 	memset(_tchannel, 0, sizeof(_tchannel));
 
 	_mixer->playStream(Audio::Mixer::kMusicSoundType, &_soundHandle, this, -1, Audio::Mixer::kMaxChannelVolume, 0, DisposeAfterUse::NO, true);
+
+	_v1data = NULL;
+	_v1size = 0;
 }
 
 SoundGenPCJr::~SoundGenPCJr() {
@@ -323,6 +326,17 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
 {
 	static bool fetched[4] = { false, false, false, false };
 	static int duration = 0;
+
+	byte *data = _v1data;
+	uint32 len = _v1size;
+	int reg = 0;
+
+	if (len <= 0 || data == NULL) {
+		_channel[ch].avail = 0;
+		_channel[ch].attenuation = 0x0F;
+		_channel[ch].attenuationCopy = 0x0F;
+		return -1;
+	}
 	
 	// Get previously fetched data if possible
 	if (fetched[ch]) {
@@ -348,13 +362,6 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
 	duration = 2 * CHAN_MAX;
 
 	// Otherwise fetch a row of data for all channels
-	byte *data = _v1data;
-	uint32 len = _v1size;
-	int reg = 0;
-
-	if (len <= 0 || data == NULL)
-		return -1;
-
 	fetched[0] = fetched[1] = fetched[2] = fetched[3] = true;
 
 	while (*data) {


Commit: 4d4a558f7beda9e3732dd30f16a6e73f5e805df2
    https://github.com/scummvm/scummvm/commit/4d4a558f7beda9e3732dd30f16a6e73f5e805df2
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:29-07:00

Commit Message:
AGI: Do not try to pass filenames of disk images from the detector to engine

Changed paths:
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/detection_tables.h
    engines/agi/loader_v1.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index bf730fc..2d9432b 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -631,6 +631,24 @@ struct AgiGame {
 	Common::Rect mouseFence;		/**< rectangle set by fence.mouse command */
 };
 
+/**
+ * Check if a disk image with the given MD5 sum exists in the search path.
+ *
+ * @param  md5       MD5 sum of the disk image to be searched
+ * @param  filename  Filled with a filename in case the image is found
+ * @return True if found, otherwise false.
+ */
+bool diskImageExists(Common::String md5, Common::String &filename);
+
+/**
+ * Get MD5 sums for a given game from the booter game description table.
+ *
+ * @param gid       Game ID of the game
+ * @param md5Disk0  Filled with the MD5 sum of disk 0
+ * @param md5Disk1  Filled with the MD5 sum of disk 1 if there are two disks
+ */
+bool getBooterMD5Sums(AgiGameID gid, Common::String &md5Disk0, Common::String &md5Disk1);
+
 class AgiLoader {
 public:
 
@@ -649,18 +667,14 @@ public:
 class AgiLoader_v1 : public AgiLoader {
 private:
 	AgiEngine *_vm;
-	Common::String _dsk0Name;
-	Common::String _dsk1Name;
+	Common::String _filenameDisk0;
+	Common::String _filenameDisk1;
 
 	int loadDir(AgiDir *agid, int offset, int num);
 	uint8 *loadVolRes(AgiDir *agid);
 
 public:
-	AgiLoader_v1(AgiEngine *vm, Common::String dsk0, Common::String dsk1) {
-		_vm = vm;
-		_dsk0Name = dsk0;
-		_dsk1Name = dsk1;
-	}
+	AgiLoader_v1(AgiEngine *vm);
 
 	virtual int init();
 	virtual int deinit();
@@ -715,6 +729,7 @@ public:
 	virtual int loadWords(const char *);
 };
 
+
 class GfxMgr;
 class SpritesMgr;
 class Menu;
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 854658c..7c6cf0e 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -48,9 +48,6 @@ struct AGIGameDescription {
 	int gameType;
 	uint32 features;
 	uint16 version;
-
-	Common::String dsk0Name;
-	Common::String dsk1Name;
 };
 
 uint32 AgiBase::getGameID() const {
@@ -97,6 +94,20 @@ void AgiBase::initVersion() {
 	_gameVersion = _gameDescription->version;
 }
 
+struct AGIBooterDescription {
+	Common::String md5Disk0;
+	Common::String md5Disk1;
+	Common::String id;
+	Common::String extra;
+	int gameID;
+	int gameType;
+	uint32 features;
+	uint16 version;
+};
+
+bool isDiskImage(Common::SeekableReadStream *stream, Common::String filename, Common::String md5);
+bool diskImageExistsInFSList(const Common::FSList &fslist, Common::String md5, Common::String &filename);
+
 }
 
 static const PlainGameDescriptor agiGames[] = {
@@ -294,9 +305,7 @@ SaveStateDescriptor AgiMetaEngine::querySaveMetaInfos(const char *target, int sl
 
 const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXXX, const Common::FSList &fslist) const {
 	typedef Common::HashMap<Common::String, int32> IntMap;
-	typedef Common::HashMap<Common::String, Common::FSNode> NodeMap;
 	IntMap allFiles;
-	NodeMap allNodes;
 	bool matchedUsingFilenames = false;
 	bool matchedUsingWag = false;
 	int wagFileCount = 0;
@@ -324,7 +333,6 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 		Common::String filename = file->getName();
 		filename.toLowercase();
 		allFiles[filename] = true;   // Save the filename in a hash table
-		allNodes[filename] = *file;  // ...and also the FSNode
 
 		if (filename.hasSuffix(".wag")) {
 			// Save latest found *.wag file's path (Can be used to open the file, the name can't)
@@ -429,41 +437,25 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 
 	// Try to detect disk images of AGI v1 and AGI v2.001 booter games
 	if (!matchedUsingFilenames && !matchedUsingWag) {
-		int index = -1;
-		
-		for (IntMap::const_iterator f = allFiles.begin(); f != allFiles.end(); ++f) {
-			if (f->_key.hasSuffix(".dsk") || f->_key.hasSuffix(".img")) {
-				Common::File file;
-				file.open(allNodes[f->_key]);
-				Common::String md5str = Common::computeStreamMD5AsString(file, detectionParams.md5Bytes);
-				debug(3, "Agi::fallbackDetector: disk image (%s) found with md5 sum (%s) ", f->_key.c_str(), md5str.c_str());
-
-				for (int i = 0; !booterDescription[i].md5str_dsk0.empty(); i++) {
-					if (booterDescription[i].md5str_dsk0 == md5str) {
-						index = i;
-						g_fallbackDesc.dsk0Name = f->_key;
-					}
-					if (booterDescription[i].md5str_dsk1 == md5str) {
-						index = i;
-						g_fallbackDesc.dsk1Name = f->_key;
-					}
-				}
-			}
-		}
-		
-		if (index >= 0) {
-			if ((booterDescription[index].md5str_dsk0.empty() == g_fallbackDesc.dsk0Name.empty()) &&
-				(booterDescription[index].md5str_dsk1.empty() == g_fallbackDesc.dsk1Name.empty())) {
-				g_fallbackDesc.gameID = booterDescription[index].gameID;
-				g_fallbackDesc.gameType = booterDescription[index].gameType;
-				g_fallbackDesc.features = booterDescription[index].features;
-				g_fallbackDesc.version = booterDescription[index].version;
-
-				g_fallbackDesc.desc.gameid = booterDescription[index].id.c_str();
-				g_fallbackDesc.desc.extra = booterDescription[index].extra.c_str();
-
-				return (const ADGameDescription *)&g_fallbackDesc;
-			}
+		for (int i = 0; !booterDescription[i].md5Disk0.empty(); i++) {
+			Common::String filenameDisk0;
+			Common::String filenameDisk1;
+
+			if (!diskImageExistsInFSList(fslist, booterDescription[i].md5Disk0, filenameDisk0))
+				continue;
+			if (!booterDescription[i].md5Disk1.empty())
+				if (!diskImageExistsInFSList(fslist, booterDescription[i].md5Disk1, filenameDisk1))
+					continue;
+
+			g_fallbackDesc.gameID = booterDescription[i].gameID;
+			g_fallbackDesc.gameType = booterDescription[i].gameType;
+			g_fallbackDesc.features = booterDescription[i].features;
+			g_fallbackDesc.version = booterDescription[i].version;
+
+			g_fallbackDesc.desc.gameid = booterDescription[i].id.c_str();
+			g_fallbackDesc.desc.extra = booterDescription[i].extra.c_str();
+
+			return (const ADGameDescription *)&g_fallbackDesc;
 		}
 	}
 
@@ -508,6 +500,66 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 
 namespace Agi {
 
+bool isDiskImage(Common::SeekableReadStream *stream, Common::String filename, Common::String md5) {
+	if (!(filename.hasSuffix(".dsk") || filename.hasSuffix(".img")))
+		return false;
+
+	if (stream->size() == 368640 && computeStreamMD5AsString(*stream, 5000) == md5)
+		return true;
+
+	return false;
+}
+
+bool diskImageExistsInFSList(const Common::FSList &fslist, Common::String md5, Common::String &filename) {
+	for (Common::FSList::const_iterator x = fslist.begin(); x != fslist.end(); x++) {
+		if (x->isDirectory()) continue;
+		
+		Common::SeekableReadStream *stream = x->createReadStream();
+		if (isDiskImage(stream, x->getName(), md5)) {
+			filename = x->getName();
+			delete stream;
+			return true;
+		}
+		delete stream;
+	}
+
+	return false;
+}
+
+bool diskImageExists(Common::String md5, Common::String &filename) {
+	Common::ArchiveMemberList files;
+	SearchMan.listMembers(files);
+	
+	Common::File file;
+	for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); x++) {
+		file.open((*x)->getName());
+		if (isDiskImage(&file, (*x)->getName(), md5)) {
+			filename = (*x)->getName();
+			file.close();
+			return true;
+		}
+		file.close();
+	}
+	
+	return false;
+}
+
+bool getBooterMD5Sums(AgiGameID gid, Common::String &md5Disk0, Common::String &md5Disk1) {
+	AGIBooterDescription *booter = NULL;
+	int i = 0;
+	while (!booterDescription[i].md5Disk0.empty()) {
+		if (booterDescription[i].gameID == gid)
+			booter = &booterDescription[i];
+		i++;
+	}
+	if (booter == NULL)
+		return false;
+	
+	md5Disk0 = booter->md5Disk0;
+	md5Disk1 = booter->md5Disk1;
+	return true;
+}
+
 bool AgiBase::canLoadGameStateCurrently() {
 	return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed);
 }
@@ -525,7 +577,7 @@ int AgiEngine::agiDetectGame() {
 	assert(_gameDescription != NULL);
 
 	if (getVersion() <= 0x2001) {
-		_loader = new AgiLoader_v1(this, _gameDescription->dsk0Name, _gameDescription->dsk1Name);
+		_loader = new AgiLoader_v1(this);
 	} else if (getVersion() <= 0x2999) {
 		_loader = new AgiLoader_v2(this);
 	} else {
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index ade4524..c535744 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -37,9 +37,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver, \
-		"", \
-		"" \
+		ver \
 	}
 
 #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \
@@ -55,9 +53,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver, \
-		"", \
-		"" \
+		ver \
 	}
 
 #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
@@ -200,9 +196,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GOLDRUSH,
 		GType_V3,
 		GF_MACGOLDRUSH,
-		0x3149,
-		"",
-		""
+		0x3149
 	},
 
 
@@ -520,9 +514,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_SQ2,
 		GType_V2,
 		0,
-		0x2936,
-		"",
-		""
+		0x2936
 	},
 
 
@@ -667,9 +659,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V2,
 		GF_AGDS,
-		0x2440,
-		"",
-		""
+		0x2440
 	},
 
 	{
@@ -686,9 +676,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GETOUTTASQ,
 		GType_V2,
 		0,
-		0x2440,
-		"",
-		""
+		0x2440
 	},
 
 	FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE),
@@ -843,9 +831,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V3,
 		GF_FANMADE,
-		0x3149,
-		"",
-		"",
+		0x3149
 	},
 	FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3),
 
@@ -853,7 +839,7 @@ static const AGIGameDescription gameDescriptions[] = {
 	FANMADE("Voodoo Girl - Queen of the Darned (v1.2 2002 Mar 29)", "11d0417b7b886f963d0b36789dac4c8f"),
 	FANMADE("Wizaro (v0.1)", "abeec1eda6eaf8dbc52443ea97ff140c"),
 
-	{ AD_TABLE_END_MARKER, 0, 0, 0, 0, "", "" }
+	{ AD_TABLE_END_MARKER, 0, 0, 0, 0 }
 };
 
 /**
@@ -873,25 +859,16 @@ static AGIGameDescription g_fallbackDesc = {
 	GID_FANMADE,
 	GType_V2,
 	GF_FANMADE,
-	0x2917,
-	"",
-	""
+	0x2917
 };
 
 /**
- * Detection table for booter games.
+ * Descriptor table for booter games
  */
-static const struct {
-	Common::String md5str_dsk0;
-	Common::String md5str_dsk1;
-	Common::String id;
-	Common::String extra;
-	int gameID;
-	int gameType;
-	uint32 features;
-	uint16 version;
-} booterDescription[] = {
-	{ "f323f10abf8140ffb2668b09af2e7b87", "", "ddp", "booter", GID_DDP, GType_V2, ADGF_NO_FLAGS, 0x2001 },
+#define BOOTER_V2(id, extra, md50, md51, gid) { md50, md51, id, extra, gid, GType_V2, ADGF_NO_FLAGS, 0x2001 },
+
+static AGIBooterDescription booterDescription[] = {
+	BOOTER_V2("ddp", "booter", "f323f10abf8140ffb2668b09af2e7b87", "", GID_DDP)
 	{ "", "", "", "", 0, 0, 0, 0 }
 };
 
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 40f7972..90655ec 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -21,6 +21,7 @@
  */
 
 #include "agi/agi.h"
+#include "common/md5.h"
 
 #define offsetTHS(track,head,sector) (512 * ((((track) * 2 + (head)) * 9) + (sector)))
 #define offset(sector) offsetTHS(sector / 18, (sector % 18) / 9, (sector % 18) % 9)
@@ -41,6 +42,18 @@
 
 namespace Agi {
 
+
+AgiLoader_v1::AgiLoader_v1(AgiEngine *vm) {
+	_vm = vm;
+	
+	// Find filenames for the disk images
+	Common::String md5Disk0, md5Disk1;
+	getBooterMD5Sums((AgiGameID)_vm->getGameID(), md5Disk0, md5Disk1);
+	diskImageExists(md5Disk0, _filenameDisk0);
+	if (!md5Disk1.empty())
+		diskImageExists(md5Disk1, _filenameDisk1);
+}
+
 int AgiLoader_v1::detectGame() {
 	return _vm->setupV2Game(_vm->getVersion());
 }
@@ -48,7 +61,7 @@ int AgiLoader_v1::detectGame() {
 int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
 	Common::File fp;
 	
-	if (!fp.open(_dsk0Name))
+	if (!fp.open(_filenameDisk0))
 		return errBadFileOpen;
 
 	// Cleanup
@@ -108,7 +121,7 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
 	int sec = agid->offset >> 16;
 	int off = agid->offset & 0xFFFF;
 	
-	fp.open(_dsk0Name);
+	fp.open(_filenameDisk0);
 	fp.seek(offset(sec) + off, SEEK_SET);
 
 	int signature = fp.readUint16BE();


Commit: 740514047468f0e5764872d01f0a91b58567bb96
    https://github.com/scummvm/scummvm/commit/740514047468f0e5764872d01f0a91b58567bb96
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:32-07:00

Commit Message:
AGI: Cleanup

Changed paths:
    engines/agi/detection.cpp
    engines/agi/detection_tables.h



diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index 7c6cf0e..c6c9740 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -332,7 +332,7 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 		if (file->isDirectory()) continue;
 		Common::String filename = file->getName();
 		filename.toLowercase();
-		allFiles[filename] = true;   // Save the filename in a hash table
+		allFiles[filename] = true; // Save the filename in a hash table
 
 		if (filename.hasSuffix(".wag")) {
 			// Save latest found *.wag file's path (Can be used to open the file, the name can't)
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index c535744..e59765f 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -37,7 +37,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver \
+		ver, \
 	}
 
 #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \
@@ -53,7 +53,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver \
+		ver, \
 	}
 
 #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
@@ -196,7 +196,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GOLDRUSH,
 		GType_V3,
 		GF_MACGOLDRUSH,
-		0x3149
+		0x3149,
 	},
 
 
@@ -514,7 +514,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_SQ2,
 		GType_V2,
 		0,
-		0x2936
+		0x2936,
 	},
 
 
@@ -659,7 +659,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V2,
 		GF_AGDS,
-		0x2440
+		0x2440,
 	},
 
 	{
@@ -676,7 +676,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GETOUTTASQ,
 		GType_V2,
 		0,
-		0x2440
+		0x2440,
 	},
 
 	FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE),
@@ -831,7 +831,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V3,
 		GF_FANMADE,
-		0x3149
+		0x3149,
 	},
 	FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3),
 
@@ -859,7 +859,7 @@ static AGIGameDescription g_fallbackDesc = {
 	GID_FANMADE,
 	GType_V2,
 	GF_FANMADE,
-	0x2917
+	0x2917,
 };
 
 /**


Commit: 8183103777fbf3528d184aa87201aed76923d8a1
    https://github.com/scummvm/scummvm/commit/8183103777fbf3528d184aa87201aed76923d8a1
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:34-07:00

Commit Message:
AGI: Simplify sector offset calculation

Changed paths:
    engines/agi/loader_v1.cpp



diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 90655ec..ed667f9 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -23,21 +23,20 @@
 #include "agi/agi.h"
 #include "common/md5.h"
 
-#define offsetTHS(track,head,sector) (512 * ((((track) * 2 + (head)) * 9) + (sector)))
-#define offset(sector) offsetTHS(sector / 18, (sector % 18) / 9, (sector % 18) % 9)
+#define SECTOR_OFFSET(s) ((s) * 512)
 
 #define BASE_SECTOR	0x1C2
 
-#define LOGDIR_SEC	offset(171) + 5
+#define LOGDIR_SEC	SECTOR_OFFSET(171) + 5
 #define LOGDIR_NUM	43
 
-#define PICDIR_SEC	offset(180) + 5
+#define PICDIR_SEC	SECTOR_OFFSET(180) + 5
 #define PICDIR_NUM	30
 
-#define VIEWDIR_SEC	offset(189) + 5
+#define VIEWDIR_SEC	SECTOR_OFFSET(189) + 5
 #define VIEWDIR_NUM	171
 
-#define SNDDIR_SEC	offset(198) + 5
+#define SNDDIR_SEC	SECTOR_OFFSET(198) + 5
 #define SNDDIR_NUM	64
 
 namespace Agi {
@@ -122,7 +121,7 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
 	int off = agid->offset & 0xFFFF;
 	
 	fp.open(_filenameDisk0);
-	fp.seek(offset(sec) + off, SEEK_SET);
+	fp.seek(SECTOR_OFFSET(sec) + off, SEEK_SET);
 
 	int signature = fp.readUint16BE();
 	if (signature != 0x1234) {
@@ -256,7 +255,7 @@ int AgiLoader_v1::loadObjects(const char *fname) {
 
 // TODO: Find the disk image equivalent.
 int AgiLoader_v1::loadWords(const char *fname) {
-	return _vm->loadObjects(fname);
+	return _vm->loadWords(fname);
 }
 
 }


Commit: 24bb5da2288b782cfe0e9546ca811e7dd28d0359
    https://github.com/scummvm/scummvm/commit/24bb5da2288b782cfe0e9546ca811e7dd28d0359
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:36-07:00

Commit Message:
AGI: Add a layer of abstraction between the sound chip and the two players

Changed paths:
    engines/agi/sound_pcjr.cpp
    engines/agi/sound_pcjr.h



diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index d5c6935..2ca7155 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -220,12 +220,12 @@ int SoundGenPCJr::volumeCalc(SndGenChan *chan) {
 	return attenuation;
 }
 
-int SoundGenPCJr::getNextNote(int ch, Tone *tone)
+int SoundGenPCJr::getNextNote(int ch)
 {
 	if (_vm->getVersion() > 0x2001)
-		return getNextNote_v2(ch, tone);
+		return getNextNote_v2(ch);
 	else
-		return getNextNote_v1(ch, tone);
+		return getNextNote_v1(ch);
 
 	return -1;
 }
@@ -234,13 +234,11 @@ int SoundGenPCJr::getNextNote(int ch, Tone *tone)
 // if tone isn't touched.. it should be inited so it just plays silence
 // return 0 if it's passing more data
 // return -1 if it's passing nothing (end of data)
-
-int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
+int SoundGenPCJr::getNextNote_v2(int ch) { 
 	ToneChan *tpcm;
 	SndGenChan *chan;
 	const byte *data;
 
-	assert(tone);
 	assert(ch < CHAN_MAX);
 
 	if (!_vm->getflag(fSoundOn))
@@ -251,7 +249,7 @@ int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
 	if (!chan->avail)
 		return -1;
 
-	while ((chan->duration == 0) && (chan->duration != 0xFFFF)) {
+	while (chan->duration <= 0) {
 		data = chan->data;
 
 		// read the duration of the note
@@ -259,58 +257,32 @@ int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
 
 		// if it's 0 then it's not going to be played
 		// if it's 0xFFFF then the channel data has finished.
-		if ((chan->duration != 0) && (chan->duration != 0xFFFF)) {
+		if ((chan->duration == 0) || (chan->duration == 0xFFFF)) {
 			tpcm->genTypePrev = -1;
 			tpcm->freqCountPrev = -1;
 
-			// only tone channels dissolve
-			if ((ch != 3) && (_dissolveMethod != 0))	// != noise??
-				chan->dissolveCount = 0;
+			break;
+		}
 
-			// attenuation (volume)
-			chan->attenuation = data[4] & 0xF;
+		_tchannel[ch].genTypePrev = -1;
+		_tchannel[ch].freqCountPrev = -1;
 
-			// frequency
-			if (ch < (CHAN_MAX - 1)) {
-				chan->freqCount = (uint16)data[2] & 0x3F;
-				chan->freqCount <<= 4;
-				chan->freqCount |= data[3] & 0x0F;
+		// only tone channels dissolve
+		if ((ch != 3) && (_dissolveMethod != 0))	// != noise??
+			chan->dissolveCount = 0;
+
+		// attenuation (volume)
+		writeData(data[4]);
+
+		// frequency
+		writeData(data[3]);
+		writeData(data[2]);
 
-				chan->genType = kGenTone;
-			} else {
-				int noiseFreq;
-
-				// check for white noise (1) or periodic (0)
-				chan->genType = (data[3] & 0x04) ? kGenWhite : kGenPeriod;
-
-				noiseFreq = data[3] & 0x03;
-
-				switch (noiseFreq) {
-				case 0:
-					chan->freqCount = 32;
-					break;
-				case 1:
-					chan->freqCount = 64;
-					break;
-				case 2:
-					chan->freqCount = 128;
-					break;
-				case 3:
-					chan->freqCount = _channel[2].freqCount * 2;
-					break;
-				}
-			}
-		}
 		// data now points to the next data seg-a-ment
 		chan->data += 5;
 	}
 
-	if (chan->duration != 0xFFFF) {
-		tone->freqCount = chan->freqCount;
-		tone->atten = volumeCalc(chan);	// calc volume, sent vol is different from saved vol
-		tone->type = chan->genType;
-		chan->duration--;
-	} else {
+	if (chan->duration == 0xFFFF) {
 		// kill channel
 		chan->avail = 0;
 		chan->attenuation = 0x0F;	// silent
@@ -319,17 +291,17 @@ int SoundGenPCJr::getNextNote_v2(int ch, Tone *tone) {
 		return -1;
 	}
 
+	chan->duration--;
+
 	return 0;
 }
 
-int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
-{
-	static bool fetched[4] = { false, false, false, false };
+int SoundGenPCJr::getNextNote_v1(int ch) {
+	static int channels = 4;
 	static int duration = 0;
 
 	byte *data = _v1data;
 	uint32 len = _v1size;
-	int reg = 0;
 
 	if (len <= 0 || data == NULL) {
 		_channel[ch].avail = 0;
@@ -339,60 +311,22 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
 	}
 	
 	// Get previously fetched data if possible
-	if (fetched[ch]) {
-		fetched[ch] = false;
-	
-		tone->freqCount = _channel[ch].freqCount;
-		tone->atten = _channel[ch].attenuation;
-		tone->type = _channel[ch].genType;
-		
+	if (channels > 0) {
+		channels--;
 		return 0;
 	}
+	channels = 4;
 
 	// In the V1 player the default duration for a row is 2 ticks
 	if (duration > 0) {
 		duration--;
-
-		tone->freqCount = _channel[ch].freqCount;
-		tone->atten = _channel[ch].attenuation;
-		tone->type = _channel[ch].genType;
-
 		return 0;
 	}
 	duration = 2 * CHAN_MAX;
 
 	// Otherwise fetch a row of data for all channels
-	fetched[0] = fetched[1] = fetched[2] = fetched[3] = true;
-
 	while (*data) {
-		if ((*data & 0x90) == 0x90) {
-			reg = (*data >> 5) & 0x3;
-			_channel[reg].attenuation = *data & 0xF;
-		} else if ((*data & 0xF0) == 0xE0) {
-			_channel[3].genType = (data[3] & 0x4) ? kGenWhite : kGenPeriod;
-			int noiseFreq = data[3] & 0x03;
-			switch (noiseFreq) {
-			case 0:
-				_channel[3].freqCount = 32;
-				break;
-			case 1:
-				_channel[3].freqCount = 64;
-				break;
-			case 2:
-				_channel[3].freqCount = 128;
-				break;
-			case 3:
-				_channel[3].freqCount = _channel[2].freqCount * 2;
-				break;
-			}
-		} else if (*data & 0x80) {
-			reg = (*data >> 5) & 0x3;
-			_channel[reg].freqCount = *data & 0xF;
-			_channel[reg].genType = kGenTone;
-		} else {
-			_channel[reg].freqCount |= (*data & 0x3F) << 4;
-		}
-
+		writeData(*data);
 		data++;
 		len--;
 	}
@@ -402,13 +336,43 @@ int SoundGenPCJr::getNextNote_v1(int ch, Tone *tone)
 	_v1data = data;
 	_v1size = len;
 
-	tone->freqCount = _channel[ch].freqCount;
-	tone->atten = _channel[ch].attenuation;
-	tone->type = _channel[ch].genType;
-
 	return 0;
 }
 
+void SoundGenPCJr::writeData(uint8 val) {
+	static int reg = 0;
+
+	debugC(5, kDebugLevelSound, "writeData(%.2X)", val);
+
+	if ((val & 0x90) == 0x90) {
+		reg = (val >> 5) & 0x3;
+		_channel[reg].attenuation = val & 0xF;
+	} else if ((val & 0xF0) == 0xE0) {
+		_channel[3].genType = (val & 0x4) ? kGenWhite : kGenPeriod;
+		int noiseFreq = val & 0x03;
+		switch (noiseFreq) {
+		case 0:
+			_channel[3].freqCount = 32;
+			break;
+		case 1:
+			_channel[3].freqCount = 64;
+			break;
+		case 2:
+			_channel[3].freqCount = 128;
+			break;
+		case 3:
+			_channel[3].freqCount = _channel[2].freqCount * 2;
+			break;
+		}
+	} else if (val & 0x80) {
+		reg = (val >> 5) & 0x3;
+		_channel[reg].freqCount = val & 0xF;
+		_channel[reg].genType = kGenTone;
+	} else {
+		_channel[reg].freqCount |= (val & 0x3F) << 4;
+	}
+}
+
 // Formulas for noise generator
 // bit0 = output
 
@@ -444,7 +408,6 @@ const int16 volTable[16] = {
 // fill buff
 int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
 	ToneChan *tpcm;
-	Tone toneNew;
 	int fillSize;
 	int retVal;
 
@@ -452,20 +415,13 @@ int SoundGenPCJr::chanGen(int chan, int16 *stream, int len) {
 
 	retVal = -1;
 
-	debugC(5, kDebugLevelSound, "chanGen()");
-
 	while (len > 0) {
 		if (tpcm->noteCount <= 0) {
 			// get new tone data
-			tpcm->avail=1;
-			debugC(5, kDebugLevelSound, "new note data (avail=%d)", tpcm->avail);
-			toneNew.freqCount = 0;
-			toneNew.atten = 0xF;
-			toneNew.type = kGenTone;
-			if ((tpcm->avail) && (getNextNote(chan, &toneNew) == 0)) {
-				tpcm->atten = toneNew.atten;
-				tpcm->freqCount = toneNew.freqCount;
-				tpcm->genType = toneNew.type;
+			if ((tpcm->avail) && (getNextNote(chan) == 0)) {
+				tpcm->atten = _channel[chan].attenuation;
+				tpcm->freqCount = _channel[chan].freqCount;
+				tpcm->genType = _channel[chan].genType;
 
 				// setup counters 'n stuff
 				// SAMPLE_RATE samples per sec.. tone changes 60 times per sec
diff --git a/engines/agi/sound_pcjr.h b/engines/agi/sound_pcjr.h
index d9ced4a..ec3fdff 100644
--- a/engines/agi/sound_pcjr.h
+++ b/engines/agi/sound_pcjr.h
@@ -71,12 +71,6 @@ struct ToneChan {
 	int feedback;						/* noise feedback mask */
 };
 
-struct Tone {
-	int freqCount;
-	int atten;
-	GenType type;
-};
-
 class SoundGenPCJr : public SoundGen, public Audio::AudioStream {
 public:
 	SoundGenPCJr(AgiEngine *vm, Audio::Mixer *pMixer);
@@ -102,11 +96,13 @@ public:
 	}
 
 private:
-	int getNextNote(int ch, Tone *tone);
-	int getNextNote_v2(int ch, Tone *tone);
-	int getNextNote_v1(int ch, Tone *tone);
+	int getNextNote(int ch);
+	int getNextNote_v2(int ch);
+	int getNextNote_v1(int ch);
 	int volumeCalc(SndGenChan *chan);
 
+	void writeData(uint8 val);
+
 	int chanGen(int chan, int16 *stream, int len);
 
 	int fillNoise(ToneChan *t, int16 *buf, int len);


Commit: d8e1b392d2abfb67c1877aa4b3be310303250523
    https://github.com/scummvm/scummvm/commit/d8e1b392d2abfb67c1877aa4b3be310303250523
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:39-07:00

Commit Message:
AGI: Use a jump table for test commands instead of switch/case

Preparations for V1 support.

Changed paths:
    engines/agi/agi.h
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 2d9432b..dbbd87e 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -1086,9 +1086,15 @@ public:
 
 private:
 	typedef void (AgiEngine::*AgiCommand)(uint8 *);
+	typedef int (AgiEngine::*AgiCondCommand)(uint8 *);
 
 	AgiCommand _agiCommands[183];
+	AgiCondCommand _agiCondCommands[256];
 	AgiLogic *_curLogic;
+	int _endTest;
+	int _orTest;
+	int _notTest;
+	int _retval;
 	int _timerHack;			// Workaround for timer loop in MH1 logic 153
 
 	void setupOpcodes();
@@ -1275,6 +1281,30 @@ private:
 	void cmd_mouse_posn(uint8 *p);
 	void cmd_release_key(uint8 *p);
 	void cmd_adj_ego_move_to_x_y(uint8 *p);
+
+	int cond_end(uint8 *p);
+	int cond_equal(uint8 *p);
+	int cond_equalv(uint8 *p);
+	int cond_less(uint8 *p);
+	int cond_lessv(uint8 *p);
+	int cond_greater(uint8 *p);
+	int cond_greaterv(uint8 *p);
+	int cond_isset(uint8 *p);
+	int cond_issetv(uint8 *p);
+	int cond_has(uint8 *p);
+	int cond_obj_in_room(uint8 *p);
+	int cond_posn(uint8 *p);
+	int cond_controller(uint8 *p);
+	int cond_have_key(uint8 *p);
+	int cond_said(uint8 *p);
+	int cond_compare_strings(uint8 *p);
+	int cond_obj_in_box(uint8 *p);
+	int cond_center_posn(uint8 *p);
+	int cond_right_posn(uint8 *p);
+	int cond_unknown_13(uint8 *p);
+	int cond_unknown(uint8 *p);
+	int cond_not(uint8 *p);
+	int cond_or(uint8 *p);
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index bde62fe..1f8943c 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1568,6 +1568,36 @@ void AgiEngine::cmd_shake_screen(uint8 *p) {
 }
 
 void AgiEngine::setupOpcodes() {
+	AgiCondCommand condTmp[] = {
+		&AgiEngine::cond_end,				// 00
+		&AgiEngine::cond_equal,				// 01
+		&AgiEngine::cond_equalv,			// 02
+		&AgiEngine::cond_less,				// 03
+		&AgiEngine::cond_lessv,				// 04
+		&AgiEngine::cond_greater,			// 05
+		&AgiEngine::cond_greaterv,			// 06
+		&AgiEngine::cond_isset,				// 07
+		&AgiEngine::cond_issetv,			// 08
+		&AgiEngine::cond_has,				// 09
+		&AgiEngine::cond_obj_in_room,		// 0A
+		&AgiEngine::cond_posn,				// 0B
+		&AgiEngine::cond_controller,		// 0C
+		&AgiEngine::cond_have_key,			// 0D
+		&AgiEngine::cond_said,				// 0E
+		&AgiEngine::cond_compare_strings,	// 0F
+		&AgiEngine::cond_obj_in_box,		// 10
+		&AgiEngine::cond_center_posn,		// 11
+		&AgiEngine::cond_right_posn,		// 12
+		&AgiEngine::cond_unknown_13			// 13
+	};
+	for (int i = 0; i < 256; ++i)
+		_agiCondCommands[i] = &AgiEngine::cond_unknown;
+	for (int i = 0; i < ARRAYSIZE(condTmp); ++i)
+		_agiCondCommands[i] = condTmp[i];
+	_agiCondCommands[0xFF] = &AgiEngine::cond_end;
+	_agiCondCommands[0xFD] = &AgiEngine::cond_not;
+	_agiCondCommands[0xFC] = &AgiEngine::cond_or;
+
 	AgiCommand tmp[] = {
 		NULL,			// 0x00
 		&AgiEngine::cmd_increment,
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 0660a61..1722b16 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -26,8 +26,8 @@
 
 namespace Agi {
 
-#define ip (_game.logics[lognum].cIP)
-#define code (_game.logics[lognum].data)
+#define ip (_curLogic->cIP)
+#define code (_curLogic->data)
 
 #define testEqual(v1, v2)		(getvar(v1) == (v2))
 #define testLess(v1, v2)		(getvar(v1) < (v2))
@@ -36,6 +36,150 @@ namespace Agi {
 #define testHas(obj)			(objectGetLocation(obj) == EGO_OWNED)
 #define testObjInRoom(obj, v)	(objectGetLocation(obj) == getvar(v))
 
+int AgiEngine::cond_end(uint8 *p) {
+	_endTest = true;
+	return true;
+}
+
+int AgiEngine::cond_equal(uint8 *p) {
+	if (p[0] == 11)
+		_timerHack++;
+	ip += 2;
+	return testEqual(p[0], p[1]);
+}
+
+int AgiEngine::cond_equalv(uint8 *p) {
+	if (p[0] == 11 || p[1] == 11)
+		_timerHack++;
+	ip += 2;
+	return testEqual(p[0], getvar(p[1]));
+}
+
+int AgiEngine::cond_less(uint8 *p) {
+	if (p[0] == 11)
+		_timerHack++;
+	ip += 2;
+	return testLess(p[0], p[1]);
+}
+
+int AgiEngine::cond_lessv(uint8 *p) {
+	if (p[0] == 11 || p[1] == 11)
+		_timerHack++;
+	ip += 2;
+	return testLess(p[0], getvar(p[1]));
+}
+
+int AgiEngine::cond_greater(uint8 *p) {
+	if (p[0] == 11)
+		_timerHack++;
+	ip += 2;
+	return testGreater(p[0], p[1]);
+}
+
+int AgiEngine::cond_greaterv(uint8 *p) {
+	if (p[0] == 11 || p[1] == 11)
+		_timerHack++;
+	ip += 2;
+	return testGreater(p[0], getvar(p[1]));
+}
+
+int AgiEngine::cond_isset(uint8 *p) {
+	ip += 1;
+	return testIsSet(p[0]);
+}
+
+int AgiEngine::cond_issetv(uint8 *p) {
+	ip += 1;
+	return testIsSet(getvar(p[1]));
+}
+
+int AgiEngine::cond_has(uint8 *p) {
+	ip += 1;
+	return testHas(p[0]);
+}
+
+int AgiEngine::cond_obj_in_room(uint8 *p) {
+	ip += 2;
+	return testObjInRoom(p[0], p[1]);
+}
+
+int AgiEngine::cond_posn(uint8 *p) {
+	ip += 5;
+	return testPosn(p[0], p[1], p[2], p[3], p[4]);
+}
+
+int AgiEngine::cond_controller(uint8 *p) {
+	ip += 1;
+	return testController(p[0]);
+}
+
+int AgiEngine::cond_have_key(uint8 *p) {
+	return testKeypressed();
+}
+
+int AgiEngine::cond_said(uint8 *p) {
+	int ec = testSaid(p[0], p + 1);
+	ip += p[0] * 2;	// skip num_words * 2
+	ip++;	// skip num_words opcode
+	return ec;
+}
+
+int AgiEngine::cond_compare_strings(uint8 *p) {
+	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", _game.strings[p[0]], _game.strings[p[1]]);
+	ip += 2;
+	return testCompareStrings(p[0], p[1]);
+}
+
+int AgiEngine::cond_obj_in_box(uint8 *p) {
+	ip += 5;
+	return testObjInBox(p[0], p[1], p[2], p[3], p[4]);
+}
+
+int AgiEngine::cond_center_posn(uint8 *p) {
+	ip += 5;
+	return testObjCenter(p[0], p[1], p[2], p[3], p[4]);
+}
+
+int AgiEngine::cond_right_posn(uint8 *p) {
+	ip += 5;
+	return testObjRight(p[0], p[1], p[2], p[3], p[4]);
+}
+
+int AgiEngine::cond_unknown_13(uint8 *p) {
+	// My current theory is that this command checks whether the ego is currently moving
+	// and that that movement has been caused using the mouse and not using the keyboard.
+	// I base this theory on the game's behavior on an Amiga emulator, not on disassembly.
+	// This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09
+	// (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature).
+	// TODO: Check this command's implementation using disassembly just to be sure.
+	int ec = _game.viewTable[0].flags & ADJ_EGO_XY;
+	debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false");
+	return ec;
+}
+
+int AgiEngine::cond_unknown(uint8 *p) {
+	_endTest = true;
+	return false;
+}
+
+int AgiEngine::cond_not(uint8 *p) {
+	_notTest = !_notTest;
+	return false;
+}
+
+int AgiEngine::cond_or(uint8 *p) {
+	int ec = true;
+	// if or_test is ON and we hit 0xFC, end of OR, then
+	// or is STILL false so break.
+	if (_orTest) {
+		ec = false;
+		_retval = false;
+		_endTest = true;
+	}
+	_orTest = true;
+	return ec;
+}
+
 uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
 	char ms1[MAX_STRINGLEN];
 	char ms2[MAX_STRINGLEN];
@@ -203,15 +347,15 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 
 int AgiEngine::testIfCode(int lognum) {
 	int ec = true;
-	int retval = true;
+	_retval = true;
 	uint8 op = 0;
-	uint8 notTest = false;
-	uint8 orTest = false;
+	_notTest = false;
+	_orTest = false;
 	uint16 lastIp = ip;
 	uint8 p[16] = { 0 };
-	bool end_test = false;
+	_endTest = false;
 
-	while (retval && !(shouldQuit() || _restartGame) && !end_test) {
+	while (_retval && !(shouldQuit() || _restartGame) && !_endTest) {
 		if (_debug.enabled && (_debug.logic0 || lognum))
 			debugConsole(lognum, lTEST_MODE, NULL);
 
@@ -219,127 +363,22 @@ int AgiEngine::testIfCode(int lognum) {
 		op = *(code + ip++);
 		memmove(p, (code + ip), 16);
 
-		switch (op) {
-		case 0xFF:	// END IF, TEST true
-			end_test = true;
-			break;
-		case 0xFD:
-			notTest = !notTest;
+		ec = (this->*_agiCondCommands[op])(p);
+		if (op == 0xFD || op == 0xFC)
 			continue;
-		case 0xFC:	// OR
-			// if or_test is ON and we hit 0xFC, end of OR, then
-			// or is STILL false so break.
-			if (orTest) {
-				ec = false;
-				retval = false;
-				end_test = true;
-			}
-
-			orTest = true;
-			continue;
-
-		case 0x00:
-			// return true?
-			end_test = true;
-			break;
-		case 0x01:
-			ec = testEqual(p[0], p[1]);
-			if (p[0] == 11)
-				_timerHack++;
-			break;
-		case 0x02:
-			ec = testEqual(p[0], getvar(p[1]));
-			if (p[0] == 11 || p[1] == 11)
-				_timerHack++;
-			break;
-		case 0x03:
-			ec = testLess(p[0], p[1]);
-			if (p[0] == 11)
-				_timerHack++;
-			break;
-		case 0x04:
-			ec = testLess(p[0], getvar(p[1]));
-			if (p[0] == 11 || p[1] == 11)
-				_timerHack++;
-			break;
-		case 0x05:
-			ec = testGreater(p[0], p[1]);
-			if (p[0] == 11)
-				_timerHack++;
-			break;
-		case 0x06:
-			ec = testGreater(p[0], getvar(p[1]));
-			if (p[0] == 11 || p[1] == 11)
-				_timerHack++;
-			break;
-		case 0x07:
-			ec = testIsSet(p[0]);
-			break;
-		case 0x08:
-			ec = testIsSet(getvar(p[0]));
-			break;
-		case 0x09:
-			ec = testHas(p[0]);
-			break;
-		case 0x0A:
-			ec = testObjInRoom(p[0], p[1]);
-			break;
-		case 0x0B:
-			ec = testPosn(p[0], p[1], p[2], p[3], p[4]);
-			break;
-		case 0x0C:
-			ec = testController(p[0]);
-			break;
-		case 0x0D:
-			ec = testKeypressed();
-			break;
-		case 0x0E:
-			ec = testSaid(p[0], (uint8 *) code + (ip + 1));
-			ip = lastIp;
-			ip++;	// skip opcode
-			ip += p[0] * 2;	// skip num_words * 2
-			ip++;	// skip num_words opcode
-			break;
-		case 0x0F:
-			debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", _game.strings[p[0]], _game.strings[p[1]]);
-			ec = testCompareStrings(p[0], p[1]);
-			break;
-		case 0x10:
-			ec = testObjInBox(p[0], p[1], p[2], p[3], p[4]);
-			break;
-		case 0x11:
-			ec = testObjCenter(p[0], p[1], p[2], p[3], p[4]);
-			break;
-		case 0x12:
-			ec = testObjRight(p[0], p[1], p[2], p[3], p[4]);
-			break;
-		case 0x13: // Unknown test command 19
-			// My current theory is that this command checks whether the ego is currently moving
-			// and that that movement has been caused using the mouse and not using the keyboard.
-			// I base this theory on the game's behavior on an Amiga emulator, not on disassembly.
-			// This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09
-			// (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature).
-			// TODO: Check this command's implementation using disassembly just to be sure.
-			ec = _game.viewTable[0].flags & ADJ_EGO_XY;
-			debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false");
-			break;
-		default:
-			ec = false;
-			end_test = true;
-		}
 
-		if (!end_test) {
-			if (op <= 0x12)
-				ip += logicNamesTest[op].numArgs;
+		if (!_endTest) {
+//			if (op <= 0x12)
+//				ip += logicNamesTest[op].numArgs;
 
 			// exchange ec value
-			if (notTest)
+			if (_notTest)
 				ec = !ec;
 
 			// not is only enabled for 1 test command
-			notTest = false;
+			_notTest = false;
 
-			if (orTest && ec) {
+			if (_orTest && ec) {
 				// a true inside an OR statement passes
 				// ENTIRE statement scan for end of OR
 
@@ -374,16 +413,16 @@ int AgiEngine::testIfCode(int lognum) {
 				}
 				ip++;
 
-				orTest = false;
-				retval = true;
+				_orTest = false;
+				_retval = true;
 			} else {
-				retval = orTest ? retval || ec : retval && ec;
+				_retval = _orTest ? _retval || ec : _retval && ec;
 			}
 		}
 	}
 
 	// if false, scan for end of IP?
-	if (retval)
+	if (_retval)
 		ip += 2;
 	else {
 		ip = lastIp;
@@ -403,9 +442,9 @@ int AgiEngine::testIfCode(int lognum) {
 	}
 
 	if (_debug.enabled && (_debug.logic0 || lognum))
-		debugConsole(lognum, 0xFF, retval ? "=true" : "=false");
+		debugConsole(lognum, 0xFF, _retval ? "=true" : "=false");
 
-	return retval;
+	return _retval;
 }
 
 } // End of namespace Agi


Commit: 1507fe4e792528244fe3c8d1a9ae45ac40936efe
    https://github.com/scummvm/scummvm/commit/1507fe4e792528244fe3c8d1a9ae45ac40936efe
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:41-07:00

Commit Message:
AGI: Fix detection of IIgs sample resources

Changed paths:
    engines/agi/sound.cpp



diff --git a/engines/agi/sound.cpp b/engines/agi/sound.cpp
index f44b34c..10074ef 100644
--- a/engines/agi/sound.cpp
+++ b/engines/agi/sound.cpp
@@ -42,7 +42,7 @@ AgiSound *AgiSound::createFromRawResource(uint8 *data, uint32 len, int resnum, S
 	uint16 type = READ_LE_UINT16(data);
 
 	// For V1 sound resources
-	if ((type & 0xFF) == 0x01)
+	if (type != AGI_SOUND_SAMPLE && (type & 0xFF) == 0x01)
 		return new PCjrSound(data, len, resnum, manager);
 
 	switch (type) { // Create a sound object based on the type


Commit: 7a80c4cdb39f003fb893361dde25d40ecd08101a
    https://github.com/scummvm/scummvm/commit/7a80c4cdb39f003fb893361dde25d40ecd08101a
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:44-07:00

Commit Message:
AGI: Fix row duration in V1 SOUND resource player

Changed paths:
    engines/agi/sound_pcjr.cpp



diff --git a/engines/agi/sound_pcjr.cpp b/engines/agi/sound_pcjr.cpp
index 2ca7155..14525dc 100644
--- a/engines/agi/sound_pcjr.cpp
+++ b/engines/agi/sound_pcjr.cpp
@@ -297,7 +297,6 @@ int SoundGenPCJr::getNextNote_v2(int ch) {
 }
 
 int SoundGenPCJr::getNextNote_v1(int ch) {
-	static int channels = 4;
 	static int duration = 0;
 
 	byte *data = _v1data;
@@ -310,19 +309,12 @@ int SoundGenPCJr::getNextNote_v1(int ch) {
 		return -1;
 	}
 	
-	// Get previously fetched data if possible
-	if (channels > 0) {
-		channels--;
-		return 0;
-	}
-	channels = 4;
-
-	// In the V1 player the default duration for a row is 2 ticks
+	// In the V1 player the default duration for a row is 3 ticks
 	if (duration > 0) {
 		duration--;
 		return 0;
 	}
-	duration = 2 * CHAN_MAX;
+	duration = 3 * CHAN_MAX;
 
 	// Otherwise fetch a row of data for all channels
 	while (*data) {


Commit: eb797b692fbee2515d20fbb0b98fe06108c72825
    https://github.com/scummvm/scummvm/commit/eb797b692fbee2515d20fbb0b98fe06108c72825
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:46-07:00

Commit Message:
AGI: Simplify handling of IF conditions

Execute all test commands in a condition even when not strictly needed.

Changed paths:
    engines/agi/agi.h
    engines/agi/op_test.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index dbbd87e..6c4d5bc 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -1093,8 +1093,9 @@ private:
 	AgiLogic *_curLogic;
 	int _endTest;
 	int _orTest;
+	int _orVal;
 	int _notTest;
-	int _retval;
+	int _testVal;
 	int _timerHack;			// Workaround for timer loop in MH1 logic 153
 
 	void setupOpcodes();
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 1722b16..3748e4f 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -168,16 +168,16 @@ int AgiEngine::cond_not(uint8 *p) {
 }
 
 int AgiEngine::cond_or(uint8 *p) {
-	int ec = true;
 	// if or_test is ON and we hit 0xFC, end of OR, then
 	// or is STILL false so break.
 	if (_orTest) {
-		ec = false;
-		_retval = false;
-		_endTest = true;
+		_orTest = false;
+		_testVal &= _orVal;
+	} else {
+		_orTest = true;
+		_orVal = false;
 	}
-	_orTest = true;
-	return ec;
+	return true;
 }
 
 uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
@@ -347,15 +347,16 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 
 int AgiEngine::testIfCode(int lognum) {
 	int ec = true;
-	_retval = true;
 	uint8 op = 0;
-	_notTest = false;
-	_orTest = false;
 	uint16 lastIp = ip;
 	uint8 p[16] = { 0 };
+
+	_notTest = false;
+	_orTest = false;
 	_endTest = false;
+	_testVal = true;
 
-	while (_retval && !(shouldQuit() || _restartGame) && !_endTest) {
+	while (!(shouldQuit() || _restartGame) && !_endTest) {
 		if (_debug.enabled && (_debug.logic0 || lognum))
 			debugConsole(lognum, lTEST_MODE, NULL);
 
@@ -364,87 +365,30 @@ int AgiEngine::testIfCode(int lognum) {
 		memmove(p, (code + ip), 16);
 
 		ec = (this->*_agiCondCommands[op])(p);
-		if (op == 0xFD || op == 0xFC)
+		if (op == 0xFF || op == 0xFD || op == 0xFC)
 			continue;
 
-		if (!_endTest) {
-//			if (op <= 0x12)
-//				ip += logicNamesTest[op].numArgs;
-
-			// exchange ec value
-			if (_notTest)
-				ec = !ec;
-
-			// not is only enabled for 1 test command
-			_notTest = false;
-
-			if (_orTest && ec) {
-				// a true inside an OR statement passes
-				// ENTIRE statement scan for end of OR
-
-				// CM: test for opcode < 0xfc changed from 'op' to
-				//     '*(code+ip)', to avoid problem with the 0xfd (NOT)
-				//     opcode byte. Changed a bad ip += ... ip++ construct.
-				//     This should fix the crash with Larry's logic.0 code:
-				//
-				//     if ((isset(4) ||
-				//          !isset(2) ||
-				//          v30 == 2 ||
-				//          v30 == 1)) {
-				//       goto Label1;
-				//     }
-				//
-				//     The bytecode is:
-				//     ff fc 07 04 fd 07 02 01 1e 02 01 1e 01 fc ff
-
-				// find end of OR
-				while (*(code + ip) != 0xFC) {
-					if (*(code + ip) == 0x0E) {	// said
-						ip++;
-
-						// cover count + ^words
-						ip += 1 + ((*(code + ip)) * 2);
-						continue;
-					}
-
-					if (*(code + ip) < 0xFC)
-						ip += logicNamesTest[*(code + ip)].numArgs;
-					ip++;
-				}
-				ip++;
-
-				_orTest = false;
-				_retval = true;
-			} else {
-				_retval = _orTest ? _retval || ec : _retval && ec;
-			}
-		}
+		// not is only enabled for 1 test command
+		if (_notTest)
+			ec = !ec;
+		_notTest = false;
+
+		if (_orTest)
+			_orVal |= ec;
+		else
+			_testVal &= ec;
 	}
 
 	// if false, scan for end of IP?
-	if (_retval)
+	if (_testVal)
 		ip += 2;
-	else {
-		ip = lastIp;
-		while (*(code + ip) != 0xff) {
-			if (*(code + ip) == 0x0e) {
-				ip++;
-				ip += (*(code + ip)) * 2 + 1;
-			} else if (*(code + ip) < 0xfc) {
-				ip += logicNamesTest[*(code + ip)].numArgs;
-				ip++;
-			} else {
-				ip++;
-			}
-		}
-		ip++;		// skip over 0xFF
+	else
 		ip += READ_LE_UINT16(code + ip) + 2;
-	}
 
 	if (_debug.enabled && (_debug.logic0 || lognum))
-		debugConsole(lognum, 0xFF, _retval ? "=true" : "=false");
+		debugConsole(lognum, 0xFF, _testVal ? "=true" : "=false");
 
-	return _retval;
+	return _testVal;
 }
 
 } // End of namespace Agi


Commit: e1153cf11fd0ddddfdc326d0ff677799fd0bb4db
    https://github.com/scummvm/scummvm/commit/e1153cf11fd0ddddfdc326d0ff677799fd0bb4db
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:48-07:00

Commit Message:
AGI: Comment cleanup

Changed paths:
    engines/agi/op_test.cpp



diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 3748e4f..24dd397 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -379,7 +379,8 @@ int AgiEngine::testIfCode(int lognum) {
 			_testVal &= ec;
 	}
 
-	// if false, scan for end of IP?
+	// Execute the following IF block if the condition is true, otherwise
+	// skip the block.
 	if (_testVal)
 		ip += 2;
 	else


Commit: a4e0cd53f01afeac9f6cf0467a6b4174bf64215e
    https://github.com/scummvm/scummvm/commit/a4e0cd53f01afeac9f6cf0467a6b4174bf64215e
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:51-07:00

Commit Message:
AGI: Refactor interpreter core (somewhat akin to SCI)

* Instruction tables are now defined in opcodes.{cpp,h}.

* Move opcode handlers from Agi::AgiEngine to Agi
* Opcode handlers take as parameter a pointer to AGI state (AgiGame)

Changed paths:
  A engines/agi/opcodes.cpp
    engines/agi/agi.cpp
    engines/agi/agi.h
    engines/agi/console.cpp
    engines/agi/id.cpp
    engines/agi/module.mk
    engines/agi/op_cmd.cpp
    engines/agi/op_dbg.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/agi.cpp b/engines/agi/agi.cpp
index 0eefbab..4cb45e8 100644
--- a/engines/agi/agi.cpp
+++ b/engines/agi/agi.cpp
@@ -536,6 +536,8 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 	memset(&_debug, 0, sizeof(struct AgiDebug));
 	memset(&_mouse, 0, sizeof(struct Mouse));
 
+	_game._vm = this;
+
 	_game.clockEnabled = false;
 	_game.state = STATE_INIT;
 
@@ -571,7 +573,7 @@ AgiEngine::AgiEngine(OSystem *syst, const AGIGameDescription *gameDesc) : AgiBas
 		_game.controllerOccured[i] = false;
 
 	setupOpcodes();
-	_curLogic = NULL;
+	_game._curLogic = NULL;
 	_timerHack = 0;
 }
 
diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 6c4d5bc..2b41514 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -537,6 +537,8 @@ enum {
  * by the interpreter.
  */
 struct AgiGame {
+	AgiEngine *_vm;
+
 	State state;		/**< state of the interpreter */
 
 	// TODO: Check whether adjMouseX and adjMouseY must be saved and loaded when using savegames.
@@ -621,6 +623,8 @@ struct AgiGame {
 	AgiView views[MAX_DIRS];		/**< AGI view resources */
 	AgiSound *sounds[MAX_DIRS];		/**< Pointers to AGI sound resources */
 
+	AgiLogic *_curLogic;
+
 	// view table
 	VtEntry viewTable[MAX_VIEWTABLE];
 
@@ -629,6 +633,14 @@ struct AgiGame {
 	int simpleSave;					/**< select simple savegames */
 
 	Common::Rect mouseFence;		/**< rectangle set by fence.mouse command */
+
+	// IF conditions
+	int endTest;
+	int orTest;
+	int orVal;
+	int notTest;
+	int testVal;
+	int ec;
 };
 
 /**
@@ -833,6 +845,8 @@ public:
 	bool canSaveGameStateCurrently();
 };
 
+typedef void (*AgiCommand)(AgiGame *state, uint8 *p);
+
 class AgiEngine : public AgiBase {
 protected:
 	// Engine APIs
@@ -972,7 +986,7 @@ public:
 	int testIfCode(int);
 	void executeAgiCommand(uint8, uint8 *);
 
-private:
+public:
 	// Some submethods of testIfCode
 	uint8 testObjRight(uint8, uint8, uint8, uint8, uint8);
 	uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8);
@@ -1085,227 +1099,13 @@ public:
 	char _predictiveResult[40];
 
 private:
-	typedef void (AgiEngine::*AgiCommand)(uint8 *);
-	typedef int (AgiEngine::*AgiCondCommand)(uint8 *);
-
 	AgiCommand _agiCommands[183];
-	AgiCondCommand _agiCondCommands[256];
-	AgiLogic *_curLogic;
-	int _endTest;
-	int _orTest;
-	int _orVal;
-	int _notTest;
-	int _testVal;
-	int _timerHack;			// Workaround for timer loop in MH1 logic 153
+	AgiCommand _agiCondCommands[256];
 
 	void setupOpcodes();
 
-	void cmd_increment(uint8 *p);
-	void cmd_decrement(uint8 *p);
-	void cmd_assignn(uint8 *p);
-	void cmd_assignv(uint8 *p);
-	void cmd_addn(uint8 *p);
-	void cmd_addv(uint8 *p);
-	void cmd_subn(uint8 *p);
-	void cmd_subv(uint8 *p);	// 0x08
-	void cmd_lindirectv(uint8 *p);
-	void cmd_rindirect(uint8 *p);
-	void cmd_lindirectn(uint8 *p);
-	void cmd_set(uint8 *p);
-	void cmd_reset(uint8 *p);
-	void cmd_toggle(uint8 *p);
-	void cmd_set_v(uint8 *p);
-	void cmd_reset_v(uint8 *p);	// 0x10
-	void cmd_toggle_v(uint8 *p);
-	void cmd_new_room(uint8 *p);
-	void cmd_new_room_f(uint8 *p);
-	void cmd_load_logic(uint8 *p);
-	void cmd_load_logic_f(uint8 *p);
-	void cmd_call(uint8 *p);
-	void cmd_call_f(uint8 *p);
-	void cmd_load_pic(uint8 *p);	// 0x18
-	void cmd_draw_pic(uint8 *p);
-	void cmd_show_pic(uint8 *p);
-	void cmd_discard_pic(uint8 *p);
-	void cmd_overlay_pic(uint8 *p);
-	void cmd_show_pri_screen(uint8 *p);
-	void cmd_load_view(uint8 *p);
-	void cmd_load_view_f(uint8 *p);
-	void cmd_discard_view(uint8 *p);	// 0x20
-	void cmd_animate_obj(uint8 *p);
-	void cmd_unanimate_all(uint8 *p);
-	void cmd_draw(uint8 *p);
-	void cmd_erase(uint8 *p);
-	void cmd_position(uint8 *p);
-	void cmd_position_f(uint8 *p);
-	void cmd_get_posn(uint8 *p);
-	void cmd_reposition(uint8 *p);	// 0x28
-	void cmd_set_view(uint8 *p);
-	void cmd_set_view_f(uint8 *p);
-	void cmd_set_loop(uint8 *p);
-	void cmd_set_loop_f(uint8 *p);
-	void cmd_fix_loop(uint8 *p);
-	void cmd_release_loop(uint8 *p);
-	void cmd_set_cel(uint8 *p);
-	void cmd_set_cel_f(uint8 *p);	// 0x30
-	void cmd_last_cel(uint8 *p);
-	void cmd_current_cel(uint8 *p);
-	void cmd_current_loop(uint8 *p);
-	void cmd_current_view(uint8 *p);
-	void cmd_number_of_loops(uint8 *p);
-	void cmd_set_priority(uint8 *p);
-	void cmd_set_priority_f(uint8 *p);
-	void cmd_release_priority(uint8 *p);	// 0x38
-	void cmd_get_priority(uint8 *p);
-	void cmd_stop_update(uint8 *p);
-	void cmd_start_update(uint8 *p);
-	void cmd_force_update(uint8 *p);
-	void cmd_ignore_horizon(uint8 *p);
-	void cmd_observe_horizon(uint8 *p);
-	void cmd_set_horizon(uint8 *p);
-	void cmd_object_on_water(uint8 *p);	// 0x40
-	void cmd_object_on_land(uint8 *p);
-	void cmd_object_on_anything(uint8 *p);
-	void cmd_ignore_objs(uint8 *p);
-	void cmd_observe_objs(uint8 *p);
-	void cmd_distance(uint8 *p);
-	void cmd_stop_cycling(uint8 *p);
-	void cmd_start_cycling(uint8 *p);
-	void cmd_normal_cycle(uint8 *p);	// 0x48
-	void cmd_end_of_loop(uint8 *p);
-	void cmd_reverse_cycle(uint8 *p);
-	void cmd_reverse_loop(uint8 *p);
-	void cmd_cycle_time(uint8 *p);
-	void cmd_stop_motion(uint8 *p);
-	void cmd_start_motion(uint8 *p);
-	void cmd_step_size(uint8 *p);
-	void cmd_step_time(uint8 *p);	// 0x50
-	void cmd_move_obj(uint8 *p);
-	void cmd_move_obj_f(uint8 *p);
-	void cmd_follow_ego(uint8 *p);
-	void cmd_wander(uint8 *p);
-	void cmd_normal_motion(uint8 *p);
-	void cmd_set_dir(uint8 *p);
-	void cmd_get_dir(uint8 *p);
-	void cmd_ignore_blocks(uint8 *p);	// 0x58
-	void cmd_observe_blocks(uint8 *p);
-	void cmd_block(uint8 *p);
-	void cmd_unblock(uint8 *p);
-	void cmd_get(uint8 *p);
-	void cmd_get_f(uint8 *p);
-	void cmd_drop(uint8 *p);
-	void cmd_put(uint8 *p);
-	void cmd_put_f(uint8 *p);	// 0x60
-	void cmd_get_room_f(uint8 *p);
-	void cmd_load_sound(uint8 *p);
-	void cmd_sound(uint8 *p);
-	void cmd_stop_sound(uint8 *p);
-	void cmd_print(uint8 *p);
-	void cmd_print_f(uint8 *p);
-	void cmd_display(uint8 *p);
-	void cmd_display_f(uint8 *p);	// 0x68
-	void cmd_clear_lines(uint8 *p);
-	void cmd_text_screen(uint8 *p);
-	void cmd_graphics(uint8 *p);
-	void cmd_set_cursor_char(uint8 *p);
-	void cmd_set_text_attribute(uint8 *p);
-	void cmd_shake_screen(uint8 *p);
-	void cmd_configure_screen(uint8 *p);
-	void cmd_status_line_on(uint8 *p);	// 0x70
-	void cmd_status_line_off(uint8 *p);
-	void cmd_set_string(uint8 *p);
-	void cmd_get_string(uint8 *p);
-	void cmd_word_to_string(uint8 *p);
-	void cmd_parse(uint8 *p);
-	void cmd_get_num(uint8 *p);
-	void cmd_prevent_input(uint8 *p);
-	void cmd_accept_input(uint8 *p);	// 0x78
-	void cmd_set_key(uint8 *p);
-	void cmd_add_to_pic(uint8 *p);
-	void cmd_add_to_pic_f(uint8 *p);
-	void cmd_status(uint8 *p);
-	void cmd_save_game(uint8 *p);
-	void cmd_load_game(uint8 *p);
-	void cmd_init_disk(uint8 *p);
-	void cmd_restart_game(uint8 *p);	// 0x80
-	void cmd_show_obj(uint8 *p);
-	void cmd_random(uint8 *p);
-	void cmd_program_control(uint8 *p);
-	void cmd_player_control(uint8 *p);
-	void cmd_obj_status_f(uint8 *p);
-	void cmd_quit(uint8 *p);
-	void cmd_show_mem(uint8 *p);
-	void cmd_pause(uint8 *p);	// 0x88
-	void cmd_echo_line(uint8 *p);
-	void cmd_cancel_line(uint8 *p);
-	void cmd_init_joy(uint8 *p);
-	void cmd_toggle_monitor(uint8 *p);
-	void cmd_version(uint8 *p);
-	void cmd_script_size(uint8 *p);
-	void cmd_set_game_id(uint8 *p);
-	void cmd_log(uint8 *p);	// 0x90
-	void cmd_set_scan_start(uint8 *p);
-	void cmd_reset_scan_start(uint8 *p);
-	void cmd_reposition_to(uint8 *p);
-	void cmd_reposition_to_f(uint8 *p);
-	void cmd_trace_on(uint8 *p);
-	void cmd_trace_info(uint8 *p);
-	void cmd_print_at(uint8 *p);
-	void cmd_print_at_v(uint8 *p);	// 0x98
-	//void cmd_discard_view(uint8 *p);	// Opcode repeated from 0x20 ?
-	void cmd_clear_text_rect(uint8 *p);
-	void cmd_set_upper_left(uint8 *p);
-	void cmd_set_menu(uint8 *p);
-	void cmd_set_menu_item(uint8 *p);
-	void cmd_submit_menu(uint8 *p);
-	void cmd_enable_item(uint8 *p);
-	void cmd_disable_item(uint8 *p);	// 0xa0
-	void cmd_menu_input(uint8 *p);
-	void cmd_show_obj_v(uint8 *p);
-	void cmd_open_dialogue(uint8 *p);
-	void cmd_close_dialogue(uint8 *p);
-	void cmd_mul_n(uint8 *p);
-	void cmd_mul_v(uint8 *p);
-	void cmd_div_n(uint8 *p);
-	void cmd_div_v(uint8 *p);	// 0xa8
-	void cmd_close_window(uint8 *p);
-	void cmd_set_simple(uint8 *p);
-	void cmd_push_script(uint8 *p);
-	void cmd_pop_script(uint8 *p);
-	void cmd_hold_key(uint8 *p);
-	void cmd_set_pri_base(uint8 *p);
-	void cmd_discard_sound(uint8 *p);
-	void cmd_hide_mouse(uint8 *p);	// 0xb0
-	void cmd_allow_menu(uint8 *p);
-	void cmd_show_mouse(uint8 *p);
-	void cmd_fence_mouse(uint8 *p);
-	void cmd_mouse_posn(uint8 *p);
-	void cmd_release_key(uint8 *p);
-	void cmd_adj_ego_move_to_x_y(uint8 *p);
-
-	int cond_end(uint8 *p);
-	int cond_equal(uint8 *p);
-	int cond_equalv(uint8 *p);
-	int cond_less(uint8 *p);
-	int cond_lessv(uint8 *p);
-	int cond_greater(uint8 *p);
-	int cond_greaterv(uint8 *p);
-	int cond_isset(uint8 *p);
-	int cond_issetv(uint8 *p);
-	int cond_has(uint8 *p);
-	int cond_obj_in_room(uint8 *p);
-	int cond_posn(uint8 *p);
-	int cond_controller(uint8 *p);
-	int cond_have_key(uint8 *p);
-	int cond_said(uint8 *p);
-	int cond_compare_strings(uint8 *p);
-	int cond_obj_in_box(uint8 *p);
-	int cond_center_posn(uint8 *p);
-	int cond_right_posn(uint8 *p);
-	int cond_unknown_13(uint8 *p);
-	int cond_unknown(uint8 *p);
-	int cond_not(uint8 *p);
-	int cond_or(uint8 *p);
+public:
+	int _timerHack;			// Workaround for timer loop in MH1 logic 153
 };
 
 } // End of namespace Agi
diff --git a/engines/agi/console.cpp b/engines/agi/console.cpp
index d49bd57..58c61c0 100644
--- a/engines/agi/console.cpp
+++ b/engines/agi/console.cpp
@@ -96,8 +96,8 @@ bool Console::Cmd_RunOpcode(int argc, const char **argv) {
 	for (int i = 0; logicNamesCmd[i].name; i++) {
 		if (!strcmp(argv[1], logicNamesCmd[i].name)) {
 			uint8 p[16];
-			if ((argc - 2) != logicNamesCmd[i].numArgs) {
-				DebugPrintf("AGI command wants %d arguments\n", logicNamesCmd[i].numArgs);
+			if ((argc - 2) != logicNamesCmd[i].argumentsLength()) {
+				DebugPrintf("AGI command wants %d arguments\n", logicNamesCmd[i].argumentsLength());
 				return 0;
 			}
 			p[0] = argv[2] ? (char)strtoul(argv[2], NULL, 0) : 0;
@@ -260,7 +260,7 @@ bool Console::Cmd_BT(int argc, const char **argv) {
 	for (it = _vm->_game.execStack.begin(); it != _vm->_game.execStack.end(); ++it) {
 		code = _vm->_game.logics[it->script].data;
 		op = code[it->curIP];
-		num = logicNamesCmd[op].numArgs;
+		num = logicNamesCmd[op].argumentsLength();
 		memmove(p, &code[it->curIP], num);
 		memset(p + num, 0, CMD_BSIZE - num);
 
diff --git a/engines/agi/id.cpp b/engines/agi/id.cpp
index 00f8407..dd370d4 100644
--- a/engines/agi/id.cpp
+++ b/engines/agi/id.cpp
@@ -48,14 +48,17 @@ int AgiEngine::setupV2Game(int ver) {
 
 	// 'quit' takes 0 args for 2.089
 	if (ver == 0x2089)
-		logicNamesCmd[0x86].numArgs = 0;
+//		logicNamesCmd[0x86].numArgs = 0;
+		logicNamesCmd[0x86].args = "";
 
 	// 'print.at' and 'print.at.v' take 3 args before 2.272
 	// This is documented in the specs as only < 2.440, but it seems
 	// that KQ3 (2.272) needs a 'print.at' taking 4 args.
 	if (ver < 0x2272) {
-		logicNamesCmd[0x97].numArgs = 3;
-		logicNamesCmd[0x98].numArgs = 3;
+//		logicNamesCmd[0x97].numArgs = 3;
+//		logicNamesCmd[0x98].numArgs = 3;
+		logicNamesCmd[0x97].args = "vvv";
+		logicNamesCmd[0x98].args = "vvv";
 	}
 
 	return ec;
@@ -73,8 +76,10 @@ int AgiEngine::setupV3Game(int ver) {
 	// 'unknown173' also takes 1 arg for 3.002.068, not 0 args.
 	// Is this actually used anywhere? -- dsymonds
 	if (ver == 0x3086) {
-		logicNamesCmd[0xb0].numArgs = 1;
-		logicNamesCmd[0xad].numArgs = 1;
+//		logicNamesCmd[0xb0].numArgs = 1;
+//		logicNamesCmd[0xad].numArgs = 1;
+		logicNamesCmd[0xb0].args = "n";
+		logicNamesCmd[0xad].args = "n";
 	}
 
 	// FIXME: Apply this fix to other games also that use 2 arguments for command 182.
@@ -83,7 +88,8 @@ int AgiEngine::setupV3Game(int ver) {
 	// has been set to use AGI 3.149 in ScummVM so that's why this initialization is
 	// here and not in setupV2Game.
 	if (getGameID() == GID_GOLDRUSH && getPlatform() == Common::kPlatformAmiga)
-		logicNamesCmd[182].numArgs = 2;
+//		logicNamesCmd[182].numArgs = 2;
+		logicNamesCmd[182].args = "vv";
 
 	return ec;
 }
diff --git a/engines/agi/module.mk b/engines/agi/module.mk
index 3bb4dac..cd901c5 100644
--- a/engines/agi/module.mk
+++ b/engines/agi/module.mk
@@ -19,6 +19,7 @@ MODULE_OBJS := \
 	menu.o \
 	motion.o \
 	objects.o \
+	opcodes.o \
 	op_cmd.o \
 	op_dbg.o \
 	op_test.o \
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 1f8943c..a000453 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -41,23 +41,30 @@ namespace Agi {
 #define p5	(p[5])
 #define p6	(p[6])
 
-#define ip	_curLogic->cIP
-#define vt	_game.viewTable[p0]
-#define vt_v _game.viewTable[_game.vars[p0]]
+#define ip	state->_curLogic->cIP
+#define vt	state->viewTable[p0]
+#define vt_v state->viewTable[state->vars[p0]]
 
-#define _v _game.vars
+#define _v state->vars
 
-void AgiEngine::cmd_increment(uint8 *p) {
+#define getGameID() state->_vm->getGameID()
+#define getFeatures() state->_vm->getFeatures()
+#define getVersion() state->_vm->getVersion()
+#define getLanguage() state->_vm->getLanguage()
+#define setflag(a,b) state->_vm->setflag(a,b)
+#define getflag(a) state->_vm->getflag(a)
+
+void cmd_increment(AgiGame *state, uint8 *p) {
 	if (_v[p0] != 0xff)
 		++_v[p0];
 }
 
-void AgiEngine::cmd_decrement(uint8 *p) {
+void cmd_decrement(AgiGame *state, uint8 *p) {
 	if (_v[p0] != 0)
 		--_v[p0];
 }
 
-void AgiEngine::cmd_assignn(uint8 *p) {
+void cmd_assignn(AgiGame *state, uint8 *p) {
 	_v[p0] = p1;
 
 	// WORKAROUND for a bug in fan _game "Get outta SQ"
@@ -71,84 +78,84 @@ void AgiEngine::cmd_assignn(uint8 *p) {
 		_v[p0] = 8;
 }
 
-void AgiEngine::cmd_addn(uint8 *p) {
+void cmd_addn(AgiGame *state, uint8 *p) {
 	_v[p0] += p1;
 }
 
-void AgiEngine::cmd_subn(uint8 *p) {
+void cmd_subn(AgiGame *state, uint8 *p) {
 	_v[p0] -= p1;
 }
 
-void AgiEngine::cmd_assignv(uint8 *p) {
+void cmd_assignv(AgiGame *state, uint8 *p) {
 	_v[p0] = _v[p1];
 }
 
-void AgiEngine::cmd_addv(uint8 *p) {
+void cmd_addv(AgiGame *state, uint8 *p) {
 	_v[p0] += _v[p1];
 }
 
-void AgiEngine::cmd_subv(uint8 *p) {
+void cmd_subv(AgiGame *state, uint8 *p) {
 	_v[p0] -= _v[p1];
 }
 
-void AgiEngine::cmd_mul_n(uint8 *p) {
+void cmd_mul_n(AgiGame *state, uint8 *p) {
 	_v[p0] *= p1;
 }
 
-void AgiEngine::cmd_mul_v(uint8 *p) {
+void cmd_mul_v(AgiGame *state, uint8 *p) {
 	_v[p0] *= _v[p1];
 }
 
-void AgiEngine::cmd_div_n(uint8 *p) {
+void cmd_div_n(AgiGame *state, uint8 *p) {
 	_v[p0] /= p1;
 }
 
-void AgiEngine::cmd_div_v(uint8 *p) {
+void cmd_div_v(AgiGame *state, uint8 *p) {
 	_v[p0] /= _v[p1];
 }
 
-void AgiEngine::cmd_random(uint8 *p) {
-	_v[p2] = _rnd->getRandomNumber(p1 - p0) + p0;
+void cmd_random(AgiGame *state, uint8 *p) {
+	_v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
 }
 
-void AgiEngine::cmd_lindirectn(uint8 *p) {
+void cmd_lindirectn(AgiGame *state, uint8 *p) {
 	_v[_v[p0]] = p1;
 }
 
-void AgiEngine::cmd_lindirectv(uint8 *p) {
+void cmd_lindirectv(AgiGame *state, uint8 *p) {
 	_v[_v[p0]] = _v[p1];
 }
 
-void AgiEngine::cmd_rindirect(uint8 *p) {
+void cmd_rindirect(AgiGame *state, uint8 *p) {
 	_v[p0] = _v[_v[p1]];
 }
 
-void AgiEngine::cmd_set(uint8 *p) {
+void cmd_set(AgiGame *state, uint8 *p) {
 	setflag(*p, true);
 }
 
-void AgiEngine::cmd_reset(uint8 *p) {
+void cmd_reset(AgiGame *state, uint8 *p) {
 	setflag(*p, false);
 }
 
-void AgiEngine::cmd_toggle(uint8 *p) {
+void cmd_toggle(AgiGame *state, uint8 *p) {
 	setflag(*p, !getflag(*p));
 }
 
-void AgiEngine::cmd_set_v(uint8 *p) {
+void cmd_set_v(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], true);
 }
 
-void AgiEngine::cmd_reset_v(uint8 *p) {
+void cmd_reset_v(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], false);
 }
 
-void AgiEngine::cmd_toggle_v(uint8 *p) {
+void cmd_toggle_v(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], !getflag(_v[p0]));
 }
 
-void AgiEngine::cmd_new_room(uint8 *p) {
-	newRoom(p0);
+void cmd_new_room(AgiGame *state, uint8 *p) {
+	state->_vm->newRoom(p0);
 
 	// WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush.
 	// Intro was skipped because the enter-keypress finalizing the entering
@@ -160,82 +167,82 @@ void AgiEngine::cmd_new_room(uint8 *p) {
 	// loaded so that no keys from the copy protection scene can be left
 	// over to cause the intro to skip to the _game's start.
 	if (getGameID() == GID_GOLDRUSH && p0 == 73)
-		_game.keypress = 0;
+		state->keypress = 0;
 }
 
-void AgiEngine::cmd_new_room_f(uint8 *p) {
-	newRoom(_v[p0]);
+void cmd_new_room_f(AgiGame *state, uint8 *p) {
+	state->_vm->newRoom(_v[p0]);
 }
 
-void AgiEngine::cmd_load_view(uint8 *p) {
-	agiLoadResource(rVIEW, p0);
+void cmd_load_view(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rVIEW, p0);
 }
 
-void AgiEngine::cmd_load_logic(uint8 *p) {
-	agiLoadResource(rLOGIC, p0);
+void cmd_load_logic(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rLOGIC, p0);
 }
 
-void AgiEngine::cmd_load_sound(uint8 *p) {
-	agiLoadResource(rSOUND, p0);
+void cmd_load_sound(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rSOUND, p0);
 }
 
-void AgiEngine::cmd_load_view_f(uint8 *p) {
-	agiLoadResource(rVIEW, _v[p0]);
+void cmd_load_view_f(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rVIEW, _v[p0]);
 }
 
-void AgiEngine::cmd_load_logic_f(uint8 *p) {
-	agiLoadResource(rLOGIC, _v[p0]);
+void cmd_load_logic_f(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rLOGIC, _v[p0]);
 }
 
-void AgiEngine::cmd_discard_view(uint8 *p) {
-	agiUnloadResource(rVIEW, p0);
+void cmd_discard_view(AgiGame *state, uint8 *p) {
+	state->_vm->agiUnloadResource(rVIEW, p0);
 }
 
-void AgiEngine::cmd_object_on_anything(uint8 *p) {
+void cmd_object_on_anything(AgiGame *state, uint8 *p) {
 	vt.flags &= ~(ON_WATER | ON_LAND);
 }
 
-void AgiEngine::cmd_object_on_land(uint8 *p) {
+void cmd_object_on_land(AgiGame *state, uint8 *p) {
 	vt.flags |= ON_LAND;
 }
 
-void AgiEngine::cmd_object_on_water(uint8 *p) {
+void cmd_object_on_water(AgiGame *state, uint8 *p) {
 	vt.flags |= ON_WATER;
 }
 
-void AgiEngine::cmd_observe_horizon(uint8 *p) {
+void cmd_observe_horizon(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_HORIZON;
 }
 
-void AgiEngine::cmd_ignore_horizon(uint8 *p) {
+void cmd_ignore_horizon(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_HORIZON;
 }
 
-void AgiEngine::cmd_observe_objs(uint8 *p) {
+void cmd_observe_objs(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_OBJECTS;
 }
 
-void AgiEngine::cmd_ignore_objs(uint8 *p) {
+void cmd_ignore_objs(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_OBJECTS;
 }
 
-void AgiEngine::cmd_observe_blocks(uint8 *p) {
+void cmd_observe_blocks(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_BLOCKS;
 }
 
-void AgiEngine::cmd_ignore_blocks(uint8 *p) {
+void cmd_ignore_blocks(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_BLOCKS;
 }
 
-void AgiEngine::cmd_set_horizon(uint8 *p) {
-	_game.horizon = p0;
+void cmd_set_horizon(AgiGame *state, uint8 *p) {
+	state->horizon = p0;
 }
 
-void AgiEngine::cmd_get_priority(uint8 *p) {
+void cmd_get_priority(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.priority;
 }
 
-void AgiEngine::cmd_set_priority(uint8 *p) {
+void cmd_set_priority(AgiGame *state, uint8 *p) {
 	vt.flags |= FIXED_PRIORITY;
 	vt.priority = p1;
 
@@ -253,250 +260,250 @@ void AgiEngine::cmd_set_priority(uint8 *p) {
 	// Therefore, this workaround only affects that specific part of this scene
 	// Ego is set to object 19 by script 54
 	if (getGameID() == GID_KQ4 && vt.currentView == 152) {
-		_game.viewTable[19].flags |= FIXED_PRIORITY;
-		_game.viewTable[19].priority = 7;
+		state->viewTable[19].flags |= FIXED_PRIORITY;
+		state->viewTable[19].priority = 7;
 	}
 }
 
-void AgiEngine::cmd_set_priority_f(uint8 *p) {
+void cmd_set_priority_f(AgiGame *state, uint8 *p) {
 	vt.flags |= FIXED_PRIORITY;
 	vt.priority = _v[p1];
 }
 
-void AgiEngine::cmd_release_priority(uint8 *p) {
+void cmd_release_priority(AgiGame *state, uint8 *p) {
 	vt.flags &= ~FIXED_PRIORITY;
 }
 
-void AgiEngine::cmd_set_upper_left(uint8 *p) {				// do nothing (AGI 2.917)
+void cmd_set_upper_left(AgiGame *state, uint8 *p) {				// do nothing (AGI 2.917)
 }
 
-void AgiEngine::cmd_start_update(uint8 *p) {
-	startUpdate(&vt);
+void cmd_start_update(AgiGame *state, uint8 *p) {
+	state->_vm->startUpdate(&vt);
 }
 
-void AgiEngine::cmd_stop_update(uint8 *p) {
-	stopUpdate(&vt);
+void cmd_stop_update(AgiGame *state, uint8 *p) {
+	state->_vm->stopUpdate(&vt);
 }
 
-void AgiEngine::cmd_current_view(uint8 *p) {
+void cmd_current_view(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentView;
 }
 
-void AgiEngine::cmd_current_cel(uint8 *p) {
+void cmd_current_cel(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentCel;
 	debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]);
 }
 
-void AgiEngine::cmd_current_loop(uint8 *p) {
+void cmd_current_loop(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentLoop;
 }
 
-void AgiEngine::cmd_last_cel(uint8 *p) {
+void cmd_last_cel(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.loopData->numCels - 1;
 }
 
-void AgiEngine::cmd_set_cel(uint8 *p) {
-	setCel(&vt, p1);
+void cmd_set_cel(AgiGame *state, uint8 *p) {
+	state->_vm->setCel(&vt, p1);
 	vt.flags &= ~DONTUPDATE;
 }
 
-void AgiEngine::cmd_set_cel_f(uint8 *p) {
-	setCel(&vt, _v[p1]);
+void cmd_set_cel_f(AgiGame *state, uint8 *p) {
+	state->_vm->setCel(&vt, _v[p1]);
 	vt.flags &= ~DONTUPDATE;
 }
 
-void AgiEngine::cmd_set_view(uint8 *p) {
-	setView(&vt, p1);
+void cmd_set_view(AgiGame *state, uint8 *p) {
+	state->_vm->setView(&vt, p1);
 }
 
-void AgiEngine::cmd_set_view_f(uint8 *p) {
-	setView(&vt, _v[p1]);
+void cmd_set_view_f(AgiGame *state, uint8 *p) {
+	state->_vm->setView(&vt, _v[p1]);
 }
 
-void AgiEngine::cmd_set_loop(uint8 *p) {
-	setLoop(&vt, p1);
+void cmd_set_loop(AgiGame *state, uint8 *p) {
+	state->_vm->setLoop(&vt, p1);
 }
 
-void AgiEngine::cmd_set_loop_f(uint8 *p) {
-	setLoop(&vt, _v[p1]);
+void cmd_set_loop_f(AgiGame *state, uint8 *p) {
+	state->_vm->setLoop(&vt, _v[p1]);
 }
 
-void AgiEngine::cmd_number_of_loops(uint8 *p) {
+void cmd_number_of_loops(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.numLoops;
 }
 
-void AgiEngine::cmd_fix_loop(uint8 *p) {
+void cmd_fix_loop(AgiGame *state, uint8 *p) {
 	vt.flags |= FIX_LOOP;
 }
 
-void AgiEngine::cmd_release_loop(uint8 *p) {
+void cmd_release_loop(AgiGame *state, uint8 *p) {
 	vt.flags &= ~FIX_LOOP;
 }
 
-void AgiEngine::cmd_step_size(uint8 *p) {
+void cmd_step_size(AgiGame *state, uint8 *p) {
 	vt.stepSize = _v[p1];
 }
 
-void AgiEngine::cmd_step_time(uint8 *p) {
+void cmd_step_time(AgiGame *state, uint8 *p) {
 	vt.stepTime = vt.stepTimeCount = _v[p1];
 }
 
-void AgiEngine::cmd_cycle_time(uint8 *p) {
+void cmd_cycle_time(AgiGame *state, uint8 *p) {
 	vt.cycleTime = vt.cycleTimeCount = _v[p1];
 }
 
-void AgiEngine::cmd_stop_cycling(uint8 *p) {
+void cmd_stop_cycling(AgiGame *state, uint8 *p) {
 	vt.flags &= ~CYCLING;
 }
 
-void AgiEngine::cmd_start_cycling(uint8 *p) {
+void cmd_start_cycling(AgiGame *state, uint8 *p) {
 	vt.flags |= CYCLING;
 }
 
-void AgiEngine::cmd_normal_cycle(uint8 *p) {
+void cmd_normal_cycle(AgiGame *state, uint8 *p) {
 	vt.cycle = CYCLE_NORMAL;
 	vt.flags |= CYCLING;
 }
 
-void AgiEngine::cmd_reverse_cycle(uint8 *p) {
+void cmd_reverse_cycle(AgiGame *state, uint8 *p) {
 	vt.cycle = CYCLE_REVERSE;
 	vt.flags |= CYCLING;
 }
 
-void AgiEngine::cmd_set_dir(uint8 *p) {
+void cmd_set_dir(AgiGame *state, uint8 *p) {
 	vt.direction = _v[p1];
 }
 
-void AgiEngine::cmd_get_dir(uint8 *p) {
+void cmd_get_dir(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.direction;
 }
 
-void AgiEngine::cmd_get_room_f(uint8 *p) {
-	_v[p1] = objectGetLocation(_v[p0]);
+void cmd_get_room_f(AgiGame *state, uint8 *p) {
+	_v[p1] = state->_vm->objectGetLocation(_v[p0]);
 }
 
-void AgiEngine::cmd_put(uint8 *p) {
-	objectSetLocation(p0, _v[p1]);
+void cmd_put(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(p0, _v[p1]);
 }
 
-void AgiEngine::cmd_put_f(uint8 *p) {
-	objectSetLocation(_v[p0], _v[p1]);
+void cmd_put_f(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(_v[p0], _v[p1]);
 }
 
-void AgiEngine::cmd_drop(uint8 *p) {
-	objectSetLocation(p0, 0);
+void cmd_drop(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(p0, 0);
 }
 
-void AgiEngine::cmd_get(uint8 *p) {
-	objectSetLocation(p0, EGO_OWNED);
+void cmd_get(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(p0, EGO_OWNED);
 }
 
-void AgiEngine::cmd_get_f(uint8 *p) {
-	objectSetLocation(_v[p0], EGO_OWNED);
+void cmd_get_f(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(_v[p0], EGO_OWNED);
 }
 
-void AgiEngine::cmd_word_to_string(uint8 *p) {
-	strcpy(_game.strings[p0], _game.egoWords[p1].word);
+void cmd_word_to_string(AgiGame *state, uint8 *p) {
+	strcpy(state->strings[p0], state->egoWords[p1].word);
 }
 
-void AgiEngine::cmd_open_dialogue(uint8 *p) {
-	_game.hasWindow = true;
+void cmd_open_dialogue(AgiGame *state, uint8 *p) {
+	state->hasWindow = true;
 }
 
-void AgiEngine::cmd_close_dialogue(uint8 *p) {
-	_game.hasWindow = false;
+void cmd_close_dialogue(AgiGame *state, uint8 *p) {
+	state->hasWindow = false;
 }
 
-void AgiEngine::cmd_close_window(uint8 *p) {
-	closeWindow();
+void cmd_close_window(AgiGame *state, uint8 *p) {
+	state->_vm->closeWindow();
 }
 
-void AgiEngine::cmd_status_line_on(uint8 *p) {
-	_game.statusLine = true;
-	writeStatus();
+void cmd_status_line_on(AgiGame *state, uint8 *p) {
+	state->statusLine = true;
+	state->_vm->writeStatus();
 }
 
-void AgiEngine::cmd_status_line_off(uint8 *p) {
-	_game.statusLine = false;
-	writeStatus();
+void cmd_status_line_off(AgiGame *state, uint8 *p) {
+	state->statusLine = false;
+	state->_vm->writeStatus();
 }
 
-void AgiEngine::cmd_show_obj(uint8 *p) {
-	_sprites->showObj(p0);
+void cmd_show_obj(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->showObj(p0);
 }
 
-void AgiEngine::cmd_show_obj_v(uint8 *p) {
-	_sprites->showObj(_v[p0]);
+void cmd_show_obj_v(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->showObj(_v[p0]);
 }
 
-void AgiEngine::cmd_sound(uint8 *p) {
-	_sound->startSound(p0, p1);
+void cmd_sound(AgiGame *state, uint8 *p) {
+	state->_vm->_sound->startSound(p0, p1);
 }
 
-void AgiEngine::cmd_stop_sound(uint8 *p) {
-	_sound->stopSound();
+void cmd_stop_sound(AgiGame *state, uint8 *p) {
+	state->_vm->_sound->stopSound();
 }
 
-void AgiEngine::cmd_menu_input(uint8 *p) {
-	newInputMode(INPUT_MENU);
+void cmd_menu_input(AgiGame *state, uint8 *p) {
+	state->_vm->newInputMode(INPUT_MENU);
 }
 
-void AgiEngine::cmd_enable_item(uint8 *p) {
-	_menu->setItem(p0, true);
+void cmd_enable_item(AgiGame *state, uint8 *p) {
+	state->_vm->_menu->setItem(p0, true);
 }
 
-void AgiEngine::cmd_disable_item(uint8 *p) {
-	_menu->setItem(p0, false);
+void cmd_disable_item(AgiGame *state, uint8 *p) {
+	state->_vm->_menu->setItem(p0, false);
 }
 
-void AgiEngine::cmd_submit_menu(uint8 *p) {
-	_menu->submit();
+void cmd_submit_menu(AgiGame *state, uint8 *p) {
+	state->_vm->_menu->submit();
 }
 
-void AgiEngine::cmd_set_scan_start(uint8 *p) {
-	_curLogic->sIP = _curLogic->cIP;
+void cmd_set_scan_start(AgiGame *state, uint8 *p) {
+	state->_curLogic->sIP = state->_curLogic->cIP;
 }
 
-void AgiEngine::cmd_reset_scan_start(uint8 *p) {
-	_curLogic->sIP = 2;
+void cmd_reset_scan_start(AgiGame *state, uint8 *p) {
+	state->_curLogic->sIP = 2;
 }
 
-void AgiEngine::cmd_save_game(uint8 *p) {
-	_game.simpleSave ? saveGameSimple() : saveGameDialog();
+void cmd_save_game(AgiGame *state, uint8 *p) {
+	state->simpleSave ? state->_vm->saveGameSimple() : state->_vm->saveGameDialog();
 }
 
-void AgiEngine::cmd_load_game(uint8 *p) {
+void cmd_load_game(AgiGame *state, uint8 *p) {
 	assert(1);
-	_game.simpleSave ? loadGameSimple() : loadGameDialog();
+	state->simpleSave ? state->_vm->loadGameSimple() : state->_vm->loadGameDialog();
 }
 
-void AgiEngine::cmd_init_disk(uint8 *p) {				// do nothing
+void cmd_init_disk(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void AgiEngine::cmd_log(uint8 *p) {				// do nothing
+void cmd_log(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void AgiEngine::cmd_trace_on(uint8 *p) {				// do nothing
+void cmd_trace_on(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void AgiEngine::cmd_trace_info(uint8 *p) {				// do nothing
+void cmd_trace_info(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void AgiEngine::cmd_show_mem(uint8 *p) {
-	messageBox("Enough memory");
+void cmd_show_mem(AgiGame *state, uint8 *p) {
+	state->_vm->messageBox("Enough memory");
 }
 
-void AgiEngine::cmd_init_joy(uint8 *p) { // do nothing
+void cmd_init_joy(AgiGame *state, uint8 *p) { // do nothing
 }
 
-void AgiEngine::cmd_script_size(uint8 *p) {
+void cmd_script_size(AgiGame *state, uint8 *p) {
 	debug(0, "script.size(%d)", p0);
 }
 
-void AgiEngine::cmd_cancel_line(uint8 *p) {
-	_game.inputBuffer[0] = 0;
-	_game.cursorPos = 0;
-	writePrompt();
+void cmd_cancel_line(AgiGame *state, uint8 *p) {
+	state->inputBuffer[0] = 0;
+	state->cursorPos = 0;
+	state->_vm->writePrompt();
 }
 
 // This implementation is based on observations of Amiga's Gold Rush.
@@ -509,7 +516,7 @@ void AgiEngine::cmd_cancel_line(uint8 *p) {
 // 4051 (When ego is stationary),
 // 471 (When walking on the first screen's bridge),
 // 71 (When walking around, using the mouse or the keyboard).
-void AgiEngine::cmd_obj_status_f(uint8 *p) {
+void cmd_obj_status_f(AgiGame *state, uint8 *p) {
 	const char *cycleDesc;  // Object's cycle description line
 	const char *motionDesc; // Object's motion description line
 	char msg[256];          // The whole object status message
@@ -570,7 +577,7 @@ void AgiEngine::cmd_obj_status_f(uint8 *p) {
 		vt_v.stepSize,
 		cycleDesc,
 		motionDesc);
-	messageBox(msg);
+	state->_vm->messageBox(msg);
 }
 
 // unknown commands:
@@ -581,49 +588,49 @@ void AgiEngine::cmd_obj_status_f(uint8 *p) {
 // unk_174: Change priority table (used in KQ4) -- j5
 // unk_177: Disable menus completely -- j5
 // unk_181: Deactivate keypressed control (default control of ego)
-void AgiEngine::cmd_set_simple(uint8 *p) {
+void cmd_set_simple(AgiGame *state, uint8 *p) {
 	if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) {
-		_game.simpleSave = true;
+		state->simpleSave = true;
 	} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
-		// Load the picture. Similar to void AgiEngine::cmd_load_pic(uint8 *p).
-		_sprites->eraseBoth();
-		agiLoadResource(rPICTURE, _v[p0]);
+		// Load the picture. Similar to void cmd_load_pic(AgiGame *state, uint8 *p).
+		state->_vm->_sprites->eraseBoth();
+		state->_vm->agiLoadResource(rPICTURE, _v[p0]);
 
-		// Draw the picture. Similar to void AgiEngine::cmd_draw_pic(uint8 *p).
-		_picture->decodePicture(_v[p0], false, true);
-		_sprites->blitBoth();
-		_game.pictureShown = 0;
+		// Draw the picture. Similar to void cmd_draw_pic(AgiGame *state, uint8 *p).
+		state->_vm->_picture->decodePicture(_v[p0], false, true);
+		state->_vm->_sprites->blitBoth();
+		state->pictureShown = 0;
 
-		// Show the picture. Similar to void AgiEngine::cmd_show_pic(uint8 *p).
+		// Show the picture. Similar to void cmd_show_pic(AgiGame *state, uint8 *p).
 		setflag(fOutputMode, false);
-		closeWindow();
-		_picture->showPic();
-		_game.pictureShown = 1;
+		state->_vm->closeWindow();
+		state->_vm->_picture->showPic();
+		state->pictureShown = 1;
 
 		// Simulate slowww computer. Many effects rely on this
-		pause(kPausePicture);
+		state->_vm->pause(kPausePicture);
 	}
 }
 
-void AgiEngine::cmd_pop_script(uint8 *p) {
+void cmd_pop_script(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x2915) {
 		debug(0, "pop.script");
 	}
 }
 
-void AgiEngine::cmd_hold_key(uint8 *p) {
+void cmd_hold_key(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
-		_egoHoldKey = true;
+		state->_vm->_egoHoldKey = true;
 	}
 }
 
-void AgiEngine::cmd_discard_sound(uint8 *p) {
+void cmd_discard_sound(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x2936) {
 		debug(0, "discard.sound");
 	}
 }
 
-void AgiEngine::cmd_hide_mouse(uint8 *p) {
+void cmd_hide_mouse(AgiGame *state, uint8 *p) {
 	// WORKAROUND: Turns off current movement that's being caused with the mouse.
 	// This fixes problems with too many popup boxes appearing in the Amiga
 	// Gold Rush's copy protection failure scene (i.e. the hanging scene, logic.192).
@@ -631,37 +638,37 @@ void AgiEngine::cmd_hide_mouse(uint8 *p) {
 	// to walk somewhere else than to the right using the mouse.
 	// FIXME: Write a proper implementation using disassembly and
 	//        apply it to other games as well if applicable.
-	_game.viewTable[0].flags &= ~ADJ_EGO_XY;
+	state->viewTable[0].flags &= ~ADJ_EGO_XY;
 
 	g_system->showMouse(false);
 }
 
-void AgiEngine::cmd_allow_menu(uint8 *p) {
+void cmd_allow_menu(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
 		setflag(fMenusWork, ((p0 != 0) ? true : false));
 	}
 }
 
-void AgiEngine::cmd_show_mouse(uint8 *p) {
+void cmd_show_mouse(AgiGame *state, uint8 *p) {
 	g_system->showMouse(true);
 }
 
-void AgiEngine::cmd_fence_mouse(uint8 *p) {
-	_game.mouseFence.moveTo(p0, p1);
-	_game.mouseFence.setWidth(p2 - p0);
-	_game.mouseFence.setHeight(p3 - p1);
+void cmd_fence_mouse(AgiGame *state, uint8 *p) {
+	state->mouseFence.moveTo(p0, p1);
+	state->mouseFence.setWidth(p2 - p0);
+	state->mouseFence.setHeight(p3 - p1);
 }
 
-void AgiEngine::cmd_release_key(uint8 *p) {
+void cmd_release_key(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
-		_egoHoldKey = false;
+		state->_vm->_egoHoldKey = false;
 	}
 }
 
-void AgiEngine::cmd_adj_ego_move_to_x_y(uint8 *p) {
+void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p) {
 	int8 x, y;
 
-	switch (logicNamesCmd[182].numArgs) {
+	switch (logicNamesCmd[182].argumentsLength()) {
 	// The 2 arguments version is used at least in Amiga Gold Rush!
 	// (v2.05 1989-03-09, Amiga AGI 2.316) in logics 130 and 150
 	// (Using arguments (0, 0), (0, 7), (0, 8), (9, 9) and (-9, 9)).
@@ -680,57 +687,57 @@ void AgiEngine::cmd_adj_ego_move_to_x_y(uint8 *p) {
 		// onto the ladder so this is more like it (Although that may be caused
 		// by something else because this command doesn't do any flag manipulations
 		// in the Amiga version - checked it with disassembly).
-		if (x != _game.adjMouseX || y != _game.adjMouseY)
-			_game.viewTable[EGO_VIEW_TABLE].flags &= ~ADJ_EGO_XY;
+		if (x != state->adjMouseX || y != state->adjMouseY)
+			state->viewTable[EGO_VIEW_TABLE].flags &= ~ADJ_EGO_XY;
 
-		_game.adjMouseX = x;
-		_game.adjMouseY = y;
+		state->adjMouseX = x;
+		state->adjMouseY = y;
 
 		debugC(4, kDebugLevelScripts, "adj.ego.move.to.x.y(%d, %d)", x, y);
 		break;
 	// TODO: Check where (if anywhere) the 0 arguments version is used
 	case 0:
 	default:
-		_game.viewTable[0].flags |= ADJ_EGO_XY;
+		state->viewTable[0].flags |= ADJ_EGO_XY;
 		break;
 	}
 }
 
-void AgiEngine::cmd_parse(uint8 *p) {
+void cmd_parse(AgiGame *state, uint8 *p) {
 	_v[vWordNotFound] = 0;
 	setflag(fEnteredCli, false);
 	setflag(fSaidAcceptedInput, false);
 
-	dictionaryWords(agiSprintf(_game.strings[p0]));
+	state->_vm->dictionaryWords(state->_vm->agiSprintf(state->strings[p0]));
 }
 
-void AgiEngine::cmd_call(uint8 *p) {
+void cmd_call(AgiGame *state, uint8 *p) {
 	int oldCIP;
 	int oldLognum;
 
 	// CM: we don't save sIP because set.scan.start can be
 	//     used in a called script (fixes xmas demo)
-	oldCIP = _curLogic->cIP;
-	oldLognum = _game.lognum;
+	oldCIP = state->_curLogic->cIP;
+	oldLognum = state->lognum;
 
-	runLogic(p0);
+	state->_vm->runLogic(p0);
 
-	_game.lognum = oldLognum;
-	_curLogic = &_game.logics[_game.lognum];
-	_curLogic->cIP = oldCIP;
+	state->lognum = oldLognum;
+	state->_curLogic = &state->logics[state->lognum];
+	state->_curLogic->cIP = oldCIP;
 }
 
-void AgiEngine::cmd_call_f(uint8 *p) {
-	cmd_call(&_v[p0]);
+void cmd_call_f(AgiGame *state, uint8 *p) {
+	cmd_call(state, &_v[p0]);
 }
 
-void AgiEngine::cmd_draw_pic(uint8 *p) {
+void cmd_draw_pic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]);
-	_sprites->eraseBoth();
-	_picture->decodePicture(_v[p0], true);
-	_sprites->blitBoth();
-	_sprites->commitBoth();
-	_game.pictureShown = 0;
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->_picture->decodePicture(_v[p0], true);
+	state->_vm->_sprites->blitBoth();
+	state->_vm->_sprites->commitBoth();
+	state->pictureShown = 0;
 	debugC(6, kDebugLevelScripts, "--- end of draw pic %d ---", _v[p0]);
 
 	// WORKAROUND for a script bug which exists in SQ1, logic scripts
@@ -749,60 +756,60 @@ void AgiEngine::cmd_draw_pic(uint8 *p) {
 		setflag(103, false);
 
 	// Simulate slowww computer. Many effects rely on this
-	pause(kPausePicture);
+	state->_vm->pause(kPausePicture);
 }
 
-void AgiEngine::cmd_show_pic(uint8 *p) {
+void cmd_show_pic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "=== show pic ===");
 
 	setflag(fOutputMode, false);
-	closeWindow();
-	_picture->showPic();
-	_game.pictureShown = 1;
+	state->_vm->closeWindow();
+	state->_vm->_picture->showPic();
+	state->pictureShown = 1;
 
 	debugC(6, kDebugLevelScripts, "--- end of show pic ---");
 }
 
-void AgiEngine::cmd_load_pic(uint8 *p) {
-	_sprites->eraseBoth();
-	agiLoadResource(rPICTURE, _v[p0]);
-	_sprites->blitBoth();
-	_sprites->commitBoth();
+void cmd_load_pic(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->agiLoadResource(rPICTURE, _v[p0]);
+	state->_vm->_sprites->blitBoth();
+	state->_vm->_sprites->commitBoth();
 }
 
-void AgiEngine::cmd_discard_pic(uint8 *p) {
+void cmd_discard_pic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "--- discard pic ---");
 	// do nothing
 }
 
-void AgiEngine::cmd_overlay_pic(uint8 *p) {
+void cmd_overlay_pic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "--- overlay pic ---");
 
-	_sprites->eraseBoth();
-	_picture->decodePicture(_v[p0], false);
-	_sprites->blitBoth();
-	_game.pictureShown = 0;
-	_sprites->commitBoth();
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->_picture->decodePicture(_v[p0], false);
+	state->_vm->_sprites->blitBoth();
+	state->pictureShown = 0;
+	state->_vm->_sprites->commitBoth();
 
 	// Simulate slowww computer. Many effects rely on this
-	pause(kPausePicture);
+	state->_vm->pause(kPausePicture);
 }
 
-void AgiEngine::cmd_show_pri_screen(uint8 *p) {
-	_debug.priority = 1;
-	_sprites->eraseBoth();
-	_picture->showPic();
-	_sprites->blitBoth();
+void cmd_show_pri_screen(AgiGame *state, uint8 *p) {
+	state->_vm->_debug.priority = 1;
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->_picture->showPic();
+	state->_vm->_sprites->blitBoth();
 
-	waitKey();
+	state->_vm->waitKey();
 
-	_debug.priority = 0;
-	_sprites->eraseBoth();
-	_picture->showPic();
-	_sprites->blitBoth();
+	state->_vm->_debug.priority = 0;
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->_picture->showPic();
+	state->_vm->_sprites->blitBoth();
 }
 
-void AgiEngine::cmd_animate_obj(uint8 *p) {
+void cmd_animate_obj(AgiGame *state, uint8 *p) {
 	if (vt.flags & ANIMATED)
 		return;
 
@@ -813,14 +820,14 @@ void AgiEngine::cmd_animate_obj(uint8 *p) {
 	vt.direction = 0;
 }
 
-void AgiEngine::cmd_unanimate_all(uint8 *p) {
+void cmd_unanimate_all(AgiGame *state, uint8 *p) {
 	int i;
 
 	for (i = 0; i < MAX_VIEWTABLE; i++)
-		_game.viewTable[i].flags &= ~(ANIMATED | DRAWN);
+		state->viewTable[i].flags &= ~(ANIMATED | DRAWN);
 }
 
-void AgiEngine::cmd_draw(uint8 *p) {
+void cmd_draw(AgiGame *state, uint8 *p) {
 	if (vt.flags & DRAWN)
 		return;
 
@@ -831,15 +838,15 @@ void AgiEngine::cmd_draw(uint8 *p) {
 
 	vt.flags |= UPDATE;
 	if (getVersion() >= 0x3000) {
-		setLoop(&vt, vt.currentLoop);
-		setCel(&vt, vt.currentCel);
+		state->_vm->setLoop(&vt, vt.currentLoop);
+		state->_vm->setCel(&vt, vt.currentCel);
 	}
 
-	fixPosition(p0);
+	state->_vm->fixPosition(p0);
 	vt.xPos2 = vt.xPos;
 	vt.yPos2 = vt.yPos;
 	vt.celData2 = vt.celData;
-	_sprites->eraseUpdSprites();
+	state->_vm->_sprites->eraseUpdSprites();
 	vt.flags |= DRAWN;
 
 	// WORKAROUND: This fixes a bug with AGI Fanmade _game Space Trek.
@@ -856,28 +863,28 @@ void AgiEngine::cmd_draw(uint8 *p) {
 	if (getFeatures() & GF_FANMADE)	// See Sarien bug #546562
 		vt.flags |= ANIMATED;
 
-	_sprites->blitUpdSprites();
+	state->_vm->_sprites->blitUpdSprites();
 	vt.flags &= ~DONTUPDATE;
 
-	_sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true);
+	state->_vm->_sprites->commitBlock(vt.xPos, vt.yPos - vt.ySize + 1, vt.xPos + vt.xSize - 1, vt.yPos, true);
 
 	debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", p0, vt.flags);
 }
 
-void AgiEngine::cmd_erase(uint8 *p) {
+void cmd_erase(AgiGame *state, uint8 *p) {
 	if (~vt.flags & DRAWN)
 		return;
 
-	_sprites->eraseUpdSprites();
+	state->_vm->_sprites->eraseUpdSprites();
 
 	if (vt.flags & UPDATE) {
 		vt.flags &= ~DRAWN;
 	} else {
-		_sprites->eraseNonupdSprites();
+		state->_vm->_sprites->eraseNonupdSprites();
 		vt.flags &= ~DRAWN;
-		_sprites->blitNonupdSprites();
+		state->_vm->_sprites->blitNonupdSprites();
 	}
-	_sprites->blitUpdSprites();
+	state->_vm->_sprites->blitUpdSprites();
 
 	int x1, y1, x2, y2;
 
@@ -886,10 +893,10 @@ void AgiEngine::cmd_erase(uint8 *p) {
 	y1 = MIN((int)MIN(vt.yPos, vt.yPos2), MIN(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
 	y2 = MAX((int)MAX(vt.yPos, vt.yPos2), MAX(vt.yPos - vt.celData->height, vt.yPos2 - vt.celData2->height));
 
-	_sprites->commitBlock(x1, y1, x2, y2, true);
+	state->_vm->_sprites->commitBlock(x1, y1, x2, y2, true);
 }
 
-void AgiEngine::cmd_position(uint8 *p) {
+void cmd_position(AgiGame *state, uint8 *p) {
 	vt.xPos = vt.xPos2 = p1;
 	vt.yPos = vt.yPos2 = p2;
 
@@ -907,10 +914,10 @@ void AgiEngine::cmd_position(uint8 *p) {
 	// strictly need the identical workaround in the position.v-command but it does make
 	// for a nice symmetry.
 	if (getFeatures() & GF_CLIPCOORDS)
-		clipViewCoordinates(&vt);
+		state->_vm->clipViewCoordinates(&vt);
 }
 
-void AgiEngine::cmd_position_f(uint8 *p) {
+void cmd_position_f(AgiGame *state, uint8 *p) {
 	vt.xPos = vt.xPos2 = _v[p1];
 	vt.yPos = vt.yPos2 = _v[p2];
 
@@ -918,15 +925,15 @@ void AgiEngine::cmd_position_f(uint8 *p) {
 	// with an accompanying identical workaround in position-command (i.e. command 0x25).
 	// See that workaround's comment for more in-depth information.
 	if (getFeatures() & GF_CLIPCOORDS)
-		clipViewCoordinates(&vt);
+		state->_vm->clipViewCoordinates(&vt);
 }
 
-void AgiEngine::cmd_get_posn(uint8 *p) {
-	_game.vars[p1] = (unsigned char)vt.xPos;
-	_game.vars[p2] = (unsigned char)vt.yPos;
+void cmd_get_posn(AgiGame *state, uint8 *p) {
+	state->vars[p1] = (unsigned char)vt.xPos;
+	state->vars[p2] = (unsigned char)vt.yPos;
 }
 
-void AgiEngine::cmd_reposition(uint8 *p) {
+void cmd_reposition(AgiGame *state, uint8 *p) {
 	int dx = (int8) _v[p1], dy = (int8) _v[p2];
 
 	debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy);
@@ -942,38 +949,38 @@ void AgiEngine::cmd_reposition(uint8 *p) {
 	else
 		vt.yPos += dy;
 
-	fixPosition(p0);
+	state->_vm->fixPosition(p0);
 }
 
-void AgiEngine::cmd_reposition_to(uint8 *p) {
+void cmd_reposition_to(AgiGame *state, uint8 *p) {
 	vt.xPos = p1;
 	vt.yPos = p2;
 	vt.flags |= UPDATE_POS;
-	fixPosition(p0);
+	state->_vm->fixPosition(p0);
 }
 
-void AgiEngine::cmd_reposition_to_f(uint8 *p) {
+void cmd_reposition_to_f(AgiGame *state, uint8 *p) {
 	vt.xPos = _v[p1];
 	vt.yPos = _v[p2];
 	vt.flags |= UPDATE_POS;
-	fixPosition(p0);
+	state->_vm->fixPosition(p0);
 }
 
-void AgiEngine::cmd_add_to_pic(uint8 *p) {
-	_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6);
+void cmd_add_to_pic(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6);
 }
 
-void AgiEngine::cmd_add_to_pic_f(uint8 *p) {
-	_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
+void cmd_add_to_pic_f(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
 }
 
-void AgiEngine::cmd_force_update(uint8 *p) {
-	_sprites->eraseBoth();
-	_sprites->blitBoth();
-	_sprites->commitBoth();
+void cmd_force_update(AgiGame *state, uint8 *p) {
+	state->_vm->_sprites->eraseBoth();
+	state->_vm->_sprites->blitBoth();
+	state->_vm->_sprites->commitBoth();
 }
 
-void AgiEngine::cmd_reverse_loop(uint8 *p) {
+void cmd_reverse_loop(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
 	vt.cycle = CYCLE_REV_LOOP;
 	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
@@ -981,7 +988,7 @@ void AgiEngine::cmd_reverse_loop(uint8 *p) {
 	setflag(p1, false);
 }
 
-void AgiEngine::cmd_end_of_loop(uint8 *p) {
+void cmd_end_of_loop(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
 	vt.cycle = CYCLE_END_OF_LOOP;
 	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
@@ -989,50 +996,50 @@ void AgiEngine::cmd_end_of_loop(uint8 *p) {
 	setflag(p1, false);
 }
 
-void AgiEngine::cmd_block(uint8 *p) {
+void cmd_block(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
-	_game.block.active = true;
-	_game.block.x1 = p0;
-	_game.block.y1 = p1;
-	_game.block.x2 = p2;
-	_game.block.y2 = p3;
+	state->block.active = true;
+	state->block.x1 = p0;
+	state->block.y1 = p1;
+	state->block.x2 = p2;
+	state->block.y2 = p3;
 }
 
-void AgiEngine::cmd_unblock(uint8 *p) {
-	_game.block.active = false;
+void cmd_unblock(AgiGame *state, uint8 *p) {
+	state->block.active = false;
 }
 
-void AgiEngine::cmd_normal_motion(uint8 *p) {
+void cmd_normal_motion(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_NORMAL;
 }
 
-void AgiEngine::cmd_stop_motion(uint8 *p) {
+void cmd_stop_motion(AgiGame *state, uint8 *p) {
 	vt.direction = 0;
 	vt.motion = MOTION_NORMAL;
 	if (p0 == 0) {		// ego only
 		_v[vEgoDir] = 0;
-		_game.playerControl = false;
+		state->playerControl = false;
 	}
 }
 
-void AgiEngine::cmd_start_motion(uint8 *p) {
+void cmd_start_motion(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_NORMAL;
 	if (p0 == 0) {		// ego only
 		_v[vEgoDir] = 0;
-		_game.playerControl = true;
+		state->playerControl = true;
 	}
 }
 
-void AgiEngine::cmd_player_control(uint8 *p) {
-	_game.playerControl = true;
-	_game.viewTable[0].motion = MOTION_NORMAL;
+void cmd_player_control(AgiGame *state, uint8 *p) {
+	state->playerControl = true;
+	state->viewTable[0].motion = MOTION_NORMAL;
 }
 
-void AgiEngine::cmd_program_control(uint8 *p) {
-	_game.playerControl = false;
+void cmd_program_control(AgiGame *state, uint8 *p) {
+	state->playerControl = false;
 }
 
-void AgiEngine::cmd_follow_ego(uint8 *p) {
+void cmd_follow_ego(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_FOLLOW_EGO;
 	vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
 	vt.parm2 = p2;
@@ -1041,7 +1048,7 @@ void AgiEngine::cmd_follow_ego(uint8 *p) {
 	vt.flags |= UPDATE;
 }
 
-void AgiEngine::cmd_move_obj(uint8 *p) {
+void cmd_move_obj(AgiGame *state, uint8 *p) {
 	// _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4);
 
 	vt.motion = MOTION_MOVE_OBJ;
@@ -1057,14 +1064,14 @@ void AgiEngine::cmd_move_obj(uint8 *p) {
 	vt.flags |= UPDATE;
 
 	if (p0 == 0)
-		_game.playerControl = false;
+		state->playerControl = false;
 
 	// AGI 2.272 (ddp, xmas) doesn't call move_obj!
 	if (getVersion() > 0x2272)
-		moveObj(&vt);
+		state->_vm->moveObj(&vt);
 }
 
-void AgiEngine::cmd_move_obj_f(uint8 *p) {
+void cmd_move_obj_f(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_MOVE_OBJ;
 	vt.parm1 = _v[p1];
 	vt.parm2 = _v[p2];
@@ -1078,63 +1085,63 @@ void AgiEngine::cmd_move_obj_f(uint8 *p) {
 	vt.flags |= UPDATE;
 
 	if (p0 == 0)
-		_game.playerControl = false;
+		state->playerControl = false;
 
 	// AGI 2.272 (ddp, xmas) doesn't call move_obj!
 	if (getVersion() > 0x2272)
-		moveObj(&vt);
+		state->_vm->moveObj(&vt);
 }
 
-void AgiEngine::cmd_wander(uint8 *p) {
+void cmd_wander(AgiGame *state, uint8 *p) {
 	if (p0 == 0)
-		_game.playerControl = false;
+		state->playerControl = false;
 
 	vt.motion = MOTION_WANDER;
 	vt.flags |= UPDATE;
 }
 
-void AgiEngine::cmd_set_game_id(uint8 *p) {
-	if (_curLogic->texts && (p0 - 1) <= _curLogic->numTexts)
-		strncpy(_game.id, _curLogic->texts[p0 - 1], 8);
+void cmd_set_game_id(AgiGame *state, uint8 *p) {
+	if (state->_curLogic->texts && (p0 - 1) <= state->_curLogic->numTexts)
+		strncpy(state->id, state->_curLogic->texts[p0 - 1], 8);
 	else
-		_game.id[0] = 0;
+		state->id[0] = 0;
 
-	debug(0, "Game ID: \"%s\"", _game.id);
+	debug(0, "Game ID: \"%s\"", state->id);
 }
 
-void AgiEngine::cmd_pause(uint8 *p) {
-	int tmp = _game.clockEnabled;
+void cmd_pause(AgiGame *state, uint8 *p) {
+	int tmp = state->clockEnabled;
 	const char *b[] = { "Continue", NULL };
 	const char *b_ru[] = { "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec", NULL };
 
-	_game.clockEnabled = false;
+	state->clockEnabled = false;
 
 	switch (getLanguage()) {
 	case Common::RU_RUS:
-		selectionBox("  \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0.  \n\n\n", b_ru);
+		state->_vm->selectionBox("  \x88\xa3\xe0\xa0 \xae\xe1\xe2\xa0\xad\xae\xa2\xab\xa5\xad\xa0.  \n\n\n", b_ru);
 		break;
 	default:
-		selectionBox("  Game is paused.  \n\n\n", b);
+		state->_vm->selectionBox("  Game is paused.  \n\n\n", b);
 		break;
 	}
-	_game.clockEnabled = tmp;
+	state->clockEnabled = tmp;
 }
 
-void AgiEngine::cmd_set_menu(uint8 *p) {
-	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, _curLogic->numTexts);
+void cmd_set_menu(AgiGame *state, uint8 *p) {
+	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
 
-	if (_curLogic->texts != NULL && p0 <= _curLogic->numTexts)
-		_menu->add(_curLogic->texts[p0 - 1]);
+	if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
+		state->_vm->_menu->add(state->_curLogic->texts[p0 - 1]);
 }
 
-void AgiEngine::cmd_set_menu_item(uint8 *p) {
-	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, _curLogic->numTexts);
+void cmd_set_menu_item(AgiGame *state, uint8 *p) {
+	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
 
-	if (_curLogic->texts != NULL && p0 <= _curLogic->numTexts)
-		_menu->addItem(_curLogic->texts[p0 - 1], p1);
+	if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
+		state->_vm->_menu->addItem(state->_curLogic->texts[p0 - 1], p1);
 }
 
-void AgiEngine::cmd_version(uint8 *p) {
+void cmd_version(AgiGame *state, uint8 *p) {
 	char verMsg[64];
 	char ver2Msg[] =
 	    "\n"
@@ -1171,87 +1178,87 @@ void AgiEngine::cmd_version(uint8 *p) {
 
 	strncpy(q + 1 + gap, verMsg, strlen(verMsg));
 	sprintf(msg, q, maj, min);
-	messageBox(msg);
+	state->_vm->messageBox(msg);
 }
 
-void AgiEngine::cmd_configure_screen(uint8 *p) {
-	_game.lineMinPrint = p0;
-	_game.lineUserInput = p1;
-	_game.lineStatus = p2;
+void cmd_configure_screen(AgiGame *state, uint8 *p) {
+	state->lineMinPrint = p0;
+	state->lineUserInput = p1;
+	state->lineStatus = p2;
 }
 
-void AgiEngine::cmd_text_screen(uint8 *p) {
+void cmd_text_screen(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "switching to text mode");
-	_game.gfxMode = false;
+	state->gfxMode = false;
 
 	// Simulates the "bright background bit" of the PC video
 	// controller.
-	if (_game.colorBg)
-		_game.colorBg |= 0x08;
+	if (state->colorBg)
+		state->colorBg |= 0x08;
 
-	_gfx->clearScreen(_game.colorBg);
+	state->_vm->_gfx->clearScreen(state->colorBg);
 }
 
-void AgiEngine::cmd_graphics(uint8 *p) {
+void cmd_graphics(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "switching to graphics mode");
 
-	if (!_game.gfxMode) {
-		_game.gfxMode = true;
-		_gfx->clearScreen(0);
-		_picture->showPic();
-		writeStatus();
-		writePrompt();
+	if (!state->gfxMode) {
+		state->gfxMode = true;
+		state->_vm->_gfx->clearScreen(0);
+		state->_vm->_picture->showPic();
+		state->_vm->writeStatus();
+		state->_vm->writePrompt();
 	}
 }
 
-void AgiEngine::cmd_set_text_attribute(uint8 *p) {
-	_game.colorFg = p0;
-	_game.colorBg = p1;
+void cmd_set_text_attribute(AgiGame *state, uint8 *p) {
+	state->colorFg = p0;
+	state->colorBg = p1;
 
-	if (_game.gfxMode) {
-		if (_game.colorBg != 0) {
-			_game.colorFg = 0;
-			_game.colorBg = 15;
+	if (state->gfxMode) {
+		if (state->colorBg != 0) {
+			state->colorFg = 0;
+			state->colorBg = 15;
 		}
 	}
 }
 
-void AgiEngine::cmd_status(uint8 *p) {
-	inventory();
+void cmd_status(AgiGame *state, uint8 *p) {
+	state->_vm->inventory();
 }
 
-void AgiEngine::cmd_quit(uint8 *p) {
+void cmd_quit(AgiGame *state, uint8 *p) {
 	const char *buttons[] = { "Quit", "Continue", NULL };
 
-	_sound->stopSound();
+	state->_vm->_sound->stopSound();
 	if (p0) {
-		quitGame();
+		state->_vm->quitGame();
 	} else {
-		if (selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) {
-			quitGame();
+		if (state->_vm->selectionBox(" Quit the game, or continue? \n\n\n", buttons) == 0) {
+			state->_vm->quitGame();
 		}
 	}
 }
 
-void AgiEngine::cmd_restart_game(uint8 *p) {
+void cmd_restart_game(AgiGame *state, uint8 *p) {
 	const char *buttons[] = { "Restart", "Continue", NULL };
 	int sel;
 
-	_sound->stopSound();
+	state->_vm->_sound->stopSound();
 	sel = getflag(fAutoRestart) ? 0 :
-		selectionBox(" Restart _game, or continue? \n\n\n", buttons);
+		state->_vm->selectionBox(" Restart _game, or continue? \n\n\n", buttons);
 
 	if (sel == 0) {
-		_restartGame = true;
+		state->_vm->_restartGame = true;
 		setflag(fRestartGame, true);
-		_menu->enableAll();
+		state->_vm->_menu->enableAll();
 	}
 }
 
-void AgiEngine::cmd_distance(uint8 *p) {
+void cmd_distance(AgiGame *state, uint8 *p) {
 	int16 x1, y1, x2, y2, d;
-	VtEntry *v0 = &_game.viewTable[p0];
-	VtEntry *v1 = &_game.viewTable[p1];
+	VtEntry *v0 = &state->viewTable[p0];
+	VtEntry *v1 = &state->viewTable[p1];
 
 	if (v0->flags & DRAWN && v1->flags & DRAWN) {
 		x1 = v0->xPos + v0->xSize / 2;
@@ -1299,24 +1306,24 @@ void AgiEngine::cmd_distance(uint8 *p) {
 	_v[p2] = (unsigned char)d;
 }
 
-void AgiEngine::cmd_accept_input(uint8 *p) {
+void cmd_accept_input(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts | kDebugLevelInput, "input normal");
 
-	newInputMode(INPUT_NORMAL);
-	_game.inputEnabled = true;
-	writePrompt();
+	state->_vm->newInputMode(INPUT_NORMAL);
+	state->inputEnabled = true;
+	state->_vm->writePrompt();
 }
 
-void AgiEngine::cmd_prevent_input(uint8 *p) {
+void cmd_prevent_input(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts | kDebugLevelInput, "no input");
 
-	newInputMode(INPUT_NONE);
-	_game.inputEnabled = false;
+	state->_vm->newInputMode(INPUT_NONE);
+	state->inputEnabled = false;
 
-	clearPrompt();
+	state->_vm->clearPrompt();
 }
 
-void AgiEngine::cmd_get_string(uint8 *p) {
+void cmd_get_string(AgiGame *state, uint8 *p) {
 	int tex, row, col;
 
 	debugC(4, kDebugLevelScripts, "%d %d %d %d %d", p0, p1, p2, p3, p4);
@@ -1332,63 +1339,63 @@ void AgiEngine::cmd_get_string(uint8 *p) {
 	if (col > 39)
 		col = 39;
 
-	newInputMode(INPUT_GETSTRING);
+	state->_vm->newInputMode(INPUT_GETSTRING);
 
-	if (_curLogic->texts != NULL && _curLogic->numTexts >= tex) {
-		int len = strlen(_curLogic->texts[tex]);
+	if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= tex) {
+		int len = strlen(state->_curLogic->texts[tex]);
 
-		printText(_curLogic->texts[tex], 0, col, row, len, _game.colorFg, _game.colorBg);
-		getString(col + len - 1, row, p4, p0);
+		state->_vm->printText(state->_curLogic->texts[tex], 0, col, row, len, state->colorFg, state->colorBg);
+		state->_vm->getString(col + len - 1, row, p4, p0);
 
 		// SGEO: display input char
-		_gfx->printCharacter((col + len), row, _game.cursorChar, _game.colorFg, _game.colorBg);
+		state->_vm->_gfx->printCharacter((col + len), row, state->cursorChar, state->colorFg, state->colorBg);
 	}
 
 	do {
-		mainCycle();
-	} while (_game.inputMode == INPUT_GETSTRING && !(shouldQuit() || _restartGame));
+		state->_vm->mainCycle();
+	} while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
 }
 
-void AgiEngine::cmd_get_num(uint8 *p) {
+void cmd_get_num(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "%d %d", p0, p1);
 
-	newInputMode(INPUT_GETSTRING);
+	state->_vm->newInputMode(INPUT_GETSTRING);
 
-	if (_curLogic->texts != NULL && _curLogic->numTexts >= (p0 - 1)) {
-		int len = strlen(_curLogic->texts[p0 - 1]);
+	if (state->_curLogic->texts != NULL && state->_curLogic->numTexts >= (p0 - 1)) {
+		int len = strlen(state->_curLogic->texts[p0 - 1]);
 
-		printText(_curLogic->texts[p0 - 1], 0, 0, 22, len, _game.colorFg, _game.colorBg);
-		getString(len - 1, 22, 3, MAX_STRINGS);
+		state->_vm->printText(state->_curLogic->texts[p0 - 1], 0, 0, 22, len, state->colorFg, state->colorBg);
+		state->_vm->getString(len - 1, 22, 3, MAX_STRINGS);
 
 		// CM: display input char
-		_gfx->printCharacter((p3 + len), 22, _game.cursorChar, _game.colorFg, _game.colorBg);
+		state->_vm->_gfx->printCharacter((p3 + len), 22, state->cursorChar, state->colorFg, state->colorBg);
 	}
 
 	do {
-		mainCycle();
-	} while (_game.inputMode == INPUT_GETSTRING && !(shouldQuit() || _restartGame));
+		state->_vm->mainCycle();
+	} while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
 
-	_v[p1] = atoi(_game.strings[MAX_STRINGS]);
+	_v[p1] = atoi(state->strings[MAX_STRINGS]);
 
-	debugC(4, kDebugLevelScripts, "[%s] -> %d", _game.strings[MAX_STRINGS], _v[p1]);
+	debugC(4, kDebugLevelScripts, "[%s] -> %d", state->strings[MAX_STRINGS], _v[p1]);
 
-	clearLines(22, 22, _game.colorBg);
-	flushLines(22, 22);
+	state->_vm->clearLines(22, 22, state->colorBg);
+	state->_vm->flushLines(22, 22);
 }
 
-void AgiEngine::cmd_set_cursor_char(uint8 *p) {
-	if (_curLogic->texts != NULL && (p0 - 1) <= _curLogic->numTexts) {
-		_game.cursorChar = *_curLogic->texts[p0 - 1];
+void cmd_set_cursor_char(AgiGame *state, uint8 *p) {
+	if (state->_curLogic->texts != NULL && (p0 - 1) <= state->_curLogic->numTexts) {
+		state->cursorChar = *state->_curLogic->texts[p0 - 1];
 	} else {
 		// default
-		_game.cursorChar = '_';
+		state->cursorChar = '_';
 	}
 }
 
-void AgiEngine::cmd_set_key(uint8 *p) {
+void cmd_set_key(AgiGame *state, uint8 *p) {
 	int key;
 
-	if (_game.lastController >= MAX_CONTROLLERS) {
+	if (state->lastController >= MAX_CONTROLLERS) {
 		warning("Number of set.keys exceeded %d", MAX_CONTROLLERS);
 		return;
 	}
@@ -1397,35 +1404,35 @@ void AgiEngine::cmd_set_key(uint8 *p) {
 
 	key = 256 * p1 + p0;
 
-	_game.controllers[_game.lastController].keycode = key;
-	_game.controllers[_game.lastController].controller = p2;
-	_game.lastController++;
+	state->controllers[state->lastController].keycode = key;
+	state->controllers[state->lastController].controller = p2;
+	state->lastController++;
 
-	_game.controllerOccured[p2] = false;
+	state->controllerOccured[p2] = false;
 }
 
-void AgiEngine::cmd_set_string(uint8 *p) {
+void cmd_set_string(AgiGame *state, uint8 *p) {
 	// CM: to avoid crash in Groza (str = 150)
 	if (p0 > MAX_STRINGS)
 		return;
-	strcpy(_game.strings[p0], _curLogic->texts[p1 - 1]);
+	strcpy(state->strings[p0], state->_curLogic->texts[p1 - 1]);
 }
 
-void AgiEngine::cmd_display(uint8 *p) {
+void cmd_display(AgiGame *state, uint8 *p) {
 	int len = 40;
 
-	char *s = wordWrapString(_curLogic->texts[p2 - 1], &len);
+	char *s = state->_vm->wordWrapString(state->_curLogic->texts[p2 - 1], &len);
 
-	printText(s, p1, 0, p0, 40, _game.colorFg, _game.colorBg);
+	state->_vm->printText(s, p1, 0, p0, 40, state->colorFg, state->colorBg);
 
 	free(s);
 }
 
-void AgiEngine::cmd_display_f(uint8 *p) {
-	printText(_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, _game.colorFg, _game.colorBg);
+void cmd_display_f(AgiGame *state, uint8 *p) {
+	state->_vm->printText(state->_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, state->colorFg, state->colorBg);
 }
 
-void AgiEngine::cmd_clear_text_rect(uint8 *p) {
+void cmd_clear_text_rect(AgiGame *state, uint8 *p) {
 	int c, x1, y1, x2, y2;
 
 	if ((c = p4) != 0)
@@ -1446,21 +1453,21 @@ void AgiEngine::cmd_clear_text_rect(uint8 *p) {
 	if (y2 > GFX_HEIGHT)
 		y2 = GFX_HEIGHT - 1;
 
-	_gfx->drawRectangle(x1, y1, x2, y2, c);
-	_gfx->flushBlock(x1, y1, x2, y2);
+	state->_vm->_gfx->drawRectangle(x1, y1, x2, y2, c);
+	state->_vm->_gfx->flushBlock(x1, y1, x2, y2);
 }
 
-void AgiEngine::cmd_toggle_monitor(uint8 *p) {
+void cmd_toggle_monitor(AgiGame *state, uint8 *p) {
 	debug(0, "toggle.monitor");
 }
 
-void AgiEngine::cmd_echo_line(uint8 *p) {
-	strcpy((char *)_game.inputBuffer, (const char *)_game.echoBuffer);
-	_game.cursorPos = strlen((char *)_game.inputBuffer);
-	_game.hasPrompt = 0;
+void cmd_echo_line(AgiGame *state, uint8 *p) {
+	strcpy((char *)state->inputBuffer, (const char *)state->echoBuffer);
+	state->cursorPos = strlen((char *)state->inputBuffer);
+	state->hasPrompt = 0;
 }
 
-void AgiEngine::cmd_clear_lines(uint8 *p) {
+void cmd_clear_lines(AgiGame *state, uint8 *p) {
 	uint8 l;
 
 	// Residence 44 calls clear.lines(24,0,0), see Sarien bug #558423
@@ -1470,42 +1477,42 @@ void AgiEngine::cmd_clear_lines(uint8 *p) {
 	// #1935838 and #1935842
 	l = (l <= 24) ? l : 24;
 
-	clearLines(p0, l, p2);
-	flushLines(p0, l);
+	state->_vm->clearLines(p0, l, p2);
+	state->_vm->flushLines(p0, l);
 }
 
-void AgiEngine::cmd_print(uint8 *p) {
+void cmd_print(AgiGame *state, uint8 *p) {
 	int n = p0 < 1 ? 1 : p0;
 
-	print(_curLogic->texts[n - 1], 0, 0, 0);
+	state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
 }
 
-void AgiEngine::cmd_print_f(uint8 *p) {
+void cmd_print_f(AgiGame *state, uint8 *p) {
 	int n = _v[p0] < 1 ? 1 : _v[p0];
 
-	print(_curLogic->texts[n - 1], 0, 0, 0);
+	state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
 }
 
-void AgiEngine::cmd_print_at(uint8 *p) {
+void cmd_print_at(AgiGame *state, uint8 *p) {
 	int n = p0 < 1 ? 1 : p0;
 
 	debugC(4, kDebugLevelScripts, "%d %d %d %d", p0, p1, p2, p3);
 
-	print(_curLogic->texts[n - 1], p1, p2, p3);
+	state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
 }
 
-void AgiEngine::cmd_print_at_v(uint8 *p) {
+void cmd_print_at_v(AgiGame *state, uint8 *p) {
 	int n = _v[p0] < 1 ? 1 : _v[p0];
 
-	print(_curLogic->texts[n - 1], p1, p2, p3);
+	state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
 }
 
-void AgiEngine::cmd_push_script(uint8 *p) {
+void cmd_push_script(AgiGame *state, uint8 *p) {
 	// We run AGIMOUSE always as a side effect
 	if (getFeatures() & GF_AGIMOUSE || true) {
-		_game.vars[27] = _mouse.button;
-		_game.vars[28] = _mouse.x / 2;
-		_game.vars[29] = _mouse.y;
+		state->vars[27] = state->_vm->_mouse.button;
+		state->vars[28] = state->_vm->_mouse.x / 2;
+		state->vars[29] = state->_vm->_mouse.y;
 	} else {
 		if (getVersion() >= 0x2915) {
 			debug(0, "push.script");
@@ -1513,35 +1520,35 @@ void AgiEngine::cmd_push_script(uint8 *p) {
 	}
 }
 
-void AgiEngine::cmd_set_pri_base(uint8 *p) {
+void cmd_set_pri_base(AgiGame *state, uint8 *p) {
 	int i, x, pri;
 
 	debug(0, "Priority base set to %d", p0);
 
-	// _game.alt_pri = true;
+	// state->alt_pri = true;
 	x = (_HEIGHT - p0) * _HEIGHT / 10;
 
 	for (i = 0; i < _HEIGHT; i++) {
 		pri = (i - p0) < 0 ? 4 : (i - p0) * _HEIGHT / x + 5;
 		if (pri > 15)
 			pri = 15;
-		_game.priTable[i] = pri;
+		state->priTable[i] = pri;
 	}
 }
 
-void AgiEngine::cmd_mouse_posn(uint8 *p) {
-	_v[p0] = WIN_TO_PIC_X(_mouse.x);
-	_v[p1] = WIN_TO_PIC_Y(_mouse.y);
+void cmd_mouse_posn(AgiGame *state, uint8 *p) {
+	_v[p0] = WIN_TO_PIC_X(state->_vm->_mouse.x);
+	_v[p1] = WIN_TO_PIC_Y(state->_vm->_mouse.y);
 }
 
-void AgiEngine::cmd_shake_screen(uint8 *p) {
+void cmd_shake_screen(AgiGame *state, uint8 *p) {
 	int i;
 
 	// AGIPAL uses shake.screen values between 100 and 109 to set the palette
 	// (Checked the original AGIPAL-hack's shake.screen-routine's disassembly).
 	if (p0 >= 100 && p0 < 110) {
 		if (getFeatures() & GF_AGIPAL) {
-			_gfx->setAGIPal(p0);
+			state->_vm->_gfx->setAGIPal(p0);
 			return;
 		} else {
 			warning("It looks like GF_AGIPAL flag is missing");
@@ -1550,242 +1557,21 @@ void AgiEngine::cmd_shake_screen(uint8 *p) {
 
 	// Disables input while shaking to prevent bug
 	// #1678230: AGI: Entering text while screen is shaking
-	bool originalValue = _game.inputEnabled;
-	_game.inputEnabled = false;
+	bool originalValue = state->inputEnabled;
+	state->inputEnabled = false;
 
-	_gfx->shakeStart();
+	state->_vm->_gfx->shakeStart();
 
-	_sprites->commitBoth();		// Fixes SQ1 demo
+	state->_vm->_sprites->commitBoth();		// Fixes SQ1 demo
 	for (i = 4 * p0; i; i--) {
-		_gfx->shakeScreen(i & 1);
-		_gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
-		mainCycle();
+		state->_vm->_gfx->shakeScreen(i & 1);
+		state->_vm->_gfx->flushBlock(0, 0, GFX_WIDTH - 1, GFX_HEIGHT - 1);
+		state->_vm->mainCycle();
 	}
-	_gfx->shakeEnd();
+	state->_vm->_gfx->shakeEnd();
 
 	// Sets input back to what it was
-	_game.inputEnabled = originalValue;
-}
-
-void AgiEngine::setupOpcodes() {
-	AgiCondCommand condTmp[] = {
-		&AgiEngine::cond_end,				// 00
-		&AgiEngine::cond_equal,				// 01
-		&AgiEngine::cond_equalv,			// 02
-		&AgiEngine::cond_less,				// 03
-		&AgiEngine::cond_lessv,				// 04
-		&AgiEngine::cond_greater,			// 05
-		&AgiEngine::cond_greaterv,			// 06
-		&AgiEngine::cond_isset,				// 07
-		&AgiEngine::cond_issetv,			// 08
-		&AgiEngine::cond_has,				// 09
-		&AgiEngine::cond_obj_in_room,		// 0A
-		&AgiEngine::cond_posn,				// 0B
-		&AgiEngine::cond_controller,		// 0C
-		&AgiEngine::cond_have_key,			// 0D
-		&AgiEngine::cond_said,				// 0E
-		&AgiEngine::cond_compare_strings,	// 0F
-		&AgiEngine::cond_obj_in_box,		// 10
-		&AgiEngine::cond_center_posn,		// 11
-		&AgiEngine::cond_right_posn,		// 12
-		&AgiEngine::cond_unknown_13			// 13
-	};
-	for (int i = 0; i < 256; ++i)
-		_agiCondCommands[i] = &AgiEngine::cond_unknown;
-	for (int i = 0; i < ARRAYSIZE(condTmp); ++i)
-		_agiCondCommands[i] = condTmp[i];
-	_agiCondCommands[0xFF] = &AgiEngine::cond_end;
-	_agiCondCommands[0xFD] = &AgiEngine::cond_not;
-	_agiCondCommands[0xFC] = &AgiEngine::cond_or;
-
-	AgiCommand tmp[] = {
-		NULL,			// 0x00
-		&AgiEngine::cmd_increment,
-		&AgiEngine::cmd_decrement,
-		&AgiEngine::cmd_assignn,
-		&AgiEngine::cmd_assignv,
-		&AgiEngine::cmd_addn,
-		&AgiEngine::cmd_addv,
-		&AgiEngine::cmd_subn,
-		&AgiEngine::cmd_subv,	// 0x08
-		&AgiEngine::cmd_lindirectv,
-		&AgiEngine::cmd_rindirect,
-		&AgiEngine::cmd_lindirectn,
-		&AgiEngine::cmd_set,
-		&AgiEngine::cmd_reset,
-		&AgiEngine::cmd_toggle,
-		&AgiEngine::cmd_set_v,
-		&AgiEngine::cmd_reset_v,	// 0x10
-		&AgiEngine::cmd_toggle_v,
-		&AgiEngine::cmd_new_room,
-		&AgiEngine::cmd_new_room_f,
-		&AgiEngine::cmd_load_logic,
-		&AgiEngine::cmd_load_logic_f,
-		&AgiEngine::cmd_call,
-		&AgiEngine::cmd_call_f,
-		&AgiEngine::cmd_load_pic,	// 0x18
-		&AgiEngine::cmd_draw_pic,
-		&AgiEngine::cmd_show_pic,
-		&AgiEngine::cmd_discard_pic,
-		&AgiEngine::cmd_overlay_pic,
-		&AgiEngine::cmd_show_pri_screen,
-		&AgiEngine::cmd_load_view,
-		&AgiEngine::cmd_load_view_f,
-		&AgiEngine::cmd_discard_view,	// 0x20
-		&AgiEngine::cmd_animate_obj,
-		&AgiEngine::cmd_unanimate_all,
-		&AgiEngine::cmd_draw,
-		&AgiEngine::cmd_erase,
-		&AgiEngine::cmd_position,
-		&AgiEngine::cmd_position_f,
-		&AgiEngine::cmd_get_posn,
-		&AgiEngine::cmd_reposition,	// 0x28
-		&AgiEngine::cmd_set_view,
-		&AgiEngine::cmd_set_view_f,
-		&AgiEngine::cmd_set_loop,
-		&AgiEngine::cmd_set_loop_f,
-		&AgiEngine::cmd_fix_loop,
-		&AgiEngine::cmd_release_loop,
-		&AgiEngine::cmd_set_cel,
-		&AgiEngine::cmd_set_cel_f,	// 0x30
-		&AgiEngine::cmd_last_cel,
-		&AgiEngine::cmd_current_cel,
-		&AgiEngine::cmd_current_loop,
-		&AgiEngine::cmd_current_view,
-		&AgiEngine::cmd_number_of_loops,
-		&AgiEngine::cmd_set_priority,
-		&AgiEngine::cmd_set_priority_f,
-		&AgiEngine::cmd_release_priority,	// 0x38
-		&AgiEngine::cmd_get_priority,
-		&AgiEngine::cmd_stop_update,
-		&AgiEngine::cmd_start_update,
-		&AgiEngine::cmd_force_update,
-		&AgiEngine::cmd_ignore_horizon,
-		&AgiEngine::cmd_observe_horizon,
-		&AgiEngine::cmd_set_horizon,
-		&AgiEngine::cmd_object_on_water,	// 0x40
-		&AgiEngine::cmd_object_on_land,
-		&AgiEngine::cmd_object_on_anything,
-		&AgiEngine::cmd_ignore_objs,
-		&AgiEngine::cmd_observe_objs,
-		&AgiEngine::cmd_distance,
-		&AgiEngine::cmd_stop_cycling,
-		&AgiEngine::cmd_start_cycling,
-		&AgiEngine::cmd_normal_cycle,	// 0x48
-		&AgiEngine::cmd_end_of_loop,
-		&AgiEngine::cmd_reverse_cycle,
-		&AgiEngine::cmd_reverse_loop,
-		&AgiEngine::cmd_cycle_time,
-		&AgiEngine::cmd_stop_motion,
-		&AgiEngine::cmd_start_motion,
-		&AgiEngine::cmd_step_size,
-		&AgiEngine::cmd_step_time,	// 0x50
-		&AgiEngine::cmd_move_obj,
-		&AgiEngine::cmd_move_obj_f,
-		&AgiEngine::cmd_follow_ego,
-		&AgiEngine::cmd_wander,
-		&AgiEngine::cmd_normal_motion,
-		&AgiEngine::cmd_set_dir,
-		&AgiEngine::cmd_get_dir,
-		&AgiEngine::cmd_ignore_blocks,	// 0x58
-		&AgiEngine::cmd_observe_blocks,
-		&AgiEngine::cmd_block,
-		&AgiEngine::cmd_unblock,
-		&AgiEngine::cmd_get,
-		&AgiEngine::cmd_get_f,
-		&AgiEngine::cmd_drop,
-		&AgiEngine::cmd_put,
-		&AgiEngine::cmd_put_f,	// 0x60
-		&AgiEngine::cmd_get_room_f,
-		&AgiEngine::cmd_load_sound,
-		&AgiEngine::cmd_sound,
-		&AgiEngine::cmd_stop_sound,
-		&AgiEngine::cmd_print,
-		&AgiEngine::cmd_print_f,
-		&AgiEngine::cmd_display,
-		&AgiEngine::cmd_display_f,	// 0x68
-		&AgiEngine::cmd_clear_lines,
-		&AgiEngine::cmd_text_screen,
-		&AgiEngine::cmd_graphics,
-		&AgiEngine::cmd_set_cursor_char,
-		&AgiEngine::cmd_set_text_attribute,
-		&AgiEngine::cmd_shake_screen,
-		&AgiEngine::cmd_configure_screen,
-		&AgiEngine::cmd_status_line_on,	// 0x70
-		&AgiEngine::cmd_status_line_off,
-		&AgiEngine::cmd_set_string,
-		&AgiEngine::cmd_get_string,
-		&AgiEngine::cmd_word_to_string,
-		&AgiEngine::cmd_parse,
-		&AgiEngine::cmd_get_num,
-		&AgiEngine::cmd_prevent_input,
-		&AgiEngine::cmd_accept_input,	// 0x78
-		&AgiEngine::cmd_set_key,
-		&AgiEngine::cmd_add_to_pic,
-		&AgiEngine::cmd_add_to_pic_f,
-		&AgiEngine::cmd_status,
-		&AgiEngine::cmd_save_game,
-		&AgiEngine::cmd_load_game,
-		&AgiEngine::cmd_init_disk,
-		&AgiEngine::cmd_restart_game,	// 0x80
-		&AgiEngine::cmd_show_obj,
-		&AgiEngine::cmd_random,
-		&AgiEngine::cmd_program_control,
-		&AgiEngine::cmd_player_control,
-		&AgiEngine::cmd_obj_status_f,
-		&AgiEngine::cmd_quit,
-		&AgiEngine::cmd_show_mem,
-		&AgiEngine::cmd_pause,	// 0x88
-		&AgiEngine::cmd_echo_line,
-		&AgiEngine::cmd_cancel_line,
-		&AgiEngine::cmd_init_joy,
-		&AgiEngine::cmd_toggle_monitor,
-		&AgiEngine::cmd_version,
-		&AgiEngine::cmd_script_size,
-		&AgiEngine::cmd_set_game_id,
-		&AgiEngine::cmd_log,	// 0x90
-		&AgiEngine::cmd_set_scan_start,
-		&AgiEngine::cmd_reset_scan_start,
-		&AgiEngine::cmd_reposition_to,
-		&AgiEngine::cmd_reposition_to_f,
-		&AgiEngine::cmd_trace_on,
-		&AgiEngine::cmd_trace_info,
-		&AgiEngine::cmd_print_at,
-		&AgiEngine::cmd_print_at_v,	// 0x98
-		&AgiEngine::cmd_discard_view,	// Opcode repeated from 0x20 ?
-		&AgiEngine::cmd_clear_text_rect,
-		&AgiEngine::cmd_set_upper_left,
-		&AgiEngine::cmd_set_menu,
-		&AgiEngine::cmd_set_menu_item,
-		&AgiEngine::cmd_submit_menu,
-		&AgiEngine::cmd_enable_item,
-		&AgiEngine::cmd_disable_item,	// 0xa0
-		&AgiEngine::cmd_menu_input,
-		&AgiEngine::cmd_show_obj_v,
-		&AgiEngine::cmd_open_dialogue,
-		&AgiEngine::cmd_close_dialogue,
-		&AgiEngine::cmd_mul_n,
-		&AgiEngine::cmd_mul_v,
-		&AgiEngine::cmd_div_n,
-		&AgiEngine::cmd_div_v,	// 0xa8
-		&AgiEngine::cmd_close_window,
-		&AgiEngine::cmd_set_simple,
-		&AgiEngine::cmd_push_script,
-		&AgiEngine::cmd_pop_script,
-		&AgiEngine::cmd_hold_key,
-		&AgiEngine::cmd_set_pri_base,
-		&AgiEngine::cmd_discard_sound,
-		&AgiEngine::cmd_hide_mouse,	// 0xb0
-		&AgiEngine::cmd_allow_menu,
-		&AgiEngine::cmd_show_mouse,
-		&AgiEngine::cmd_fence_mouse,
-		&AgiEngine::cmd_mouse_posn,
-		&AgiEngine::cmd_release_key,
-		&AgiEngine::cmd_adj_ego_move_to_x_y
-	};
-	assert(ARRAYSIZE(_agiCommands) == ARRAYSIZE(tmp));
-	for (int i = 0; i < ARRAYSIZE(tmp); ++i)
-		_agiCommands[i] = tmp[i];
+	state->inputEnabled = originalValue;
 }
 
 /**
@@ -1798,6 +1584,7 @@ int AgiEngine::runLogic(int n) {
 	uint8 *code = NULL;
 	int num = 0;
 	ScriptPos sp;
+	AgiGame *state = &_game;
 
 	debugC(2, kDebugLevelScripts, "=================");
 	debugC(2, kDebugLevelScripts, "runLogic(%d)", n);
@@ -1813,10 +1600,10 @@ int AgiEngine::runLogic(int n) {
 	}
 
 	_game.lognum = n;
-	_curLogic = &_game.logics[_game.lognum];
+	_game._curLogic = &_game.logics[_game.lognum];
 
-	code = _curLogic->data;
-	_curLogic->cIP = _curLogic->sIP;
+	code = _game._curLogic->data;
+	_game._curLogic->cIP = _game._curLogic->sIP;
 
 	_timerHack = 0;
 	while (ip < _game.logics[n].size && !(shouldQuit() || _restartGame)) {
@@ -1866,13 +1653,14 @@ int AgiEngine::runLogic(int n) {
 			_game.execStack.pop_back();
 			return 1;
 		default:
-			num = logicNamesCmd[op].numArgs;
+			num = logicNamesCmd[op].argumentsLength();
 			memmove(p, code + ip, num);
 			memset(p + num, 0, CMD_BSIZE - num);
 
 			debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]);
 
-			(this->*_agiCommands[op])(p);
+//			(this->*_agiCommands[op])(&_game, p);
+			_agiCommands[op](&_game, p);
 			ip += num;
 		}
 
@@ -1888,7 +1676,8 @@ int AgiEngine::runLogic(int n) {
 void AgiEngine::executeAgiCommand(uint8 op, uint8 *p) {
 	debugC(2, kDebugLevelScripts, "%s(%d %d %d)", logicNamesCmd[op].name, p[0], p[1], p[2]);
 
-	(this->*_agiCommands[op])(p);
+	_agiCommands[op](&_game, p);
+//	(this->*_agiCommands[op])(p);
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/op_dbg.cpp b/engines/agi/op_dbg.cpp
index be73dbe..87e235c 100644
--- a/engines/agi/op_dbg.cpp
+++ b/engines/agi/op_dbg.cpp
@@ -28,248 +28,17 @@ namespace Agi {
 #define ip	(_game.logics[lognum].cIP)
 #define code	(_game.logics[lognum].data)
 
-#ifdef _L
-#undef _L
-#endif
-
-#define _L(a,b,c) { a, b, c }
-
-struct AgiLogicnames logicNamesTest[] = {
-	_L("", 0, 0x00),
-	_L("equaln", 2, 0x80),
-	_L("equalv", 2, 0xC0),
-	_L("lessn", 2, 0x80),
-	_L("lessv", 2, 0xC0),
-	_L("greatern", 2, 0x80),
-	_L("greaterv", 2, 0xC0),
-	_L("isset", 1, 0x00),
-	_L("issetv", 1, 0x80),
-	_L("has", 1, 0x00),
-	_L("obj.in.room", 2, 0x40),
-	_L("posn", 5, 0x00),
-	_L("controller", 1, 0x00),
-	_L("have.key", 0, 0x00),
-
-	// Not 0 args. Has variable number.
-	_L("said", 0, 0x00),
-
-	_L("compare.strings", 2, 0x00),
-	_L("obj.in.box", 5, 0x00),
-	_L("center.posn", 5, 0x00),
-	_L("right.posn", 5, 0x00),
-
-	// Haven't seen an official name for this command so tried to name it descriptively.
-	_L("in.motion.using.mouse", 0, 0x00)
-};
-
-struct AgiLogicnames logicNamesIf[] = {
-	_L("OR", 0, 0x00),
-	_L("NOT", 0, 0x00),
-	_L("ELSE", 0, 0x00),
-	_L("IF", 0, 0x00)
-};
-
-struct AgiLogicnames logicNamesCmd[] = {
-	_L("return", 0, 0x00),	// 00
-	_L("increment", 1, 0x80),	// 01
-	_L("decrement", 1, 0x80),	// 02
-	_L("assignn", 2, 0x80),	// 03
-	_L("assignv", 2, 0xC0),	// 04
-	_L("addn", 2, 0x80),	// 05
-	_L("addv", 2, 0xC0),	// 06
-	_L("subn", 2, 0x80),	// 07
-	_L("subv", 2, 0xC0),	// 08
-	_L("lindirectv", 2, 0xC0),	// 09
-	_L("rindirect", 2, 0xC0),	// 0A
-	_L("lindirectn", 2, 0x80),	// 0B
-	_L("set", 1, 0x00),	// 0C
-	_L("reset", 1, 0x00),	// 0D
-	_L("toggle", 1, 0x00),	// 0E
-	_L("set.v", 1, 0x80),	// 0F
-	_L("reset.v", 1, 0x80),	// 10
-	_L("toggle.v", 1, 0x80),	// 11
-	_L("new.room", 1, 0x00),	// 12
-	_L("new.room.v", 1, 0x80),	// 13
-	_L("load.logics", 1, 0x00),	// 14
-	_L("load.logics.v", 1, 0x80),	// 15
-	_L("call", 1, 0x00),	// 16
-	_L("call.v", 1, 0x80),	// 17
-	_L("load.pic", 1, 0x80),	// 18
-	_L("draw.pic", 1, 0x80),	// 19
-	_L("show.pic", 0, 0x00),	// 1A
-	_L("discard.pic", 1, 0x80),	// 1B
-	_L("overlay.pic", 1, 0x80),	// 1C
-	_L("show.pri.screen", 0, 0x00),	// 1D
-	_L("load.view", 1, 0x00),	// 1E
-	_L("load.view.v", 1, 0x80),	// 1F
-	_L("discard.view", 1, 0x00),	// 20
-	_L("animate.obj", 1, 0x00),	// 21
-	_L("unanimate.all", 0, 0x00),	// 22
-	_L("draw", 1, 0x00),	// 23
-	_L("erase", 1, 0x00),	// 24
-	_L("position", 3, 0x00),	// 25
-	_L("position.v", 3, 0x60),	// 26
-	_L("get.posn", 3, 0x60),	// 27
-	_L("reposition", 3, 0x60),	// 28
-	_L("set.view", 2, 0x00),	// 29
-	_L("set.view.v", 2, 0x40),	// 2A
-	_L("set.loop", 2, 0x00),	// 2B
-	_L("set.loop.v", 2, 0x40),	// 2C
-	_L("fix.loop", 1, 0x00),	// 2D
-	_L("release.loop", 1, 0x00),	// 2E
-	_L("set.cel", 2, 0x00),	// 2F
-	_L("set.cel.v", 2, 0x40),	// 30
-	_L("last.cel", 2, 0x40),	// 31
-	_L("current.cel", 2, 0x40),	// 32
-	_L("current.loop", 2, 0x40),	// 33
-	_L("current.view", 2, 0x40),	// 34
-	_L("number.of.loops", 2, 0x40),	// 35
-	_L("set.priority", 2, 0x00),	// 36
-	_L("set.priority.v", 2, 0x40),	// 37
-	_L("release.priority", 1, 0x00),	// 38
-	_L("get.priority", 2, 0x40),	// 39
-	_L("stop.update", 1, 0x00),	// 3A
-	_L("start.update", 1, 0x00),	// 3B
-	_L("force.update", 1, 0x00),	// 3C
-	_L("ignore.horizon", 1, 0x00),	// 3D
-	_L("observe.horizon", 1, 0x00),	// 3E
-	_L("set.horizon", 1, 0x00),	// 3F
-	_L("object.on.water", 1, 0x00),	// 40
-	_L("object.on.land", 1, 0x00),	// 41
-	_L("object.on.anything", 1, 0x00),	// 42
-	_L("ignore.objs", 1, 0x00),	// 43
-	_L("observe.objs", 1, 0x00),	// 44
-	_L("distance", 3, 0x20),	// 45
-	_L("stop.cycling", 1, 0x00),	// 46
-	_L("start.cycling", 1, 0x00),	// 47
-	_L("normal.cycle", 1, 0x00),	// 48
-	_L("end.of.loop", 2, 0x00),	// 49
-	_L("reverse.cycle", 1, 0x00),	// 4A
-	_L("reverse.loop", 2, 0x00),	// 4B
-	_L("cycle.time", 2, 0x40),	// 4C
-	_L("stop.motion", 1, 0x00),	// 4D
-	_L("start.motion", 1, 0x00),	// 4E
-	_L("step.size", 2, 0x40),	// 4F
-	_L("step.time", 2, 0x40),	// 50
-	_L("move.obj", 5, 0x00),	// 51
-	_L("move.obj.v", 5, 0x70),	// 52
-	_L("follow.ego", 3, 0x00),	// 53
-	_L("wander", 1, 0x00),	// 54
-	_L("normal.motion", 1, 0x00),	// 55
-	_L("set.dir", 2, 0x40),	// 56
-	_L("get.dir", 2, 0x40),	// 57
-	_L("ignore.blocks", 1, 0x00),	// 58
-	_L("observe.blocks", 1, 0x00),	// 59
-	_L("block", 4, 0x00),	// 5A
-	_L("unblock", 0, 0x00),	// 5B
-	_L("get", 1, 0x00),	// 5C
-	_L("get.v", 1, 0x80),	// 5D
-	_L("drop", 1, 0x00),	// 5E
-	_L("put", 2, 0x00),	// 5F
-	_L("put.v", 2, 0x40),	// 60
-	_L("get.room.v", 2, 0xC0),	// 61
-	_L("load.sound", 1, 0x00),	// 62
-	_L("sound", 2, 0x00),	// 63
-	_L("stop.sound", 0, 0x00),	// 64
-	_L("print", 1, 0x00),	// 65
-	_L("print.v", 1, 0x80),	// 66
-	_L("display", 3, 0x00),	// 67
-	_L("display.v", 3, 0xE0),	// 68
-	_L("clear.lines", 3, 0x00),	// 69
-	_L("text.screen", 0, 0x00),	// 6A
-	_L("graphics", 0, 0x00),	// 6B
-	_L("set.cursor.char", 1, 0x00),	// 6C
-	_L("set.text.attribute", 2, 0x00),	// 6D
-	_L("shake.screen", 1, 0x00),	// 6E
-	_L("configure.screen", 3, 0x00),	// 6F
-	_L("status.line.on", 0, 0x00),	// 70
-	_L("status.line.off", 0, 0x00),	// 71
-	_L("set.string", 2, 0x00),	// 72
-	_L("get.string", 5, 0x00),	// 73
-	_L("word.to.string", 2, 0x00),	// 74
-	_L("parse", 1, 0x00),	// 75
-	_L("get.num", 2, 0x40),	// 76
-	_L("prevent.input", 0, 0x00),	// 77
-	_L("accept.input", 0, 0x00),	// 78
-	_L("set.key", 3, 0x00),	// 79
-	_L("add.to.pic", 7, 0x00),	// 7A
-	_L("add.to.pic.v", 7, 0xFE),	// 7B
-	_L("status", 0, 0x00),	// 7C
-	_L("save.game", 0, 0x00),	// 7D
-	_L("restore.game", 0, 0x00),	// 7E
-	_L("init.disk", 0, 0x00),	// 7F
-	_L("restart.game", 0, 0x00),	// 80
-	_L("show.obj", 1, 0x00),	// 81
-	_L("random", 3, 0x20),	// 82
-	_L("program.control", 0, 0x00),	// 83
-	_L("player.control", 0, 0x00),	// 84
-	_L("obj.status.v", 1, 0x80),	// 85
-	// 0 args for AGI version 2.089
-	_L("quit", 1, 0x00),	// 86
-
-	_L("show.mem", 0, 0x00),	// 87
-	_L("pause", 0, 0x00),	// 88
-	_L("echo.line", 0, 0x00),	// 89
-	_L("cancel.line", 0, 0x00),	// 8A
-	_L("init.joy", 0, 0x00),	// 8B
-	_L("toggle.monitor", 0, 0x00),	// 8C
-	_L("version", 0, 0x00),	// 8D
-	_L("script.size", 1, 0x00),	// 8E
-	_L("set.game.id", 1, 0x00),	// 8F
-	_L("log", 1, 0x00),	// 90
-	_L("set.scan.start", 0, 0x00),	// 91
-	_L("reset.scan.start", 0, 0x00),	// 92
-	_L("reposition.to", 3, 0x00),	// 93
-	_L("reposition.to.v", 3, 0x60),	// 94
-	_L("trace.on", 0, 0x00),	// 95
-	_L("trace.info", 3, 0x00),	// 96
-
-	// 3 args for AGI versions before 2.440
-	_L("print.at", 4, 0x00),	// 97
-	_L("print.at.v", 4, 0x80),	// 98
-
-	_L("discard.view.v", 1, 0x80),	// 99
-	_L("clear.text.rect", 5, 0x00),	// 9A
-	_L("set.upper.left", 2, 0x00),	// 9B
-	_L("set.menu", 1, 0x00),	// 9C
-	_L("set.menu.item", 2, 0x00),	// 9D
-	_L("submit.menu", 0, 0x00),	// 9E
-	_L("enable.item", 1, 0x00),	// 9F
-	_L("disable.item", 1, 0x00),	// A0
-	_L("menu.input", 0, 0x00),	// A1
-	_L("show.obj.v", 1, 0x01),	// A2
-	_L("open.dialogue", 0, 0x00),	// A3
-	_L("close.dialogue", 0, 0x00),	// A4
-	_L("mul.n", 2, 0x80),	// A5
-	_L("mul.v", 2, 0xC0),	// A6
-	_L("div.n", 2, 0x80),	// A7
-	_L("div.v", 2, 0xC0),	// A8
-	_L("close.window", 0, 0x00),	// A9
-
-	_L("set.simple", 1, 0x00),	// AA
-	_L("push.script", 0, 0x00),	// AB
-	_L("pop.script", 0, 0x00),	// AC
-	_L("hold.key", 0, 0x00),	// AD
-	_L("set.pri.base", 1, 0x00),	// AE
-	_L("discard.sound", 1, 0x00),	// AF
-
-	// 1 arg for AGI version 3.002.086
-	_L("hide.mouse", 0, 0x00),	// B0
-
-	_L("allow.menu", 1, 0x00),	// B1
-	_L("show.mouse", 0, 0x00),	// B2
-	_L("fence.mouse", 4, 0x00),	// B3
-	_L("mouse.posn", 2, 0x00),	// B4
-	_L("release.key", 0, 0x00),	// B5
-
-	// 2 args for at least the Amiga Gold Rush! (v2.05 1989-03-09) using Amiga AGI 2.316.
-	_L("adj.ego.move.to.xy", 0, 0x00),	// B6
-	_L(NULL, 0, 0x00)
+AgiInstruction logicNamesIf[] = {
+    { "OR", "", NULL },
+    { "NOT", "", NULL },
+    { "ELSE", "", NULL },
+    { "IF", "", NULL }
 };
 
 void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
-	AgiLogicnames *x;
-	uint8 a, c, z;
+	AgiInstruction *x;
+	uint8 a, z;
+	const char *c;
 
 	if (str) {
 		debug(0, "         %s", str);
@@ -302,8 +71,8 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
 		break;
 	default:
 		x = mode == lCOMMAND_MODE ? logicNamesCmd : logicNamesTest;
-		a = (unsigned char)(x + *(code + ip))->numArgs;
-		c = (unsigned char)(x + *(code + ip))->argMask;
+		a = x[*(code + ip)].argumentsLength();
+		c = x[*(code + ip)].args;
 
 		if (_debug.opcodes) {
 			debugN(0, "%02X %02X %02X %02X %02X %02X %02X %02X %02X\n"
@@ -321,12 +90,12 @@ void AgiEngine::debugConsole(int lognum, int mode, const char *str) {
 		debugN(0, "%s ", (x + *(code + ip))->name);
 
 		for (z = 1; a > 0;) {
-			if (~c & 0x80) {
+			if (*c == 'n') {
 				debugN(0, "%d", *(code + (ip + z)));
 			} else {
 				debugN(0, "v%d[%d]", *(code + (ip + z)), getvar(*(code + (ip + z))));
 			}
-			c <<= 1;
+			c++;
 			z++;
 			if (--a > 0)
 				debugN(0, ",");
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 24dd397..0054fad 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -26,158 +26,158 @@
 
 namespace Agi {
 
-#define ip (_curLogic->cIP)
-#define code (_curLogic->data)
+#define ip (state->_curLogic->cIP)
+#define code (state->_curLogic->data)
+
+#define getvar(a) state->_vm->getvar(a)
+#define getflag(a) state->_vm->getflag(a)
 
 #define testEqual(v1, v2)		(getvar(v1) == (v2))
 #define testLess(v1, v2)		(getvar(v1) < (v2))
 #define testGreater(v1, v2)	(getvar(v1) > (v2))
 #define testIsSet(flag)		(getflag(flag))
-#define testHas(obj)			(objectGetLocation(obj) == EGO_OWNED)
-#define testObjInRoom(obj, v)	(objectGetLocation(obj) == getvar(v))
+#define testHas(obj)			(state->_vm->objectGetLocation(obj) == EGO_OWNED)
+#define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getvar(v))
 
-int AgiEngine::cond_end(uint8 *p) {
-	_endTest = true;
-	return true;
+void cond_end(AgiGame *state, uint8 *p) {
+	state->endTest = true;
+	state->ec = true;
 }
 
-int AgiEngine::cond_equal(uint8 *p) {
+void cond_equal(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testEqual(p[0], p[1]);
+	state->ec = testEqual(p[0], p[1]);
 }
 
-int AgiEngine::cond_equalv(uint8 *p) {
+void cond_equalv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testEqual(p[0], getvar(p[1]));
+	state->ec = testEqual(p[0], getvar(p[1]));
 }
 
-int AgiEngine::cond_less(uint8 *p) {
+void cond_less(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testLess(p[0], p[1]);
+	state->ec = testLess(p[0], p[1]);
 }
 
-int AgiEngine::cond_lessv(uint8 *p) {
+void cond_lessv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testLess(p[0], getvar(p[1]));
+	state->ec = testLess(p[0], getvar(p[1]));
 }
 
-int AgiEngine::cond_greater(uint8 *p) {
+void cond_greater(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testGreater(p[0], p[1]);
+	state->ec = testGreater(p[0], p[1]);
 }
 
-int AgiEngine::cond_greaterv(uint8 *p) {
+void cond_greaterv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
-		_timerHack++;
+		state->_vm->_timerHack++;
 	ip += 2;
-	return testGreater(p[0], getvar(p[1]));
+	state->ec = testGreater(p[0], getvar(p[1]));
 }
 
-int AgiEngine::cond_isset(uint8 *p) {
+void cond_isset(AgiGame *state, uint8 *p) {
 	ip += 1;
-	return testIsSet(p[0]);
+	state->ec = testIsSet(p[0]);
 }
 
-int AgiEngine::cond_issetv(uint8 *p) {
+void cond_issetv(AgiGame *state, uint8 *p) {
 	ip += 1;
-	return testIsSet(getvar(p[1]));
+	state->ec = testIsSet(getvar(p[1]));
 }
 
-int AgiEngine::cond_has(uint8 *p) {
+void cond_has(AgiGame *state, uint8 *p) {
 	ip += 1;
-	return testHas(p[0]);
+	state->ec = testHas(p[0]);
 }
 
-int AgiEngine::cond_obj_in_room(uint8 *p) {
+void cond_obj_in_room(AgiGame *state, uint8 *p) {
 	ip += 2;
-	return testObjInRoom(p[0], p[1]);
+	state->ec = testObjInRoom(p[0], p[1]);
 }
 
-int AgiEngine::cond_posn(uint8 *p) {
+void cond_posn(AgiGame *state, uint8 *p) {
 	ip += 5;
-	return testPosn(p[0], p[1], p[2], p[3], p[4]);
+	state->ec = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
 }
 
-int AgiEngine::cond_controller(uint8 *p) {
+void cond_controller(AgiGame *state, uint8 *p) {
 	ip += 1;
-	return testController(p[0]);
+	state->ec = state->_vm->testController(p[0]);
 }
 
-int AgiEngine::cond_have_key(uint8 *p) {
-	return testKeypressed();
+void cond_have_key(AgiGame *state, uint8 *p) {
+	state->ec = state->_vm->testKeypressed();
 }
 
-int AgiEngine::cond_said(uint8 *p) {
-	int ec = testSaid(p[0], p + 1);
+void cond_said(AgiGame *state, uint8 *p) {
+	int ec = state->_vm->testSaid(p[0], p + 1);
 	ip += p[0] * 2;	// skip num_words * 2
 	ip++;	// skip num_words opcode
-	return ec;
+	state->ec = ec;
 }
 
-int AgiEngine::cond_compare_strings(uint8 *p) {
-	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", _game.strings[p[0]], _game.strings[p[1]]);
+void cond_compare_strings(AgiGame *state, uint8 *p) {
+	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
 	ip += 2;
-	return testCompareStrings(p[0], p[1]);
+	state->ec = state->_vm->testCompareStrings(p[0], p[1]);
 }
 
-int AgiEngine::cond_obj_in_box(uint8 *p) {
+void cond_obj_in_box(AgiGame *state, uint8 *p) {
 	ip += 5;
-	return testObjInBox(p[0], p[1], p[2], p[3], p[4]);
+	state->ec = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
 }
 
-int AgiEngine::cond_center_posn(uint8 *p) {
+void cond_center_posn(AgiGame *state, uint8 *p) {
 	ip += 5;
-	return testObjCenter(p[0], p[1], p[2], p[3], p[4]);
+	state->ec = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
 }
 
-int AgiEngine::cond_right_posn(uint8 *p) {
+void cond_right_posn(AgiGame *state, uint8 *p) {
 	ip += 5;
-	return testObjRight(p[0], p[1], p[2], p[3], p[4]);
+	state->ec = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
 }
 
-int AgiEngine::cond_unknown_13(uint8 *p) {
+void cond_unknown_13(AgiGame *state, uint8 *p) {
 	// My current theory is that this command checks whether the ego is currently moving
 	// and that that movement has been caused using the mouse and not using the keyboard.
 	// I base this theory on the game's behavior on an Amiga emulator, not on disassembly.
 	// This command is used at least in the Amiga version of Gold Rush! v2.05 1989-03-09
 	// (AGI 2.316) in logics 1, 3, 5, 6, 137 and 192 (Logic.192 revealed this command's nature).
 	// TODO: Check this command's implementation using disassembly just to be sure.
-	int ec = _game.viewTable[0].flags & ADJ_EGO_XY;
+	int ec = state->viewTable[0].flags & ADJ_EGO_XY;
 	debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false");
-	return ec;
+	state->ec = ec;
 }
 
-int AgiEngine::cond_unknown(uint8 *p) {
-	_endTest = true;
-	return false;
+void cond_unknown(AgiGame *state, uint8 *p) {
+	state->endTest = true;
 }
 
-int AgiEngine::cond_not(uint8 *p) {
-	_notTest = !_notTest;
-	return false;
+void cond_not(AgiGame *state, uint8 *p) {
+	state->notTest = !state->notTest;
 }
 
-int AgiEngine::cond_or(uint8 *p) {
+void cond_or(AgiGame *state, uint8 *p) {
 	// if or_test is ON and we hit 0xFC, end of OR, then
 	// or is STILL false so break.
-	if (_orTest) {
-		_orTest = false;
-		_testVal &= _orVal;
+	if (state->orTest) {
+		state->orTest = false;
+		state->testVal &= state->orVal;
 	} else {
-		_orTest = true;
-		_orVal = false;
+		state->orTest = true;
+		state->orVal = false;
 	}
-	return true;
 }
 
 uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
@@ -291,6 +291,7 @@ uint8 AgiEngine::testObjRight(uint8 n, uint8 x1, uint8 y1, uint8 x2, uint8 y2) {
 
 // When player has entered something, it is parsed elsewhere
 uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
+	AgiGame *state = &_game;
 	int c, n = _game.numEgoWords;
 	int z = 0;
 
@@ -346,17 +347,18 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 }
 
 int AgiEngine::testIfCode(int lognum) {
-	int ec = true;
+	AgiGame *state = &_game;
 	uint8 op = 0;
 	uint16 lastIp = ip;
 	uint8 p[16] = { 0 };
 
-	_notTest = false;
-	_orTest = false;
-	_endTest = false;
-	_testVal = true;
+	state->ec = true;
+	state->notTest = false;
+	state->orTest = false;
+	state->endTest = false;
+	state->testVal = true;
 
-	while (!(shouldQuit() || _restartGame) && !_endTest) {
+	while (!(shouldQuit() || _restartGame) && !state->endTest) {
 		if (_debug.enabled && (_debug.logic0 || lognum))
 			debugConsole(lognum, lTEST_MODE, NULL);
 
@@ -364,32 +366,32 @@ int AgiEngine::testIfCode(int lognum) {
 		op = *(code + ip++);
 		memmove(p, (code + ip), 16);
 
-		ec = (this->*_agiCondCommands[op])(p);
+		_agiCondCommands[op](state, p);
 		if (op == 0xFF || op == 0xFD || op == 0xFC)
 			continue;
 
 		// not is only enabled for 1 test command
-		if (_notTest)
-			ec = !ec;
-		_notTest = false;
+		if (state->notTest)
+			state->ec = !state->ec;
+		state->notTest = false;
 
-		if (_orTest)
-			_orVal |= ec;
+		if (state->orTest)
+			state->orVal |= state->ec;
 		else
-			_testVal &= ec;
+			state->testVal &= state->ec;
 	}
 
 	// Execute the following IF block if the condition is true, otherwise
 	// skip the block.
-	if (_testVal)
+	if (state->testVal)
 		ip += 2;
 	else
 		ip += READ_LE_UINT16(code + ip) + 2;
 
 	if (_debug.enabled && (_debug.logic0 || lognum))
-		debugConsole(lognum, 0xFF, _testVal ? "=true" : "=false");
+		debugConsole(lognum, 0xFF, state->testVal ? "=true" : "=false");
 
-	return _testVal;
+	return state->testVal;
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
new file mode 100644
index 0000000..aef7684
--- /dev/null
+++ b/engines/agi/opcodes.cpp
@@ -0,0 +1,250 @@
+/* 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.
+ *
+ */
+
+#include "agi/agi.h"
+#include "agi/opcodes.h"
+
+namespace Agi {
+
+AgiInstruction logicNamesTest[] = {
+	{ "",					"",			&cond_end },				// 00
+	{ "equaln",				"vn",		&cond_equal },				// 01
+	{ "equalv",				"vv",		&cond_equalv },				// 02
+	{ "lessn",				"vn",		&cond_less },				// 03
+	{ "lessv",				"vv",		&cond_lessv },				// 04
+	{ "greatern",			"vn",		&cond_greater },			// 05
+	{ "greaterv",			"vv",		&cond_greaterv },			// 06
+	{ "isset",				"n",		&cond_isset },				// 07
+	{ "issetv",				"v",		&cond_issetv },				// 08
+	{ "has",				"n",		&cond_has },				// 09
+	{ "obj.in.room",		"nv",		&cond_obj_in_room},			// 0A
+	{ "posn",				"nnnnn",	&cond_posn },				// 0B
+	{ "controller",			"n",		&cond_controller },			// 0C
+	{ "have.key",			"",			&cond_have_key},			// 0D
+	{ "said",				"",			&cond_said },				// 0E
+	{ "compare.strings",	"ss",		&cond_compare_strings },	// 0F
+	{ "obj.in.box",			"nnnnn",	&cond_obj_in_box },			// 10
+	{ "center.posn",		"nnnnn",	&cond_center_posn },		// 11
+	{ "right.posn",			"nnnnn",	&cond_right_posn },			// 12
+	{ "in.motion.using.mouse", "",		&cond_unknown_13 } // 13
+};
+
+AgiInstruction logicNamesCmd[] = {
+	{ "return",				"",			NULL },
+	{ "increment",			"v",		&cmd_increment },
+	{ "decrement",			"v",		&cmd_decrement },
+	{ "assignn",			"vn",		&cmd_assignn },
+	{ "assignv",			"vv",		&cmd_assignv },
+	{ "addn",				"vn",		&cmd_addn },
+	{ "addv",				"vv",		&cmd_addv },
+	{ "subn",				"vn",		&cmd_subn },
+	{ "subv",				"vv",		&cmd_subv },
+	{ "lindirectv",			"vv",		&cmd_lindirectv },
+	{ "lindirect",			"vv",		&cmd_rindirect },
+	{ "lindirectn",			"vn",		&cmd_lindirectn },
+	{ "set",				"n",		&cmd_set },
+	{ "reset",				"n",		&cmd_reset },
+	{ "toggle",				"n",		&cmd_toggle },
+	{ "set.v",				"v",		&cmd_set_v },
+	{ "reset.v",			"v",		&cmd_reset_v },
+	{ "toggle.v",			"v",		&cmd_toggle_v },
+	{ "new.room",			"n",		&cmd_new_room },
+	{ "new.room.v",			"v",		&cmd_new_room_f },
+	{ "load.logics",		"n",		&cmd_load_logic },
+	{ "load.logics.v",		"v",		&cmd_load_logic_f },
+	{ "call",				"n",		&cmd_call },
+	{ "call.v",				"v",		&cmd_call_f },
+	{ "load.pic",			"v",		&cmd_load_pic },
+	{ "draw.pic",			"v",		&cmd_draw_pic },
+	{ "show.pic",			"",			&cmd_show_pic },
+	{ "discard.pic",		"v",		&cmd_discard_pic },
+	{ "overlay.pic",		"v",		&cmd_overlay_pic },
+	{ "show.pri.screen",	"",			&cmd_show_pri_screen },
+	{ "load.view",			"n",		&cmd_load_view },
+	{ "load.view.v",		"v",		&cmd_load_view_f },
+	{ "discard.view",		"n",		&cmd_discard_view },
+	{ "animate.obj",		"n",		&cmd_animate_obj },
+	{ "unanimate.all",		"",			&cmd_unanimate_all },
+	{ "draw",				"n",		&cmd_draw },
+	{ "erase",				"n",		&cmd_erase },
+	{ "position",			"nnn",		&cmd_position },
+	{ "position.v",			"nvv",		&cmd_position_f },
+	{ "get.posn",			"nvv",		&cmd_get_posn },
+	{ "reposition",			"nvv",		&cmd_reposition },
+	{ "set.view",			"nn",		&cmd_set_view },
+	{ "set.view.v",			"nv",		&cmd_set_view_f },
+	{ "set.loop",			"nn",		&cmd_set_loop },
+	{ "set.loop.v",			"nv",		&cmd_set_loop_f },
+	{ "fix.loop",			"n",		&cmd_fix_loop },
+	{ "release.loop",		"n",		&cmd_release_loop },
+	{ "set.cel",			"nn",		&cmd_set_cel },
+	{ "set.cel.v",			"nv",		&cmd_set_cel_f },
+	{ "last.cel",			"nv",		&cmd_last_cel },
+	{ "current.cel",		"nv",		&cmd_current_cel },
+	{ "current.loop",		"nv",		&cmd_current_loop },
+	{ "current.view",		"nv",		&cmd_current_view },
+	{ "number.of.loops",	"nv",		&cmd_number_of_loops },
+	{ "set.priority",		"nn",		&cmd_set_priority },
+	{ "set.priority.v",		"nv",		&cmd_set_priority_f },
+	{ "release.priority",	"n",		&cmd_release_priority },
+	{ "get.priority",		"nn",		&cmd_get_priority },
+	{ "stop.update",		"n",		&cmd_stop_update },
+	{ "start.update",		"n",		&cmd_start_update },
+	{ "force.update",		"n",		&cmd_force_update },
+	{ "ignore.horizon",		"n",		&cmd_ignore_horizon },
+	{ "observe.horizon",	"n",		&cmd_observe_horizon },
+	{ "set.horizon",		"n",		&cmd_set_horizon },
+	{ "object.on.water",	"n",		&cmd_object_on_water },
+	{ "object.on.land",		"n",		&cmd_object_on_land },
+	{ "object.on.anything",	"n",		&cmd_object_on_anything },
+	{ "ignore.objs",		"n",		&cmd_ignore_objs },
+	{ "observe.objs",		"n",		&cmd_observe_objs },
+	{ "distance",			"nnv",		&cmd_distance },
+	{ "stop.cycling",		"n",		&cmd_stop_cycling },
+	{ "start.cycling",		"n",		&cmd_start_cycling },
+	{ "normal.cycle",		"n",		&cmd_normal_cycle },
+	{ "end.of.loop",		"nn",		&cmd_end_of_loop },
+	{ "reverse.cycle",		"n",		&cmd_reverse_cycle },
+	{ "reverse.loop",		"nn",		&cmd_reverse_loop },
+	{ "cycle.time",			"nv",		&cmd_cycle_time },
+	{ "stop.motion",		"n",		&cmd_stop_motion },
+	{ "start.motion",		"n",		&cmd_start_motion },
+	{ "step.size",			"nv",		&cmd_step_size },
+	{ "step.time",			"nv",		&cmd_step_time },
+	{ "move.obj",			"nnnnn",	&cmd_move_obj },
+	{ "move.obj.v",			"nvvvv",	&cmd_move_obj_f },
+	{ "follow.ego",			"nnn",		&cmd_follow_ego },
+	{ "wander",				"n",		&cmd_wander },
+	{ "normal.motion",		"n",		&cmd_normal_motion },
+	{ "set.dir",			"nv",		&cmd_set_dir },
+	{ "get.dir",			"nv",		&cmd_get_dir },
+	{ "ignore.blocks",		"n",		&cmd_ignore_blocks },
+	{ "observe.blocks",		"n",		&cmd_observe_blocks },
+	{ "block",				"nnnn",		&cmd_block },
+	{ "unblock",			"",			&cmd_unblock },
+	{ "get",				"n",		&cmd_get },
+	{ "get.v",				"v",		&cmd_get_f },
+	{ "drop",				"n",		&cmd_drop },
+	{ "put",				"nn",		&cmd_put },
+	{ "put.v",				"vv",		&cmd_put_f },
+	{ "get.room.v",			"vv",		&cmd_get_room_f },
+	{ "load.sound",			"n",		&cmd_load_sound },
+	{ "sound",				"nn",		&cmd_sound },
+	{ "stop.sound",			"",			&cmd_stop_sound },
+	{ "print",				"s",		&cmd_print },
+	{ "print.v",			"v",		&cmd_print_f },
+	{ "display",			"nns",		&cmd_display },
+	{ "display.v",			"vvv",		&cmd_display_f },
+	{ "clear.lines",		"nns",		&cmd_clear_lines },
+	{ "text.screen",		"",			&cmd_text_screen },
+	{ "graphics",			"",			&cmd_graphics },
+	{ "set.cursor.char",	"s",		&cmd_set_cursor_char },
+	{ "set.text.attribute",	"nn",		&cmd_set_text_attribute },
+	{ "shake.screen",		"n",		&cmd_shake_screen },
+	{ "configure.screen",	"nnn",		&cmd_configure_screen },
+	{ "status.line.on",		"",			&cmd_status_line_on },
+	{ "status.line.off",	"",			&cmd_status_line_off },
+	{ "set.string",			"ns",		&cmd_set_string },
+	{ "get.string",			"ns",		&cmd_get_string },
+	{ "word.to.string",		"nn",		&cmd_word_to_string },
+	{ "parse",				"n",		&cmd_parse },
+	{ "get.num",			"nv",		&cmd_get_num },
+	{ "prevent.input",		"",			&cmd_prevent_input },
+	{ "accept.input",		"",			&cmd_accept_input },
+	{ "set.key",			"nnn",		&cmd_set_key },
+	{ "add.to.pic",			"nnnnnnn",	&cmd_add_to_pic },
+	{ "add.to.pic.v",		"vvvvvvv",	&cmd_add_to_pic_f },
+	{ "status",				"",			&cmd_status },
+	{ "save.game",			"",			&cmd_save_game },
+	{ "restore.game",		"",			&cmd_load_game },
+	{ "init.disk",			"",			&cmd_init_disk },
+	{ "restart.game",		"",			&cmd_restart_game },
+	{ "show.obj",			"n",		&cmd_show_obj },
+	{ "random",				"nnv",		&cmd_random },
+	{ "program.control",	"",			&cmd_program_control },
+	{ "player.control",		"",			&cmd_player_control },
+	{ "obj.status.v",		"v",		&cmd_obj_status_f },
+	{ "quit",				"n",		&cmd_quit },
+	{ "show.mem",			"",			&cmd_show_mem },
+	{ "pause",				"",			&cmd_pause },
+	{ "echo.line",			"",			&cmd_echo_line },
+	{ "cancel.line",		"",			&cmd_cancel_line },
+	{ "init.joy",			"",			&cmd_init_joy },
+	{ "toggle.monitor",		"",			&cmd_toggle_monitor },
+	{ "version",			"",			&cmd_version },
+	{ "script.size",		"n",		&cmd_script_size },
+	{ "set.game.id",		"s",		&cmd_set_game_id },
+	{ "log",				"s",		&cmd_log },
+	{ "set.scan.start",		"",			&cmd_set_scan_start },
+	{ "reset.scan.start",	"",			&cmd_reset_scan_start },
+	{ "reposition.to",		"nnn",		&cmd_reposition_to },
+	{ "reposition.to.v",	"nvv",		&cmd_reposition_to_f },
+	{ "trace.on",			"",			&cmd_trace_on },
+	{ "trace.info", 		"nnn",		&cmd_trace_info },
+	{ "print.at",			"snnn",		&cmd_print_at },
+	{ "print.at.v",			"vnnn",		&cmd_print_at_v },
+	{ "discard.view.v",		"v",		&cmd_discard_view},
+	{ "clear.text.rect",	"nnnnn",	&cmd_clear_text_rect },
+	{ "set.upper.left",		"nn",		&cmd_set_upper_left },
+	{ "set.menu",			"s",		&cmd_set_menu },
+	{ "set.menu.member",	"sn",		&cmd_set_menu_item },
+	{ "submit.menu",		"",			&cmd_submit_menu },
+	{ "enable.member",		"n",		&cmd_enable_item },
+	{ "disable.member",		"n",		&cmd_disable_item },
+	{ "menu.input",			"",			&cmd_menu_input },
+	{ "show.obj.v",			"v",		&cmd_show_obj_v },
+	{ "open.dialogue",		"",			&cmd_open_dialogue },
+	{ "close.dialogue",		"",			&cmd_close_dialogue },
+	{ "mul.n",				"vn",		&cmd_mul_n },
+	{ "mul.v",				"vv",		&cmd_mul_v },
+	{ "div.n",				"vn",		&cmd_div_n },
+	{ "div.v",				"vv",		&cmd_div_v },
+	{ "close.window",		"",			&cmd_close_window },
+	{ "set.simple",			"n",		&cmd_set_simple },
+	{ "push.script",		"",			&cmd_push_script },
+	{ "pop.script",			"",			&cmd_pop_script },
+	{ "hold.key",			"",			&cmd_hold_key },
+	{ "set.pri.base",		"n",		&cmd_set_pri_base },
+	{ "discard.sound",		"n",		&cmd_discard_sound },
+	{ "hide.mouse",			"",			&cmd_hide_mouse },
+	{ "allow.menu",			"n",		&cmd_allow_menu },
+	{ "show.mouse",			"",			&cmd_show_mouse },
+	{ "fence.mouse",		"nnnn",		&cmd_fence_mouse },
+	{ "mouse.posn",			"vv",		&cmd_mouse_posn },
+	{ "release.key",		"",			&cmd_release_key },
+	{ "adj.ego.move.to.xy",	"",			&cmd_adj_ego_move_to_x_y }
+};
+
+void AgiEngine::setupOpcodes() {
+	for (int i = 0; i < 256; ++i)
+		_agiCondCommands[i] = &cond_unknown;
+	for (int i = 0; i <= ARRAYSIZE(logicNamesTest); ++i)
+		_agiCondCommands[i] = logicNamesTest[i].func;
+	_agiCondCommands[0xFF] = &cond_end;
+	_agiCondCommands[0xFD] = &cond_not;
+	_agiCondCommands[0xFC] = &cond_or;
+
+	for (int i = 0; i < ARRAYSIZE(logicNamesCmd); ++i)
+		_agiCommands[i] = logicNamesCmd[i].func;
+}
+
+}
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index b0d2051..6007aa1 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -23,17 +23,227 @@
 #ifndef AGI_OPCODES_H
 #define AGI_OPCODES_H
 
+#include <string.h>
+
 namespace Agi {
 
-struct AgiLogicnames {
+struct AgiInstruction {
 	const char *name;
-	uint16 numArgs;
-	uint16 argMask;
+	const char *args;
+	AgiCommand func;
+
+	int argumentsLength() { return strlen(args); }
 };
 
-extern AgiLogicnames logicNamesTest[];
-extern AgiLogicnames logicNamesCmd[];
-extern AgiLogicnames logicNamesIf[];
+extern AgiInstruction logicNamesTest[];
+extern AgiInstruction logicNamesCmd[];
+
+void cmd_increment(AgiGame *state, uint8 *p);
+void cmd_decrement(AgiGame *state, uint8 *p);
+void cmd_assignn(AgiGame *state, uint8 *p);
+void cmd_assignv(AgiGame *state, uint8 *p);
+void cmd_addn(AgiGame *state, uint8 *p);
+void cmd_addv(AgiGame *state, uint8 *p);
+void cmd_subn(AgiGame *state, uint8 *p);
+void cmd_subv(AgiGame *state, uint8 *p);	// 0x08
+void cmd_lindirectv(AgiGame *state, uint8 *p);
+void cmd_rindirect(AgiGame *state, uint8 *p);
+void cmd_lindirectn(AgiGame *state, uint8 *p);
+void cmd_set(AgiGame *state, uint8 *p);
+void cmd_reset(AgiGame *state, uint8 *p);
+void cmd_toggle(AgiGame *state, uint8 *p);
+void cmd_set_v(AgiGame *state, uint8 *p);
+void cmd_reset_v(AgiGame *state, uint8 *p);	// 0x10
+void cmd_toggle_v(AgiGame *state, uint8 *p);
+void cmd_new_room(AgiGame *state, uint8 *p);
+void cmd_new_room_f(AgiGame *state, uint8 *p);
+void cmd_load_logic(AgiGame *state, uint8 *p);
+void cmd_load_logic_f(AgiGame *state, uint8 *p);
+void cmd_call(AgiGame *state, uint8 *p);
+void cmd_call_f(AgiGame *state, uint8 *p);
+void cmd_load_pic(AgiGame *state, uint8 *p);	// 0x18
+void cmd_draw_pic(AgiGame *state, uint8 *p);
+void cmd_show_pic(AgiGame *state, uint8 *p);
+void cmd_discard_pic(AgiGame *state, uint8 *p);
+void cmd_overlay_pic(AgiGame *state, uint8 *p);
+void cmd_show_pri_screen(AgiGame *state, uint8 *p);
+void cmd_load_view(AgiGame *state, uint8 *p);
+void cmd_load_view_f(AgiGame *state, uint8 *p);
+void cmd_discard_view(AgiGame *state, uint8 *p);	// 0x20
+void cmd_animate_obj(AgiGame *state, uint8 *p);
+void cmd_unanimate_all(AgiGame *state, uint8 *p);
+void cmd_draw(AgiGame *state, uint8 *p);
+void cmd_erase(AgiGame *state, uint8 *p);
+void cmd_position(AgiGame *state, uint8 *p);
+void cmd_position_f(AgiGame *state, uint8 *p);
+void cmd_get_posn(AgiGame *state, uint8 *p);
+void cmd_reposition(AgiGame *state, uint8 *p);	// 0x28
+void cmd_set_view(AgiGame *state, uint8 *p);
+void cmd_set_view_f(AgiGame *state, uint8 *p);
+void cmd_set_loop(AgiGame *state, uint8 *p);
+void cmd_set_loop_f(AgiGame *state, uint8 *p);
+void cmd_fix_loop(AgiGame *state, uint8 *p);
+void cmd_release_loop(AgiGame *state, uint8 *p);
+void cmd_set_cel(AgiGame *state, uint8 *p);
+void cmd_set_cel_f(AgiGame *state, uint8 *p);	// 0x30
+void cmd_last_cel(AgiGame *state, uint8 *p);
+void cmd_current_cel(AgiGame *state, uint8 *p);
+void cmd_current_loop(AgiGame *state, uint8 *p);
+void cmd_current_view(AgiGame *state, uint8 *p);
+void cmd_number_of_loops(AgiGame *state, uint8 *p);
+void cmd_set_priority(AgiGame *state, uint8 *p);
+void cmd_set_priority_f(AgiGame *state, uint8 *p);
+void cmd_release_priority(AgiGame *state, uint8 *p);	// 0x38
+void cmd_get_priority(AgiGame *state, uint8 *p);
+void cmd_stop_update(AgiGame *state, uint8 *p);
+void cmd_start_update(AgiGame *state, uint8 *p);
+void cmd_force_update(AgiGame *state, uint8 *p);
+void cmd_ignore_horizon(AgiGame *state, uint8 *p);
+void cmd_observe_horizon(AgiGame *state, uint8 *p);
+void cmd_set_horizon(AgiGame *state, uint8 *p);
+void cmd_object_on_water(AgiGame *state, uint8 *p);	// 0x40
+void cmd_object_on_land(AgiGame *state, uint8 *p);
+void cmd_object_on_anything(AgiGame *state, uint8 *p);
+void cmd_ignore_objs(AgiGame *state, uint8 *p);
+void cmd_observe_objs(AgiGame *state, uint8 *p);
+void cmd_distance(AgiGame *state, uint8 *p);
+void cmd_stop_cycling(AgiGame *state, uint8 *p);
+void cmd_start_cycling(AgiGame *state, uint8 *p);
+void cmd_normal_cycle(AgiGame *state, uint8 *p);	// 0x48
+void cmd_end_of_loop(AgiGame *state, uint8 *p);
+void cmd_reverse_cycle(AgiGame *state, uint8 *p);
+void cmd_reverse_loop(AgiGame *state, uint8 *p);
+void cmd_cycle_time(AgiGame *state, uint8 *p);
+void cmd_stop_motion(AgiGame *state, uint8 *p);
+void cmd_start_motion(AgiGame *state, uint8 *p);
+void cmd_step_size(AgiGame *state, uint8 *p);
+void cmd_step_time(AgiGame *state, uint8 *p);	// 0x50
+void cmd_move_obj(AgiGame *state, uint8 *p);
+void cmd_move_obj_f(AgiGame *state, uint8 *p);
+void cmd_follow_ego(AgiGame *state, uint8 *p);
+void cmd_wander(AgiGame *state, uint8 *p);
+void cmd_normal_motion(AgiGame *state, uint8 *p);
+void cmd_set_dir(AgiGame *state, uint8 *p);
+void cmd_get_dir(AgiGame *state, uint8 *p);
+void cmd_ignore_blocks(AgiGame *state, uint8 *p);	// 0x58
+void cmd_observe_blocks(AgiGame *state, uint8 *p);
+void cmd_block(AgiGame *state, uint8 *p);
+void cmd_unblock(AgiGame *state, uint8 *p);
+void cmd_get(AgiGame *state, uint8 *p);
+void cmd_get_f(AgiGame *state, uint8 *p);
+void cmd_drop(AgiGame *state, uint8 *p);
+void cmd_put(AgiGame *state, uint8 *p);
+void cmd_put_f(AgiGame *state, uint8 *p);	// 0x60
+void cmd_get_room_f(AgiGame *state, uint8 *p);
+void cmd_load_sound(AgiGame *state, uint8 *p);
+void cmd_sound(AgiGame *state, uint8 *p);
+void cmd_stop_sound(AgiGame *state, uint8 *p);
+void cmd_print(AgiGame *state, uint8 *p);
+void cmd_print_f(AgiGame *state, uint8 *p);
+void cmd_display(AgiGame *state, uint8 *p);
+void cmd_display_f(AgiGame *state, uint8 *p);	// 0x68
+void cmd_clear_lines(AgiGame *state, uint8 *p);
+void cmd_text_screen(AgiGame *state, uint8 *p);
+void cmd_graphics(AgiGame *state, uint8 *p);
+void cmd_set_cursor_char(AgiGame *state, uint8 *p);
+void cmd_set_text_attribute(AgiGame *state, uint8 *p);
+void cmd_shake_screen(AgiGame *state, uint8 *p);
+void cmd_configure_screen(AgiGame *state, uint8 *p);
+void cmd_status_line_on(AgiGame *state, uint8 *p);	// 0x70
+void cmd_status_line_off(AgiGame *state, uint8 *p);
+void cmd_set_string(AgiGame *state, uint8 *p);
+void cmd_get_string(AgiGame *state, uint8 *p);
+void cmd_word_to_string(AgiGame *state, uint8 *p);
+void cmd_parse(AgiGame *state, uint8 *p);
+void cmd_get_num(AgiGame *state, uint8 *p);
+void cmd_prevent_input(AgiGame *state, uint8 *p);
+void cmd_accept_input(AgiGame *state, uint8 *p);	// 0x78
+void cmd_set_key(AgiGame *state, uint8 *p);
+void cmd_add_to_pic(AgiGame *state, uint8 *p);
+void cmd_add_to_pic_f(AgiGame *state, uint8 *p);
+void cmd_status(AgiGame *state, uint8 *p);
+void cmd_save_game(AgiGame *state, uint8 *p);
+void cmd_load_game(AgiGame *state, uint8 *p);
+void cmd_init_disk(AgiGame *state, uint8 *p);
+void cmd_restart_game(AgiGame *state, uint8 *p);	// 0x80
+void cmd_show_obj(AgiGame *state, uint8 *p);
+void cmd_random(AgiGame *state, uint8 *p);
+void cmd_program_control(AgiGame *state, uint8 *p);
+void cmd_player_control(AgiGame *state, uint8 *p);
+void cmd_obj_status_f(AgiGame *state, uint8 *p);
+void cmd_quit(AgiGame *state, uint8 *p);
+void cmd_show_mem(AgiGame *state, uint8 *p);
+void cmd_pause(AgiGame *state, uint8 *p);	// 0x88
+void cmd_echo_line(AgiGame *state, uint8 *p);
+void cmd_cancel_line(AgiGame *state, uint8 *p);
+void cmd_init_joy(AgiGame *state, uint8 *p);
+void cmd_toggle_monitor(AgiGame *state, uint8 *p);
+void cmd_version(AgiGame *state, uint8 *p);
+void cmd_script_size(AgiGame *state, uint8 *p);
+void cmd_set_game_id(AgiGame *state, uint8 *p);
+void cmd_log(AgiGame *state, uint8 *p);	// 0x90
+void cmd_set_scan_start(AgiGame *state, uint8 *p);
+void cmd_reset_scan_start(AgiGame *state, uint8 *p);
+void cmd_reposition_to(AgiGame *state, uint8 *p);
+void cmd_reposition_to_f(AgiGame *state, uint8 *p);
+void cmd_trace_on(AgiGame *state, uint8 *p);
+void cmd_trace_info(AgiGame *state, uint8 *p);
+void cmd_print_at(AgiGame *state, uint8 *p);
+void cmd_print_at_v(AgiGame *state, uint8 *p);	// 0x98
+//void cmd_discard_view(AgiGame *state, uint8 *p);	// Opcode repeated from 0x20 ?
+void cmd_clear_text_rect(AgiGame *state, uint8 *p);
+void cmd_set_upper_left(AgiGame *state, uint8 *p);
+void cmd_set_menu(AgiGame *state, uint8 *p);
+void cmd_set_menu_item(AgiGame *state, uint8 *p);
+void cmd_submit_menu(AgiGame *state, uint8 *p);
+void cmd_enable_item(AgiGame *state, uint8 *p);
+void cmd_disable_item(AgiGame *state, uint8 *p);	// 0xa0
+void cmd_menu_input(AgiGame *state, uint8 *p);
+void cmd_show_obj_v(AgiGame *state, uint8 *p);
+void cmd_open_dialogue(AgiGame *state, uint8 *p);
+void cmd_close_dialogue(AgiGame *state, uint8 *p);
+void cmd_mul_n(AgiGame *state, uint8 *p);
+void cmd_mul_v(AgiGame *state, uint8 *p);
+void cmd_div_n(AgiGame *state, uint8 *p);
+void cmd_div_v(AgiGame *state, uint8 *p);	// 0xa8
+void cmd_close_window(AgiGame *state, uint8 *p);
+void cmd_set_simple(AgiGame *state, uint8 *p);
+void cmd_push_script(AgiGame *state, uint8 *p);
+void cmd_pop_script(AgiGame *state, uint8 *p);
+void cmd_hold_key(AgiGame *state, uint8 *p);
+void cmd_set_pri_base(AgiGame *state, uint8 *p);
+void cmd_discard_sound(AgiGame *state, uint8 *p);
+void cmd_hide_mouse(AgiGame *state, uint8 *p);	// 0xb0
+void cmd_allow_menu(AgiGame *state, uint8 *p);
+void cmd_show_mouse(AgiGame *state, uint8 *p);
+void cmd_fence_mouse(AgiGame *state, uint8 *p);
+void cmd_mouse_posn(AgiGame *state, uint8 *p);
+void cmd_release_key(AgiGame *state, uint8 *p);
+void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p);
+
+void cond_end(AgiGame *state, uint8 *p);
+void cond_equal(AgiGame *state, uint8 *p);
+void cond_equalv(AgiGame *state, uint8 *p);
+void cond_less(AgiGame *state, uint8 *p);
+void cond_lessv(AgiGame *state, uint8 *p);
+void cond_greater(AgiGame *state, uint8 *p);
+void cond_greaterv(AgiGame *state, uint8 *p);
+void cond_isset(AgiGame *state, uint8 *p);
+void cond_issetv(AgiGame *state, uint8 *p);
+void cond_has(AgiGame *state, uint8 *p);
+void cond_obj_in_room(AgiGame *state, uint8 *p);
+void cond_posn(AgiGame *state, uint8 *p);
+void cond_controller(AgiGame *state, uint8 *p);
+void cond_have_key(AgiGame *state, uint8 *p);
+void cond_said(AgiGame *state, uint8 *p);
+void cond_compare_strings(AgiGame *state, uint8 *p);
+void cond_obj_in_box(AgiGame *state, uint8 *p);
+void cond_center_posn(AgiGame *state, uint8 *p);
+void cond_right_posn(AgiGame *state, uint8 *p);
+void cond_unknown_13(AgiGame *state, uint8 *p);
+void cond_unknown(AgiGame *state, uint8 *p);
+void cond_not(AgiGame *state, uint8 *p);
+void cond_or(AgiGame *state, uint8 *p);
 
 } // End of namespace Agi
 


Commit: 41dccce00cdd3c5e3692b2e8eb22de1ef0b9c1e1
    https://github.com/scummvm/scummvm/commit/41dccce00cdd3c5e3692b2e8eb22de1ef0b9c1e1
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:53-07:00

Commit Message:
AGI: Execute test commands only when needed

Changed paths:
    engines/agi/agi.h
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 2b41514..55c1ab3 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -634,12 +634,8 @@ struct AgiGame {
 
 	Common::Rect mouseFence;		/**< rectangle set by fence.mouse command */
 
-	// IF conditions
+	// IF condition handling
 	int endTest;
-	int orTest;
-	int orVal;
-	int notTest;
-	int testVal;
 	int ec;
 };
 
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 0054fad..7ccd30e 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -39,80 +39,63 @@ namespace Agi {
 #define testHas(obj)			(state->_vm->objectGetLocation(obj) == EGO_OWNED)
 #define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getvar(v))
 
-void cond_end(AgiGame *state, uint8 *p) {
-	state->endTest = true;
-	state->ec = true;
-}
-
 void cond_equal(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testEqual(p[0], p[1]);
 }
 
 void cond_equalv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testEqual(p[0], getvar(p[1]));
 }
 
 void cond_less(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testLess(p[0], p[1]);
 }
 
 void cond_lessv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testLess(p[0], getvar(p[1]));
 }
 
 void cond_greater(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testGreater(p[0], p[1]);
 }
 
 void cond_greaterv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	ip += 2;
 	state->ec = testGreater(p[0], getvar(p[1]));
 }
 
 void cond_isset(AgiGame *state, uint8 *p) {
-	ip += 1;
 	state->ec = testIsSet(p[0]);
 }
 
 void cond_issetv(AgiGame *state, uint8 *p) {
-	ip += 1;
 	state->ec = testIsSet(getvar(p[1]));
 }
 
 void cond_has(AgiGame *state, uint8 *p) {
-	ip += 1;
 	state->ec = testHas(p[0]);
 }
 
 void cond_obj_in_room(AgiGame *state, uint8 *p) {
-	ip += 2;
 	state->ec = testObjInRoom(p[0], p[1]);
 }
 
 void cond_posn(AgiGame *state, uint8 *p) {
-	ip += 5;
 	state->ec = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_controller(AgiGame *state, uint8 *p) {
-	ip += 1;
 	state->ec = state->_vm->testController(p[0]);
 }
 
@@ -122,29 +105,23 @@ void cond_have_key(AgiGame *state, uint8 *p) {
 
 void cond_said(AgiGame *state, uint8 *p) {
 	int ec = state->_vm->testSaid(p[0], p + 1);
-	ip += p[0] * 2;	// skip num_words * 2
-	ip++;	// skip num_words opcode
 	state->ec = ec;
 }
 
 void cond_compare_strings(AgiGame *state, uint8 *p) {
 	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
-	ip += 2;
 	state->ec = state->_vm->testCompareStrings(p[0], p[1]);
 }
 
 void cond_obj_in_box(AgiGame *state, uint8 *p) {
-	ip += 5;
 	state->ec = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_center_posn(AgiGame *state, uint8 *p) {
-	ip += 5;
 	state->ec = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_right_posn(AgiGame *state, uint8 *p) {
-	ip += 5;
 	state->ec = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
 }
 
@@ -164,22 +141,6 @@ void cond_unknown(AgiGame *state, uint8 *p) {
 	state->endTest = true;
 }
 
-void cond_not(AgiGame *state, uint8 *p) {
-	state->notTest = !state->notTest;
-}
-
-void cond_or(AgiGame *state, uint8 *p) {
-	// if or_test is ON and we hit 0xFC, end of OR, then
-	// or is STILL false so break.
-	if (state->orTest) {
-		state->orTest = false;
-		state->testVal &= state->orVal;
-	} else {
-		state->orTest = true;
-		state->orVal = false;
-	}
-}
-
 uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
 	char ms1[MAX_STRINGLEN];
 	char ms2[MAX_STRINGLEN];
@@ -349,49 +310,87 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 int AgiEngine::testIfCode(int lognum) {
 	AgiGame *state = &_game;
 	uint8 op = 0;
-	uint16 lastIp = ip;
 	uint8 p[16] = { 0 };
 
 	state->ec = true;
-	state->notTest = false;
-	state->orTest = false;
+	int notTest = false;
+	int orTest = false;
+	int orVal = false;
 	state->endTest = false;
-	state->testVal = true;
+	int testVal = true;
+	int skipTest = false;
+	int skipOr = false;
 
 	while (!(shouldQuit() || _restartGame) && !state->endTest) {
 		if (_debug.enabled && (_debug.logic0 || lognum))
 			debugConsole(lognum, lTEST_MODE, NULL);
 
-		lastIp = ip;
 		op = *(code + ip++);
 		memmove(p, (code + ip), 16);
 
-		_agiCondCommands[op](state, p);
-		if (op == 0xFF || op == 0xFD || op == 0xFC)
+		// Execute test command if needed
+		switch (op) {
+		case 0xFC:
+			skipOr = false;
+			if (orTest) {
+				orTest = false;
+				testVal &= orVal;
+				if (!orVal)
+					skipTest = true;
+			} else {
+				orTest = true;
+				orVal = false;
+			}
 			continue;
+		case 0xFD:
+			notTest = true;
+			continue;
+		case 0x00:
+		case 0xFF:
+			state->endTest = true;
+			continue;
+		
+		default:
+			if (!skipTest && !skipOr) {
+				_agiCondCommands[op](state, p);
+
+				// not is only enabled for 1 test command
+				if (notTest)
+					state->ec = !state->ec;
+				notTest = false;
+
+				if (orTest) {
+					orVal |= state->ec;
+					if (state->ec)
+						skipOr = true;
+				} else {
+					testVal &= state->ec;
+					if (!state->ec)
+						skipTest = true;
+				}
+			}
+			break;
+		}
 
-		// not is only enabled for 1 test command
-		if (state->notTest)
-			state->ec = !state->ec;
-		state->notTest = false;
-
-		if (state->orTest)
-			state->orVal |= state->ec;
-		else
-			state->testVal &= state->ec;
+		// Skip the instruction
+		if (op <= 0x13) {
+			if (op == 0x0E) // said()
+				ip += *(code + ip) * 2 + 1;
+			else
+				ip += logicNamesTest[op].argumentsLength();
+		}
 	}
 
-	// Execute the following IF block if the condition is true, otherwise
-	// skip the block.
-	if (state->testVal)
+	// Skip the following IF block if the condition evaluates as false
+	if (testVal)
 		ip += 2;
 	else
 		ip += READ_LE_UINT16(code + ip) + 2;
 
 	if (_debug.enabled && (_debug.logic0 || lognum))
-		debugConsole(lognum, 0xFF, state->testVal ? "=true" : "=false");
+		debugConsole(lognum, 0xFF, testVal ? "=true" : "=false");
 
-	return state->testVal;
+	return testVal;
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index aef7684..301f22a 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -26,7 +26,7 @@
 namespace Agi {
 
 AgiInstruction logicNamesTest[] = {
-	{ "",					"",			&cond_end },				// 00
+	{ "",					"",			NULL },						// 00
 	{ "equaln",				"vn",		&cond_equal },				// 01
 	{ "equalv",				"vv",		&cond_equalv },				// 02
 	{ "lessn",				"vn",		&cond_less },				// 03
@@ -239,9 +239,6 @@ void AgiEngine::setupOpcodes() {
 		_agiCondCommands[i] = &cond_unknown;
 	for (int i = 0; i <= ARRAYSIZE(logicNamesTest); ++i)
 		_agiCondCommands[i] = logicNamesTest[i].func;
-	_agiCondCommands[0xFF] = &cond_end;
-	_agiCondCommands[0xFD] = &cond_not;
-	_agiCondCommands[0xFC] = &cond_or;
 
 	for (int i = 0; i < ARRAYSIZE(logicNamesCmd); ++i)
 		_agiCommands[i] = logicNamesCmd[i].func;
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 6007aa1..075bd27 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -221,7 +221,6 @@ void cmd_mouse_posn(AgiGame *state, uint8 *p);
 void cmd_release_key(AgiGame *state, uint8 *p);
 void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p);
 
-void cond_end(AgiGame *state, uint8 *p);
 void cond_equal(AgiGame *state, uint8 *p);
 void cond_equalv(AgiGame *state, uint8 *p);
 void cond_less(AgiGame *state, uint8 *p);
@@ -242,8 +241,6 @@ void cond_center_posn(AgiGame *state, uint8 *p);
 void cond_right_posn(AgiGame *state, uint8 *p);
 void cond_unknown_13(AgiGame *state, uint8 *p);
 void cond_unknown(AgiGame *state, uint8 *p);
-void cond_not(AgiGame *state, uint8 *p);
-void cond_or(AgiGame *state, uint8 *p);
 
 } // End of namespace Agi
 


Commit: d273f58b3c3fcc22dee3c2761f397cdb6974eab7
    https://github.com/scummvm/scummvm/commit/d273f58b3c3fcc22dee3c2761f397cdb6974eab7
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:56-07:00

Commit Message:
AGI: AgiLoader_v1: Precalculate final resource offsets

That is, calculate the final offsets when loading the resource directories,
and when loading the resource simply seek into the disk image file.

Changed paths:
    engines/agi/loader_v1.cpp



diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index ed667f9..6a7ab6c 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -82,7 +82,7 @@ int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
 			int sec = (BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1;
 			int off = ((b1 & 0x1) << 8) | b2;
 			agid[i].volume = 0;
-			agid[i].offset = (sec << 16) | off;
+			agid[i].offset = SECTOR_OFFSET(sec) + off;
 		}
 	}
 
@@ -117,11 +117,8 @@ uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
 	if (agid->offset == _EMPTY)
 		return NULL;
 	
-	int sec = agid->offset >> 16;
-	int off = agid->offset & 0xFFFF;
-	
 	fp.open(_filenameDisk0);
-	fp.seek(SECTOR_OFFSET(sec) + off, SEEK_SET);
+	fp.seek(agid->offset, SEEK_SET);
 
 	int signature = fp.readUint16BE();
 	if (signature != 0x1234) {


Commit: 04353038ae51599a430da76cdeecc6c78ab4d137
    https://github.com/scummvm/scummvm/commit/04353038ae51599a430da76cdeecc6c78ab4d137
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:26:58-07:00

Commit Message:
AGI: Add loader and detection for Black Cauldron booter

Changed paths:
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/detection_tables.h
    engines/agi/loader_v1.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 55c1ab3..2ba617f 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -131,8 +131,9 @@ enum AgiGameID {
 
 enum AgiGameType {
 	GType_PreAGI = 0,
-	GType_V2 = 1,
-	GType_V3 = 2
+	GType_V1 = 1,
+	GType_V2 = 2,
+	GType_V3 = 3
 };
 
 //
@@ -678,7 +679,8 @@ private:
 	Common::String _filenameDisk0;
 	Common::String _filenameDisk1;
 
-	int loadDir(AgiDir *agid, int offset, int num);
+	int loadDir_DDP(AgiDir *agid, int offset, int max);
+	int loadDir_BC(AgiDir *agid, int offset, int max);
 	uint8 *loadVolRes(AgiDir *agid);
 
 public:
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index c6c9740..ad3760c 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -199,6 +199,7 @@ bool AgiMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameD
 	case Agi::GType_PreAGI:
 		*engine = new Agi::PreAgiEngine(syst, gd);
 		break;
+	case Agi::GType_V1:
 	case Agi::GType_V2:
 	case Agi::GType_V3:
 		*engine = new Agi::AgiEngine(syst, gd);
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index e59765f..be9bc1e 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -865,9 +865,11 @@ static AGIGameDescription g_fallbackDesc = {
 /**
  * Descriptor table for booter games
  */
+#define BOOTER_V1(id, extra, md50, md51, gid) { md50, md51, id, extra, gid, GType_V1, ADGF_NO_FLAGS, 0x1120 },
 #define BOOTER_V2(id, extra, md50, md51, gid) { md50, md51, id, extra, gid, GType_V2, ADGF_NO_FLAGS, 0x2001 },
 
 static AGIBooterDescription booterDescription[] = {
+	BOOTER_V1("bc", "booter", "98a51d3a372baa9df288b6c0f0232567", "5568f7a52e787305656246f95e2aa375", GID_BC)
 	BOOTER_V2("ddp", "booter", "f323f10abf8140ffb2668b09af2e7b87", "", GID_DDP)
 	{ "", "", "", "", 0, 0, 0, 0 }
 };
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 6a7ab6c..ab350cd 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -23,41 +23,56 @@
 #include "agi/agi.h"
 #include "common/md5.h"
 
+#define IMAGE_SIZE 368640 // = 40 * 2 * 9 * 512 = tracks * sides * sectors * sector size
 #define SECTOR_OFFSET(s) ((s) * 512)
 
-#define BASE_SECTOR	0x1C2
 
-#define LOGDIR_SEC	SECTOR_OFFSET(171) + 5
-#define LOGDIR_NUM	43
+#define DDP_BASE_SECTOR	0x1C2
 
-#define PICDIR_SEC	SECTOR_OFFSET(180) + 5
-#define PICDIR_NUM	30
+#define DDP_LOGDIR_SEC	SECTOR_OFFSET(171) + 5
+#define DDP_LOGDIR_MAX	43
 
-#define VIEWDIR_SEC	SECTOR_OFFSET(189) + 5
-#define VIEWDIR_NUM	171
+#define DDP_PICDIR_SEC	SECTOR_OFFSET(180) + 5
+#define DDP_PICDIR_MAX	30
 
-#define SNDDIR_SEC	SECTOR_OFFSET(198) + 5
-#define SNDDIR_NUM	64
+#define DDP_VIEWDIR_SEC	SECTOR_OFFSET(189) + 5
+#define DDP_VIEWDIR_MAX	171
+
+#define DDP_SNDDIR_SEC	SECTOR_OFFSET(198) + 5
+#define DDP_SNDDIR_MAX	64
+
+
+#define BC_LOGDIR_SEC	SECTOR_OFFSET(90) + 5
+#define BC_LOGDIR_MAX	118
+
+#define BC_VIEWDIR_SEC	SECTOR_OFFSET(96) + 5
+#define BC_VIEWDIR_MAX	180
+
+#define BC_PICDIR_SEC	SECTOR_OFFSET(93) + 8
+#define BC_PICDIR_MAX	117
+
+#define BC_SNDDIR_SEC	SECTOR_OFFSET(99) + 5
+#define BC_SNDDIR_MAX	29
 
 namespace Agi {
 
 
 AgiLoader_v1::AgiLoader_v1(AgiEngine *vm) {
 	_vm = vm;
-	
+}
+
+int AgiLoader_v1::detectGame() {
 	// Find filenames for the disk images
 	Common::String md5Disk0, md5Disk1;
 	getBooterMD5Sums((AgiGameID)_vm->getGameID(), md5Disk0, md5Disk1);
 	diskImageExists(md5Disk0, _filenameDisk0);
 	if (!md5Disk1.empty())
 		diskImageExists(md5Disk1, _filenameDisk1);
-}
 
-int AgiLoader_v1::detectGame() {
 	return _vm->setupV2Game(_vm->getVersion());
 }
 
-int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
+int AgiLoader_v1::loadDir_DDP(AgiDir *agid, int offset, int max) {
 	Common::File fp;
 	
 	if (!fp.open(_filenameDisk0))
@@ -70,7 +85,7 @@ int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
 	}
 	
 	fp.seek(offset, SEEK_SET);
-	for (int i = 0; i < num; i++) {
+	for (int i = 0; i <= max; i++) {
 		int b0 = fp.readByte();
 		int b1 = fp.readByte();
 		int b2 = fp.readByte();
@@ -79,7 +94,7 @@ int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
 			agid[i].volume = 0xFF;
 			agid[i].offset = _EMPTY;
 		} else {
-			int sec = (BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1;
+			int sec = (DDP_BASE_SECTOR + (((b0 & 0xF) << 8) | b1)) >> 1;
 			int off = ((b1 & 0x1) << 8) | b2;
 			agid[i].volume = 0;
 			agid[i].offset = SECTOR_OFFSET(sec) + off;
@@ -91,16 +106,65 @@ int AgiLoader_v1::loadDir(AgiDir *agid, int offset, int num) {
 	return errOK;
 }
 
+int AgiLoader_v1::loadDir_BC(AgiDir *agid, int offset, int max) {
+	Common::File fp;
+	
+	if (!fp.open(_filenameDisk0))
+		return errBadFileOpen;
+
+	// Cleanup
+	for (int i = 0; i < MAX_DIRS; i++) {
+		agid[i].volume = 0xFF;
+		agid[i].offset = _EMPTY;
+	}
+	
+	fp.seek(offset, SEEK_SET);
+	for (int i = 0; i <= max; i++) {
+		int b0 = fp.readByte();
+		int b1 = fp.readByte();
+		int b2 = fp.readByte();
+		
+		if (b0 == 0xFF && b1 == 0xFF && b2 == 0xFF) {
+			agid[i].volume = 0xFF;
+			agid[i].offset = _EMPTY;
+		} else {
+			int sec = (b0 & 0x3F) * 18 + ((b1 >> 1) & 0x1) * 9 + ((b1 >> 2) & 0x1F) - 1;
+			int off = ((b1 & 0x1) << 8) | b2;
+			int vol = (b0 & 0xC0) >> 6;
+			agid[i].volume = 0;
+			agid[i].offset = (vol == 2) * IMAGE_SIZE + SECTOR_OFFSET(sec) + off;
+		}
+	}
+
+	fp.close();
+
+	return errOK;
+}
+
 int AgiLoader_v1::init() {
 	int ec = errOK;
 
-	ec = loadDir(_vm->_game.dirLogic, LOGDIR_SEC, LOGDIR_NUM);
-	if (ec == errOK)
-		ec = loadDir(_vm->_game.dirPic, PICDIR_SEC, PICDIR_NUM);
-	if (ec == errOK)
-		ec = loadDir(_vm->_game.dirView, VIEWDIR_SEC, VIEWDIR_NUM);
-	if (ec == errOK)
-		ec = loadDir(_vm->_game.dirSound, SNDDIR_SEC, SNDDIR_NUM);
+	switch (_vm->getGameID()) {
+	case GID_DDP:
+		ec = loadDir_DDP(_vm->_game.dirLogic, DDP_LOGDIR_SEC, DDP_LOGDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_DDP(_vm->_game.dirPic, DDP_PICDIR_SEC, DDP_PICDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_DDP(_vm->_game.dirView, DDP_VIEWDIR_SEC, DDP_VIEWDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_DDP(_vm->_game.dirSound, DDP_SNDDIR_SEC, DDP_SNDDIR_MAX);
+		break;
+
+	case GID_BC:
+		ec = loadDir_BC(_vm->_game.dirLogic, BC_LOGDIR_SEC, BC_LOGDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_BC(_vm->_game.dirPic, BC_PICDIR_SEC, BC_PICDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_BC(_vm->_game.dirView, BC_VIEWDIR_SEC, BC_VIEWDIR_MAX);
+		if (ec == errOK)
+			ec = loadDir_BC(_vm->_game.dirSound, BC_SNDDIR_SEC, BC_SNDDIR_MAX);
+		break;
+	}
 
 	return ec;
 }
@@ -113,12 +177,19 @@ int AgiLoader_v1::deinit() {
 uint8 *AgiLoader_v1::loadVolRes(struct AgiDir *agid) {
 	uint8 *data = NULL;
 	Common::File fp;
+	int offset = agid->offset;
 
-	if (agid->offset == _EMPTY)
+	if (offset == _EMPTY)
 		return NULL;
 	
-	fp.open(_filenameDisk0);
-	fp.seek(agid->offset, SEEK_SET);
+	if (offset > IMAGE_SIZE) {
+		fp.open(_filenameDisk1);
+		offset -= IMAGE_SIZE;
+	} else {
+		fp.open(_filenameDisk0);
+	}
+
+	fp.seek(offset, SEEK_SET);
 
 	int signature = fp.readUint16BE();
 	if (signature != 0x1234) {


Commit: 0b6b6708034f93eb8bfd9ecca0574f9d84031af1
    https://github.com/scummvm/scummvm/commit/0b6b6708034f93eb8bfd9ecca0574f9d84031af1
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:00-07:00

Commit Message:
AGI: Add still incomplete V1 instruction tables

Changed paths:
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 301f22a..70ba1fa 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -25,7 +25,132 @@
 
 namespace Agi {
 
-AgiInstruction logicNamesTest[] = {
+AgiInstruction *logicNamesTest;
+AgiInstruction *logicNamesCmd;
+
+AgiInstruction insV1Test[] = {
+	{ "",					"",			NULL },					// 00
+	{ "equaln",				"vn",		&cond_equal },			// 01
+	{ "equalv",				"vv",		&cond_equalv },			// 02
+	{ "lessn",				"vn",		&cond_less },			// 03
+	{ "lessv",				"vv",		&cond_lessv },			// 04
+	{ "greatern",			"vn",		&cond_greater },		// 05
+	{ "greaterv",			"vv",		&cond_greaterv },		// 06
+	{ "isset",				"n",		&cond_isset },			// 07
+	{ "issetv",				"v",		&cond_issetv },			// 08
+	{ "...",				"nnnn",		NULL },					// 09
+	{ "posn",				"nnnnn",	&cond_posn },			// 0A
+	{ "controller",			"n",		&cond_controller },		// 0B
+	{ "...",				"nn",		NULL },					// 0C
+	{ "...",				"",			NULL },					// 0D
+	{ "have.key",			"",			&cond_have_key },		// 0E
+	{ "...",				"nn",		NULL },					// 0F
+	{ "bit",				"nv",		NULL },					// 10
+	{ "...",				"nnnnn",	NULL },					// 11
+	{ "...",				"nnnnn",	NULL },					// 12
+};
+
+AgiInstruction insV1[] = {
+	{ "return",				"",			NULL },						// 00
+	{ "increment",			"v",		&cmd_increment },			// 01
+	{ "decrement",			"v",		&cmd_decrement },			// 02
+	{ "assignn",			"vn",		&cmd_assignn },				// 03
+	{ "assignv",			"vv",		&cmd_assignv },				// 04
+	{ "addn",				"vn",		&cmd_addn },				// 05
+	{ "addv",				"vv",		&cmd_addv },				// 06
+	{ "subn",				"vn",		&cmd_subn },				// 07
+	{ "subv",				"vv",		&cmd_subv },				// 08
+	{ "load.view",			"n",		&cmd_load_view },			// 09
+	{ "animate.obj",		"n",		&cmd_animate_obj },			// 0A
+	{ "new.room",			"n",		&cmd_new_room },			// 0B
+	{ "draw.pic",			"v",		&cmd_draw_pic },			// 0C
+	{ "print",				"s",		&cmd_print },				// 0D
+	{ "status",				"",			&cmd_status },				// 0E
+	{ "save.game",			"",			&cmd_save_game },			// 0F
+	{ "restore.game",		"",			&cmd_load_game },			// 10
+	{ "...",				"",			NULL },						// 11
+	{ "restart.game",		"",			&cmd_restart_game },		// 12
+	{ "random",				"v",		&cmd_random },				// 13 TODO: 1 vs 3 vars
+	{ "get",				"n",		&cmd_get },					// 14
+	{ "drop",				"n",		&cmd_drop },				// 15
+	{ "draw",				"n",		&cmd_draw },				// 16
+	{ "erase",				"n",		&cmd_erase },				// 17
+	{ "position",			"nnn",		&cmd_position },			// 18
+	{ "position.v",			"nvv",		&cmd_position_f },			// 19
+	{ "get.posn",			"nvv",		&cmd_get_posn },			// 1A
+	{ "set.cel",			"nn",		&cmd_set_cel },				// 1B
+	{ "set.loop",			"nn",		&cmd_set_loop },			// 1C
+	{ "end.of.loop",		"nn",		&cmd_end_of_loop },			// 1D
+	{ "reverse.loop",		"nn",		&cmd_reverse_loop },		// 1E
+	{ "move.obj",			"nnnnn",	&cmd_move_obj },			// 1F
+	{ "set.view",			"nn",		&cmd_set_view },			// 20
+	{ "follow.ego",			"nnn",		&cmd_follow_ego },			// 21
+	{ "...",				"",			NULL },						// 22
+	{ "...",				"",			NULL },						// 23
+	{ "ignore.blocks",		"n",		&cmd_ignore_blocks },		// 24
+	{ "observe.blocks",		"n",		&cmd_observe_blocks },		// 25
+	{ "wander",				"n",		&cmd_wander },				// 26
+	{ "reposition",			"nvv",		&cmd_reposition },			// 27
+	{ "stop.motion",		"n",		&cmd_stop_motion },			// 28
+	{ "start.motion",		"n",		&cmd_start_motion },		// 29
+	{ "stop.cycling",		"n",		&cmd_stop_cycling },		// 2A
+	{ "start.cycling",		"n",		&cmd_start_cycling },		// 2B
+	{ "stop.update",		"n",		&cmd_stop_update },			// 2C
+	{ "start.update",		"n",		&cmd_start_update },		// 2D
+	{ "program.control",	"",			&cmd_program_control },		// 2E
+	{ "player.control",		"",			&cmd_player_control },		// 2F
+	{ "set.priority",		"nn",		&cmd_set_priority },		// 30
+	{ "release.priority",	"n",		&cmd_release_priority },	// 31
+	{ "add.to.pic",			"nnnnnn",	&cmd_add_to_pic },			// 32 TODO: 7 vs 8 args
+	{ "set.horizon",		"n",		&cmd_set_horizon },			// 33
+	{ "ignore.horizon",		"n",		&cmd_ignore_horizon },		// 34
+	{ "observe.horizon",	"n",		&cmd_observe_horizon },		// 35
+	{ "load.logics",		"n",		&cmd_load_logic },			// 36
+	{ "object.on.water",	"n",		&cmd_object_on_water },		// 37
+	{ "load.pic",			"v",		&cmd_load_pic },			// 38
+	{ "load.sound",			"n",		&cmd_load_sound },			// 39
+	{ "sound",				"nn",		&cmd_sound },				// 3A
+	{ "stop.sound",			"",			&cmd_stop_sound },			// 3B
+	{ "set",				"n",		&cmd_set },					// 3C
+	{ "reset",				"n",		&cmd_reset },				// 3D
+	{ "...",				"n",		NULL },						// 3E
+	{ "new.room.v",			"v",		&cmd_new_room_f },			// 3F
+	{ "...",				"n",		NULL },						// 40
+	{ "...",				"",			NULL },						// 41
+	{ "...",				"v",		NULL },						// 42
+	{ "move.obj.v",			"nvvvv",	&cmd_move_obj_f },			// 43
+	{ "...",				"",			NULL },						// 44
+	{ "...",				"",			NULL },						// 45
+	{ "...",				"",			NULL },						// 46
+	{ "...",				"",			NULL },						// 47
+	{ "...",				"nv",		NULL },						// 48 get.priority??
+	{ "ignore.objs",		"n",		&cmd_ignore_objs },			// 49
+	{ "observe.objs",		"n",		&cmd_observe_objs },		// 4A
+	{ "distance",			"nnv",		&cmd_distance },			// 4B
+	{ "object.on.land",		"n",		&cmd_object_on_land },		// 4C
+	{ "...",				"nv",		NULL },						// 4D set.priority.v???
+	{ "...",				"",			NULL },						// 4E
+	{ "...",				"n",		NULL },						// 4F
+	{ "display",			"nnns",		&cmd_display },				// 50 TODO: 4 vs 3 args
+	{ "prevent.input???",	"",			NULL },						// 51
+	{ "...",				"",			NULL },						// 52
+	{ "...",				"n",		NULL },						// 53 ???
+	{ "...",				"",			NULL },						// 54 ???
+	{ "stop.motion",		"",			&cmd_stop_motion },			// 55 or force.update??
+	{ "discard.view",		"n",		&cmd_discard_view },		// 56
+	{ "discard.pic",		"v",		&cmd_discard_pic },			// 57
+	{ "...",				"nn",		NULL },						// 58
+	{ "...",				"",			NULL },						// 59
+	{ "last.cel",			"nv",		&cmd_last_cel },			// 5A
+	{ "set.cel.v",			"nv",		&cmd_set_cel_f },			// 5B
+	{ "...",				"",			NULL },						// 5C
+	{ "...",				"n",		NULL },						// 5D
+	{ "...",				"",			NULL },						// 5E
+	{ "...",				"",			NULL },						// 5F
+	{ "setbit",				"nv",		NULL },						// 60
+};
+
+AgiInstruction insV2Test[] = {
 	{ "",					"",			NULL },						// 00
 	{ "equaln",				"vn",		&cond_equal },				// 01
 	{ "equalv",				"vv",		&cond_equalv },				// 02
@@ -45,10 +170,10 @@ AgiInstruction logicNamesTest[] = {
 	{ "obj.in.box",			"nnnnn",	&cond_obj_in_box },			// 10
 	{ "center.posn",		"nnnnn",	&cond_center_posn },		// 11
 	{ "right.posn",			"nnnnn",	&cond_right_posn },			// 12
-	{ "in.motion.using.mouse", "",		&cond_unknown_13 } // 13
+	{ "in.motion.using.mouse", "",		&cond_unknown_13 }			// 13
 };
 
-AgiInstruction logicNamesCmd[] = {
+AgiInstruction insV2[] = {
 	{ "return",				"",			NULL },
 	{ "increment",			"v",		&cmd_increment },
 	{ "decrement",			"v",		&cmd_decrement },
@@ -237,11 +362,24 @@ AgiInstruction logicNamesCmd[] = {
 void AgiEngine::setupOpcodes() {
 	for (int i = 0; i < 256; ++i)
 		_agiCondCommands[i] = &cond_unknown;
-	for (int i = 0; i <= ARRAYSIZE(logicNamesTest); ++i)
-		_agiCondCommands[i] = logicNamesTest[i].func;
 
-	for (int i = 0; i < ARRAYSIZE(logicNamesCmd); ++i)
-		_agiCommands[i] = logicNamesCmd[i].func;
+	if (getVersion() >= 0x2000) {
+		for (int i = 0; i <= ARRAYSIZE(insV2Test); ++i)
+			_agiCondCommands[i] = insV2Test[i].func;
+		for (int i = 0; i < ARRAYSIZE(insV2); ++i)
+			_agiCommands[i] = insV2[i].func;
+
+		logicNamesTest = insV2Test;
+		logicNamesCmd = insV2;
+	} else {
+		for (int i = 0; i <= ARRAYSIZE(insV1Test); ++i)
+			_agiCondCommands[i] = insV1Test[i].func;
+		for (int i = 0; i < ARRAYSIZE(insV1); ++i)
+			_agiCommands[i] = insV1[i].func;
+
+		logicNamesTest = insV1Test;
+		logicNamesCmd = insV1;
+	}
 }
 
 }
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 075bd27..3c733ce 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -35,8 +35,8 @@ struct AgiInstruction {
 	int argumentsLength() { return strlen(args); }
 };
 
-extern AgiInstruction logicNamesTest[];
-extern AgiInstruction logicNamesCmd[];
+extern AgiInstruction *logicNamesTest;
+extern AgiInstruction *logicNamesCmd;
 
 void cmd_increment(AgiGame *state, uint8 *p);
 void cmd_decrement(AgiGame *state, uint8 *p);


Commit: c731f1f48c780ed09db03c8c5347d5e96da886ac
    https://github.com/scummvm/scummvm/commit/c731f1f48c780ed09db03c8c5347d5e96da886ac
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:03-07:00

Commit Message:
AGI: Implement common internal dictionary for different words.tok formats

Preparations for V1 words.tok support.

Changed paths:
    engines/agi/agi.h
    engines/agi/words.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 2ba617f..368aecf 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -626,6 +626,9 @@ struct AgiGame {
 
 	AgiLogic *_curLogic;
 
+	// words
+	Common::Array<AgiWord*> words[26];
+
 	// view table
 	VtEntry viewTable[MAX_VIEWTABLE];
 
@@ -1018,6 +1021,7 @@ public:
 	bool isEgoView(const VtEntry *v);
 
 	// Words
+public:
 	int showWords();
 	int loadWords(const char *);
 	void unloadWords();
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 4b96fdf..4004abd 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -20,19 +20,12 @@
  *
  */
 
-//
-// New find_word algorithm by Thomas Akesson <tapilot at home.se>
-//
-
 #include "agi/agi.h"
 
 #include "common/textconsole.h"
 
 namespace Agi {
 
-static uint8 *words;		// words in the game
-static uint32 wordsFlen;	// length of word memory
-
 //
 // Local implementation to avoid problems with strndup() used by
 // gcc 3.2 Cygwin (see #635984)
@@ -45,10 +38,6 @@ static char *myStrndup(const char *src, int n) {
 
 int AgiEngine::loadWords(const char *fname) {
 	Common::File fp;
-	uint32 flen;
-	uint8 *mem = NULL;
-
-	words = NULL;
 
 	if (!fp.open(fname)) {
 		warning("loadWords: can't open %s", fname);
@@ -56,85 +45,70 @@ int AgiEngine::loadWords(const char *fname) {
 	}
 	debug(0, "Loading dictionary: %s", fname);
 
-	fp.seek(0, SEEK_END);
-	flen = fp.pos();
-	wordsFlen = flen;
-	fp.seek(0, SEEK_SET);
-
-	if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) {
-		fp.close();
-		return errNotEnoughMemory;
+	// Loop through alphabet, as words in the dictionary file are sorted by
+	// first character
+	for (int i = 0; i < 26; i++) {
+		fp.seek(i * 2, SEEK_SET);
+		int offset = fp.readUint16BE();
+		if (offset == 0)
+			continue;
+		fp.seek(offset, SEEK_SET);
+		int k = fp.readByte();
+		while (!fp.eos() && !fp.err()) {
+			// Read next word
+			char c, str[64];
+			do {
+				c = fp.readByte();
+				str[k++] = (c ^ 0x7F) & 0x7F;
+			} while (!(c & 0x80) && k < (int)sizeof(str) - 1);
+			str[k] = 0;
+
+			// And store it in our internal dictionary
+			AgiWord *w = new AgiWord;
+			w->word = myStrndup(str, k);
+			w->id = fp.readUint16BE();
+			_game.words[i].push_back(w);
+
+			// Are there more words with an already known prefix?
+			if (!(k = fp.readByte()))
+				break;
+		}
 	}
 
-	fp.read(mem, flen);
-	fp.close();
-
-	words = mem;
-
 	return errOK;
 }
 
 void AgiEngine::unloadWords() {
-	free(words);
-	words = NULL;
+	for (int i = 0; i < 26; i++)
+		_game.words[i].clear();
 }
 
 /**
  * Find a word in the dictionary
  * Uses an algorithm hopefully like the one Sierra used. Returns the ID
  * of the word and the length in flen. Returns -1 if not found.
- *
- * Thomas Akesson, November 2001
  */
 int AgiEngine::findWord(const char *word, int *flen) {
-	int mchr = 0;		// matched chars
-	int len, fchr, id = -1;
-	const uint8 *p = words;
-	const uint8 *q = words + wordsFlen;
-	*flen = 0;
+	int c;
 
 	debugC(2, kDebugLevelScripts, "find_word(%s)", word);
 
 	if (word[0] >= 'a' && word[0] <= 'z')
-		fchr = word[0] - 'a';
+		c = word[0] - 'a';
 	else
 		return -1;
 
-	len = strlen(word);
-
-	// Get the offset to the first word beginning with the
-	// right character
-	p += READ_BE_UINT16(p + 2 * fchr);
-
-	while (p[0] >= mchr) {
-		if (p[0] == mchr) {
-			p++;
-			// Loop through all matching characters
-			while ((p[0] ^ word[mchr]) == 0x7F && mchr < len) {
-				mchr++;
-				p++;
-			}
-			// Check if this is the last character of the word
-			// and if it matches
-			if ((p[0] ^ word[mchr]) == 0xFF && mchr < len) {
-				mchr++;
-				if (word[mchr] == 0 || word[mchr] == 0x20) {
-					id = READ_BE_UINT16(p + 1);
-					*flen = mchr;
-				}
-			}
+	*flen = 0;
+	Common::Array<AgiWord*> &a = _game.words[c];
+	for (int i = 0; i < (int)a.size(); i++) {
+		int wlen = strlen(a[i]->word);
+		if (!strncmp(a[i]->word, word, wlen) && (word[wlen] == 0 || word[wlen] == 0x20)) {
+			*flen = wlen;
+			return a[i]->id;
 		}
-		if (p >= q)
-			return -1;
-
-		// Step to the next word
-		while (p[0] < 0x80)
-			p++;
-
-		p += 3;
 	}
 
-	return id;
+	return -1;
 }
 
 void AgiEngine::dictionaryWords(char *msg) {


Commit: 368a3722a3cae2326efaf124608605058b274cd5
    https://github.com/scummvm/scummvm/commit/368a3722a3cae2326efaf124608605058b274cd5
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:05-07:00

Commit Message:
AGI: Implement loader for V1 words.tok dictionary

Changed paths:
    engines/agi/agi.h
    engines/agi/loader_v1.cpp
    engines/agi/words.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 368aecf..3e644da 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -1024,6 +1024,7 @@ public:
 public:
 	int showWords();
 	int loadWords(const char *);
+	int loadWords_v1(Common::File &f);
 	void unloadWords();
 	int findWord(const char *word, int *flen);
 	void dictionaryWords(char *);
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index ab350cd..02a20c9 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -26,33 +26,25 @@
 #define IMAGE_SIZE 368640 // = 40 * 2 * 9 * 512 = tracks * sides * sectors * sector size
 #define SECTOR_OFFSET(s) ((s) * 512)
 
-
 #define DDP_BASE_SECTOR	0x1C2
-
 #define DDP_LOGDIR_SEC	SECTOR_OFFSET(171) + 5
 #define DDP_LOGDIR_MAX	43
-
 #define DDP_PICDIR_SEC	SECTOR_OFFSET(180) + 5
 #define DDP_PICDIR_MAX	30
-
 #define DDP_VIEWDIR_SEC	SECTOR_OFFSET(189) + 5
 #define DDP_VIEWDIR_MAX	171
-
 #define DDP_SNDDIR_SEC	SECTOR_OFFSET(198) + 5
 #define DDP_SNDDIR_MAX	64
 
-
 #define BC_LOGDIR_SEC	SECTOR_OFFSET(90) + 5
 #define BC_LOGDIR_MAX	118
-
 #define BC_VIEWDIR_SEC	SECTOR_OFFSET(96) + 5
 #define BC_VIEWDIR_MAX	180
-
 #define BC_PICDIR_SEC	SECTOR_OFFSET(93) + 8
 #define BC_PICDIR_MAX	117
-
 #define BC_SNDDIR_SEC	SECTOR_OFFSET(99) + 5
 #define BC_SNDDIR_MAX	29
+#define BC_WORDS		SECTOR_OFFSET(0x26D) + 5
 
 namespace Agi {
 
@@ -321,9 +313,14 @@ int AgiLoader_v1::loadObjects(const char *fname) {
 	return _vm->loadObjects(fname);
 }
 
-// TODO: Find the disk image equivalent.
 int AgiLoader_v1::loadWords(const char *fname) {
-	return _vm->loadWords(fname);
+	if (_vm->getGameID() == GID_BC) {
+		Common::File f;
+		f.open(_filenameDisk0);
+		f.seek(BC_WORDS, SEEK_SET);
+		return _vm->loadWords_v1(f);
+	}
+	return errOK;
 }
 
 }
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 4004abd..8b53e9d 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -36,6 +36,33 @@ static char *myStrndup(const char *src, int n) {
 	return tmp;
 }
 
+int AgiEngine::loadWords_v1(Common::File &f) {
+	char str[64];
+	int k;
+	
+	// Loop through alphabet, as words in the dictionary file are sorted by
+	// first character
+	f.seek(f.pos() + 26 * 2, SEEK_SET);
+	do {
+		// Read next word
+		for (k = 0; k < (int)sizeof(str) - 1; k++) {
+			str[k] = f.readByte();
+			if (str[k] == 0 || (uint8)str[k] == 0xFF)
+				break;
+		}
+
+		// And store it in our internal dictionary
+		if (k > 0) {
+			AgiWord *w = new AgiWord;
+			w->word = myStrndup(str, k + 1);
+			w->id = f.readUint16LE();
+			_game.words[str[0] - 'a'].push_back(w);
+		}
+	} while((uint8)str[0] != 0xFF);
+
+	return errOK;
+}
+
 int AgiEngine::loadWords(const char *fname) {
 	Common::File fp;
 
@@ -50,8 +77,7 @@ int AgiEngine::loadWords(const char *fname) {
 	for (int i = 0; i < 26; i++) {
 		fp.seek(i * 2, SEEK_SET);
 		int offset = fp.readUint16BE();
-		if (offset == 0)
-			continue;
+		if (offset == 0) continue;
 		fp.seek(offset, SEEK_SET);
 		int k = fp.readByte();
 		while (!fp.eos() && !fp.err()) {


Commit: d02251fa4df9dc9e575a8f7e6705f5ef8384a2fd
    https://github.com/scummvm/scummvm/commit/d02251fa4df9dc9e575a8f7e6705f5ef8384a2fd
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:08-07:00

Commit Message:
AGI: Formatting (+ a few debug prints)

Changed paths:
    engines/agi/detection_tables.h
    engines/agi/words.cpp



diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index be9bc1e..100719c 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -37,7 +37,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver, \
+		ver \
 	}
 
 #define GAME_LVFPNF(id,name,fname,md5,size,lang,ver,features,gid,platform,interp) { \
@@ -53,7 +53,7 @@ using Common::GUIO_NONE;
 		gid, \
 		interp, \
 		features, \
-		ver, \
+		ver \
 	}
 
 #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
@@ -196,7 +196,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GOLDRUSH,
 		GType_V3,
 		GF_MACGOLDRUSH,
-		0x3149,
+		0x3149
 	},
 
 
@@ -514,7 +514,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_SQ2,
 		GType_V2,
 		0,
-		0x2936,
+		0x2936
 	},
 
 
@@ -659,7 +659,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V2,
 		GF_AGDS,
-		0x2440,
+		0x2440
 	},
 
 	{
@@ -676,7 +676,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_GETOUTTASQ,
 		GType_V2,
 		0,
-		0x2440,
+		0x2440
 	},
 
 	FANMADE_F("Half-Death - Terror At White-Mesa", "b62c05d0ace878261392073f57ae788c", GF_AGIMOUSE),
@@ -831,7 +831,7 @@ static const AGIGameDescription gameDescriptions[] = {
 		GID_FANMADE,
 		GType_V3,
 		GF_FANMADE,
-		0x3149,
+		0x3149
 	},
 	FANMADE_SVP("V - The Graphical Adventure", "1646eaade74f137a9041eb427a389969", 768, 0x2440, Common::kPlatformCoCo3),
 
@@ -859,7 +859,7 @@ static AGIGameDescription g_fallbackDesc = {
 	GID_FANMADE,
 	GType_V2,
 	GF_FANMADE,
-	0x2917,
+	0x2917
 };
 
 /**
diff --git a/engines/agi/words.cpp b/engines/agi/words.cpp
index 8b53e9d..ec6928f 100644
--- a/engines/agi/words.cpp
+++ b/engines/agi/words.cpp
@@ -39,6 +39,8 @@ static char *myStrndup(const char *src, int n) {
 int AgiEngine::loadWords_v1(Common::File &f) {
 	char str[64];
 	int k;
+
+	debug(0, "Loading dictionary");
 	
 	// Loop through alphabet, as words in the dictionary file are sorted by
 	// first character
@@ -57,6 +59,7 @@ int AgiEngine::loadWords_v1(Common::File &f) {
 			w->word = myStrndup(str, k + 1);
 			w->id = f.readUint16LE();
 			_game.words[str[0] - 'a'].push_back(w);
+			debug(3, "'%s' (%d)", w->word, w->id);
 		}
 	} while((uint8)str[0] != 0xFF);
 
@@ -77,7 +80,8 @@ int AgiEngine::loadWords(const char *fname) {
 	for (int i = 0; i < 26; i++) {
 		fp.seek(i * 2, SEEK_SET);
 		int offset = fp.readUint16BE();
-		if (offset == 0) continue;
+		if (offset == 0)
+			continue;
 		fp.seek(offset, SEEK_SET);
 		int k = fp.readByte();
 		while (!fp.eos() && !fp.err()) {


Commit: 9bc25749d6433b3c7c843406d04ad49b1bd1fd77
    https://github.com/scummvm/scummvm/commit/9bc25749d6433b3c7c843406d04ad49b1bd1fd77
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:10-07:00

Commit Message:
AGI: Implement V1 SAID test commands

Yes, V1 has three versions of SAID, for one, two and three arguments.

Also add a few corrections to V1 instruction tables.

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index a000453..f488bda 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1574,6 +1574,16 @@ void cmd_shake_screen(AgiGame *state, uint8 *p) {
 	state->inputEnabled = originalValue;
 }
 
+void cmd_set_speed(AgiGame *state, uint8 *p) {
+	// V1 command
+	(void)state;
+	(void)p;
+}
+
+void cmd_unknown(AgiGame *state, uint8 *p) {
+	warning("Skipping unknown opcode %2X", *(p - 1));
+}
+
 /**
  * Execute a logic script
  * @param n  Number of the logic resource to execute
@@ -1659,7 +1669,6 @@ int AgiEngine::runLogic(int n) {
 
 			debugC(2, kDebugLevelScripts, "%s%s(%d %d %d)", st, logicNamesCmd[op].name, p[0], p[1], p[2]);
 
-//			(this->*_agiCommands[op])(&_game, p);
 			_agiCommands[op](&_game, p);
 			ip += num;
 		}
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 7ccd30e..ee4f99b 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -23,6 +23,7 @@
 
 #include "agi/agi.h"
 #include "agi/opcodes.h"
+#include "common/endian.h"
 
 namespace Agi {
 
@@ -83,6 +84,10 @@ void cond_issetv(AgiGame *state, uint8 *p) {
 	state->ec = testIsSet(getvar(p[1]));
 }
 
+void cond_isset_v1(AgiGame *state, uint8 *p) {
+	state->ec = getvar(p[0]) > 0;
+}
+
 void cond_has(AgiGame *state, uint8 *p) {
 	state->ec = testHas(p[0]);
 }
@@ -108,6 +113,48 @@ void cond_said(AgiGame *state, uint8 *p) {
 	state->ec = ec;
 }
 
+void cond_said1(AgiGame *state, uint8 *p) {
+	state->ec = false;
+
+	if (!getflag(fEnteredCli))
+		return;
+
+	int id0 = READ_LE_UINT16(p);
+
+	if ((id0 == 1 || id0 == state->egoWords[0].id))
+		state->ec = true;
+}
+
+void cond_said2(AgiGame *state, uint8 *p) {
+	state->ec = false;
+
+	if (!getflag(fEnteredCli))
+		return;
+
+	int id0 = READ_LE_UINT16(p);
+	int id1 = READ_LE_UINT16(p + 2);
+
+	if ((id0 == 1 || id0 == state->egoWords[0].id) &&
+		(id1 == 1 || id1 == state->egoWords[1].id))
+		state->ec = true;
+}
+
+void cond_said3(AgiGame *state, uint8 *p) {
+	state->ec = false;
+
+	if (!getflag(fEnteredCli))
+		return;
+
+	int id0 = READ_LE_UINT16(p);
+	int id1 = READ_LE_UINT16(p + 2);
+	int id2 = READ_LE_UINT16(p + 4);
+
+	if ((id0 == 1 || id0 == state->egoWords[0].id) &&
+		(id1 == 1 || id1 == state->egoWords[1].id) &&
+		(id2 == 1 || id2 == state->egoWords[2].id))
+		state->ec = true;
+}
+
 void cond_compare_strings(AgiGame *state, uint8 *p) {
 	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
 	state->ec = state->_vm->testCompareStrings(p[0], p[1]);
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 70ba1fa..d9618bc 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -36,18 +36,16 @@ AgiInstruction insV1Test[] = {
 	{ "lessv",				"vv",		&cond_lessv },			// 04
 	{ "greatern",			"vn",		&cond_greater },		// 05
 	{ "greaterv",			"vv",		&cond_greaterv },		// 06
-	{ "isset",				"n",		&cond_isset },			// 07
-	{ "issetv",				"v",		&cond_issetv },			// 08
-	{ "...",				"nnnn",		NULL },					// 09
+	{ "isset",				"v",		&cond_isset_v1 },		// 07
+	{ "has",				"n",		&cond_has },			// 08
+	{ "said",				"nnnn",		&cond_said2 },			// 09
 	{ "posn",				"nnnnn",	&cond_posn },			// 0A
 	{ "controller",			"n",		&cond_controller },		// 0B
-	{ "...",				"nn",		NULL },					// 0C
-	{ "...",				"",			NULL },					// 0D
+	{ "obj.in.room",		"nv",		&cond_obj_in_room },	// 0C
+	{ "said",				"nnnnnn",	&cond_said3 },			// 0D
 	{ "have.key",			"",			&cond_have_key },		// 0E
-	{ "...",				"nn",		NULL },					// 0F
-	{ "bit",				"nv",		NULL },					// 10
-	{ "...",				"nnnnn",	NULL },					// 11
-	{ "...",				"nnnnn",	NULL },					// 12
+	{ "said",				"nn",		&cond_said1 },			// 0F
+	{ "bit",				"nv",		&cond_unknown },		// 10
 };
 
 AgiInstruction insV1[] = {
@@ -68,7 +66,7 @@ AgiInstruction insV1[] = {
 	{ "status",				"",			&cmd_status },				// 0E
 	{ "save.game",			"",			&cmd_save_game },			// 0F
 	{ "restore.game",		"",			&cmd_load_game },			// 10
-	{ "...",				"",			NULL },						// 11
+	{ "...",				"",			&cmd_init_disk },			// 11 TODO
 	{ "restart.game",		"",			&cmd_restart_game },		// 12
 	{ "random",				"v",		&cmd_random },				// 13 TODO: 1 vs 3 vars
 	{ "get",				"n",		&cmd_get },					// 14
@@ -85,8 +83,8 @@ AgiInstruction insV1[] = {
 	{ "move.obj",			"nnnnn",	&cmd_move_obj },			// 1F
 	{ "set.view",			"nn",		&cmd_set_view },			// 20
 	{ "follow.ego",			"nnn",		&cmd_follow_ego },			// 21
-	{ "...",				"",			NULL },						// 22
-	{ "...",				"",			NULL },						// 23
+	{ "...",				"",			&cmd_unknown },				// 22
+	{ "...",				"",			&cmd_unknown },				// 23
 	{ "ignore.blocks",		"n",		&cmd_ignore_blocks },		// 24
 	{ "observe.blocks",		"n",		&cmd_observe_blocks },		// 25
 	{ "wander",				"n",		&cmd_wander },				// 26
@@ -111,43 +109,43 @@ AgiInstruction insV1[] = {
 	{ "load.sound",			"n",		&cmd_load_sound },			// 39
 	{ "sound",				"nn",		&cmd_sound },				// 3A
 	{ "stop.sound",			"",			&cmd_stop_sound },			// 3B
-	{ "set",				"n",		&cmd_set },					// 3C
-	{ "reset",				"n",		&cmd_reset },				// 3D
-	{ "...",				"n",		NULL },						// 3E
+	{ "set.v",				"v",		&cmd_set_v },				// 3C
+	{ "reset.v",			"v",		&cmd_reset_v },				// 3D
+	{ "toggle.v",			"v",		&cmd_toggle_v },			// 3E
 	{ "new.room.v",			"v",		&cmd_new_room_f },			// 3F
-	{ "...",				"n",		NULL },						// 40
-	{ "...",				"",			NULL },						// 41
-	{ "...",				"v",		NULL },						// 42
+	{ "call",				"n",		&cmd_call },				// 40
+	{ "...",				"",			&cmd_unknown },				// 41
+	{ "set.speed",			"v",		&cmd_set_speed },			// 42
 	{ "move.obj.v",			"nvvvv",	&cmd_move_obj_f },			// 43
-	{ "...",				"",			NULL },						// 44
-	{ "...",				"",			NULL },						// 45
-	{ "...",				"",			NULL },						// 46
-	{ "...",				"",			NULL },						// 47
-	{ "...",				"nv",		NULL },						// 48 get.priority??
+	{ "...",				"",			&cmd_unknown },				// 44
+	{ "...",				"",			&cmd_unknown },				// 45
+	{ "...",				"",			&cmd_unknown },				// 46
+	{ "...",				"",			&cmd_unknown },				// 47
+	{ "...",				"nv",		&cmd_unknown },				// 48 get.priority??
 	{ "ignore.objs",		"n",		&cmd_ignore_objs },			// 49
 	{ "observe.objs",		"n",		&cmd_observe_objs },		// 4A
 	{ "distance",			"nnv",		&cmd_distance },			// 4B
 	{ "object.on.land",		"n",		&cmd_object_on_land },		// 4C
-	{ "...",				"nv",		NULL },						// 4D set.priority.v???
-	{ "...",				"",			NULL },						// 4E
-	{ "...",				"n",		NULL },						// 4F
+	{ "...",				"nv",		&cmd_unknown },				// 4D set.priority.v???
+	{ "...",				"",			&cmd_unknown },				// 4E
+	{ "load.logics",		"n",		&cmd_load_logic },			// 4F TODO: what is the other load.logics then?
 	{ "display",			"nnns",		&cmd_display },				// 50 TODO: 4 vs 3 args
-	{ "prevent.input???",	"",			NULL },						// 51
-	{ "...",				"",			NULL },						// 52
-	{ "...",				"n",		NULL },						// 53 ???
-	{ "...",				"",			NULL },						// 54 ???
+	{ "prevent.input???",	"",			&cmd_unknown },				// 51
+	{ "...",				"",			&cmd_unknown },				// 52
+	{ "...",				"n",		&cmd_unknown },				// 53 ???
+	{ "...",				"",			&cmd_unknown },				// 54 ???
 	{ "stop.motion",		"",			&cmd_stop_motion },			// 55 or force.update??
 	{ "discard.view",		"n",		&cmd_discard_view },		// 56
 	{ "discard.pic",		"v",		&cmd_discard_pic },			// 57
-	{ "...",				"nn",		NULL },						// 58
-	{ "...",				"",			NULL },						// 59
+	{ "...",				"nn",		&cmd_unknown },				// 58
+	{ "...",				"",			&cmd_unknown },				// 59
 	{ "last.cel",			"nv",		&cmd_last_cel },			// 5A
 	{ "set.cel.v",			"nv",		&cmd_set_cel_f },			// 5B
-	{ "...",				"",			NULL },						// 5C
-	{ "...",				"n",		NULL },						// 5D
-	{ "...",				"",			NULL },						// 5E
-	{ "...",				"",			NULL },						// 5F
-	{ "setbit",				"nv",		NULL },						// 60
+	{ "...",				"",			&cmd_unknown },				// 5C
+	{ "load.view",			"n",		&cmd_load_view },			// 5D
+	{ "...",				"",			&cmd_unknown },				// 5E
+	{ "...",				"",			&cmd_unknown },				// 5F
+	{ "setbit",				"nv",		&cmd_unknown },				// 60
 };
 
 AgiInstruction insV2Test[] = {
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 3c733ce..3939b2d 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -221,6 +221,9 @@ void cmd_mouse_posn(AgiGame *state, uint8 *p);
 void cmd_release_key(AgiGame *state, uint8 *p);
 void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p);
 
+void cmd_set_speed(AgiGame *state, uint8 *p);
+void cmd_unknown(AgiGame *state, uint8 *p);
+
 void cond_equal(AgiGame *state, uint8 *p);
 void cond_equalv(AgiGame *state, uint8 *p);
 void cond_less(AgiGame *state, uint8 *p);
@@ -242,6 +245,11 @@ void cond_right_posn(AgiGame *state, uint8 *p);
 void cond_unknown_13(AgiGame *state, uint8 *p);
 void cond_unknown(AgiGame *state, uint8 *p);
 
+void cond_isset_v1(AgiGame *state, uint8 *p);
+void cond_said1(AgiGame *state, uint8 *p);
+void cond_said2(AgiGame *state, uint8 *p);
+void cond_said3(AgiGame *state, uint8 *p);
+
 } // End of namespace Agi
 
 #endif /* AGI_OPCODES_H */


Commit: 09f937126e2db931b5dcfec85460973d45cc87f1
    https://github.com/scummvm/scummvm/commit/09f937126e2db931b5dcfec85460973d45cc87f1
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:13-07:00

Commit Message:
AGI: Fix and clarify IF expression handling

Changed paths:
    engines/agi/agi.h
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 3e644da..48a9aa5 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -639,8 +639,7 @@ struct AgiGame {
 	Common::Rect mouseFence;		/**< rectangle set by fence.mouse command */
 
 	// IF condition handling
-	int endTest;
-	int ec;
+	int testResult;
 };
 
 /**
@@ -989,6 +988,8 @@ public:
 
 public:
 	// Some submethods of testIfCode
+	void skipInstruction(byte op);
+	void skipInstructionsUntil(byte v);
 	uint8 testObjRight(uint8, uint8, uint8, uint8, uint8);
 	uint8 testObjCenter(uint8, uint8, uint8, uint8, uint8);
 	uint8 testObjInBox(uint8, uint8, uint8, uint8, uint8);
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index ee4f99b..230ed97 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -43,78 +43,78 @@ namespace Agi {
 void cond_equal(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testEqual(p[0], p[1]);
+	state->testResult = testEqual(p[0], p[1]);
 }
 
 void cond_equalv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testEqual(p[0], getvar(p[1]));
+	state->testResult = testEqual(p[0], getvar(p[1]));
 }
 
 void cond_less(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testLess(p[0], p[1]);
+	state->testResult = testLess(p[0], p[1]);
 }
 
 void cond_lessv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testLess(p[0], getvar(p[1]));
+	state->testResult = testLess(p[0], getvar(p[1]));
 }
 
 void cond_greater(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testGreater(p[0], p[1]);
+	state->testResult = testGreater(p[0], p[1]);
 }
 
 void cond_greaterv(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
-	state->ec = testGreater(p[0], getvar(p[1]));
+	state->testResult = testGreater(p[0], getvar(p[1]));
 }
 
 void cond_isset(AgiGame *state, uint8 *p) {
-	state->ec = testIsSet(p[0]);
+	state->testResult = testIsSet(p[0]);
 }
 
 void cond_issetv(AgiGame *state, uint8 *p) {
-	state->ec = testIsSet(getvar(p[1]));
+	state->testResult = testIsSet(getvar(p[1]));
 }
 
 void cond_isset_v1(AgiGame *state, uint8 *p) {
-	state->ec = getvar(p[0]) > 0;
+	state->testResult = getvar(p[0]) > 0;
 }
 
 void cond_has(AgiGame *state, uint8 *p) {
-	state->ec = testHas(p[0]);
+	state->testResult = testHas(p[0]);
 }
 
 void cond_obj_in_room(AgiGame *state, uint8 *p) {
-	state->ec = testObjInRoom(p[0], p[1]);
+	state->testResult = testObjInRoom(p[0], p[1]);
 }
 
 void cond_posn(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
+	state->testResult = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_controller(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testController(p[0]);
+	state->testResult = state->_vm->testController(p[0]);
 }
 
 void cond_have_key(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testKeypressed();
+	state->testResult = state->_vm->testKeypressed();
 }
 
 void cond_said(AgiGame *state, uint8 *p) {
 	int ec = state->_vm->testSaid(p[0], p + 1);
-	state->ec = ec;
+	state->testResult = ec;
 }
 
 void cond_said1(AgiGame *state, uint8 *p) {
-	state->ec = false;
+	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
 		return;
@@ -122,11 +122,11 @@ void cond_said1(AgiGame *state, uint8 *p) {
 	int id0 = READ_LE_UINT16(p);
 
 	if ((id0 == 1 || id0 == state->egoWords[0].id))
-		state->ec = true;
+		state->testResult = true;
 }
 
 void cond_said2(AgiGame *state, uint8 *p) {
-	state->ec = false;
+	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
 		return;
@@ -136,11 +136,11 @@ void cond_said2(AgiGame *state, uint8 *p) {
 
 	if ((id0 == 1 || id0 == state->egoWords[0].id) &&
 		(id1 == 1 || id1 == state->egoWords[1].id))
-		state->ec = true;
+		state->testResult = true;
 }
 
 void cond_said3(AgiGame *state, uint8 *p) {
-	state->ec = false;
+	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
 		return;
@@ -152,24 +152,24 @@ void cond_said3(AgiGame *state, uint8 *p) {
 	if ((id0 == 1 || id0 == state->egoWords[0].id) &&
 		(id1 == 1 || id1 == state->egoWords[1].id) &&
 		(id2 == 1 || id2 == state->egoWords[2].id))
-		state->ec = true;
+		state->testResult = true;
 }
 
 void cond_compare_strings(AgiGame *state, uint8 *p) {
 	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
-	state->ec = state->_vm->testCompareStrings(p[0], p[1]);
+	state->testResult = state->_vm->testCompareStrings(p[0], p[1]);
 }
 
 void cond_obj_in_box(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
+	state->testResult = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_center_posn(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
+	state->testResult = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_right_posn(AgiGame *state, uint8 *p) {
-	state->ec = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
+	state->testResult = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
 }
 
 void cond_unknown_13(AgiGame *state, uint8 *p) {
@@ -181,11 +181,12 @@ void cond_unknown_13(AgiGame *state, uint8 *p) {
 	// TODO: Check this command's implementation using disassembly just to be sure.
 	int ec = state->viewTable[0].flags & ADJ_EGO_XY;
 	debugC(7, kDebugLevelScripts, "op_test: in.motion.using.mouse = %s (Amiga-specific testcase 19)", ec ? "true" : "false");
-	state->ec = ec;
+	state->testResult = ec;
 }
 
 void cond_unknown(AgiGame *state, uint8 *p) {
-	state->endTest = true;
+	warning("Skipping unknown test command %2X", *(p - 1));
+	state->testResult = false;
 }
 
 uint8 AgiEngine::testCompareStrings(uint8 s1, uint8 s2) {
@@ -356,88 +357,109 @@ uint8 AgiEngine::testSaid(uint8 nwords, uint8 *cc) {
 
 int AgiEngine::testIfCode(int lognum) {
 	AgiGame *state = &_game;
-	uint8 op = 0;
-	uint8 p[16] = { 0 };
-
-	state->ec = true;
-	int notTest = false;
-	int orTest = false;
-	int orVal = false;
-	state->endTest = false;
-	int testVal = true;
-	int skipTest = false;
-	int skipOr = false;
-
-	while (!(shouldQuit() || _restartGame) && !state->endTest) {
+	uint8 op;
+	uint8 p[16];
+
+	int notMode = false;
+	int orMode = false;
+	int endTest = false;
+	int result = true;
+
+	while (!(shouldQuit() || _restartGame) && !endTest) {
 		if (_debug.enabled && (_debug.logic0 || lognum))
 			debugConsole(lognum, lTEST_MODE, NULL);
 
 		op = *(code + ip++);
 		memmove(p, (code + ip), 16);
 
-		// Execute test command if needed
 		switch (op) {
 		case 0xFC:
-			skipOr = false;
-			if (orTest) {
-				orTest = false;
-				testVal &= orVal;
-				if (!orVal)
-					skipTest = true;
+			if (orMode) {
+				// We have reached the end of an OR expression without
+				// a single test command evaluating as true. Thus the OR
+				// expression evalutes as false which means the whole
+				// expression evaluates as false. So skip until the
+				// ending 0xFF and return.
+				skipInstructionsUntil(0xFF);
+				result = false;
+				endTest = true;
 			} else {
-				orTest = true;
-				orVal = false;
+				orMode = true;
 			}
 			continue;
 		case 0xFD:
-			notTest = true;
+			notMode = true;
 			continue;
 		case 0x00:
 		case 0xFF:
-			state->endTest = true;
+			endTest = true;
 			continue;
 		
 		default:
-			if (!skipTest && !skipOr) {
-				_agiCondCommands[op](state, p);
-
-				// not is only enabled for 1 test command
-				if (notTest)
-					state->ec = !state->ec;
-				notTest = false;
-
-				if (orTest) {
-					orVal |= state->ec;
-					if (state->ec)
-						skipOr = true;
-				} else {
-					testVal &= state->ec;
-					if (!state->ec)
-						skipTest = true;
+			// Evaluate the command and skip the rest of the instruction
+			_agiCondCommands[op](state, p);
+			skipInstruction(op);
+
+			// NOT mode is enabled only for one instruction
+			if (notMode)
+				state->testResult = !state->testResult;
+			notMode = false;
+
+			if (orMode) {
+				if (state->testResult) {
+					// We are in OR mode and the last test command evaluated
+					// as true, thus the whole OR expression evaluates as
+					// true. So skip the rest of the OR expression and
+					// continue normally.
+					skipInstructionsUntil(0xFC);
+					orMode = false;
+					continue;
+				}
+			} else {
+				result &= state->testResult;
+				if (!result) {
+					// Since we are in AND mode and the last test command
+					// evaluated as false, the whole expression also evaluates
+					// as false. So skip until the ending 0xFF and return.
+					skipInstructionsUntil(0xFF);
+					endTest = true;
+					continue;
 				}
 			}
 			break;
 		}
-
-		// Skip the instruction
-		if (op <= 0x13) {
-			if (op == 0x0E) // said()
-				ip += *(code + ip) * 2 + 1;
-			else
-				ip += logicNamesTest[op].argumentsLength();
-		}
 	}
 
 	// Skip the following IF block if the condition evaluates as false
-	if (testVal)
+	if (result)
 		ip += 2;
 	else
 		ip += READ_LE_UINT16(code + ip) + 2;
 
 	if (_debug.enabled && (_debug.logic0 || lognum))
-		debugConsole(lognum, 0xFF, testVal ? "=true" : "=false");
+		debugConsole(lognum, 0xFF, result ? "=true" : "=false");
+
+	return result;
+}
 
-	return testVal;
+void AgiEngine::skipInstruction(byte op) {
+	AgiGame *state = &_game;
+	if (op >= 0xFC)
+		return;
+	if (op == 0x0E) // said
+		ip += *(code + ip) * 2 + 1;
+	else
+		ip += logicNamesTest[op].argumentsLength();
+}
+
+void AgiEngine::skipInstructionsUntil(byte v) {
+	AgiGame *state = &_game;
+	while (1) {
+		byte op = *(code + ip++);
+		if (op == v)
+			return;
+		skipInstruction(op);
+	}
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index d9618bc..d700764 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -29,7 +29,7 @@ AgiInstruction *logicNamesTest;
 AgiInstruction *logicNamesCmd;
 
 AgiInstruction insV1Test[] = {
-	{ "",					"",			NULL },					// 00
+	{ "",					"",			&cond_unknown },		// 00
 	{ "equaln",				"vn",		&cond_equal },			// 01
 	{ "equalv",				"vv",		&cond_equalv },			// 02
 	{ "lessn",				"vn",		&cond_less },			// 03
@@ -149,7 +149,7 @@ AgiInstruction insV1[] = {
 };
 
 AgiInstruction insV2Test[] = {
-	{ "",					"",			NULL },						// 00
+	{ "",					"",			&cond_unknown },			// 00
 	{ "equaln",				"vn",		&cond_equal },				// 01
 	{ "equalv",				"vv",		&cond_equalv },				// 02
 	{ "lessn",				"vn",		&cond_less },				// 03
@@ -358,9 +358,6 @@ AgiInstruction insV2[] = {
 };
 
 void AgiEngine::setupOpcodes() {
-	for (int i = 0; i < 256; ++i)
-		_agiCondCommands[i] = &cond_unknown;
-
 	if (getVersion() >= 0x2000) {
 		for (int i = 0; i <= ARRAYSIZE(insV2Test); ++i)
 			_agiCondCommands[i] = insV2Test[i].func;


Commit: 2289ba88b64dd53d48d0d47138a553ab4452adc2
    https://github.com/scummvm/scummvm/commit/2289ba88b64dd53d48d0d47138a553ab4452adc2
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:15-07:00

Commit Message:
AGI: Rename cmd_what_ever to cmdWhatEver

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index f488bda..42c3e57 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -54,17 +54,17 @@ namespace Agi {
 #define setflag(a,b) state->_vm->setflag(a,b)
 #define getflag(a) state->_vm->getflag(a)
 
-void cmd_increment(AgiGame *state, uint8 *p) {
+void cmdIncrement(AgiGame *state, uint8 *p) {
 	if (_v[p0] != 0xff)
 		++_v[p0];
 }
 
-void cmd_decrement(AgiGame *state, uint8 *p) {
+void cmdDecrement(AgiGame *state, uint8 *p) {
 	if (_v[p0] != 0)
 		--_v[p0];
 }
 
-void cmd_assignn(AgiGame *state, uint8 *p) {
+void cmdAssignN(AgiGame *state, uint8 *p) {
 	_v[p0] = p1;
 
 	// WORKAROUND for a bug in fan _game "Get outta SQ"
@@ -78,83 +78,83 @@ void cmd_assignn(AgiGame *state, uint8 *p) {
 		_v[p0] = 8;
 }
 
-void cmd_addn(AgiGame *state, uint8 *p) {
+void cmdAddN(AgiGame *state, uint8 *p) {
 	_v[p0] += p1;
 }
 
-void cmd_subn(AgiGame *state, uint8 *p) {
+void cmdSubN(AgiGame *state, uint8 *p) {
 	_v[p0] -= p1;
 }
 
-void cmd_assignv(AgiGame *state, uint8 *p) {
+void cmdAssignV(AgiGame *state, uint8 *p) {
 	_v[p0] = _v[p1];
 }
 
-void cmd_addv(AgiGame *state, uint8 *p) {
+void cmdAddV(AgiGame *state, uint8 *p) {
 	_v[p0] += _v[p1];
 }
 
-void cmd_subv(AgiGame *state, uint8 *p) {
+void cmdSubV(AgiGame *state, uint8 *p) {
 	_v[p0] -= _v[p1];
 }
 
-void cmd_mul_n(AgiGame *state, uint8 *p) {
+void cmdMulN(AgiGame *state, uint8 *p) {
 	_v[p0] *= p1;
 }
 
-void cmd_mul_v(AgiGame *state, uint8 *p) {
+void cmdMulV(AgiGame *state, uint8 *p) {
 	_v[p0] *= _v[p1];
 }
 
-void cmd_div_n(AgiGame *state, uint8 *p) {
+void cmdDivN(AgiGame *state, uint8 *p) {
 	_v[p0] /= p1;
 }
 
-void cmd_div_v(AgiGame *state, uint8 *p) {
+void cmdDivV(AgiGame *state, uint8 *p) {
 	_v[p0] /= _v[p1];
 }
 
-void cmd_random(AgiGame *state, uint8 *p) {
+void cmdRandom(AgiGame *state, uint8 *p) {
 	_v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
 }
 
-void cmd_lindirectn(AgiGame *state, uint8 *p) {
+void cmdLindirectN(AgiGame *state, uint8 *p) {
 	_v[_v[p0]] = p1;
 }
 
-void cmd_lindirectv(AgiGame *state, uint8 *p) {
+void cmdLindirectV(AgiGame *state, uint8 *p) {
 	_v[_v[p0]] = _v[p1];
 }
 
-void cmd_rindirect(AgiGame *state, uint8 *p) {
+void cmdRindirect(AgiGame *state, uint8 *p) {
 	_v[p0] = _v[_v[p1]];
 }
 
-void cmd_set(AgiGame *state, uint8 *p) {
+void cmdSet(AgiGame *state, uint8 *p) {
 	setflag(*p, true);
 }
 
-void cmd_reset(AgiGame *state, uint8 *p) {
+void cmdReset(AgiGame *state, uint8 *p) {
 	setflag(*p, false);
 }
 
-void cmd_toggle(AgiGame *state, uint8 *p) {
+void cmdToggle(AgiGame *state, uint8 *p) {
 	setflag(*p, !getflag(*p));
 }
 
-void cmd_set_v(AgiGame *state, uint8 *p) {
+void cmdSetV(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], true);
 }
 
-void cmd_reset_v(AgiGame *state, uint8 *p) {
+void cmdResetV(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], false);
 }
 
-void cmd_toggle_v(AgiGame *state, uint8 *p) {
+void cmdToggleV(AgiGame *state, uint8 *p) {
 	setflag(_v[p0], !getflag(_v[p0]));
 }
 
-void cmd_new_room(AgiGame *state, uint8 *p) {
+void cmdNewRoom(AgiGame *state, uint8 *p) {
 	state->_vm->newRoom(p0);
 
 	// WORKAROUND: Works around intro skipping bug (#1737343) in Gold Rush.
@@ -170,79 +170,79 @@ void cmd_new_room(AgiGame *state, uint8 *p) {
 		state->keypress = 0;
 }
 
-void cmd_new_room_f(AgiGame *state, uint8 *p) {
+void cmdNewRoomF(AgiGame *state, uint8 *p) {
 	state->_vm->newRoom(_v[p0]);
 }
 
-void cmd_load_view(AgiGame *state, uint8 *p) {
+void cmdLoadView(AgiGame *state, uint8 *p) {
 	state->_vm->agiLoadResource(rVIEW, p0);
 }
 
-void cmd_load_logic(AgiGame *state, uint8 *p) {
+void cmdLoadLogic(AgiGame *state, uint8 *p) {
 	state->_vm->agiLoadResource(rLOGIC, p0);
 }
 
-void cmd_load_sound(AgiGame *state, uint8 *p) {
+void cmdLoadSound(AgiGame *state, uint8 *p) {
 	state->_vm->agiLoadResource(rSOUND, p0);
 }
 
-void cmd_load_view_f(AgiGame *state, uint8 *p) {
+void cmdLoadViewF(AgiGame *state, uint8 *p) {
 	state->_vm->agiLoadResource(rVIEW, _v[p0]);
 }
 
-void cmd_load_logic_f(AgiGame *state, uint8 *p) {
+void cmdLoadLogicF(AgiGame *state, uint8 *p) {
 	state->_vm->agiLoadResource(rLOGIC, _v[p0]);
 }
 
-void cmd_discard_view(AgiGame *state, uint8 *p) {
+void cmdDiscardView(AgiGame *state, uint8 *p) {
 	state->_vm->agiUnloadResource(rVIEW, p0);
 }
 
-void cmd_object_on_anything(AgiGame *state, uint8 *p) {
+void cmdObjectOnAnything(AgiGame *state, uint8 *p) {
 	vt.flags &= ~(ON_WATER | ON_LAND);
 }
 
-void cmd_object_on_land(AgiGame *state, uint8 *p) {
+void cmdObjectOnLand(AgiGame *state, uint8 *p) {
 	vt.flags |= ON_LAND;
 }
 
-void cmd_object_on_water(AgiGame *state, uint8 *p) {
+void cmdObjectOnWater(AgiGame *state, uint8 *p) {
 	vt.flags |= ON_WATER;
 }
 
-void cmd_observe_horizon(AgiGame *state, uint8 *p) {
+void cmdObserveHorizon(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_HORIZON;
 }
 
-void cmd_ignore_horizon(AgiGame *state, uint8 *p) {
+void cmdIgnoreHorizon(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_HORIZON;
 }
 
-void cmd_observe_objs(AgiGame *state, uint8 *p) {
+void cmdObserveObjs(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_OBJECTS;
 }
 
-void cmd_ignore_objs(AgiGame *state, uint8 *p) {
+void cmdIgnoreObjs(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_OBJECTS;
 }
 
-void cmd_observe_blocks(AgiGame *state, uint8 *p) {
+void cmdObserveBlocks(AgiGame *state, uint8 *p) {
 	vt.flags &= ~IGNORE_BLOCKS;
 }
 
-void cmd_ignore_blocks(AgiGame *state, uint8 *p) {
+void cmdIgnoreBlocks(AgiGame *state, uint8 *p) {
 	vt.flags |= IGNORE_BLOCKS;
 }
 
-void cmd_set_horizon(AgiGame *state, uint8 *p) {
+void cmdSetHorizon(AgiGame *state, uint8 *p) {
 	state->horizon = p0;
 }
 
-void cmd_get_priority(AgiGame *state, uint8 *p) {
+void cmdGetPriority(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.priority;
 }
 
-void cmd_set_priority(AgiGame *state, uint8 *p) {
+void cmdSetPriority(AgiGame *state, uint8 *p) {
 	vt.flags |= FIXED_PRIORITY;
 	vt.priority = p1;
 
@@ -265,242 +265,242 @@ void cmd_set_priority(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_set_priority_f(AgiGame *state, uint8 *p) {
+void cmdSetPriorityF(AgiGame *state, uint8 *p) {
 	vt.flags |= FIXED_PRIORITY;
 	vt.priority = _v[p1];
 }
 
-void cmd_release_priority(AgiGame *state, uint8 *p) {
+void cmdReleasePriority(AgiGame *state, uint8 *p) {
 	vt.flags &= ~FIXED_PRIORITY;
 }
 
-void cmd_set_upper_left(AgiGame *state, uint8 *p) {				// do nothing (AGI 2.917)
+void cmdSetUpperLeft(AgiGame *state, uint8 *p) {				// do nothing (AGI 2.917)
 }
 
-void cmd_start_update(AgiGame *state, uint8 *p) {
+void cmdStartUpdate(AgiGame *state, uint8 *p) {
 	state->_vm->startUpdate(&vt);
 }
 
-void cmd_stop_update(AgiGame *state, uint8 *p) {
+void cmdStopUpdate(AgiGame *state, uint8 *p) {
 	state->_vm->stopUpdate(&vt);
 }
 
-void cmd_current_view(AgiGame *state, uint8 *p) {
+void cmdCurrentView(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentView;
 }
 
-void cmd_current_cel(AgiGame *state, uint8 *p) {
+void cmdCurrentCel(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentCel;
 	debugC(4, kDebugLevelScripts, "v%d=%d", p1, _v[p1]);
 }
 
-void cmd_current_loop(AgiGame *state, uint8 *p) {
+void cmdCurrentLoop(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.currentLoop;
 }
 
-void cmd_last_cel(AgiGame *state, uint8 *p) {
+void cmdLastCel(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.loopData->numCels - 1;
 }
 
-void cmd_set_cel(AgiGame *state, uint8 *p) {
+void cmdSetCel(AgiGame *state, uint8 *p) {
 	state->_vm->setCel(&vt, p1);
 	vt.flags &= ~DONTUPDATE;
 }
 
-void cmd_set_cel_f(AgiGame *state, uint8 *p) {
+void cmdSetCelF(AgiGame *state, uint8 *p) {
 	state->_vm->setCel(&vt, _v[p1]);
 	vt.flags &= ~DONTUPDATE;
 }
 
-void cmd_set_view(AgiGame *state, uint8 *p) {
+void cmdSetView(AgiGame *state, uint8 *p) {
 	state->_vm->setView(&vt, p1);
 }
 
-void cmd_set_view_f(AgiGame *state, uint8 *p) {
+void cmdSetViewF(AgiGame *state, uint8 *p) {
 	state->_vm->setView(&vt, _v[p1]);
 }
 
-void cmd_set_loop(AgiGame *state, uint8 *p) {
+void cmdSetLoop(AgiGame *state, uint8 *p) {
 	state->_vm->setLoop(&vt, p1);
 }
 
-void cmd_set_loop_f(AgiGame *state, uint8 *p) {
+void cmdSetLoopF(AgiGame *state, uint8 *p) {
 	state->_vm->setLoop(&vt, _v[p1]);
 }
 
-void cmd_number_of_loops(AgiGame *state, uint8 *p) {
+void cmdNumberOfLoops(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.numLoops;
 }
 
-void cmd_fix_loop(AgiGame *state, uint8 *p) {
+void cmdFixLoop(AgiGame *state, uint8 *p) {
 	vt.flags |= FIX_LOOP;
 }
 
-void cmd_release_loop(AgiGame *state, uint8 *p) {
+void cmdReleaseLoop(AgiGame *state, uint8 *p) {
 	vt.flags &= ~FIX_LOOP;
 }
 
-void cmd_step_size(AgiGame *state, uint8 *p) {
+void cmdStepSize(AgiGame *state, uint8 *p) {
 	vt.stepSize = _v[p1];
 }
 
-void cmd_step_time(AgiGame *state, uint8 *p) {
+void cmdStepTime(AgiGame *state, uint8 *p) {
 	vt.stepTime = vt.stepTimeCount = _v[p1];
 }
 
-void cmd_cycle_time(AgiGame *state, uint8 *p) {
+void cmdCycleTime(AgiGame *state, uint8 *p) {
 	vt.cycleTime = vt.cycleTimeCount = _v[p1];
 }
 
-void cmd_stop_cycling(AgiGame *state, uint8 *p) {
+void cmdStopCycling(AgiGame *state, uint8 *p) {
 	vt.flags &= ~CYCLING;
 }
 
-void cmd_start_cycling(AgiGame *state, uint8 *p) {
+void cmdStartCycling(AgiGame *state, uint8 *p) {
 	vt.flags |= CYCLING;
 }
 
-void cmd_normal_cycle(AgiGame *state, uint8 *p) {
+void cmdNormalCycle(AgiGame *state, uint8 *p) {
 	vt.cycle = CYCLE_NORMAL;
 	vt.flags |= CYCLING;
 }
 
-void cmd_reverse_cycle(AgiGame *state, uint8 *p) {
+void cmdReverseCycle(AgiGame *state, uint8 *p) {
 	vt.cycle = CYCLE_REVERSE;
 	vt.flags |= CYCLING;
 }
 
-void cmd_set_dir(AgiGame *state, uint8 *p) {
+void cmdSetDir(AgiGame *state, uint8 *p) {
 	vt.direction = _v[p1];
 }
 
-void cmd_get_dir(AgiGame *state, uint8 *p) {
+void cmdGetDir(AgiGame *state, uint8 *p) {
 	_v[p1] = vt.direction;
 }
 
-void cmd_get_room_f(AgiGame *state, uint8 *p) {
+void cmdGetRoomF(AgiGame *state, uint8 *p) {
 	_v[p1] = state->_vm->objectGetLocation(_v[p0]);
 }
 
-void cmd_put(AgiGame *state, uint8 *p) {
+void cmdPut(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(p0, _v[p1]);
 }
 
-void cmd_put_f(AgiGame *state, uint8 *p) {
+void cmdPutF(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(_v[p0], _v[p1]);
 }
 
-void cmd_drop(AgiGame *state, uint8 *p) {
+void cmdDrop(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(p0, 0);
 }
 
-void cmd_get(AgiGame *state, uint8 *p) {
+void cmdGet(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(p0, EGO_OWNED);
 }
 
-void cmd_get_f(AgiGame *state, uint8 *p) {
+void cmdGetF(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(_v[p0], EGO_OWNED);
 }
 
-void cmd_word_to_string(AgiGame *state, uint8 *p) {
+void cmdWordToString(AgiGame *state, uint8 *p) {
 	strcpy(state->strings[p0], state->egoWords[p1].word);
 }
 
-void cmd_open_dialogue(AgiGame *state, uint8 *p) {
+void cmdOpenDialogue(AgiGame *state, uint8 *p) {
 	state->hasWindow = true;
 }
 
-void cmd_close_dialogue(AgiGame *state, uint8 *p) {
+void cmdCloseDialogue(AgiGame *state, uint8 *p) {
 	state->hasWindow = false;
 }
 
-void cmd_close_window(AgiGame *state, uint8 *p) {
+void cmdCloseWindow(AgiGame *state, uint8 *p) {
 	state->_vm->closeWindow();
 }
 
-void cmd_status_line_on(AgiGame *state, uint8 *p) {
+void cmdStatusLineOn(AgiGame *state, uint8 *p) {
 	state->statusLine = true;
 	state->_vm->writeStatus();
 }
 
-void cmd_status_line_off(AgiGame *state, uint8 *p) {
+void cmdStatusLineOff(AgiGame *state, uint8 *p) {
 	state->statusLine = false;
 	state->_vm->writeStatus();
 }
 
-void cmd_show_obj(AgiGame *state, uint8 *p) {
+void cmdShowObj(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->showObj(p0);
 }
 
-void cmd_show_obj_v(AgiGame *state, uint8 *p) {
+void cmdShowObjV(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->showObj(_v[p0]);
 }
 
-void cmd_sound(AgiGame *state, uint8 *p) {
+void cmdSound(AgiGame *state, uint8 *p) {
 	state->_vm->_sound->startSound(p0, p1);
 }
 
-void cmd_stop_sound(AgiGame *state, uint8 *p) {
+void cmdStopSound(AgiGame *state, uint8 *p) {
 	state->_vm->_sound->stopSound();
 }
 
-void cmd_menu_input(AgiGame *state, uint8 *p) {
+void cmdMenuInput(AgiGame *state, uint8 *p) {
 	state->_vm->newInputMode(INPUT_MENU);
 }
 
-void cmd_enable_item(AgiGame *state, uint8 *p) {
+void cmdEnableItem(AgiGame *state, uint8 *p) {
 	state->_vm->_menu->setItem(p0, true);
 }
 
-void cmd_disable_item(AgiGame *state, uint8 *p) {
+void cmdDisableItem(AgiGame *state, uint8 *p) {
 	state->_vm->_menu->setItem(p0, false);
 }
 
-void cmd_submit_menu(AgiGame *state, uint8 *p) {
+void cmdSubmitMenu(AgiGame *state, uint8 *p) {
 	state->_vm->_menu->submit();
 }
 
-void cmd_set_scan_start(AgiGame *state, uint8 *p) {
+void cmdSetScanStart(AgiGame *state, uint8 *p) {
 	state->_curLogic->sIP = state->_curLogic->cIP;
 }
 
-void cmd_reset_scan_start(AgiGame *state, uint8 *p) {
+void cmdResetScanStart(AgiGame *state, uint8 *p) {
 	state->_curLogic->sIP = 2;
 }
 
-void cmd_save_game(AgiGame *state, uint8 *p) {
+void cmdSaveGame(AgiGame *state, uint8 *p) {
 	state->simpleSave ? state->_vm->saveGameSimple() : state->_vm->saveGameDialog();
 }
 
-void cmd_load_game(AgiGame *state, uint8 *p) {
+void cmdLoadGame(AgiGame *state, uint8 *p) {
 	assert(1);
 	state->simpleSave ? state->_vm->loadGameSimple() : state->_vm->loadGameDialog();
 }
 
-void cmd_init_disk(AgiGame *state, uint8 *p) {				// do nothing
+void cmdInitDisk(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void cmd_log(AgiGame *state, uint8 *p) {				// do nothing
+void cmdLog(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void cmd_trace_on(AgiGame *state, uint8 *p) {				// do nothing
+void cmdTraceOn(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void cmd_trace_info(AgiGame *state, uint8 *p) {				// do nothing
+void cmdTraceInfo(AgiGame *state, uint8 *p) {				// do nothing
 }
 
-void cmd_show_mem(AgiGame *state, uint8 *p) {
+void cmdShowMem(AgiGame *state, uint8 *p) {
 	state->_vm->messageBox("Enough memory");
 }
 
-void cmd_init_joy(AgiGame *state, uint8 *p) { // do nothing
+void cmdInitJoy(AgiGame *state, uint8 *p) { // do nothing
 }
 
-void cmd_script_size(AgiGame *state, uint8 *p) {
+void cmdScriptSize(AgiGame *state, uint8 *p) {
 	debug(0, "script.size(%d)", p0);
 }
 
-void cmd_cancel_line(AgiGame *state, uint8 *p) {
+void cmdCancelLine(AgiGame *state, uint8 *p) {
 	state->inputBuffer[0] = 0;
 	state->cursorPos = 0;
 	state->_vm->writePrompt();
@@ -516,7 +516,7 @@ void cmd_cancel_line(AgiGame *state, uint8 *p) {
 // 4051 (When ego is stationary),
 // 471 (When walking on the first screen's bridge),
 // 71 (When walking around, using the mouse or the keyboard).
-void cmd_obj_status_f(AgiGame *state, uint8 *p) {
+void cmdObjStatusF(AgiGame *state, uint8 *p) {
 	const char *cycleDesc;  // Object's cycle description line
 	const char *motionDesc; // Object's motion description line
 	char msg[256];          // The whole object status message
@@ -588,20 +588,20 @@ void cmd_obj_status_f(AgiGame *state, uint8 *p) {
 // unk_174: Change priority table (used in KQ4) -- j5
 // unk_177: Disable menus completely -- j5
 // unk_181: Deactivate keypressed control (default control of ego)
-void cmd_set_simple(AgiGame *state, uint8 *p) {
+void cmdSetSimple(AgiGame *state, uint8 *p) {
 	if (!(getFeatures() & (GF_AGI256 | GF_AGI256_2))) {
 		state->simpleSave = true;
 	} else { // AGI256 and AGI256-2 use this unknown170 command to load 256 color pictures.
-		// Load the picture. Similar to void cmd_load_pic(AgiGame *state, uint8 *p).
+		// Load the picture. Similar to void cmdLoad_pic(AgiGame *state, uint8 *p).
 		state->_vm->_sprites->eraseBoth();
 		state->_vm->agiLoadResource(rPICTURE, _v[p0]);
 
-		// Draw the picture. Similar to void cmd_draw_pic(AgiGame *state, uint8 *p).
+		// Draw the picture. Similar to void cmdDraw_pic(AgiGame *state, uint8 *p).
 		state->_vm->_picture->decodePicture(_v[p0], false, true);
 		state->_vm->_sprites->blitBoth();
 		state->pictureShown = 0;
 
-		// Show the picture. Similar to void cmd_show_pic(AgiGame *state, uint8 *p).
+		// Show the picture. Similar to void cmdShow_pic(AgiGame *state, uint8 *p).
 		setflag(fOutputMode, false);
 		state->_vm->closeWindow();
 		state->_vm->_picture->showPic();
@@ -612,25 +612,25 @@ void cmd_set_simple(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_pop_script(AgiGame *state, uint8 *p) {
+void cmdPopScript(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x2915) {
 		debug(0, "pop.script");
 	}
 }
 
-void cmd_hold_key(AgiGame *state, uint8 *p) {
+void cmdHoldKey(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
 		state->_vm->_egoHoldKey = true;
 	}
 }
 
-void cmd_discard_sound(AgiGame *state, uint8 *p) {
+void cmdDiscardSound(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x2936) {
 		debug(0, "discard.sound");
 	}
 }
 
-void cmd_hide_mouse(AgiGame *state, uint8 *p) {
+void cmdHideMouse(AgiGame *state, uint8 *p) {
 	// WORKAROUND: Turns off current movement that's being caused with the mouse.
 	// This fixes problems with too many popup boxes appearing in the Amiga
 	// Gold Rush's copy protection failure scene (i.e. the hanging scene, logic.192).
@@ -643,29 +643,29 @@ void cmd_hide_mouse(AgiGame *state, uint8 *p) {
 	g_system->showMouse(false);
 }
 
-void cmd_allow_menu(AgiGame *state, uint8 *p) {
+void cmdAllowMenu(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
 		setflag(fMenusWork, ((p0 != 0) ? true : false));
 	}
 }
 
-void cmd_show_mouse(AgiGame *state, uint8 *p) {
+void cmdShowMouse(AgiGame *state, uint8 *p) {
 	g_system->showMouse(true);
 }
 
-void cmd_fence_mouse(AgiGame *state, uint8 *p) {
+void cmdFenceMouse(AgiGame *state, uint8 *p) {
 	state->mouseFence.moveTo(p0, p1);
 	state->mouseFence.setWidth(p2 - p0);
 	state->mouseFence.setHeight(p3 - p1);
 }
 
-void cmd_release_key(AgiGame *state, uint8 *p) {
+void cmdReleaseKey(AgiGame *state, uint8 *p) {
 	if (getVersion() >= 0x3098) {
 		state->_vm->_egoHoldKey = false;
 	}
 }
 
-void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p) {
+void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p) {
 	int8 x, y;
 
 	switch (logicNamesCmd[182].argumentsLength()) {
@@ -703,7 +703,7 @@ void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_parse(AgiGame *state, uint8 *p) {
+void cmdParse(AgiGame *state, uint8 *p) {
 	_v[vWordNotFound] = 0;
 	setflag(fEnteredCli, false);
 	setflag(fSaidAcceptedInput, false);
@@ -711,7 +711,7 @@ void cmd_parse(AgiGame *state, uint8 *p) {
 	state->_vm->dictionaryWords(state->_vm->agiSprintf(state->strings[p0]));
 }
 
-void cmd_call(AgiGame *state, uint8 *p) {
+void cmdCall(AgiGame *state, uint8 *p) {
 	int oldCIP;
 	int oldLognum;
 
@@ -727,11 +727,11 @@ void cmd_call(AgiGame *state, uint8 *p) {
 	state->_curLogic->cIP = oldCIP;
 }
 
-void cmd_call_f(AgiGame *state, uint8 *p) {
-	cmd_call(state, &_v[p0]);
+void cmdCallF(AgiGame *state, uint8 *p) {
+	cmdCall(state, &_v[p0]);
 }
 
-void cmd_draw_pic(AgiGame *state, uint8 *p) {
+void cmdDrawPic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]);
 	state->_vm->_sprites->eraseBoth();
 	state->_vm->_picture->decodePicture(_v[p0], true);
@@ -759,7 +759,7 @@ void cmd_draw_pic(AgiGame *state, uint8 *p) {
 	state->_vm->pause(kPausePicture);
 }
 
-void cmd_show_pic(AgiGame *state, uint8 *p) {
+void cmdShowPic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "=== show pic ===");
 
 	setflag(fOutputMode, false);
@@ -770,19 +770,19 @@ void cmd_show_pic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "--- end of show pic ---");
 }
 
-void cmd_load_pic(AgiGame *state, uint8 *p) {
+void cmdLoadPic(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->eraseBoth();
 	state->_vm->agiLoadResource(rPICTURE, _v[p0]);
 	state->_vm->_sprites->blitBoth();
 	state->_vm->_sprites->commitBoth();
 }
 
-void cmd_discard_pic(AgiGame *state, uint8 *p) {
+void cmdDiscardPic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "--- discard pic ---");
 	// do nothing
 }
 
-void cmd_overlay_pic(AgiGame *state, uint8 *p) {
+void cmdOverlayPic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "--- overlay pic ---");
 
 	state->_vm->_sprites->eraseBoth();
@@ -795,7 +795,7 @@ void cmd_overlay_pic(AgiGame *state, uint8 *p) {
 	state->_vm->pause(kPausePicture);
 }
 
-void cmd_show_pri_screen(AgiGame *state, uint8 *p) {
+void cmdShowPriScreen(AgiGame *state, uint8 *p) {
 	state->_vm->_debug.priority = 1;
 	state->_vm->_sprites->eraseBoth();
 	state->_vm->_picture->showPic();
@@ -809,7 +809,7 @@ void cmd_show_pri_screen(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->blitBoth();
 }
 
-void cmd_animate_obj(AgiGame *state, uint8 *p) {
+void cmdAnimateObj(AgiGame *state, uint8 *p) {
 	if (vt.flags & ANIMATED)
 		return;
 
@@ -820,14 +820,14 @@ void cmd_animate_obj(AgiGame *state, uint8 *p) {
 	vt.direction = 0;
 }
 
-void cmd_unanimate_all(AgiGame *state, uint8 *p) {
+void cmdUnanimateAll(AgiGame *state, uint8 *p) {
 	int i;
 
 	for (i = 0; i < MAX_VIEWTABLE; i++)
 		state->viewTable[i].flags &= ~(ANIMATED | DRAWN);
 }
 
-void cmd_draw(AgiGame *state, uint8 *p) {
+void cmdDraw(AgiGame *state, uint8 *p) {
 	if (vt.flags & DRAWN)
 		return;
 
@@ -871,7 +871,7 @@ void cmd_draw(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "vt entry #%d flags = %02x", p0, vt.flags);
 }
 
-void cmd_erase(AgiGame *state, uint8 *p) {
+void cmdErase(AgiGame *state, uint8 *p) {
 	if (~vt.flags & DRAWN)
 		return;
 
@@ -896,7 +896,7 @@ void cmd_erase(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->commitBlock(x1, y1, x2, y2, true);
 }
 
-void cmd_position(AgiGame *state, uint8 *p) {
+void cmdPosition(AgiGame *state, uint8 *p) {
 	vt.xPos = vt.xPos2 = p1;
 	vt.yPos = vt.yPos2 = p2;
 
@@ -917,7 +917,7 @@ void cmd_position(AgiGame *state, uint8 *p) {
 		state->_vm->clipViewCoordinates(&vt);
 }
 
-void cmd_position_f(AgiGame *state, uint8 *p) {
+void cmdPositionF(AgiGame *state, uint8 *p) {
 	vt.xPos = vt.xPos2 = _v[p1];
 	vt.yPos = vt.yPos2 = _v[p2];
 
@@ -928,12 +928,12 @@ void cmd_position_f(AgiGame *state, uint8 *p) {
 		state->_vm->clipViewCoordinates(&vt);
 }
 
-void cmd_get_posn(AgiGame *state, uint8 *p) {
+void cmdGetPosn(AgiGame *state, uint8 *p) {
 	state->vars[p1] = (unsigned char)vt.xPos;
 	state->vars[p2] = (unsigned char)vt.yPos;
 }
 
-void cmd_reposition(AgiGame *state, uint8 *p) {
+void cmdReposition(AgiGame *state, uint8 *p) {
 	int dx = (int8) _v[p1], dy = (int8) _v[p2];
 
 	debugC(4, kDebugLevelScripts, "dx=%d, dy=%d", dx, dy);
@@ -952,35 +952,35 @@ void cmd_reposition(AgiGame *state, uint8 *p) {
 	state->_vm->fixPosition(p0);
 }
 
-void cmd_reposition_to(AgiGame *state, uint8 *p) {
+void cmdRepositionTo(AgiGame *state, uint8 *p) {
 	vt.xPos = p1;
 	vt.yPos = p2;
 	vt.flags |= UPDATE_POS;
 	state->_vm->fixPosition(p0);
 }
 
-void cmd_reposition_to_f(AgiGame *state, uint8 *p) {
+void cmdRepositionToF(AgiGame *state, uint8 *p) {
 	vt.xPos = _v[p1];
 	vt.yPos = _v[p2];
 	vt.flags |= UPDATE_POS;
 	state->_vm->fixPosition(p0);
 }
 
-void cmd_add_to_pic(AgiGame *state, uint8 *p) {
+void cmdAddToPic(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->addToPic(p0, p1, p2, p3, p4, p5, p6);
 }
 
-void cmd_add_to_pic_f(AgiGame *state, uint8 *p) {
+void cmdAddToPicF(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->addToPic(_v[p0], _v[p1], _v[p2], _v[p3], _v[p4], _v[p5], _v[p6]);
 }
 
-void cmd_force_update(AgiGame *state, uint8 *p) {
+void cmdForceUpdate(AgiGame *state, uint8 *p) {
 	state->_vm->_sprites->eraseBoth();
 	state->_vm->_sprites->blitBoth();
 	state->_vm->_sprites->commitBoth();
 }
 
-void cmd_reverse_loop(AgiGame *state, uint8 *p) {
+void cmdReverseLoop(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
 	vt.cycle = CYCLE_REV_LOOP;
 	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
@@ -988,7 +988,7 @@ void cmd_reverse_loop(AgiGame *state, uint8 *p) {
 	setflag(p1, false);
 }
 
-void cmd_end_of_loop(AgiGame *state, uint8 *p) {
+void cmdEndOfLoop(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
 	vt.cycle = CYCLE_END_OF_LOOP;
 	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
@@ -996,7 +996,7 @@ void cmd_end_of_loop(AgiGame *state, uint8 *p) {
 	setflag(p1, false);
 }
 
-void cmd_block(AgiGame *state, uint8 *p) {
+void cmdBlock(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
 	state->block.active = true;
 	state->block.x1 = p0;
@@ -1005,15 +1005,15 @@ void cmd_block(AgiGame *state, uint8 *p) {
 	state->block.y2 = p3;
 }
 
-void cmd_unblock(AgiGame *state, uint8 *p) {
+void cmdUnblock(AgiGame *state, uint8 *p) {
 	state->block.active = false;
 }
 
-void cmd_normal_motion(AgiGame *state, uint8 *p) {
+void cmdNormalMotion(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_NORMAL;
 }
 
-void cmd_stop_motion(AgiGame *state, uint8 *p) {
+void cmdStopMotion(AgiGame *state, uint8 *p) {
 	vt.direction = 0;
 	vt.motion = MOTION_NORMAL;
 	if (p0 == 0) {		// ego only
@@ -1022,7 +1022,7 @@ void cmd_stop_motion(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_start_motion(AgiGame *state, uint8 *p) {
+void cmdStartMotion(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_NORMAL;
 	if (p0 == 0) {		// ego only
 		_v[vEgoDir] = 0;
@@ -1030,16 +1030,16 @@ void cmd_start_motion(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_player_control(AgiGame *state, uint8 *p) {
+void cmdPlayerControl(AgiGame *state, uint8 *p) {
 	state->playerControl = true;
 	state->viewTable[0].motion = MOTION_NORMAL;
 }
 
-void cmd_program_control(AgiGame *state, uint8 *p) {
+void cmdProgramControl(AgiGame *state, uint8 *p) {
 	state->playerControl = false;
 }
 
-void cmd_follow_ego(AgiGame *state, uint8 *p) {
+void cmdFollowEgo(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_FOLLOW_EGO;
 	vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
 	vt.parm2 = p2;
@@ -1048,7 +1048,7 @@ void cmd_follow_ego(AgiGame *state, uint8 *p) {
 	vt.flags |= UPDATE;
 }
 
-void cmd_move_obj(AgiGame *state, uint8 *p) {
+void cmdMoveObj(AgiGame *state, uint8 *p) {
 	// _D (_D_WARN "o=%d, x=%d, y=%d, s=%d, f=%d", p0, p1, p2, p3, p4);
 
 	vt.motion = MOTION_MOVE_OBJ;
@@ -1071,7 +1071,7 @@ void cmd_move_obj(AgiGame *state, uint8 *p) {
 		state->_vm->moveObj(&vt);
 }
 
-void cmd_move_obj_f(AgiGame *state, uint8 *p) {
+void cmdMoveObjF(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_MOVE_OBJ;
 	vt.parm1 = _v[p1];
 	vt.parm2 = _v[p2];
@@ -1092,7 +1092,7 @@ void cmd_move_obj_f(AgiGame *state, uint8 *p) {
 		state->_vm->moveObj(&vt);
 }
 
-void cmd_wander(AgiGame *state, uint8 *p) {
+void cmdWander(AgiGame *state, uint8 *p) {
 	if (p0 == 0)
 		state->playerControl = false;
 
@@ -1100,7 +1100,7 @@ void cmd_wander(AgiGame *state, uint8 *p) {
 	vt.flags |= UPDATE;
 }
 
-void cmd_set_game_id(AgiGame *state, uint8 *p) {
+void cmdSetGameID(AgiGame *state, uint8 *p) {
 	if (state->_curLogic->texts && (p0 - 1) <= state->_curLogic->numTexts)
 		strncpy(state->id, state->_curLogic->texts[p0 - 1], 8);
 	else
@@ -1109,7 +1109,7 @@ void cmd_set_game_id(AgiGame *state, uint8 *p) {
 	debug(0, "Game ID: \"%s\"", state->id);
 }
 
-void cmd_pause(AgiGame *state, uint8 *p) {
+void cmdPause(AgiGame *state, uint8 *p) {
 	int tmp = state->clockEnabled;
 	const char *b[] = { "Continue", NULL };
 	const char *b_ru[] = { "\x8f\xe0\xae\xa4\xae\xab\xa6\xa8\xe2\xec", NULL };
@@ -1127,21 +1127,21 @@ void cmd_pause(AgiGame *state, uint8 *p) {
 	state->clockEnabled = tmp;
 }
 
-void cmd_set_menu(AgiGame *state, uint8 *p) {
+void cmdSetMenu(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
 
 	if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
 		state->_vm->_menu->add(state->_curLogic->texts[p0 - 1]);
 }
 
-void cmd_set_menu_item(AgiGame *state, uint8 *p) {
+void cmdSetMenuItem(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "text %02x of %02x", p0, state->_curLogic->numTexts);
 
 	if (state->_curLogic->texts != NULL && p0 <= state->_curLogic->numTexts)
 		state->_vm->_menu->addItem(state->_curLogic->texts[p0 - 1], p1);
 }
 
-void cmd_version(AgiGame *state, uint8 *p) {
+void cmdVersion(AgiGame *state, uint8 *p) {
 	char verMsg[64];
 	char ver2Msg[] =
 	    "\n"
@@ -1181,13 +1181,13 @@ void cmd_version(AgiGame *state, uint8 *p) {
 	state->_vm->messageBox(msg);
 }
 
-void cmd_configure_screen(AgiGame *state, uint8 *p) {
+void cmdConfigureScreen(AgiGame *state, uint8 *p) {
 	state->lineMinPrint = p0;
 	state->lineUserInput = p1;
 	state->lineStatus = p2;
 }
 
-void cmd_text_screen(AgiGame *state, uint8 *p) {
+void cmdTextScreen(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "switching to text mode");
 	state->gfxMode = false;
 
@@ -1199,7 +1199,7 @@ void cmd_text_screen(AgiGame *state, uint8 *p) {
 	state->_vm->_gfx->clearScreen(state->colorBg);
 }
 
-void cmd_graphics(AgiGame *state, uint8 *p) {
+void cmdGraphics(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "switching to graphics mode");
 
 	if (!state->gfxMode) {
@@ -1211,7 +1211,7 @@ void cmd_graphics(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_set_text_attribute(AgiGame *state, uint8 *p) {
+void cmdSetTextAttribute(AgiGame *state, uint8 *p) {
 	state->colorFg = p0;
 	state->colorBg = p1;
 
@@ -1223,11 +1223,11 @@ void cmd_set_text_attribute(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_status(AgiGame *state, uint8 *p) {
+void cmdStatus(AgiGame *state, uint8 *p) {
 	state->_vm->inventory();
 }
 
-void cmd_quit(AgiGame *state, uint8 *p) {
+void cmdQuit(AgiGame *state, uint8 *p) {
 	const char *buttons[] = { "Quit", "Continue", NULL };
 
 	state->_vm->_sound->stopSound();
@@ -1240,7 +1240,7 @@ void cmd_quit(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_restart_game(AgiGame *state, uint8 *p) {
+void cmdRestartGame(AgiGame *state, uint8 *p) {
 	const char *buttons[] = { "Restart", "Continue", NULL };
 	int sel;
 
@@ -1255,7 +1255,7 @@ void cmd_restart_game(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_distance(AgiGame *state, uint8 *p) {
+void cmdDistance(AgiGame *state, uint8 *p) {
 	int16 x1, y1, x2, y2, d;
 	VtEntry *v0 = &state->viewTable[p0];
 	VtEntry *v1 = &state->viewTable[p1];
@@ -1306,7 +1306,7 @@ void cmd_distance(AgiGame *state, uint8 *p) {
 	_v[p2] = (unsigned char)d;
 }
 
-void cmd_accept_input(AgiGame *state, uint8 *p) {
+void cmdAcceptInput(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts | kDebugLevelInput, "input normal");
 
 	state->_vm->newInputMode(INPUT_NORMAL);
@@ -1314,7 +1314,7 @@ void cmd_accept_input(AgiGame *state, uint8 *p) {
 	state->_vm->writePrompt();
 }
 
-void cmd_prevent_input(AgiGame *state, uint8 *p) {
+void cmdPreventInput(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts | kDebugLevelInput, "no input");
 
 	state->_vm->newInputMode(INPUT_NONE);
@@ -1323,7 +1323,7 @@ void cmd_prevent_input(AgiGame *state, uint8 *p) {
 	state->_vm->clearPrompt();
 }
 
-void cmd_get_string(AgiGame *state, uint8 *p) {
+void cmdGetString(AgiGame *state, uint8 *p) {
 	int tex, row, col;
 
 	debugC(4, kDebugLevelScripts, "%d %d %d %d %d", p0, p1, p2, p3, p4);
@@ -1356,7 +1356,7 @@ void cmd_get_string(AgiGame *state, uint8 *p) {
 	} while (state->inputMode == INPUT_GETSTRING && !(state->_vm->shouldQuit() || state->_vm->_restartGame));
 }
 
-void cmd_get_num(AgiGame *state, uint8 *p) {
+void cmdGetNum(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "%d %d", p0, p1);
 
 	state->_vm->newInputMode(INPUT_GETSTRING);
@@ -1383,7 +1383,7 @@ void cmd_get_num(AgiGame *state, uint8 *p) {
 	state->_vm->flushLines(22, 22);
 }
 
-void cmd_set_cursor_char(AgiGame *state, uint8 *p) {
+void cmdSetCursorChar(AgiGame *state, uint8 *p) {
 	if (state->_curLogic->texts != NULL && (p0 - 1) <= state->_curLogic->numTexts) {
 		state->cursorChar = *state->_curLogic->texts[p0 - 1];
 	} else {
@@ -1392,7 +1392,7 @@ void cmd_set_cursor_char(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_set_key(AgiGame *state, uint8 *p) {
+void cmdSetKey(AgiGame *state, uint8 *p) {
 	int key;
 
 	if (state->lastController >= MAX_CONTROLLERS) {
@@ -1411,14 +1411,14 @@ void cmd_set_key(AgiGame *state, uint8 *p) {
 	state->controllerOccured[p2] = false;
 }
 
-void cmd_set_string(AgiGame *state, uint8 *p) {
+void cmdSetString(AgiGame *state, uint8 *p) {
 	// CM: to avoid crash in Groza (str = 150)
 	if (p0 > MAX_STRINGS)
 		return;
 	strcpy(state->strings[p0], state->_curLogic->texts[p1 - 1]);
 }
 
-void cmd_display(AgiGame *state, uint8 *p) {
+void cmdDisplay(AgiGame *state, uint8 *p) {
 	int len = 40;
 
 	char *s = state->_vm->wordWrapString(state->_curLogic->texts[p2 - 1], &len);
@@ -1428,11 +1428,11 @@ void cmd_display(AgiGame *state, uint8 *p) {
 	free(s);
 }
 
-void cmd_display_f(AgiGame *state, uint8 *p) {
+void cmdDisplayF(AgiGame *state, uint8 *p) {
 	state->_vm->printText(state->_curLogic->texts[_v[p2] - 1], _v[p1], 0, _v[p0], 40, state->colorFg, state->colorBg);
 }
 
-void cmd_clear_text_rect(AgiGame *state, uint8 *p) {
+void cmdClearTextRect(AgiGame *state, uint8 *p) {
 	int c, x1, y1, x2, y2;
 
 	if ((c = p4) != 0)
@@ -1457,17 +1457,17 @@ void cmd_clear_text_rect(AgiGame *state, uint8 *p) {
 	state->_vm->_gfx->flushBlock(x1, y1, x2, y2);
 }
 
-void cmd_toggle_monitor(AgiGame *state, uint8 *p) {
+void cmdToggleMonitor(AgiGame *state, uint8 *p) {
 	debug(0, "toggle.monitor");
 }
 
-void cmd_echo_line(AgiGame *state, uint8 *p) {
+void cmdEchoLine(AgiGame *state, uint8 *p) {
 	strcpy((char *)state->inputBuffer, (const char *)state->echoBuffer);
 	state->cursorPos = strlen((char *)state->inputBuffer);
 	state->hasPrompt = 0;
 }
 
-void cmd_clear_lines(AgiGame *state, uint8 *p) {
+void cmdClearLines(AgiGame *state, uint8 *p) {
 	uint8 l;
 
 	// Residence 44 calls clear.lines(24,0,0), see Sarien bug #558423
@@ -1481,19 +1481,19 @@ void cmd_clear_lines(AgiGame *state, uint8 *p) {
 	state->_vm->flushLines(p0, l);
 }
 
-void cmd_print(AgiGame *state, uint8 *p) {
+void cmdPrint(AgiGame *state, uint8 *p) {
 	int n = p0 < 1 ? 1 : p0;
 
 	state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
 }
 
-void cmd_print_f(AgiGame *state, uint8 *p) {
+void cmdPrintF(AgiGame *state, uint8 *p) {
 	int n = _v[p0] < 1 ? 1 : _v[p0];
 
 	state->_vm->print(state->_curLogic->texts[n - 1], 0, 0, 0);
 }
 
-void cmd_print_at(AgiGame *state, uint8 *p) {
+void cmdPrintAt(AgiGame *state, uint8 *p) {
 	int n = p0 < 1 ? 1 : p0;
 
 	debugC(4, kDebugLevelScripts, "%d %d %d %d", p0, p1, p2, p3);
@@ -1501,13 +1501,13 @@ void cmd_print_at(AgiGame *state, uint8 *p) {
 	state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
 }
 
-void cmd_print_at_v(AgiGame *state, uint8 *p) {
+void cmdPrintAtV(AgiGame *state, uint8 *p) {
 	int n = _v[p0] < 1 ? 1 : _v[p0];
 
 	state->_vm->print(state->_curLogic->texts[n - 1], p1, p2, p3);
 }
 
-void cmd_push_script(AgiGame *state, uint8 *p) {
+void cmdPushScript(AgiGame *state, uint8 *p) {
 	// We run AGIMOUSE always as a side effect
 	if (getFeatures() & GF_AGIMOUSE || true) {
 		state->vars[27] = state->_vm->_mouse.button;
@@ -1520,7 +1520,7 @@ void cmd_push_script(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_set_pri_base(AgiGame *state, uint8 *p) {
+void cmdSetPriBase(AgiGame *state, uint8 *p) {
 	int i, x, pri;
 
 	debug(0, "Priority base set to %d", p0);
@@ -1536,12 +1536,12 @@ void cmd_set_pri_base(AgiGame *state, uint8 *p) {
 	}
 }
 
-void cmd_mouse_posn(AgiGame *state, uint8 *p) {
+void cmdMousePosn(AgiGame *state, uint8 *p) {
 	_v[p0] = WIN_TO_PIC_X(state->_vm->_mouse.x);
 	_v[p1] = WIN_TO_PIC_Y(state->_vm->_mouse.y);
 }
 
-void cmd_shake_screen(AgiGame *state, uint8 *p) {
+void cmdShakeScreen(AgiGame *state, uint8 *p) {
 	int i;
 
 	// AGIPAL uses shake.screen values between 100 and 109 to set the palette
@@ -1574,13 +1574,13 @@ void cmd_shake_screen(AgiGame *state, uint8 *p) {
 	state->inputEnabled = originalValue;
 }
 
-void cmd_set_speed(AgiGame *state, uint8 *p) {
+void cmdSetSpeed(AgiGame *state, uint8 *p) {
 	// V1 command
 	(void)state;
 	(void)p;
 }
 
-void cmd_unknown(AgiGame *state, uint8 *p) {
+void cmdUnknown(AgiGame *state, uint8 *p) {
 	warning("Skipping unknown opcode %2X", *(p - 1));
 }
 
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 230ed97..70d0cc0 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -40,80 +40,80 @@ namespace Agi {
 #define testHas(obj)			(state->_vm->objectGetLocation(obj) == EGO_OWNED)
 #define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getvar(v))
 
-void cond_equal(AgiGame *state, uint8 *p) {
+void condEqual(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], p[1]);
 }
 
-void cond_equalv(AgiGame *state, uint8 *p) {
+void condEqualV(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testEqual(p[0], getvar(p[1]));
 }
 
-void cond_less(AgiGame *state, uint8 *p) {
+void condLess(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], p[1]);
 }
 
-void cond_lessv(AgiGame *state, uint8 *p) {
+void condLessV(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testLess(p[0], getvar(p[1]));
 }
 
-void cond_greater(AgiGame *state, uint8 *p) {
+void condGreater(AgiGame *state, uint8 *p) {
 	if (p[0] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], p[1]);
 }
 
-void cond_greaterv(AgiGame *state, uint8 *p) {
+void condGreaterV(AgiGame *state, uint8 *p) {
 	if (p[0] == 11 || p[1] == 11)
 		state->_vm->_timerHack++;
 	state->testResult = testGreater(p[0], getvar(p[1]));
 }
 
-void cond_isset(AgiGame *state, uint8 *p) {
+void condIsSet(AgiGame *state, uint8 *p) {
 	state->testResult = testIsSet(p[0]);
 }
 
-void cond_issetv(AgiGame *state, uint8 *p) {
+void condIsSetV(AgiGame *state, uint8 *p) {
 	state->testResult = testIsSet(getvar(p[1]));
 }
 
-void cond_isset_v1(AgiGame *state, uint8 *p) {
+void condIsSetV1(AgiGame *state, uint8 *p) {
 	state->testResult = getvar(p[0]) > 0;
 }
 
-void cond_has(AgiGame *state, uint8 *p) {
+void condHas(AgiGame *state, uint8 *p) {
 	state->testResult = testHas(p[0]);
 }
 
-void cond_obj_in_room(AgiGame *state, uint8 *p) {
+void condObjInRoom(AgiGame *state, uint8 *p) {
 	state->testResult = testObjInRoom(p[0], p[1]);
 }
 
-void cond_posn(AgiGame *state, uint8 *p) {
+void condPosn(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testPosn(p[0], p[1], p[2], p[3], p[4]);
 }
 
-void cond_controller(AgiGame *state, uint8 *p) {
+void condController(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testController(p[0]);
 }
 
-void cond_have_key(AgiGame *state, uint8 *p) {
+void condHaveKey(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testKeypressed();
 }
 
-void cond_said(AgiGame *state, uint8 *p) {
+void condSaid(AgiGame *state, uint8 *p) {
 	int ec = state->_vm->testSaid(p[0], p + 1);
 	state->testResult = ec;
 }
 
-void cond_said1(AgiGame *state, uint8 *p) {
+void condSaid1(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
@@ -125,7 +125,7 @@ void cond_said1(AgiGame *state, uint8 *p) {
 		state->testResult = true;
 }
 
-void cond_said2(AgiGame *state, uint8 *p) {
+void condSaid2(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
@@ -139,7 +139,7 @@ void cond_said2(AgiGame *state, uint8 *p) {
 		state->testResult = true;
 }
 
-void cond_said3(AgiGame *state, uint8 *p) {
+void condSaid3(AgiGame *state, uint8 *p) {
 	state->testResult = false;
 
 	if (!getflag(fEnteredCli))
@@ -155,24 +155,24 @@ void cond_said3(AgiGame *state, uint8 *p) {
 		state->testResult = true;
 }
 
-void cond_compare_strings(AgiGame *state, uint8 *p) {
+void condCompareStrings(AgiGame *state, uint8 *p) {
 	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
 	state->testResult = state->_vm->testCompareStrings(p[0], p[1]);
 }
 
-void cond_obj_in_box(AgiGame *state, uint8 *p) {
+void condObjInBox(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testObjInBox(p[0], p[1], p[2], p[3], p[4]);
 }
 
-void cond_center_posn(AgiGame *state, uint8 *p) {
+void condCenterPosn(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testObjCenter(p[0], p[1], p[2], p[3], p[4]);
 }
 
-void cond_right_posn(AgiGame *state, uint8 *p) {
+void condRightPosn(AgiGame *state, uint8 *p) {
 	state->testResult = state->_vm->testObjRight(p[0], p[1], p[2], p[3], p[4]);
 }
 
-void cond_unknown_13(AgiGame *state, uint8 *p) {
+void condUnknown13(AgiGame *state, uint8 *p) {
 	// My current theory is that this command checks whether the ego is currently moving
 	// and that that movement has been caused using the mouse and not using the keyboard.
 	// I base this theory on the game's behavior on an Amiga emulator, not on disassembly.
@@ -184,7 +184,7 @@ void cond_unknown_13(AgiGame *state, uint8 *p) {
 	state->testResult = ec;
 }
 
-void cond_unknown(AgiGame *state, uint8 *p) {
+void condUnknown(AgiGame *state, uint8 *p) {
 	warning("Skipping unknown test command %2X", *(p - 1));
 	state->testResult = false;
 }
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index d700764..b2bccd8 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -29,332 +29,332 @@ AgiInstruction *logicNamesTest;
 AgiInstruction *logicNamesCmd;
 
 AgiInstruction insV1Test[] = {
-	{ "",					"",			&cond_unknown },		// 00
-	{ "equaln",				"vn",		&cond_equal },			// 01
-	{ "equalv",				"vv",		&cond_equalv },			// 02
-	{ "lessn",				"vn",		&cond_less },			// 03
-	{ "lessv",				"vv",		&cond_lessv },			// 04
-	{ "greatern",			"vn",		&cond_greater },		// 05
-	{ "greaterv",			"vv",		&cond_greaterv },		// 06
-	{ "isset",				"v",		&cond_isset_v1 },		// 07
-	{ "has",				"n",		&cond_has },			// 08
-	{ "said",				"nnnn",		&cond_said2 },			// 09
-	{ "posn",				"nnnnn",	&cond_posn },			// 0A
-	{ "controller",			"n",		&cond_controller },		// 0B
-	{ "obj.in.room",		"nv",		&cond_obj_in_room },	// 0C
-	{ "said",				"nnnnnn",	&cond_said3 },			// 0D
-	{ "have.key",			"",			&cond_have_key },		// 0E
-	{ "said",				"nn",		&cond_said1 },			// 0F
-	{ "bit",				"nv",		&cond_unknown },		// 10
+	{ "",					"",			&condUnknown },		// 00
+	{ "equaln",				"vn",		&condEqual },		// 01
+	{ "equalv",				"vv",		&condEqualV },		// 02
+	{ "lessn",				"vn",		&condLess },		// 03
+	{ "lessv",				"vv",		&condLessV },		// 04
+	{ "greatern",			"vn",		&condGreater },		// 05
+	{ "greaterv",			"vv",		&condGreaterV },	// 06
+	{ "isset",				"v",		&condIsSetV1 },	// 07
+	{ "has",				"n",		&condHas },			// 08
+	{ "said",				"nnnn",		&condSaid2 },		// 09
+	{ "posn",				"nnnnn",	&condPosn },		// 0A
+	{ "controller",			"n",		&condController },	// 0B
+	{ "obj.in.room",		"nv",		&condObjInRoom },	// 0C
+	{ "said",				"nnnnnn",	&condSaid3 },		// 0D
+	{ "have.key",			"",			&condHaveKey },		// 0E
+	{ "said",				"nn",		&condSaid1 },		// 0F
+	{ "bit",				"nv",		&condUnknown },		// 10
 };
 
 AgiInstruction insV1[] = {
 	{ "return",				"",			NULL },						// 00
-	{ "increment",			"v",		&cmd_increment },			// 01
-	{ "decrement",			"v",		&cmd_decrement },			// 02
-	{ "assignn",			"vn",		&cmd_assignn },				// 03
-	{ "assignv",			"vv",		&cmd_assignv },				// 04
-	{ "addn",				"vn",		&cmd_addn },				// 05
-	{ "addv",				"vv",		&cmd_addv },				// 06
-	{ "subn",				"vn",		&cmd_subn },				// 07
-	{ "subv",				"vv",		&cmd_subv },				// 08
-	{ "load.view",			"n",		&cmd_load_view },			// 09
-	{ "animate.obj",		"n",		&cmd_animate_obj },			// 0A
-	{ "new.room",			"n",		&cmd_new_room },			// 0B
-	{ "draw.pic",			"v",		&cmd_draw_pic },			// 0C
-	{ "print",				"s",		&cmd_print },				// 0D
-	{ "status",				"",			&cmd_status },				// 0E
-	{ "save.game",			"",			&cmd_save_game },			// 0F
-	{ "restore.game",		"",			&cmd_load_game },			// 10
-	{ "...",				"",			&cmd_init_disk },			// 11 TODO
-	{ "restart.game",		"",			&cmd_restart_game },		// 12
-	{ "random",				"v",		&cmd_random },				// 13 TODO: 1 vs 3 vars
-	{ "get",				"n",		&cmd_get },					// 14
-	{ "drop",				"n",		&cmd_drop },				// 15
-	{ "draw",				"n",		&cmd_draw },				// 16
-	{ "erase",				"n",		&cmd_erase },				// 17
-	{ "position",			"nnn",		&cmd_position },			// 18
-	{ "position.v",			"nvv",		&cmd_position_f },			// 19
-	{ "get.posn",			"nvv",		&cmd_get_posn },			// 1A
-	{ "set.cel",			"nn",		&cmd_set_cel },				// 1B
-	{ "set.loop",			"nn",		&cmd_set_loop },			// 1C
-	{ "end.of.loop",		"nn",		&cmd_end_of_loop },			// 1D
-	{ "reverse.loop",		"nn",		&cmd_reverse_loop },		// 1E
-	{ "move.obj",			"nnnnn",	&cmd_move_obj },			// 1F
-	{ "set.view",			"nn",		&cmd_set_view },			// 20
-	{ "follow.ego",			"nnn",		&cmd_follow_ego },			// 21
-	{ "...",				"",			&cmd_unknown },				// 22
-	{ "...",				"",			&cmd_unknown },				// 23
-	{ "ignore.blocks",		"n",		&cmd_ignore_blocks },		// 24
-	{ "observe.blocks",		"n",		&cmd_observe_blocks },		// 25
-	{ "wander",				"n",		&cmd_wander },				// 26
-	{ "reposition",			"nvv",		&cmd_reposition },			// 27
-	{ "stop.motion",		"n",		&cmd_stop_motion },			// 28
-	{ "start.motion",		"n",		&cmd_start_motion },		// 29
-	{ "stop.cycling",		"n",		&cmd_stop_cycling },		// 2A
-	{ "start.cycling",		"n",		&cmd_start_cycling },		// 2B
-	{ "stop.update",		"n",		&cmd_stop_update },			// 2C
-	{ "start.update",		"n",		&cmd_start_update },		// 2D
-	{ "program.control",	"",			&cmd_program_control },		// 2E
-	{ "player.control",		"",			&cmd_player_control },		// 2F
-	{ "set.priority",		"nn",		&cmd_set_priority },		// 30
-	{ "release.priority",	"n",		&cmd_release_priority },	// 31
-	{ "add.to.pic",			"nnnnnn",	&cmd_add_to_pic },			// 32 TODO: 7 vs 8 args
-	{ "set.horizon",		"n",		&cmd_set_horizon },			// 33
-	{ "ignore.horizon",		"n",		&cmd_ignore_horizon },		// 34
-	{ "observe.horizon",	"n",		&cmd_observe_horizon },		// 35
-	{ "load.logics",		"n",		&cmd_load_logic },			// 36
-	{ "object.on.water",	"n",		&cmd_object_on_water },		// 37
-	{ "load.pic",			"v",		&cmd_load_pic },			// 38
-	{ "load.sound",			"n",		&cmd_load_sound },			// 39
-	{ "sound",				"nn",		&cmd_sound },				// 3A
-	{ "stop.sound",			"",			&cmd_stop_sound },			// 3B
-	{ "set.v",				"v",		&cmd_set_v },				// 3C
-	{ "reset.v",			"v",		&cmd_reset_v },				// 3D
-	{ "toggle.v",			"v",		&cmd_toggle_v },			// 3E
-	{ "new.room.v",			"v",		&cmd_new_room_f },			// 3F
-	{ "call",				"n",		&cmd_call },				// 40
-	{ "...",				"",			&cmd_unknown },				// 41
-	{ "set.speed",			"v",		&cmd_set_speed },			// 42
-	{ "move.obj.v",			"nvvvv",	&cmd_move_obj_f },			// 43
-	{ "...",				"",			&cmd_unknown },				// 44
-	{ "...",				"",			&cmd_unknown },				// 45
-	{ "...",				"",			&cmd_unknown },				// 46
-	{ "...",				"",			&cmd_unknown },				// 47
-	{ "...",				"nv",		&cmd_unknown },				// 48 get.priority??
-	{ "ignore.objs",		"n",		&cmd_ignore_objs },			// 49
-	{ "observe.objs",		"n",		&cmd_observe_objs },		// 4A
-	{ "distance",			"nnv",		&cmd_distance },			// 4B
-	{ "object.on.land",		"n",		&cmd_object_on_land },		// 4C
-	{ "...",				"nv",		&cmd_unknown },				// 4D set.priority.v???
-	{ "...",				"",			&cmd_unknown },				// 4E
-	{ "load.logics",		"n",		&cmd_load_logic },			// 4F TODO: what is the other load.logics then?
-	{ "display",			"nnns",		&cmd_display },				// 50 TODO: 4 vs 3 args
-	{ "prevent.input???",	"",			&cmd_unknown },				// 51
-	{ "...",				"",			&cmd_unknown },				// 52
-	{ "...",				"n",		&cmd_unknown },				// 53 ???
-	{ "...",				"",			&cmd_unknown },				// 54 ???
-	{ "stop.motion",		"",			&cmd_stop_motion },			// 55 or force.update??
-	{ "discard.view",		"n",		&cmd_discard_view },		// 56
-	{ "discard.pic",		"v",		&cmd_discard_pic },			// 57
-	{ "...",				"nn",		&cmd_unknown },				// 58
-	{ "...",				"",			&cmd_unknown },				// 59
-	{ "last.cel",			"nv",		&cmd_last_cel },			// 5A
-	{ "set.cel.v",			"nv",		&cmd_set_cel_f },			// 5B
-	{ "...",				"",			&cmd_unknown },				// 5C
-	{ "load.view",			"n",		&cmd_load_view },			// 5D
-	{ "...",				"",			&cmd_unknown },				// 5E
-	{ "...",				"",			&cmd_unknown },				// 5F
-	{ "setbit",				"nv",		&cmd_unknown },				// 60
+	{ "increment",			"v",		&cmdIncrement },			// 01
+	{ "decrement",			"v",		&cmdDecrement },			// 02
+	{ "assignn",			"vn",		&cmdAssignN },				// 03
+	{ "assignv",			"vv",		&cmdAssignV },				// 04
+	{ "addn",				"vn",		&cmdAddN },				// 05
+	{ "addv",				"vv",		&cmdAddV },				// 06
+	{ "subn",				"vn",		&cmdSubN },				// 07
+	{ "subv",				"vv",		&cmdSubV },				// 08
+	{ "load.view",			"n",		&cmdLoadView },			// 09
+	{ "animate.obj",		"n",		&cmdAnimateObj },			// 0A
+	{ "new.room",			"n",		&cmdNewRoom },			// 0B
+	{ "draw.pic",			"v",		&cmdDrawPic },			// 0C
+	{ "print",				"s",		&cmdPrint },				// 0D
+	{ "status",				"",			&cmdStatus },				// 0E
+	{ "save.game",			"",			&cmdSaveGame },			// 0F
+	{ "restore.game",		"",			&cmdLoadGame },			// 10
+	{ "...",				"",			&cmdInitDisk },			// 11 TODO
+	{ "restart.game",		"",			&cmdRestartGame },		// 12
+	{ "random",				"v",		&cmdRandom },				// 13 TODO: 1 vs 3 vars
+	{ "get",				"n",		&cmdGet },					// 14
+	{ "drop",				"n",		&cmdDrop },				// 15
+	{ "draw",				"n",		&cmdDraw },				// 16
+	{ "erase",				"n",		&cmdErase },				// 17
+	{ "position",			"nnn",		&cmdPosition },			// 18
+	{ "position.v",			"nvv",		&cmdPositionF },			// 19
+	{ "get.posn",			"nvv",		&cmdGetPosn },			// 1A
+	{ "set.cel",			"nn",		&cmdSetCel },				// 1B
+	{ "set.loop",			"nn",		&cmdSetLoop },			// 1C
+	{ "end.of.loop",		"nn",		&cmdEndOfLoop },			// 1D
+	{ "reverse.loop",		"nn",		&cmdReverseLoop },		// 1E
+	{ "move.obj",			"nnnnn",	&cmdMoveObj },			// 1F
+	{ "set.view",			"nn",		&cmdSetView },			// 20
+	{ "follow.ego",			"nnn",		&cmdFollowEgo },			// 21
+	{ "...",				"",			&cmdUnknown },				// 22
+	{ "...",				"",			&cmdUnknown },				// 23
+	{ "ignore.blocks",		"n",		&cmdIgnoreBlocks },		// 24
+	{ "observe.blocks",		"n",		&cmdObserveBlocks },		// 25
+	{ "wander",				"n",		&cmdWander },				// 26
+	{ "reposition",			"nvv",		&cmdReposition },			// 27
+	{ "stop.motion",		"n",		&cmdStopMotion },			// 28
+	{ "start.motion",		"n",		&cmdStartMotion },		// 29
+	{ "stop.cycling",		"n",		&cmdStopCycling },		// 2A
+	{ "start.cycling",		"n",		&cmdStartCycling },		// 2B
+	{ "stop.update",		"n",		&cmdStopUpdate },			// 2C
+	{ "start.update",		"n",		&cmdStartUpdate },		// 2D
+	{ "program.control",	"",			&cmdProgramControl },		// 2E
+	{ "player.control",		"",			&cmdPlayerControl },		// 2F
+	{ "set.priority",		"nn",		&cmdSetPriority },		// 30
+	{ "release.priority",	"n",		&cmdReleasePriority },	// 31
+	{ "add.to.pic",			"nnnnnn",	&cmdAddToPic },			// 32 TODO: 7 vs 8 args
+	{ "set.horizon",		"n",		&cmdSetHorizon },			// 33
+	{ "ignore.horizon",		"n",		&cmdIgnoreHorizon },		// 34
+	{ "observe.horizon",	"n",		&cmdObserveHorizon },		// 35
+	{ "load.logics",		"n",		&cmdLoadLogic },			// 36
+	{ "object.on.water",	"n",		&cmdObjectOnWater },		// 37
+	{ "load.pic",			"v",		&cmdLoadPic },			// 38
+	{ "load.sound",			"n",		&cmdLoadSound },			// 39
+	{ "sound",				"nn",		&cmdSound },				// 3A
+	{ "stop.sound",			"",			&cmdStopSound },			// 3B
+	{ "set.v",				"v",		&cmdSetV },				// 3C
+	{ "reset.v",			"v",		&cmdResetV },				// 3D
+	{ "toggle.v",			"v",		&cmdToggleV },			// 3E
+	{ "new.room.v",			"v",		&cmdNewRoomF },			// 3F
+	{ "call",				"n",		&cmdCall },				// 40
+	{ "...",				"",			&cmdUnknown },				// 41
+	{ "set.speed",			"v",		&cmdSetSpeed },			// 42
+	{ "move.obj.v",			"nvvvv",	&cmdMoveObjF },			// 43
+	{ "...",				"",			&cmdUnknown },				// 44
+	{ "...",				"",			&cmdUnknown },				// 45
+	{ "...",				"",			&cmdUnknown },				// 46
+	{ "...",				"",			&cmdUnknown },				// 47
+	{ "...",				"nv",		&cmdUnknown },				// 48 get.priority??
+	{ "ignore.objs",		"n",		&cmdIgnoreObjs },			// 49
+	{ "observe.objs",		"n",		&cmdObserveObjs },		// 4A
+	{ "distance",			"nnv",		&cmdDistance },			// 4B
+	{ "object.on.land",		"n",		&cmdObjectOnLand },		// 4C
+	{ "...",				"nv",		&cmdUnknown },				// 4D set.priority.v???
+	{ "...",				"",			&cmdUnknown },				// 4E
+	{ "load.logics",		"n",		&cmdLoadLogic },			// 4F TODO: what is the other load.logics then?
+	{ "display",			"nnns",		&cmdDisplay },				// 50 TODO: 4 vs 3 args
+	{ "prevent.input???",	"",			&cmdUnknown },				// 51
+	{ "...",				"",			&cmdUnknown },				// 52
+	{ "...",				"n",		&cmdUnknown },				// 53 ???
+	{ "...",				"",			&cmdUnknown },				// 54 ???
+	{ "stop.motion",		"",			&cmdStopMotion },			// 55 or force.update??
+	{ "discard.view",		"n",		&cmdDiscardView },		// 56
+	{ "discard.pic",		"v",		&cmdDiscardPic },			// 57
+	{ "...",				"nn",		&cmdUnknown },				// 58
+	{ "...",				"",			&cmdUnknown },				// 59
+	{ "last.cel",			"nv",		&cmdLastCel },			// 5A
+	{ "set.cel.v",			"nv",		&cmdSetCelF },			// 5B
+	{ "...",				"",			&cmdUnknown },				// 5C
+	{ "load.view",			"n",		&cmdLoadView },			// 5D
+	{ "...",				"",			&cmdUnknown },				// 5E
+	{ "...",				"",			&cmdUnknown },				// 5F
+	{ "setbit",				"nv",		&cmdUnknown },				// 60
 };
 
 AgiInstruction insV2Test[] = {
-	{ "",					"",			&cond_unknown },			// 00
-	{ "equaln",				"vn",		&cond_equal },				// 01
-	{ "equalv",				"vv",		&cond_equalv },				// 02
-	{ "lessn",				"vn",		&cond_less },				// 03
-	{ "lessv",				"vv",		&cond_lessv },				// 04
-	{ "greatern",			"vn",		&cond_greater },			// 05
-	{ "greaterv",			"vv",		&cond_greaterv },			// 06
-	{ "isset",				"n",		&cond_isset },				// 07
-	{ "issetv",				"v",		&cond_issetv },				// 08
-	{ "has",				"n",		&cond_has },				// 09
-	{ "obj.in.room",		"nv",		&cond_obj_in_room},			// 0A
-	{ "posn",				"nnnnn",	&cond_posn },				// 0B
-	{ "controller",			"n",		&cond_controller },			// 0C
-	{ "have.key",			"",			&cond_have_key},			// 0D
-	{ "said",				"",			&cond_said },				// 0E
-	{ "compare.strings",	"ss",		&cond_compare_strings },	// 0F
-	{ "obj.in.box",			"nnnnn",	&cond_obj_in_box },			// 10
-	{ "center.posn",		"nnnnn",	&cond_center_posn },		// 11
-	{ "right.posn",			"nnnnn",	&cond_right_posn },			// 12
-	{ "in.motion.using.mouse", "",		&cond_unknown_13 }			// 13
+	{ "",					"",			&condUnknown },			// 00
+	{ "equaln",				"vn",		&condEqual },			// 01
+	{ "equalv",				"vv",		&condEqualV },			// 02
+	{ "lessn",				"vn",		&condLess },			// 03
+	{ "lessv",				"vv",		&condLessV },			// 04
+	{ "greatern",			"vn",		&condGreater },			// 05
+	{ "greaterv",			"vv",		&condGreaterV },		// 06
+	{ "isset",				"n",		&condIsSet },			// 07
+	{ "issetv",				"v",		&condIsSetV },			// 08
+	{ "has",				"n",		&condHas },				// 09
+	{ "obj.in.room",		"nv",		&condObjInRoom},		// 0A
+	{ "posn",				"nnnnn",	&condPosn },			// 0B
+	{ "controller",			"n",		&condController },		// 0C
+	{ "have.key",			"",			&condHaveKey},			// 0D
+	{ "said",				"",			&condSaid },			// 0E
+	{ "compare.strings",	"ss",		&condCompareStrings },	// 0F
+	{ "obj.in.box",			"nnnnn",	&condObjInBox },		// 10
+	{ "center.posn",		"nnnnn",	&condCenterPosn },		// 11
+	{ "right.posn",			"nnnnn",	&condRightPosn },		// 12
+	{ "in.motion.using.mouse", "",		&condUnknown13 }		// 13
 };
 
 AgiInstruction insV2[] = {
 	{ "return",				"",			NULL },
-	{ "increment",			"v",		&cmd_increment },
-	{ "decrement",			"v",		&cmd_decrement },
-	{ "assignn",			"vn",		&cmd_assignn },
-	{ "assignv",			"vv",		&cmd_assignv },
-	{ "addn",				"vn",		&cmd_addn },
-	{ "addv",				"vv",		&cmd_addv },
-	{ "subn",				"vn",		&cmd_subn },
-	{ "subv",				"vv",		&cmd_subv },
-	{ "lindirectv",			"vv",		&cmd_lindirectv },
-	{ "lindirect",			"vv",		&cmd_rindirect },
-	{ "lindirectn",			"vn",		&cmd_lindirectn },
-	{ "set",				"n",		&cmd_set },
-	{ "reset",				"n",		&cmd_reset },
-	{ "toggle",				"n",		&cmd_toggle },
-	{ "set.v",				"v",		&cmd_set_v },
-	{ "reset.v",			"v",		&cmd_reset_v },
-	{ "toggle.v",			"v",		&cmd_toggle_v },
-	{ "new.room",			"n",		&cmd_new_room },
-	{ "new.room.v",			"v",		&cmd_new_room_f },
-	{ "load.logics",		"n",		&cmd_load_logic },
-	{ "load.logics.v",		"v",		&cmd_load_logic_f },
-	{ "call",				"n",		&cmd_call },
-	{ "call.v",				"v",		&cmd_call_f },
-	{ "load.pic",			"v",		&cmd_load_pic },
-	{ "draw.pic",			"v",		&cmd_draw_pic },
-	{ "show.pic",			"",			&cmd_show_pic },
-	{ "discard.pic",		"v",		&cmd_discard_pic },
-	{ "overlay.pic",		"v",		&cmd_overlay_pic },
-	{ "show.pri.screen",	"",			&cmd_show_pri_screen },
-	{ "load.view",			"n",		&cmd_load_view },
-	{ "load.view.v",		"v",		&cmd_load_view_f },
-	{ "discard.view",		"n",		&cmd_discard_view },
-	{ "animate.obj",		"n",		&cmd_animate_obj },
-	{ "unanimate.all",		"",			&cmd_unanimate_all },
-	{ "draw",				"n",		&cmd_draw },
-	{ "erase",				"n",		&cmd_erase },
-	{ "position",			"nnn",		&cmd_position },
-	{ "position.v",			"nvv",		&cmd_position_f },
-	{ "get.posn",			"nvv",		&cmd_get_posn },
-	{ "reposition",			"nvv",		&cmd_reposition },
-	{ "set.view",			"nn",		&cmd_set_view },
-	{ "set.view.v",			"nv",		&cmd_set_view_f },
-	{ "set.loop",			"nn",		&cmd_set_loop },
-	{ "set.loop.v",			"nv",		&cmd_set_loop_f },
-	{ "fix.loop",			"n",		&cmd_fix_loop },
-	{ "release.loop",		"n",		&cmd_release_loop },
-	{ "set.cel",			"nn",		&cmd_set_cel },
-	{ "set.cel.v",			"nv",		&cmd_set_cel_f },
-	{ "last.cel",			"nv",		&cmd_last_cel },
-	{ "current.cel",		"nv",		&cmd_current_cel },
-	{ "current.loop",		"nv",		&cmd_current_loop },
-	{ "current.view",		"nv",		&cmd_current_view },
-	{ "number.of.loops",	"nv",		&cmd_number_of_loops },
-	{ "set.priority",		"nn",		&cmd_set_priority },
-	{ "set.priority.v",		"nv",		&cmd_set_priority_f },
-	{ "release.priority",	"n",		&cmd_release_priority },
-	{ "get.priority",		"nn",		&cmd_get_priority },
-	{ "stop.update",		"n",		&cmd_stop_update },
-	{ "start.update",		"n",		&cmd_start_update },
-	{ "force.update",		"n",		&cmd_force_update },
-	{ "ignore.horizon",		"n",		&cmd_ignore_horizon },
-	{ "observe.horizon",	"n",		&cmd_observe_horizon },
-	{ "set.horizon",		"n",		&cmd_set_horizon },
-	{ "object.on.water",	"n",		&cmd_object_on_water },
-	{ "object.on.land",		"n",		&cmd_object_on_land },
-	{ "object.on.anything",	"n",		&cmd_object_on_anything },
-	{ "ignore.objs",		"n",		&cmd_ignore_objs },
-	{ "observe.objs",		"n",		&cmd_observe_objs },
-	{ "distance",			"nnv",		&cmd_distance },
-	{ "stop.cycling",		"n",		&cmd_stop_cycling },
-	{ "start.cycling",		"n",		&cmd_start_cycling },
-	{ "normal.cycle",		"n",		&cmd_normal_cycle },
-	{ "end.of.loop",		"nn",		&cmd_end_of_loop },
-	{ "reverse.cycle",		"n",		&cmd_reverse_cycle },
-	{ "reverse.loop",		"nn",		&cmd_reverse_loop },
-	{ "cycle.time",			"nv",		&cmd_cycle_time },
-	{ "stop.motion",		"n",		&cmd_stop_motion },
-	{ "start.motion",		"n",		&cmd_start_motion },
-	{ "step.size",			"nv",		&cmd_step_size },
-	{ "step.time",			"nv",		&cmd_step_time },
-	{ "move.obj",			"nnnnn",	&cmd_move_obj },
-	{ "move.obj.v",			"nvvvv",	&cmd_move_obj_f },
-	{ "follow.ego",			"nnn",		&cmd_follow_ego },
-	{ "wander",				"n",		&cmd_wander },
-	{ "normal.motion",		"n",		&cmd_normal_motion },
-	{ "set.dir",			"nv",		&cmd_set_dir },
-	{ "get.dir",			"nv",		&cmd_get_dir },
-	{ "ignore.blocks",		"n",		&cmd_ignore_blocks },
-	{ "observe.blocks",		"n",		&cmd_observe_blocks },
-	{ "block",				"nnnn",		&cmd_block },
-	{ "unblock",			"",			&cmd_unblock },
-	{ "get",				"n",		&cmd_get },
-	{ "get.v",				"v",		&cmd_get_f },
-	{ "drop",				"n",		&cmd_drop },
-	{ "put",				"nn",		&cmd_put },
-	{ "put.v",				"vv",		&cmd_put_f },
-	{ "get.room.v",			"vv",		&cmd_get_room_f },
-	{ "load.sound",			"n",		&cmd_load_sound },
-	{ "sound",				"nn",		&cmd_sound },
-	{ "stop.sound",			"",			&cmd_stop_sound },
-	{ "print",				"s",		&cmd_print },
-	{ "print.v",			"v",		&cmd_print_f },
-	{ "display",			"nns",		&cmd_display },
-	{ "display.v",			"vvv",		&cmd_display_f },
-	{ "clear.lines",		"nns",		&cmd_clear_lines },
-	{ "text.screen",		"",			&cmd_text_screen },
-	{ "graphics",			"",			&cmd_graphics },
-	{ "set.cursor.char",	"s",		&cmd_set_cursor_char },
-	{ "set.text.attribute",	"nn",		&cmd_set_text_attribute },
-	{ "shake.screen",		"n",		&cmd_shake_screen },
-	{ "configure.screen",	"nnn",		&cmd_configure_screen },
-	{ "status.line.on",		"",			&cmd_status_line_on },
-	{ "status.line.off",	"",			&cmd_status_line_off },
-	{ "set.string",			"ns",		&cmd_set_string },
-	{ "get.string",			"ns",		&cmd_get_string },
-	{ "word.to.string",		"nn",		&cmd_word_to_string },
-	{ "parse",				"n",		&cmd_parse },
-	{ "get.num",			"nv",		&cmd_get_num },
-	{ "prevent.input",		"",			&cmd_prevent_input },
-	{ "accept.input",		"",			&cmd_accept_input },
-	{ "set.key",			"nnn",		&cmd_set_key },
-	{ "add.to.pic",			"nnnnnnn",	&cmd_add_to_pic },
-	{ "add.to.pic.v",		"vvvvvvv",	&cmd_add_to_pic_f },
-	{ "status",				"",			&cmd_status },
-	{ "save.game",			"",			&cmd_save_game },
-	{ "restore.game",		"",			&cmd_load_game },
-	{ "init.disk",			"",			&cmd_init_disk },
-	{ "restart.game",		"",			&cmd_restart_game },
-	{ "show.obj",			"n",		&cmd_show_obj },
-	{ "random",				"nnv",		&cmd_random },
-	{ "program.control",	"",			&cmd_program_control },
-	{ "player.control",		"",			&cmd_player_control },
-	{ "obj.status.v",		"v",		&cmd_obj_status_f },
-	{ "quit",				"n",		&cmd_quit },
-	{ "show.mem",			"",			&cmd_show_mem },
-	{ "pause",				"",			&cmd_pause },
-	{ "echo.line",			"",			&cmd_echo_line },
-	{ "cancel.line",		"",			&cmd_cancel_line },
-	{ "init.joy",			"",			&cmd_init_joy },
-	{ "toggle.monitor",		"",			&cmd_toggle_monitor },
-	{ "version",			"",			&cmd_version },
-	{ "script.size",		"n",		&cmd_script_size },
-	{ "set.game.id",		"s",		&cmd_set_game_id },
-	{ "log",				"s",		&cmd_log },
-	{ "set.scan.start",		"",			&cmd_set_scan_start },
-	{ "reset.scan.start",	"",			&cmd_reset_scan_start },
-	{ "reposition.to",		"nnn",		&cmd_reposition_to },
-	{ "reposition.to.v",	"nvv",		&cmd_reposition_to_f },
-	{ "trace.on",			"",			&cmd_trace_on },
-	{ "trace.info", 		"nnn",		&cmd_trace_info },
-	{ "print.at",			"snnn",		&cmd_print_at },
-	{ "print.at.v",			"vnnn",		&cmd_print_at_v },
-	{ "discard.view.v",		"v",		&cmd_discard_view},
-	{ "clear.text.rect",	"nnnnn",	&cmd_clear_text_rect },
-	{ "set.upper.left",		"nn",		&cmd_set_upper_left },
-	{ "set.menu",			"s",		&cmd_set_menu },
-	{ "set.menu.member",	"sn",		&cmd_set_menu_item },
-	{ "submit.menu",		"",			&cmd_submit_menu },
-	{ "enable.member",		"n",		&cmd_enable_item },
-	{ "disable.member",		"n",		&cmd_disable_item },
-	{ "menu.input",			"",			&cmd_menu_input },
-	{ "show.obj.v",			"v",		&cmd_show_obj_v },
-	{ "open.dialogue",		"",			&cmd_open_dialogue },
-	{ "close.dialogue",		"",			&cmd_close_dialogue },
-	{ "mul.n",				"vn",		&cmd_mul_n },
-	{ "mul.v",				"vv",		&cmd_mul_v },
-	{ "div.n",				"vn",		&cmd_div_n },
-	{ "div.v",				"vv",		&cmd_div_v },
-	{ "close.window",		"",			&cmd_close_window },
-	{ "set.simple",			"n",		&cmd_set_simple },
-	{ "push.script",		"",			&cmd_push_script },
-	{ "pop.script",			"",			&cmd_pop_script },
-	{ "hold.key",			"",			&cmd_hold_key },
-	{ "set.pri.base",		"n",		&cmd_set_pri_base },
-	{ "discard.sound",		"n",		&cmd_discard_sound },
-	{ "hide.mouse",			"",			&cmd_hide_mouse },
-	{ "allow.menu",			"n",		&cmd_allow_menu },
-	{ "show.mouse",			"",			&cmd_show_mouse },
-	{ "fence.mouse",		"nnnn",		&cmd_fence_mouse },
-	{ "mouse.posn",			"vv",		&cmd_mouse_posn },
-	{ "release.key",		"",			&cmd_release_key },
-	{ "adj.ego.move.to.xy",	"",			&cmd_adj_ego_move_to_x_y }
+	{ "increment",			"v",		&cmdIncrement },
+	{ "decrement",			"v",		&cmdDecrement },
+	{ "assignn",			"vn",		&cmdAssignN },
+	{ "assignv",			"vv",		&cmdAssignV },
+	{ "addn",				"vn",		&cmdAddN },
+	{ "addv",				"vv",		&cmdAddV },
+	{ "subn",				"vn",		&cmdSubN },
+	{ "subv",				"vv",		&cmdSubV },
+	{ "lindirectv",			"vv",		&cmdLindirectV },
+	{ "lindirect",			"vv",		&cmdRindirect },
+	{ "lindirectn",			"vn",		&cmdLindirectN },
+	{ "set",				"n",		&cmdSet },
+	{ "reset",				"n",		&cmdReset },
+	{ "toggle",				"n",		&cmdToggle },
+	{ "set.v",				"v",		&cmdSetV },
+	{ "reset.v",			"v",		&cmdResetV },
+	{ "toggle.v",			"v",		&cmdToggleV },
+	{ "new.room",			"n",		&cmdNewRoom },
+	{ "new.room.v",			"v",		&cmdNewRoomF },
+	{ "load.logics",		"n",		&cmdLoadLogic },
+	{ "load.logics.v",		"v",		&cmdLoadLogicF },
+	{ "call",				"n",		&cmdCall },
+	{ "call.v",				"v",		&cmdCallF },
+	{ "load.pic",			"v",		&cmdLoadPic },
+	{ "draw.pic",			"v",		&cmdDrawPic },
+	{ "show.pic",			"",			&cmdShowPic },
+	{ "discard.pic",		"v",		&cmdDiscardPic },
+	{ "overlay.pic",		"v",		&cmdOverlayPic },
+	{ "show.pri.screen",	"",			&cmdShowPriScreen },
+	{ "load.view",			"n",		&cmdLoadView },
+	{ "load.view.v",		"v",		&cmdLoadViewF },
+	{ "discard.view",		"n",		&cmdDiscardView },
+	{ "animate.obj",		"n",		&cmdAnimateObj },
+	{ "unanimate.all",		"",			&cmdUnanimateAll },
+	{ "draw",				"n",		&cmdDraw },
+	{ "erase",				"n",		&cmdErase },
+	{ "position",			"nnn",		&cmdPosition },
+	{ "position.v",			"nvv",		&cmdPositionF },
+	{ "get.posn",			"nvv",		&cmdGetPosn },
+	{ "reposition",			"nvv",		&cmdReposition },
+	{ "set.view",			"nn",		&cmdSetView },
+	{ "set.view.v",			"nv",		&cmdSetViewF },
+	{ "set.loop",			"nn",		&cmdSetLoop },
+	{ "set.loop.v",			"nv",		&cmdSetLoopF },
+	{ "fix.loop",			"n",		&cmdFixLoop },
+	{ "release.loop",		"n",		&cmdReleaseLoop },
+	{ "set.cel",			"nn",		&cmdSetCel },
+	{ "set.cel.v",			"nv",		&cmdSetCelF },
+	{ "last.cel",			"nv",		&cmdLastCel },
+	{ "current.cel",		"nv",		&cmdCurrentCel },
+	{ "current.loop",		"nv",		&cmdCurrentLoop },
+	{ "current.view",		"nv",		&cmdCurrentView },
+	{ "number.of.loops",	"nv",		&cmdNumberOfLoops },
+	{ "set.priority",		"nn",		&cmdSetPriority },
+	{ "set.priority.v",		"nv",		&cmdSetPriorityF },
+	{ "release.priority",	"n",		&cmdReleasePriority },
+	{ "get.priority",		"nn",		&cmdGetPriority },
+	{ "stop.update",		"n",		&cmdStopUpdate },
+	{ "start.update",		"n",		&cmdStartUpdate },
+	{ "force.update",		"n",		&cmdForceUpdate },
+	{ "ignore.horizon",		"n",		&cmdIgnoreHorizon },
+	{ "observe.horizon",	"n",		&cmdObserveHorizon },
+	{ "set.horizon",		"n",		&cmdSetHorizon },
+	{ "object.on.water",	"n",		&cmdObjectOnWater },
+	{ "object.on.land",		"n",		&cmdObjectOnLand },
+	{ "object.on.anything",	"n",		&cmdObjectOnAnything },
+	{ "ignore.objs",		"n",		&cmdIgnoreObjs },
+	{ "observe.objs",		"n",		&cmdObserveObjs },
+	{ "distance",			"nnv",		&cmdDistance },
+	{ "stop.cycling",		"n",		&cmdStopCycling },
+	{ "start.cycling",		"n",		&cmdStartCycling },
+	{ "normal.cycle",		"n",		&cmdNormalCycle },
+	{ "end.of.loop",		"nn",		&cmdEndOfLoop },
+	{ "reverse.cycle",		"n",		&cmdReverseCycle },
+	{ "reverse.loop",		"nn",		&cmdReverseLoop },
+	{ "cycle.time",			"nv",		&cmdCycleTime },
+	{ "stop.motion",		"n",		&cmdStopMotion },
+	{ "start.motion",		"n",		&cmdStartMotion },
+	{ "step.size",			"nv",		&cmdStepSize },
+	{ "step.time",			"nv",		&cmdStepTime },
+	{ "move.obj",			"nnnnn",	&cmdMoveObj },
+	{ "move.obj.v",			"nvvvv",	&cmdMoveObjF },
+	{ "follow.ego",			"nnn",		&cmdFollowEgo },
+	{ "wander",				"n",		&cmdWander },
+	{ "normal.motion",		"n",		&cmdNormalMotion },
+	{ "set.dir",			"nv",		&cmdSetDir },
+	{ "get.dir",			"nv",		&cmdGetDir },
+	{ "ignore.blocks",		"n",		&cmdIgnoreBlocks },
+	{ "observe.blocks",		"n",		&cmdObserveBlocks },
+	{ "block",				"nnnn",		&cmdBlock },
+	{ "unblock",			"",			&cmdUnblock },
+	{ "get",				"n",		&cmdGet },
+	{ "get.v",				"v",		&cmdGetF },
+	{ "drop",				"n",		&cmdDrop },
+	{ "put",				"nn",		&cmdPut },
+	{ "put.v",				"vv",		&cmdPutF },
+	{ "get.room.v",			"vv",		&cmdGetRoomF },
+	{ "load.sound",			"n",		&cmdLoadSound },
+	{ "sound",				"nn",		&cmdSound },
+	{ "stop.sound",			"",			&cmdStopSound },
+	{ "print",				"s",		&cmdPrint },
+	{ "print.v",			"v",		&cmdPrintF },
+	{ "display",			"nns",		&cmdDisplay },
+	{ "display.v",			"vvv",		&cmdDisplayF },
+	{ "clear.lines",		"nns",		&cmdClearLines },
+	{ "text.screen",		"",			&cmdTextScreen },
+	{ "graphics",			"",			&cmdGraphics },
+	{ "set.cursor.char",	"s",		&cmdSetCursorChar },
+	{ "set.text.attribute",	"nn",		&cmdSetTextAttribute },
+	{ "shake.screen",		"n",		&cmdShakeScreen },
+	{ "configure.screen",	"nnn",		&cmdConfigureScreen },
+	{ "status.line.on",		"",			&cmdStatusLineOn },
+	{ "status.line.off",	"",			&cmdStatusLineOff },
+	{ "set.string",			"ns",		&cmdSetString },
+	{ "get.string",			"ns",		&cmdGetString },
+	{ "word.to.string",		"nn",		&cmdWordToString },
+	{ "parse",				"n",		&cmdParse },
+	{ "get.num",			"nv",		&cmdGetNum },
+	{ "prevent.input",		"",			&cmdPreventInput },
+	{ "accept.input",		"",			&cmdAcceptInput },
+	{ "set.key",			"nnn",		&cmdSetKey },
+	{ "add.to.pic",			"nnnnnnn",	&cmdAddToPic },
+	{ "add.to.pic.v",		"vvvvvvv",	&cmdAddToPicF },
+	{ "status",				"",			&cmdStatus },
+	{ "save.game",			"",			&cmdSaveGame },
+	{ "restore.game",		"",			&cmdLoadGame },
+	{ "init.disk",			"",			&cmdInitDisk },
+	{ "restart.game",		"",			&cmdRestartGame },
+	{ "show.obj",			"n",		&cmdShowObj },
+	{ "random",				"nnv",		&cmdRandom },
+	{ "program.control",	"",			&cmdProgramControl },
+	{ "player.control",		"",			&cmdPlayerControl },
+	{ "obj.status.v",		"v",		&cmdObjStatusF },
+	{ "quit",				"n",		&cmdQuit },
+	{ "show.mem",			"",			&cmdShowMem },
+	{ "pause",				"",			&cmdPause },
+	{ "echo.line",			"",			&cmdEchoLine },
+	{ "cancel.line",		"",			&cmdCancelLine },
+	{ "init.joy",			"",			&cmdInitJoy },
+	{ "toggle.monitor",		"",			&cmdToggleMonitor },
+	{ "version",			"",			&cmdVersion },
+	{ "script.size",		"n",		&cmdScriptSize },
+	{ "set.game.id",		"s",		&cmdSetGameID },
+	{ "log",				"s",		&cmdLog },
+	{ "set.scan.start",		"",			&cmdSetScanStart },
+	{ "reset.scan.start",	"",			&cmdResetScanStart },
+	{ "reposition.to",		"nnn",		&cmdRepositionTo },
+	{ "reposition.to.v",	"nvv",		&cmdRepositionToF },
+	{ "trace.on",			"",			&cmdTraceOn },
+	{ "trace.info", 		"nnn",		&cmdTraceInfo },
+	{ "print.at",			"snnn",		&cmdPrintAt },
+	{ "print.at.v",			"vnnn",		&cmdPrintAtV },
+	{ "discard.view.v",		"v",		&cmdDiscardView},
+	{ "clear.text.rect",	"nnnnn",	&cmdClearTextRect },
+	{ "set.upper.left",		"nn",		&cmdSetUpperLeft },
+	{ "set.menu",			"s",		&cmdSetMenu },
+	{ "set.menu.member",	"sn",		&cmdSetMenuItem },
+	{ "submit.menu",		"",			&cmdSubmitMenu },
+	{ "enable.member",		"n",		&cmdEnableItem },
+	{ "disable.member",		"n",		&cmdDisableItem },
+	{ "menu.input",			"",			&cmdMenuInput },
+	{ "show.obj.v",			"v",		&cmdShowObjV },
+	{ "open.dialogue",		"",			&cmdOpenDialogue },
+	{ "close.dialogue",		"",			&cmdCloseDialogue },
+	{ "mul.n",				"vn",		&cmdMulN },
+	{ "mul.v",				"vv",		&cmdMulV },
+	{ "div.n",				"vn",		&cmdDivN },
+	{ "div.v",				"vv",		&cmdDivV },
+	{ "close.window",		"",			&cmdCloseWindow },
+	{ "set.simple",			"n",		&cmdSetSimple },
+	{ "push.script",		"",			&cmdPushScript },
+	{ "pop.script",			"",			&cmdPopScript },
+	{ "hold.key",			"",			&cmdHoldKey },
+	{ "set.pri.base",		"n",		&cmdSetPriBase },
+	{ "discard.sound",		"n",		&cmdDiscardSound },
+	{ "hide.mouse",			"",			&cmdHideMouse },
+	{ "allow.menu",			"n",		&cmdAllowMenu },
+	{ "show.mouse",			"",			&cmdShowMouse },
+	{ "fence.mouse",		"nnnn",		&cmdFenceMouse },
+	{ "mouse.posn",			"vv",		&cmdMousePosn },
+	{ "release.key",		"",			&cmdReleaseKey },
+	{ "adj.ego.move.to.xy",	"",			&cmdAdjEgoMoveToXY }
 };
 
 void AgiEngine::setupOpcodes() {
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 3939b2d..742b0d5 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -38,217 +38,217 @@ struct AgiInstruction {
 extern AgiInstruction *logicNamesTest;
 extern AgiInstruction *logicNamesCmd;
 
-void cmd_increment(AgiGame *state, uint8 *p);
-void cmd_decrement(AgiGame *state, uint8 *p);
-void cmd_assignn(AgiGame *state, uint8 *p);
-void cmd_assignv(AgiGame *state, uint8 *p);
-void cmd_addn(AgiGame *state, uint8 *p);
-void cmd_addv(AgiGame *state, uint8 *p);
-void cmd_subn(AgiGame *state, uint8 *p);
-void cmd_subv(AgiGame *state, uint8 *p);	// 0x08
-void cmd_lindirectv(AgiGame *state, uint8 *p);
-void cmd_rindirect(AgiGame *state, uint8 *p);
-void cmd_lindirectn(AgiGame *state, uint8 *p);
-void cmd_set(AgiGame *state, uint8 *p);
-void cmd_reset(AgiGame *state, uint8 *p);
-void cmd_toggle(AgiGame *state, uint8 *p);
-void cmd_set_v(AgiGame *state, uint8 *p);
-void cmd_reset_v(AgiGame *state, uint8 *p);	// 0x10
-void cmd_toggle_v(AgiGame *state, uint8 *p);
-void cmd_new_room(AgiGame *state, uint8 *p);
-void cmd_new_room_f(AgiGame *state, uint8 *p);
-void cmd_load_logic(AgiGame *state, uint8 *p);
-void cmd_load_logic_f(AgiGame *state, uint8 *p);
-void cmd_call(AgiGame *state, uint8 *p);
-void cmd_call_f(AgiGame *state, uint8 *p);
-void cmd_load_pic(AgiGame *state, uint8 *p);	// 0x18
-void cmd_draw_pic(AgiGame *state, uint8 *p);
-void cmd_show_pic(AgiGame *state, uint8 *p);
-void cmd_discard_pic(AgiGame *state, uint8 *p);
-void cmd_overlay_pic(AgiGame *state, uint8 *p);
-void cmd_show_pri_screen(AgiGame *state, uint8 *p);
-void cmd_load_view(AgiGame *state, uint8 *p);
-void cmd_load_view_f(AgiGame *state, uint8 *p);
-void cmd_discard_view(AgiGame *state, uint8 *p);	// 0x20
-void cmd_animate_obj(AgiGame *state, uint8 *p);
-void cmd_unanimate_all(AgiGame *state, uint8 *p);
-void cmd_draw(AgiGame *state, uint8 *p);
-void cmd_erase(AgiGame *state, uint8 *p);
-void cmd_position(AgiGame *state, uint8 *p);
-void cmd_position_f(AgiGame *state, uint8 *p);
-void cmd_get_posn(AgiGame *state, uint8 *p);
-void cmd_reposition(AgiGame *state, uint8 *p);	// 0x28
-void cmd_set_view(AgiGame *state, uint8 *p);
-void cmd_set_view_f(AgiGame *state, uint8 *p);
-void cmd_set_loop(AgiGame *state, uint8 *p);
-void cmd_set_loop_f(AgiGame *state, uint8 *p);
-void cmd_fix_loop(AgiGame *state, uint8 *p);
-void cmd_release_loop(AgiGame *state, uint8 *p);
-void cmd_set_cel(AgiGame *state, uint8 *p);
-void cmd_set_cel_f(AgiGame *state, uint8 *p);	// 0x30
-void cmd_last_cel(AgiGame *state, uint8 *p);
-void cmd_current_cel(AgiGame *state, uint8 *p);
-void cmd_current_loop(AgiGame *state, uint8 *p);
-void cmd_current_view(AgiGame *state, uint8 *p);
-void cmd_number_of_loops(AgiGame *state, uint8 *p);
-void cmd_set_priority(AgiGame *state, uint8 *p);
-void cmd_set_priority_f(AgiGame *state, uint8 *p);
-void cmd_release_priority(AgiGame *state, uint8 *p);	// 0x38
-void cmd_get_priority(AgiGame *state, uint8 *p);
-void cmd_stop_update(AgiGame *state, uint8 *p);
-void cmd_start_update(AgiGame *state, uint8 *p);
-void cmd_force_update(AgiGame *state, uint8 *p);
-void cmd_ignore_horizon(AgiGame *state, uint8 *p);
-void cmd_observe_horizon(AgiGame *state, uint8 *p);
-void cmd_set_horizon(AgiGame *state, uint8 *p);
-void cmd_object_on_water(AgiGame *state, uint8 *p);	// 0x40
-void cmd_object_on_land(AgiGame *state, uint8 *p);
-void cmd_object_on_anything(AgiGame *state, uint8 *p);
-void cmd_ignore_objs(AgiGame *state, uint8 *p);
-void cmd_observe_objs(AgiGame *state, uint8 *p);
-void cmd_distance(AgiGame *state, uint8 *p);
-void cmd_stop_cycling(AgiGame *state, uint8 *p);
-void cmd_start_cycling(AgiGame *state, uint8 *p);
-void cmd_normal_cycle(AgiGame *state, uint8 *p);	// 0x48
-void cmd_end_of_loop(AgiGame *state, uint8 *p);
-void cmd_reverse_cycle(AgiGame *state, uint8 *p);
-void cmd_reverse_loop(AgiGame *state, uint8 *p);
-void cmd_cycle_time(AgiGame *state, uint8 *p);
-void cmd_stop_motion(AgiGame *state, uint8 *p);
-void cmd_start_motion(AgiGame *state, uint8 *p);
-void cmd_step_size(AgiGame *state, uint8 *p);
-void cmd_step_time(AgiGame *state, uint8 *p);	// 0x50
-void cmd_move_obj(AgiGame *state, uint8 *p);
-void cmd_move_obj_f(AgiGame *state, uint8 *p);
-void cmd_follow_ego(AgiGame *state, uint8 *p);
-void cmd_wander(AgiGame *state, uint8 *p);
-void cmd_normal_motion(AgiGame *state, uint8 *p);
-void cmd_set_dir(AgiGame *state, uint8 *p);
-void cmd_get_dir(AgiGame *state, uint8 *p);
-void cmd_ignore_blocks(AgiGame *state, uint8 *p);	// 0x58
-void cmd_observe_blocks(AgiGame *state, uint8 *p);
-void cmd_block(AgiGame *state, uint8 *p);
-void cmd_unblock(AgiGame *state, uint8 *p);
-void cmd_get(AgiGame *state, uint8 *p);
-void cmd_get_f(AgiGame *state, uint8 *p);
-void cmd_drop(AgiGame *state, uint8 *p);
-void cmd_put(AgiGame *state, uint8 *p);
-void cmd_put_f(AgiGame *state, uint8 *p);	// 0x60
-void cmd_get_room_f(AgiGame *state, uint8 *p);
-void cmd_load_sound(AgiGame *state, uint8 *p);
-void cmd_sound(AgiGame *state, uint8 *p);
-void cmd_stop_sound(AgiGame *state, uint8 *p);
-void cmd_print(AgiGame *state, uint8 *p);
-void cmd_print_f(AgiGame *state, uint8 *p);
-void cmd_display(AgiGame *state, uint8 *p);
-void cmd_display_f(AgiGame *state, uint8 *p);	// 0x68
-void cmd_clear_lines(AgiGame *state, uint8 *p);
-void cmd_text_screen(AgiGame *state, uint8 *p);
-void cmd_graphics(AgiGame *state, uint8 *p);
-void cmd_set_cursor_char(AgiGame *state, uint8 *p);
-void cmd_set_text_attribute(AgiGame *state, uint8 *p);
-void cmd_shake_screen(AgiGame *state, uint8 *p);
-void cmd_configure_screen(AgiGame *state, uint8 *p);
-void cmd_status_line_on(AgiGame *state, uint8 *p);	// 0x70
-void cmd_status_line_off(AgiGame *state, uint8 *p);
-void cmd_set_string(AgiGame *state, uint8 *p);
-void cmd_get_string(AgiGame *state, uint8 *p);
-void cmd_word_to_string(AgiGame *state, uint8 *p);
-void cmd_parse(AgiGame *state, uint8 *p);
-void cmd_get_num(AgiGame *state, uint8 *p);
-void cmd_prevent_input(AgiGame *state, uint8 *p);
-void cmd_accept_input(AgiGame *state, uint8 *p);	// 0x78
-void cmd_set_key(AgiGame *state, uint8 *p);
-void cmd_add_to_pic(AgiGame *state, uint8 *p);
-void cmd_add_to_pic_f(AgiGame *state, uint8 *p);
-void cmd_status(AgiGame *state, uint8 *p);
-void cmd_save_game(AgiGame *state, uint8 *p);
-void cmd_load_game(AgiGame *state, uint8 *p);
-void cmd_init_disk(AgiGame *state, uint8 *p);
-void cmd_restart_game(AgiGame *state, uint8 *p);	// 0x80
-void cmd_show_obj(AgiGame *state, uint8 *p);
-void cmd_random(AgiGame *state, uint8 *p);
-void cmd_program_control(AgiGame *state, uint8 *p);
-void cmd_player_control(AgiGame *state, uint8 *p);
-void cmd_obj_status_f(AgiGame *state, uint8 *p);
-void cmd_quit(AgiGame *state, uint8 *p);
-void cmd_show_mem(AgiGame *state, uint8 *p);
-void cmd_pause(AgiGame *state, uint8 *p);	// 0x88
-void cmd_echo_line(AgiGame *state, uint8 *p);
-void cmd_cancel_line(AgiGame *state, uint8 *p);
-void cmd_init_joy(AgiGame *state, uint8 *p);
-void cmd_toggle_monitor(AgiGame *state, uint8 *p);
-void cmd_version(AgiGame *state, uint8 *p);
-void cmd_script_size(AgiGame *state, uint8 *p);
-void cmd_set_game_id(AgiGame *state, uint8 *p);
-void cmd_log(AgiGame *state, uint8 *p);	// 0x90
-void cmd_set_scan_start(AgiGame *state, uint8 *p);
-void cmd_reset_scan_start(AgiGame *state, uint8 *p);
-void cmd_reposition_to(AgiGame *state, uint8 *p);
-void cmd_reposition_to_f(AgiGame *state, uint8 *p);
-void cmd_trace_on(AgiGame *state, uint8 *p);
-void cmd_trace_info(AgiGame *state, uint8 *p);
-void cmd_print_at(AgiGame *state, uint8 *p);
-void cmd_print_at_v(AgiGame *state, uint8 *p);	// 0x98
-//void cmd_discard_view(AgiGame *state, uint8 *p);	// Opcode repeated from 0x20 ?
-void cmd_clear_text_rect(AgiGame *state, uint8 *p);
-void cmd_set_upper_left(AgiGame *state, uint8 *p);
-void cmd_set_menu(AgiGame *state, uint8 *p);
-void cmd_set_menu_item(AgiGame *state, uint8 *p);
-void cmd_submit_menu(AgiGame *state, uint8 *p);
-void cmd_enable_item(AgiGame *state, uint8 *p);
-void cmd_disable_item(AgiGame *state, uint8 *p);	// 0xa0
-void cmd_menu_input(AgiGame *state, uint8 *p);
-void cmd_show_obj_v(AgiGame *state, uint8 *p);
-void cmd_open_dialogue(AgiGame *state, uint8 *p);
-void cmd_close_dialogue(AgiGame *state, uint8 *p);
-void cmd_mul_n(AgiGame *state, uint8 *p);
-void cmd_mul_v(AgiGame *state, uint8 *p);
-void cmd_div_n(AgiGame *state, uint8 *p);
-void cmd_div_v(AgiGame *state, uint8 *p);	// 0xa8
-void cmd_close_window(AgiGame *state, uint8 *p);
-void cmd_set_simple(AgiGame *state, uint8 *p);
-void cmd_push_script(AgiGame *state, uint8 *p);
-void cmd_pop_script(AgiGame *state, uint8 *p);
-void cmd_hold_key(AgiGame *state, uint8 *p);
-void cmd_set_pri_base(AgiGame *state, uint8 *p);
-void cmd_discard_sound(AgiGame *state, uint8 *p);
-void cmd_hide_mouse(AgiGame *state, uint8 *p);	// 0xb0
-void cmd_allow_menu(AgiGame *state, uint8 *p);
-void cmd_show_mouse(AgiGame *state, uint8 *p);
-void cmd_fence_mouse(AgiGame *state, uint8 *p);
-void cmd_mouse_posn(AgiGame *state, uint8 *p);
-void cmd_release_key(AgiGame *state, uint8 *p);
-void cmd_adj_ego_move_to_x_y(AgiGame *state, uint8 *p);
+void cmdIncrement(AgiGame *state, uint8 *p);
+void cmdDecrement(AgiGame *state, uint8 *p);
+void cmdAssignN(AgiGame *state, uint8 *p);
+void cmdAssignV(AgiGame *state, uint8 *p);
+void cmdAddN(AgiGame *state, uint8 *p);
+void cmdAddV(AgiGame *state, uint8 *p);
+void cmdSubN(AgiGame *state, uint8 *p);
+void cmdSubV(AgiGame *state, uint8 *p);	// 0x08
+void cmdLindirectV(AgiGame *state, uint8 *p);
+void cmdRindirect(AgiGame *state, uint8 *p);
+void cmdLindirectN(AgiGame *state, uint8 *p);
+void cmdSet(AgiGame *state, uint8 *p);
+void cmdReset(AgiGame *state, uint8 *p);
+void cmdToggle(AgiGame *state, uint8 *p);
+void cmdSetV(AgiGame *state, uint8 *p);
+void cmdResetV(AgiGame *state, uint8 *p);	// 0x10
+void cmdToggleV(AgiGame *state, uint8 *p);
+void cmdNewRoom(AgiGame *state, uint8 *p);
+void cmdNewRoomF(AgiGame *state, uint8 *p);
+void cmdLoadLogic(AgiGame *state, uint8 *p);
+void cmdLoadLogicF(AgiGame *state, uint8 *p);
+void cmdCall(AgiGame *state, uint8 *p);
+void cmdCallF(AgiGame *state, uint8 *p);
+void cmdLoadPic(AgiGame *state, uint8 *p);	// 0x18
+void cmdDrawPic(AgiGame *state, uint8 *p);
+void cmdShowPic(AgiGame *state, uint8 *p);
+void cmdDiscardPic(AgiGame *state, uint8 *p);
+void cmdOverlayPic(AgiGame *state, uint8 *p);
+void cmdShowPriScreen(AgiGame *state, uint8 *p);
+void cmdLoadView(AgiGame *state, uint8 *p);
+void cmdLoadViewF(AgiGame *state, uint8 *p);
+void cmdDiscardView(AgiGame *state, uint8 *p);	// 0x20
+void cmdAnimateObj(AgiGame *state, uint8 *p);
+void cmdUnanimateAll(AgiGame *state, uint8 *p);
+void cmdDraw(AgiGame *state, uint8 *p);
+void cmdErase(AgiGame *state, uint8 *p);
+void cmdPosition(AgiGame *state, uint8 *p);
+void cmdPositionF(AgiGame *state, uint8 *p);
+void cmdGetPosn(AgiGame *state, uint8 *p);
+void cmdReposition(AgiGame *state, uint8 *p);	// 0x28
+void cmdSetView(AgiGame *state, uint8 *p);
+void cmdSetViewF(AgiGame *state, uint8 *p);
+void cmdSetLoop(AgiGame *state, uint8 *p);
+void cmdSetLoopF(AgiGame *state, uint8 *p);
+void cmdFixLoop(AgiGame *state, uint8 *p);
+void cmdReleaseLoop(AgiGame *state, uint8 *p);
+void cmdSetCel(AgiGame *state, uint8 *p);
+void cmdSetCelF(AgiGame *state, uint8 *p);	// 0x30
+void cmdLastCel(AgiGame *state, uint8 *p);
+void cmdCurrentCel(AgiGame *state, uint8 *p);
+void cmdCurrentLoop(AgiGame *state, uint8 *p);
+void cmdCurrentView(AgiGame *state, uint8 *p);
+void cmdNumberOfLoops(AgiGame *state, uint8 *p);
+void cmdSetPriority(AgiGame *state, uint8 *p);
+void cmdSetPriorityF(AgiGame *state, uint8 *p);
+void cmdReleasePriority(AgiGame *state, uint8 *p);	// 0x38
+void cmdGetPriority(AgiGame *state, uint8 *p);
+void cmdStopUpdate(AgiGame *state, uint8 *p);
+void cmdStartUpdate(AgiGame *state, uint8 *p);
+void cmdForceUpdate(AgiGame *state, uint8 *p);
+void cmdIgnoreHorizon(AgiGame *state, uint8 *p);
+void cmdObserveHorizon(AgiGame *state, uint8 *p);
+void cmdSetHorizon(AgiGame *state, uint8 *p);
+void cmdObjectOnWater(AgiGame *state, uint8 *p);	// 0x40
+void cmdObjectOnLand(AgiGame *state, uint8 *p);
+void cmdObjectOnAnything(AgiGame *state, uint8 *p);
+void cmdIgnoreObjs(AgiGame *state, uint8 *p);
+void cmdObserveObjs(AgiGame *state, uint8 *p);
+void cmdDistance(AgiGame *state, uint8 *p);
+void cmdStopCycling(AgiGame *state, uint8 *p);
+void cmdStartCycling(AgiGame *state, uint8 *p);
+void cmdNormalCycle(AgiGame *state, uint8 *p);	// 0x48
+void cmdEndOfLoop(AgiGame *state, uint8 *p);
+void cmdReverseCycle(AgiGame *state, uint8 *p);
+void cmdReverseLoop(AgiGame *state, uint8 *p);
+void cmdCycleTime(AgiGame *state, uint8 *p);
+void cmdStopMotion(AgiGame *state, uint8 *p);
+void cmdStartMotion(AgiGame *state, uint8 *p);
+void cmdStepSize(AgiGame *state, uint8 *p);
+void cmdStepTime(AgiGame *state, uint8 *p);	// 0x50
+void cmdMoveObj(AgiGame *state, uint8 *p);
+void cmdMoveObjF(AgiGame *state, uint8 *p);
+void cmdFollowEgo(AgiGame *state, uint8 *p);
+void cmdWander(AgiGame *state, uint8 *p);
+void cmdNormalMotion(AgiGame *state, uint8 *p);
+void cmdSetDir(AgiGame *state, uint8 *p);
+void cmdGetDir(AgiGame *state, uint8 *p);
+void cmdIgnoreBlocks(AgiGame *state, uint8 *p);	// 0x58
+void cmdObserveBlocks(AgiGame *state, uint8 *p);
+void cmdBlock(AgiGame *state, uint8 *p);
+void cmdUnblock(AgiGame *state, uint8 *p);
+void cmdGet(AgiGame *state, uint8 *p);
+void cmdGetF(AgiGame *state, uint8 *p);
+void cmdDrop(AgiGame *state, uint8 *p);
+void cmdPut(AgiGame *state, uint8 *p);
+void cmdPutF(AgiGame *state, uint8 *p);	// 0x60
+void cmdGetRoomF(AgiGame *state, uint8 *p);
+void cmdLoadSound(AgiGame *state, uint8 *p);
+void cmdSound(AgiGame *state, uint8 *p);
+void cmdStopSound(AgiGame *state, uint8 *p);
+void cmdPrint(AgiGame *state, uint8 *p);
+void cmdPrintF(AgiGame *state, uint8 *p);
+void cmdDisplay(AgiGame *state, uint8 *p);
+void cmdDisplayF(AgiGame *state, uint8 *p);	// 0x68
+void cmdClearLines(AgiGame *state, uint8 *p);
+void cmdTextScreen(AgiGame *state, uint8 *p);
+void cmdGraphics(AgiGame *state, uint8 *p);
+void cmdSetCursorChar(AgiGame *state, uint8 *p);
+void cmdSetTextAttribute(AgiGame *state, uint8 *p);
+void cmdShakeScreen(AgiGame *state, uint8 *p);
+void cmdConfigureScreen(AgiGame *state, uint8 *p);
+void cmdStatusLineOn(AgiGame *state, uint8 *p);	// 0x70
+void cmdStatusLineOff(AgiGame *state, uint8 *p);
+void cmdSetString(AgiGame *state, uint8 *p);
+void cmdGetString(AgiGame *state, uint8 *p);
+void cmdWordToString(AgiGame *state, uint8 *p);
+void cmdParse(AgiGame *state, uint8 *p);
+void cmdGetNum(AgiGame *state, uint8 *p);
+void cmdPreventInput(AgiGame *state, uint8 *p);
+void cmdAcceptInput(AgiGame *state, uint8 *p);	// 0x78
+void cmdSetKey(AgiGame *state, uint8 *p);
+void cmdAddToPic(AgiGame *state, uint8 *p);
+void cmdAddToPicF(AgiGame *state, uint8 *p);
+void cmdStatus(AgiGame *state, uint8 *p);
+void cmdSaveGame(AgiGame *state, uint8 *p);
+void cmdLoadGame(AgiGame *state, uint8 *p);
+void cmdInitDisk(AgiGame *state, uint8 *p);
+void cmdRestartGame(AgiGame *state, uint8 *p);	// 0x80
+void cmdShowObj(AgiGame *state, uint8 *p);
+void cmdRandom(AgiGame *state, uint8 *p);
+void cmdProgramControl(AgiGame *state, uint8 *p);
+void cmdPlayerControl(AgiGame *state, uint8 *p);
+void cmdObjStatusF(AgiGame *state, uint8 *p);
+void cmdQuit(AgiGame *state, uint8 *p);
+void cmdShowMem(AgiGame *state, uint8 *p);
+void cmdPause(AgiGame *state, uint8 *p);	// 0x88
+void cmdEchoLine(AgiGame *state, uint8 *p);
+void cmdCancelLine(AgiGame *state, uint8 *p);
+void cmdInitJoy(AgiGame *state, uint8 *p);
+void cmdToggleMonitor(AgiGame *state, uint8 *p);
+void cmdVersion(AgiGame *state, uint8 *p);
+void cmdScriptSize(AgiGame *state, uint8 *p);
+void cmdSetGameID(AgiGame *state, uint8 *p);
+void cmdLog(AgiGame *state, uint8 *p);	// 0x90
+void cmdSetScanStart(AgiGame *state, uint8 *p);
+void cmdResetScanStart(AgiGame *state, uint8 *p);
+void cmdRepositionTo(AgiGame *state, uint8 *p);
+void cmdRepositionToF(AgiGame *state, uint8 *p);
+void cmdTraceOn(AgiGame *state, uint8 *p);
+void cmdTraceInfo(AgiGame *state, uint8 *p);
+void cmdPrintAt(AgiGame *state, uint8 *p);
+void cmdPrintAtV(AgiGame *state, uint8 *p);	// 0x98
+//void cmdDiscardView(AgiGame *state, uint8 *p);	// Opcode repeated from 0x20 ?
+void cmdClearTextRect(AgiGame *state, uint8 *p);
+void cmdSetUpperLeft(AgiGame *state, uint8 *p);
+void cmdSetMenu(AgiGame *state, uint8 *p);
+void cmdSetMenuItem(AgiGame *state, uint8 *p);
+void cmdSubmitMenu(AgiGame *state, uint8 *p);
+void cmdEnableItem(AgiGame *state, uint8 *p);
+void cmdDisableItem(AgiGame *state, uint8 *p);	// 0xa0
+void cmdMenuInput(AgiGame *state, uint8 *p);
+void cmdShowObjV(AgiGame *state, uint8 *p);
+void cmdOpenDialogue(AgiGame *state, uint8 *p);
+void cmdCloseDialogue(AgiGame *state, uint8 *p);
+void cmdMulN(AgiGame *state, uint8 *p);
+void cmdMulV(AgiGame *state, uint8 *p);
+void cmdDivN(AgiGame *state, uint8 *p);
+void cmdDivV(AgiGame *state, uint8 *p);	// 0xa8
+void cmdCloseWindow(AgiGame *state, uint8 *p);
+void cmdSetSimple(AgiGame *state, uint8 *p);
+void cmdPushScript(AgiGame *state, uint8 *p);
+void cmdPopScript(AgiGame *state, uint8 *p);
+void cmdHoldKey(AgiGame *state, uint8 *p);
+void cmdSetPriBase(AgiGame *state, uint8 *p);
+void cmdDiscardSound(AgiGame *state, uint8 *p);
+void cmdHideMouse(AgiGame *state, uint8 *p);	// 0xb0
+void cmdAllowMenu(AgiGame *state, uint8 *p);
+void cmdShowMouse(AgiGame *state, uint8 *p);
+void cmdFenceMouse(AgiGame *state, uint8 *p);
+void cmdMousePosn(AgiGame *state, uint8 *p);
+void cmdReleaseKey(AgiGame *state, uint8 *p);
+void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p);
 
-void cmd_set_speed(AgiGame *state, uint8 *p);
-void cmd_unknown(AgiGame *state, uint8 *p);
+void cmdSetSpeed(AgiGame *state, uint8 *p);
+void cmdUnknown(AgiGame *state, uint8 *p);
 
-void cond_equal(AgiGame *state, uint8 *p);
-void cond_equalv(AgiGame *state, uint8 *p);
-void cond_less(AgiGame *state, uint8 *p);
-void cond_lessv(AgiGame *state, uint8 *p);
-void cond_greater(AgiGame *state, uint8 *p);
-void cond_greaterv(AgiGame *state, uint8 *p);
-void cond_isset(AgiGame *state, uint8 *p);
-void cond_issetv(AgiGame *state, uint8 *p);
-void cond_has(AgiGame *state, uint8 *p);
-void cond_obj_in_room(AgiGame *state, uint8 *p);
-void cond_posn(AgiGame *state, uint8 *p);
-void cond_controller(AgiGame *state, uint8 *p);
-void cond_have_key(AgiGame *state, uint8 *p);
-void cond_said(AgiGame *state, uint8 *p);
-void cond_compare_strings(AgiGame *state, uint8 *p);
-void cond_obj_in_box(AgiGame *state, uint8 *p);
-void cond_center_posn(AgiGame *state, uint8 *p);
-void cond_right_posn(AgiGame *state, uint8 *p);
-void cond_unknown_13(AgiGame *state, uint8 *p);
-void cond_unknown(AgiGame *state, uint8 *p);
+void condEqual(AgiGame *state, uint8 *p);
+void condEqualV(AgiGame *state, uint8 *p);
+void condLess(AgiGame *state, uint8 *p);
+void condLessV(AgiGame *state, uint8 *p);
+void condGreater(AgiGame *state, uint8 *p);
+void condGreaterV(AgiGame *state, uint8 *p);
+void condIsSet(AgiGame *state, uint8 *p);
+void condIsSetV(AgiGame *state, uint8 *p);
+void condHas(AgiGame *state, uint8 *p);
+void condObjInRoom(AgiGame *state, uint8 *p);
+void condPosn(AgiGame *state, uint8 *p);
+void condController(AgiGame *state, uint8 *p);
+void condHaveKey(AgiGame *state, uint8 *p);
+void condSaid(AgiGame *state, uint8 *p);
+void condCompareStrings(AgiGame *state, uint8 *p);
+void condObjInBox(AgiGame *state, uint8 *p);
+void condCenterPosn(AgiGame *state, uint8 *p);
+void condRightPosn(AgiGame *state, uint8 *p);
+void condUnknown13(AgiGame *state, uint8 *p);
+void condUnknown(AgiGame *state, uint8 *p);
 
-void cond_isset_v1(AgiGame *state, uint8 *p);
-void cond_said1(AgiGame *state, uint8 *p);
-void cond_said2(AgiGame *state, uint8 *p);
-void cond_said3(AgiGame *state, uint8 *p);
+void condIsSetV1(AgiGame *state, uint8 *p);
+void condSaid1(AgiGame *state, uint8 *p);
+void condSaid2(AgiGame *state, uint8 *p);
+void condSaid3(AgiGame *state, uint8 *p);
 
 } // End of namespace Agi
 


Commit: e4a1193d22142be750e20ab0a32f03f8c11cf950
    https://github.com/scummvm/scummvm/commit/e4a1193d22142be750e20ab0a32f03f8c11cf950
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:17-07:00

Commit Message:
AGI: Add last undefined V1 test command that tests if a bit of var is set

Also fix skipInstruction() for V1.

Changed paths:
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index 70d0cc0..a99a4ea 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -155,6 +155,10 @@ void condSaid3(AgiGame *state, uint8 *p) {
 		state->testResult = true;
 }
 
+void condBit(AgiGame *state, uint8 *p) {
+	state->testResult = (getvar(p[1]) >> p[0]) & 1;
+}
+
 void condCompareStrings(AgiGame *state, uint8 *p) {
 	debugC(7, kDebugLevelScripts, "comparing [%s], [%s]", state->strings[p[0]], state->strings[p[1]]);
 	state->testResult = state->_vm->testCompareStrings(p[0], p[1]);
@@ -446,7 +450,7 @@ void AgiEngine::skipInstruction(byte op) {
 	AgiGame *state = &_game;
 	if (op >= 0xFC)
 		return;
-	if (op == 0x0E) // said
+	if (op == 0x0E && state->_vm->getVersion() >= 0x2000) // said
 		ip += *(code + ip) * 2 + 1;
 	else
 		ip += logicNamesTest[op].argumentsLength();
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index b2bccd8..ba7f587 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -36,7 +36,7 @@ AgiInstruction insV1Test[] = {
 	{ "lessv",				"vv",		&condLessV },		// 04
 	{ "greatern",			"vn",		&condGreater },		// 05
 	{ "greaterv",			"vv",		&condGreaterV },	// 06
-	{ "isset",				"v",		&condIsSetV1 },	// 07
+	{ "isset",				"v",		&condIsSetV1 },		// 07
 	{ "has",				"n",		&condHas },			// 08
 	{ "said",				"nnnn",		&condSaid2 },		// 09
 	{ "posn",				"nnnnn",	&condPosn },		// 0A
@@ -45,7 +45,7 @@ AgiInstruction insV1Test[] = {
 	{ "said",				"nnnnnn",	&condSaid3 },		// 0D
 	{ "have.key",			"",			&condHaveKey },		// 0E
 	{ "said",				"nn",		&condSaid1 },		// 0F
-	{ "bit",				"nv",		&condUnknown },		// 10
+	{ "bit",				"nv",		&condBit },			// 10
 };
 
 AgiInstruction insV1[] = {
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 742b0d5..f45a52b 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -249,6 +249,7 @@ void condIsSetV1(AgiGame *state, uint8 *p);
 void condSaid1(AgiGame *state, uint8 *p);
 void condSaid2(AgiGame *state, uint8 *p);
 void condSaid3(AgiGame *state, uint8 *p);
+void condBit(AgiGame *state, uint8 *p);
 
 } // End of namespace Agi
 


Commit: d2f9087f20864bc2268dc7795b2e4ff023cd7758
    https://github.com/scummvm/scummvm/commit/d2f9087f20864bc2268dc7795b2e4ff023cd7758
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:20-07:00

Commit Message:
AGI: Fix warning messages about undefined opcodes

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 42c3e57..bd189ee 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -41,6 +41,7 @@ namespace Agi {
 #define p5	(p[5])
 #define p6	(p[6])
 
+#define code state->_curLogic->data
 #define ip	state->_curLogic->cIP
 #define vt	state->viewTable[p0]
 #define vt_v state->viewTable[state->vars[p0]]
@@ -1581,7 +1582,7 @@ void cmdSetSpeed(AgiGame *state, uint8 *p) {
 }
 
 void cmdUnknown(AgiGame *state, uint8 *p) {
-	warning("Skipping unknown opcode %2X", *(p - 1));
+	warning("Skipping unknown opcode %2X", *(code + ip - 1));
 }
 
 /**
@@ -1589,12 +1590,11 @@ void cmdUnknown(AgiGame *state, uint8 *p) {
  * @param n  Number of the logic resource to execute
  */
 int AgiEngine::runLogic(int n) {
+	AgiGame *state = &_game;
 	uint8 op = 0;
 	uint8 p[CMD_BSIZE] = { 0 };
-	uint8 *code = NULL;
 	int num = 0;
 	ScriptPos sp;
-	AgiGame *state = &_game;
 
 	debugC(2, kDebugLevelScripts, "=================");
 	debugC(2, kDebugLevelScripts, "runLogic(%d)", n);
@@ -1612,7 +1612,6 @@ int AgiEngine::runLogic(int n) {
 	_game.lognum = n;
 	_game._curLogic = &_game.logics[_game.lognum];
 
-	code = _game._curLogic->data;
 	_game._curLogic->cIP = _game._curLogic->sIP;
 
 	_timerHack = 0;
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index a99a4ea..f8fd767 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -189,7 +189,7 @@ void condUnknown13(AgiGame *state, uint8 *p) {
 }
 
 void condUnknown(AgiGame *state, uint8 *p) {
-	warning("Skipping unknown test command %2X", *(p - 1));
+	warning("Skipping unknown test command %2X", *(code + ip - 1));
 	state->testResult = false;
 }
 


Commit: 1dbe5bfccfb3d10b31ea9b5ac567165c650b3f98
    https://github.com/scummvm/scummvm/commit/1dbe5bfccfb3d10b31ea9b5ac567165c650b3f98
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:22-07:00

Commit Message:
AGI: Implement loader for V1 "object" file

Changed paths:
    engines/agi/agi.h
    engines/agi/loader_v1.cpp
    engines/agi/objects.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 48a9aa5..1c89718 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -969,16 +969,21 @@ public:
 	void checkQuickLoad();
 
 	// Objects
+public:
 	int showObjects();
-	int decodeObjects(uint8 *mem, uint32 flen);
 	int loadObjects(const char *fname);
-	int allocObjects(int);
+	int loadObjects(Common::File &fp);
 	void unloadObjects();
 	const char *objectName(unsigned int);
 	int objectGetLocation(unsigned int);
 	void objectSetLocation(unsigned int, int);
+private:
+	int decodeObjects(uint8 *mem, uint32 flen);
+	int readObjects(Common::File &fp, int flen);
+	int allocObjects(int);
 
 	// Logic
+public:
 	int decodeLogic(int);
 	void unloadLogic(int);
 	int runLogic(int);
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 02a20c9..8da74ce 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -45,6 +45,7 @@
 #define BC_SNDDIR_SEC	SECTOR_OFFSET(99) + 5
 #define BC_SNDDIR_MAX	29
 #define BC_WORDS		SECTOR_OFFSET(0x26D) + 5
+#define BC_OBJECTS		SECTOR_OFFSET(0x1E6) + 3
 
 namespace Agi {
 
@@ -308,9 +309,14 @@ int AgiLoader_v1::unloadResource(int t, int n) {
 	return errOK;
 }
 
-// TODO: Find the disk image equivalent.
 int AgiLoader_v1::loadObjects(const char *fname) {
-	return _vm->loadObjects(fname);
+	if (_vm->getGameID() == GID_BC) {
+		Common::File f;
+		f.open(_filenameDisk0);
+		f.seek(BC_OBJECTS, SEEK_SET);
+		return _vm->loadObjects(f);
+	}
+	return errOK;
 }
 
 int AgiLoader_v1::loadWords(const char *fname) {
diff --git a/engines/agi/objects.cpp b/engines/agi/objects.cpp
index e04c974..efc8645 100644
--- a/engines/agi/objects.cpp
+++ b/engines/agi/objects.cpp
@@ -34,7 +34,7 @@ int AgiEngine::allocObjects(int n) {
 }
 
 int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) {
-	unsigned int i, so, padsize;
+	unsigned int i, so, padsize, spos;
 
 	padsize = _game.gameFlags & ID_AMIGA ? 4 : 3;
 
@@ -64,11 +64,12 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) {
 		return errNotEnoughMemory;
 
 	// build the object list
-	for (i = 0, so = padsize; i < _game.numObjects; i++, so += padsize) {
+	spos = getVersion() >= 0x2000 ? padsize : 0;
+	for (i = 0, so = spos; i < _game.numObjects; i++, so += padsize) {
 		int offset;
 
 		(_objects + i)->location = *(mem + so + 2);
-		offset = READ_LE_UINT16(mem + so) + padsize;
+		offset = READ_LE_UINT16(mem + so) + spos;
 
 		if ((uint) offset < flen) {
 			(_objects + i)->name = (char *)strdup((const char *)mem + offset);
@@ -84,20 +85,33 @@ int AgiEngine::decodeObjects(uint8 *mem, uint32 flen) {
 
 int AgiEngine::loadObjects(const char *fname) {
 	Common::File fp;
-	uint32 flen;
-	uint8 *mem;
-
-	_objects = NULL;
-	_game.numObjects = 0;
 
 	debugC(5, kDebugLevelResources, "(Loading objects '%s')", fname);
 
 	if (!fp.open(fname))
 		return errBadFileOpen;
 
-	fp.seek(0, SEEK_END);
-	flen = fp.pos();
-	fp.seek(0, SEEK_SET);
+	return readObjects(fp, fp.size());
+}
+
+/**
+ * Loads an object file that is in the common VOL resource format. Expects
+ * the file pointer to point to the last field in header, ie. file length.
+ * This is used at least by the V1 booter games.
+ */
+int AgiEngine::loadObjects(Common::File &fp) {
+	int flen = fp.readUint16LE();
+	return readObjects(fp, flen);
+}
+
+/**
+ * Read and decode objects, and store them in the internal structure.
+ *
+ * @param  fp    File pointer
+ * @param  flen  File length
+ */
+int AgiEngine::readObjects(Common::File &fp, int flen) {
+	uint8 *mem;
 
 	if ((mem = (uint8 *)calloc(1, flen + 32)) == NULL) {
 		fp.close();


Commit: af691e46c4ccbe0457d2a7d5a4386d9287518740
    https://github.com/scummvm/scummvm/commit/af691e46c4ccbe0457d2a7d5a4386d9287518740
Author: Jussi Pitkanen (pitkajus at paju.oulu.fi)
Date: 2011-08-13T15:27:24-07:00

Commit Message:
AGI: Updates to V1 instruction table, plus an outcommented experiment

The experiment tries to implement the program control of the V1 interpreter.
Maybe it is better to add another method for doing that once the workings of
it are more clear.

Changed paths:
    engines/agi/agi.h
    engines/agi/op_cmd.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 1c89718..5795801 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -640,6 +640,10 @@ struct AgiGame {
 
 	// IF condition handling
 	int testResult;
+
+
+	int max_logics;
+	int logic_list[256];
 };
 
 /**
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index bd189ee..673cac4 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -1420,9 +1420,11 @@ void cmdSetString(AgiGame *state, uint8 *p) {
 }
 
 void cmdDisplay(AgiGame *state, uint8 *p) {
+	// V1 has 4 args
+	int t = (getVersion() >= 0x2000 ? p2 : p3);
 	int len = 40;
 
-	char *s = state->_vm->wordWrapString(state->_curLogic->texts[p2 - 1], &len);
+	char *s = state->_vm->wordWrapString(state->_curLogic->texts[t - 1], &len);
 
 	state->_vm->printText(s, p1, 0, p0, 40, state->colorFg, state->colorBg);
 
@@ -1581,6 +1583,34 @@ void cmdSetSpeed(AgiGame *state, uint8 *p) {
 	(void)p;
 }
 
+void cmdSetItemView(AgiGame *state, uint8 *p) {
+	// V1 command
+	(void)state;
+	(void)p;
+}
+
+void cmdCallV1(AgiGame *state, uint8 *p) {
+	state->_vm->agiLoadResource(rLOGIC, p0);
+	state->logic_list[++state->max_logics];
+	_v[13] = 1;
+}
+
+void cmdNewRoomV1(AgiGame *state, uint8 *p) {
+	warning("cmdNewRoomV1()");
+	state->_vm->agiLoadResource(rLOGIC, p0);
+	state->max_logics = 1;
+	state->logic_list[1] = p0;
+	_v[13] = 1;
+}
+
+void cmdNewRoomVV1(AgiGame *state, uint8 *p) {
+	warning("cmdNewRoomVV1()");
+	state->_vm->agiLoadResource(rLOGIC, _v[p0]);
+	state->max_logics = 1;
+	state->logic_list[1] = _v[p0];
+	_v[13] = 1;
+}
+
 void cmdUnknown(AgiGame *state, uint8 *p) {
 	warning("Skipping unknown opcode %2X", *(code + ip - 1));
 }
@@ -1595,6 +1625,10 @@ int AgiEngine::runLogic(int n) {
 	uint8 p[CMD_BSIZE] = { 0 };
 	int num = 0;
 	ScriptPos sp;
+	//int logic_index = 0;
+
+	state->logic_list[0] = 0;
+	state->max_logics = 0;
 
 	debugC(2, kDebugLevelScripts, "=================");
 	debugC(2, kDebugLevelScripts, "runLogic(%d)", n);
@@ -1659,6 +1693,18 @@ int AgiEngine::runLogic(int n) {
 			debugC(2, kDebugLevelScripts, "%sreturn() // Logic %d", st, n);
 			debugC(2, kDebugLevelScripts, "=================");
 
+//			if (getVersion() < 0x2000) {
+//				if (logic_index < state->max_logics) {
+//					n = state->logic_list[++logic_index];
+//					state->_curLogic = &state->logics[n];
+//					state->lognum = n;
+//					ip = 2;
+//					warning("running logic %d\n", n);
+//					break;
+//				}
+//				_v[13]=0;
+//			}
+
 			_game.execStack.pop_back();
 			return 1;
 		default:
@@ -1672,6 +1718,14 @@ int AgiEngine::runLogic(int n) {
 			ip += num;
 		}
 
+//		if ((op == 0x0B || op == 0x3F || op == 0x40) && logic_index < state->max_logics) {
+//			n = state->logic_list[++logic_index];
+//			state->_curLogic = &state->logics[n];
+//			state->lognum = n;
+//			ip = 2;
+//			warning("running logic %d\n", n);
+//		}
+		
 		if (_game.exitAllLogics)
 			break;
 	}
@@ -1685,7 +1739,6 @@ void AgiEngine::executeAgiCommand(uint8 op, uint8 *p) {
 	debugC(2, kDebugLevelScripts, "%s(%d %d %d)", logicNamesCmd[op].name, p[0], p[1], p[2]);
 
 	_agiCommands[op](&_game, p);
-//	(this->*_agiCommands[op])(p);
 }
 
 } // End of namespace Agi
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index ba7f587..e69d167 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -49,103 +49,103 @@ AgiInstruction insV1Test[] = {
 };
 
 AgiInstruction insV1[] = {
-	{ "return",				"",			NULL },						// 00
-	{ "increment",			"v",		&cmdIncrement },			// 01
-	{ "decrement",			"v",		&cmdDecrement },			// 02
-	{ "assignn",			"vn",		&cmdAssignN },				// 03
-	{ "assignv",			"vv",		&cmdAssignV },				// 04
+	{ "return",				"",			NULL },					// 00
+	{ "increment",			"v",		&cmdIncrement },		// 01
+	{ "decrement",			"v",		&cmdDecrement },		// 02
+	{ "assignn",			"vn",		&cmdAssignN },			// 03
+	{ "assignv",			"vv",		&cmdAssignV },			// 04
 	{ "addn",				"vn",		&cmdAddN },				// 05
 	{ "addv",				"vv",		&cmdAddV },				// 06
 	{ "subn",				"vn",		&cmdSubN },				// 07
 	{ "subv",				"vv",		&cmdSubV },				// 08
 	{ "load.view",			"n",		&cmdLoadView },			// 09
-	{ "animate.obj",		"n",		&cmdAnimateObj },			// 0A
-	{ "new.room",			"n",		&cmdNewRoom },			// 0B
+	{ "animate.obj",		"n",		&cmdAnimateObj },		// 0A
+	{ "new.room",			"n",		&cmdNewRoomV1 },		// 0B
 	{ "draw.pic",			"v",		&cmdDrawPic },			// 0C
-	{ "print",				"s",		&cmdPrint },				// 0D
-	{ "status",				"",			&cmdStatus },				// 0E
+	{ "print",				"s",		&cmdPrint },			// 0D
+	{ "status",				"",			&cmdStatus },			// 0E
 	{ "save.game",			"",			&cmdSaveGame },			// 0F
 	{ "restore.game",		"",			&cmdLoadGame },			// 10
 	{ "...",				"",			&cmdInitDisk },			// 11 TODO
 	{ "restart.game",		"",			&cmdRestartGame },		// 12
-	{ "random",				"v",		&cmdRandom },				// 13 TODO: 1 vs 3 vars
-	{ "get",				"n",		&cmdGet },					// 14
+	{ "random",				"v",		&cmdRandom },			// 13 TODO: 1 vs 3 vars
+	{ "get",				"n",		&cmdGet },				// 14
 	{ "drop",				"n",		&cmdDrop },				// 15
 	{ "draw",				"n",		&cmdDraw },				// 16
-	{ "erase",				"n",		&cmdErase },				// 17
+	{ "erase",				"n",		&cmdErase },			// 17
 	{ "position",			"nnn",		&cmdPosition },			// 18
-	{ "position.v",			"nvv",		&cmdPositionF },			// 19
+	{ "position.v",			"nvv",		&cmdPositionF },		// 19
 	{ "get.posn",			"nvv",		&cmdGetPosn },			// 1A
-	{ "set.cel",			"nn",		&cmdSetCel },				// 1B
+	{ "set.cel",			"nn",		&cmdSetCel },			// 1B
 	{ "set.loop",			"nn",		&cmdSetLoop },			// 1C
-	{ "end.of.loop",		"nn",		&cmdEndOfLoop },			// 1D
+	{ "end.of.loop",		"nn",		&cmdEndOfLoop },		// 1D
 	{ "reverse.loop",		"nn",		&cmdReverseLoop },		// 1E
 	{ "move.obj",			"nnnnn",	&cmdMoveObj },			// 1F
 	{ "set.view",			"nn",		&cmdSetView },			// 20
-	{ "follow.ego",			"nnn",		&cmdFollowEgo },			// 21
-	{ "...",				"",			&cmdUnknown },				// 22
-	{ "...",				"",			&cmdUnknown },				// 23
+	{ "follow.ego",			"nnn",		&cmdFollowEgo },		// 21
+	{ "...",				"",			&cmdUnknown },			// 22
+	{ "...",				"",			&cmdUnknown },			// 23
 	{ "ignore.blocks",		"n",		&cmdIgnoreBlocks },		// 24
-	{ "observe.blocks",		"n",		&cmdObserveBlocks },		// 25
-	{ "wander",				"n",		&cmdWander },				// 26
-	{ "reposition",			"nvv",		&cmdReposition },			// 27
-	{ "stop.motion",		"n",		&cmdStopMotion },			// 28
+	{ "observe.blocks",		"n",		&cmdObserveBlocks },	// 25
+	{ "wander",				"n",		&cmdWander },			// 26
+	{ "reposition",			"nvv",		&cmdReposition },		// 27
+	{ "stop.motion",		"n",		&cmdStopMotion },		// 28
 	{ "start.motion",		"n",		&cmdStartMotion },		// 29
 	{ "stop.cycling",		"n",		&cmdStopCycling },		// 2A
 	{ "start.cycling",		"n",		&cmdStartCycling },		// 2B
-	{ "stop.update",		"n",		&cmdStopUpdate },			// 2C
+	{ "stop.update",		"n",		&cmdStopUpdate },		// 2C
 	{ "start.update",		"n",		&cmdStartUpdate },		// 2D
-	{ "program.control",	"",			&cmdProgramControl },		// 2E
-	{ "player.control",		"",			&cmdPlayerControl },		// 2F
+	{ "program.control",	"",			&cmdProgramControl },	// 2E
+	{ "player.control",		"",			&cmdPlayerControl },	// 2F
 	{ "set.priority",		"nn",		&cmdSetPriority },		// 30
 	{ "release.priority",	"n",		&cmdReleasePriority },	// 31
 	{ "add.to.pic",			"nnnnnn",	&cmdAddToPic },			// 32 TODO: 7 vs 8 args
-	{ "set.horizon",		"n",		&cmdSetHorizon },			// 33
-	{ "ignore.horizon",		"n",		&cmdIgnoreHorizon },		// 34
-	{ "observe.horizon",	"n",		&cmdObserveHorizon },		// 35
-	{ "load.logics",		"n",		&cmdLoadLogic },			// 36
-	{ "object.on.water",	"n",		&cmdObjectOnWater },		// 37
+	{ "set.horizon",		"n",		&cmdSetHorizon },		// 33
+	{ "ignore.horizon",		"n",		&cmdIgnoreHorizon },	// 34
+	{ "observe.horizon",	"n",		&cmdObserveHorizon },	// 35
+	{ "load.logics",		"n",		&cmdLoadLogic },		// 36
+	{ "object.on.water",	"n",		&cmdObjectOnWater },	// 37
 	{ "load.pic",			"v",		&cmdLoadPic },			// 38
-	{ "load.sound",			"n",		&cmdLoadSound },			// 39
-	{ "sound",				"nn",		&cmdSound },				// 3A
-	{ "stop.sound",			"",			&cmdStopSound },			// 3B
+	{ "load.sound",			"n",		&cmdLoadSound },		// 39
+	{ "sound",				"nn",		&cmdSound },			// 3A
+	{ "stop.sound",			"",			&cmdStopSound },		// 3B
 	{ "set.v",				"v",		&cmdSetV },				// 3C
-	{ "reset.v",			"v",		&cmdResetV },				// 3D
+	{ "reset.v",			"v",		&cmdResetV },			// 3D
 	{ "toggle.v",			"v",		&cmdToggleV },			// 3E
-	{ "new.room.v",			"v",		&cmdNewRoomF },			// 3F
-	{ "call",				"n",		&cmdCall },				// 40
-	{ "...",				"",			&cmdUnknown },				// 41
+	{ "new.room.v",			"v",		&cmdNewRoomVV1 },		// 3F
+	{ "call",				"n",		&cmdCallV1 },			// 40
+	{ "...",				"",			&cmdUnknown },			// 41
 	{ "set.speed",			"v",		&cmdSetSpeed },			// 42
 	{ "move.obj.v",			"nvvvv",	&cmdMoveObjF },			// 43
-	{ "...",				"",			&cmdUnknown },				// 44
-	{ "...",				"",			&cmdUnknown },				// 45
-	{ "...",				"",			&cmdUnknown },				// 46
-	{ "...",				"",			&cmdUnknown },				// 47
-	{ "...",				"nv",		&cmdUnknown },				// 48 get.priority??
-	{ "ignore.objs",		"n",		&cmdIgnoreObjs },			// 49
+	{ "...",				"nn",		&cmdUnknown },			// 44
+	{ "get.v",				"v",		&cmdUnknown },			// 45
+	{ "assign.v",			"vv",		&cmdUnknown },			// 46
+	{ "...",				"n",		&cmdUnknown },			// 47
+	{ "get.priority",		"nv",		&cmdGetPriority },		// 48
+	{ "ignore.objs",		"n",		&cmdIgnoreObjs },		// 49
 	{ "observe.objs",		"n",		&cmdObserveObjs },		// 4A
 	{ "distance",			"nnv",		&cmdDistance },			// 4B
 	{ "object.on.land",		"n",		&cmdObjectOnLand },		// 4C
-	{ "...",				"nv",		&cmdUnknown },				// 4D set.priority.v???
-	{ "...",				"",			&cmdUnknown },				// 4E
-	{ "load.logics",		"n",		&cmdLoadLogic },			// 4F TODO: what is the other load.logics then?
-	{ "display",			"nnns",		&cmdDisplay },				// 50 TODO: 4 vs 3 args
-	{ "prevent.input???",	"",			&cmdUnknown },				// 51
-	{ "...",				"",			&cmdUnknown },				// 52
-	{ "...",				"n",		&cmdUnknown },				// 53 ???
-	{ "...",				"",			&cmdUnknown },				// 54 ???
-	{ "stop.motion",		"",			&cmdStopMotion },			// 55 or force.update??
+	{ "...",				"nv",		&cmdUnknown },			// 4D set.priority.v???
+	{ "...",				"",			&cmdUnknown },			// 4E
+	{ "load.logics",		"n",		&cmdLoadLogic },		// 4F TODO: what is the other load.logics then?
+	{ "display",			"nnns",		&cmdDisplay },			// 50 TODO: 4 vs 3 args
+	{ "prevent.input???",	"",			&cmdUnknown },			// 51
+	{ "...",				"",			&cmdUnknown },			// 52
+	{ "...",				"n",		&cmdUnknown },			// 53 ???
+	{ "...",				"",			&cmdUnknown },			// 54 ???
+	{ "stop.motion",		"",			&cmdStopMotion },		// 55 or force.update??
 	{ "discard.view",		"n",		&cmdDiscardView },		// 56
-	{ "discard.pic",		"v",		&cmdDiscardPic },			// 57
-	{ "...",				"nn",		&cmdUnknown },				// 58
-	{ "...",				"",			&cmdUnknown },				// 59
+	{ "discard.pic",		"v",		&cmdDiscardPic },		// 57
+	{ "set.item.view",		"nn",		&cmdSetItemView },		// 58
+	{ "...",				"",			&cmdUnknown },			// 59
 	{ "last.cel",			"nv",		&cmdLastCel },			// 5A
 	{ "set.cel.v",			"nv",		&cmdSetCelF },			// 5B
-	{ "...",				"",			&cmdUnknown },				// 5C
+	{ "...",				"",			&cmdUnknown },			// 5C
 	{ "load.view",			"n",		&cmdLoadView },			// 5D
-	{ "...",				"",			&cmdUnknown },				// 5E
-	{ "...",				"",			&cmdUnknown },				// 5F
-	{ "setbit",				"nv",		&cmdUnknown },				// 60
+	{ "...",				"",			&cmdUnknown },			// 5E
+	{ "...",				"",			&cmdUnknown },			// 5F
+	{ "setbit",				"nv",		&cmdUnknown },			// 60
 };
 
 AgiInstruction insV2Test[] = {
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index f45a52b..3885c10 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -222,6 +222,10 @@ void cmdReleaseKey(AgiGame *state, uint8 *p);
 void cmdAdjEgoMoveToXY(AgiGame *state, uint8 *p);
 
 void cmdSetSpeed(AgiGame *state, uint8 *p);
+void cmdSetItemView(AgiGame *state, uint8 *p);
+void cmdCallV1(AgiGame *state, uint8 *p);
+void cmdNewRoomV1(AgiGame *state, uint8 *p);
+void cmdNewRoomVV1(AgiGame *state, uint8 *p);
 void cmdUnknown(AgiGame *state, uint8 *p);
 
 void condEqual(AgiGame *state, uint8 *p);


Commit: 3fb50b815e78b9284497deb6ead60a6efff02453
    https://github.com/scummvm/scummvm/commit/3fb50b815e78b9284497deb6ead60a6efff02453
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2011-08-13T15:27:27-07:00

Commit Message:
AGI: Further work on v1 opcode difference

Changed paths:
    engines/agi/agi.h
    engines/agi/op_cmd.cpp
    engines/agi/op_test.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 5795801..102ecd9 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -88,6 +88,7 @@ typedef signed int Err;
 
 #define	_EMPTY		0xfffff
 #define	EGO_OWNED	0xff
+#define	EGO_OWNED_V1	0xf9
 
 #define	CRYPT_KEY_SIERRA	"Avis Durgan"
 #define CRYPT_KEY_AGDS		"Alex Simkin"
diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 673cac4..6260691 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -56,8 +56,13 @@ namespace Agi {
 #define getflag(a) state->_vm->getflag(a)
 
 void cmdIncrement(AgiGame *state, uint8 *p) {
-	if (_v[p0] != 0xff)
-		++_v[p0];
+	if (getVersion() < 0x2000) {
+		if (_v[p0] < 0xf0)
+			++_v[p0];
+	} else {
+		if (_v[p0] != 0xff)
+			++_v[p0];
+	}
 }
 
 void cmdDecrement(AgiGame *state, uint8 *p) {
@@ -115,6 +120,10 @@ void cmdDivV(AgiGame *state, uint8 *p) {
 	_v[p0] /= _v[p1];
 }
 
+void cmdRandomV1(AgiGame *state, uint8 *p) {
+	_v[p0] = state->_vm->_rnd->getRandomNumber(250);
+}
+
 void cmdRandom(AgiGame *state, uint8 *p) {
 	_v[p2] = state->_vm->_rnd->getRandomNumber(p1 - p0) + p0;
 }
@@ -399,6 +408,10 @@ void cmdGet(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(p0, EGO_OWNED);
 }
 
+void cmdGetV1(AgiGame *state, uint8 *p) {
+	state->_vm->objectSetLocation(p0, EGO_OWNED_V1);
+}
+
 void cmdGetF(AgiGame *state, uint8 *p) {
 	state->_vm->objectSetLocation(_v[p0], EGO_OWNED);
 }
@@ -732,6 +745,16 @@ void cmdCallF(AgiGame *state, uint8 *p) {
 	cmdCall(state, &_v[p0]);
 }
 
+void cmdDrawPicV1(AgiGame *state, uint8 *p) {
+	debugC(6, kDebugLevelScripts, "=== draw pic V1 %d ===", _v[p0]);
+	state->_vm->_picture->decodePicture(_v[p0], true);
+
+	state->_vm->clearPrompt();
+
+	// Simulate slowww computer. Many effects rely on this
+	state->_vm->pause(kPausePicture);
+}
+
 void cmdDrawPic(AgiGame *state, uint8 *p) {
 	debugC(6, kDebugLevelScripts, "=== draw pic %d ===", _v[p0]);
 	state->_vm->_sprites->eraseBoth();
@@ -811,11 +834,21 @@ void cmdShowPriScreen(AgiGame *state, uint8 *p) {
 }
 
 void cmdAnimateObj(AgiGame *state, uint8 *p) {
-	if (vt.flags & ANIMATED)
-		return;
+	if (getVersion() < 0x2000) {
+		if (vt.flags & DIDNT_MOVE)
+			return;
+	} else {
+		if (vt.flags & ANIMATED)
+			return;
+	}
 
 	debugC(4, kDebugLevelScripts, "animate vt entry #%d", p0);
 	vt.flags = ANIMATED | UPDATE | CYCLING;
+
+	if (getVersion() < 0x2000) {
+		vt.flags |= DIDNT_MOVE;
+	}
+
 	vt.motion = MOTION_NORMAL;
 	vt.cycle = CYCLE_NORMAL;
 	vt.direction = 0;
@@ -918,6 +951,11 @@ void cmdPosition(AgiGame *state, uint8 *p) {
 		state->_vm->clipViewCoordinates(&vt);
 }
 
+void cmdPositionV1(AgiGame *state, uint8 *p) {
+	vt.xPos = p1;
+	vt.yPos = p2;
+}
+
 void cmdPositionF(AgiGame *state, uint8 *p) {
 	vt.xPos = vt.xPos2 = _v[p1];
 	vt.yPos = vt.yPos2 = _v[p2];
@@ -929,6 +967,11 @@ void cmdPositionF(AgiGame *state, uint8 *p) {
 		state->_vm->clipViewCoordinates(&vt);
 }
 
+void cmdPositionFV1(AgiGame *state, uint8 *p) {
+	vt.xPos = _v[p1];
+	vt.yPos = _v[p2];
+}
+
 void cmdGetPosn(AgiGame *state, uint8 *p) {
 	state->vars[p1] = (unsigned char)vt.xPos;
 	state->vars[p2] = (unsigned char)vt.yPos;
@@ -1045,8 +1088,14 @@ void cmdFollowEgo(AgiGame *state, uint8 *p) {
 	vt.parm1 = p1 > vt.stepSize ? p1 : vt.stepSize;
 	vt.parm2 = p2;
 	vt.parm3 = 0xff;
-	setflag(p2, false);
-	vt.flags |= UPDATE;
+	
+	if (getVersion() < 0x2000) {
+		_v[p2] = 0;
+		vt.flags |= UPDATE | ANIMATED;
+	} else {
+		setflag(p2, false);
+		vt.flags |= UPDATE;
+	}
 }
 
 void cmdMoveObj(AgiGame *state, uint8 *p) {
@@ -1061,8 +1110,13 @@ void cmdMoveObj(AgiGame *state, uint8 *p) {
 	if (p3 != 0)
 		vt.stepSize = p3;
 
-	setflag(p4, false);
-	vt.flags |= UPDATE;
+	if (getVersion() < 0x2000) {
+		_v[p4] = 0;
+		vt.flags |= UPDATE | ANIMATED;
+	} else {
+		setflag(p4, false);
+		vt.flags |= UPDATE;
+	}
 
 	if (p0 == 0)
 		state->playerControl = false;
diff --git a/engines/agi/op_test.cpp b/engines/agi/op_test.cpp
index f8fd767..bc71165 100644
--- a/engines/agi/op_test.cpp
+++ b/engines/agi/op_test.cpp
@@ -38,6 +38,7 @@ namespace Agi {
 #define testGreater(v1, v2)	(getvar(v1) > (v2))
 #define testIsSet(flag)		(getflag(flag))
 #define testHas(obj)			(state->_vm->objectGetLocation(obj) == EGO_OWNED)
+#define testHasV1(obj)			(state->_vm->objectGetLocation(obj) == EGO_OWNED_V1)
 #define testObjInRoom(obj, v)	(state->_vm->objectGetLocation(obj) == getvar(v))
 
 void condEqual(AgiGame *state, uint8 *p) {
@@ -92,6 +93,10 @@ void condHas(AgiGame *state, uint8 *p) {
 	state->testResult = testHas(p[0]);
 }
 
+void condHasV1(AgiGame *state, uint8 *p) {
+	state->testResult = testHasV1(p[0]);
+}
+
 void condObjInRoom(AgiGame *state, uint8 *p) {
 	state->testResult = testObjInRoom(p[0], p[1]);
 }
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index e69d167..d39307c 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -37,7 +37,7 @@ AgiInstruction insV1Test[] = {
 	{ "greatern",			"vn",		&condGreater },		// 05
 	{ "greaterv",			"vv",		&condGreaterV },	// 06
 	{ "isset",				"v",		&condIsSetV1 },		// 07
-	{ "has",				"n",		&condHas },			// 08
+	{ "has",				"n",		&condHasV1 },		// 08
 	{ "said",				"nnnn",		&condSaid2 },		// 09
 	{ "posn",				"nnnnn",	&condPosn },		// 0A
 	{ "controller",			"n",		&condController },	// 0B
@@ -61,20 +61,20 @@ AgiInstruction insV1[] = {
 	{ "load.view",			"n",		&cmdLoadView },			// 09
 	{ "animate.obj",		"n",		&cmdAnimateObj },		// 0A
 	{ "new.room",			"n",		&cmdNewRoomV1 },		// 0B
-	{ "draw.pic",			"v",		&cmdDrawPic },			// 0C
-	{ "print",				"s",		&cmdPrint },			// 0D
-	{ "status",				"",			&cmdStatus },			// 0E
-	{ "save.game",			"",			&cmdSaveGame },			// 0F
-	{ "restore.game",		"",			&cmdLoadGame },			// 10
-	{ "...",				"",			&cmdInitDisk },			// 11 TODO
-	{ "restart.game",		"",			&cmdRestartGame },		// 12
-	{ "random",				"v",		&cmdRandom },			// 13 TODO: 1 vs 3 vars
-	{ "get",				"n",		&cmdGet },				// 14
+	{ "draw.pic",			"v",		&cmdDrawPicV1 },		// 0C
+	{ "print",				"s",		&cmdPrint },			// 0D TODO
+	{ "status",				"",			&cmdStatus },			// 0E TODO
+	{ "save.game",			"",			&cmdSaveGame },			// 0F TODO
+	{ "restore.game",		"",			&cmdLoadGame },			// 10 TODO
+	{ "init.disk",			"",			&cmdInitDisk },			// 11 TODO
+	{ "restart.game",		"",			&cmdRestartGame },		// 12 TODO
+	{ "random",				"v",		&cmdRandomV1 },			// 13
+	{ "get",				"n",		&cmdGetV1 },			// 14
 	{ "drop",				"n",		&cmdDrop },				// 15
-	{ "draw",				"n",		&cmdDraw },				// 16
-	{ "erase",				"n",		&cmdErase },			// 17
-	{ "position",			"nnn",		&cmdPosition },			// 18
-	{ "position.v",			"nvv",		&cmdPositionF },		// 19
+	{ "draw",				"n",		&cmdDraw },				// 16 TODO
+	{ "erase",				"n",		&cmdErase },			// 17 TODO
+	{ "position",			"nnn",		&cmdPositionV1 },		// 18
+	{ "position.v",			"nvv",		&cmdPositionFV1 },		// 19
 	{ "get.posn",			"nvv",		&cmdGetPosn },			// 1A
 	{ "set.cel",			"nn",		&cmdSetCel },			// 1B
 	{ "set.loop",			"nn",		&cmdSetLoop },			// 1C
@@ -83,8 +83,8 @@ AgiInstruction insV1[] = {
 	{ "move.obj",			"nnnnn",	&cmdMoveObj },			// 1F
 	{ "set.view",			"nn",		&cmdSetView },			// 20
 	{ "follow.ego",			"nnn",		&cmdFollowEgo },		// 21
-	{ "...",				"",			&cmdUnknown },			// 22
-	{ "...",				"",			&cmdUnknown },			// 23
+	{ "...",				"",			&cmdUnknown },			// 22 # block
+	{ "...",				"",			&cmdUnknown },			// 23 # unblock
 	{ "ignore.blocks",		"n",		&cmdIgnoreBlocks },		// 24
 	{ "observe.blocks",		"n",		&cmdObserveBlocks },	// 25
 	{ "wander",				"n",		&cmdWander },			// 26
@@ -120,32 +120,33 @@ AgiInstruction insV1[] = {
 	{ "...",				"nn",		&cmdUnknown },			// 44
 	{ "get.v",				"v",		&cmdUnknown },			// 45
 	{ "assign.v",			"vv",		&cmdUnknown },			// 46
-	{ "...",				"n",		&cmdUnknown },			// 47
+	{ "...",				"n",		&cmdUnknown },			// 47 # printvar.v
 	{ "get.priority",		"nv",		&cmdGetPriority },		// 48
 	{ "ignore.objs",		"n",		&cmdIgnoreObjs },		// 49
 	{ "observe.objs",		"n",		&cmdObserveObjs },		// 4A
 	{ "distance",			"nnv",		&cmdDistance },			// 4B
 	{ "object.on.land",		"n",		&cmdObjectOnLand },		// 4C
-	{ "...",				"nv",		&cmdUnknown },			// 4D set.priority.v???
-	{ "...",				"",			&cmdUnknown },			// 4E
-	{ "load.logics",		"n",		&cmdLoadLogic },		// 4F TODO: what is the other load.logics then?
+	{ "...",				"nv",		&cmdUnknown },			// 4D # set.priority.f
+	{ "...",				"",			&cmdUnknown },			// 4E  # show.obj
+	{ "load.logics",		"n",		&cmdLoadLogic },		// 4F # load.global.logics
 	{ "display",			"nnns",		&cmdDisplay },			// 50 TODO: 4 vs 3 args
-	{ "prevent.input???",	"",			&cmdUnknown },			// 51
-	{ "...",				"",			&cmdUnknown },			// 52
-	{ "...",				"n",		&cmdUnknown },			// 53 ???
+	{ "prevent.input???",	"",			&cmdUnknown },			// 51 
+	{ "...",				"",			&cmdUnknown },			// 52 # nop
+	{ "...",				"n",		&cmdUnknown },			// 53 # text.screen
 	{ "...",				"",			&cmdUnknown },			// 54 ???
 	{ "stop.motion",		"",			&cmdStopMotion },		// 55 or force.update??
 	{ "discard.view",		"n",		&cmdDiscardView },		// 56
 	{ "discard.pic",		"v",		&cmdDiscardPic },		// 57
 	{ "set.item.view",		"nn",		&cmdSetItemView },		// 58
-	{ "...",				"",			&cmdUnknown },			// 59
+	{ "...",				"",			&cmdUnknown },			// 59 # reverse.cycle
 	{ "last.cel",			"nv",		&cmdLastCel },			// 5A
 	{ "set.cel.v",			"nv",		&cmdSetCelF },			// 5B
-	{ "...",				"",			&cmdUnknown },			// 5C
+	{ "...",				"",			&cmdUnknown },			// 5C # normal.cycle
 	{ "load.view",			"n",		&cmdLoadView },			// 5D
 	{ "...",				"",			&cmdUnknown },			// 5E
 	{ "...",				"",			&cmdUnknown },			// 5F
 	{ "setbit",				"nv",		&cmdUnknown },			// 60
+	{ "...",				"nv",		&cmdUnknown },			// 61 # clearbit
 };
 
 AgiInstruction insV2Test[] = {
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index 3885c10..f0a1c17 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -63,6 +63,7 @@ void cmdCall(AgiGame *state, uint8 *p);
 void cmdCallF(AgiGame *state, uint8 *p);
 void cmdLoadPic(AgiGame *state, uint8 *p);	// 0x18
 void cmdDrawPic(AgiGame *state, uint8 *p);
+void cmdDrawPicV1(AgiGame *state, uint8 *p);
 void cmdShowPic(AgiGame *state, uint8 *p);
 void cmdDiscardPic(AgiGame *state, uint8 *p);
 void cmdOverlayPic(AgiGame *state, uint8 *p);
@@ -75,7 +76,9 @@ void cmdUnanimateAll(AgiGame *state, uint8 *p);
 void cmdDraw(AgiGame *state, uint8 *p);
 void cmdErase(AgiGame *state, uint8 *p);
 void cmdPosition(AgiGame *state, uint8 *p);
+void cmdPositionV1(AgiGame *state, uint8 *p);
 void cmdPositionF(AgiGame *state, uint8 *p);
+void cmdPositionFV1(AgiGame *state, uint8 *p);
 void cmdGetPosn(AgiGame *state, uint8 *p);
 void cmdReposition(AgiGame *state, uint8 *p);	// 0x28
 void cmdSetView(AgiGame *state, uint8 *p);
@@ -130,6 +133,7 @@ void cmdObserveBlocks(AgiGame *state, uint8 *p);
 void cmdBlock(AgiGame *state, uint8 *p);
 void cmdUnblock(AgiGame *state, uint8 *p);
 void cmdGet(AgiGame *state, uint8 *p);
+void cmdGetV1(AgiGame *state, uint8 *p);
 void cmdGetF(AgiGame *state, uint8 *p);
 void cmdDrop(AgiGame *state, uint8 *p);
 void cmdPut(AgiGame *state, uint8 *p);
@@ -168,6 +172,7 @@ void cmdInitDisk(AgiGame *state, uint8 *p);
 void cmdRestartGame(AgiGame *state, uint8 *p);	// 0x80
 void cmdShowObj(AgiGame *state, uint8 *p);
 void cmdRandom(AgiGame *state, uint8 *p);
+void cmdRandomV1(AgiGame *state, uint8 *p);
 void cmdProgramControl(AgiGame *state, uint8 *p);
 void cmdPlayerControl(AgiGame *state, uint8 *p);
 void cmdObjStatusF(AgiGame *state, uint8 *p);
@@ -237,6 +242,7 @@ void condGreaterV(AgiGame *state, uint8 *p);
 void condIsSet(AgiGame *state, uint8 *p);
 void condIsSetV(AgiGame *state, uint8 *p);
 void condHas(AgiGame *state, uint8 *p);
+void condHasV1(AgiGame *state, uint8 *p);
 void condObjInRoom(AgiGame *state, uint8 *p);
 void condPosn(AgiGame *state, uint8 *p);
 void condController(AgiGame *state, uint8 *p);


Commit: be9c5c0427f1e7edfdc1c244726e31fdeb53766d
    https://github.com/scummvm/scummvm/commit/be9c5c0427f1e7edfdc1c244726e31fdeb53766d
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2011-08-13T15:27:29-07:00

Commit Message:
AGI: Checked V1 instructions till 0x20

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h
    engines/agi/view.cpp



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 6260691..01abf21 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -314,7 +314,10 @@ void cmdLastCel(AgiGame *state, uint8 *p) {
 
 void cmdSetCel(AgiGame *state, uint8 *p) {
 	state->_vm->setCel(&vt, p1);
-	vt.flags &= ~DONTUPDATE;
+
+	if (getVersion() >= 0x2000) {
+		vt.flags &= ~DONTUPDATE;
+	}
 }
 
 void cmdSetCelF(AgiGame *state, uint8 *p) {
@@ -1032,6 +1035,15 @@ void cmdReverseLoop(AgiGame *state, uint8 *p) {
 	setflag(p1, false);
 }
 
+void cmdReverseLoopV1(AgiGame *state, uint8 *p) {
+	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
+	vt.cycle = CYCLE_REV_LOOP;
+	state->_vm->setCel(&vt, 0);
+	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
+	vt.parm1 = p1;
+	vt.parm3 = 0;
+}
+
 void cmdEndOfLoop(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
 	vt.cycle = CYCLE_END_OF_LOOP;
@@ -1040,6 +1052,15 @@ void cmdEndOfLoop(AgiGame *state, uint8 *p) {
 	setflag(p1, false);
 }
 
+void cmdEndOfLoopV1(AgiGame *state, uint8 *p) {
+	debugC(4, kDebugLevelScripts, "o%d, f%d", p0, p1);
+	vt.cycle = CYCLE_END_OF_LOOP;
+	state->_vm->setCel(&vt, 0);
+	vt.flags |= (DONTUPDATE | UPDATE | CYCLING);
+	vt.parm1 = p1;
+	vt.parm3 = 0;
+}
+
 void cmdBlock(AgiGame *state, uint8 *p) {
 	debugC(4, kDebugLevelScripts, "x1=%d, y1=%d, x2=%d, y2=%d", p0, p1, p2, p3);
 	state->block.active = true;
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index d39307c..3b8406c 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -78,8 +78,8 @@ AgiInstruction insV1[] = {
 	{ "get.posn",			"nvv",		&cmdGetPosn },			// 1A
 	{ "set.cel",			"nn",		&cmdSetCel },			// 1B
 	{ "set.loop",			"nn",		&cmdSetLoop },			// 1C
-	{ "end.of.loop",		"nn",		&cmdEndOfLoop },		// 1D
-	{ "reverse.loop",		"nn",		&cmdReverseLoop },		// 1E
+	{ "end.of.loop",		"nn",		&cmdEndOfLoopV1 },		// 1D
+	{ "reverse.loop",		"nn",		&cmdReverseLoopV1 },	// 1E
 	{ "move.obj",			"nnnnn",	&cmdMoveObj },			// 1F
 	{ "set.view",			"nn",		&cmdSetView },			// 20
 	{ "follow.ego",			"nnn",		&cmdFollowEgo },		// 21
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index f0a1c17..d0b741b 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -114,8 +114,10 @@ void cmdStopCycling(AgiGame *state, uint8 *p);
 void cmdStartCycling(AgiGame *state, uint8 *p);
 void cmdNormalCycle(AgiGame *state, uint8 *p);	// 0x48
 void cmdEndOfLoop(AgiGame *state, uint8 *p);
+void cmdEndOfLoopV1(AgiGame *state, uint8 *p);
 void cmdReverseCycle(AgiGame *state, uint8 *p);
 void cmdReverseLoop(AgiGame *state, uint8 *p);
+void cmdReverseLoopV1(AgiGame *state, uint8 *p);
 void cmdCycleTime(AgiGame *state, uint8 *p);
 void cmdStopMotion(AgiGame *state, uint8 *p);
 void cmdStartMotion(AgiGame *state, uint8 *p);
diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index 0d420ca..e249b80 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -270,6 +270,11 @@ void AgiEngine::clipViewCoordinates(VtEntry *v) {
 		v->flags |= UPDATE_POS;
 		v->yPos = _game.horizon + 1;
 	}
+
+	if (getVersion() < 0x2000) {
+		v->flags |= DONTUPDATE;
+	}
+
 }
 
 /**


Commit: 3cb41b5dfc19ab2b4115e4f791b074fc27044f59
    https://github.com/scummvm/scummvm/commit/3cb41b5dfc19ab2b4115e4f791b074fc27044f59
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2011-08-13T15:27:32-07:00

Commit Message:
AGI: Checked V1 instructions till 0x2c

Changed paths:
    engines/agi/op_cmd.cpp
    engines/agi/opcodes.cpp
    engines/agi/opcodes.h
    engines/agi/view.cpp



diff --git a/engines/agi/op_cmd.cpp b/engines/agi/op_cmd.cpp
index 01abf21..7148ef6 100644
--- a/engines/agi/op_cmd.cpp
+++ b/engines/agi/op_cmd.cpp
@@ -999,6 +999,15 @@ void cmdReposition(AgiGame *state, uint8 *p) {
 	state->_vm->fixPosition(p0);
 }
 
+void cmdRepositionV1(AgiGame *state, uint8 *p) {
+	vt.xPos2 = vt.xPos;
+	vt.yPos2 = vt.yPos;
+	vt.flags |= UPDATE_POS;
+
+	vt.xPos = (vt.xPos + p1) & 0xff;
+	vt.yPos = (vt.yPos + p2) & 0xff;
+}
+
 void cmdRepositionTo(AgiGame *state, uint8 *p) {
 	vt.xPos = p1;
 	vt.yPos = p2;
@@ -1087,6 +1096,10 @@ void cmdStopMotion(AgiGame *state, uint8 *p) {
 	}
 }
 
+void cmdStopMotionV1(AgiGame *state, uint8 *p) {
+	vt.flags &= ~ANIMATED;
+}
+
 void cmdStartMotion(AgiGame *state, uint8 *p) {
 	vt.motion = MOTION_NORMAL;
 	if (p0 == 0) {		// ego only
@@ -1095,6 +1108,10 @@ void cmdStartMotion(AgiGame *state, uint8 *p) {
 	}
 }
 
+void cmdStartMotionV1(AgiGame *state, uint8 *p) {
+	vt.flags |= ANIMATED;
+}
+
 void cmdPlayerControl(AgiGame *state, uint8 *p) {
 	state->playerControl = true;
 	state->viewTable[0].motion = MOTION_NORMAL;
@@ -1173,7 +1190,11 @@ void cmdWander(AgiGame *state, uint8 *p) {
 		state->playerControl = false;
 
 	vt.motion = MOTION_WANDER;
-	vt.flags |= UPDATE;
+	if (getVersion() < 0x2000) {
+		vt.flags |= UPDATE | ANIMATED;
+	} else {
+		vt.flags |= UPDATE;
+	}
 }
 
 void cmdSetGameID(AgiGame *state, uint8 *p) {
diff --git a/engines/agi/opcodes.cpp b/engines/agi/opcodes.cpp
index 3b8406c..5571d5c 100644
--- a/engines/agi/opcodes.cpp
+++ b/engines/agi/opcodes.cpp
@@ -83,14 +83,14 @@ AgiInstruction insV1[] = {
 	{ "move.obj",			"nnnnn",	&cmdMoveObj },			// 1F
 	{ "set.view",			"nn",		&cmdSetView },			// 20
 	{ "follow.ego",			"nnn",		&cmdFollowEgo },		// 21
-	{ "...",				"",			&cmdUnknown },			// 22 # block
-	{ "...",				"",			&cmdUnknown },			// 23 # unblock
+	{ "block",				"",			&cmdBlock },			// 22
+	{ "unblock",			"",			&cmdUnblock },			// 23
 	{ "ignore.blocks",		"n",		&cmdIgnoreBlocks },		// 24
 	{ "observe.blocks",		"n",		&cmdObserveBlocks },	// 25
 	{ "wander",				"n",		&cmdWander },			// 26
-	{ "reposition",			"nvv",		&cmdReposition },		// 27
-	{ "stop.motion",		"n",		&cmdStopMotion },		// 28
-	{ "start.motion",		"n",		&cmdStartMotion },		// 29
+	{ "reposition",			"nvv",		&cmdRepositionV1 },		// 27
+	{ "stop.motion",		"n",		&cmdStopMotionV1 },		// 28
+	{ "start.motion",		"n",		&cmdStartMotionV1 },	// 29
 	{ "stop.cycling",		"n",		&cmdStopCycling },		// 2A
 	{ "start.cycling",		"n",		&cmdStartCycling },		// 2B
 	{ "stop.update",		"n",		&cmdStopUpdate },		// 2C
diff --git a/engines/agi/opcodes.h b/engines/agi/opcodes.h
index d0b741b..afc6174 100644
--- a/engines/agi/opcodes.h
+++ b/engines/agi/opcodes.h
@@ -81,6 +81,7 @@ void cmdPositionF(AgiGame *state, uint8 *p);
 void cmdPositionFV1(AgiGame *state, uint8 *p);
 void cmdGetPosn(AgiGame *state, uint8 *p);
 void cmdReposition(AgiGame *state, uint8 *p);	// 0x28
+void cmdRepositionV1(AgiGame *state, uint8 *p);	// 0x28
 void cmdSetView(AgiGame *state, uint8 *p);
 void cmdSetViewF(AgiGame *state, uint8 *p);
 void cmdSetLoop(AgiGame *state, uint8 *p);
@@ -120,7 +121,9 @@ void cmdReverseLoop(AgiGame *state, uint8 *p);
 void cmdReverseLoopV1(AgiGame *state, uint8 *p);
 void cmdCycleTime(AgiGame *state, uint8 *p);
 void cmdStopMotion(AgiGame *state, uint8 *p);
+void cmdStopMotionV1(AgiGame *state, uint8 *p);
 void cmdStartMotion(AgiGame *state, uint8 *p);
+void cmdStartMotionV1(AgiGame *state, uint8 *p);
 void cmdStepSize(AgiGame *state, uint8 *p);
 void cmdStepTime(AgiGame *state, uint8 *p);	// 0x50
 void cmdMoveObj(AgiGame *state, uint8 *p);
diff --git a/engines/agi/view.cpp b/engines/agi/view.cpp
index e249b80..956d398 100644
--- a/engines/agi/view.cpp
+++ b/engines/agi/view.cpp
@@ -299,6 +299,12 @@ void AgiEngine::setView(VtEntry *v, int n) {
 	v->currentView = n;
 	v->numLoops = v->viewData->numLoops;
 	v->viewReplaced = true;
+
+	if (getVersion() < 0x2000) {
+		v->stepSize = v->viewData->rdata[0];
+		v->cycleTime = v->viewData->rdata[1];
+		v->cycleTimeCount = 0;
+	}
 	setLoop(v, v->currentLoop >= v->numLoops ? 0 : v->currentLoop);
 }
 


Commit: 46354d5772f9f2ac408bd81590e534ffd2eddc39
    https://github.com/scummvm/scummvm/commit/46354d5772f9f2ac408bd81590e534ffd2eddc39
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2011-08-13T15:27:34-07:00

Commit Message:
AGI: Switched booters detection to AD

Changed paths:
    engines/agi/agi.h
    engines/agi/detection.cpp
    engines/agi/detection_tables.h
    engines/agi/loader_v1.cpp



diff --git a/engines/agi/agi.h b/engines/agi/agi.h
index 102ecd9..24c2744 100644
--- a/engines/agi/agi.h
+++ b/engines/agi/agi.h
@@ -137,6 +137,11 @@ enum AgiGameType {
 	GType_V3 = 3
 };
 
+ enum BooterDisks {
+	 BooterDisk1 = 0,
+	 BooterDisk2 = 1
+ };
+
 //
 // GF_OLDAMIGAV20 means that the interpreter is an old Amiga AGI interpreter that
 // uses value 20 for the computer type (v20 i.e. vComputer) rather than the usual value 5.
@@ -647,24 +652,6 @@ struct AgiGame {
 	int logic_list[256];
 };
 
-/**
- * Check if a disk image with the given MD5 sum exists in the search path.
- *
- * @param  md5       MD5 sum of the disk image to be searched
- * @param  filename  Filled with a filename in case the image is found
- * @return True if found, otherwise false.
- */
-bool diskImageExists(Common::String md5, Common::String &filename);
-
-/**
- * Get MD5 sums for a given game from the booter game description table.
- *
- * @param gid       Game ID of the game
- * @param md5Disk0  Filled with the MD5 sum of disk 0
- * @param md5Disk1  Filled with the MD5 sum of disk 1 if there are two disks
- */
-bool getBooterMD5Sums(AgiGameID gid, Common::String &md5Disk0, Common::String &md5Disk1);
-
 class AgiLoader {
 public:
 
@@ -846,6 +833,8 @@ public:
 	void initVersion();
 	void setVersion(uint16 version);
 
+	const char *getDiskName(uint16 id);
+
 	bool canLoadGameStateCurrently();
 	bool canSaveGameStateCurrently();
 };
diff --git a/engines/agi/detection.cpp b/engines/agi/detection.cpp
index ad3760c..e418845 100644
--- a/engines/agi/detection.cpp
+++ b/engines/agi/detection.cpp
@@ -94,19 +94,13 @@ void AgiBase::initVersion() {
 	_gameVersion = _gameDescription->version;
 }
 
-struct AGIBooterDescription {
-	Common::String md5Disk0;
-	Common::String md5Disk1;
-	Common::String id;
-	Common::String extra;
-	int gameID;
-	int gameType;
-	uint32 features;
-	uint16 version;
-};
+const char *AgiBase::getDiskName(uint16 id) {
+	for (int i = 0; _gameDescription->desc.filesDescriptions[i].fileName != NULL; i++)
+		if (_gameDescription->desc.filesDescriptions[i].fileType == id)
+			return _gameDescription->desc.filesDescriptions[i].fileName;
 
-bool isDiskImage(Common::SeekableReadStream *stream, Common::String filename, Common::String md5);
-bool diskImageExistsInFSList(const Common::FSList &fslist, Common::String md5, Common::String &filename);
+	return "";
+}
 
 }
 
@@ -436,30 +430,6 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 		warning("More than one (%d) *.wag files found. WAG files ignored", wagFileCount);
 	}
 
-	// Try to detect disk images of AGI v1 and AGI v2.001 booter games
-	if (!matchedUsingFilenames && !matchedUsingWag) {
-		for (int i = 0; !booterDescription[i].md5Disk0.empty(); i++) {
-			Common::String filenameDisk0;
-			Common::String filenameDisk1;
-
-			if (!diskImageExistsInFSList(fslist, booterDescription[i].md5Disk0, filenameDisk0))
-				continue;
-			if (!booterDescription[i].md5Disk1.empty())
-				if (!diskImageExistsInFSList(fslist, booterDescription[i].md5Disk1, filenameDisk1))
-					continue;
-
-			g_fallbackDesc.gameID = booterDescription[i].gameID;
-			g_fallbackDesc.gameType = booterDescription[i].gameType;
-			g_fallbackDesc.features = booterDescription[i].features;
-			g_fallbackDesc.version = booterDescription[i].version;
-
-			g_fallbackDesc.desc.gameid = booterDescription[i].id.c_str();
-			g_fallbackDesc.desc.extra = booterDescription[i].extra.c_str();
-
-			return (const ADGameDescription *)&g_fallbackDesc;
-		}
-	}
-
 	// Check that the AGI interpreter version is a supported one
 	if (!(g_fallbackDesc.version >= 0x2000 && g_fallbackDesc.version < 0x4000)) {
 		warning("Unsupported AGI interpreter version 0x%x in AGI's fallback detection. Using default 0x2917", g_fallbackDesc.version);
@@ -501,66 +471,6 @@ const ADGameDescription *AgiMetaEngine::fallbackDetect(const FileMap &allFilesXX
 
 namespace Agi {
 
-bool isDiskImage(Common::SeekableReadStream *stream, Common::String filename, Common::String md5) {
-	if (!(filename.hasSuffix(".dsk") || filename.hasSuffix(".img")))
-		return false;
-
-	if (stream->size() == 368640 && computeStreamMD5AsString(*stream, 5000) == md5)
-		return true;
-
-	return false;
-}
-
-bool diskImageExistsInFSList(const Common::FSList &fslist, Common::String md5, Common::String &filename) {
-	for (Common::FSList::const_iterator x = fslist.begin(); x != fslist.end(); x++) {
-		if (x->isDirectory()) continue;
-		
-		Common::SeekableReadStream *stream = x->createReadStream();
-		if (isDiskImage(stream, x->getName(), md5)) {
-			filename = x->getName();
-			delete stream;
-			return true;
-		}
-		delete stream;
-	}
-
-	return false;
-}
-
-bool diskImageExists(Common::String md5, Common::String &filename) {
-	Common::ArchiveMemberList files;
-	SearchMan.listMembers(files);
-	
-	Common::File file;
-	for (Common::ArchiveMemberList::const_iterator x = files.begin(); x != files.end(); x++) {
-		file.open((*x)->getName());
-		if (isDiskImage(&file, (*x)->getName(), md5)) {
-			filename = (*x)->getName();
-			file.close();
-			return true;
-		}
-		file.close();
-	}
-	
-	return false;
-}
-
-bool getBooterMD5Sums(AgiGameID gid, Common::String &md5Disk0, Common::String &md5Disk1) {
-	AGIBooterDescription *booter = NULL;
-	int i = 0;
-	while (!booterDescription[i].md5Disk0.empty()) {
-		if (booterDescription[i].gameID == gid)
-			booter = &booterDescription[i];
-		i++;
-	}
-	if (booter == NULL)
-		return false;
-	
-	md5Disk0 = booter->md5Disk0;
-	md5Disk1 = booter->md5Disk1;
-	return true;
-}
-
 bool AgiBase::canLoadGameStateCurrently() {
 	return (!(getGameType() == GType_PreAGI) && getflag(fMenusWork) && !_noSaveLoadAllowed);
 }
diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h
index 100719c..28e9407 100644
--- a/engines/agi/detection_tables.h
+++ b/engines/agi/detection_tables.h
@@ -56,6 +56,7 @@ using Common::GUIO_NONE;
 		ver \
 	}
 
+#define BOOTER2(id,extra,fname,md5,size,ver,gid) GAME_LVFPN(id,extra,fname,md5,size,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
 #define GAME(id,extra,md5,ver,gid) GAME_LVFPN(id,extra,"logdir",md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V2)
 #define GAME3(id,extra,fname,md5,ver,gid) GAME_LVFPN(id,extra,fname,md5,-1,Common::EN_ANY,ver,0,gid,Common::kPlatformPC,GType_V3)
 
@@ -118,6 +119,69 @@ static const AGIGameDescription gameDescriptions[] = {
 	// AGI Demo for Kings Quest III and Space Quest I
 	GAME("agidemo", "Demo Kings Quest III and Space Quest I", "502e6bf96827b6c4d3e67c9cdccd1033", 0x2272, GID_AGIDEMO),
 
+	{
+		// Black Cauldron (PC 3.5" booter) 1.1J [AGI 1.12]
+		{
+			"bc",
+			"Booter 1.1J",
+			{
+				{ "bc-d1.img", BooterDisk1, "1d29a82b41c9c7491e2b68d16864bd11", 368640},
+				{ "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640},
+				{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformPC,
+			ADGF_NO_FLAGS,
+			GUIO_NONE
+		},
+		GID_BC,
+		GType_V1,
+		0,
+		0x1120
+	},
+
+	{
+		// Black Cauldron (PC 3.5" booter) 1.1K [AGI 1.12]
+		{
+			"bc",
+			"Booter 1.1K",
+			{
+				{ "bc-d1.img", BooterDisk1, "98a51d3a372baa9df288b6c0f0232567", 368640},
+				{ "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640},
+				{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformPC,
+			ADGF_NO_FLAGS,
+			GUIO_NONE
+		},
+		GID_BC,
+		GType_V1,
+		0,
+		0x1120
+	},
+
+	{
+		// Black Cauldron (PC 3.5" booter) 1.1M [AGI 1.12]
+		{
+			"bc",
+			"Booter 1.1M",
+			{
+				{ "bc-d1.img", BooterDisk1, "edc0e5befbe5e44bb109cdf9137ee12d", 368640},
+				{ "bc-d2.img", BooterDisk2, "5568f7a52e787305656246f95e2aa375", 368640},
+				{ NULL, 0, NULL, 0}
+			},
+			Common::EN_ANY,
+			Common::kPlatformPC,
+			ADGF_NO_FLAGS,
+			GUIO_NONE
+		},
+		GID_BC,
+		GType_V1,
+		0,
+		0x1120
+	},
+
 	// Black Cauldron (Amiga) 2.00 6/14/87
 	GAME_P("bc", "2.00 1987-06-14", "7b01694af21213b4727bb94476f64eb5", 0x2440, GID_BC, Common::kPlatformAmiga),
 
@@ -143,9 +207,9 @@ static const AGIGameDescription gameDescriptions[] = {
 	// Black Cauldron (CoCo3 360k) [AGI 2.072]
 	GAME_PS("bc", "updated", "c4e1937f74e8100cd0152b904434d8b4", 357, 0x2440, GID_BC, Common::kPlatformCoCo3),
 
-// TODO
-// These aren't supposed to work now as they require unsupported agi engine 2.01
-#if 0
+	// Donald Duck's Playground (PC Booter) 1.0Q
+	BOOTER2("ddp", "Booter 1.0Q", "ddp.img", "f323f10abf8140ffb2668b09af2e7b87", 368640, 0x2001, GID_DDP),
+
 	// Donald Duck's Playground (Amiga) 1.0C
 	// Menus not tested
 	GAME_P("ddp", "1.0C 1987-04-27", "550971d196f65190a5c760d2479406ef", 0x2272, GID_DDP, Common::kPlatformAmiga),
@@ -157,7 +221,6 @@ static const AGIGameDescription gameDescriptions[] = {
 	// reported by Filippos (thebluegr) in bugreport #1654500
 	// Menus not tested
 	GAME_PS("ddp", "1.0C 1986-06-09", "550971d196f65190a5c760d2479406ef", 132, 0x2272, GID_DDP, Common::kPlatformPC),
-#endif
 
 	// Gold Rush! (Amiga) 1.01 1/13/89 aka 2.05 3/9/89	# 2.316
 	GAME3_PS("goldrush", "1.01 1989-01-13 aka 2.05 1989-03-09", "dirs", "a1d4de3e75c2688c1e2ca2634ffc3bd8", 2399, 0x3149, 0, GID_GOLDRUSH, Common::kPlatformAmiga),
@@ -862,16 +925,4 @@ static AGIGameDescription g_fallbackDesc = {
 	0x2917
 };
 
-/**
- * Descriptor table for booter games
- */
-#define BOOTER_V1(id, extra, md50, md51, gid) { md50, md51, id, extra, gid, GType_V1, ADGF_NO_FLAGS, 0x1120 },
-#define BOOTER_V2(id, extra, md50, md51, gid) { md50, md51, id, extra, gid, GType_V2, ADGF_NO_FLAGS, 0x2001 },
-
-static AGIBooterDescription booterDescription[] = {
-	BOOTER_V1("bc", "booter", "98a51d3a372baa9df288b6c0f0232567", "5568f7a52e787305656246f95e2aa375", GID_BC)
-	BOOTER_V2("ddp", "booter", "f323f10abf8140ffb2668b09af2e7b87", "", GID_DDP)
-	{ "", "", "", "", 0, 0, 0, 0 }
-};
-
 } // End of namespace Agi
diff --git a/engines/agi/loader_v1.cpp b/engines/agi/loader_v1.cpp
index 8da74ce..c6a3e66 100644
--- a/engines/agi/loader_v1.cpp
+++ b/engines/agi/loader_v1.cpp
@@ -56,11 +56,8 @@ AgiLoader_v1::AgiLoader_v1(AgiEngine *vm) {
 
 int AgiLoader_v1::detectGame() {
 	// Find filenames for the disk images
-	Common::String md5Disk0, md5Disk1;
-	getBooterMD5Sums((AgiGameID)_vm->getGameID(), md5Disk0, md5Disk1);
-	diskImageExists(md5Disk0, _filenameDisk0);
-	if (!md5Disk1.empty())
-		diskImageExists(md5Disk1, _filenameDisk1);
+	_filenameDisk0 = _vm->getDiskName(BooterDisk1);
+	_filenameDisk1 = _vm->getDiskName(BooterDisk2);
 
 	return _vm->setupV2Game(_vm->getVersion());
 }






More information about the Scummvm-git-logs mailing list